Pandas如何高效实现DataFrame行与对应自定义矩阵点乘
高性能实现方案
原写法性能差的核心原因有三个:
- 用
iterrows()逐行遍历,每一行都会被转成Series对象,遍历本身的开销非常高 - 循环内反复通过
df.loc[index]取值,单元素调用numpy计算函数,完全没用到numpy的向量化批量计算能力 - 逐行构造矩阵、逐行做点积,所有运算都跑在Python循环层,没法利用底层C实现的运算加速
针对你这个场景,直接把逐行逻辑改成整组数组的向量化运算即可,不需要写任何显式循环,代码如下:
import pandas as pd import numpy as np df = pd.DataFrame({"A": [1, 2, 3, 4], "B": [5, 6, 7, 8], "C": [9, 10, 11, 12], "D": [1, 1, 1, 1]}) # 一次性批量计算所有矩阵位置需要的元素,无循环 sin_A = np.sin(df["A"].to_numpy()) sign_B = np.sign(df["B"].to_numpy()) abs_C = np.abs(df["C"].to_numpy()) sign_C = np.sign(df["C"].to_numpy()) tan_C = np.tan(df["C"].to_numpy()) row_count = len(df) # 构造批量三维矩阵:维度为(行数, 4, 4),对应每一行要乘的4x4矩阵 batch_mat = np.zeros((row_count, 4, 4)) # 按矩阵位置批量填充值 batch_mat[:, 0, 0] = sin_A batch_mat[:, 0, 3] = sin_A batch_mat[:, 1, 1] = sign_B batch_mat[:, 1, 3] = abs_C batch_mat[:, 2, 0] = sign_C batch_mat[:, 2, 2] = sign_C batch_mat[:, 3, 0] = 1 batch_mat[:, 3, 1] = 2 batch_mat[:, 3, 3] = tan_C # 取出DataFrame的数值矩阵,维度为(行数,4) row_array = df[["A", "B", "C", "D"]].to_numpy() # 批量完成所有行的点积运算:每个行向量乘对应位置的4x4矩阵 result = np.einsum('ij,ijk->ik', row_array, batch_mat) # 结果直接赋值回DataFrame df[["U", "V", "W", "X"]] = result print(df)
性能说明
- 10万行数据规模下,原循环写法通常需要数秒到十几秒,上述向量化写法耗时普遍在100毫秒以内,性能提升可达100倍以上
- 所有计算都在numpy的C底层完成,没有Python层循环的额外开销
- 如果后续矩阵结构有调整,只需要修改
batch_mat对应位置的填充逻辑即可,核心运算代码不需要改动
注意:尽量不要在循环中反复通过loc/iloc访问DataFrame元素,这类索引操作的开销远大于numpy数组的直接运算,需要做批量计算时优先把列转成numpy数组再处理。
内容的提问来源于stack exchange,提问作者CNGF
相关产品推荐
相关产品推荐

