按两列分组,累计金额与日期为6个月的回顾窗口

时间:2017-12-22 03:12:23

标签: python python-3.x pandas pandas-groupby

原始数据集

userId     createDate                  grade
0          2016-05-08 22:00:49.673     2
0          2016-07-23 12:37:11.570     7
0          2017-01-03 12:05:33.060     7
1009       2016-06-27 09:28:19.677     5
1009       2016-07-23 12:37:11.570     8
1009       2017-01-03 12:05:33.060     9
1009       2017-02-08 16:17:17.547     4
2011       2016-11-03 14:30:25.390     6
2011       2016-12-15 21:06:14.730     11
2011       2017-01-04 20:22:31.423     2
2011       2017-08-08 16:17:17.547     7

我想从createDate获得6个月回顾窗口的每个用户的等级滚动总和,即从创建日期起6个月内的所有等级的总和 预期:

userId     createDate                 
    0          2016-05-08 22:00:49.673     2
               2016-07-23 12:37:11.570     9
               2017-01-03 12:05:33.060     14
    1009       2016-06-27 09:28:19.677     5
               2016-07-23 12:37:11.570     13
               2017-01-03 12:05:33.060     17
               2017-02-08 16:17:17.547     13
    2011       2016-11-03 14:30:25.390     6
               2016-12-15 21:06:14.730     17
               2017-01-04 20:22:31.423     19
               2017-08-08 16:17:17.547     7

我目前的尝试不正确:

df.groupby(['userId','createDate'])['grade'].mean().groupby([pd.Grouper(level='userId'),pd.TimeGrouper('6M', level='createDate', closed = 'left')]).cumsum()

它给了我以下结果:

userId  createDate             
0       2016-05-08 22:00:49.673     2
        2016-07-23 12:37:11.570     9
        2017-01-03 12:05:33.060     7
1009    2016-06-27 09:28:19.677     5
        2016-07-23 12:37:11.570    13
        2017-01-03 12:05:33.060     9
        2017-02-08 16:17:17.547    13
2011    2016-11-03 14:30:25.390     6
        2016-12-15 21:06:14.730    17
        2017-01-04 20:22:31.423    19
        2017-08-08 16:17:17.547     7

1 个答案:

答案 0 :(得分:2)

groupby内使用rolling sumapply,偏移量为180D而不是6个月,因为月份的天数往往会连续几个月发生变化。滚动窗口必须是常量,即

df.groupby(['userId'])['createDate','grade'].apply(lambda x : x.set_index('createDate').rolling('180D').sum())

                                grade
userId createDate                    
0      2016-05-08 22:00:49.673    2.0
       2016-07-23 12:37:11.570    9.0
       2017-01-03 12:05:33.060   14.0
1009   2016-06-27 09:28:19.677    5.0
       2016-07-23 12:37:11.570   13.0
       2017-01-03 12:05:33.060   17.0
       2017-02-08 16:17:17.547   13.0
2011   2016-11-03 14:30:25.390    6.0
       2016-12-15 21:06:14.730   17.0
       2017-01-04 20:22:31.423   19.0
       2017-08-08 16:17:17.547    7.0

编辑评论:

回顾6个月前,需要对日期进行排序。所以也许你可能需要sort_values

 df.groupby(['userId'])['createDate','grade'].apply(lambda x : \
            x.sort_values('createDate').set_index('createDate').rolling('180D').sum())

根据@ coldspeed的评论进行编辑:

使用apply是一种过度杀伤,首先设置索引然后使用滚动总和:

df.set_index('createDate').groupby('userId').grade.rolling('‌​180D').sum() 

时间:

df = pd.concat([df]*1000)

%%timeit
df.set_index('createDate').groupby('userId').grade.rolling('180D').sum() 
100 loops, best of 3: 7.55 ms per loop

%%timeit
df.groupby(['userId'])['createDate','grade'].apply(lambda x : x.sort_values('createDate').set_index('createDate').rolling('180D').sum())
10 loops, best of 3: 19.5 ms per loop