机器学习笔记 - 吴恩达 - 目录
什么是线性回归?
线性回归初等数学就学过?
回归是通过先通过数据的分布规律,建立一个假设函数,例如线性回归的假设函数: h θ ( x ) = θ 0 + θ 1 x h_\theta (x) = \theta_0 + \theta_1 x hθ(x)=θ0+θ1x
其中h是数据集x对应的结果, θ 0 \theta_0 θ0和 θ 1 \theta_1 θ1是系数。
机器学习的目的是想办法从训练数据集中,得到 θ 0 \theta_0 θ0和 θ 1 \theta_1 θ1的系数,使该假设函数尽可能的拟合数据,最后可以用这个假设函数去预测新数据的结果。
如何让计算机知道什么样的theta值比较合适?
代价函数:可以利用代入大量训练数据 X i X_i Xi,让假设函数先计算得到结果 H i H_i Hi。利用训练集的结果值 Y i Y_i Yi和 H i H_i Hi作差,这就得到每个训练数据 X i X_i Xi的误差,再将每个训练数据的误差求和,最后取平均。
这就可以得到了代价函数J,这就是对于当前theta值的假设函数的拟合效果是怎么样的,做出了量化的评判。
如果只有一个变量决定结果,所以代价函数的表达式: J ( θ 0 , θ 1 ) = 1 2 m ∑ i = 1 m ( h θ ( x ( i ) − y ( i ) ) ) 2 J(\theta_0, \theta_1) = \frac{1}{2m} \sum_{i=1}^m (h_\theta (x^{(i)} - y^{(i)})) ^2 J(θ0,θ1)=2m1∑i=1m(hθ(x(i)−y(i)))2
如何让计算机自动拟合数据?
梯度下降:线性回归这里,我们采用梯度下降的方法。通过高数中求偏导的方式,对一个点求各变量偏导即可得到该点的梯度,我们通过对假设函数中的theta减去这个梯度即可逐步修正theta值(偏导有正有负)。
多次迭代theta的操作后,即可到达代价函数的极小值,达到满意的theta值。
Andrew Ng将梯度下降的方法,想象成一个人下山,如何更快的下山,这就要找梯度最大的方向走。
需要注意的是,求导值太大可能会导致越过一个极小值点,从而无法正确的梯度下降,所以,我们通常会为偏导值乘上一个学习系数alpha来调整梯度下降的速率。
对于一元一次的假设函数,梯度下降算法如下:
θ 0 : = θ j − α ∂ ∂ θ 0 J ( θ 0 , θ 1 ) \theta_0 := \theta_j - \alpha \frac{\partial}{\partial \theta_0} J (\theta_0, \theta_1) θ0:=θj−α∂θ0∂J(θ0,θ1)
θ 1 : = θ j − α ∂ ∂ θ 1 J ( θ 0 , θ 1 ) \theta_1 := \theta_j - \alpha \frac{\partial}{\partial \theta_1} J (\theta_0, \theta_1) θ1:=θj−α∂θ1∂J(θ0,θ1)
对高数中的梯度不太熟的,可以观看动画演示(2个变量情况):Gradients and Partial Derivatives
推广到多元,仅仅是变量x的系数theta更多了 (采用矩阵的方式处理,易于计算)
多元梯度下降:
θ j : = θ j − α ∂ ∂ θ j J ( θ 0 , θ 1 ) ( j = 0 , 1 , 2 , . . . , n ) \theta_j := \theta_j - \alpha \frac{\partial}{\partial \theta_j} J (\theta_0, \theta_1) \\ (j = 0, 1, 2, ... , n) θj:=θj−α∂θj∂J(θ0,θ1)(j=0,1,2,...,n)
线性回归模型(Linear Regression Model)
假设函数:
h θ ( x ) = θ 0 + θ 1 x h_\theta (x) = \theta_0 + \theta_1 x hθ(x)=θ0+θ1x
代价函数:
J ( θ ) = 1 2 m ∑ i = 1 m ( h θ ( x ( i ) − y ( i ) ) ) 2 J(\theta) = \frac{1}{2m} \sum_{i=1}^m (h_\theta (x^{(i)} - y^{(i)})) ^2 J(θ)=2m1i=1∑m(hθ(x(i)−y(i)))2
梯度下降算法(Gradient descent algorithm)
θ j : = θ j − α ∂ ∂ θ j J ( θ ) ( j = 0 , 1 , 2 , . . . , n ) \theta_j := \theta_j - \alpha \frac{\partial}{\partial \theta_j} J (\theta) \\ (j = 0, 1, 2, ... , n) θj:=θj−α∂θj∂J(θ)(j=0,1,2,...,n)
注:j = 0时, x 0 x_0 x0 = 1,即函数的偏移项
这是一段多元梯度下降的线性回归的代码
代码中,为了便于书写,以W作为 θ j \theta_j θj(j = 1, 2, … , n),以b作为 θ 0 \theta_0 θ0
方法功能:
fit():用来加载数据,并初始化一些变量
partial_derivative():是计算偏导(注意偏导的方程是自己手动先算好的,并不是调用求偏导的库)
gradient_descent():是对theta值一直梯度下降(减去偏导值)
train():开始运行
predict():对测试集做预测
import numpy as np
class LinearRegression:
'''
线性回归
参数:
X - 训练集(需要将训练集的特征缩放到0~1,将参数以列向量重排)
Y - 训练集的结果(取值为0|1)
W - 假设函数的多参数组成矩阵(w1、w2、w3 ...)(W_j对应theta_j,j=1,2,3...)
b - 假设函数的参数(x0 = 1的值)(b对应theta_0)
learning_rate - 学习速率
num_iter - 迭代次数
costs - 代价函数值的集合(非必须操作)
使用:
lg = LinearRegression()
lg.init(X_train, Y_train)
lg.train(0.001, 2000)
predicted = lg.predict(X_test)
'''
X = 0
Y = 0
W = 0
b = 0
learning_rate = 0
num_iter = 0
costs = []
# 初始化变量
def init(self, X, Y):
'''
加载训练集,并设置一些初始值
参数:
X - 训练集
Y - 训练集的结果
'''
self.X = X
self.Y = Y
self.W = np.zeros(shape = (X.shape[0], 1))
self.b = 0
self.costs = []
# 对代价函数J求导
# h(x) = W * x + b
def partial_derivative(self):
'''
对梯度下降公式后半部分的求导(手动计算)数值
返回:
dW,db - 假设函数的参数的偏导值
'''
m = self.X.shape[1]
# 假设函数的激活值(正向传播)
H = np.dot(self.W.T, self.X) + self.b
# 计算代价,记录代价(非必须操作,只是便于观察梯度下降的效果)
cost = (1 / (2 * m)) * np.sum(H - self.Y) ** 2
self.costs.append(cost)
# 求偏导(反向传播)
dW = 1 / m * np.dot(self.X, (H - self.Y).T) # 注:矩阵点乘后,已经求过和
db = 1 / m * np.sum(H - self.Y) # 注:没有进行过矩阵乘法运算,需要手动求和
return dW, db
# 梯度下降
# temp0 = W - alpha * partial_derivative(J0(W, b))
# temp1 = b - alpha * partial_derivative(J1(W, b))
# ...
def gradient_descent(self):
'''
进行梯度下降的运算,公式:W_j = W_j - alpha * partial_derivative(J_j(W_j, b)), j = 1,2,3...
'''
for i in range(self.num_iter):
dW, db = self.partial_derivative()
# 梯度下降,优化参数W、b
self.W = self.W - self.learning_rate * dW
self.b = self.b - self.learning_rate * db
# 开始训练
def train(self, learning_rate = 0, num_iter = 0):
'''
开始训练
参数:
learning_rate - 学习速率
num_iter - 迭代次数
'''
self.learning_rate = learning_rate
self.num_iter = num_iter
self.gradient_descent()
# 预测
def predict(self, X):
'''
预测X数据集
参数:
X - 测试数据集
返回:
predicted - 对于测试数据集X的预测结果
'''
# 带入参数w、b预测测试集
predicted = np.dot(self.W.T, X) + self.b
return predicted
简单的自拟了一些训练数据。
注意,训练数据和测试数据,必须要和代码里写的格式一样。这里采用列向量表示每组数据的各个特征,每一列就是一组数据。
(虽然代码写为矩阵计算,是多元的,但这是一个变量的测试)
先导入上面写好的线性回归的类,加载训练集,设置训练的学习速率和迭代次数,最后预测测试集的结果。然后,还用折线图画出了代价函数的迭代图。
import numpy as np
import matplotlib.pyplot as plt
from linear_regression import LinearRegression
import random
if __name__ == '__main__':
# 生成数据
X_train = np.arange(1, 30, 1)
X_train = X_train.reshape(1, X_train.shape[0])
Y_train = np.array([15, 11, 10, 32, 16, 20, 27, 44, 41, 48, 53, 39, 41, 40, 49, 36, 49, 94, 57, 45, 72, 96, 43, 81, 70, 99, 80, 91, 70])
X_test = np.arange(1, 30, 1)
X_test = X_test.reshape(1, X_test.shape[0])
N = 200 # 迭代次数
# 线性回归
lr = LinearRegression()
lr.init(X_train, Y_train)
lr.train(0.005, N)
predicted = lr.predict(X_test)
# 显示
# 测试集,模型参数w、b的函数
plt.subplot(1,2,1)
Y_test = predicted
plt.scatter(X_train, Y_train)
X_test = X_test.reshape(X_test.shape[1], 1)
Y_test = Y_test.reshape(Y_test.shape[1], 1)
plt.plot(X_test, Y_test, color = 'red')
# 迭代代价图
plt.subplot(1,2,2)
plt.plot([x for x in range(N)], lr.costs)
plt.show()
# 这是用random随机生产在自定义的线性方程上下有一定浮动的数据,保存成了列表
[15, 11, 10, 32, 16, 20, 27, 44, 41, 48, 53, 39, 41, 40, 49, 36, 49, 94, 57, 45, 72, 96, 43, 81, 70, 99, 80, 91, 70]
学习速率的选择
学习速率的选择要适度,如果选择小了,梯度下降太慢,需要更多次迭代才能达到适合的theta值;如果选择大了,每次乘以偏导值后,很可能会一直在极小值附近,并且可能会发散,导致无法收敛到极小值
特征缩放
为了更好的梯度下降,我们应该在进行梯度下降操作之前,将数据进行特征缩放。
(这是为了防止,一个数据的某个特征取值范围很小,另一个特征却很大,那每次梯度下降时,取值大的特征下降的很慢)
局部最优解
还需要注意的是,高数中,我们知道,如果一个函数比较复杂,它也许不止只有一个极小值点,我们通常想要得到的是最小值。梯度下降的方法,如果有多个极小值点,在初始点(初始的theta值)选定后,那将会总是达到同一个极小值点。
但是在线性回归中,因为就是简单的一元函数,故只有一个极小值,即最小值,无论初始的theta选择什么,总会通过多次迭代到同一个最小值。
代价函数的求导步骤
∂ ∂ θ j J ( θ ) = ∂ ∂ θ j 1 2 m ∑ i = 1 m ( h θ ( x ( i ) − y ( i ) ) ) 2 \frac{\partial}{\partial \theta_j} J (\theta) = \frac{\partial}{\partial \theta_j} \frac{1}{2m} \sum_{i=1}^m (h_\theta (x^{(i)} - y^{(i)})) ^2 ∂θj∂J(θ)=∂θj∂2m1i=1∑m(hθ(x(i)−y(i)))2
= ∂ ∂ θ j 1 2 m ∑ i = 1 m ( θ 0 + θ 1 x ( i ) − y ( i ) ) ) 2 = \frac{\partial}{\partial \theta_j} \frac{1}{2m} \sum_{i=1}^m (\theta_0 + \theta_1 x^{(i)} - y^{(i)})) ^2 =∂θj∂2m1i=1∑m(θ0+θ1x(i)−y(i)))2
( j = 0 ) (j = 0) (j=0) θ 0 = ∂ ∂ θ 0 J ( θ ) = ∂ ∂ θ 0 1 2 m ∑ i = 1 m ( h θ ( x ( i ) − y ( i ) ) ) 2 \theta_0 = \frac{\partial}{\partial \theta_0} J (\theta) = \frac{\partial}{\partial \theta_0} \frac{1}{2m} \sum_{i=1}^m (h_\theta (x^{(i)} - y^{(i)})) ^2 θ0=∂θ0∂J(θ)=∂θ0∂2m1∑i=1m(hθ(x(i)−y(i)))2
( j = 1 ) (j = 1) (j=1) θ 1 = ∂ ∂ θ 1 J ( θ ) = ∂ ∂ θ 1 1 2 m ∑ i = 1 m ( h θ ( x ( i ) − y ( i ) ) ) 2 \theta_1 = \frac{\partial}{\partial \theta_1} J (\theta) = \frac{\partial}{\partial \theta_1} \frac{1}{2m} \sum_{i=1}^m (h_\theta (x^{(i)} - y^{(i)})) ^2 θ1=∂θ1∂J(θ)=∂θ1∂2m1∑i=1m(hθ(x(i)−y(i)))2
( j = 2 ) (j = 2) (j=2) θ 2 = ∂ ∂ θ 2 J ( θ ) = ∂ ∂ θ 2 1 2 m ∑ i = 1 m ( h θ ( x ( i ) − y ( i ) ) ) 2 \theta_2 = \frac{\partial}{\partial \theta_2} J (\theta) = \frac{\partial}{\partial \theta_2} \frac{1}{2m} \sum_{i=1}^m (h_\theta (x^{(i)} - y^{(i)})) ^2 θ2=∂θ2∂J(θ)=∂θ2∂2m1∑i=1m(hθ(x(i)−y(i)))2
…
( j = 0 , 1 , 2 , . . . , n ) (j = 0, 1, 2, ... , n) (j=0,1,2,...,n)
其中,j = 0 时, x 0 = 1 x_0 = 1 x0=1