linear regreesion 线性回归

机器学习笔记 - 吴恩达 - 目录


笔记

描述

什么是线性回归?

线性回归初等数学就学过?

回归是通过先通过数据的分布规律,建立一个假设函数,例如线性回归的假设函数: 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)=2m1i=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αθ0J(θ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αθ1J(θ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αθjJ(θ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=1m(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αθjJ(θ)(j=0,1,2,...,n)
注:j = 0时, x 0 x_0 x0 = 1,即函数的偏移项


代码

python实现

这是一段多元梯度下降的线性回归的代码
代码中,为了便于书写,以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 θjJ(θ)=θj2m1i=1m(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 =θj2m1i=1m(θ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=θ0J(θ)=θ02m1i=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=θ1J(θ)=θ12m1i=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=θ2J(θ)=θ22m1i=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


你可能感兴趣的:(machine,learn,线性回归,python)