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

如何高效检测同一列中姓名的相似度(大数据量场景)

高效姓名相似度匹配解决方案

核心思路:避免全量两两比对

全量交叉合并会生成约1.6亿条记录(40000²),完全超出内存承载能力,必须通过减少待比对配对数来解决问题。

1. 预分组(Blocking)

先按姓名的特征分组,仅在组内进行比对,大幅削减配对数量:

  • 按首字母/前n个字符分组:提取姓名的首字母或前几个字符作为分组键,只比对同组内的姓名
    from fuzzywuzzy import fuzz
    import pandas as pd
    
    df = pd.DataFrame(data = ['John','gal britt','mona','diana','molly','merry','mony','molla','johnathon','dina'], columns=['Name'])
    
    # 生成分组键:统一转为小写后取首字母
    df['block_key'] = df['Name'].str.lower().str[0]
    
    # 遍历组内生成配对并计算相似度
    results = []
    for key, group in df.groupby('block_key'):
        # 组内交叉合并并排除自身配对
        pairs = group.merge(group, on='block_key', suffixes=('_1', '_2'))
        pairs = pairs[pairs['Name_1'] != pairs['Name_2']]
        # 计算模糊匹配相似度
        pairs['similarity'] = pairs.apply(lambda x: fuzz.ratio(x['Name_1'], x['Name_2']), axis=1)
        results.append(pairs)
    
    final_df = pd.concat(results)[['Name_1', 'Name_2', 'similarity']]
    
  • 按分词/结构分组:如果姓名包含多部分(如"gal britt"),可以按姓氏或拆分后的单词分组,进一步缩小比对范围

2. 近似字符串索引库

利用专门的近似索引工具,快速定位相似字符串,无需全量比对:

  • 使用annoy构建向量索引:基于字符n-gram生成向量,通过近似最近邻算法快速找到相似项
    from annoy import AnnoyIndex
    import numpy as np
    from sklearn.feature_extraction.text import CountVectorizer
    from fuzzywuzzy import fuzz
    
    # 用字符2-gram生成姓名向量
    vectorizer = CountVectorizer(analyzer='char', ngram_range=(2,3))
    name_vectors = vectorizer.fit_transform(df['Name']).toarray()
    
    # 构建Annoy索引
    dim = name_vectors.shape[1]
    index = AnnoyIndex(dim, 'angular')
    for i, vec in enumerate(name_vectors):
        index.add_item(i, vec)
    index.build(10) # 树的数量,平衡搜索速度和精度
    
    # 查找每个姓名的近似匹配(排除自身)
    results = []
    for i, name in enumerate(df['Name']):
        # 取前6个相似项,去掉自身(第1个是自己)
        similar_indices = index.get_nns_by_item(i, 6)[1:]
        for idx in similar_indices:
            sim = fuzz.ratio(name, df['Name'].iloc[idx])
            results.append({'Name_1': name, 'Name_2': df['Name'].iloc[idx], 'similarity': sim})
    
    final_df = pd.DataFrame(results)
    
  • 用fuzzywuzzy.process批量提取:设置相似度阈值,只保留符合要求的匹配项
    from fuzzywuzzy import process
    
    results = []
    # 对每个姓名,提取相似度≥80的匹配项(排除自身)
    for name in df['Name']:
        matches = process.extract(name, df['Name'], limit=5, scorer=fuzz.ratio)
        for match_name, sim, _ in matches:
            if name != match_name and sim >= 80:
                results.append({'Name_1': name, 'Name_2': match_name, 'similarity': sim})
    
    final_df = pd.DataFrame(results).drop_duplicates(subset=['Name_1', 'Name_2'])
    

3. 分块处理

如果必须进行全量比对,将数据集拆分为小块,逐块比对后合并结果:

from fuzzywuzzy import fuzz
import pandas as pd

chunk_size = 1000
results = []

# 遍历所有块组合
for i in range(0, len(df), chunk_size):
    chunk1 = df.iloc[i:i+chunk_size]
    # 只和当前及后续块比对,避免重复配对
    for j in range(i, len(df), chunk_size):
        chunk2 = df.iloc[j:j+chunk_size]
        pairs = chunk1.merge(chunk2, how='cross')
        # 同块内排除自身配对
        if i == j:
            pairs = pairs[pairs['Name_x'] != pairs['Name_y']]
        # 计算相似度
        pairs['similarity'] = pairs.apply(lambda x: fuzz.ratio(x['Name_x'], x['Name_y']), axis=1)
        results.append(pairs)

final_df = pd.concat(results)[['Name_x', 'Name_y', 'similarity']]

搭配相似度阈值过滤,只保留高相似记录,可进一步减少内存占用。

4. 并行加速处理

结合分块和多进程,提升处理效率:

from fuzzywuzzy import fuzz
import pandas as pd
from multiprocessing import Pool

def process_chunk(chunk_pair):
    chunk1, chunk2 = chunk_pair
    pairs = chunk1.merge(chunk2, how='cross')
    # 同块内排除自身配对
    if chunk1.equals(chunk2):
        pairs = pairs[pairs['Name_x'] != pairs['Name_y']]
    pairs['similarity'] = pairs.apply(lambda x: fuzz.ratio(x['Name_x'], x['Name_y']), axis=1)
    return pairs

# 生成块组合
chunk_size = 1000
chunks = [df.iloc[i:i+chunk_size] for i in range(0, len(df), chunk_size)]
chunk_pairs = []
for i in range(len(chunks)):
    for j in range(i, len(chunks)):
        chunk_pairs.append((chunks[i], chunks[j]))

# 多进程处理
with Pool(4) as p:
    results = p.map(process_chunk, chunk_pairs)

final_df = pd.concat(results)[['Name_x', 'Name_y', 'similarity']]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 18:05:19