在上一篇博客中,得到了多元线性回归的正规方程解(Normal Equation),对于一个多元线性回归的模型来说,我们要估计的 θ 可以用以下式子来计算:
那么我们在具体的使用这种正规方程解来解决多元线性回归方程之前,对于 θ,下标从 0 到 n,一共 n+1 个数值,但是对于实际上我们的样本来说一共只有 n 个维度,其中这个 θ0 是截距(intercept),在有的时候,我们进行线性回归的时候,最终报告给用户相应的结果的时候,有可能不是将这个 θ 整体报告给用户,而是将截距和系数(coefficients)分开,这样做的原因是在系数部分每一个 θ 值都对应着原来样本中的一个特征,那么这个系数从某种程度上来讲可以用于描述我们这些特征对于最终样本相应的这个贡献的程度是怎样的,而这个截距是和我们样本的特征是不想干的,它只是一个偏移,所以我们将截距和系数分开。
对于这个系数,对我们整体样本特征相应的解释,之后会介绍,在这里,先了解一下截距和系数之间的区别,我们具体封装属于我们自己的多元线性回归算法的时候就会采用这种分开的方式。事实上,scikit-learn 对多元线性回归的封装也是采用这种分开的方式。
下面我们来看一下具体的编程实现。
首先,我们自己实现一个线性回归算法。
# LinearRegression.py
import numpy as np
from metrics import r2_score
class LinearRegression:
def __init__(self):
"""初始化 Linear Regression"""
self.coef_ = None # 系数
self.interception_ = None # 截距
self._theta = None # θ
def fit_normal(self, X_train, y_train):
"""根据训练数据集X_train,y_train训练Linear Regression模型"""
assert X_train.shape[0] == y_train.shape[0], \
"the size of X_train must be equal to the size of y_train"
X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) # 在 X_train 前加一列 1
self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train)
self.interception_ = self._theta[0] #截距
self.coef_ = self._theta[1:] #系数
return self
def predict(self, X_predict):
"""给定待预测数据集X_predict,返回表示X_predict的结果向量"""
assert self.interception_ is not None and self.coef_ is not None, \
"must fit before predict!"
assert X_predict.shape[1] == len(self.coef_), \
"the feature number of X_predict must be equal to X_train"
X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])
return X_b.dot(self._theta)
def score(self, X_test, y_test):
"""根据测试数据集X_test和y_test确定当前模型的准确度"""
y_predict = self.predict(X_test)
return r2_score(y_test, y_predict)
def __repr__(self):
return "LinearRegression()"
下面我们开始测试:
通过这个过程,相信我们对 sklearn 中的机器学习算法的套路也有了更深刻的了解,首先定义一个对象,然后再使用 fit 方法训练出一个模型得到相应的参数,然后再使用 score 方法来预测正确率。其实线性回归法还有更强大的一面,那就是它对我们的数据是具有可解释性的。在下一片博客就会介绍这个可解释性到底怎么回事?并对之前学习的线性回归法做一个总结~~~
具体代码见 17 实现多元线性回归.ipynb