我有一个 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-date 对计算一个 bool 值,指示目标列是否在给定日期的 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 个月查看,但由于我的数据集很大,它太慢了。
所以,我想知道是否可以将日期分组并在时间窗口上进行滚动操作来查看这个?例如:
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
将检查 future 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())
这里有两个技巧:
我颠倒了日期的顺序 (
.iloc[::-1]
) 以获取前瞻性窗口;这已在其他 SO questions 中提出.我删除了总和的最后一个条目以从总和中删除“当前”日期,因此它只向前看。
第二个“hack”意味着它仅在给定 ID 的日期没有重复时才有效。
我有兴趣制定更稳健的解决方案(例如,为 id 重复日期)。
关于python - DataFrameGroupby 对象的滚动操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58628367/