Python机器学习算法入门之梯度下降法实现线性回归

简介:

1. 背景

文章的背景取自An Introduction to Gradient Descent and Linear Regression,本文想在该文章的基础上,完整地描述线性回归算法。部分数据和图片取自该文章。没有太多时间抠细节,所以难免有什么缺漏错误之处,望指正。

线性回归的目标很简单,就是用一条线,来拟合这些点,并且使得点集与拟合函数间的误差最小。如果这个函数曲线是一条直线,那就被称为线性回归,如果曲线是一条二次曲线,就被称为二次回归。数据来自于GradientDescentExample中的data.csv文件,共100个数据点,如下图所示:


我们的目标是用一条直线来拟合这些点。既然是二维,那 么y = b + m x 这个公式相信对于中国学生都很熟悉。其中 b 是直线在y轴的截距(y-intercept), m 是直线的斜率(slope)。寻找最佳拟合直线的过程,其实就是寻找最佳的 b m 的过程。为了寻找最佳的拟合直线,这里首先要定义,什么样的直线才是最佳的直线。我们定义误差(cost function):

E r r o r ( b , m ) = 1 N 1 N ( ( b + m x i ) y i ) 2

计算损失函数的python代码如下:

# y = b + mx

def compute_error_for_line_given_points(b, m, points):

totalError = sum((((b + m * point[0]) - point[1]) ** 2 for point in points))

return totalError / float(len(points))

现在问题被转化为,寻找参数 b m ,使得误差函数 E r r o r ( b , m ) 有最小值。在这里, x i y i 都被视为已知值。从下图看,最小二乘法所做的是通过数学推导直接计算得到最低点;而梯度下降法所做的是从图中的任意一点开始,逐步找到图的最低点。

2. 多元线性回归模型

从机器学习的角度来说,以上的数据只有一个feature,所以用一元线性回归模型即可。这里我们将一元线性模型的结论一般化,即推广到多元线性回归模型。这部分内部参考了机器学习中的数学(1)-回归(regression)、梯度下降(gradient descent)。假设有 x 1 x 2 , x n n 个feature, θ x 的系数,则

h θ ( x ) = θ 0 + θ 1 x 1 + . . . + θ n x n = θ T x x 0 = 1


J ( θ ) = 1 2 i = 1 m ( h θ ( x ( i ) ) y ( i ) ) 2 m m

更一般地,我们可以得到广义线性回归。 ϕ ( x ) 可以换成不同的函数,从而得到的拟合函数就不一定是一条直线了。

广 线

h θ ( x ) = θ T x = θ 0 + i = 1 n θ i ϕ i ( x i )

2.1 误差函数的进一步思考

这里有一个有意思的东西,就是误差函数为什么要写成这样的形式。首先是误差函数最前面的系数 1 2 ,这个参数其实对结果并没有什么影响,这里之所以取 1 2 ,是为了抵消求偏导过程中得到的 2 。可以实验,把 E r r o r ( b , m ) 最前面的 1 N 修改或者删除并不会改变最终的拟合结果。那么为什么要使用平方误差呢?考虑以下公式:

y ( i ) = θ T x ( i ) + ε ( i )

假定误差 ε ( i ) ( 1 i m ) 是独立同分布的,由中心极限定理可得, ε ( i ) 服从均值为 0 ,方差为 σ 2 的正态分布(均值若不为0,可以归约到 θ 0 )。进一步的推导来自从@邹博_机器学习的机器学习课件。

所以求 m a x L ( θ ) 的过程,就变成了求 m i n J ( θ ) 的过程,从理论上解释了误差函数 J ( θ ) 的由来。

3 最小二乘法求误差函数最优解

最小二乘法(normal equation)相信大家都很熟悉,这里简单进行解释并提供python实现。首先,我们进一步把 J ( θ ) 写成矩阵的形式。 X m n 列的矩阵(代表 m 个样本,每个样本有 n 个feature), θ Y m 1 列的矩阵。所以 

J ( θ ) = 1 2 i = 1 m ( h θ ( x ( i ) ) y ( i ) ) 2 = 1 2 ( X θ Y ) T ( X θ Y )

所以 θ 的最优解为: θ = ( X T X ) 1 X T Y

当然这里可能遇到一些问题,比如 X 必须可逆,比如求逆运算时间开销较大。具体解决方案待补充。

3.1 python实现最小二乘法

这里的代码仅仅针对背景里的这个问题。部分参考了回归方法及其python实现

# 通过最小二乘法直接得到最优系数,返回计算出来的系数b, m

def least_square_regress(points):

x_mat = np.mat(np.array([np.ones([len(points)]), points[:, 0]]).T) # 转为100行2列的矩阵,2列其实只有一个feature,其中x0恒为1

y_mat = points[:, 1].reshape(len(points), 1) # 转为100行1列的矩阵

xT_x = x_mat.T * x_mat

if np.linalg.det(xT_x) == 0.0:

print('this matrix is singular,cannot inverse') # 奇异矩阵,不存在逆矩阵

return

coefficient_mat = xT_x.I * (x_mat.T * y_mat)

return coefficient_mat[0, 0], coefficient_mat[1, 0] # 即系数b和m

程序执行结果如下:
b = 7.99102098227, m = 1.32243102276, error = 110.257383466, 相关系数 = 0.773728499888

拟合结果如下图:

4. 梯度下降法求误差函数最优解

有了最小二乘法以后,我们已经可以对数据点进行拟合。但由于最小二乘法需要计算 X 的逆矩阵,计算量很大,因此特征个数多时计算会很慢,只适用于特征个数小于100000时使用;当特征数量大于100000时适合使用梯度下降法。最小二乘法与梯度下降法的区别见最小二乘法和梯度下降法有哪些区别?

4.1. 梯度

首先,我们简单回顾一下微积分中梯度的概念。这里参考了方向导数与梯度,具体的证明请务必看一下这份材料,很短很简单的。

讨论函数 z = f ( x , y ) 在某一点 P 沿某一方向的变化率问题。设函数 z = f ( x , y ) 在点 P ( x , y ) 的某一邻域 U ( P ) 内有定义,自点 P 引射线 l 到点 P ( x + Δ x , y + Δ y ) P U ( P ) ,如下图所示。

定义函数 z = f ( x , y ) 在点 P 沿方向 l 的方向导数为:

f l = lim ρ 0 f ( x + Δ x , y + Δ y ) f ( x , y ) ρ ρ = ( Δ x ) 2 + ( Δ y ) 2

方向导数可以理解为,函数 z = f ( x , y ) 沿某个方向变化的速率。可以类比一下函数 y = k x + b 的斜率 k = d y d x 。斜率越大,函数 y y 增长得越快。那么现在问题来了,函数 z = f ( x , y ) 在点 P 沿哪个方向增加的速度最快?而这个方向就是梯度的方向

g r a d f ( x , y ) = f x i + f y j

从几何角度来理解,函数 z = f ( x , y ) 表示一个曲面,曲面被平面 z = c 截得的曲线在 x o y 平面上投影如下图,这个投影也就是我们所谓的等高线。

函数 z = f ( x , y ) 在点 P ( x , y ) 处的梯度方向与点 P 的等高线 f ( x , y ) = c 在这点的法向量的方向相同,且从数值较低的等高线指向数值较高的等高线。

4.2 梯度方向计算

理解了梯度的概念之后,我们重新回到1. 背景中提到的例子。1. 背景提到,梯度下降法所做的是从图中的任意一点开始,逐步找到图的最低点。那么现在问题来了,从任意一点开始, b m 可以往任意方向"走",如何可以保证我们走的方向一定是使误差函数 E r r o r ( b , m ) 减小且减小最快的方向呢?回忆4.1.梯度中提到的结论,梯度的方向是函数上升最快的方向,那么函数下降最快的方向,也就是梯度的反方向。有了这个思路,我们首先计算梯度方向,

E r r o r ( b , m ) m = i = 1 N x i ( ( b + m x i ) y i )

E r r o r ( b , m ) b = i = 1 N ( ( b + m x i ) y i ) x 0 1

有了这两个结果,我们就可以开始使用梯度下降法来寻找误差函数 E r r o r ( b , m ) 的最低点。我们从任意的点 ( b , m ) 开始,逐步地沿梯度的负方向改变 b m 的值。每一次改变, E r r o r ( b , m ) 都会得到更小的值,反复进行该操作,逐步逼近 E r r o r ( b , m ) 的最低点。

回到更一般的情况,对于每一个向量 θ 的每一维分量 θ i ,我们都可以求出梯度的方向,也就是错误函数 J ( θ ) 下降最快的方向: 

θ j J ( θ ) = θ j 1 2 i = 1 m ( h θ ( x ( i ) ) y ( i ) ) 2 = i = 1 m ( h θ ( x ( i ) ) y ( i ) ) x j ( i )

4.3 批量梯度下降法

从上面的公式中,我们进一步得到特征的参数 θ j 的迭代式。因为这个迭代式需要把m个样本全部带入计算,所以我们称之为批量梯度下降

θ j = θ j α J ( θ ) θ j = θ j α i = 1 m ( h θ ( x ( i ) ) y ( i ) ) x j ( i )

针对此例,梯度下降法一次迭代过程的python代码如下:

def step_gradient(b_current, m_current, points, learningRate):

b_gradient = 0

m_gradient = 0

N = float(len(points))

for i in range(0, len(points)):

x = points[i, 0]

y = points[i, 1]

m_gradient += (2 / N) * x * ((b_current + m_current * x) - y)

b_gradient += (2 / N) * ((b_current + m_current * x) - y)

new_b = b_current - (learningRate * b_gradient) # 沿梯度负方向

new_m = m_current - (learningRate * m_gradient) # 沿梯度负方向

return [new_b, new_m]

其中learningRate是学习速率,它决定了逼近最低点的速率。可以想到的是,如果learningRate太大,则可能导致我们不断地最低点附近来回震荡;而learningRate太小,则会导致逼近的速度太慢。An Introduction to Gradient Descent and Linear Regression提供了完整的实现代码GradientDescentExample

这里多插入一句,如何在python中生成GIF动图。配置的过程参考了使用Matplotlib和Imagemagick实现算法可视化与GIF导出。需要安装ImageMagick,使用到的python库是Wand: a ctypes-based simple ImageMagick binding for Python。然后修改C:\Python27\Lib\site-packages\matplotlib__init__.py文件,在

# this is the instance used by the matplotlib classes

rcParams = rc_params()

后面加上:

# fix a bug by ZZR
rcParams['animation.convert_path'] = 'C:\Program Files\ImageMagick-6.9.2-Q16\convert.exe'

即可在python中调用ImageMagick。如何画动图参见Matplotlib动画指南,不再赘述。learningRate=0.0001,迭代100轮的结果如下图:

After {100} iterations b = 0.0350749705923, m = 1.47880271753, error = 112.647056643, 相关系数 = 0.773728499888
After {1000} iterations b = 0.0889365199374, m = 1.47774408519, error = 112.614810116, 相关系数 = 0.773728499888
After {1w} iterations b = 0.607898599705, m = 1.46754404363, error = 112.315334271, 相关系数 = 0.773728499888
After {10w} iterations b = 4.24798444022, m = 1.39599926553, error = 110.786319297, 相关系数 = 0.773728499888

4.4 随机梯度下降法

批量梯度下降法每次迭代都要用到训练集的所有数据,计算量很大,针对这种不足,引入了随机梯度下降法。随机梯度下降法每次迭代只使用单个样本,迭代公式如下:

θ j = θ j α ( h θ ( x ( i ) ) y ( i ) ) x j ( i )

可以看出,随机梯度下降法是减小单个样本的错误函数,每次迭代不一定都是向着全局最优方向,但大方向是朝着全局最优的。

这里还有一些重要的细节没有提及,比如如何确实learningRate,如果判断何时递归可以结束等等。



原文发布时间为:2016-12-01
本文作者:ZZR
本文来自云栖社区合作伙伴“ Python中文社区”,了解相关信息可以关注“ Python中文社区”微信公众号
相关文章
|
2天前
|
数据采集 机器学习/深度学习 人工智能
Python编程入门:从基础到实战
【10月更文挑战第24天】本文将带你进入Python的世界,从最基础的语法开始,逐步深入到实际的项目应用。我们将一起探索Python的强大功能和灵活性,无论你是编程新手还是有经验的开发者,都能在这篇文章中找到有价值的内容。让我们一起开启Python的奇妙之旅吧!
|
4天前
|
数据采集 存储 数据库
Python中实现简单爬虫的入门指南
【10月更文挑战第22天】本文将带你进入Python爬虫的世界,从基础概念到实战操作,一步步指导你如何使用Python编写一个简单的网络爬虫。我们将不展示代码示例,而是通过详细的步骤描述和逻辑讲解,帮助你理解爬虫的工作原理和开发过程。无论你是编程新手还是有一定经验的开发者,这篇文章都将为你打开一扇通往数据收集新世界的大门。
|
2天前
|
测试技术 开发者 Python
探索Python中的装饰器:从入门到实践
【10月更文挑战第24天】 在Python的世界里,装饰器是一个既神秘又强大的工具。它们就像是程序的“隐形斗篷”,能在不改变原有代码结构的情况下,增加新的功能。本篇文章将带你走进装饰器的世界,从基础概念出发,通过实际例子,逐步深入到装饰器的高级应用,让你的代码更加优雅和高效。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开一扇通往高效编程的大门。
|
4天前
|
存储 人工智能 数据挖掘
Python编程入门:构建你的第一个程序
【10月更文挑战第22天】编程,这个听起来高深莫测的词汇,实际上就像搭积木一样简单有趣。本文将带你走进Python的世界,用最浅显的语言和实例,让你轻松掌握编写第一个Python程序的方法。无论你是编程新手还是希望了解Python的爱好者,这篇文章都将是你的理想起点。让我们一起开始这段奇妙的编程之旅吧!
13 3
|
3天前
|
机器学习/深度学习 人工智能 算法
机器学习基础:使用Python和Scikit-learn入门
机器学习基础:使用Python和Scikit-learn入门
11 1
|
6天前
|
机器学习/深度学习 数据可视化 Python
使用最小二乘法进行线性回归(Python)
【10月更文挑战第28天】本文介绍了使用Python实现最小二乘法进行线性回归的步骤,包括数据准备、计算均值、计算斜率和截距、构建线性回归方程以及预测和可视化结果。通过示例代码展示了如何从创建数据点到最终绘制回归直线的完整过程。
|
4天前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
12 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
|
5天前
|
存储 程序员 开发者
Python编程入门:从零开始掌握基础语法
【10月更文挑战第21天】本文将带你走进Python的世界,通过浅显易懂的语言和实例,让你快速了解并掌握Python的基础语法。无论你是编程新手还是想学习一门新的编程语言,这篇文章都将是你的不二之选。我们将一起探索变量、数据类型、运算符、控制结构、函数等基本概念,并通过实际代码示例加深理解。准备好了吗?让我们开始吧!
|
5天前
|
数据采集 机器学习/深度学习 数据可视化
深入浅出:用Python进行数据分析的入门指南
【10月更文挑战第21天】 在信息爆炸的时代,掌握数据分析技能就像拥有一把钥匙,能够解锁隐藏在庞大数据集背后的秘密。本文将引导你通过Python语言,学习如何从零开始进行数据分析。我们将一起探索数据的收集、处理、分析和可视化等步骤,并最终学会如何利用数据讲故事。无论你是编程新手还是希望提升数据分析能力的专业人士,这篇文章都将为你提供一条清晰的学习路径。
|
6月前
|
人工智能 Java Python
python入门(二)安装第三方包
python入门(二)安装第三方包

热门文章

最新文章