Pandas计算最大连续间隔时间
日常统计中总会遇到需要统计和周期有关的数据,如用户连续登录天数,事件发生的连续性等。
样本数据是用户的ID和抽奖日期,准备计算出每个用户的连续抽奖最大间隔时间,我先说一下我的思路。先将根据用户ID将用户分组并按照日期排序,对相邻的日期进行比较,差异为1天的即为连续数据,对连续数据进行计数即可计算出最大的时间间隔。
数据样本
import pandas as pd
df = pd.read_csv(r'tmp\draw.csv')
df
draw_date | weixin_id | |
---|---|---|
0 | 2021-05-25 | 751478029716439040 |
1 | 2021-05-28 | 751478029716439040 |
2 | 2021-06-08 | 751478029716439040 |
3 | 2021-06-09 | 751478029716439040 |
4 | 2021-06-15 | 639062248681259008 |
5 | 2021-06-16 | 639062248681259008 |
6 | 2021-06-17 | 639062248681259008 |
7 | 2021-06-18 | 639062248681259008 |
8 | 2021-06-19 | 639062248681259008 |
9 | 2021-06-21 | 639062248681259008 |
样本中数据是字符串,我先将日期转成对应的格式
df['draw_date'] = pd.to_datetime(df['draw_date'])
我这里使用shift
将日期下移一位,再加上一天和相邻数据进行比较,目的是判断前后两条时间间隔是否相差1天,不相等记为True反之为False
import datetime
for name,group in df.groupby('weixin_id'):
check = ((group['draw_date'].shift(1) + datetime.timedelta(1)) != group['draw_date'])
print(check)
4 True
5 False
6 False
7 False
8 False
9 True
Name: draw_date, dtype: bool
0 True
1 True
2 True
3 False
Name: draw_date, dtype: bool
用cumsum
窗口函数,对上文提到的标记按照行累加,标记为False的情况不会计算
for name,group in df.groupby('weixin_id'):
check = ((group['draw_date'].shift(1) + datetime.timedelta(1)) != group['draw_date'])
cumsum = check.cumsum()
print(cumsum)
4 1
5 1
6 1
7 1
8 1
9 2
Name: draw_date, dtype: int32
0 1
1 2
2 3
3 3
Name: draw_date, dtype: int32
用value_counts
对上文累计的数据进行分组计数,可以算出每段时间的间隔天数,按照我们的需求取最大的即可
for name,group in df.groupby('weixin_id'):
check = ((group['draw_date'].shift(1) + datetime.timedelta(1)) != group['draw_date'])
cumsum = check.cumsum()
value_counts = cumsum.value_counts()
print(value_counts)
1 5
2 1
Name: draw_date, dtype: int64
3 2
2 1
1 1
Name: draw_date, dtype: int64
上边的循环代码可以用agg
替代
import datetime
df.groupby('weixin_id').agg(
lambda group:
((group.shift(1) + datetime.timedelta(1)) != group).cumsum().value_counts().max()
)
draw_date | |
---|---|
weixin_id | |
639062248681259008 | 5 |
751478029716439040 | 2 |
前后数据比较也可直接使用diff
函数,该函数可算出前后两条数据相减的结果
df.groupby('weixin_id').agg(
lambda group :
group.diff(1).map(
lambda d:d.days - 1).fillna(0).cumsum().value_counts().max()
)
draw_date | |
---|---|
weixin_id | |
639062248681259008 | 5 |
751478029716439040 | 2 |
参考文档
Pandas计算最大连续间隔时间
https://blog.yjll.blog/post/15886092.html