• 线性回归与梯度下降法[二]——优化与比较


    接着上文——机器学习基础——梯度下降法(Gradient Descent)往下讲。这次我们主要用matlab来实现更一般化的梯度下降法。由上文中的几个变量到多个变量。改变算法的思路,使用矩阵来进行计算。同时对算法的优化和调参进行总结。即特征缩放(feature scaling)问题和学习速率(alpha)的取值问题。还有在拟合线性模型时,如何选择正确的算法,梯度下降 or 最小二乘法?

    matlab的基本用法,已经总结在matlab基础教程——根据Andrew Ng的machine learning整理上。相对于python来说,的确matlab的语法更简单,上手更快,只要简单学习下就能上手编写算法,或者用于计算。

    matlab实现一般梯度下降法

    针对于Andrew Ng的machine learning课当中的数据,我们这里给出了matlab的一般梯度下降法的代码。
    在了解了算法原理后,实现起来就非常简单了,主要分为以下几步:

    1. 数据加载和预处理
      从文件中读入数据,并分块放到相应的矩阵中去。这里我们选取的模型是(y = heta_0+ heta_1x_1)。显然(x_0)取1,所以需要在原有的X矩阵中添加一列全1的列。
    data = load ('data1.txt');
    X = data(:, 1);
    y = data(:, 2);
    X = [ones(length(data),1),data(:,1)];
    
    1. 设置算法的学习参数
    X = [ones(length(data),1),data(:,1)];
    theta = zeros(2,1);%theta初始值为0
    alpha = 0.01;
    max_iter = 5000;
    m = length(y);%数据组数
    J_history = zeros(max_iter,1);%初始化迭代误差变量
    
    1. 执行算法。
    for iter = 1:max_iter
    	theta = theta - alpha / m * X' * (X * theta - y);	%梯度下降
        J_history(iter) = sum((X * theta-y) .^ 2) / (2*m);	%记录每次 迭代后的全局误差
        fprintf('iter:%d ------ Error:%f
    ',iter,J_history(iter));
    end
    

    下面是完整的代码https://github.com/maoqyhz/machine_learning_practice

    %加载数据和数据预处理
    data = load ('data1.txt');
    fprintf('Running Gradient Descent ...
    ');
    
    X = data(:, 1); 	%取X集合
    y = data(:, 2);		%取y集合
    
    %画出数据的散点图
    figure;
    plot(X, y, 'rx', 'MarkerSize', 10);
    ylabel('Profit in $10,000s'); 
    xlabel('Population of City in 10,000s'); 
    hold on; 
    
    %设置学习参数
    X = [ones(length(data),1),data(:,1)]; 	% y = theta0*x0 + theta1*x1 默认x0为1
    theta = zeros(2,1);	%theta初始值为0
    alpha = 0.01;
    max_iter = 5000;
    
    m = length(y);	%数据组数
    J_history = zeros(max_iter,1);	%初始化迭代误差变量
    iter = 1;
    for iter = 1:max_iter
    	%每迭代100次画一条曲线
        if  mod(iter,100) == 0
            plot(X(:,2), X*theta, 'g')
        end
    
    	theta = theta - alpha / m * X' * (X * theta - y);	%梯度下降
        J_history(iter) = sum((X * theta-y) .^ 2) / (2*m);	%记录每次迭代后的全局误差
        fprintf('iter:%d ------ Error:%f
    ',iter,J_history(iter));
    end
    
    %输出最终的theta值和最终的拟合曲线
    disp('Theta found by gradient descent:');
    disp(theta);
    plot(X(:,2), X*theta, 'k')
    legend('Training data', 'Linear regression')
    hold off 
    

    运行结果如下:

    • 图1为得到的结果,可以看到在现有的学习速率下,基本上4600次左右就能收敛了。得出了最终的( heta)值。

    • 图2为拟合的过程,每迭代100次会画出一条绿色曲线,不断迭代最终收敛的曲线是黑色的那条,可以清楚看见拟合的过程。

    特征缩放和数据的归一化

    下图为上例中的数据部分,可以看到第一列和第二列的数据差距并不大,所以不需要很多的迭代次数就能收敛。但是如果数据之间差距很大,在计算过程中会导致数据超出数据类型的最大存储值,或者是需要额外的迭代次数来到达收敛的情况,所以此时我们对数据进行处理,也就是所说的特征缩放。

    数据归一化

    数据归一化是非常有用的特征缩放方法,可以把数据缩放到([-1,1])中。常见的归一化方法有两种。

    min-max标准化(Min-Max Normalization)

    可以使数据进行线性变换,使结果值映射到([0,1])之间。设原区间为([a,b]),转换函数如下:

    [x^* = frac{x-a}{b-a} ]

    Z-score标准化方法(Z-socre Normalization)

    这种方法给予原始数据的均值(mean)和标准差(standard deviation)进行数据的标准化。经过处理的数据符合标准正态分布,即均值为0,标准差为1,转化函数为:

    [x^* = frac{x-mu}{sigma} ]

    其中(mu)为数据的均值,(sigma)为数据的标准差。

    matlab来处理数据归一化问题

    新的数据集如下,显然,不同的特征之前的差距比较大,此时就需要进行归一化处理。

    1. 数据归一化
    %Z-score Normalization
    function [ X_norm,avg,sigma ] = normalize(X)
    	avg = mean(X,1); %均值
    	sigma = std(X,1);%标准差
    	%repmat函数用来数据填充
    	X_norm  = (X - repmat(avg,size(X,1),1)) ./  repmat(sigma,size(X,1),1);
    end
    
    1. 测试样本需要进行归一化。
    % 使用1 1650 3对数据进行估计
    x = [1650 3];
    price = [1 (([1650 3] - avg) ./ sigma)] * theta ;
    

    学习速率的取值

    可以看到学习速率太小,需要进行多次迭代才能收敛;学习速率太大,可能会miss最小值儿无法收敛。因此我们需要选取合适的学习速率Andrew Ng已经告诉我们方法,如图所示,选择学习速率的区间,不断地去调整以满足自己的数据和算法。说到底机器学习就是个调参的过程,啊哈哈~~

    梯度下降法VS最小二乘法

    对于线性回归问题,我们既可以用梯度下降法也可以用最小二乘法来解决。那么这两种算法有和不同?简而言之,前者是需要多次迭代来收敛到全局最小值,后者则是提供一种解析解法,直接一次性求得( heta)的最优值。

    对于最小二乘法,我们这里只给出具体的结论。证明牵涉到矩阵的求导,可以直接看西瓜书。

    那么,当(X^TX)为满秩矩阵或正定矩阵时,我们可以一步得到( heta)的最优值。

    [ heta = (X^TX)^{-1}X^Ty ]

    而在matlab中,最小二乘法的求解过程也的确只需要一行代码就可以完成。把下面的代码替换掉梯度下降的代码即可。

    theta = pinv( X' * X ) * X' * y;
    

    How to choose?

    梯度下降法

    • 需要设置学习速率。
    • 需要进行多次迭代。
    • 数据比较大时(百万?),可以很好的工作。

    最小二乘法

    • 不需要设置学习速率。
    • 不需要迭代。
    • 需要矩阵计算,数据大时,计算速度慢。

    参考文献

  • 相关阅读:
    设计模式目录
    垃圾收集器
    598. Range Addition II
    Java中的四种引用
    垃圾回收算法
    645. Set Mismatch
    java 8中撤销永久代,引入元空间
    L2-013. 红色警报 (并查集)
    POJ 1127 Jack Straws (线段相交)
    L2-014. 列车调度 (DP)
  • 原文地址:https://www.cnblogs.com/Sinte-Beuve/p/6188145.html
Copyright © 2020-2023  润新知