如何基于正态方程实现支持多变量拟合预测的自定义线性回归类
核心错误点梳理
- 截距项(全1哑变量)添加逻辑错误:你之前给每个特征单独嵌套[1, 特征值],把原本形状为
(506, 13)的二维特征矩阵改成了(506,13,2)的三维数组,矩阵运算自然维度不匹配。正确做法是给每个样本的特征向量最前面加一个1,也就是把X从(样本数, 特征数)变成(样本数, 特征数+1),多出来的一列全为1即可。 - 自定义类结构错误:类的实例方法第一个参数必须是
self,拟合得到的权重需要保存在实例属性中,才能供predict方法调用,不能直接return就结束流程。 - 多变量适配逻辑误解:正规方程
(X.T * X) **-1 * X.T * y对单变量、多变量场景完全通用,只要X维度正确,得到的权重向量第一个元素是截距,后面依次是每个特征的系数,总长度为特征数+1。
符合要求的完整实现代码
from numpy.linalg import inv import numpy as np from sklearn.datasets import load_boston from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error class CustomLinearReg: def __init__(self): # 初始化和sklearn对齐的属性:截距、特征系数、拟合标志 self.intercept_ = None self.coef_ = None self._fitted = False def fit(self, X, y): # 给特征矩阵添加全1的截距项列,拼在所有特征最前面 # 原始X形状(样本数, n特征),拼接后为(样本数, n特征+1) X_b = np.hstack([np.ones((X.shape[0], 1)), X]) # 正规方程计算权重 weights = inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y) # 拆分权重:第一个元素是截距,后续是各特征对应系数 self.intercept_ = weights[0] self.coef_ = weights[1:] self._fitted = True # 返回截距+特征系数对 return self.intercept_, self.coef_ def predict(self, X): if not self._fitted: raise ValueError("请先调用fit方法拟合模型后再进行预测") # 预测用的特征矩阵也要加相同的截距项列 X_b = np.hstack([np.ones((X.shape[0], 1)), X]) # 矩阵乘法得到所有样本预测值 return X_b.dot(np.hstack([self.intercept_, self.coef_])) # 效果测试(和sklearn官方LinearRegression对比) if __name__ == "__main__": boston = load_boston() X, y = boston.data, boston.target X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 自定义模型调用 custom_reg = CustomLinearReg() intercept, coefs = custom_reg.fit(X_train, y_train) y_pred_custom = custom_reg.predict(X_test) print(f"自定义模型截距:{round(intercept, 3)}") print(f"自定义模型前3个特征系数:{[round(c,3) for c in coefs[:3]]}") print(f"自定义模型测试集MSE:{round(mean_squared_error(y_test, y_pred_custom), 3)}") # 官方模型对比 from sklearn.linear_model import LinearRegression sk_reg = LinearRegression() sk_reg.fit(X_train, y_train) y_pred_sk = sk_reg.predict(X_test) print(f"\n官方模型截距:{round(sk_reg.intercept_, 3)}") print(f"官方模型前3个特征系数:{[round(c,3) for c in sk_reg.coef_[:3]]}") print(f"官方模型测试集MSE:{round(mean_squared_error(y_test, y_pred_sk), 3)}")
逻辑说明
- 截距项的作用就是拟合公式里的常数项,对应单变量场景下的
w[0][0],多变量场景下也只需要加一列全1即可,不需要对每个特征单独处理。 - 代码的属性命名、方法调用逻辑完全和sklearn的
LinearRegression对齐,你可以直接替换使用。
内容的提问来源于stack exchange,提问作者Johnny
相关产品推荐
相关产品推荐

