优化Pandas中高耗时双重循环的相似文本关联ID更新方案
优化方案:甩掉慢到离谱的双重循环
你现在的需求是:同一个groupId下,把stringCol里相似的文本对应的relationId统一成组里最早出现的那个值。原来的双重循环是O(n²)复杂度,数据量稍大就卡得不行,下面是更高效的实现方法:
第一步:先按组和时间排序
先把每个组内的行按intTime升序排好,这样最早出现的文本会排在最前面,后面聚类后直接拿第一个的relationId就行:
df_sorted = df.sort_values(by=['groupId', 'intTime']).reset_index(drop=True)
第二步:分组做文本相似聚类
Pandas本身没有直接处理文本相似合并的函数,但可以结合scikit-learn的聚类工具,用Levenshtein距离做相似度判断,把同一组里的相似文本归成一类,再统一relationId:
from sklearn.cluster import DBSCAN from Levenshtein import distance as lev_dist from sklearn.metrics import pairwise_distances def process_single_group(group): # 取出当前组的所有文本 texts = group['stringCol'].values # 计算文本间的Levenshtein距离矩阵 dist_matrix = pairwise_distances(texts.reshape(-1, 1), metric=lambda x, y: lev_dist(x[0], y[0])) # DBSCAN聚类,eps是相似阈值(比如你原来的comparator判断距离<=2就算相似,就设eps=2) # min_samples=1确保单个文本也能成簇 dbscan = DBSCAN(eps=2, min_samples=1, metric='precomputed') cluster_labels = dbscan.fit_predict(dist_matrix) # 给每个簇分配最早出现的relationId group['cluster'] = cluster_labels # 按簇取第一个的relationId做映射 cluster_to_id = group.groupby('cluster')['relationId'].first().to_dict() group['relationId'] = group['cluster'].map(cluster_to_id) return group.drop('cluster', axis=1) # 按groupId分组处理所有数据 df_final = df_sorted.groupby('groupId').apply(process_single_group).reset_index(drop=True)
为啥这个方法更快?
- 聚类算法的时间复杂度远低于双重循环的O(n²),数据量大的时候差距特别明显
- 用Pandas的
groupby.apply批量处理分组,不用手动写嵌套循环 - 提前排序保证了每个簇里第一个元素就是最早出现的,直接复用它的
relationId就行
额外优化建议
如果数据量超大,还能再提速:
- 先给文本做预处理:转小写、删标点、去冗余字符,减少计算量
- 调整DBSCAN的
eps参数,完全匹配你原来comparator的相似判断逻辑 - 用近似近邻库(比如faiss)替代全量距离矩阵计算,进一步压缩时间
内容的提问来源于stack exchange,提问作者DavidRit
相关产品推荐
相关产品推荐

