如何实现按卡号+门店的Rolling Count滚动计数并优化性能
实现按卡号+门店维度的滚动历史交易计数(高性能版)
原始交易数据集
| transaction_ID | card_number | transaction_datetime | amount | store |
|---|---|---|---|---|
| 1 | 123 | 2023-06-24 12:20:24 | 100.0 | A |
| 2 | 456 | 2023-08-27 23:12:00 | 250.0 | B |
| 3 | 123 | 2023-09-02 09:00:03 | 416.12 | A |
| 4 | 123 | 2023-09-02 10:30:03 | 6580.0 | C |
现有按卡号的滚动计数函数
def rolling_count(df, freq): return (df.set_index("transaction_datetime") .groupby("card_number")["card_number"] .rolling(freq, closed="left") .count() .fillna(0) .values)
调用方式:
df["number_transactions_lastday"] = rolling_count(df, "1D")
需求说明
需要新增rolling_count_store函数,统计同卡号+同门店维度下,当前交易指定时间范围内的历史交易数,调用方式如下:
df["number_tr_store_last6m"] = rolling_count_store(df, "180D") # 6个月≈180天
期望输出数据集:
| transaction_ID | card_number | transaction_datetime | amount | store | number_tr_store_last6m |
|---|---|---|---|---|---|
| 1 | 123 | 2023-06-24 12:20:24 | 100.0 | A | 0 |
| 2 | 456 | 2023-08-27 23:12:00 | 250.0 | B | 0 |
| 3 | 123 | 2023-09-02 09:00:03 | 416.12 | A | 1 |
| 4 | 123 | 2023-09-02 10:30:03 | 6580.0 | C | 0 |
同时要求代码具备高性能,适配大规模数据集。
高性能解决方案
核心思路是将分组维度扩展为card_number + store组合,同时通过预排序优化计算效率:
import pandas as pd def rolling_count_store(df, freq): # 确保时间列是datetime类型 df = df.copy() df["transaction_datetime"] = pd.to_datetime(df["transaction_datetime"]) # 按分组键+时间排序,提升滚动窗口计算性能 sorted_df = df.sort_values(["card_number", "store", "transaction_datetime"]) # 按卡号+门店分组执行滚动计数,最后恢复原始索引顺序 return (sorted_df.set_index("transaction_datetime") .groupby(["card_number", "store"])["transaction_ID"] .rolling(freq, closed="left") .count() .fillna(0) .reindex(df.index) .values)
关键优化点
- 组合分组:用
["card_number", "store"]作为分组键,精准限定同卡号同门店的统计范围 - 预排序:提前按分组键+时间排序,避免滚动窗口计算时的无序遍历,大幅提升大数据集处理速度
- 严谨计数:使用
transaction_ID作为计数列,避免卡号为空的异常情况 - 索引对齐:通过
reindex确保输出结果与原始DataFrame的行顺序完全匹配
调用示例
df["number_tr_store_last6m"] = rolling_count_store(df, "180D")
内容的提问来源于stack exchange,提问作者shadowpaprika
相关产品推荐
相关产品推荐

