本系列另一篇文章《决策树》
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=a1​x1​+a2​x2​+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=0n​x(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要减小一点点。


(图片来自互联网)

算法步骤

  1. a和b的起始值设置为零
  2. 通过模型y^=ax+b\hat{y}=ax+by^​=ax+b,我们可以算出y^\hat{y}y^​
  3. 有了y^\hat{y}y^​,就可以用优化方法算去更新参数
  4. 重复2和3,直到找到J的最小值

流程图如下:

Created with Raphaël 2.2.0开始a=0, b=0计算模型y_hat=ax+b计算a和b的微分更新a和b找到损失函数的最小值结束yesno

下图解释了模型,损失函数和优化方法之间的关系。

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机器学习手写算法系列——线性回归相关推荐

  1. python机器学习手写算法系列——逻辑回归

    从机器学习到逻辑回归 今天,我们只关注机器学习到线性回归这条线上的概念.别的以后再说.为了让大家听懂,我这次也不查维基百科了,直接按照自己的理解用大白话说,可能不是很严谨. 机器学习就是机器可以自己学 ...

  2. python机器学习手写算法系列——kmeans聚类

    从机器学习到kmeans 聚类是一种非监督学习,他和监督学习里的分类有相似之处,两者都是把样本分布到不同的组里去.区别在于,分类分析是有标签的,聚类是没有标签的.或者说,分类是有y的,聚类是没有y的, ...

  3. python机器学习手写算法系列——贝叶斯优化 Bayesian Optimization

    Bayesian Optimization 贝叶斯优化在无需求导的情况下,求一个黑盒函数的全局最优解的一系列设计策略.(Wikipedia) 最优解问题 最简单的,获得最优解的方法,就是网格搜索Gri ...

  4. python机器学习手写字体识别_Python 3 利用机器学习模型 进行手写体数字检测

    0.引言 介绍了如何生成手写体数字的数据,提取特征,借助 sklearn 机器学习模型建模,进行识别手写体数字 1-9 模型的建立和测试. 用到的几种模型: 1. LR,Logistic Regres ...

  5. 多元线性回归算法python实现_手写算法-Python代码推广多元线性回归

    1.梯度下降-矩阵形式 上篇文章介绍了一元线性回归,包括Python实现和sklearn实现的实例.对比,以及一些问题点,详情可以看这里: 链接: 手写算法-Python代码实现一元线性回归 里面封装 ...

  6. 【机器学习与算法】python手写算法:Cart树

    [机器学习与算法]python手写算法:Cart树 背景 代码 输出示例 背景 Cart树算法原理即遍历每个变量的每个分裂节点,找到增益(gini或entropy)最大的分裂节点进行二叉分割. 这里只 ...

  7. 手写算法-python代码实现Ridge(L2正则项)回归

    手写算法-python代码实现Ridge回归 Ridge简介 Ridge回归分析与python代码实现 方法一:梯度下降法求解Ridge回归参数 方法二:标准方程法实现Ridge回归 调用sklear ...

  8. python手写代码面试_常见Python面试题—手写代码系列

    原标题:常见Python面试题-手写代码系列 1.如何反向迭代一个序列 #如果是一个list,最快的方法使用reverse tempList = [1,2,3,4] tempList.reverse( ...

  9. python手写代码面试_常见Python面试题 — 手写代码系列

    原标题:常见Python面试题 - 手写代码系列 作者: Peace & Love 来自:https://blog.csdn.net/u013205877/article/details/77 ...

最新文章

  1. 大话设计模式笔记(七)の原型模式
  2. html 一行显示边框线,HTML 网页中要显示出来一个虚线的边框 就是一行字在边框里面,那个边框是显示出来的,程式码应该怎么写?...
  3. [android] AndroidManifest.xml【 manifest - permission-tree 和 manifest - permission-group】
  4. Python将list存为csv文件
  5. python基础语法快速浏览
  6. PocketSphinx语音识别系统语言模型的训练和声学模型的改进
  7. Spring Cloud云架构 - commonservice-sso服务搭建(一)
  8. Python稳基修炼之计算机等级考试易错细节题1(含答案和解析)
  9. DOS命令大全(经典收藏)【运行CMD后的命令】
  10. Problem 1108 - 淼·诺贝尔
  11. paip.提升安全性--------密码控件与软键盘
  12. Windows10三月更新后,电脑打印文件时蓝屏解决方案
  13. 2021杭电多校第三场 D题—Game on Plane(思维题)
  14. 在未来的多云世界中,选择云服务提供商,需要考虑什么?
  15. 软件硕士和计算机硕士,详解软件工程硕士和计算机硕士区别
  16. opencv实现视频实时去雾算法
  17. HTML基础DW使用教程
  18. 0Ω电阻可以过多大电流?
  19. 安装SQL2000时出现 ntvdm遇到一个硬错误的处理办法
  20. android 语音播报(通过手说tts 实现中文语音播报)

热门文章

  1. node.js安装robot.js教程
  2. phpstudy创建网页并用php输出hello world
  3. 小学生用计算机写作文,我家的电脑作文300字
  4. 如何成为一名 必学的12个基本步骤
  5. 基于SpringBoot的图书管理系统[毕业设计]
  6. 金山词霸在360极速浏览器下不能取词
  7. C4 数据集基本信息速览
  8. 微信全功能HOOK接口源码
  9. JIT是什么,我的简单理解
  10. 计算机相关专业知识试题及答案,计算机专业知识试题及答案