在Python-pandas中计算连续天数
有一个表格,里面记录了不同客户的访问日期和客户ID。表格如下。有些客户会连续几天来,停几天后再连续几天来。我想计算每个客户的连续访问天数。在我的例子中,每个客户可能会有几段连续的天数。例如,客户1有3天是连续的,然后又有4天是连续的。我想知道怎么才能得到所有这些连续天数的数字,并找出其中最大的一个。
id visit_date
1 1/2/2022
1 1/3/2022
1 1/4/2022
1 1/7/2022
1 1/8/2022
1 1/9/2022
1 1/10/2022
2 1/1/2022
2 1/2/2022
2 1/4/2022
2 1/6/2022
2 1/7/2022
2 1/8/2022
2 1/9/2022
2 1/10/2022
3 1/3/2022
3 1/4/2022
3 1/5/2022
4 1/3/2022
4 1/4/2022
4 1/8/2022
我尝试了不同的方法,但没有找到任何解决方案。我期望的结果是:
id consecutive_days
1 3
1 4
2 2
2 5
3 2
4 0
4 个回答
0
假设每个客户的日期都是按顺序排列的,你可以计算每一行之间的差值,然后对每组中差值等于1的行进行求和。
consecutive_days_per_id = df.groupby('id').apply(lambda group: (pd.to_datetime(group['date']).dt.day.diff() == 1).sum())
注意:如果你的列已经是日期时间类型,就可以忽略“pd.to_datetime()”这一部分。
0
代码
grp = (pd.to_datetime(df['visit_date'])
.groupby(df['id']).diff().ne('1day')
.groupby(df['id']).cumsum()
)
out = (df.groupby(['id', grp]).size()[lambda x: x > 1]
.droplevel(1).reset_index(name='consecutive_days')
)
输出:
id consecutive_days
0 1 3
1 1 4
2 2 2
3 2 5
4 3 3
5 4 2
获取最大的一个
result = out.groupby('id').max()
结果:
consecutive_days
id
1 4
2 5
3 3
4 2
0
如果你只关心最大值的话,可以省去使用两次 groupby
的步骤,直接用 numpy 的聚合函数,这在处理大数据时会更高效:
out = (pd
.to_datetime(df['visit_date'], dayfirst=False)
.groupby(df['id'])
.agg(lambda g: np.diff(np.nonzero(np.r_[g.diff().ne('1d'), len(g)])[0]).max())
#.reset_index(name='consecutive_days') # optional
)
输出结果:
id
1 4
2 5
3 3
4 2
Name: visit_date, dtype: int64
以框架形式输出:
id consecutive_days
0 1 4
1 2 5
2 3 3
3 4 2
聚合前的中间结果:
id
1 [3, 4]
2 [2, 1, 5]
3 [3]
4 [2, 1]
Name: visit_date, dtype: object
最后,如果你想排除 1
,可以在聚合之后再处理(如果是 Series,可以用 out[out>1]
,如果是 DataFrame,可以用 out.query('consecutive_days>1')
)