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

如何在Python中高效对比大数据集单列的每行与其他行?

高效实现DataFrame中字符串两两对比并生成相似度得分

问题背景

现有包含unique_id和id_string两列的DataFrame:

unique_idid_string
123abc
456pqr
789xyz
000lmn

需要将每个unique_id对应的id_string与其他所有id_string对比,生成包含相似度得分的结果,格式如下:

unique_idid_stringduplicate_idduplicate_stringscore
123abc456pqr91
123abc789xyz92
123abc000lmn93

原代码采用双重循环+DataFrame.append的方式,在50万行数据集下运行效率极低,需基于itertools.combinations进行优化。

原低效代码

out_put_df = pd.DataFrame()
for i in   input_df.index:
    unique_id = input_df.at[i, 'unique_id']
    id_string = input_df.at[i, 'id_string']
    j = i+1
    for j in range(len(input_df.index)-j):
        dupicate_id = input_df.at[j, 'unique_id']
        duplicate_string = input_df.at[j, 'id_string']
        comparition_score = fuzz.token_set_ratio(id_string, duplicate_string)
        out_put_df = out_put_df.append(pd.DataFrame({'unique_id': unique_id,'id_string': id_string,'dupicate_id': dupicate_id,'duplicate_string': duplicate_string,'comparition_score': comparition_score}, index=[0]), ignore_index=True)

优化方案

1. 基于itertools.combinations的基础优化

itertools.combinations可直接生成所有不重复的两两索引对(避免重复计算A-B和B-A),配合列表存储结果(替代循环中append),大幅提升效率。

import pandas as pd
from itertools import combinations
from fuzzywuzzy import fuzz

# 生成所有i<j的索引对,避免重复对比
index_pairs = combinations(input_df.index, 2)

# 用列表存储结果,避免循环中频繁创建DataFrame
results = []

for idx1, idx2 in index_pairs:
    row1 = input_df.loc[idx1]
    row2 = input_df.loc[idx2]
    
    # 计算相似度得分
    score = fuzz.token_set_ratio(row1['id_string'], row2['id_string'])
    
    # 添加双向记录(匹配输出示例的格式)
    results.append({
        'unique_id': row1['unique_id'],
        'id_string': row1['id_string'],
        'duplicate_id': row2['unique_id'],
        'duplicate_string': row2['id_string'],
        'score': score
    })
    results.append({
        'unique_id': row2['unique_id'],
        'id_string': row2['id_string'],
        'duplicate_id': row1['unique_id'],
        'duplicate_string': row1['id_string'],
        'score': score
    })

# 一次性转换为DataFrame
output_df = pd.DataFrame(results)

2. 超大数据集(50万行)的进阶优化

50万行数据的两两组合数约为1.25×10¹¹,直接计算完全不现实,需结合分块处理+高速相似度库调整方案:

  • 用RapidFuzz替代FuzzyWuzzy:前者是后者的C语言重写版本,速度提升数十倍;
  • 分块处理:将数据集拆分为小块,逐块与其他部分对比,降低内存占用;
  • 可选:仅保留相似度高于阈值的结果,减少输出数据量。
import pandas as pd
from rapidfuzz import fuzz, process

# 设置分块大小,根据内存调整
chunk_size = 1000
results = []

for i in range(0, len(input_df), chunk_size):
    chunk = input_df.iloc[i:i+chunk_size]
    for idx1, row1 in chunk.iterrows():
        # 排除当前行,获取其他所有行
        other_rows = input_df.drop(idx1)
        # 批量计算当前字符串与其他所有字符串的相似度
        scores = process.extract(row1['id_string'], other_rows['id_string'], 
                                scorer=fuzz.token_set_ratio, limit=None)
        
        # 整理结果
        for match_str, score, idx2 in scores:
            row2 = other_rows.loc[idx2]
            results.append({
                'unique_id': row1['unique_id'],
                'id_string': row1['id_string'],
                'duplicate_id': row2['unique_id'],
                'duplicate_string': row2['id_string'],
                'score': score
            })

output_df = pd.DataFrame(results)

核心优化点

  • 禁止循环中使用DataFrame.append:每次append都会生成新的DataFrame,时间复杂度极高,改用列表存储字典后一次性转换;
  • 用combinations减少循环层级:直接生成所有需要的对比对,代码更简洁,避免嵌套循环的冗余;
  • 替换相似度计算库:RapidFuzz在保持API兼容的前提下,性能远超FuzzyWuzzy;
  • 分块处理:针对超大数据集,分块可有效控制内存使用,避免内存溢出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 10:40:48