线性回归
单变量线性回归
房价和面积—预测
给定一组房价和房屋面积的数据集,通过机器学习算法(监督学习)来拟合画出一条线,根据这条线来对未知的数据进行判断。
假设机器通过这些房价数据学习得到一条房价—面积关系线,如上图中红线,那么如果你朋友的750英尺的房子,就可以通过这条红线来估算出房价,可以看出,大约是在150K美金左右。
这是一个典型的回归问题(Regression),因为结果(房价)可以是任意实数,且数据是可以连续的。
更进一步,由于变量房屋尺寸,且预测结果(房价)和变量间的表达式可以用线性方程描述y = k*x + b
所有,此问题在机器学习中的术语叫做:单变量线性回归 Linear Regression with One Variable
损失函数(Cost Function)
代价函数/损失函数,就是用于评估误差水平的函数,常见的损失函数有平方损失函数、交叉熵损失函数,其中前者多用于回归问题,后者多用于分类问题。理论上,给定一批房屋面积—价格数据点,我可以根据这批数据画出无数条假设函数直线用于模拟房价和面积之间的关系,
那么怎么找到最优的那条线?这时,我们就会用到代价函数,好的代价函数必然使得数据集总体的误差最小。
例1的代价函数如下:
直白点意思就是:求每个样本点i 的误差的平方,累加求平均值,关于最后为什么是1/2m 而不是 1/m,这个其实主要是通用的约定,为了求导方便。
损失函数的意义就在于,通过求损失函数的值,我们可以评估预测函数的准确性,损失越小,则模型的预测越精准。所以,训练模型很多时候就是降低损失,找到损失函数的最小值,通过其最小值来产出最优的假设函数。
因此我们真正需要的是编写程序来找出这些最小化代价函数的θ_0和θ_1的值,能够自动地找出能使代价函数J最小化的参数θ_0和θ_1的值。即-----梯度下降法。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv('ex1data1.txt',names=['Population','Profit'])
#求代价函数
def computeCost(X,y,theta):
temp = np.power((X*theta.T-y),2)
return np.sum(temp)/(2*X.shape[0])
#加一列特征1,实现向量化
data.insert(0,'one',1)
cols = data.shape[1]
X = data.iloc[:,0:cols-1]#X是所有行,去掉最后一列
y = data.iloc[:,cols-1:cols]#X是所有行,最后一列
X = np.matrix(X.values)
y = np.matrix(y.values)
theta = np.matrix(np.array([0,0]))
#计算代价函数
computeCost(X,y,theta)
梯度下降法
梯度下降是一个用来求函数最小值的算法,我们将使用梯度下降算法来求出代价函数J(θ_0,θ_1) 的最小值。
梯度下降背后的思想是:开始时我们随机选择一个参数的组合(θ_0,θ_1,…,θ_n ),计算代价函数,然后我们寻找下一个能让代价函数值下降最多的参数组合。我们持续这么做直到到到一个局部最小值(local minimum),因为我们并没有尝试完所有的参数组合,所以不能确定我们得到的局部最小值是否便是全局最小值(global minimum),选择不同的初始参数组合,可能会找到不同的局部最小值。
图中为二元函数梯度下降图解,如果参数为更多元,则无法绘制出相应的梯度下降图,不过这幅图恰巧能生动地解释梯度下降的含义。
这里x、y轴分别为参数所在维度,z轴代表代价函数J的大小,所有的参数点和损失函数值构成了五彩的三维曲面,最终目标:即通过梯度下降算法,找到最小的点。
肉眼可见右边红色箭头所指的点,为局部梯度最低点,即局部最小值点;左边红色箭头所指的点为整个三维曲面上的最小值点,即全局最低点。
公式
这里,批量梯度下降(batch gradient descent)算法的公式为:
参数解释
- 公式中为什么是-,因为用于表示梯度下降,即逐渐降低,故用负号表示
- 公式中用的是 := 符号,此含义表示,等式中的参数需要同时更新,如此处有两个参数,正确的更新方式是:
学习率
批量梯度下降公式中, 为学习率(learning rate)它决定了我们沿着能让代价函数下降程度最大的方向向下迈出的步子有多大,在批量梯度下降中,我们每一次都同时让所有的参数减去学习速率乘以代价函数的导数
学习率过小
如果太小了,即我的学习速率太小,结果就是只能这样像小宝宝一样一点点地挪动,去努力接近最低点,这样就需要很多步才能到达最低点。所以,如果太小的话可能会很慢,因为它会一点点挪动,它会需要很多步才能到达全局最低点。
学习率过大
如果太大,那么梯度下降法可能会越过最低点,甚至可能无法收敛,下一次迭代又移动了一大步,越过一次,又越过一次,一次次越过最低点,直到你发现实际上离最低点越来越远。所以,如果太大,它会导致无法收敛,甚至发散。
总结可得:
#初始化一些附加变量 -—学习速率α和要执行的迭代次数。
#学习率
alpha = 0.01
#迭代次数
iters = 1000
def gradientDescent(X, y, theta, alpha, iters):
#初始化临时矩阵temp
temp = np.matrix(np.zeros(theta.shape))
#获取theta数量
parameters = theta.shape[1]
#初始化代价函数矩阵,维数为迭代次数
cost =np.zeros(iters)
for i in range(iters):
#根据theta个数循环更新theta
for j in range(parameters):
#求h(x) - y 与 对应x 的积
term = np.multiply((X * theta.T) - y, X[:,j])
#求和,乘列数分之一,乘学习率,更新对应theta
temp[0,j] = theta[0,j] - (alpha / len(X)) * np.sum(term)
#得到更新后的theta
theta = temp
#计算代价
cost[i] = computeCost(X, y, theta)
return theta, cost
#梯度下降
g,cost = gradientDescent(X, y, theta, alpha, iters)
#最终损失
computeCost(X, y, g)
#会出图像
#定义自变量取值范围
x = np.linspace(data.Population.min(), data.Population.max(), 100)
#得到拟合方程
f = g[0, 0] + (g[0, 1] * x)
#绘出图像框架12*8
fig, ax = plt.subplots(figsize=(12,8))
#绘出函数图像,并添加图例标签
ax.plot(x, f, 'r', label='Prediction')
#绘出散点图,并添加图例标签
ax.scatter(data.Population, data.Profit, label='Traning Data')
#添加图例在第二象限
ax.legend(loc=2)
#添加坐标轴
ax.set_xlabel('Population')
ax.set_ylabel('Profit')
#添加图像主题
ax.set_title('Predicted Profit vs. Population Size')
plt.show()
#绘出损失图像
fig,ax = plt.subplots(figsize=(12,8))
ax.plot(np.arange(iters),cost,'r')
多变量线性回归
探讨了单变量/特征的回归模型,现在我们对房价模型增加更多的特征,例如房间数楼层等,构成一个含有多个变量的模型,模型中的特征为(x_1,x_1,…,x_n )。
增添更多特征后,我们引入一系列新的注释:
n 代表特征的数量
x^((i) )代表第 i 个训练实例,是特征矩阵中的第i行,是一个向量(vector)。
多变量的梯度下降
开始随机选择一系列参数值,计算所有预测结果,再给所有参数一个新的值,如此循环直到收敛,即损失函数局部最小值。
特征归一化
在我们面对多维特征问题的时候,我们要保证这些特征都具有相近的尺度,这将帮助梯度下降算法更快地收敛。
以房价问题为例,假设我们使用两个特征,房屋的尺寸和房间的数量,尺寸的值为 0-2000平方英尺,而房间数量的值则是0-5,以两个参数分别为横纵坐标,绘制代价函数的等高线图能,看出图像会显得很扁,梯度下降算法需要非常多次的迭代才能收敛。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
path = 'ex1data2.txt'
data2 = pd.read_csv(path,names=['Size','Badrooms','Price'])
#特征归一化
data2 = (data2-data2.mean())/data2.std()
# 加一列
data2.insert(0, 'Ones', 1)
# 初始化x y
cols = data2.shape[1]
X2 = data2.iloc[:,0:cols-1]
y2 = data2.iloc[:,cols-1:cols]
# 转为矩阵
X2 = np.matrix(X2.values)
y2 = np.matrix(y2.values)
theta2 = np.matrix(np.array([0,0,0]))
# 梯度下降法
g2, cost2 = gradientDescent(X2, y2, theta2, alpha, iters)
# get the cost (error) of the model
computeCost(X2, y2, g2)
#绘出损失图像
fig,ax = plt.subplots(figsize=(12,8))
ax.plot(np.arange(iters),cost2,'r')
正规方程
正规方程是通过求解下面的方程来找出使得代价函数最小的参数的:
∂
∂
θ
j
J
(
θ
j
)
=
0
\frac{\partial }{\partial {{\theta }_{j}}}J\left( {{\theta }_{j}} \right)=0
∂θj∂J(θj)=0 。
假设我们的训练集特征矩阵为 X(包含了
x
0
=
1
{{x}_{0}}=1
x0=1)并且我们的训练集结果为向量 y,则利用正规方程解出向量
θ
=
(
X
T
X
)
−
1
X
T
y
\theta ={{\left( {{X}^{T}}X \right)}^{-1}}{{X}^{T}}y
θ=(XTX)−1XTy 。
上标T代表矩阵转置,上标-1 代表矩阵的逆。设矩阵
A
=
X
T
X
A={{X}^{T}}X
A=XTX,则:
(
X
T
X
)
−
1
=
A
−
1
{{\left( {{X}^{T}}X \right)}^{-1}}={{A}^{-1}}
(XTX)−1=A−1
梯度下降与正规方程的比较:
梯度下降:需要选择学习率α,需要多次迭代,当特征数量n大时也能较好适用,适用于各种类型的模型
正规方程:不需要选择学习率α,一次计算得出,需要计算 ( X T X ) − 1 {{\left( {{X}^{T}}X \right)}^{-1}} (XTX)−1,如果特征数量n较大则运算代价大,因为矩阵逆的计算时间复杂度为 O ( n 3 ) O(n3) O(n3),通常来说当 n n n小于10000 时还是可以接受的,只适用于线性模型,不适合逻辑回归模型等其他模型
# 正规方程
def normalEqn(X, y):
theta = np.linalg.inv(X.T@X)@X.T@y #X.T@X等价于X.T.dot(X)
return theta
final_theta2=normalEqn(X, y)#感觉和批量梯度下降的theta的值有点差距
final_theta2 #梯度下降得到的结果是matrix([[-3.24140214, 1.1272942 ]])
scikit-learn
scikit-learn包含众多顶级机器学习算法,主要有六大基本功能,分别是分类、回归、聚类、数据将维、模型选择和数据预处理。
from sklearn import linear_model
model = linear_model.LinearRegression()
model.fit(X, y)
x = np.array(X[:, 1].A1)
f = model.predict(X).flatten()
fig, ax = plt.subplots(figsize=(12,8))
ax.plot(x, f, 'r', label='Prediction')
ax.scatter(data.Population, data.Profit, label='Traning Data')
ax.legend(loc=2)
ax.set_xlabel('Population')
ax.set_ylabel('Profit')
ax.set_title('Predicted Profit vs. Population Size')
plt.show()