然后我们使用上面的三个标准来计算它们的误差:
y_predict = linear.predict(x_test) # MSE mse = np.sum((y_predict - y_test) ** 2) / len(y_test) # RMSE rmse = np.sqrt(mse) # MAE mae = np.sum(np.abs(y_predict - y_test)) / len(y_test) print(mse) # 25.9281717303928 print(rmse) # 5.091971301018183 print(mae) # 3.795667974965169可以看出还是很简单的,然后老规矩,下面肯定要看看sklearn中,这些衡量标准。首先sklearn没有RMSE,我们可以先求出MSE,再手动开根。
from sklearn.metrics import mean_absolute_error from sklearn.metrics import mean_squared_error print(mean_absolute_error(y_test, y_predict)) # 25.9281717303928 print(np.sqrt(mean_squared_error(y_test, y_predict))) # 5.091971301018183 print(mean_squared_error(y_test, y_predict)) # 3.795667974965169关于RMSE和MAE,我们知道这两种衡量标准它们在量纲上是一致的,但是哪个更好呢?根据我们上面预测的结果发现RMSE大于MAE,没错,我们观察一下式子。因为RMSE进行了平方,虽然又进行了开根,但是整体来说还是有将错误放大的趋势,而MAE没有,因此我们将RMSE作为评价指标会更有意义。
介绍了这么多指标,你以为就完了,其实我们还有一个最好的衡量线性回归法的指标,在sklearn的线性回归中,写入score函数中的也是这个指标。
最好的衡量线性回归法的指标:R Squared事实上,无论是RMSE还是MAE,是随着样本的不同而变化的。比如房产数据,可能预测出来的误差是五万美元,学生成绩预测出来的误差是10分,那么我们的算法是作用在房产数据好呢?还是作用在学生成绩好呢?这些是没有办法比较的。而分类问题不同,分类是根据样本的真实特征和预测特征进行比较,看看预测对了多少个,然后除以总个数,得到的准确度是在0到1之间的。越接*1越好,越接*0越差,而RMSE和MAE由于样本种类的不同,导致是无法比较的。
于是,我们便有了下一个指标R Squared,也就是所谓的 \(R^{2}\) 。
\(R^{2} = 1 - \frac{\displaystyle\sum(\hat y^{i} - y^{i})^{2}}{\displaystyle\sum(\overline y^{i} - y^{i})^{2}} = \frac{使用我们的模型预测时产生的错误}{使用 y=\overline y 预测时产生的错误}\)
怎么理解这个式子呢?首先把 \(y\) 的平均值看成一个模型,这个模型也叫作基准模型,分母就是用基准模型预测出来的误差。换句话说,这个结果是与样本特征是无关的,因为它没有用到 \(x\) ,那么这个基准模型必然会产生很多错误。而分子则是使用我们训练出来模型进行预测出来误差,如果我们训练出来的模型预测时产生的错误除以基准模型预测时产生的错误的结果越小,那么再用1去减,得到的结果就越大,说明我们训练的模型就越好。
根据 \(R^{2}\) 我们可以得出如下结论:
\(R^{2}\) <= 1
\(R^{2}\) 越大越好,当我们的模型不犯任何错误时,\(R^{2}\) 取得最大值1
当我们的模型等于基准模型(Baseline Model)时,\(R^{2}\) 为0
如果 \(R^{2}\) < 0,说明我们学*到的模型还不如基准模型。那么很有可能我们的数据压根就不存在所谓的线性关系,不管是正相关还是负相关。
我们再来看看这个 \(R^{2}\) ,如果我们对式子进行一下变换的话。
\(R^{2} = 1 - \frac{\displaystyle\sum(\hat y^{i} - y^{i})^{2}}{\displaystyle\sum(\overline y^{i} - y^{i})^{2}} = 1 - \frac{\displaystyle\sum(\hat y^{i} - y^{i})^{2} / m}{\displaystyle\sum(\overline y^{i} - y^{i})^{2} / m} = 1 - \frac{MSE(\hat y, y)}{Var(y)}\)
会发现这个 \(R^{2}\) 就等于 1 - MSE/Var(y)
在sklearn中也提供了R Squared。
from sklearn.metrics import r2_score print(r2_score(y_test, y_predict)) # 0.5107683519296282 # 或者手动计算也可以 mse = mean_squared_error(y_test, y_predict) r2_score = 1 - mse / np.var(y_test) print(r2_score) # 0.5107683519296282我们在K*邻中,会直接封装一个score函数,返回分类的准确度,那么在sklearn中,我们也依旧可以封装一个score。另外在sklearn的线性回归中,score函数也是直接返回了R Squared,而且sklearn的线性回归是支持多元线性回归的,后面会说。因此如果只想看分类的准确度可以调用score方法,如果想要预测出来的值,那么可以调用predict方法。
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 SimpleLinearRegression: def __init__(self): self.a_ = None self.b_ = None def fit(self, x_train: np.ndarray, y_train: np.ndarray): assert x_train.ndim == 1, "简单线性回归只支持一个具有一个特征的训练集" assert len(x_train) == len(y_train), "样本数必须和标签数保持一致" x_mean = np.mean(x_train) y_mean = np.mean(y_train) self.a_ = np.sum((x_train - x_mean) * (y_train - y_mean)) / np.sum((x_train - x_mean) ** 2) self.b_ = y_mean - self.a_ * x_mean return self def predict(self, x_predict): assert self.a_ is not None, "预测(predict)之前要先拟合(fit)" if isinstance(x_predict, list): x_predict = np.array(x_predict) return self.a_ * x_predict + self.b_ def score(self, x_test, y_test): y_predict = self.predict(x_test) mse = mean_squared_error(y_test, y_predict) r2_score = 1 - mse / np.var(y_test) return r2_score def __str__(self): return f"<SimpleLinearRegression>:a_={self.a_},b_={self.b_}" def __repr__(self): return f"<SimpleLinearRegression>:a_={self.a_},b_={self.b_}" boston = load_boston() x = boston.data[:, 5] # 选择房屋的房间数 y = boston.target x = x[y < np.max(y)] y = y[y < np.max(y)] x_train, x_test, y_train, y_test = train_test_split(x, y) linear = SimpleLinearRegression() linear.fit(x_train, y_train) print(linear.score(x_test, y_test)) # 0.5849894775958314 多元线性回归和正规方程解