如何解决Python处理地址匹配时的exit code 137错误?
解决地址匹配时的内存不足(SIGKILL)问题
你遇到的exit code 137确实是内存耗尽导致系统强制终止进程。核心问题出在两个关键环节:
- 虽然用Dask读取了300万条的
business_rates.csv,但list(df.address)直接把所有地址全量加载到内存,完全浪费了Dask的分块优势 process.cdist对1000条参考地址和300万条主地址计算相似度矩阵,会生成1000×300万的巨型数组,光是存储这个数组就需要几十GB内存,直接撑爆内存
下面是针对性的优化方案:
1. 先按邮编缩小匹配范围(最有效)
地址匹配时,相同邮编的地址才具备匹配可能,先按邮编过滤能把匹配范围缩小几个数量级:
- 给主数据和参考数据都提取并标准化邮编(统一大小写、去除空格)
- 按邮编分组,只在同一邮编组内做地址相似度匹配
2. 不要一次性加载全量主数据到内存
用Pandas分块读取主数据,每次只处理一小块,或者用Dask的分块特性并行处理:
import pandas as pd from rapidfuzz import process, fuzz import time # 读取参考数据并按邮编分组 ref_df = pd.read_csv('all_food_hygiene_data_clean_up.csv') ref_df['post_code_clean'] = ref_df['post_code'].str.strip().str.upper() ref_groups = ref_df.groupby('post_code_clean') # 分块读取主数据,每次处理10万条 chunk_size = 100000 results = [] start = time.time() print("start time:", time.ctime(start)) for chunk in pd.read_csv('business_rates.csv', chunksize=chunk_size, low_memory=False): # 从主地址中提取并标准化邮编 chunk['post_code_clean'] = chunk['address'].str.extract(r'([A-Z]{1,2}[0-9][A-Z0-9]? ?[0-9][A-Z]{2})', expand=False) chunk['post_code_clean'] = chunk['post_code_clean'].str.strip().str.upper() # 遍历每个邮编组,只在同邮编内做匹配 for post_code, ref_group in ref_groups: if post_code not in chunk['post_code_clean'].unique(): continue # 提取当前邮编下的主地址和参考地址 chunk_addresses = chunk[chunk['post_code_clean'] == post_code]['address'].tolist() ref_addresses = ref_group['ref_address'].unique().tolist() # 批量匹配,只保留最高分结果 for ref_addr in ref_addresses: matches = process.extractOne(ref_addr, chunk_addresses, scorer=fuzz.token_sort_ratio, score_cutoff=70) if matches: results.append({ 'ref_address': ref_addr, 'matched_address': matches[0], 'score': matches[1], 'post_code': post_code }) # 合并结果并保存 results_df = pd.DataFrame(results) final_df = pd.merge(ref_df, results_df, how='left', on='ref_address') final_df.to_csv('results.csv', index=False) end = time.time() print("end time:", time.ctime(end))
3. 优化RapidFuzz计算参数
- 提高
score_cutoff的值(比如70),过滤低匹配分的结果,减少计算量和内存占用 - 不要用
workers=-1,限制线程数避免内存竞争 - 用
process.extractOne代替cdist,只获取每个参考地址的最高分匹配,不需要生成全量相似度矩阵
4. 用Dask实现并行处理
如果需要处理全量数据,可利用Dask的map_partitions并行处理每个分区:
import dask.dataframe as dd from rapidfuzz import process, fuzz def match_partition(partition, ref_addresses): matches = [] for addr in partition['address']: best_match = process.extractOne(addr, ref_addresses, scorer=fuzz.token_sort_ratio, score_cutoff=70) if best_match: matches.append({ 'original_address': addr, 'matched_ref_address': best_match[0], 'score': best_match[1] }) return pd.DataFrame(matches) # 读取数据 ref_df = pd.read_csv('all_food_hygiene_data_clean_up.csv') ref_addresses = ref_df['ref_address'].unique().tolist() df = dd.read_csv('business_rates.csv', low_memory=False) # 并行处理每个分区 matches_df = df.map_partitions(match_partition, ref_addresses, meta={ 'original_address': str, 'matched_ref_address': str, 'score': float }) # 保存结果 matches_df.compute().to_csv('dask_matches.csv', index=False)
关键注意点
- 永远不要把大Dask DataFrame转成list或Pandas DataFrame,这会把全量数据加载到内存
- 地址匹配前先做数据清洗:统一大小写、去除多余空格、标准化街道名称(比如把"St."改成"Street"),能提高匹配准确率和速度
- 如果内存仍然紧张,可以考虑增加机器内存,或者使用高内存云服务器实例
内容的提问来源于stack exchange,提问作者Kelly Tang
相关产品推荐
相关产品推荐

