Coursra-MachineLearning 第二次作业总结
来源:互联网 发布:易语言ce修改器源码 编辑:程序博客网 时间:2024/06/06 02:00
Logistic Regression
1.1 Visualizing the data
我们的目标是根据ex2data1里面的数据,把被接受入学的数据和被拒绝入学的数据都标注在一张坐标图上。
为了表示区分,接受入学的样本在图上用“黑色小十字”来表示,而拒绝入学的样本在图上用“黄色小圆点”来表示。
如果要做这个事情,第一步就是要把混杂在一起的数据分成两堆。y=1的为一堆,y=0的为一堆。
难点1 find函数
我能够猜到 pos = find(y ==1) 是将y向量中等于1那些值所在的位置记录下来放到一个向量中,这个向量就是pos。这里主要是了解find这个函数的用法
在document里面有很多find函数,就是这个Find indices of nonzero elements.
其中有一个 Elements Equal to Specific Values用法。难点2 矩阵切片的再认识
X(pos,1)这个我也能猜出来是,它表示的是X这个矩阵中第一列中的行序数在pos向量中的那些值。我的疑问是,这个矩阵切片操作还可以这么表示,一个变量用向量,另一个变量用常数。仔细想想其实之前也用过,比如X = data(:,[1,2])中逗号前的部分“:”其实就是一种向量的表示方法,也就是说作为矩阵定位的变量是可以用向量来表示的;而逗号后面的部分“[1,2]”其实是第一列和第二列构成的矩阵,从这个表示方法来推测,其实1,2这些所谓的常数,其实应该是代表列位置的索引。总结一下,其实一个矩阵A的切片方式A(X,Y),X表示的行的部分,X可以由表示行的那些索引构成的向量,Y表示列的部分,可以由表示列的索引构成的向量。对于这个例子来说我还可以构造一个矩阵 s = data([1,15,25],[1,3])
搞清了这两点,我们就可以画图了,参考第二周作业笔记中对于画图函数的理解。以在坐标轴上标注出“被接受”的样本为例,最重要的是两个向量,一个向量是被接受样本的x坐标向量,另一个是被接受样本的y坐标向量,x坐标向量可以用X(pos,1)表示,y坐标向量可以用y(pos,2),在加上一些图形属性的参数就是
plot(X(pos, 1), X(pos, 2), ‘k+’,’LineWidth’, 2, ‘MarkerSize’, 7);
同理“被拒绝”样本的x,y坐标轴向量为X(neg, 1), X(neg, 2),绘图函数为:
plot(X(neg, 1), X(neg, 2), ‘ko’, ‘MarkerFaceColor’, ‘y’, ‘MarkerSize’, 7);
1.2 Implementation
1.2.1 sigmoid function
其实这个函数非常简单,只是有两点要注意
1. 指数函数的表示方法
如果是以e为底的那么就用 exp(x)来表示,如果是以其它自然数为底的比如说
2. 向量形式的实现
这个sigmoid函数是以向量的形式来实现的,在用1除以1+e^z的时候要用“./”而不是普通除,这个如果不是看人家的代码还真不容易发现。
所谓向量化可以这么理解:我需要对向量中的每个元素进行同一种运算。
比如以sigmoid函数作为例子,假设待计算的向量为
引入向量运算的理由是经常有大量的数据经常用同一个函数进行运算,按照一般程序的处理方法,就得用循环语句了。如果能把接受同样过程处理的数据打包批量进行处理就好了,这个就是向量化的思想。
Matlab里面大多数函数都已经实现了向量化,我们在实现函数的时候也要尽可能的实现向量化,具体来说就是如果可以用Matlab提供现有运算工具就能实现对向量(或者矩阵)中每个元素的处理就可以直接用先有工具的组合就行了。但是如果没有,那就只能写循环语句了。以这个sigmoid函数为例,待处理数据初始的状态为
这里面还涉及到一个知识点,就是矩阵和标量之间的运算,标量和矩阵之间的运算相当于标量和矩阵中的每一个元素进行运算,对于除法来说,标量在左边和在右边是完全不一样的,你可以做一个实验,构造一个矩阵A,之后用2除以A和A除以2,结果是不同的,这点很容易知道,但是如果是2除以A要用 “2 ./ A” A除以2用“A ./ 2”或者“A / 2 ”都可以。其它的乘法以及加减法加点或者不加点运算效果都是一样的。只有除法要注意。
1.2.2 Cost function and gradient
这块还是要用向量的方式实现,可以用第二周发现的方法,我们用几个小的观察一下规律嘛(有点像高中学数列的时候)
1. 关于cost function的实现,我自己没想出来向量形式的实现方式,只能用循环的方法实现(好Low啊),后来看了网友的答案得到启发。我来推导一下这个是怎么实现的。
首先还是用一个小数来把问题具体化,设m=3,n=2(三个样本,两个特征)。
系数矩阵
参数向量为
如果用样本矩阵来表示系数矩阵就应该是
其实这个形式就跟CS229-notes1里面page10的那个系数矩阵表达方法一样的。我为什么要写一遍系数矩阵,是因为后面要划归为向量形式要对这种形式比较熟悉。
接下来我们把
我们把
这部分就是
这部分其实就是向量
向量
而
* 方法一:把
其实这就看出来了,就是向量
* 方法二:因此向量
也就相当于向量
而向量
因此
由此我们可以得到
同理
J = -1 / m * (dot(y,log(sigmoid(X * theta))) + dot((1 - y ),log(1 - sigmoid(X * theta))));
另外我还发现不知道是效率高咋滴,大家都不喜欢用向量内积的方式,而是先用点乘的方式之后在用sum把一个向量里面的所有分量相加
J = -1 / m * sum (y .* log(sigmoid(X * theta)) + (1 - y ) .* log(1 - sigmoid(X * theta)));
2. 求梯度,其实梯度就是参数迭代公式中的偏导部分,为啥这个叫做梯度,其实这个是斜率,参数要按照一个角度下降,控制这个角度多大的就是这个梯度的大小。
参数收敛公式:
其实这个公式没什么牛逼的地方,思想很简单就是把
我们依然用小数来具体化,设m = 3 ,n=2,j = 1,则
这种多个乘积相加的形式应该本能的反映出这是向量点积于是,可以分成
所以
于是全部参数的梯度一次性求出就是
看了一下答案,发现
所以
而
(PS:这里为了方便把1/3略去了)
所以这个推导还不是很容易的。
grad = 1 / m * (X' * (sigmoid(X * theta)-y));
这两行代码用了两天,平均一天一行代码(囧)
1.2.3 Learning parameters using fminunc
这个不需要我们自己实现,需要注意的是,这个使用的套路是,我们实现一个函数,这个函数再作为参数传递给优化的函数
1.2.3.1 plotDecisionBoundary.m
1.2.3.1.1 contour函数的使用方法
这个分成两种情况,第一种情况是系数矩阵的列小于3,也就是特征只有两个的情况,特征如果只有两个的情况下,决策边界就是平面图形上的一条直线,画图的方法比较容易直接看程序吧。
当系数矩阵的列大于3的时候,画图利用的是轮廓图的方法。为了便于直观的思考,我们这里只考虑特征值有三个的情况,也就是决策边界图形是一个平面(x+y+z=0是一个平面)
要搞清contour()这个函数是怎么用的,就要首先搞清在Matlab里面三维图形是怎么画的
假设Matlab里面有一个三维绘制函数draw3D,那么根据二维图像的绘制方式这个函数只要接受三个参数就可以了,draw3D(x,y,z),第一个参数x是坐标在x轴方向上的分量构成的向量,第二个参数是坐标在y轴上的分量构成的向量,第三个参数z是坐标在z轴上的分量构成的向量。因为三维空间上的一个点就是(x,y,z),如果这三个分量都确定了,这个点就确认了,如果函数的参数是这样设置的,那么函数使用起来就特别直观,而实际上Matlab里面的3D绘图函数上是接收矩阵作为参数的,不知道为啥弄得那么复杂。在Matlab里最基础的绘制3D图形的函数叫做mesh,不叫draw3D。
以mesh()为例,它的参数有这样三种情况
1. 如果x,y,z是同型的二维矩阵,那么这三个矩阵中处于相同位置的值,构成了一个坐标点,比如x(1,1),y(1,1),z(1,1)构成了属于图形上的一个点,但是如果x(1,1),y(1,1),z(1,2),这三个值构成的坐标点虽然是一个点,但是这个点不在图形上。
2. 如果只接受一个参数,即mesh(z),那么z必须是一个二维的矩阵,那么在这种情况下,这个矩阵如何映射到图上的点呢?从直觉上我们能感觉x,y的坐标可能会跟矩阵的行方向索引以及列方向所以相关,最自然的感觉是对于Z矩阵中的某一个元素Z(i,j),Z(i,j)的值作为z轴方向的分量,行方向上的索引i作为x轴方向上的分量,列方向上的索引j作为y轴方向上的分量,即(i,j,Z(i,j))是图形上的一个点。实际情况是,z(i,j)作为z轴方向上的分量没问题,而x,y其实正好和想象中的相反,我们设Z是一个m x n 的矩阵,首先X方向的范围是 1-n,Y方向的范围是1-m ,而且对于矩阵Z中的任意一个元素z(i,j),行方向的索引i是坐标点在y轴方向上的分量,而列方向上的索引j是x轴方向上的索引,即(j,i,Z(i,j))是图形上的一个点。这种感觉用这张图表示比较形象。
我们可以用这么一个矩阵做一个测试
zz =
8 8 98 8 97 7 77 7 6
利用mesh(ZZ)得到的为
3. 如果x是一个向量,y也是一个向量,z是一个矩阵,那么这两个向量和一个矩阵通过何种方式组合成一个图像上的点呢,如果理解了上一点,也就是只接受一个矩阵作为参数的情况,那么这中情况也比较好理解。在上一种情况中,咱们直接说结论吧,对于矩阵中的任意一个点Z(i,j)来说,它对应的坐标为(j , i , Z( i , j )),也就是拿矩阵的列方向索引为x坐标轴的分量,拿矩阵的行方向索引作为y坐标轴的分量。但是如果这里增加了X和Y向量的话,矩阵的行列方向的索引就不能直接作为坐标的分量了,而应该作为X向量和Y向量的索引,根据这个索引得到向量中的某一个值,这个值作为坐标里的一个分量。也就是多了一层映射。具体来说就是Z(i,j),用列方向索引j,在X向量找第j个分量(即X(j))作为坐标x轴方向上的分量;用行方向上的索引i在Y向量找第i个分量(即Y(i))作为坐标在y轴方向的的分量。总结一下,如果给了三个参数X向量,Y向量,Z矩阵,那么对于矩阵中的任何一个点Z(i,j),( X(j) , Y(i) , Z( i , j ) )是图形上的一个点。注意正是由于这种关系,那么X向量的长度要和Z的列的数量一样,Y向量的长度要和Z的行的数量一样。
这个 x,y,z上存在这样的映射关系,length(x)=n,length(y)=m,z是一个m x n的二维矩阵(即 [m,n]=size(z)),那么(x[j],y[i],z[i,j])构成的点在图形上
mesh是以网格的方式来作图,surf就在网格上铺了一层表面。
了解了三维作图的方法,等高线就容易理解了,等高线的图形你可以理解为做出三维的图形之后,系统自动的给你截取等高线,所以contour和mesh使用参数的方法一样。
为什么这里用到contour函数,这是因为,对于多特征(超过2个)的分类问题,决策边界不再是一个直线而是一个立体,或者超维的立体,这个时候我们想在二维的平面上表现出决策边界只能在Z=0所在的平面上截出这个超维图像的边界。
1.2.3.1.2 meshgrid函数的使用方法
在实际的绘图过程中,我们一般按照什么步骤去绘图呢,类似于二维的图像绘制,最方便的方法是构造X矩阵,Y矩阵,之后将X、Y带入到Z = f(X,Y)的式子中去得到Z矩阵(注意这个式子一定要是向量兼容的形式)。之后把X,Y,Z带入到mesh(X,Y,Z)就可以了。
而构造X,Y矩阵最方便的方法是用meshgrid函数。meshgrid,有两种用法,第一种是[X,Y] = meshgrid(gv),第二种是[X,Y] = meshgrid(xgv,ygv)。
1. 先说第一种,[X,Y] = meshgrid(gv),它的作用是
* 把gv这个向量按行扩展成一个length(gv) x length(gv)的矩阵之后之后赋值给X
* 把X这个矩阵转置赋值给Y。
2. 再说第二种,[X,Y] = meshgrid(xgv,ygv),它的构造的方法是:
* 设 xgv和ygv都是行向量,且m = length(xgv),n = length(xgv)
* 生成的矩阵无论是X还是Y,都是 n x m型的矩阵
* if m>n : a 按行扩展到n行构成一个矩阵赋给X,b先转置成列向量按列扩展到m列构成一个矩阵赋值给Y
* if m
1.2.3.1.3 如果不用meshgrid函数,也就是采用mesh(xgv,ygv,ZZ)的方法
在这两次作业中的代码中(ex1.m以及plotDecisionBoundary.m),没有采用meshgrid的方法,而是采用这样的方法:
1. 分别生成两个X,Y向量,之后再生成一个length(X) x length(Y)的全零矩阵Z
2. 填充Z矩阵,填充的方法是:从顺序上是Z的第一行开始从左到右一行一行的填充,填充的内容对于Z(i,j)来说是用x(i),y(j)带入Z(x,y)来得到。用代码上来表示就是
for i = 1 : length(X)
for j = 1 : length(Y)
Z(i,j) = f(X(i) , Y(j))
3. 将Z矩阵转置(这步还是挺聪明的)
4. 讲X,Y,Z代入mesh(X,Y,Z)
第3步还是相当的聪明的
1.2.3.2 mapFeature.m
虽然绘图里用到这个函数,但是这个步骤还没用到,正则化部分里会用到,所以在下面展开说
1.2.4 Evaluating logistic regression
这部分的主要任务是完成predict.m这个程序,这个程序没有什么太多难的。
主要要注意的还是find的用法,比如调用sigmoid函数的结果向量为S,那么在S中找到值大于等于0.5的那些分量所在的位置,把它记录下来并且保存在一个向量中,pos = find(S>=0.5)
之后将P这个零向量中相应的位置赋值为1 p(pos) =1。我一开始惊讶于,原来还可以这么用,其实pos = find(S>=0.5),p(pos) =1 也是向量的运算,S>=0.5其实是对S中的每一个分量都执行这个操作。p(pos) = 1可以看成pos中的每一个分量i取出来带到p向量里面p(i) =1
Regularized logistic regression
2.1 Visualizing the data
这个没有要实现的,直接执行就行
2.2 Feature mapping
- 为什么要引入featuremapping这个函数,主要目的是由于决策边界不能由直线来表示,于是我们可以通过在现有的特征基础上进行组合的方法生成一些新的特征的方法来使我们的拟合曲线变成比较复杂的形态。具体来说就是两个特征x1,x2,我们可以通过对其多次的重复乘得到一个新的feature。比如我要构造一个6次方的特征,可以有
x16,x15x2,x14x22,x13x23,x12x24,x1x25,x26 这7个组合,其实x16 可以看成6个x1 相乘,x15x2 可以看成5个x1 和一个x2 相乘,到底有几种组合,这是一个排列组合的问题,这个不太擅长就先跳过去啦,有谁比较擅长可以教教我。如果从0次开始一直到6次的所有组合都加起来一共有28个。也就是如果我们有两个features,如果我们要映射到6次的时候,一共会构造出28个features。这个就是mapfeature的思想。 再说一下代码中技巧
在代码中有一个end+1的用法,如果我们对一个矩阵A进行操作的时候,end代表A最后一行的索引数。
可以参考这个文档由于mapfeature构造了28个特征,那么
theta 也得相应的增加,也得有28个。
2.3 Cost function and gradient
总的来说如果是搞定了costFunction.m的内容的这个并不是很难,但是我也踏了一些坑,我先说一下自己的思路:
1. 计算cost
目标是写出公式
在计算
t = theta(2:size(theta,1));
其实有更加优雅的方法
t = theta(2:end)
于是后面的部分用代码表示就是:
lambda / ( 2 * m ) * sum(t .* t)
其实还有更优雅的表达方法
lambda / ( 2 * m ) * t' * t
这里我还踩了一个坑,因为
ps:pow2()不是计算平方的公式是计算以2为底的指数的公式
2. 计算偏导数
这块我就是按照题目里的提示分成两部分做的,先计算
grad = [g1 ; g2]
注意因为grad是列向量,所以g1和g2中间用得是分号。
3. 更加优雅的思路
这是我见过最聪明的方法了。因为其实在正则化的过程中,其实
那么偏导数这部分计算公式都可以不变
思路是这样的
注意观察这个公式,这个公式可以分成两个部分,前一部分和普通的代价函数计算一样,后一部分是参与正则化的参数。那么我们可以建立两个参数向量第一个参数向量包含从
本质上,我们梯度下降的核心公式是这个:
其中,
我们依然用一个小的数来具体化,设n=2,则参数有三个需要确定
而
grad = ( X' * (sigmoid(X*theta) - y ) )/ m + lambda/m * theta_1 ;
我之前的思路就相当于把这个公式:
分开计算,在计算第一个公式的时候相当于用到了每个样本的第一个分量
而其实通过上面的推导步骤可以发现其实上面的条件公式也是可以整合成一个公式的,只要弄出两个
- Coursra-MachineLearning 第二次作业总结
- Coursra-MachineLearning 第一次作业总结
- 慕课第二次作业学习总结
- 第二次课总结及作业思考
- 第二次作业
- 第二次作业
- 第二次作业
- 第二次作业
- 第二次作业
- 第二次作业
- 第二次作业
- 第二次作业
- 第二次作业
- 第二次作业
- 第二次作业
- 第二次作业~~~~~
- 第二次作业
- 第二次作业
- XDOJ 1233
- 矩阵对角之间的走法常见问题之动态规划
- MINI2440裸机实验之LCD
- JavaWeb监控框架-JavaMelody
- 内容提供者——添加内容观察者
- Coursra-MachineLearning 第二次作业总结
- OpenCV-利用cvPtr2D存取矩阵元素和用cvGetReal2D取矩阵元素
- format函数
- [LeetCode]295. Find Median from Data Stream
- <input>标签用val()取不到值
- c用信号量(Semaphore)实现消费者生产者同步
- tar包方式安装Mysql
- servlet之el表达式
- 网上商城项目总结 续