Pandas-计算下一个/即将到来的价值频率x天数



这是我在这里问的问题的后续:Pandas-计算最近x天的值频率

我不想在过去的x天内进行计数,而是想查看ID,并计算它在接下来的x天中显示的次数。例如,从给定的日期时间开始,ID A在接下来的7天内出现了多少次?所以这就像一个反向滚动计数。

import pandas as pd


df = pd.DataFrame(
[['A', '2020-02-02 20:31:00'],
['A', '2020-02-03 00:52:00'],
['A', '2020-02-07 23:45:00'],
['A', '2020-02-08 13:19:00'],
['A', '2020-02-18 13:16:00'],
['A', '2020-02-27 12:16:00'],
['A', '2020-02-28 12:16:00'],
['B', '2020-02-07 18:57:00'],
['B', '2020-02-07 21:50:00'],
['B', '2020-02-12 19:03:00'],
['C', '2020-02-01 13:50:00'],
['C', '2020-02-11 15:50:00'],
['C', '2020-02-21 10:50:00']],
columns = ['ID', 'Date'])
df['Date'] = pd.to_datetime(df['Date'])

期望输出:

ID                Date  count_in_next_7_days
0   A 2020-02-02 20:31:00                     3
1   A 2020-02-03 00:52:00                     2
2   A 2020-02-07 23:45:00                     1
3   A 2020-02-08 13:19:00                     0
4   A 2020-02-18 13:16:00                     0
5   A 2020-02-27 12:16:00                     1
6   A 2020-02-28 12:16:00                     0
7   B 2020-02-07 18:57:00                     2
8   B 2020-02-07 21:50:00                     1
9   B 2020-02-12 19:03:00                     0
10  C 2020-02-01 13:50:00                     0
11  C 2020-02-11 15:50:00                     0
12  C 2020-02-21 10:50:00                     0

以下是如何获取前7天窗口的计数。我尝试过同样的代码,但在按日期降序排列后,我认为只切换顺序就可以了,但事实并非如此。所以我一直在思考如何让滚动窗口向前看x天,而不是向后看x天。

delta = 7
df = df[['ID','Date']]
df = (df.set_index('Date')
.assign(count_last=1)
.groupby('ID')
.rolling(f'{delta}D')
.sum() - 1).reset_index(drop=False)

这里有一个使用groupby和apply的方法。我有一种感觉,使用groupby和transform可能有更好的方法,但我从未使用过transform,仍在努力解决它。

def f(thing):
cutoff = thing.loc['Date'] + seven
mask = group.loc[thing.name:,'Date'] <= cutoff
return mask.sum() - 1
df = df.assign(count_in_next_7_days=0)
seven = pd.Timedelta('7 days')
grouped = df.groupby('ID')
for name,group in grouped:
n = group.apply(f,axis=1)
df.loc[df['ID'] == name,['count_in_next_7_days']] = n

这里有一个使用numpy与广播进行比较的替代方案。假设它是按日期排序的,'Date'是日期时间数据类型。

df = df.assign(count_in_next_7_days=0)
ids = df.ID.unique()
for idee in ids:
mask = df['ID'] == idee
x = df.loc[mask,'Date'].values
y = x + seven
comparison = y[:,None] >= x
counts = comparison.sum(1) - 1 - np.arange(x.shape[0])
df.loc[mask,'count_in_next_7_days'] = counts

对于counts = comparison.sum(1) - 1 - np.arange(x.shape[0]),负1表示不计算本身,负.arange()表示不计算过去的日期。

最新更新