如何用Pandas实现每行按不同列集合求和并保证向量化性能?
高效计算每行指定列的求和(向量化方案)
问题场景
现有如下Pandas DataFrame,包含数值列与Lists_to_sum列,该列存储每行需要求和的列名集合:
import pandas as pd import numpy as np df = pd.DataFrame(np.array([[284.77, 234.37, 243.8, 84.36, 0., 0., 0., 55.04, 228.2, 181.97, 0., 0.], [13.78, 0., 38.58, 33.16, 0., 38.04, 74.02, 45.74, 27.2, 9.19, 0., 0.], [88.66, 255.72, 323.19, 7.24, 0., 73.38, 45.73, 0., 0., 77.39, 26.57, 279.34], [0., 0., 34.42, 9.16, 0., 43.4, 42.17, 123.69, 60.5, 25.47, 72.32, 7.29], [320.6, 1445.56, 856.23, 371.21, 0., 244.22, 134.58, 631.59, 561.82, 1172.44, 895.68, 186.28], [0., 0., 32.29, 1000.91, 0., 680., 585.46, 466.6, 0., 493.48, 157.1, 125.31]]), columns=[1,2,3,4,5,6,7,8,9,10,11,12]) df['Lists_to_sum'] = [[1,2,3,4], [4,6,8,9,10,11], [2], [3,4,5,6,7,8,9,10,11], [1,2,3,4,5,6,7,8,9], [2,3,4,5,6,7,8,9,10,11,12],]
需求为添加SUM_per_ROW列,存储每行对应Lists_to_sum列指定列的求和结果,且方案需具备向量化性能以适配大数据场景。当前循环方法虽能得到正确结果,但性能极差,不适用于千万级行数的DataFrame:
for n,m,i in zip(df.index, df['Lists_to_sum'], range(0, df.shape[0])): df.at[n,'SUM_per_ROW'] = df[m][i:i+1].sum(axis=1) print('{} de {}'.format(i+1, df.shape[0]))
高效向量化解决方案
方案1:Numpy布尔掩码计算(性能最优)
完全基于Numpy的向量化操作,底层为C实现,适合千万级规模数据:
# 将列名转换为列索引(列名1-12对应索引0-11) col_indices = df['Lists_to_sum'].apply(lambda x: [i-1 for i in x]) # 创建布尔掩码矩阵,每行标记需要求和的列 mask = np.zeros((len(df), len(df.columns)-1), dtype=bool) for idx, cols in enumerate(col_indices): mask[idx, cols] = True # 利用掩码提取数据并按行求和 df['SUM_per_ROW'] = df.iloc[:, :-1].values[mask].reshape(len(df), -1).sum(axis=1)
方案2:Explode + Groupby 计算(代码简洁)
借助Pandas内置的分组优化,代码更简洁,适合中等至大规模数据:
# 展开Lists_to_sum列,关联每行的原始数值 temp_df = df.explode('Lists_to_sum') # 按原行索引分组,对指定列求和 df['SUM_per_ROW'] = temp_df.groupby(temp_df.index)[temp_df['Lists_to_sum'].astype(int)].sum()
方案说明
- 原始循环方法的性能瓶颈在于逐行调用
df.at更新数据,每次操作都会触发Pandas的索引校验和数据结构更新,时间复杂度为O(n)且常数项极大。 - 两个方案均为向量化操作,避免了Python级别的循环,性能提升可达数十倍甚至上百倍:
- 方案1的Numpy掩码方法直接操作底层数组,内存占用更低,速度最快。
- 方案2代码更易读,无需手动处理索引转换,适合快速开发。
内容的提问来源于stack exchange,提问作者espinafrando
相关产品推荐
相关产品推荐

