系列文章目录
第1章 专家系统
第2章 决策树
第3章 神经元和感知机
识别手写数字——感知机
前言
感知机等早期人工智能模型采取仿生学的方法模拟生物智能机制,人们在开展这些早期研究的时候,并没有从统计学角度去深究它们的数学本质。与此同时,甚至在更早时候,统计学家已经在使用一些函数拟合或者参数估计的方法,来描述观测数据的概率分布,或者定量描述不同观测量之间的函数关系。人们假设数据符合某种分布,或者数据之间存在某种定量函数关系,通过观察数据推测概率分布或者函数关系的参数。这些方法与人工智能中的很多方法有着密切的联系,它们背后的数学原理是一致的。其后发展起来的统计学习理论帮助我们更加系统地认识统计学方法在人工智能中的应用。下面我们从最基本的线性回归开始,看如何用统计学的方法解决问题。
一、线性回归概述
学者法兰西斯·高尔顿(Francis Galton)最早在19世纪提出了回归的概念,用来描述人群的遗传特征“回归”到平均值这一规律。现代统计学意义上的回归分析已经发展成为完全不同的概念。
现代意义的回归分析是一种构建预测模型的方法,研究如何定量描述自变量和因变量之间的关系 -。我们可以将其理解为函数拟合。假设自变量和因变量之间存在某种函数关系,当我们用定量的数学形式去描述这种关系时,有一些参数是未知的。根据实际数据选取合适的参数,使得自变量和因变量之间的函数关系贴近真实观察值,这就是回归分析。
当自变量和因变量之间的关系为线性函数时,这种回归分析称为线性回归。完成回归分析后,我们可以利用得到的定量函数关系,根据给定的自变量计算出对应的因变量。而对于没有观察过的自变量取值,回归分析可以预测因变量的值。
二、最小二乘法
解决线性回归问题的方法叫作最小二乘(least square)法。这个方法的名称说明了它的目标,也就是最小化误差的平方和。
首先来看只有一个自变量(或者说自变量只有一维)的简单情况。设自变量为
x
x
x,因变量为
y
y
y,数据是若干对
(
x
(
i
)
,
y
(
i
)
)
(x_{(i)},y_{(i)})
(x(i),y(i)))(我们用带括号的下标表示样本或者数据条目的编号,把普通下标留到后面处理多特征样本或者多维度数据时,作为特征或者维度的编号)。我们希望得出线性关系
y
=
w
x
+
b
y=wx+b
y=wx+b。显然,无法使得每一个样本都精确满足
x
(
i
)
=
ω
x
(
i
)
+
b
x_{(i)}=\omega x_{(i)}+b
x(i)=ωx(i)+b,只能使误差尽量小。假设有N个样本,那么总的误差E表示如下(1/2是为了方便求导数)。
E
=
1
2
∑
i
=
1
N
(
ω
x
(
i
)
+
b
−
y
(
i
)
)
2
E = \frac{1}{2}\sum_{i=1}^{N}(\omega x_{(i)}+b-y_{(i)})^{2}
E=21i=1∑N(ωx(i)+b−y(i))2
我们发现误差是
ω
\omega
ω和
b
b
b的二次函数,而二次函数的极值点是导数为0的位置。因此,可以设导数为0,然后求解方程。
∂
E
∂
ω
=
∑
i
=
1
N
x
(
i
)
(
ω
x
(
i
)
+
b
−
y
(
i
)
)
=
0
∂
E
∂
b
=
∑
i
=
1
N
(
ω
x
(
i
)
+
b
−
y
(
i
)
)
=
0
\frac{\partial E}{\partial \omega} =\sum_{i=1}^{N} x_{(i)}(\omega x_{(i)}+b-y_{(i)})=0 \\ \frac{\partial E}{\partial b} =\sum_{i=1}^{N} (\omega x_{(i)}+b-y_{(i)})=0
∂ω∂E=i=1∑Nx(i)(ωx(i)+b−y(i))=0∂b∂E=i=1∑N(ωx(i)+b−y(i))=0
这是一个二元一次方程组,其中只有
ω
\omega
ω和
b
b
b两个变量,可以得到下面的解.
ω
=
∑
i
=
1
N
x
(
i
)
∑
i
=
1
N
y
(
i
)
−
N
∑
i
=
1
N
x
(
i
)
y
(
i
)
∑
i
=
1
N
x
(
i
)
x
(
i
)
−
N
∑
i
=
1
N
x
(
i
)
2
b
=
1
N
∑
i
=
1
N
(
y
(
i
)
−
ω
x
(
i
)
)
\omega = \frac{\sum_{i=1}^{N} x_{(i)} \sum_{i=1}^{N} y_{(i)}- N \sum_{i=1}^{N}x_{(i)}y_{(i)}} {\sum_{i=1}^{N}x_{(i)}x_{(i)}-N \sum_{i=1}^{N}x_{(i)}^{2}}\\ b = \frac{1}{N} \sum_{i=1}^{N}(y_{(i)}-\omega x_{(i)})
ω=∑i=1Nx(i)x(i)−N∑i=1Nx(i)2∑i=1Nx(i)∑i=1Ny(i)−N∑i=1Nx(i)y(i)b=N1i=1∑N(y(i)−ωx(i))
三、矩阵形式
为了将自变量维度和数据编号加以区分,我们用普通下标表示数据维度,带括号的下标表示数据编号。对于第i条数据的自变量 x ( i ) x_{(i)} x(i),它的第j维(或者说第个特征)表示为 x ( i ) j x_{(i)j} x(i)j,该维度对应的权重为 ω j \omega_{j} ωj。
为了表示方便,我们可以增加一个维度,自变量在该维度总是等于1,于是这个维度的权重就是
ω
d
+
1
=
b
\omega_{d+1}=b
ωd+1=b。这样,我们可以把所有的权重写成一个向量
ω
=
(
ω
1
,
ω
2
,
.
.
.
,
ω
d
+
1
)
T
\omega = (\omega_1,\omega_2,...,\omega_{d+1})^T
ω=(ω1,ω2,...,ωd+1)T为了方便,我们把它们转置为列向量)。
单个自变量也可以写成向量
x
(
i
)
=
(
x
(
i
)
1
,
x
(
i
)
2
,
.
.
.
,
x
(
i
)
d
,
1
)
\mathbf{x_{(i)}}=(x_{(i)1},x_{(i)2},...,x_{(i)d},1)
x(i)=(x(i)1,x(i)2,...,x(i)d,1),于是,线性预测模型可以用向量内积表示
f
(
x
)
=
x
⋅
ω
f(x)=x \cdot \omega
f(x)=x⋅ω。
因变量在数据中的取值也可以写成向量
y
(
i
)
=
(
y
(
1
)
,
y
(
2
)
,
.
.
.
,
y
(
N
)
)
T
\mathbf{y_{(i)}}=(y_{(1)},y_{(2)},...,y_{(N)})^T
y(i)=(y(1),y(2),...,y(N))T
所有数据中的自变量可以组成一个矩阵
X
\mathbf {X}
X。
X
=
(
x
(
1
)
1
x
(
1
)
2
⋯
x
(
1
)
d
1
x
(
2
)
1
x
(
2
)
2
⋯
x
(
2
)
d
1
⋮
⋮
⋱
⋮
⋮
x
(
N
)
1
x
(
N
)
2
⋯
x
(
N
)
d
1
)
X=\begin{pmatrix} x_{(1)1} & x_{(1)2} & \cdots & x_{(1)d} & 1 \\ x_{(2)1} & x_{(2)2} & \cdots & x_{(2)d} & 1 \\ \vdots & \vdots & \ddots & \vdots & \vdots \\ x_{(N)1} & x_{(N)2} & \cdots & x_{(N)d} & 1 \end{pmatrix}
X=
x(1)1x(2)1⋮x(N)1x(1)2x(2)2⋮x(N)2⋯⋯⋱⋯x(1)dx(2)d⋮x(N)d11⋮1
于是,预测误差的总和
E
E
E可以表示为矩阵运算
E
=
(
y
−
X
ω
)
T
(
y
−
X
ω
)
E=(y-X\omega)^T(y-X\omega)
E=(y−Xω)T(y−Xω)
我们还是采用求导数的方法取
E
E
E的极值,令导数等于0,求解得到
ω
\omega
ω.。
∂
E
∂
ω
=
2
X
T
(
X
ω
−
y
)
=
0
ω
=
(
X
T
X
)
−
1
X
T
y
\frac{\partial E}{\partial \omega } = 2X^T(X \omega - y)=0 \\ \omega = (X^TX)^{-1}X^Ty
∂ω∂E=2XT(Xω−y)=0ω=(XTX)−1XTy
四、代码实践
Python是一种简单友好的语言,它是解释执行的,而不是直接编译成CPU能读懂的机器码,所以虽然Python很灵活,但是执行速度不佳。因此,numpy等软件包将一些常用的矩阵和向量运算用更优化的方式实现了,这些软件包是采用编译型的语言实现的,省去了解释器解释代码的过程,能够充分利用计算机的计算能力。我们只需要通过Python调用这些软件包,就可以实现高性能的计算。
import numpy
# 准备餐厅套餐价格数据
#每行为一条数据
#各列分别是座位数量、食材价格、员工薪资和套餐价格
food_price_data = numpy.array([
[100, 7.2,3000,20],
[120,7.3,3500, 21],
[500,7.2,3100,18],
[80, 6.5,2900,17],
[80,7.9,4500,25],
[500, 7.0,3000,16],
[250,7.2,3100,19],
[250,7.5,4000, 22],
[150,7.8,5000,24],
[300, 7.2, 3500,20],
[400,7.1,3200,18],
[200,7.3,3600,21]
],dtype=numpy.float)
# 自变量维度为1 的线性回归
# 输入自变量x,因变量y
def linear_regression_single_dimension(x,y):
# 计算样本数量
n = len(x)
# 计算x 的和
sum_x = n
# 计算y 的和
sum_y = np.sum(y)
# 计算 x平方的和
sum_xx = np.sum(x*x)
# 计算xy 乘积之和
sum_xy = np.sum(x*y)
# 计算参数
w = (sum_x*sum_y-n*sum_xy) / (sum_x * sum_x - n*sum_xx)
b = (sum_y - w*sum_x) / n
return w,b
print(linear_regression_single_dimension(food_price_data[:,0],food_price_data[:,3]))
下面,我们实现最小二乘法,来处理多维自变量的线性回归.
# 最小二乘法
# 计算 w = (X^T X)^-1 X^T y
# X^T 表示X的转置
# ()^-1 表示求逆矩阵
def least_square(X,y):
# 确保y是列向量
y = np.array(y).reshape([-1,1])
# 计算X 的转置
XT = np.transpose(X)
# 计算逆矩阵
XTX_inv = np.linalg.inv(np.matmul(XT,X))
w = np.matmul(XTX_inv,np.matmul(XT,y))
return w
# 多维线性回归
def linear_regression(X,y):
# 在矩阵X的右侧添加一列
ones = np.ones((X.shape[0],1), dtype=y.dtype)
X = np.concatenate((X,ones), axis=1)
return least_square(X,y)
print(linear_regression(food_price_data[:,0:1],food_price_data[:,3]))
总结
本章主要介绍了线性回归的数学原理,要注意它的矩阵形式的推导。同时在使用numpy实现线性回归时,要注意矩阵乘法、求逆的使用,要注意将行向量转为列向量。