Pandas分组新增列时append操作慢,如何对该逻辑进行向量化优化
Pandas 向量化优化方案
核心逻辑
完全替换原代码的双层循环+append操作,仅用两步向量化操作完成需求:
- 在每个
c1分组内,对c2的唯一值按出现顺序编码,得到从0开始计数的索引idx - 结合每行的
c1值和计算得到的idx,从预置values中取出对应值作为c3
优化后代码
import pandas as pd df = pd.DataFrame( { "c1": [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2], "c2": ["a", "a", "a", "b", "b", "b", "y", "y", "y", "z", "z", "z"], } ) values = {1: ["a1", "a2"], 2: ["b1", "b2"]} # 计算c1分组内c2对应的顺序索引 df['idx'] = df.groupby('c1')['c2'].transform(lambda x: x.factorize()[0]) # 生成c3列 df['c3'] = df.apply(lambda row: values[row['c1']][row['idx']], axis=1) # 删除辅助列 df = df.drop('idx', axis=1) print(df)
性能说明
原代码性能瓶颈有两个:一是双层for循环遍历分组的开销,二是每次append操作都会全量复制已有DataFrame数据,数据量越大耗时增长越快。优化后的代码全部使用Pandas内置向量化操作,无显式循环和反复复制开销,数据量达到十万级以上时,性能比原写法提升百倍以上。
超大数据量可选更高性能写法
如果数据量超过百万行,可以把取值逻辑替换为映射表匹配,避免apply的行遍历开销:
# 提前构建(c1, idx)到c3值的映射 mapping = {} for c1_val, c3_list in values.items(): for idx, c3_val in enumerate(c3_list): mapping[(c1_val, idx)] = c3_val # 用索引映射直接取值 df['idx'] = df.groupby('c1')['c2'].transform(lambda x: x.factorize()[0]) df['c3'] = df.set_index(['c1', 'idx']).index.map(mapping.get) df = df.drop('idx', axis=1)
内容的提问来源于stack exchange,提问作者Valencia
相关产品推荐
相关产品推荐

