咨询矩阵与DataFrame每行与其余行的高效比较方法(订单场景)
高效识别符合条件的订单对(避免O(n²)暴力比较)
看起来你现在卡在了暴力遍历所有订单对的低效问题上——16.6万行的话,两两比较就是2.7e10次操作,跑几天太正常了。咱们换个思路,利用pandas的向量化操作和时间序列工具,把复杂度降到O(n log n),几小时甚至几分钟就能搞定。
先明确需求:你要找的是Order Type不为Z,且下单时间在3天内的订单(默认按同一客户场景处理,毕竟有Customer Number列,不需要客户分组可直接调整)。
第一步:预处理数据
先过滤无效记录,确保日期格式正确(这步是时间计算的基础,不能省):
import pandas as pd # 读入你的订单数据(这里以CSV为例,其他格式同理) df = pd.read_csv('your_order_dataset.csv') # 过滤掉Order Type为Z的订单 df_filtered = df[df['Order Type'] != 'Z'].copy() # 将日期列转换为datetime类型,避免字符串操作的低效和错误 df_filtered['Date of Order'] = pd.to_datetime(df_filtered['Date of Order'])
方法一:分组+时间差计算(适合找连续的订单对)
按客户分组后排序,直接计算每个订单与同客户前一个订单的时间差,快速筛选符合条件的记录:
# 按客户+订单日期排序,保证同客户的订单按时间顺序排列 df_filtered = df_filtered.sort_values(['Customer Number', 'Date of Order']) # 计算每个订单与同客户上一个订单的天数间隔 df_filtered['days_since_last_order'] = df_filtered.groupby('Customer Number')['Date of Order'].diff().dt.days # 筛选出时间差≤3天的订单(这些订单和前一个订单就是目标配对) target_records = df_filtered[df_filtered['days_since_last_order'] <= 3] # 如果需要完整的订单对信息,将当前订单与前一个订单合并 order_pairs = pd.merge( target_records, df_filtered.shift(1), left_index=True, right_index=True, suffixes=('_later', '_earlier'), how='left' )
方法二:用merge_asof高效匹配时间范围内的订单
这是pandas专为时间序列匹配设计的工具,比分组diff更灵活,能找到某个订单时间前后3天内的所有匹配订单:
# merge_asof要求左右表必须按分组键和时间键排序 df_sorted = df_filtered.sort_values(['Customer Number', 'Date of Order']) # 自合并,找每个订单之前3天内的同客户订单 merged_result = pd.merge_asof( df_sorted, df_sorted, on='Date of Order', by='Customer Number', # 不需要客户分组的话直接删除这一行 suffixes=('_current', '_match'), tolerance=pd.Timedelta(days=3), direction='backward' # 找当前订单之前的匹配,要找之后的改direction='forward' ) # 去掉自身匹配的情况(自合并会默认把订单自己也匹配上) merged_result = merged_result[merged_result['Order Number_current'] != merged_result['Order Number_match']]
为什么这些方法高效?
暴力循环是O(n²)的复杂度,而上面的方法核心是排序(O(n log n))+ 线性遍历/合并(O(n)),16万行的排序在普通电脑上几秒就能完成,后续操作都是向量化的,完全不会出现跑几天的情况。如果数据量再大,还可以用Dask或PySpark做并行处理,但pandas本身的方法已经足够应对16万行的规模。
内容的提问来源于stack exchange,提问作者ALEX.VAMVAS
相关产品推荐
相关产品推荐

