Pandas如何高效实现两个CSV文件间的数据匹配查找提升处理速度
问题背景
现有两类CSV数据用于地图坐标匹配:
crq_data:存储用户上传*.csv文件中的城市、州字段数据cityCoordinates.csv:美国城市、州及对应经纬度坐标的基准库,作为查找数据源匹配用户上传数据的对应坐标,供Folium地图绘制使用
当前代码采用逐行嵌套循环的匹配逻辑,逐行追加坐标数据,单条匹配耗时约n秒,数据量达到6000行时用户需要等待数千秒才能完成处理,运行效率极低,同时原有代码还存在赋值逻辑错误,需要优化。
原有问题代码
crq_file = askopenfilename(filetypes=[('CSV Files', '*csv')]) crq_data = pd.read_csv(crq_file, encoding="utf8") coords = pd.read_csv("cityCoordinates.csv") for crq in range(len(crq_data)): task_city = crq_data.iloc[crq]["TaskCity"] task_state = crq_data.iloc[crq]["TaskState"] for coordinates in range(len(coords)): cityCoord = coords.iloc[coordinates]["City"] stateCoord = coords.iloc[coordinates]["State"] latCoord = coords.iloc[coordinates]["Latitude"] lngCoord = coords.iloc[coordinates]["Longitude"] if task_city == cityCoord and task_state == stateCoord: crq_data["CRQ Latitude"] = latCoord crq_data["CRQ Longitude"] = lngCoord print(cityCoord, stateCoord, latCoord, lngCoord)
原有代码除了性能问题,还存在逻辑bug:匹配到坐标后给
crq_data["CRQ Latitude"]、crq_data["CRQ Longitude"]赋值是整列覆盖操作,不是给当前行赋值,最终所有行的坐标都会被最后一次匹配到的结果覆盖,完全不符合预期。
优化方案
核心思路是抛弃时间复杂度为O(n*m)的双层嵌套循环,用pandas内置的表连接能力一次性完成全量匹配,时间复杂度降到O(n+m),6000行数据可在百毫秒级完成处理,同时修复原有赋值逻辑bug。
优化后代码
import pandas as pd from tkinter.filedialog import askopenfilename # 读取源数据 crq_file = askopenfilename(filetypes=[('CSV Files', '*csv')]) crq_data = pd.read_csv(crq_file, encoding="utf8") coords = pd.read_csv("cityCoordinates.csv") # 重命名坐标库字段,和业务表关联字段对齐 coords_aligned = coords.rename(columns={ "City": "TaskCity", "State": "TaskState", "Latitude": "CRQ Latitude", "Longitude": "CRQ Longitude" }) # 【可选】预处理关联字段,避免大小写、前后空格导致匹配失败 for df in [crq_data, coords_aligned]: df["TaskCity"] = df["TaskCity"].str.strip().str.lower() df["TaskState"] = df["TaskState"].str.strip().str.lower() # 左连接一次性完成全量坐标匹配,未匹配到的记录坐标列自动为空 crq_data = crq_data.merge( coords_aligned[["TaskCity", "TaskState", "CRQ Latitude", "CRQ Longitude"]], on=["TaskCity", "TaskState"], how="left" ) # 打印所有匹配成功的记录 matched_records = crq_data.dropna(subset=["CRQ Latitude", "CRQ Longitude"]) for _, row in matched_records.iterrows(): print(row["TaskCity"], row["TaskState"], row["CRQ Latitude"], row["CRQ Longitude"])
优化点说明
- 性能提升:内置merge操作基于C实现,比Python层双层循环快3~4个数量级,万级以内数据处理无感知
- 逻辑修复:连接操作会自动给每一行匹配对应坐标,不会出现整列被覆盖的问题
- 鲁棒性提升:可选的字段预处理步骤可以解决因数据格式不一致(比如大小写差异、首尾多余空格)导致的匹配失败问题
- 可扩展性:后续如果需要新增匹配字段,只需要修改
on参数里的关联字段列表即可,不需要改动循环逻辑
内容的提问来源于stack exchange,提问作者Anna M
相关产品推荐
相关产品推荐

