正在对DataFrameGroupby对象进行滚动操作



我有一个pandas数据帧,我希望对数据中的不同组执行相同的滚动操作。考虑以下具有四列的df(有关要构建的代码,请参阅问题底部(:

id      date       category   target
1    2017-01-01      'a'        0
1    2017-01-01      'b'        0
1    2017-01-21      'a'        1
1    2017-01-21      'b'        1
1    2017-10-01      'a'        0
1    2017-10-01      'b'        0
2    2017-01-01      'a'        1    
2    2017-01-01      'b'        1    
2    2017-01-21      'a'        0
2    2017-01-21      'b'        0
2    2017-10-01      'a'        0
2    2017-10-01      'b'        0

我想要的是一个操作,它为每个唯一的id-日期对计算一个布尔值,指示目标列在给定日期的6个月内是否为1。因此,对于所提供的df,我希望得到这样的结果:

id      date       one_within_6m
1    2017-01-01       True
1    2017-01-21       False
1    2017-10-01       False
2    2017-01-01       False
2    2017-01-21       False
2    2017-10-01       False

我可以使用for循环来迭代行,并提前6个月查找每次访问,但由于我的数据集太大,速度太慢。

所以,我想知道是否有可能按id对日期进行分组,并在时间窗口上进行滚动操作来查看这一点?例如:

df_grouped = df.groupby(['id', 'date'])
# … do something to set date as index
# ... define some custom function
df_grouped.rolling('6m', on='target').apply(some_custom_function)

一些注意事项:

  • 在6个月的窗口中可以有多个"1",对于当前日期,这应该被视为True。

  • 在我的脑海中,some_custom_function将检查未来6个月(不包括当前日期(的目标总和是否大于1。

支持代码:

生成此问题中使用的DataFrame实例:

ids = np.concatenate([np.ones(6), np.ones(6)+1])
dates = ['2017-01-01','2017-01-01','2017-01-21','2017-01-21',
'2017-10-01','2017-10-01','2017-01-01','2017-01-01',
'2017-01-21','2017-01-21','2017-10-01','2017-10-01']
categories = ['a','b','a','b','a','b','a','b','a','b','a','b']
targets = [0,0,1,1,0,0,1,1,0,0,0,0]
df = pd.DataFrame({'id':ids,
'date':dates,
'category':categories,
'target':targets})
df['date'] = pd.to_datetime(df['date'])

我找到了一个可行的解决方案,但它只有在每个id的每个日期都是唯一的情况下才有效。这是我的数据中的情况,需要一些额外的处理:

new_df = df.groupby(['id','date']).mean().reset_index()

返回:

id      date      target
0   1.0   2017-01-01    0
1   1.0   2017-01-21    1
2   1.0   2017-10-01    0
3   2.0   2017-01-01    1
4   2.0   2017-01-21    0
5   2.0   2017-10-01    0

然后,我可以在groupby对象上使用滚动方法来获得所需的结果:

df = new_df.set_index('date')
df.iloc[::-1].groupby('id')['target'].rolling(window='180D', 
centre=False).apply(lambda x : x[:-1].sum())

这里有两个技巧:

  1. 我颠倒日期的顺序(.iloc[::-1](以获得前瞻性窗口;其他SO问题中也提出了这一点。

  2. 我去掉了总和的最后一个条目,从总和中删除了"当前"日期,所以它只向前看。

第二个"破解"意味着它只有在给定id没有重复日期时才有效。

我有兴趣制作一个更健壮的解决方案(例如,重复id的日期(。

最新更新