机器学习(一)——机器学习概述和线性回归
文章目录
机器学习基本概念
什么是机器学习
在讨论机器学习(Machine Learning)之前,首先我们先回顾一下人是怎么样进行学习的:当一个人碰到一个问题时,他会根据自己以往的履历和经验,针对该问题得到一个解决方案,并从这个问题的结果中,再次吸取教训和经验,不断完善自己。
机器学习其实就是模仿这样的一个过程,让机器“学会”人类学习的过程。换句话说,就是让计算机能在各种各样的“经历”(在计算机中,指的就是数据)中“总结”出一套解决方案,并在碰见新案例时,能够做出判断。
机器学习和传统编程的区别
1959年,Arthur Samuel给出了机器学习的一个非正式定义,原文如下:
Machine learning: Field of study that gives computers the ability to learn without being explicitly programed.
翻译一下,机器学习是研究如何在不被精确编程的情况下赋予计算机学习能力的一个领域。事实上,这也是机器学习与传统编程的区别:机器学习通过由人给机器制定一套学习方案,对于不同的问题、不同的数据可以使用类似的一套学习方案得到适用于特定情况的解决方案;而传统编程只能对特定的问题制定特定的方案,而对于其他问题,这一套方案就束手无策。
举个栗子,比如我们现在要让计算机学会辨别一朵花是梅花还是向日葵。传统编程是这样的:首先观察梅花和向日葵:
可以发现,梅花和向日葵在颜色和花盘大小上存在明显差异,于是就有了以下的解决方案:
机器学习则不同,它只指定这两种花在颜色和花盘大小上可能存在差异,而让机器自己去通过学习来制定分类两种花的评判标准。
可以看出,传统编程确定的解决方案只适用于分类这两种花的情况,但机器学习确定的是一种学习方法,任何在颜色和花盘大小上有差异的两种花朵都可以使用相同的学习理论,来形成自己的解决方案。
这只是一个很简单的例子,但是在很多领域,例如开发会下围棋的机器人、人脸识别器等,传统编程很难实现一个特定的方案。这时,你仍然能使用机器学习算法,来让机器去学习,去得到一个解决方案。
机器学习的分类
机器学习大体上可以分为两类:监督学习(Supervised Learning)和非监督学习(Unsupervised Learning),分类的指标是学习的数据是否有标注,也可以理解为是否有一个“正确答案”。举个栗子,我们要对一批马进行分类,如果我们按颜色分类,那么我们会给每一匹马打上标注:这匹马是棕色的,这匹马是白色的——每一匹马都有一个明确的颜色,也就是标注,这就是监督学习。如果我们按大小分类,我们只有每一匹马的身高、体重等数据,我们并没有一个标准,不能直接给它定性,但我们可以通过把相似身高、体重的马归结在一起,再来进行一些判断,这种在学习时没有“正确答案”的学习就是非监督学习。
另外,根据你的标注是离散的(例如马的颜色)或是连续的(例如房屋的价格),我们可以把监督学习再细分为分类问题和回归问题。同样地,非监督学习也可以细分为聚类和关联问题,这在以后会依次讲到。
*
线性回归
问题描述
接下来我们以机器学习中最简单的线性回归为例来说明机器学习的一般过程。
有这样一个问题:你是一名房地产大亨,目前你想要转让一幢面积为 281 m 2 281m^2 281m2的别墅,你想要知道你的别墅大概能卖多少钱,于是你去搜集了本市的别墅价格以及别墅的面积。从这堆数据中,你如何才能得到你别墅大致的价格呢?
数据分析
首先,我们将收集到的别墅价格和面积画成散点图。
我们可以大致地看出,别墅的价格和面积点近似地沿一条直线排列,于是我们想到,我们是否可以用一条直线去近似地拟合这一些点,然后根据这条直线,计算出面积为
281
m
2
281m^2
281m2时的价格呢?
确定好模型后,很快你就会发现:没有任何一条直线能完美地通过所有的点,这时,你只能做出一定的让步:允许你的模型产生误差,但要尽可能地把误差限制到最小。这就涉及到了机器学习中一个非常重要的概念:损失函数(Loss Function)。
损失函数
搭建模型的目的:使预测价格和实际价格尽可能接近。
设实际价格为
y
i
y_i
yi,预测价格为
y
i
^
\hat{y_i}
yi^,实际价格和预测价格之间的差距就构成了一种损失函数
L
L
LL
LL:
L
L
=
∑
∣
y
i
^
−
y
i
∣
LL=\sum{\left|\hat{y_i}-y_i\right|}
LL=∑∣yi^−yi∣
但绝对值函数并不是一个处处可导的函数,于是我们重新定义一个数学上容易处理的损失函数:
L
L
=
∑
(
y
i
^
−
y
i
)
2
LL=\sum(\hat{y_i}-y_i)^2
LL=∑(yi^−yi)2
根据该损失函数,我们接着就可以对模型进行训练了。
数学推导
接下来一部分,我们将对如何确定最优参数进行数学上的推导,对这部分不感兴趣的童鞋可以直接跳过。
在大多数机器学习问题中,我们都很难直接得出确定最优参数的公式,需要利用一些优化方法(如梯度下降法)来得到近似最优解。但线性回归是个例外,类似线性回归的这种简单模型求导方便,我们可以直接得出参数的解析解,下面就对线性回归参数的解析解进行数学上的推导。
我们考虑更一般的情况:设我们要预测的因变量为
y
i
^
\hat{y_i}
yi^,自变量为
x
1
x_1
x1到
x
n
x_n
xn,它们的系数分别为
a
1
a_1
a1到
a
n
a_n
an,用向量来表示,分别记作
X
\textbf{X}
X、
a
\textbf{a}
a。那么损失函数可以表示为:
L
L
=
∑
(
y
i
−
a
X
i
−
a
0
)
2
(
X
i
表
示
第
i
个
数
据
)
LL=\sum{(y_i-aX_i-a_0)^2}(X_i表示第i个数据)
LL=∑(yi−aXi−a0)2(Xi表示第i个数据)
为了方便起见,我们将
a
0
a_0
a0也并入
a
\textbf{a}
a中,并在
X
\textbf{X}
X中加入一个元素1。对
a
\textbf{a}
a求偏导数,并令它们都等于0:
∂
L
L
∂
a
j
=
−
2
∑
X
i
(
y
i
−
a
X
i
)
=
0
,
j
=
0
,
1
,
.
.
.
,
n
\frac{\partial LL}{\partial a_j}=-2\sum{X_i(y_i-aX_i)}=0,j=0,1,...,n
∂aj∂LL=−2∑Xi(yi−aXi)=0,j=0,1,...,n
设
X
i
X_i
Xi按行排列成一个矩阵
X
\textbf{X}
X,
y
i
y_i
yi构成列向量
Y
Y
Y,对上式两边约去
−
2
-2
−2后移项,写成矩阵形式为:
X
T
X
a
=
X
T
Y
X^TXa=X^TY
XTXa=XTY
这便是数学上著名的正规方程组。最后在等式两边乘上
(
X
T
X
)
−
1
(X^TX)^{-1}
(XTX)−1(假设逆矩阵存在),我们便可以得到参数的最优解析解:
a
^
=
(
X
T
X
)
−
1
X
T
Y
\hat{a}=(X^TX)^{-1}X^TY
a^=(XTX)−1XTY
编程实现
安装并导入必要的包
我们利用Python和支持矩阵运算的numpy来实现线性回归。关于安装numpy,我们只需要使用快捷键win+R打开运行窗口,输入cmd,然后在命令行窗口输入如下代码:pip install numpy
等待安装完成后,在程序中导入numpy。
# -*- coding: UTF-8 -*-
import numpy as np
编写线性回归类
对于机器学习模型而言,我们一般把一个模型当作一个类来处理,并且类中要有两个特定函数:fit函数和predict函数,分别对应训练模型和预测结果。同样的我们将线性回归模型定义成一个LinearRegression类,并编写它的fit函数和predict函数。
# -*- coding: UTF-8 -*-
import numpy as np
"""
利用numpy实现线性回归
注:本代码中的异常名可能不太符合逻辑
"""
class LinearRegression:
# 构造函数
def __init__(self, fit_intercept=True):
# 自变量的数量
self.n_features = 0
# 是否考虑截距项(不考虑则截距为0)
self.fit_intercept = fit_intercept
# 系数数组
self.coef_ = np.array([])
# 截距数组
if self.fit_intercept:
self.intercept = 0
# 训练模型
def fit(self, X, Y, axis=0):
# 把输入数据全部转化成按行排列
if len(X.shape) == 1:
if axis == 0:
x = np.array([X])
elif axis == 1:
x = X.reshape(-1, 1)
else:
raise IndexError
else:
if axis == 0:
x = np.copy(X)
elif axis == 1:
x = X.transpose()
else:
raise IndexError
y = Y.reshape(-1, 1)
self.n_features = x.shape[1]
n_sample = x.shape[0]
# 是否有截距项决定是否要拼接一列全为0的矩阵元素
if self.fit_intercept:
x = np.hstack((np.ones([n_sample, 1]), x))
# 计算参数
arg = np.dot(np.dot(np.linalg.inv(np.dot(x.transpose(), x)), x.transpose()), y)
if self.fit_intercept:
self.coef_ = arg[1:]
self.intercept = arg[0]
else:
self.coef_ = arg
# 预测数据
def predict(self, X, axis=0):
if len(X.shape) == 1:
if axis == 0:
x = np.array([X])
else:
x = X.reshape(-1, 1)
else:
if axis == 0:
x = np.copy(X)
elif axis == 1:
x = X.transpose()
else:
raise IndexError
if x.shape[1] != self.n_features:
raise IndexError
if self.fit_intercept:
x = np.hstack((np.ones([x.shape[0], 1]), x))
if len(x.shape) == 1:
x = np.array([x])
arg = np.hstack((np.array([self.intercept]), self.coef_)).reshape(-1, 1)
y = np.dot(x, arg)
else:
if len(x.shape) == 1:
x = np.array([x])
y = np.dot(x, self.coef_.reshape(-1, 1))
return y
解决问题,做出预测
使用我们已经写好的类,我们可以很方便地将数据输入,建立线性回归模型,进行训练,做出预测并进行可视化。
# -*- coding: UTF-8 -*-
"""
测试代码
"""
import numpy as np
from LinearRegression import LinearRegression
import matplotlib.pyplot as plt
import matplotlib
if __name__ == "__main__":
size = np.array([232.0, 249.0, 333.0, 212.3, 286.0, 199.2, 205.3])
prize = np.array([4370, 4880, 7660, 4000, 6000, 3550, 3800])
# 训练模型
model = LinearRegression()
model.fit(size, prize, axis=1)
# 做出预测
yPred = model.predict(np.array([281.0]), axis=1)
print(yPred[0])
# 将结果可视化
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
plt.scatter(size, prize)
plt.xlabel(u'面积($m^2$)')
plt.ylabel(u'价格(万元)')
x = np.linspace(180, 350, 1000)
y = model.predict(x,axis=1)
plt.plot(x, y, c='r')
plt.show()
最后我们得到面积为
281.0
m
2
281.0m^2
281.0m2的别墅的价格大约为5964.46万元。
小结
这篇博文主要介绍了机器学习的基本概念,并以线性回归为例介绍了机器学习的三大要素:模型函数、损失函数、优化算法。在下一篇博文中,我将对线性回归进行更深层次的讨论。