输入数据必须按DATE在每个组中进行排序,在此数据中是否正常.
输入数据无法很好地映射情况,因此将添加下4行.
WIN1列是从WIN创建的 – 值为1表示“是”,0表示“否”.我需要两个输出列.
df['WIN1'] = df['WIN'].map(lambda x: 1 if x == 'Yes' else 0)
列NumOfDaysSinceLastWin
首先创建列cumsum(累积和).
df['cumsum'] = df['WIN1'].cumsum()
如果所有WIN都是’是’,那很简单.数据将被分组,日期和上一个日期(-1)之间的差值在列差异中.
#df['diffs'] = df.groupby(['ID', 'cumsum'])['DATE'].apply(lambda d: (d-d.shift()).fillna(0))
但情况很复杂,因为列WIN的值为“否”.因此,如果值为“是”,则需要与之前的“是”不同,如果“否”需要与之前的“赢”不同.差异可以通过多种方式计算,但通过减去两列–DATE和列date1来选择.
列date1
行必须以特殊方式分组 – 值“否”,前一个“是”.可以通过列cumsum中的累积和来实现.
然后,该组的最小值为“是”列的值,然后该值重复到具有“否”值的行.
列数是特殊的 – 没有重复的cumsum列值是1.重复的值按组递增.
df['min'] = df.groupby(['ID','cumsum'])['DATE'].transform('min')
df['count'] = df.groupby(['cumsum'])['cumsum'].transform('count')
前一行中值’YES’的日期对于差异是必要的.数据帧df1仅过滤df的值“是”,然后按列ID对其进行分组.指数不变,因此输出可以映射到数据帧df的新列.
df1 = df[~df['WIN'].isin(['No'])]
df['date1'] = df1.groupby(['ID'])['DATE'].apply(lambda d: d.shift())
print df
ID DATE WIN WIN1 cumsum min count date1
0 A 2015-06-05 Yes 1 1 2015-06-05 1 NaT
1 A 2015-06-05 Yes 1 2 2015-06-05 1 2015-06-05
2 A 2015-06-07 Yes 1 3 2015-06-07 1 2015-06-05
3 A 2015-06-07 Yes 1 4 2015-06-07 1 2015-06-07
4 A 2015-06-07 Yes 1 5 2015-06-07 4 2015-06-07
5 A 2015-06-08 No 0 5 2015-06-07 4 NaT
6 B 2015-06-07 No 0 5 2015-06-07 4 NaT
7 B 2015-06-07 No 0 5 2015-06-07 4 NaT
8 B 2015-08-07 Yes 1 6 2015-08-07 1 NaT
9 C 2015-05-15 Yes 1 7 2015-05-15 3 NaT
10 C 2015-05-30 No 0 7 2015-05-15 3 NaT
11 C 2015-07-30 No 0 7 2015-05-15 3 NaT
12 C 2015-08-03 Yes 1 8 2015-08-03 1 2015-05-15
13 C 2015-08-03 Yes 1 9 2015-08-03 1 2015-08-03
然后,日期列min(值’No’和前一个’是’)和列date1(其他值’Yes’)可以按列计数连接.
添加了新条件 – 列date1的值将为null – (NaT),因为这些值将被列min覆盖.
df.loc[(df['count'] > 1) & (df['date1'].isnull()), 'date1'] = df['min']
print df
ID DATE WIN WIN1 cumsum min count date1
0 A 2015-06-05 Yes 1 1 2015-06-05 1 2015-06-05
1 A 2015-06-05 Yes 1 2 2015-06-05 1 2015-06-05
2 A 2015-06-07 Yes 1 3 2015-06-07 1 2015-06-05
3 A 2015-06-07 Yes 1 4 2015-06-07 1 2015-06-07
4 A 2015-06-07 Yes 1 5 2015-06-07 4 2015-06-07
5 A 2015-06-08 No 0 5 2015-06-07 4 2015-06-07
6 B 2015-06-07 No 0 5 2015-06-07 4 2015-06-07
7 B 2015-06-07 No 0 5 2015-06-07 4 2015-06-07
8 B 2015-08-07 Yes 1 6 2015-08-07 1 2015-08-07
9 C 2015-05-15 Yes 1 7 2015-05-15 3 2015-05-15
10 C 2015-05-30 No 0 7 2015-05-15 3 2015-05-15
11 C 2015-07-30 No 0 7 2015-05-15 3 2015-05-15
12 C 2015-08-03 Yes 1 8 2015-08-03 1 2015-05-15
13 C 2015-08-03 Yes 1 9 2015-08-03 1 2015-08-03
重复日期时间 – 子解决方案
对不起,如果这是一个复杂的方式,也许有人找到更好的.
我的解决方案是找到重复值,按上一个“是”填充它们,并将其添加到列date1以获得差异.
这些值在列数中标识.其他(值1)重置为NaN.然后,date1中的值按列数复制到date2.
df['count'] = df1.groupby(['ID', 'DATE', 'WIN1'])['WIN1'].transform('count')