如何为Pandas时序数据框按购买日期枚举用户购买顺序?
高效生成客户购买次序列的Pandas方案
问题场景
现有存储客户购买记录的Pandas数据框,结构如下:
| cli_id(客户ID) | date(日期) | item_purchased(购买商品) |
|---|---|---|
| 1 | 2017-01-01 | A |
| 2 | 2017-01-04 | C |
| 3 | 2017-01-03 | B |
| 1 | 2017-02-01 | B |
| 2 | 2017-01-31 | B |
| 3 | 2017-02-02 | A |
| 1 | 2017-02-15 | A |
| 2 | 2017-02-10 | A |
| 3 | 2017-02-16 | C |
| 2 | 2017-02-20 | B |
需要新增purchase_order列,标记每位客户的购买次序(按日期排序后的第1、2、3...次购买),最终输出如下:
| cli_id(客户ID) | date(日期) | item_purchased(购买商品) | purchase_order(购买顺序) |
|---|---|---|---|
| 1 | 2017-01-01 | A | 1 |
| 2 | 2017-01-04 | C | 1 |
| 3 | 2017-01-03 | B | 1 |
| 1 | 2017-02-01 | B | 2 |
| 2 | 2017-01-31 | B | 2 |
| 3 | 2017-02-02 | A | 2 |
| 1 | 2017-02-15 | A | 3 |
| 2 | 2017-02-10 | A | 3 |
| 3 | 2017-02-16 | C | 3 |
| 2 | 2017-02-20 | B | 4 |
原循环实现代码速度较慢,代码如下:
list_cli_id = [1,2,3,1,2,3,1,2,3,2] list_dates = ['2017-01-01', '2017-01-04', '2017-01-03', '2017-02-01', '2017-01-31', '2017-02-02', '2017-02-15', '2017-02-10', '2017-02-16', '2017-02-20'] list_item_purchased = ['A','C','B','B','B','A','A','A','C','B'] df = pd.DataFrame({'cli_id': list_cli_id, 'date': list_dates, 'item_purchased': list_item_purchased}) df['date'] = pd.to_datetime(df['date']) first = True for id in df['cli_id'].unique(): if first: df_order = df[df['cli_id'] == id].sort_values(by='date').reset_index().reset_index() else: df_order = df_order.append(df[df['cli_id'] == id].sort_values(by='date').reset_index().reset_index(), ignore_index=True) first = False df_order = df_order.rename(columns={"level_0": "purchase_order"}).drop('index', axis=1)
高效实现方案
利用Pandas的分组、排序和矢量化计数功能,完全替代循环,大幅提升效率,代码更简洁:
完整优化代码
list_cli_id = [1,2,3,1,2,3,1,2,3,2] list_dates = ['2017-01-01', '2017-01-04', '2017-01-03', '2017-02-01', '2017-01-31', '2017-02-02', '2017-02-15', '2017-02-10', '2017-02-16', '2017-02-20'] list_item_purchased = ['A','C','B','B','B','A','A','A','C','B'] df = pd.DataFrame({'cli_id': list_cli_id, 'date': list_dates, 'item_purchased': list_item_purchased}) df['date'] = pd.to_datetime(df['date']) # 按客户ID和日期排序,确保同一客户的记录按时间先后排列 df_sorted = df.sort_values(by=['cli_id', 'date']) # 为每个客户的购买记录生成从1开始的次序 df_sorted['purchase_order'] = df_sorted.groupby('cli_id').cumcount() + 1 # 可选:如果需要恢复原数据的行顺序 df_final = df_sorted.sort_index()
核心逻辑说明
sort_values(['cli_id', 'date']):先按客户ID分组,再按日期排序,保证每个客户的购买记录按时间顺序排列。groupby('cli_id').cumcount() + 1:对每个客户的分组内记录进行计数,cumcount()默认从0开始,加1后得到从1开始的购买次序,完全匹配需求。- 避免了低效的循环和
append操作:append在大数据量下性能极差,而矢量化操作能利用Pandas的底层优化,速度提升数倍甚至数十倍。
后续统计各次购买的众数
生成purchase_order列后,可直接按该列分组统计商品众数:
# 统计各次购买的商品众数 mode_by_order = df_sorted.groupby('purchase_order')['item_purchased'].agg(pd.Series.mode)
内容的提问来源于stack exchange,提问作者Pere Munar
相关产品推荐
相关产品推荐

