pandas多规则列运算加速实现(适配百万级行数据集)
510万行pandas New_ID字段高性能实现方案
核心逻辑
规则2本质是ID1连通分量归并问题:只要两个ID1出现在同一个ID2分组下,二者就属于同一个连通集合;所有连通集合内的ID1对应的行,统一取集合中关联记录日期最新的ID1作为最终New_ID。
这类传递性归并场景用并查集(DSU)实现时间复杂度接近O(n),510万行数据全量运行耗时通常在5-15秒,无内存溢出风险。
注:之前测试的
groupby('ID2')['ID1'].transform('last')仅完成了ID2组内的最新值映射,没有处理跨ID2的ID1连通传递关系,因此无法满足规则2。
前置条件利用
现有数据集已经满足两个可以大幅提效的前提,不需要额外做排序/去重操作:
- 数据已按
date字段全局升序排列,任意分组的最后一行即为日期最新的记录 ['ID1', 'ID2']组合无重复,不存在重复归并的冗余记录
完整实现代码
import pandas as pd # 并查集实现,用于ID1连通分量归并 class DSU: def __init__(self, size): # 用数组存储父节点,比字典速度更快,初始化时需先将ID1映射为整数编码 self.parent = list(range(size)) 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): # 合并时始终将索引更大(对应日期更新,因为数据全局按date升序)的节点作为根 root_x = self.find(x) root_y = self.find(y) if root_x == root_y: return if root_x > root_y: self.parent[root_y] = root_x else: self.parent[root_x] = root_y # ---------------------- 主流程 ---------------------- # 1. 将ID1映射为整数编码,加速并查集操作 id1_codes, id1_uniques = pd.factorize(df['ID1']) df['tmp_id1_code'] = id1_codes # 2. 计算每个ID2分组内日期最新的ID1编码(数据已升序,组内最后一个值即为最新) id2_group = df.groupby('ID2')['tmp_id1_code'] id2_latest_code = id2_group.last().to_dict() df['tmp_id2_latest_code'] = df['ID2'].map(id2_latest_code) # 3. 初始化并查集,归并同一连通集合内的所有ID1 dsu = DSU(len(id1_uniques)) # 仅遍历去重后的(ID1编码, 组内最新ID1编码)对,避免重复合并 merge_pairs = df[['tmp_id1_code', 'tmp_id2_latest_code']].drop_duplicates() for _, (code, latest_code) in merge_pairs.itertuples(index=False): if code != latest_code: dsu.union(code, latest_code) # 4. 映射得到最终New_ID root_codes = [dsu.find(c) for c in df['tmp_id1_code']] df['New_ID'] = [id1_uniques[c] for c in root_codes] # 5. 删除临时列 df = df.drop(columns=['tmp_id1_code', 'tmp_id2_latest_code'])
性能优化说明
- 用
pd.factorize将字符串/混合类型ID1转为整数编码,用数组实现并查集,比纯字典实现速度提升40%以上 - 对合并对做去重处理,仅保留唯一的归并关系,避免无意义的重复union操作,归并步骤的遍历量通常仅为总行数的1%-10%
- 全程无嵌套循环、无反复merge/join操作,所有步骤均为线性复杂度
正确性校验
可通过小样本验证逻辑符合要求:
- 单个ID2分组下仅1个ID1:组内所有行New_ID等于该ID1,符合规则1
- 单个ID2分组下有多个ID1:组内所有ID1对应的行(跨任意ID2分组)New_ID统一为连通集合内日期最新的ID1,符合规则2
- 跨ID2连通场景:如ID2=a下有ID1=1、ID1=2,ID2=b下有ID1=2、ID1=3,则1/2/3属于同一连通集合,所有对应行New_ID统一为三个ID1中日期最新的值
内容的提问来源于stack exchange,提问作者ko3
相关产品推荐
相关产品推荐

