np.linalg.lstsq更可靠,因其内部用SVD自动截断小奇异值,避免病态矩阵求逆的数值不稳定;而手推公式np.linalg.inv(X.T@X)@X.T@y在X.T@X接近奇异时易放大误差或报错。

为什么直接用 np.linalg.lstsq 比手推公式更可靠
因为浮点精度、矩阵病态性、截距项处理这些细节,手写 np.dot(np.linalg.inv(X.T @ X), X.T @ y) 极易出错。比如当 X.T @ X 接近奇异时,np.linalg.inv 会返回巨大误差甚至报 LinAlgError: Singular matrix;而 np.linalg.lstsq 内部用 SVD 分解,能自动截断小奇异值,稳定性强得多。
实操建议:
- 始终传入二维
X(哪怕只有一列特征),形状为(n_samples, n_features),否则lstsq可能静默失败 - 若需带截距项,手动在
X左侧拼一列1:X_with_intercept = np.column_stack([np.ones(len(X)), X]) -
lstsq返回四元组,真正需要的是第一个元素(系数向量)和第三个(残差平方和):coeffs, residuals, rank, s = np.linalg.lstsq(X_with_intercept, y, rcond=None)
如何正确设置 rcond 参数避免警告或偏差
rcond 控制 SVD 截断阈值,默认值在 NumPy 1.22+ 已改为 None(即自动选),但旧版本默认是 -1(触发弃用警告)。设得太小(如 1e-15)会让本该被忽略的微小奇异值参与计算,放大噪声;设得太大(如 1e-2)又可能误删有效秩。
实操建议:
- 显式传
rcond=None,让 NumPy 按max(M,N) * eps * max(s)自动计算(eps是浮点精度) - 如果数据明显共线(比如两个特征高度相关),观察返回的
rank是否小于n_features,这是lstsq已主动降秩的信号 - 不要用
rcond=0——它等价于不截断,失去数值鲁棒性
怎样把 lstsq 结果和 sklearn.LinearRegression 对齐
两者默认都支持截距,但 sklearn 把截距单独存为 .intercept_ 属性,而 lstsq 把它和其他系数一起放在返回数组首位。若你用 X_with_intercept,那么 coeffs[0] 就是截距,coeffs[1:] 是斜率。
实操建议:
- 验证时用相同数据:确保
X和y完全一致,且sklearn的fit_intercept=True(默认) - 注意
sklearn对单样本预测会补维度,lstsq不处理,所以预测时统一用X_test @ coeffs(含截距列) - 如果
sklearn返回rank不足,说明其内部也检测到矩阵问题,此时lstsq的rank输出就是关键诊断依据
遇到 residuals 为空数组怎么办
当 n_features >= n_samples(变量数 ≥ 样本数),最小二乘解不唯一,lstsq 无法计算残差,返回空数组 array([])。这不是错误,而是数学上的必然——此时模型过参数化,欠定系统有无穷多解。
实操建议:
- 检查
X.shape和y.shape,确认是否真的n_features >= n_samples - 若确实如此,考虑用岭回归(
np.linalg.solve(X.T @ X + alpha * np.eye(n), X.T @ y))加 L2 正则 - 或者删掉冗余特征,或用 PCA 降维,再调用
lstsq
真正容易被忽略的是:即使 residuals 非空,它的长度也不总是 1——当 y 是二维(多输出)时,它返回每个输出的残差,这时候得用 residuals.sum() 才得到总残差平方和。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











