ML-线性回归
线性回归
对于每一个样本数据\(x=(x_{1},x_{2},...,x_{n})\),希望拟合出一个模型 f(x)。当有新的数据输入时,可以给出误差最小的估计值。假设函数如下:
可以写成向量的形式,其中\(\theta =\{\theta_{0}, \theta_{1}, \theta_{2}, ..., \theta_{n}\}\),\(x^{(i)} =\{x_{0},x_{1},x_{2},...,x_{n}\}\), \(\theta x^{(i)}\)表示向量的内积,即 \(y^{(i)}\) ,下面的式子表示的是向量的运算
最后,对于所有的训练数据,将训练数据表示成矩阵形式 \(X_b\), \(\theta\) 是权重矩阵
所有的预测结果可以表示为列矩阵\(\hat{y}\),注意此时的\(\hat{y}\)是预测的结果,计算误差时还需要与给定的训练集中的结果y比较:
对于数据集 \(D=\{(x_{1}, y_{1}), (x_{2}, y_{2}), ...,(x_{m}, y_{m})\}\) ,算法希望得到一个模型,是的预测的值\(f(x)\)与\(y_{i}\)的误差最小。预测的误差可以用代价函数来表示,以下式子也称为均方误差:
注意:这里的\(J(\theta)\) 中只有 \(\theta ^ {(i)}\) 是变量,变量一共有m个,x都是已知的,对每一个变量求偏导数,更新每一个 \(\theta^{(i)}\)的值。一直到出现了某组 \(\theta\) 可以使\(J(\theta)\)取最小值(梯度下降法)
那么接下来要做的,就是求出这个代价函数的最小值。当代价函数取最小值时 $\theta $的值就是拟合的结果。
交叉验证
将数据随机划分为训练集和测试集。感觉这里写的还不是很好,没有考虑到正反情况的均匀分布。先copy来参考一下:
def train_test_split(X, y, test_ratio=0.2, seed=None):
"""将数据 X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test"""
assert X.shape[0] == y.shape[0], \
"the size of X must be equal to the size of y"
assert 0.0 <= test_ratio <= 1.0, \
"test_ration must be valid"
if seed:
np.random.seed(seed)
shuffled_indexes = np.random.permutation(len(X))
test_size = int(len(X) * test_ratio)
test_indexes = shuffled_indexes[:test_size]
train_indexes = shuffled_indexes[test_size:]
X_train = X[train_indexes]
y_train = y[train_indexes]
X_test = X[test_indexes]
y_test = y[test_indexes]
return X_train, X_test, y_train, y_test
正规方程法
- 不需要迭代,直接算出 \(\theta\)
- 当规模n很大时,会影响效率
- 数据不需要作归一化处理
为了求 \(J(\theta ) = \sum_{i=1}^{m}(f(x_{i})-y_{i})^{2}\)的最小值,对每个 \(\theta\)分量求导数,并令分量上的导数为0。最后会得到如下结果:
但是,不是所有X都能算出 \((X^{T}X)^{-1}\),如果该矩阵不可逆,就会算出多个结果。但是,一般情况下,都是可逆的
使用python实现很方便:
class LinearRegression:
"""具有通用性的多元线性回归的实现"""
def __init__(self):
self.coef_ = None # 表示参数,theta_[1:]
self.intercept_ = None # 表示截距 ==>theta[0]
self._thera = None # 表示完整的theta==> theta[:]
def fit_normal(self, x_train, y_train):
"""拟合"""
# 构造数据集矩阵
X_b = np.hstack([np.ones((len(x_train), 1)), x_train])
# 计算系数
self._thera = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train)
self.coef_ = self._thera[1:]
self.intercept_ = self._thera[0]
return self
def predict(self, x_test):
X_b = np.hstack(np.ones(len(x_test), 1), x_test)
return X_b.dot(self._thera)
使用 scikit-learn 解决回归问题
使用sklearn的数据集
boston = datasets.load_boston()
X = boston.data # 特征数据集
y = boston.target # 目标变量
去除一些噪音,这种语法只能用在ndarray中
plt.scatter(np.arange(len(y)), y, color="red") # 有一些y顶在50的上限上
X = X[y < 50]
y = y[y < 50]
使用sklearn的LinearRegression计算参数
from LinerRegression.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from LinerRegression.metrics import r2_score
X_train, x_test, y_train, y_test = train_test_split(X, y, seed=666)
liner = LinearRegression()
liner.fit(X_train, y_train)
print("参数:", liner.coef_)
print("偏置:", liner.intercept_)
score = r2_score(y_test, liner.predict(x_test))
print(score) # R方: 0.8129794056212811
使用前面编写的LinearRegression可以得到一样的答案
reg = LinearRegression()
reg.fit(X_train, y_train)
score = r2_score(y_test, liner.predict(x_test)) # 0.8129794056212811
score2 = r2_score(y_test, reg.predict(x_test)) # 0.8129794056212811
评估
有几个公式可以评价算法的效果
均方误差 MSE(Mean Squared Error)
# x_test:测试数据的特征,y_test:测试数据的目标变量,y_predict:根据x_test预测出的y
# 就是计算(x_test, y_test) 与 (x_test, y_predict)之间的误差
y_predict = reg.predict(x_test)
np.sum((y_predict - y_test)**2) / len(y_test)
均方根误差 RMSE(Root Mean Squared Error)
from math import sqrt
rmse = sqrt(mse_test)
平均绝对误差 MAE(Mean Absolute Error)
MAE不可导,在拟合时不方便求极值,所以没法拿来作代价函数。但是在此处却可以用来衡量算法的效果。因为此处不需要求导,只是做一个衡量的标准
mae = np.sum(np.absolute(y_predict - y_test))/len(y_test)
R Square(R方)
- \(R^2<=1\)
- \(R^2\)越大越好。当预测模型没有犯错时,得到最大值1
- 当预测模型的效果等于基准模型时,为0
- 如果\(R^2<0\),说明学习到的预测模型还不如基准模型。此时很有可能我们的数据不存在线性关系
def r2_score(y_true, y_predict):
"""R方"""
return 1 - mean_squared_error(y_true, y_predict) / np.var(y_true)
scikit-learn 中的评估函数
- 没有 RMSE,可以用MSE开根号
- score(X, Y) 传递的参数是X和Y,并不是\(\hat{y}\) 和 \(y\)
- MSE 和 MAE 放在
sklearn.metrics
模块下
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
# MSE
mean_squared_error(y_test, liner.predict(x_test)
# MAE
mean_absolute_error(y_test, liner.predict(x_test))
# R方
liner.score(x_test, y_test)