基于DataFrame阈值为另一DataFrame高效打标签的实现方案
高效实现Pandas DataFrame按分类区间打标签(1000万行数据优化)
方案一:适用于每个分类对应唯一区间的场景
这是最高效的场景,完全通过矢量化操作替代逐行循环:
import pandas as pd # 先确保df1的分类键唯一(避免多对多合并产生冗余数据) df1 = df1.drop_duplicates(subset=['Category A', 'Category B']) # 仅合并必要字段:分类、区间阈值、标签 merged = df2.merge( df1[['Category A', 'Category B', 'Lower Bound', 'Upper Bound', 'Label']], on=['Category A', 'Category B'], how='left' ) # 矢量化判断Value是否在区间内,提取对应Label(可通过inclusive参数调整区间开闭) df2['Label'] = merged['Label'].where( merged['Value'].between(merged['Lower Bound'], merged['Upper Bound'], inclusive='both') )
效率优势
- 彻底规避
apply/iterrows的Python级逐行循环,全部用Pandas底层C实现的矢量化操作 - 合并采用优化后的哈希连接,比循环匹配效率高几个数量级
方案二:适用于单个分类对应多个区间的场景
如果同一个(Category A, Category B)存在多个阈值区间,可通过合并+筛选实现:
# 合并所有分类-区间组合 merged = df2.merge( df1[['Category A', 'Category B', 'Lower Bound', 'Upper Bound', 'Label']], on=['Category A', 'Category B'], how='left' ) # 筛选符合区间条件的记录 mask = merged['Value'].between(merged['Lower Bound'], merged['Upper Bound'], inclusive='both') matched_labels = merged[mask][['id', 'Label']] # 将匹配标签映射回原df2 df2 = df2.merge(matched_labels, on='id', how='left')
可选优化
如果区间存在重叠,可给df1添加优先级列,筛选时按优先级排序后取第一条匹配结果。
为什么你之前的merge没提速?
大概率是以下问题导致:
- df1存在重复分类键:合并后产生大量冗余行,拖慢后续操作,先执行
df1.drop_duplicates(subset=['Category A', 'Category B'])去重 - 合并了不必要的列:比如df1的
id列,增加内存占用和合并时间,只保留需要的字段即可 - 未用矢量化判断:合并后仍用循环筛选,浪费了merge的性能优势
性能参考
针对1000万行df2 + 1万条分类规则的df1:
- 原
apply+iterrows方法:预计耗时数十分钟 - 方案一:预计耗时10-30秒(取决于硬件配置)
内容的提问来源于stack exchange,提问作者samodle
相关产品推荐
相关产品推荐

