python机器学习手写算法系列——线性回归
本系列另一篇文章《决策树》
https://blog.csdn.net/juwikuang/article/details/89333344
本文源代码:
https://github.com/juwikuang/machine_learning_step_by_step
最近我发现我之前写的一篇文章《一个公式告诉你为什么程序员要转算法工程师》
http://blog.csdn.net/juwikuang/article/details/73057194
有很多人访问。我想,很多程序员和我当初一样,想从程序员转算法工程师。
说说我当初为什么会想到升级成算法工程师。记得三年前,我还在印孚瑟斯(Infosys),我们的CFO非常自豪的宣布公司已经成功的让专科生的比例提高了,让本科生的比例降低了。我作为一个本科程序员,听了十分难受。当然,公司这样做是为了利润,也合理合法。换了我是CFO,我也会这样做,不过,我应该不会像他一样大声说。有些事,可以做,不能说。
后来,机缘巧合,我学习了机器学习,走上了算法工程师这条路。当时我学机器学习,是从吴恩达(Andrew Ng)的Coursera课程开始的。很多人和我一样,也是开了这门课,开始机器学习的。这门课挺好,可惜开发语言用了Octave,以至于我每次写作业,都很痛苦,因为我还要学Octave语言,而且这东西学了也没啥用。另外,这门课是英语的,只有少数人能看懂。
本文的目的,就是从最基本,最简单的机器学习算法讲起,手把手的教你实现这个算法。一边编程,一边就明白这个算法的原理了。我本人也是程序员转的算法工程师,我们的强项就是编程,弱项就是数学。我针对这个特点,专门做了以下教程。
言归正传。首先我们看看线性回归在整个机器学习里的位置。
从机器学习到线性回归
今天,我们只关注机器学习到线性回归这条线上的概念。别的以后再说。为了让大家听懂,我这次也不查维基百科了,直接按照自己的理解用大白话说,可能不是很严谨。
机器学习就是机器可以自己学习,而机器学习的方法就是利用现有的数据和算法,解出算法的参数。从而得到可以用的模型。
监督学习就是利用已有的数据(我们叫X,或者特征),和数据的标注(我们叫Y),找到x和y之间的对应关系,或者说是函数f。
回归分析是一种因变量为连续值得监督学习。
线性回归是一种x和y之间的关系为线性关系的回归分析。y=a1x1+a2x2+by=a_1x_1+a_2x_2+by=a1x1+a2x2+b,这个叫线性关系。如果这里出现了x2x^2x2,log(x)log(x)log(x), sin(x)sin(x)sin(x)之类的,那就不是线性关系了。
一元线性回归说的是,自变量x是一个纯量(scalar)。scalar类型的变量,是不可再分的。
我希望你能说明白这些概念的关系。不过,我自己也是花了很久才了解清楚的。如果你没听明白,也没关系。毕竟都是概念,没什么实际的例子,也很难理解。等你看完了本文,了解了一元线性回归。回过头来再看这些概念,就能更好的理解了。
问题
这里,我们的问题是,找出算法工程师和程序员之间的工资关系。这里直接给出北京,上海,杭州,深圳,广州的工资。
城市 | x-程序员工资 | y-算法工程师工资 |
---|---|---|
北京 | 1.3854 | 2.1332 |
上海 | 1.2213 | 2.0162 |
杭州 | 1.1009 | 1.9138 |
深圳 | 1.0655 | 1.8621 |
广州 | 0.09503 | 1.8016 |
把他们用图打出来看看他们之间的关系。
由图可见,他们之间大致是一个线性关系,这时候,我们就可以试着用一元线性回归去拟合(fit)他们之间的关系。
数学模型
一元线性回归公式
以下是公式
y=ax+b+εy=ax+b+εy=ax+b+ε
y 为应变量 dependent variable
x 为自变量 independent variable
a 为斜率 coeffient
b 为截距 intercept
ε (读作epsilon)为误差,正态分布
线性回归的目标是,找到一组a和b,使得ε最小
y^=ax+b\hat{y}=ax+by^=ax+b
ε=y−y^ε=y-\hat{y}ε=y−y^
y^\hat{y}y^ 读作y hat,也有人读作y帽子。这里的帽子一般表示估计值,用来区别真实值y。
下图可以更好的帮助你理解。
(图片来自互联网)
黑色的点为观测样本,即y=ax+b+εy=ax+b+εy=ax+b+ε。
x红色的线为回归线,即y^=ax+b\hat{y}=ax+by^=ax+b。
x蓝色的线段为误差,即ε=y−y^ε=y-\hat{y}ε=y−y^
方差 - 损失函数 Cost Function
在机器学习中,很多时候,我们需要找到一个损失函数。有了损失函数,我们就可以经过不断地迭代,找到损失函数的全局或者局部最小值(或者最大值)。损失函数使得我们的问题转化成数学问题,从而可以用计算机求解。在线性回归中,我们用方差作为损失函数。我们的目标是使得方差最小。
下面的表格解释了什么是方差。
其中SSE(Sum of Square Error)是总的方差,MSE(Mean Square Error)是方差的平均值。
而这里的损失函数,用的是0.5 * MSE。即:
J(a,b)=12n∑i=0n(yi−y^i)2J(a,b)=\frac{1}{2n}\sum_{i=0}^{n}(y_i−\hat{y}_i )^2J(a,b)=2n1∑i=0n(yi−y^i)2
记住,这里的损失函数是针对参数a和b的函数,y和y^\hat{y}y^ 其实都是已知的。
优化方法 Optimization Function
有了损失函数,我们还需要一个方法,使得我们可以找到这个损失函数的最小值。机器学习把他叫做优化方法。这里的优化方法,就是算损失的方向。或者说,当我的参数变化的时候,我的损失是变大了还是变小了。如果a变大了,损失变小了。那么,说明a增大这个方向是正确的,我们可以朝着这个方向继续小幅度的前进。反之,就应该考虑往相反的方向试试看。因为每个参数(a和b)都是一维的,所以,所谓的方向,无非就是正负符号。
这里,我们需要用偏微分的方法,得到损失函数的变化量。即:
∂J∂a=∂12n∑i=0n(yi−y^i)2∂a\frac{\partial J}{\partial a} = \frac{\partial \frac{1}{2n}\sum_{i=0}^{n}(y_i−\hat{y}_i )^2}{\partial a}∂a∂J=∂a∂2n1∑i=0n(yi−y^i)2
=1n∑i=0n(yi−axi−b)∂(yi−axi−b)∂a= \frac{1}{n}\sum_{i=0}^{n}(y_i-ax_i-b) \frac{\partial (y_i-ax_i-b)}{\partial a}=n1∑i=0n(yi−axi−b)∂a∂(yi−axi−b)
=1n∑i=0n(yi−axi−b)(−xi)= \frac{1}{n}\sum_{i=0}^{n}(y_i-ax_i-b) (-x_i)=n1∑i=0n(yi−axi−b)(−xi)
=1n∑i=0nx(y^i−yi)= \frac{1}{n}\sum_{i=0}^{n}x(\hat{y}_i-y_i)=n1∑i=0nx(y^i−yi)
∂J∂b=∂12n∑i=0n(yi−y^i)2∂a\frac{\partial J}{\partial b} = \frac{\partial \frac{1}{2n}\sum_{i=0}^{n}(y_i−\hat{y}_i )^2}{\partial a}∂b∂J=∂a∂2n1∑i=0n(yi−y^i)2
=1n∑i=0n(yi−axi−b)∂(yi−axi−b)∂b= \frac{1}{n}\sum_{i=0}^{n}(y_i-ax_i-b) \frac{\partial (y_i-ax_i-b)}{\partial b}=n1∑i=0n(yi−axi−b)∂b∂(yi−axi−b)
=1n∑i=0n(yi−axi−b)(−1)= \frac{1}{n}\sum_{i=0}^{n}(y_i-ax_i-b) (-1)=n1∑i=0n(yi−axi−b)(−1)
=1n∑i=0n(y^i−yi)= \frac{1}{n}\sum_{i=0}^{n}(\hat{y}_i-y_i)=n1∑i=0n(y^i−yi)
如果你已经忘了微积分,你暂时可以不必纠结上面的公式,只要知道公式给出了损失函数的变化就可以了。伟大的python还提供了sympy,你可以用sympy做微积分。这部分我也放在附件代码里了,有兴趣的可以看一下。
之前说到,整过迭代过程是小幅度进行的。这里,就需要一个超参数来控制这个过程。这个超参数就是α\alphaα,通常是0.01.
这时,我们就可以去更新a和b的值:
a=a−α∂J∂aa = a - \alpha \frac{\partial J}{\partial a}a=a−α∂a∂J
b=b−α∂J∂bb = b - \alpha \frac{\partial J}{\partial b}b=b−α∂b∂J
到这里,在你继续往下读之前,你先自己考虑一下,为什么这里是负号?
你考虑好了么,如果你考虑好了,我就公布答案了。
本身∂J∂a\frac{\partial J}{\partial a}∂a∂J 和 ∂J∂b\frac{\partial J}{\partial b}∂b∂J 是损失函数的变化量。如果损失函数随着a变大了,即 ∂J∂a\frac{\partial J}{\partial a}∂a∂J 为正。说明a的增大会导致损失函数的增大。那么是不是说,a的减小会使得损失函数减小呢?而我们的目标是使得J最小,所以,这个时候,我们的a要减小一点点。
(图片来自互联网)
算法步骤
- a和b的起始值设置为零
- 通过模型y^=ax+b\hat{y}=ax+by^=ax+b,我们可以算出y^\hat{y}y^
- 有了y^\hat{y}y^,就可以用优化方法算去更新参数
- 重复2和3,直到找到J的最小值
流程图如下:
下图解释了模型,损失函数和优化方法之间的关系。
Python 实现
理论部分先告一段落,我们现在开始写代码,实现一元线性回归。
首先是模型,这个很简单:
def model(a, b, x):return a*x + b
接着,是损失函数:
def cost_function(a, b, x, y):n = 5return 0.5/n * (np.square(y-a*x-b)).sum()
最后,是优化函数:
def optimize(a,b,x,y):n = 5alpha = 1e-1y_hat = model(a,b,x)da = (1.0/n) * ((y_hat-y)*x).sum()db = (1.0/n) * ((y_hat-y).sum())a = a - alpha*dab = b - alpha*dbreturn a, b
以上三个函数中a和b是标量(scalar value),x和y是向量(vector)
至此,一元线性回归的主要部分就完成了。一共才14行代码,是不是很简单。
训练模型
有了模型,损失函数,优化函数,我们就可以训练模型了。具体过程请见附件代码。
这里给出分别训练1次,再训练5次,再训练10次,再训练100,再训练10000次的模型。
从上面几幅图,我们可以看到,随着训练次数的增加,回归线越来越接近样本了。我们自己写的线性回归比较简单,我只能目测,凭直觉感觉损失函数已经达到了最小值,我们就停在10000次吧。
看得再多,不如自己动手。阅读下一章节之前,请自己实现一元线性回归。
这里有现成的代码,供你参考。
http://download.csdn.net/download/juwikuang/10050886
模型评价
在机器学习中,模型的好坏是有标准的。在回归模型中,我们用R2R^2R2 来评价模型。公式:
R2=SSR/SSTR^2=SSR/SSTR2=SSR/SST
其中
SSR=∑i=0n(y^i−yˉ)SSR=\sum_{i=0}^{n}(\hat{y}_i-\bar{y})SSR=∑i=0n(y^i−yˉ)
SST=∑i=0n(yi−yˉ)SST=\sum_{i=0}^{n}(y_i-\bar{y})SST=∑i=0n(yi−yˉ)
yˉ\bar{y}yˉ 读作y bar,是y的平均值。
可以证明SST=SSR+SSESST=SSR+SSESST=SSR+SSE,证明过程又会涉及到期望等概念,我们这里不展开了。
好了,现在你应该回到代码中去计算R2R^2R2 了。
用scikit-learn训练和评价模型
平时在工作中,我们不可能自己去写回归模型,最常用的第三方工具是scikit-learn。
其官网是:
http://scikit-learn.org/
以下是ipython代码。
import numpy as np
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
%matplotlib inlinex = [13854,12213,11009,10655,9503] #程序员工资,顺序为北京,上海,杭州,深圳,广州
x = np.reshape(x,newshape=(5,1)) / 10000.0
y = [21332, 20162, 19138, 18621, 18016] #算法工程师,顺序和上面一致
y = np.reshape(y,newshape=(5,1)) / 10000.0
# 调用模型
lr = LinearRegression()
# 训练模型
lr.fit(x,y)
# 计算R平方
print lr.score(x,y)
# 计算y_hat
y_hat = lr.predict(x)
# 打印出图
plt.scatter(x,y)
plt.plot(x, y_hat)
plt.show()
恭喜你,看完了本文,也学会了一元线性回归。如果对你有帮助,请给我一个赞。你的支持和鼓励是我继续写下去的动力。
如果有疑问,请下面留言。
python机器学习手写算法系列
完整源代码:
https://github.com/juwikuang/machine_learning_step_by_step
欢迎阅读本系列其他文章:
《python机器学习手写算法系列——线性回归》
《python机器学习手写算法系列——逻辑回归》
《python机器学习手写算法系列——决策树》
《python机器学习手写算法系列——kmeans聚类》
python机器学习手写算法系列——线性回归相关推荐
- python机器学习手写算法系列——逻辑回归
从机器学习到逻辑回归 今天,我们只关注机器学习到线性回归这条线上的概念.别的以后再说.为了让大家听懂,我这次也不查维基百科了,直接按照自己的理解用大白话说,可能不是很严谨. 机器学习就是机器可以自己学 ...
- python机器学习手写算法系列——kmeans聚类
从机器学习到kmeans 聚类是一种非监督学习,他和监督学习里的分类有相似之处,两者都是把样本分布到不同的组里去.区别在于,分类分析是有标签的,聚类是没有标签的.或者说,分类是有y的,聚类是没有y的, ...
- python机器学习手写算法系列——贝叶斯优化 Bayesian Optimization
Bayesian Optimization 贝叶斯优化在无需求导的情况下,求一个黑盒函数的全局最优解的一系列设计策略.(Wikipedia) 最优解问题 最简单的,获得最优解的方法,就是网格搜索Gri ...
- python机器学习手写字体识别_Python 3 利用机器学习模型 进行手写体数字检测
0.引言 介绍了如何生成手写体数字的数据,提取特征,借助 sklearn 机器学习模型建模,进行识别手写体数字 1-9 模型的建立和测试. 用到的几种模型: 1. LR,Logistic Regres ...
- 多元线性回归算法python实现_手写算法-Python代码推广多元线性回归
1.梯度下降-矩阵形式 上篇文章介绍了一元线性回归,包括Python实现和sklearn实现的实例.对比,以及一些问题点,详情可以看这里: 链接: 手写算法-Python代码实现一元线性回归 里面封装 ...
- 【机器学习与算法】python手写算法:Cart树
[机器学习与算法]python手写算法:Cart树 背景 代码 输出示例 背景 Cart树算法原理即遍历每个变量的每个分裂节点,找到增益(gini或entropy)最大的分裂节点进行二叉分割. 这里只 ...
- 手写算法-python代码实现Ridge(L2正则项)回归
手写算法-python代码实现Ridge回归 Ridge简介 Ridge回归分析与python代码实现 方法一:梯度下降法求解Ridge回归参数 方法二:标准方程法实现Ridge回归 调用sklear ...
- python手写代码面试_常见Python面试题—手写代码系列
原标题:常见Python面试题-手写代码系列 1.如何反向迭代一个序列 #如果是一个list,最快的方法使用reverse tempList = [1,2,3,4] tempList.reverse( ...
- python手写代码面试_常见Python面试题 — 手写代码系列
原标题:常见Python面试题 - 手写代码系列 作者: Peace & Love 来自:https://blog.csdn.net/u013205877/article/details/77 ...
最新文章
- 大话设计模式笔记(七)の原型模式
- html 一行显示边框线,HTML 网页中要显示出来一个虚线的边框 就是一行字在边框里面,那个边框是显示出来的,程式码应该怎么写?...
- [android] AndroidManifest.xml【 manifest - permission-tree 和 manifest - permission-group】
- Python将list存为csv文件
- python基础语法快速浏览
- PocketSphinx语音识别系统语言模型的训练和声学模型的改进
- Spring Cloud云架构 - commonservice-sso服务搭建(一)
- Python稳基修炼之计算机等级考试易错细节题1(含答案和解析)
- DOS命令大全(经典收藏)【运行CMD后的命令】
- Problem 1108 - 淼·诺贝尔
- paip.提升安全性--------密码控件与软键盘
- Windows10三月更新后,电脑打印文件时蓝屏解决方案
- 2021杭电多校第三场 D题—Game on Plane(思维题)
- 在未来的多云世界中,选择云服务提供商,需要考虑什么?
- 软件硕士和计算机硕士,详解软件工程硕士和计算机硕士区别
- opencv实现视频实时去雾算法
- HTML基础DW使用教程
- 0Ω电阻可以过多大电流?
- 安装SQL2000时出现 ntvdm遇到一个硬错误的处理办法
- android 语音播报(通过手说tts 实现中文语音播报)