假设我有以下数据框。
df = pd.DataFrame([[1234,0,1],[1234,1,2],[1234,0,3],[2256,1,4],[1234,0,5],[1234,1,6],[1234,0,7],[2256,0,8],[2256,1,9],[2256,0,10]],columns=['ID','result','time'])
示例
ID result time
0 1234 0 1
1 1234 1 2
2 1234 0 3
3 2256 1 4
4 1234 0 5
5 1234 1 6
6 1234 0 7
7 2256 0 8
8 2256 1 9
9 2256 0 10
10 1234 1 11
我想按ID分组。然后,我想为每个ID添加“ time_since_1”列。 “ time_since_1”是每个ID的结果变为1以来的持续时间。时间将在 之后重置。每个ID的结果变为1。所以我也需要移动。
所需的输出
ID result time time_since_1
0 1234 0 1 0 → Nothing hasn't happened yet
1 1234 1 2 0 → first time = 0 (ID = 1234)
2 1234 0 3 1 → 3-2 = 1 (ID = 1234)
3 2256 1 4 0 → first time = 0 (ID = 2256)
4 1234 0 5 3 → 5-2 = 3 (ID = 1234)
5 1234 1 6 4 → 6-2 = 4 (ID = 1234)
6 1234 0 7 1 → 7-6 = 1 (ID = 1234)
7 2256 0 8 4 → 8-4 = 4 (ID = 2256)
8 2256 1 9 5 → 9-4 = 5 (ID = 2256)
9 2256 0 10 1 → 10-9 = 1 (ID = 2256)
10 1234 1 11 5 → 11-6 = 5 (ID = 1234)
我试图编写代码,最终我发现.expanding()在这种情况下可能会有所帮助。所以,我尝试了下面的代码。
df['time_since_1'] = df.groupby('ID').apply(lambda x: x.expanding().apply(lambda y: y['time'] - y[y['result']==1].tail(1)['time']))
这种事情不起作用,因为.expanding()。apply()返回ndarray,并且不确定如何处理它们。我需要使用expanding()并获取result = 1的时间的最后一行,以便可以从中减去最近一行的时间。我不确定该怎么做。
由于expanding()。apply()返回了ndarray,所以我试图用它来制作数据帧,但是似乎也有错误,并且不确定正确的方法。
def func(y):
df = pd.DataFrame(y,columns=['ID','result','time_since_1'])
# filter here
# return one value (time_since_1)
df['time_since_1'] = df.groupby('ID').apply(lambda x: x.expanding().apply(lambda y: func(y))
任何其他想法或代码都可以帮助我。谢谢。
答案 0 :(得分:0)
我的不尝试是预期的解决方案,但也许可以帮助您...
r=df.groupby('ID').apply(lambda x: x.where(x['result'].eq(1))['time'].shift().ffill().fillna(df['time']))
df['time_since_1']=df['time']-r.reset_index().sort_values('level_1').set_index('level_1')['time']
print(df)
ID result time time_since_1
0 1234 0 1 0.0
1 1234 1 2 0.0
2 1234 0 3 1.0
3 2256 1 4 0.0
4 1234 0 5 3.0
5 1234 1 6 4.0
6 1234 0 7 1.0
7 2256 0 8 4.0
8 2256 1 9 5.0
9 2256 0 10 1.0
10 1234 1 11 5.0