机器学习常见算法模型练习——线性回归

小鸡
阅读634 喜欢3 算法 更新2019-3-24

什么是线性回归

最简单的线性回归就是直接利用一条直线拟合二维平面上的一系列点,目的是利用这条直线概括所有训练集中样本的散布规律或趋势,最终用于新样本点的预测。二维平面上直线方程的一般形式为y=ax+b,使用训练集中的数据以某种方式训练该模型后,就可以确定方程中的两个参数a,b的最优值。后面如果观察到了新的样本xi,就可以带入上面学习到的公式计算y的值了。

在三维空间中,需要学习的是确定一个二维平面的参数;

以此类推,在n维空间中,需要学习的是确定一个n−1维的超平面的参数.

之所以称该方法为线性模型,是因为该模型是由所有特征的线性组合构成的,基本形式为:

y^=hθ(x)=θ0+θ1x1+θ2x2+⋯+θnxn⋯ (1−1)
  1. y^表示线性回归模型的预测值(相对于真实观察值);
  2. n表示特征的数量;
  3. xi表示第i个特征的观察值;
  4. θj表示第j个参数的值.
  5. 如果模型包括n个特征,那么就会包括n+1个参数,还包括常数项(还是被称为截距)。

式子(1-1)使用向量化形式可以表示为hθ=θT⋅x, 在多样本的情况下通常表示为:

hθ(x)=X⋅θ⋯ (1−2)
  • X是m⋅(n+1)的矩阵,其中m表示样本的数量;
  • θ是包含所有参数的列向量,长度为n+1.
    式子(1-2)表示所有样本值的矩阵与对应参数向量的乘积,属于矩阵乘法((Matrix multiplication)。

线性回归的代价函数

假设现在有了训练数据和模型,那么要怎么开始训练呢?这时候就必须定义一个代价函数,代价函数量化了模型预测值与实际观察值之间的误差大小。有了代价函数就可以评价取当前参数时模型性能的好坏。

在选择一个恰当的代价函数后,整个模型的训练过程就是求代价函数最小值的过程。这个过程并不容易,可能会出现下面两种情况:

  1. 得到全局最优解:即代价函数的最小值;
  2. 得到局部最优解:由于很多原因我们可能仅仅只能求的代价函数在某个区间内的极小值.

如果代价函数是一个凸函数(convex function),那么从数学上可以保证肯定能求得全局最优解;如果代价函数是非凸函数,就无法从理论上保证最终能得到代价函数的全局最优解(NP-hard问题)。

对于线性回归算法,比较常用的代价函数是均方误差(Mean Square Error, MSE)函数:

E = ∑(h(Xi)-Yi)^2 = ∑[(WXi + b) - Yi ]^2
  • 上式表示所有模型的预测值与实际观察值之差的平方和,因此训练集中任何一个实际观察值与模型预测值之间的误差都包含在了这个公式中;
  • 为了求导方便,有时添加了一个系数1/2;
  • 该函数是一个凸函数.

利用梯度下降训练模型

梯度下降几乎可以说是机器学习算法中,训练模型和调参最重要的方法了。梯度就是所有偏导数构成的向量。因为计算代价函数的梯度需要求导,这里应该是机器学习中使用微积分最多的地方了。

梯度下降的一般步骤

  1. 参数的初始化:通常所有参数都初始化为1;
  2. 确定学习率;
  3. 求代价函数的梯度(所有参数的偏导数);
  4. 所有参数都沿梯度方向移动一步,步长就是学习率的大小;
  5. 重复步骤4直到参数不再发生变化(此时取到极值点,梯度为0)或达到预先设定的迭代次数.

学习率

学习率一般用希腊字母α表示,可能需要多尝试几次,才能找到合适的学习率。过大的学习率会导致梯度下降时越过代价函数的最小值点,随着训练步数的增加,代价函数不减反增;如果学习率太小,训练中的每一步参数的变化会非常小,这时可以看到代价函数的值在不断减小,但是需要非常大的迭代次数才能到达代价函数的最小值点。

按照吴恩达老师的建议,每次可以3倍放大或者3倍缩小来调整,直到找到合适的学习率。

学习率过大会导致参数的取值越过最小值点;学习率过小会导致参数变化缓慢

代价函数的梯度

在机器学习中,对代价函数包含的每一个参数求偏导数,这些偏导数组成的向量就是代价函数的梯度。

这个时候就要用到微积分中求导数的知识了。

均方误差函数的梯度,详细内容见梯度下降介绍

一个简单的线性回归模型训练

#coding=utf-8

import numpy as np
import matplotlib.pyplot as plt
m = 100 # 样本量
X = 2 * np.random.rand(m, 1) # 取大小在区间(0, 1)上的随机数,构成一个100*1的矩阵
y = 5 + 2 * X + np.random.rand(m, 1)

# J = ∑(hθ(x(i))−y(i))^2
# 计算代价函数
def L_theta(theta, X_x0, y):
return np.sum(np.square(np.dot(X_x0, theta) - y)) # np.dot 表示矩阵乘法

def linear_regression(rate,tim):
T = tim # 迭代次数
X_x0 = np.c_[np.ones((m, 1)), X] # ADD X0 = 1 to each instance
theta=np.ones((2, 1))
for i in range(T):
theta[0, 0] -= rate * (1/m * np.sum(np.dot(X_x0, theta) - y))
theta[1, 0] -= rate * (1/m * np.sum(np.dot(np.transpose(X), np.dot(X_x0, theta) - y)))
return theta

if __name__ == "__main__":
theta = linear_regression(0.006,1000)
x2 = np.linspace(0, 2, 100)
y2 = theta[1,0] * x2 + theta[0,0]
plt.plot(X, y, "b.")
plt.plot(x2,y2,color=red)
plt.show()

来源文章
梯度下降介绍