这个式子很简单,关于为什么第一个 \((y - X_{b} · θ)\) 要进行转置,如果不进行转置的话,那么 \((y - X_{b} · θ)(y - X_{b} · θ)\) 得到的还是一个向量。我们的目标函数是对每一个样本的真实值和预测值之间的误差进行了求和,那么我们如果不转置的话,还要进行一个求和运算,如果对第一项进行转置的话,那么点乘之后会自动进行相加,因此这种表示方法更为直观。
因此我们的目标函数就是找到一个θ,使得目标函数尽可能的小。这里推导过程就不给出了,就是下面的θ,有兴趣的话可以去网上搜索一下推导过程。
\(θ = (X_{b}^{T}X_{b})^{-1}X_{b}^{T}y\)
此时的这个θ,我们就称之为正规方程解。关于这个式子也没有必要背,因为在网上一搜就是,其实在真正使用多元线性回归的时候,我们还有另外的方法可以估计出这个θ的值,这个另外的方法,我们之后介绍。
另外我们在求解这个θ的时候,实际上也会有一些问题的,那就是时间复杂度高,为O(n3),优化之后也有O(n2.4)。但是好处就是不需要对数据进行归一化处理,因为我们就是对原始的数据进行运算,这种运算是不存在量纲的问题的。
实现多元线性回归那么我们就来实现一下多元线性回归。
import numpy as np class LinearRegression: def __init__(self): self.coef_ = None self.interception_ = None # 我们需要计算θ,但是呢,这个θ是不需要用户访问,因此我们设置为被保护的 self._theta = None def fit(self, X_train, y_train): assert X_train.shape[0] == y_train.shape[0], "样本的个数和标签的个数要保持一致" # 计算Xb,这个Xb就是样本的基础上再加上一列 X_b = np.c_[np.ones(len(X_train)), X_train] self._theta = np.linalg.inv(X_b.T @ X_b) @ X_b.T @ y_train self.interception_ = self._theta[0] self.coef_ = self._theta[1:] return self def predict(self, X_predict): assert self.coef_ is not None, "预测(predict)之前必须先fit(拟合)" assert X_predict.shape[1] == len(self.coef_), "样本的特征数要和相应的系数保持一致" X_b = np.c_[np.ones(len(X_predict)), X_predict] predict = X_b @ self._theta return predict def score(self, X_test, y_test): y_predict = self.predict(X_test) mse = np.sum((y_test - y_predict) ** 2) / len(y_test) var = np.var(y_test) r2_score = 1 - mse / var return r2_score if __name__ == \'__main__\': from sklearn.datasets import load_boston boston = load_boston() # 选择所有的特征 X = boston.data y = boston.target index = np.arange(0, X.shape[0]) test_size = 0.3 np.random.shuffle(index) X_train, X_test, y_train, y_test = (X[index[int(X.shape[0] * test_size):]], X[index[: int(X.shape[0] * test_size)]], y[index[int(X.shape[0] * test_size):]], y[index[: int(X.shape[0] * test_size)]]) linear = LinearRegression() linear.fit(X_train, y_train) print(linear.coef_) """ [-1.26398128e-01 3.57329311e-02 -9.99460755e-03 2.49336361e+00 -1.66228834e+01 3.58359972e+00 -1.04839104e-03 -1.39258694e+00 3.43283440e-01 -1.30859190e-02 -1.00377059e+00 1.06387337e-02 -5.33110952e-01] """ print(linear.interception_) # 38.10416228778042 print(linear.score(X_test, y_test)) # 0.7907505239934073可以看到当我们使用所有的特征时,结果的R Squared是比我们之前只使用一个特征要好。
那么最后我们还是要来看看sklearn中给我们提供的线性回归算法。
from sklearn.linear_model import LinearRegression from sklearn.datasets import load_boston from sklearn.model_selection import train_test_split boston = load_boston() X = boston.data y = boston.target X_train, X_test, y_train, y_test = train_test_split(X, y) linear = LinearRegression() # 可以看到都是这种模式,我们不需要管里面的逻辑是如何实现的 # 只需要将训练集的特征和标签传进去进行训练即可 linear.fit(X_train, y_train) # 得到训练的模型之后,可以调用predict,传入X_test得到预测的结果 # 如果只想看分类的准确度,也可以调用score,直接传入X_test和y_test得到准确度 print(linear.score(X_test, y_test)) # 0.7712210030661906