大规模数据集姓名去重:高效分组与标准化方法求助
超大规模姓名去重:基于并查集的高效分组与标准化方案
用**并查集(Union-Find)**处理匹配对的关联关系,是解决大规模数据下姓名分组问题的最优方案——它能高效识别所有连通的姓名组,完全避免循环、isin等低效操作的性能问题,且严格基于匹配关联聚类,和索引值无关。
具体实现步骤
1. 实现高效并查集类
这个数据结构支持近似O(1)的合并与查找操作,适配百万级以上数据:
class UnionFind: def __init__(self, elements): self.parent = {elem: elem for elem in elements} self.rank = {elem: 0 for elem in elements} def find(self, x): if self.parent[x] != x: self.parent[x] = self.find(self.parent[x]) # 路径压缩,加速后续查找 return self.parent[x] def union(self, x, y): x_root = self.find(x) y_root = self.find(y) if x_root == y_root: return # 按秩合并,保持树结构平衡 if self.rank[x_root] < self.rank[y_root]: self.parent[x_root] = y_root else: self.parent[y_root] = x_root if self.rank[x_root] == self.rank[y_root]: self.rank[x_root] += 1
2. 处理匹配对,构建连通组
假设你的vectors是筛选后的高相似度匹配对DataFrame(recordlinkage默认生成MultiIndex,即(left_idx, right_idx)):
# 提取所有涉及的索引(左右匹配项) all_indices = set(vectors.index.get_level_values(0)).union(set(vectors.index.get_level_values(1))) # 初始化并查集 uf = UnionFind(all_indices) # 遍历所有匹配对,合并关联索引 for left_idx, right_idx in vectors.index: uf.union(left_idx, right_idx)
如果匹配对存在普通列(如left_idx、right_idx),替换遍历逻辑为:for _, row in vectors.iterrows(): uf.union(row['left_idx'], row['right_idx'])
3. 给原始数据标记组ID
假设原始姓名数据存储在df中,索引与匹配对的索引一致:
# 给每个姓名索引分配对应的组根节点ID df['group_id'] = df.index.map(lambda x: uf.find(x))
4. 按组计算众数,完成标准化
取每组出现次数最多的姓名作为标准化结果,处理单元素组的边界情况:
# 计算每组姓名的众数(若有多个众数取第一个) group_modes = df.groupby('group_id')['name'].agg( lambda x: x.mode().iloc[0] if not x.mode().empty else x.iloc[0] ) # 映射回原始数据,生成标准化姓名 df['standardized_name'] = df['group_id'].map(group_modes)
核心优势
- 性能碾压循环/
isin:并查集的时间复杂度接近线性,百万级数据可在数秒内完成分组 - 精准关联聚类:完全基于匹配对的关联关系分组,和索引值大小无关
- 逻辑清晰:从匹配对到分组再到标准化的流程直观,新手易调试
内容的提问来源于stack exchange,提问作者memmy
相关产品推荐
相关产品推荐

