我有一个熊猫数据框,希望对数据中的不同组执行相同的滚动操作。考虑下面的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对计算一个布尔值,以指示在给定日期的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
在我的头上将检查接下来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'])
答案 0 :(得分:0)
我找到了一个可行的解决方案,但只有在每个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的日期)。