Pandas DataFrame水平数据序列按行线性回归实现方案
逐行线性回归高效实现方案
不用做全量DataFrame转置,也别逐行调用sklearn回归接口——sklearn的模型每次调用都带大量参数校验、初始化开销,逐行跑性能极差。最优思路是直接利用numpy的广播机制做向量化最小二乘计算,全程无Python层循环,性能比逐行apply高10~100倍。
实现步骤
- 首先按列名规则直接拆分出自变量、因变量矩阵,不用逐行取数:
用列名筛选直接拿到所有行的X序列、Y序列,得到两个形状为(总行数, 单序列长度n)的numpy数组,每一行对应一组待拟合的(x1...xn, y1...yn)点对。 - 批量计算所有行的回归系数:
单变量线性回归有解析解,不需要迭代求解,通过批量矩阵运算可以一次性算出所有行的斜率、截距,代码如下:
import numpy as np import pandas as pd # 筛选X、Y列,支持直接用前缀/正则匹配列名 X_mat = df.filter(like="colX").to_numpy() Y_mat = df.filter(like="colY").to_numpy() # 给每个X序列补截距项(全1列,对应回归常数b),适配y = k*x + b的形式 X_with_const = np.stack([X_mat, np.ones_like(X_mat)], axis=-1) # 批量计算伪逆+矩阵乘法,一次性得到所有行的回归系数 # 输出coefs形状为(总行数, 2),每行第一个值是斜率k,第二个值是截距b coefs = np.einsum("ijk,ik->ij", np.linalg.pinv(X_with_const), Y_mat) # 结果写回DataFrame df["linRegressionCoefs"] = coefs.tolist()
性能说明
- 逐行apply调用sklearn
LinearRegression:10万行规模耗时约30~60s,额外内存开销大 - 逐行apply调用
np.linalg.lstsq:10万行规模耗时约3~5s - 上述向量化方案:10万行规模耗时约50~100ms,内存占用比全量转置DataFrame的方案低30%左右,且不存在转置操作带来的索引对齐风险。
适配调整
- 如果不需要拟合截距项,直接去掉补全1列的步骤,修改对应矩阵运算维度即可,输出结果为每行一个斜率值
- 如果某行存在X序列所有值完全相同的异常情况,
np.linalg.pinv会自动返回正则化的最小二乘解,不会抛出异常,鲁棒性比普通lstsq计算更好 - 不要用
df.apply(axis=1)逐行取子集做回归,pandas的行遍历本身有极高的额外开销,数据量稍大就会出现明显卡顿。
内容的提问来源于stack exchange,提问作者lionel riviere
相关产品推荐
相关产品推荐

