Coursra-MachineLearning 第一次作业总结

来源:互联网 发布:pp手机助手 mac 编辑:程序博客网 时间:2024/06/03 20:07

Matlab在语法上与Python有类似的地方

  1. 变量的声明没有独立,变量的声明和使用是同时的
  2. 类似动态语言,所见即所得,命令行式以及文件式,这点是不是和R有点相似
  3. 脚本之间关系,是不是也有不同的命名空间,这次的作业其实是一个大脚本串起来的
    这次必完成的作业是一元线性回归的作业,ex1虽然是一个大脚本,但是其实它的目的也很单一就是把一组数据利用一元线性回归的方式找到模型并且把其中的过程图画出来。目标完成其实是分成好几个模块的,比如绘图的模块(代价函数的图形不需要自己实现);实现梯度下降的方法,在迭代的过程中我们要知道它是不是再往最优的方向走,那就得看代价函数的值是不是在变小,因此还要计算代价函数。关于这几个脚本是否具有相同的命名空间,基本上主要的数据初始化都是在主脚本上进行的。我觉得一般来说被调用的脚本里面及时是有些数据产生那也是在这个脚本的命名空间里面的,如果不是以返回值返回的话,应该不会影响到其它脚本。

难点在于梯度下降中θ的迭代方式的实现

  1. 梯度下降也分成两个部分,一个是cost function的实现,一个是θ的实现
  2. 这里要尽量采用向量的计算方法,注意向量的计算方法不是矩阵的计算方法,总结一下向量的计算技巧,什么情况下可以一气计算,什么情况下不行,只能循环计算。微批量处理
    matlab的优势就在于他可以像数学计算那样,把批量的数据作为单位一气进行运算,而不是像传统的程序一样只能一个数字一个数字的算,最典型的就是向量和矩阵,在matlab里面是可以以矩阵为单位或者以向量为单位进行计算的。如果你是以向量作为单位来计算的,那么在同一个数学等式里面,你要保证参与运算的数据都是纬度一样的向量。这里多说一句,在《线性代数》同济第五版里面,并没有专门介绍向量的运算法则,只说道一个向量的内积。我觉得可以这样理解,因为向量可以看成一个特殊的矩阵(n行1列的矩阵),那么向量的运算很多都是和矩阵以一样的,其实所谓的内积也是矩阵乘法的一种特殊形式。

  3. θj:=θjα1mmi=1(hθ(x(i))y(i))xj(i) 这个式子能不能用向量的方式来进行求解,因为这个式子比较复杂,凭空想难度还是比较高的,因此我们用一个小点数将其具体化来观察它的特点(其实Ng就是利用这种方法来讲课的,一个变量的线性回归)。
    我们假设m=3,n=2,那么hypothesis的形式为hθ(x)=θ0+θ1x1+θ2x2。我们要确定的参数为θ=θ0θ1θ2。而系数矩阵X
    111x1(1)x1(2)x1(3)x2(1)x2(2)x2(3)
    我们先令j=0,看一下θ的迭代式子有什么特点。θ0:=θ0α133i=1(hθ(x(i))y(i))xj(i)。我们把这个求和公式展开,于是θ0:=θ0α13[(hθ(x(1))y(1))x0(1)+(hθ(x(2))y(2))x0(2)+(hθ(x(3))y(3))x0(3)],你可以看到方框号里的这一部分,正好就是向量θTxY与向量x0(1)x0(2)x0(3)的内积。而这个向量x0(1)x0(2)x0(3)正好就是系数矩阵X的第一列,我们可以在matlab里用X(:,1)来表示X矩阵的第一列,对于θ0对应的X矩阵的第一列,也就是0+1,那么我们可以推出来针对每一个θj其取值的式子用向量的形式表示为θj=θjα1m[θTxY,X(:,j+1)]。用代码的形式表示就是

    predictions = X * theta ;Err = predictions - y ;theta0 = theta(1) - alpha / m * dot(Err , X(:,1));theta1 = theta(2) - alpha / m * dot(Err , X(:,2));theta = [theta0 ; theta1];

    这个仍然是一个一个的计算向量θ的分量,那我能不能一个式子就将θ这个向量算出呢?我们还是用简单具体的例子来观察其中的规律:
    θ0=θ0α13[Err,X(:,1)]
    θ1=θ1α13[Err,X(:,2)]
    θ2=θ2α13[Err,X(:,3)]
    把这三个式子合成一个就是θ0θ1θ2=θ0θ1θ2α13ErrX(:,1)ErrX(:,2)ErrX(:,3),如果方括号括住的部分能够用合适的方式(比如说以向量运算或者矩阵运算的方式)一次性的表现出来,那么这个问题就解决了。我们仔细观察一下这一部分,把这个地方细化一下,我令Err=e0e1e2,在ErrX(:,1)ErrX(:,2)ErrX(:,3)中的每一个分量都是Err这个向量和系数矩阵X=111x1(1)x1(2)x1(3)x2(1)x2(2)x2(3)中的一列的进行内积的结果,可以观察出来,ErrX(:,1)ErrX(:,2)ErrX(:,3)其实就是矩阵XT与向量Err的积(这个矩阵乘法),即XTErr,于是将θ向量一次性求出来的式子为

    θ=θα1m(XTErr)

    于是这个用matlab代码表示为:

    predictions = X * theta ;Err = predictions - y ;theta = theta - alpha / m * (X' * Err);

一个思想方法

如果我们想直观的了解一个比较复杂东西的原理,我们可以代一些小的数进去观察一下他们的规律。
用简单具体的例子来观察一般规律。

程序调试的方法

单步调试的方法,在想设置断点的行序号前双击就行了
http://jingyan.baidu.com/article/3c48dd3481790fe10ae35854.html

Matlab 矩阵相关操作

matlab矩阵的表示和简单操作

Feature Normalization 的实现

  1. 实现公式xi:=xiμisi

    • 对于数据集里的每一个特征减去一个均值(mean )
    • 减去均值之后,对各个特征值除以各自的标准差(standard deviations)。Matlab里面计算标准差的函数是std()
  2. 均值用mu这个变量表示,如果不出意外的话,Matlab里面均值的函数是mean(),试了一下果然是。mu = mean(X(:,1)),但是这只是一个,还有把所有的特征值求出来放到一个向量里面。
    mu = zeros(1,size(X,2));
    mu = mean(X); 可以这样整体运算行吗,试了一下果然可以。
    size(X,2)的意思是这样的:把X这个数据的纬度求出来放到一个向量中,然后取出第二个向量

  3. 求标准差,跟上面的均值类似
    sigma = zeros(1,size(X,2));
    sigma = std(X);
    试了一下也是可以的

  4. 有了均值和标准差就该对原来的数据进行特征归一化了,能一口气做完吗,仔细想了一下不行,mu是一个一行两列的行向量,而X是一个47行2列的矩阵,让X的第一列的所有值减去mu的第一个分离,让X的第二列的所有值减去mu的第二个分量。如果说μ=(μ1,μ2) 能过扩展成和X同样规格的矩阵,第一列全是μ1,第二列全是μ2,那么让X减去这个扩展矩阵就行了。但是我想了半天还是不行。好像线性代数里面没有这样一个运算能够让一个向量扩展成一个矩阵的。所以只能通过for语句,利用矩阵的点运算。在查矩阵点运算的时候发现其实矩阵减去一个数的时候,是矩阵的全部元素都减去的,所以不用点运算。这个叫做矩阵和标量之间的运算。所以代码可以这样

    for i = 1 : 1 : size(X_norm,2)X_norm(:,i) = X_norm(:,i) - mu(i)end

    这样X就进行了归一化的第一步,之后除以标准差

    for i = 1 : 1 : size(X_norm,2)X_norm(:,i) = X_norm(:,i) / sigma(i)end

    后来我发现其实感觉这两个可以并成一步,不影响,于是我最后的代码为:

    mu = mean(X_norm);sigma = std(X_norm);for i = 1:1:size(X_norm,2)    X_norm(:,i) = X_norm(:,i) - mu(i);    X_norm(:,i) = X_norm(:,i) / sigma(i);end

    看了网友的答案,发现其实可以更直接啊

        X_norm(:,i) = (X(:,i) - mu(i)) / sigma(i);

    不得不承认还是网友的这个好。

  5. Matlab函数可以返回多个值
    function [X_norm, mu, sigma] = featureNormalize(X)
    等号后面的是这个函数的名称,等号前面的中括号里面的就是这个函数的返回值。而且在调用这个函数的时候,如果要赋值的话也必须按照这样的格式来。比如[a,b,c] = featureNormalize(x);这样a,b,c里面就有值了。

Gradient Descent 的实现

  1. 主要有两个函数要实现一个是 computeCostMulti.m,一个是gradientDescentMulti.m。我想说的是,因为之前单变量的时候我就是尽量用向量的方式实现,也就是well-vectorized,所以单变量写的程序可以直接拿过来用。
  2. 还是网友Atig写的最简洁优雅,computeCostMulti.m一行就搞定了。

    J = (X*theta - y)' * (X*theta - y) / (2*m);

    其实我把一些量拆出来一个一个实现了,这样比较好思考,思考的跨度不是那么大。
  3. 那么对于gradientDescentMulti.m我想是不是也可以用简介优雅的方式实现。

    theta = theta - alpha / m * (X' * (X * theta - y));

    这次貌似是我写的更简洁优雅一些,但是Atig还是用类似之前的方法来求,这说明他没有发现这个其实可以用一个向量形式来表示的。经过测试我这个是正确的。

Selecting learning rates

一、Matlab绘图的理解

  1. 对plot函数的理解
    既然要比较不同的学习率的效果,就得画图,我谈一下我对于Matlab画图工具的理解。画图分成两步,第一步是给出画布,这个用figure命令。第二步是在已有的画布上画出图形,这个是用plot函数。那么plot函数的参数我们如何记忆呢?回忆下我们上学的时候如果要作图(2纬的)是怎么做的,我只要一堆坐标点就行了是吧,每个坐标点如同(x,y)这样的数字对,当我们把所有的坐标都标在图上,把它们连起来就行了。那么其实我们给plot函数提供的最核心的参数就是这个了,坐标点。但是在Matlab里面,我们并非是直接把两两在一起的数值对提供给plot函数,而是换了一个形式,我们把表示坐标的数值对中的X方向上的分量集中在一起成为一个向量(称之为x向量),把Y方向上的分量集中在一起形成另一个向量(称之为y向量),其实我们是将x向量和y向量分别作为两个参数提供给plot函数的。除了x,y向量这两个最重要的参数之外,还有一个参数它可以对图形的样式产生影响,比如我们想用什么样的颜色,什么样的线形(实线还是虚线),每个坐标点用什么样式表示(有人用叉子表示,有人用三角表示还有的就用一个点表示)。所以plot这个函数基本上可以这样记忆plot(X,Y,S)其中X是X坐标向量,Y是Y坐标向量,S是线的样式。那么线的样式都有什么样的,可以在help plot中查,这个是一个类似于man命令的东西。如果想查看更多的例子可以在document查plot。

  2. 代码套路
    figure;
    plot(X,Y,S);
    xlabel(‘x坐标轴的描述’);
    ylabel(‘y坐标轴的描述’);

  3. 构建X向量和Y向量的方法
    x向量和y向量都是一组数,我们肯定不会一个一个手动输入,一般来说要么是从导入的数据中生成,要么就是自己利用一些自动化的方法批量生成(想到这里我想到Python里面的generator等概念)。
    我们以y=sin(x)这个函数为例,我们先批量的生成x向量,有两种常用的生成的方式(其实向量生成的方式有很多)

    • x = 起点 : 步长 : 终点 。步长可省略,如果省略的话步长为1。比如: x = 0:pi/100:2pi
    • x = linspace(起点,终点,n)。linspace这个函数会把起点和终点之间分割成n份,把每个分割点(包含头尾)取出来构成一个向量。如果不写n,默认是100
      有了x向量,y向量自然就有了(y和x之间有映射关系)
  4. 明白了2维作图的原理,其实三维作图,以及轮廓图都是类似的

    • 确定空间中的一个点需要X,Y,Z三个向量,三维作图用的关键字是surf
    • 轮廓图其实就是等高线图,有了一个三维立体之后,我要拿若干的等距的平面去切(平行于XY的平面)这个立体,平面与立体相交产生的曲线在投影到XY平面上就形成了轮廓图,因此轮廓图需要四个必要的参数,X向量,Y向量,Z向量,描述一系列等距平面之间距离的向量,轮廓图用的是contour关键字。

二、默认向量的方向

在同济版线性代数里面(第四章向量组的线性相关性第一节向量组及其线性组合),如果不加说明一个向量一般是列向量,如果是行向量会加上一个转置符号。
在第二周作用的Matlab程序里面里面对于向量的使用也基本上是以列向量为默认的情况。

三、在同一个图像中画出在四种不同的学习率下cost function J(θ)与迭代次数的曲线图

  1. 定义四个学习率alpha_1 = 0.01, alpha_2 = 0.03 , alpha_3 = 0.1, alpha_4 =0.3。以及对应的J(θ)J_history_1,J_history_2,J_history_3,J_history_4。
  2. 有没有必要定义四个theta,如果都能收敛的话,理论上是不用的,但是万一有些出入或者有不能收敛的呢,所以最好还是定义四个theta。theta_1,theta_2,theta_3,theta_4。
  3. 还有一个问题迭代次数选多少比较合适,如果学习率选得小的话迭代次数会经历比较多的此时才会收敛,程序默认用的学习率是0.01已经这四个候选里面最小的了,所以如果其它学习率能够收敛的话,需要迭代的次数肯定比0.01对应的迭代次数少。所以num_iters维持400不变。
  4. 需不需要重新写一个程序,还是在原来的ex1_multi.m程序里修改,修改了会不会对作业提交有影响?可以做个测试嘛,把ex1_multi.m做一个备份,在原有的基础上改。
  5. 经过实验,这四个学习率全部都收敛
    4钟不同的学习率对应的收敛速度
  6. 在四个学习率下面得到四个不同的θ,到底选那个?
    θ1 = [3.343020639932770e+05;1.000871160058464e+05;3.673548450928255e+03]
    θ2= [3.404109189727448e+05;1.103081133705862e+05;-6.326538107500906e+03]
    θ3= [3.404126595744679e+05;1.106310489581547e+05;-6.649472950128434e+03]
    θ4= [3.404126595744680e+05;1.106310502788461e+05;-6.649474270819795e+03]
    其中 E+05 表示 10的正5次方,E-05表示10的负5次方
    第三项差的也太多了吧,干脆这几个都用吧

  7. 预测房价
    拿一个新的值来预测房价,公式是p=θTx或者p=xTθ,这里θ是列向量所以可以用第二种形式。要注意新的值带入hypothesis的时候也要进行特征缩放。还有一个问题,由于x要多一列1,你可以先特征缩放完在加上1,也可以先加上1再进行特征缩放。不管采取那种方式,都涉及一个向量或者矩阵扩展的表示形式问题。
    对于一维行向量,可以用逗号分割也可以不用[a,b,c]和[a b c]效果一样比如aa = [1,2,3;4,5,6]和bb = [1 2 3 ;4 5 6]结果一样,我习惯用逗号分割,和手工书写的习惯一致。如果向量要增加一个,直接加就行了。其实[0, mu]和[0 mu]的效果也一样。
    如果是采取后面的方式的话,为了保持1这一列不变,mu向量扩展的时候前面要加0,sigma向量扩展前面加1。
    当然也可以先缩放再扩展,但是这样可能就没法写一个式子了

Normal Equations

  1. 这个反而是最简单的,求矩阵的逆用pinv(X),这个在视频里说过的。就一行代码:
    theta = pinv(X’ * X) * X’ * y;

  2. 预测房价
    正规方程法不需要进行特征缩放,所以这步也很简单

  3. 可以看到正规方程法计算出的θ和梯度下降法计算出的θ还是有很大的区别的,why?仅仅是因为特征缩放的问题吗?