Pandas:分组查询订单号的最长连续序列与末次连续序列
Pandas分组计算订单号最长连续序列与末次连续序列
先看我们的原始数据:
| user_id | product_id | order_number |
|---|---|---|
| 1 | 1 | 1 |
| 1 | 1 | 2 |
| 1 | 1 | 3 |
| 1 | 2 | 1 |
| 1 | 2 | 5 |
| 2 | 1 | 1 |
| 2 | 1 | 3 |
| 2 | 1 | 4 |
| 2 | 1 | 5 |
| 3 | 1 | 1 |
| 3 | 1 | 2 |
| 3 | 1 | 6 |
需求很明确:按user_id和product_id分组,计算两个核心指标:
longest_streak:order_number的最长连续无跳过序列长度(如果所有订单号都是孤立的,无连续序列,值为0)last_streak:从最后一个order_number往前数的连续段长度(若最后一个订单号没有前续连续值,值为0)
期望输出结果:
| user_id | product_id | longest_streak | last_streak |
|---|---|---|---|
| 1 | 1 | 3 | 3 |
| 1 | 2 | 0 | 0 |
| 2 | 1 | 3 | 3 |
| 3 | 1 | 2 | 0 |
实现思路与代码
我把整个实现拆成几个关键步骤,每一步都有明确的作用:
1. 准备数据并确保有序
首先要保证每个分组内的order_number是升序排列的,不然连续序列的判断会出错:
import pandas as pd # 构建原始DataFrame data = { 'user_id': [1,1,1,1,1,2,2,2,2,3,3,3], 'product_id': [1,1,1,2,2,1,1,1,1,1,1,1], 'order_number': [1,2,3,1,5,1,3,4,5,1,2,6] } df = pd.DataFrame(data) # 排序:按用户、商品、订单号升序 df = df.sort_values(['user_id', 'product_id', 'order_number']).reset_index(drop=True)
2. 标记连续序列分组
通过计算每个订单号与前一个的差值,判断是否属于同一个连续段:
# 计算当前订单号与前一个的差值 df['diff'] = df.groupby(['user_id', 'product_id'])['order_number'].diff() # 生成连续段ID:当差值不等于1时,视为新的连续段,用cumsum分配唯一ID df['segment_id'] = df.groupby(['user_id', 'product_id'])['diff'].apply(lambda x: (x != 1).cumsum())
比如用户1、商品1的订单号1、2、3,差值都是1,会被分到同一个segment_id;而订单号1和5的差值是4,会被分到不同的segment_id。
3. 计算每个连续段的长度
对每个(用户、商品、连续段)分组,统计该段内的订单数量:
df['streak_length'] = df.groupby(['user_id', 'product_id', 'segment_id'])['order_number'].transform('count')
4. 计算最长连续序列
取每个(用户、商品)分组中最大的段长度,若最大长度<=1,说明没有连续序列,设为0:
# 提取每个分组的最大段长度 longest = df.groupby(['user_id', 'product_id'])['streak_length'].max().reset_index() # 转换为符合需求的longest_streak longest['longest_streak'] = longest['streak_length'].apply(lambda x: x if x > 1 else 0) longest = longest.drop('streak_length', axis=1)
5. 计算末次连续序列
找到每个分组的最后一个连续段,判断其长度是否大于1,大于则保留长度,否则设为0:
# 获取每个分组的最后一个连续段ID last_segment = df.groupby(['user_id', 'product_id'])['segment_id'].last().reset_index() # 合并得到最后一个段的长度 last_streak_df = pd.merge( last_segment, df[['user_id', 'product_id', 'segment_id', 'streak_length']].drop_duplicates(), on=['user_id', 'product_id', 'segment_id'] ) # 转换为符合需求的last_streak last_streak_df['last_streak'] = last_streak_df['streak_length'].apply(lambda x: x if x > 1 else 0) last_streak_df = last_streak_df.drop(['segment_id', 'streak_length'], axis=1)
6. 合并结果得到最终输出
把最长和末次连续序列的结果合并起来:
result = pd.merge(longest, last_streak_df, on=['user_id', 'product_id']) print(result)
运行这段代码后,就能得到你期望的结果啦!
内容的提问来源于stack exchange,提问作者iLoeng
相关产品推荐
相关产品推荐

