如何高效匹配DataFrame中的值?百万级数据集优化方案问询
百万级数据集多条件匹配的高效优化方案
问题背景
我有个百万行级的大型数据集,需要基于多条件和另外两个数据集做值匹配。现在用for循环+dataframe.iterrows()实现,但数据量上来后速度极慢,想找更高效的方法。
数据表示例
数据集A
| Name | Gender | Responsible | Function | DateLabel | Store |
|---|---|---|---|---|---|
| Bob D | M | Mike M | Worker | Jun-20 | 122 |
| Mike L | M | Josh J | Manager | Apr-21 | 133 |
| Diana V | F | Christine | Manager | Apr-23 | 133 |
数据集B
| Resp Name | Dpt |
|---|---|
| Mike M | Ops |
| Josh J | Logistics |
| Christine | Legal |
数据集C
| Resp Name | Store | Date |
|---|---|---|
| Mike M | 122 | Jun-20 |
| Mike M | 122 | Jun-21 |
| Mike M | 122 | Apr-22 |
| Christine | 133 | Apr-23 |
| Christine | 133 | Apr-21 |
匹配规则
- 核心匹配:A的
Responsible与B的Resp Name一致时,将B的Dpt关联到A的数据中 - 额外条件:若该
Responsible同时存在于C中,必须额外满足A的DateLabel等于C的Date、A的Store等于C的Store,才关联Dpt
现有低效代码
elist=[] for i, col in A.iterrows(): for ix, c in B.iterrows(): if col["Resp"] == c["Resp. Name"] and col["Name"] not in elist and c["Resp name"] not in C: elist.append([col["Name"], col["Gender"], ..., c["Dpt"]]) elif col["Resp"] == c["Resp. Name"] and col["Name"] in elist and c["Resp name"] in C: for n, x in c.iterrows(): if c["resp name"] == x["Resp name"] and col["store"] == x["Store"] and col["DateLabel"] == x["date"]: elist.append([col["Name"], col["Gender"], ..., c["Dpt"]])
高效优化方案
思路:用Pandas内置合并函数替代循环
Pandas的merge是基于底层C实现的向量化操作,比Python层面的循环效率高几个数量级,完全适配百万级数据场景。
步骤1:统一关键列名
先对齐各数据集的匹配键列名,避免匹配出错:
import pandas as pd # 重命名列,统一匹配键 B = B.rename(columns={"Resp Name": "Responsible"}) C = C.rename(columns={"Resp Name": "Responsible", "Date": "DateLabel"})
步骤2:提取C的有效匹配组合
先提取C中满足条件的唯一记录组合,用于后续过滤:
# 提取C中(Responsible, Store, DateLabel)的唯一匹配组 c_valid_matches = C[["Responsible", "Store", "DateLabel"]].drop_duplicates()
步骤3:分场景合并数据
将匹配逻辑拆分为两种场景,分别处理后合并结果:
# 场景1:Responsible不在C中,直接关联B的Dpt case1 = A[~A["Responsible"].isin(C["Responsible"])].merge(B, on="Responsible", how="left") # 场景2:Responsible在C中,需先匹配Store和DateLabel,再关联Dpt case2 = A[A["Responsible"].isin(C["Responsible"])]\ .merge(c_valid_matches, on=["Responsible", "Store", "DateLabel"], how="inner")\ .merge(B, on="Responsible", how="left") # 合并两个场景的结果 final_df = pd.concat([case1, case2], ignore_index=True)
步骤4:保留A全量数据的优化(可选)
如果需要保留A的所有记录(即使匹配失败),可以调整合并逻辑:
# 先标记A中哪些行能在C中匹配到Store和DateLabel temp_df = A.merge(c_valid_matches, on=["Responsible", "Store", "DateLabel"], how="left", indicator=True) temp_df["has_c_match"] = temp_df["_merge"] == "both" # 关联B的Dpt,同时对C中未匹配成功的行清空Dpt temp_df = temp_df.merge(B, on="Responsible", how="left") temp_df.loc[temp_df["has_c_match"] & (temp_df["_merge"] != "both"), "Dpt"] = None # 清理临时列 final_df = temp_df.drop(columns=["_merge", "has_c_match"])
性能优势
- 完全避免三层嵌套循环,利用Pandas向量化计算,百万级数据处理时间从小时级压缩到分钟/秒级
- 内置
merge会自动优化内存占用和计算逻辑,远优于手动循环的资源利用率
内容的提问来源于stack exchange,提问作者NoobQuestions1
相关产品推荐
相关产品推荐

