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

Pandas大数据集下字典别名模糊匹配生成新列的性能优化问询

针对Pandas大数据集模糊匹配的优化方案

首先,你的原代码在大数据集下变慢的核心原因是嵌套的Python循环+逐行处理——iterrows()本身效率就很低,再加上每个行要遍历所有客户及其别名,时间复杂度是O(nmk)(n是行数,m是客户数,k是别名数量),数据量上来后肯定会卡顿。下面给你几个实用的优化方案,能大幅提升处理速度:

优化方案一:用预编译正则+Pandas矢量化操作(最推荐)

利用Pandas的矢量化字符串方法(底层是C实现)替代Python循环,同时预编译正则表达式减少重复计算,这是提升效率最明显的方式。

步骤说明:

  1. 把每个客户的别名集合转换成预编译的正则表达式,用|连接所有别名,忽略大小写。
  2. 对每个数据块,统一处理Business Name列的字符串转换(避免重复操作)。
  3. 用str.contains()批量匹配正则,一次性更新符合条件的行,替代逐行赋值。

优化后代码:

import pandas as pd
from pathlib import Path
import re
import os

def create_aggregate_names(workbook: str, names: dict, sheet: str) -> None:
    # 处理输入文件,CSV分块读取,Excel也建议分块(如果文件很大)
    if '.xlsx' in workbook:
        # 读取Excel时也可以分块,避免内存溢出
        chunks = pd.read_excel(workbook, sheet_name=sheet, chunksize=100000)
    else:
        chunks = pd.read_csv(workbook, sep='|', encoding='latin-1', 
                             warn_bad_lines=True, error_bad_lines=False, chunksize=100000)
    
    path = Path(workbook).parents[0]
    output_file = f"{path}/data.csv"
    # 提前构建正则映射:客户名 -> 预编译正则(避免重复编译)
    regex_mapping = {}
    for customer, data in names.items():
        aliases = data["aliases"]
        # 转义别名中的特殊字符,避免正则语法冲突,然后用|连接
        pattern = '|'.join(re.escape(alias.lower()) for alias in aliases)
        regex_mapping[customer] = re.compile(pattern, re.IGNORECASE)
    
    # 处理每个数据块
    for idx, chunk in enumerate(chunks):
        # 初始化新列,默认值为原Business Name
        if "Aggregate Business Name" not in chunk.columns:
            chunk["Aggregate Business Name"] = chunk["Business Name"].astype(str)
        
        # 统一转换为小写字符串,避免重复操作
        business_names = chunk["Business Name"].astype(str).str.lower()
        
        # 批量匹配每个客户的正则,更新对应行
        for customer, regex in regex_mapping.items():
            # 找到匹配的行,批量赋值
            mask = business_names.str.contains(regex)
            chunk.loc[mask, "Aggregate Business Name"] = customer
        
        # 写入CSV:第一次写入加表头,后续追加不加
        chunk.to_csv(output_file, sep='|', index=False, mode='a', 
                     header=not os.path.exists(output_file) or idx == 0)

优化方案二:用Dask处理超大规模数据集(内存不足时用)

如果你的数据集大到Pandas无法一次性加载到内存(比如数亿行),可以用Dask DataFrame——它支持并行分块处理,语法和Pandas几乎一致,能充分利用多核CPU。

示例代码:

import dask.dataframe as dd
from pathlib import Path
import re

def create_aggregate_names_dask(workbook: str, names: dict, sheet: str) -> None:
    path = Path(workbook).parents[0]
    output_file = f"{path}/data.csv"
    
    # 用Dask读取文件,自动分块
    if '.xlsx' in workbook:
        df = dd.read_excel(workbook, sheet_name=sheet)
    else:
        df = dd.read_csv(workbook, sep='|', encoding='latin-1', 
                         warn_bad_lines=True, error_bad_lines=False)
    
    # 构建正则映射
    regex_mapping = {}
    for customer, data in names.items():
        aliases = data["aliases"]
        pattern = '|'.join(re.escape(alias.lower()) for alias in aliases)
        regex_mapping[customer] = re.compile(pattern, re.IGNORECASE)
    
    # 定义匹配函数,Dask会并行应用到每个分块
    def map_aggregate_name(name):
        name_str = str(name).lower()
        for customer, regex in regex_mapping.items():
            if regex.search(name_str):
                return customer
        return str(name)
    
    # 生成新列,指定数据类型
    df["Aggregate Business Name"] = df["Business Name"].apply(
        map_aggregate_name, meta=('Aggregate Business Name', 'str')
    )
    
    # 保存为单一CSV文件
    df.to_csv(output_file, sep='|', index=False, single_file=True)

关键优化点总结

  • 避免iterrows():Pandas的矢量化方法(如str.contains)比Python循环快10~100倍,底层是C实现,没有Python循环的 overhead。
  • 预编译正则:正则表达式只编译一次,避免每次匹配都重新解析语法。
  • 减少重复字符串操作:提前把Business Name转成小写,避免在循环中重复转换。
  • 批量赋值:用loc[mask]替代at[index],一次性更新所有匹配行,效率更高。
  • 处理表头重复:写入CSV时判断是否需要添加表头,避免输出文件重复表头。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:48:41