python - Pandas 按组统计最近 n 天事件发生的次数

标签 python pandas

我有按 ID 发生的事件表。我如何计算最近 n 天内每种事件类型在当前行之前发生的次数?

例如,事件列表如下:

df = pd.DataFrame([{'id': 1, 'event_day': '2016-01-01', 'event_type': 'type1'},
{'id': 1, 'event_day': '2016-01-02', 'event_type': 'type1'},
{'id': 2, 'event_day': '2016-02-01', 'event_type': 'type2'},
{'id': 2, 'event_day': '2016-02-15', 'event_type': 'type3'},
{'id': 3, 'event_day': '2016-01-06', 'event_type': 'type3'},
{'id': 3, 'event_day': '2016-03-11', 'event_type': 'type3'},])
df['event_day'] = pd.to_datetime(df['event_day'])
df = df.sort_values(['id', 'event_day'])

或者:

   event_day event_type  id
0 2016-01-01      type1   1
1 2016-01-02      type1   1
2 2016-02-01      type2   2
3 2016-02-15      type3   2
4 2016-01-06      type3   3
5 2016-03-11      type3   3

by id 我想计算过去 n 天内每个 event_type 在当前行之前发生的次数。例如,在第 3 行 id=2,那么在事件历史记录中的那个点之前(但不包括)有多少次事件类型 1、2 和 3 在最后 n 天内发生了 id 2?

所需的输出如下所示:

    event_day   event_type  event_type1_in_last_30days  event_type2_in_last_30days  event_type3_in_last_30days  id
0   2016-01-01  type1       0                           0                           0                           1
1   2016-01-02  type1       1                           0                           0                           1
2   2016-02-01  type2       0                           0                           0                           2
3   2016-02-15  type3       0                           1                           0                           2
4   2016-01-06  type3       0                           0                           0                           3
5   2016-03-11  type3       0                           0                           0                           3

最佳答案

res = ((((df['event_day'].values >= df['event_day'].values[:, None] - pd.to_timedelta('30 days')) 
        & (df['event_day'].values < df['event_day'].values[:, None]))
        & (df['id'].values == df['id'].values[:, None]))
        .dot(pd.get_dummies(df['event_type'])))
res
Out: 
array([[ 0.,  0.,  0.],
       [ 1.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.]])

第一部分是生成矩阵如下:

(df['event_day'].values >= df['event_day'].values[:, None] - pd.to_timedelta('30 days'))
Out: 
array([[ True,  True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True,  True],
       [False,  True,  True,  True,  True,  True],
       [False, False,  True,  True, False,  True],
       [ True,  True,  True,  True,  True,  True],
       [False, False, False,  True, False,  True]], dtype=bool)

这是一个 6x6 矩阵,每一行都会与其他行进行比较。它利用 NumPy 的广播进行成对比较(.values[:, None] 添加了另一个轴)。为了使其完整,我们需要检查这一行是否也比另一行发生得更早:

(((df['event_day'].values >= df['event_day'].values[:, None] - pd.to_timedelta('30 days')) 
   & (df['event_day'].values < df['event_day'].values[:, None])))
Out: 
array([[False, False, False, False, False, False],
       [ True, False, False, False, False, False],
       [False,  True, False, False,  True, False],
       [False, False,  True, False, False, False],
       [ True,  True, False, False, False, False],
       [False, False, False,  True, False, False]], dtype=bool)

另一个条件是关于 id 的。使用类似的方法,您可以构建一个成对比较矩阵来显示 id 何时匹配:

(df['id'].values == df['id'].values[:, None])
Out: 
array([[ True,  True, False, False, False, False],
       [ True,  True, False, False, False, False],
       [False, False,  True,  True, False, False],
       [False, False,  True,  True, False, False],
       [False, False, False, False,  True,  True],
       [False, False, False, False,  True,  True]], dtype=bool)

它变成了:

(((df['event_day'].values >= df['event_day'].values[:, None] - pd.to_timedelta('30 days')) 
    & (df['event_day'].values < df['event_day'].values[:, None]))
    & (df['id'].values == df['id'].values[:, None]))
Out: 
array([[False, False, False, False, False, False],
       [ True, False, False, False, False, False],
       [False, False, False, False, False, False],
       [False, False,  True, False, False, False],
       [False, False, False, False, False, False],
       [False, False, False, False, False, False]], dtype=bool)

最后,您想查看每种类型的它,以便您可以使用 get_dummies:

pd.get_dummies(df['event_type'])
Out: 
   type1  type2  type3
0    1.0    0.0    0.0
1    1.0    0.0    0.0
2    0.0    1.0    0.0
3    0.0    0.0    1.0
4    0.0    0.0    1.0
5    0.0    0.0    1.0

如果将结果矩阵与该矩阵相乘,它应该会给出每种类型满足该条件的行数。您可以将生成的数组传递给 DataFrame 构造函数并连接:

pd.concat([df, pd.DataFrame(res, columns = ['e1', 'e2', 'e3'])], axis=1)
Out: 
   event_day event_type  id   e1   e2   e3
0 2016-01-01      type1   1  0.0  0.0  0.0
1 2016-01-02      type1   1  1.0  0.0  0.0
2 2016-02-01      type2   2  0.0  0.0  0.0
3 2016-02-15      type3   2  0.0  1.0  0.0
4 2016-01-06      type3   3  0.0  0.0  0.0
5 2016-03-11      type3   3  0.0  0.0  0.0

关于python - Pandas 按组统计最近 n 天事件发生的次数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38726855/

相关文章:

python - 在 pandas 数据框中查找元素

python - 将程序中的 Python Pandas Dataframe 输出合并到一个 Dataframe 中

python - 将 pandas 数据框中的多类训练示例(行)过度采样和欠采样到指定值

python - urllib2.Request post 相当于node.js

python - 使用 Python boto3 从 S3 下载 Sentinel 文件

Python Xgboost : ValueError ('feature_names may not contain [, ] or <' )

python - 在 Pandas 的一列中切片字符串

python - 合并创建错误后从 int 类型切换到 float64

python - os.walk() 是否缺少指向目录的符号链接(symbolic link)?

python - 如何修复 discord bot 中的 "SyntaxError: invalid syntax"