如何使用文本相似度删除pandas DataFrame中的相似非重复行
现有方案的问题分析
你当前实现的核心问题是O(n²)的时间复杂度:假设你有5000条数据,就要执行接近1200万次相似度计算,加上每次Jaro-Winkler计算本身和pandas取数的额外开销,速度慢是必然的。另外你的逻辑还有一个小缺陷:只要两条文本相似就把第一个索引加入删除列表,可能出现一组相似文本全部被误删的情况,不符合「相似内容保留一条」的去重需求。
优化方案
1. 基础优化(适配几千条数据的场景,改完就能用)
不需要换算法,只要调整逻辑、替换更快的依赖库,速度就能提升5~10倍:
- 提前把文本导出为Python原生列表,避免反复从pandas取数的开销
- 替换
textdistance为jellyfish库,后者的相似度计算是C实现的,速度快很多 - 改成保留索引逻辑:维护一个已保留的索引列表,新文本只和已保留的文本比对,没有相似的才加入保留列表,既减少比对次数,也避免误删所有相似内容
优化后代码示例:
import jellyfish import pandas as pd threshold = 0.9 text_list = df1['cleaned'].tolist() keep_indices = [] for idx, text in enumerate(text_list): is_dup = False # 仅和已保留的文本比对,不需要全量两两比对 for keep_idx in keep_indices: # 可选前置优化:长度差超过10%直接跳过,相似度不可能到0.9 if abs(len(text) - len(text_list[keep_idx])) / len(text) > 0.1: continue sim = jellyfish.jaro_winkler_similarity(text, text_list[keep_idx]) if sim >= threshold: is_dup = True break if not is_dup: keep_indices.append(idx) # 直接取保留的行完成去重 df_dedup = df1.iloc[keep_indices]
2. 进阶优化(适配万条以上数据的场景)
如果后续数据量涨到万级以上,可以用局部敏感哈希(LSH) 做预筛选:先把文本转换成哈希指纹,只对哈希指纹接近的文本再做精确相似度计算,时间复杂度可以降到接近O(n)。
用datasketch库实现的示例:
from datasketch import MinHash, MinHashLSH threshold = 0.9 text_list = df1['cleaned'].tolist() keep_indices = [] # 初始化LSH,num_perm值越高精度越高,速度稍慢,128是通用平衡值 lsh = MinHashLSH(threshold=threshold, num_perm=128) def get_text_minhash(text, n_gram=3): m = MinHash(num_perm=128) # 把文本拆成3字符的n-gram生成哈希指纹 for i in range(len(text) - n_gram + 1): ngram = text[i:i+n_gram].encode('utf-8') m.update(ngram) return m for idx, text in enumerate(text_list): m = get_text_minhash(text) # 先查LSH有没有近似文本,没有才保留 if not lsh.query(m): lsh.insert(idx, m) keep_indices.append(idx) df_dedup = df1.iloc[keep_indices]
内容的提问来源于stack exchange,提问作者catris25
相关产品推荐
相关产品推荐

