如何向量化Pandas函数以加速大型DataFrame的运算?
用Pandas向量化重构你的分组逻辑
兄弟,你的循环逻辑其实可以提炼成更简洁的向量化操作——本质上你是想把每个A分组里的1都“归集”到最后一行,其他行置0对吧?先不说循环慢的问题,咱们先拆解下你要的最终效果:
- 每个
A分组内,如果原C列有至少一个1,那么该组最后一行的new设为1,其余行全为0 - 如果分组内
C全是0,那整个组的new都保持0
完全不需要逐行循环,用Pandas的分组+标记就能搞定,代码如下:
import pandas as pd # 你的原始DataFrame membership = pd.DataFrame.from_dict(dict([ ('A', ['20000000460', '20000000460', '20000000460','20000000460','20000000459','20000000461','20000000461','20000000462','20000000464','20000000464','20000000464','20000000464','20000000465','20000000465','20000000466']), ('B', [4,0,5,0,6,0,2,5,6,7,4,3,2,7,9]), ('C', [1,1,0,0,0,1,0,1,1,1,0,0,0,0,1]) ])) # 向量化实现逻辑 def vectorized_members(df): # 1. 初始化new列为C的副本 df['new'] = df['C'].copy() # 2. 按A分组,标记每个组的最后一行 df['is_last_row'] = df.groupby('A').cumcount(ascending=False) == 0 # 3. 计算每个组是否存在至少一个1(用transform把组结果映射到每行) group_has_one = df.groupby('A')['C'].transform('any') # 4. 最终设置new的值:只有最后一行且组内有1时为1,其余为0 df['new'] = df.apply(lambda x: 1 if x['is_last_row'] and group_has_one.loc[x.name] else 0, axis=1) # 可选:删除中间辅助列 df.drop('is_last_row', axis=1, inplace=True) return df # 运行并查看结果 result = vectorized_members(membership) print(result[['A', 'C', 'new']])
为什么这比循环快?
- 你的原循环是Python层面的逐行遍历,大数据量下会触发大量的
loc索引操作,速度极慢; - 上面的向量化操作都是基于Pandas底层的C实现的分组、变换逻辑,避免了Python循环的开销,数据量越大,速度提升越明显(几十万甚至上百万行的话,速度能差几十上百倍)。
验证结果
对比你原函数的输出,这个向量化版本的结果是完全一致的:
比如A=20000000460的分组,原循环后new是[0,0,0,1],向量化版本也是一样的;A=20000000461分组原循环后new是[0,1],这里也能得到同样结果。
内容的提问来源于stack exchange,提问作者K. Sante
相关产品推荐
相关产品推荐

