。我有一个与此类似的数据框(除了Visit
和Deliv
列的数量分别达到Visit_12
和Deliv 12
之外,并且有几百个客户端-我已经在这里简化了
Client Visit_1 Visit_2 Visit_3 Deliv_1 Deliv_2 Deliv_3 Key_DT
Client_1 2018-01-01 2018-01-20 2018-03-29 No Yes Yes 2018-01-15
Client_2 2018-01-10 2018-01-30 2018-02-10 Yes Yes No 2018-01-25
Client_3 2018-01-20 2018-04-01 2018-04-10 Yes Yes Yes 2018-04-15
Client_4 2018-01-30 2018-03-01 2018-03-10 Yes No Yes 2018-02-25
Client_5 2018-04-02 2018-04-07 2018-04-20 Yes No Yes 2018-04-01
我想创建一个名为Vis_sum
的新列,该列显示在Key_DT
之后但在2018-01-20
之前拥有2018-03-25
的所有客户的访问次数之和从Visit_1
到Visit_3
,即(i)在同一行中的Key_DT
之后,(ii)在2018-03-25
之前,并且(iii)具有Yes
在关联的Deliv
列中(例如,Deliv_1
与Visit_1
关联)。看起来应该像这样
Client Visit_1 Visit_2 Visit_3 Deliv_1 Deliv_2 Deliv_3 Key_DT Vis_sum
Client_1 2018-01-01 2018-01-20 2018-03-29 No Yes Yes 2018-01-15 0
Client_2 2018-01-10 2018-01-30 2018-02-10 Yes Yes No 2018-01-25 1
Client_3 2018-01-20 2018-04-01 2018-04-10 Yes Yes Yes 2018-04-15 0
Client_4 2018-01-30 2018-03-01 2018-03-10 Yes No Yes 2018-02-25 1
Client_5 2018-04-02 2018-04-07 2018-04-20 Yes No Yes 2018-04-01 0
请注意-所有列中都缺少数据,因此必须将其考虑在内。
我尝试了以下方法-但没有用。虽然部分(i)和(ii)的代码可以一起使用,而(iii)的代码可以单独使用,但是在编写完下面的所有代码后,它对于其中的每一行都会返回0
列Vis_sum
:
df.loc[((df.Key_DT < '2018-03-25') &
(df.Key_DT >= '2018-01-20')), 'Vis_sum'] = ((df.filter(like='Visit_').gt(df.Key_DT,axis=0)) & (df.filter(like='Visit_').lt(pd.to_datetime('2018-03-25')).fillna(0).astype(bool)) & (df.filter(like='Deliv_').eq('Yes'))).sum(1)
答案 0 :(得分:1)
我有一个类似的数据集(由调查产生的混乱),我使用了melt
,merge
和groupby-transform-cumcount
来获得我想要的号码
假设您的数据集称为df:
#First melt the DF and the unique visits (you'll have to do this for all your value_vars)
df1 = pd.melt(df,id_vars='Client',value_vars=['Visit_1','Visit_2','Visit_3'],var_name='Visit',value_name='Visit Date')
print(df1.head(5))
Client Visit Visit Date
0 Client_1 Visit_1 2018-01-01
1 Client_2 Visit_1 2018-01-10
2 Client_3 Visit_1 2018-01-20
3 Client_4 Visit_1 2018-01-30
4 Client_5 Visit_1 2018-04-02
#lets do the same for the deliveries
df2 = pd.melt(df,id_vars='Client',value_vars=['Deliv_1','Deliv_2','Deliv_3'],var_name='Delivery',value_name='Check')
融化之后,我们可以将您的值重新合并到表格样式df中。
# Lets merge these and then put the Key_DT back on
res = pd.merge(df1,df2,on='Client')
res = pd.merge(res,df[['Client','Key_DT']],on='Client')
print(res.head(5))
Client Visit Visit Date Delivery Check Key_DT
0 Client_1 Visit_1 2018-01-01 Deliv_1 No 2018-01-15
1 Client_1 Visit_1 2018-01-01 Deliv_2 Yes 2018-01-15
2 Client_1 Visit_1 2018-01-01 Deliv_3 Yes 2018-01-15
3 Client_1 Visit_2 2018-01-20 Deliv_1 No 2018-01-15
4 Client_1 Visit_2 2018-01-20 Deliv_2 Yes 2018-01-15
根据您的条件进行过滤,并通过Client
s = res.loc[(res['Key_DT'] >= '2018-01-20') & (res['Key_DT'] <= '2018-03-25') & (res.Check == 'Yes')]
res['visit_sum'] = s.groupby(['Client','Visit'])['Check'].transform('cumcount')
res['visit_sum'] = res['visit_sum'].fillna(0)
print(res.loc[res['visit_sum'] > 0])
Client Visit Visit Date Delivery Check Key_DT visit_sum
27 Client_4 Visit_1 2018-01-30 Deliv_1 Yes 2018-02-25 1.0
29 Client_4 Visit_1 2018-01-30 Deliv_3 Yes 2018-02-25 1.0
30 Client_4 Visit_2 2018-03-01 Deliv_1 Yes 2018-02-25 1.0
32 Client_4 Visit_2 2018-03-01 Deliv_3 Yes 2018-02-25 1.0
33 Client_4 Visit_3 2018-03-10 Deliv_1 Yes 2018-02-25 1.0
35 Client_4 Visit_3 2018-03-10 Deliv_3 Yes 2018-02-25 1.0
希望 sort 可以帮助您,并帮助您获得预期的结果。
答案 1 :(得分:1)
您编写的代码不起作用,因为它不知道它应该将Visit_#
与Deliv_#
匹配。尝试以下方法:
df.loc[((df.Key_DT < '2018-03-25') & (df.Key_DT >= '2018-01-20')), 'Vis_sum'] = ((df.filter(like='Visit_').gt(df.Key_DT,axis=0)) & (df.filter(like='Visit_').lt(pd.to_datetime('2018-03-25'),axis=0).fillna(0).astype(bool)) & (df.filter(like='Deliv_').rename(columns=lambda x: x.replace('Deliv','Visit')).eq('Yes'))).sum(1)