You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Fuzzywuzzy处理百万级Excel数据匹配过慢的优化求助

百万级Excel数据模糊匹配优化方案

问题背景

用户拥有一个50MB以上的.xlsx文件,包含Sheet A和Sheet B两个工作表,Sheet A存有数百万条记录,需要将Sheet A的「Entity Name」列与Sheet B的7个「name」列做模糊匹配。原Python脚本运行超20小时仍无结果,需优化运行速度并输出指定格式的匹配结果。

原代码核心性能瓶颈

  • 遍历效率极差:用嵌套列表推导式对每个A列元素遍历所有B列去重元素,时间复杂度为O(M*N)(M是A列行数,N是B列去重后数据量),百万级数据下完全无法承受。
  • 未充分利用数据源:原代码仅提取Sheet B第一个「name」列的去重值,忽略了另外6个「name」列的数据,导致匹配数据源不完整。
  • 模糊匹配库效率低:fuzzywuzzy的纯Python实现对大规模数据计算速度慢,未使用底层优化版本。

针对性优化方案

1. 完整提取Sheet B的所有name列并去重

先把Sheet B中7个name列全部提取合并,生成无重复的匹配数据源,确保匹配范围完整的同时减少重复计算:

# 筛选Sheet B中所有名为name的列
all_name_cols = [col for col in dataframe2.columns if col == 'name']
# 合并所有name列、剔除空值并去重
B_cleaned = dataframe2[all_name_cols].stack().dropna().unique().tolist()

2. 替换Fuzzywuzzy为RapidFuzz

RapidFuzz是Fuzzywuzzy的C++重写版本,计算速度提升10-100倍,API完全兼容,直接替换即可:

# 先安装依赖
pip install rapidfuzz pandas openpyxl

代码中替换导入语句:

from rapidfuzz import fuzz, process

3. 用批量匹配替代嵌套遍历

RapidFuzz的process.extractOne专门用于单元素的最优匹配,比手动嵌套遍历高效得多;数据量极大时还可使用多进程加速:

基础单进程优化

# 批量获取每个A列元素的最优匹配结果
tuples_list = [process.extractOne(i, B_cleaned, scorer=fuzz.token_set_ratio) for i in A_cleaned]
# 拆分结果:匹配值、分数、匹配索引(索引可忽略)
fuzzy_match, similarity_score, _ = map(list, zip(*tuples_list))

进阶多进程优化(适配百万级数据)

利用concurrent.futures开启多进程,充分利用CPU多核能力:

from concurrent.futures import ProcessPoolExecutor

def match_single_entity(entity):
    """单个实体的匹配函数,用于多进程调用"""
    result = process.extractOne(entity, B_cleaned, scorer=fuzz.token_set_ratio)
    return (result[0], result[1])

# 自动根据CPU核心数设置进程数
with ProcessPoolExecutor() as executor:
    results = list(executor.map(match_single_entity, A_cleaned))

fuzzy_match, similarity_score = map(list, zip(*results))

4. 优化Excel读写速度

  • 读取大Excel时,指定openpyxl引擎(xlsx格式默认);
  • 写入结果优先用CSV格式(读写速度远快于Excel),如需Excel格式可再转存:
# 先写入CSV(速度更快)
df.to_csv("C:/Users/Downloads/fuz-match-output.csv", index=False)
# 按需转存为Excel格式
pd.read_csv("C:/Users/Downloads/fuz-match-output.csv").to_excel("C:/Users/Downloads/fuz-match-output.xlsx", sheet_name="匹配结果", index=False)

5. 统一字符串预处理(可选)

对所有匹配字符串做标准化处理,既能提升匹配精度,也能减少无效计算:

import re

def clean_string(s):
    # 转小写、去除特殊字符、合并连续空格
    s = s.lower().strip()
    s = re.sub(r'[^\w\s]', '', s)
    s = re.sub(r'\s+', ' ', s)
    return s

# 预处理A、B列的字符串
A_cleaned = [clean_string(df1) for df1 in dataframe1["Entity Name"].dropna()]
B_cleaned = [clean_string(name) for name in dataframe2[all_name_cols].stack().dropna().unique()]

完整优化代码

import pandas as pd
from rapidfuzz import fuzz, process
from concurrent.futures import ProcessPoolExecutor
import re

def clean_string(s):
    """统一字符串预处理函数"""
    s = s.lower().strip()
    s = re.sub(r'[^\w\s]', '', s)
    s = re.sub(r'\s+', ' ', s)
    return s

def match_single_entity(entity):
    """单个实体的匹配逻辑,用于多进程调用"""
    result = process.extractOne(entity, B_cleaned, scorer=fuzz.token_set_ratio)
    return (result[0], result[1])

if __name__ == "__main__":
    filename = 'C:/Users/Downloads/SUniverse.xlsx'
    
    # 读取Excel工作表
    dataframe1 = pd.read_excel(filename, sheet_name='A', engine='openpyxl')
    dataframe2 = pd.read_excel(filename, sheet_name='B', engine='openpyxl')
    
    # 处理Sheet A:提取并清理Entity Name列
    raw_A = dataframe1["Entity Name"].dropna()
    A_cleaned = [clean_string(name) for name in raw_A]
    
    # 处理Sheet B:合并所有name列、去重并清理
    all_name_cols = [col for col in dataframe2.columns if col == 'name']
    raw_B = dataframe2[all_name_cols].stack().dropna().unique()
    B_cleaned = [clean_string(name) for name in raw_B]
    
    # 多进程批量执行匹配
    with ProcessPoolExecutor() as executor:
        results = list(executor.map(match_single_entity, A_cleaned))
    
    # 整理成要求的结果格式
    fuzzy_match, similarity_score = map(list, zip(*results))
    df = pd.DataFrame({
        "Entity Name": raw_A.tolist(),
        "Name": fuzzy_match,
        "fuzzy score": similarity_score
    })
    
    # 输出结果文件
    df.to_csv("C:/Users/Downloads/fuz-match-output.csv", index=False)
    df.to_excel("C:/Users/Downloads/fuz-match-output.xlsx", sheet_name="匹配结果", index=False, engine='openpyxl')
    
    print('匹配完成!')

内容的提问来源于stack exchange,提问作者technophile_3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 03:25:20