鲭兜的博客


努力に胜る天才无し


机器学习笔记(第二点五周)

在硅谷,进行大规模的机器学习项目的人,通常会使用的程序语言就是Octave。Octave是一种很好的原始语言prototyping language。使用Octave,你能快速地实现你的算法,剩下的事情,你只需要进行大规模的资源配置。只要再花时间,用C++或者Java这些语言,把算法重新实现就行了。如果你能让你的学习算法在Octave上快速的实现,基本的想法实现以后,再用C++或者Java去改写,这样你就能节省出大量的时间。

1、Octave/Matlab的使用入门

1-1、Basic Operations 基础操作

简单算式
在Octave中,可以直接计算简单算式,比如5+6、3-2、5×8、1/2、2^6
逻辑运算
在Octave中,可以判断逻辑表达式的真(1)假(0),比如1==2、1~=2(注意是~=,不是!=)、1&&0、1||0、xor(1,0)
化简提示符
在Octave中,前面的提示符总是很冗长(包含Octave版本信息等),输入命令PS1('>> ');可以使得前面的提示符全部变成>>
变量赋值
在Octave中,可以定义一个变量并且初始化,比如a=3。如果你想定义一个变量,但是不希望在屏幕上打印,你可以在命令之后加上一个分号,比如a=3;。分号可以抑制打印输出,敲入回车后不会打印任何东西。
变量可以初始化为字符串,比如b='hi'
变量还可以初始化为逻辑值,比如c=(3>=1)
变量输出
如果你想输出变量,你可以直接输出变量名加上回车。
对于更复杂的屏幕输出,也可以是用disp命令显示,使用disp命令输出的结果前面没有a=的提示(按字符串输出)。
也可以使用旧风格的C语言语法,sprintf结构与printf一样。
也有一些控制输出长短格式的快捷命令,比如format longformat short(默认情况下是short)
矩阵与向量
在Octave中,可以定义一个矩阵变量并初始化,比如A=[1 2;3 4;5 6](从本质上来说,分号的作用,就是在矩阵内换行到下一行)
同样的,在Octave中,可以定一个向量变量并初始化(向量其实是一种特殊的矩阵,类型上都是矩阵),比如V=[1 2 3]V=[1;2;3]
在Octave中,可以快速定义一种向量,比如V=1:0.1:2,怎么理解呢?这个集合V是一组值(向量),从1开始,增量为0.1,直到增加到2为止。还有V=1:6,中间省略步长,表示默认步长为1。
在Octave中,还有一些其他方法来生成矩阵,比如ones(2,3)生成2行3列的全1矩阵,比如zeros(2,3)生成2行3列的零矩阵,比如rand(2,3)生成2行3列的随机矩阵(矩阵元素为0~1之间的随机值),还比如randn(2,3)生成2行3列的N矩阵(平均值为0,方差为1)。
另外,可以通过一些运算来得到复杂矩阵,比如W=-6+sqrt(10)*(randn(1,10000))得到一个有10000个元素的行向量。
此外,还有一个比较重要的矩阵生成命令,是eye(4),生成一个4阶的单位矩阵。

1-2、Moving Data Around 移动数据

矩阵尺寸
在Octave中,size(A)返回A矩阵的尺寸。而且可以把函数返回的结果同样看成是一个矩阵,作为新矩阵的赋值,比如sz=size(A)。此外,size(A,k)表示第k维度上A矩阵的尺寸。
在Octave中,length(A)可以返回A矩阵的尺寸信息,但是只返回一个值,这个值是A矩阵中维度尺寸的最大值。
加载数据
通常,打开Octave时,我们会处于一个默认路径,这个路径是Octave的安装路径,可以使用pwd命令来查看Octave当前选择路径。
在Octave中,cd命令表示改变当前路径到指定的路径中,比如cd 'C:\Users\abc\Desktop'
使用ls命令,可以显示当前路径下的所有文件信息。
在Octave中,可以使用load test.dat命令(或者load('test.dat')命令)来读取当前路径下存在的test.dat文件的数据。(load的文件必须存在)
在Octave中,可以使用who命令,来查看当前工作空间的所有变量名。还可以使用whos命令,更加详细地进行查看所有变量的一些信息。
在Octave中,可以使用clear A命令来删除变量A,也可以使用clear all命令来删除所有变量。
在Octave中,可以截取矩阵的一部分来给新矩阵赋值,比如A=B(1:10),表示把B矩阵中的前10个元素赋给A矩阵。
在Octave中,可以使用save test.dat A命令,来将矩阵A的数据保存到当前路径下的test.dat文件中(save的文件不一定存在,如果不存在,软件将会帮助创建)。此外,使用save test.txt A -ascii命令,表示把数据存成一个文本文档或者将数据的ASCII码存成文本文档。
操作数据
在Octave中,可以使用A(3,2)命令来索引矩阵A[3][2]的值。
在Octave中,可以使用A(2,:)命令来索引矩阵A第二行的行向量(所以,‘:’表示该行或者该列的所有元素)。同理,可以使用A(:,2)来索引矩阵A第二列的列向量。此外,还可以使用更为复杂的索引,比如A([1 3],:)表示取矩阵A第一个索引值为1或3的行,即A矩阵的第一行和第三行。在选中这部分矩阵的同时,你也可以为它赋值,比如A(:,2)=[10;11;12]表示取出矩阵A的第二列并且把一个列向量[10;11;12]赋值给了它。
在Octave中,可以直接使用一个矩阵为另一个矩阵赋值,比如A=[A,[100;101;102]]表示在矩阵A右边加上一个列向量、C=[A B](或者C=[A,B])表示将矩阵A和矩阵B左右放置连接成一个新矩阵C、C=[A;B]表示将矩阵A和矩阵B上下放置连接成一个新矩阵C。(所以分号的作用就是将后面的数据换到下一行)
在Octave中,可以使用A(:)命令来将矩阵A中的所有元素放入一个单独的列向量。

1-3、Computing On Data 数据计算

在Octave中,可以使用A*C命令来将矩阵A与矩阵C相乘。
在Octave中,可以使用A.*B命令来将矩阵A与矩阵B中对应元素相乘。
在Octave中,可以使用A.^2命令来将矩阵A中的所有元素平方。
在Octave中,可以使用1./V命令来将矩阵V中的所有元素取倒数。
在Octave中,可以使用log(V)命令来将矩阵V中的所有元素对2取对数。
在Octave中,可以使用exp(V)命令来将矩阵V中的所有元素变成$e^x$。
在Octave中,可以使用abs(V)命令来将矩阵V中的所有元素取绝对值。
在Octave中,可以使用-V命令来将矩阵V中的所有元素取负。
在Octave中,可以使用V+1命令来将矩阵V中的所有元素加一,所以矩阵与实数的运算是矩阵里的每一个元素与实数进行运算。
在Octave中,可以使用A'命令来表示矩阵A的转置矩阵。
在Octave中,可以使用max(a)命令显示向量a中的最大元素值,还可以使用[val, ind]=max(a)命令来显示最大值和最大值的索引,对于矩阵A使用max函数的话,函数会在每一列上进行比较,返回每一列的最大值和最大值的索引。
在Octave中,可以使用max(A,B)表示矩阵A和矩阵B对应每个元素之间的较大值。可以使用max(A,[],1)表示以第一维度为比较方向查看矩阵A的最大值,即每一列的最大值。同理,可以使用max(A,[],2)表示以第二维度为比较方向查看矩阵A的最大值,即每一行的最大值。可以使用max(max(A))命令或者max(A(:))命令来查看整个矩阵A的最大值。
在Octave中,可以使用a<3命令来表示向量a的所有元素与3比较的逻辑结果。
在Octave中,可以使用find(a<3)命令来表示向量a的所有元素中元素值小于3的索引值。
在Octave中,可以使用magic(3)命令来定义一个3阶幻方矩阵。
在Octave中,可以使用sum(a)命令计算向量a中所有元素的和,可以使用sum(A,1)命令计算矩阵A中每一列的和,同理,可以使用sum(A,2)命令计算矩阵A中每一行的和。
在Octave中,可以使用prod(a)命令计算向量a中所有元素的积。
在Octave中,可以使用floor(a)命令计算向量a中所有元素的不大于元素值的最大整数。
在Octave中,可以使用ceil(a)命令计算向量a中所有元素的不小于元素值的最小整数。
在Octave中,可以使用flipud(A)命令将矩阵A上下翻转。
在Octave中,可以使用pinv(A)命令计算矩阵A的逆矩阵。

1-4、Plotting Data 绘制数据

在运用学习算法时,往往几个简单的图,就可以让我们更好地理解算法的内容,以及检查算法是否正常运行、是否达到目的。
在Octave中,可以使用plot(t,y1)命令来绘制以t为自变量、y1为因变量的函数曲线。
在Octave中,可以使用hold on命令来要求后面图的绘制是在前面图的基础上的。
在Octave中,可以使用xlabel('time')命令来标注x轴的标记为time。
在Octave中,可以使用legend('sin','cos')命令来标注不同条线的线标。
在Octave中,可以使用title('my plot')命令来标注图像的标题。
在Octave中,可以使用print -dpng 'myPlot.png'命令来保存当前绘制图像到当前路径中。
在Octave中,可以使用close命令来关闭当前绘制的图像。
在Octave中,允许同时绘制多个图像,但是要在绘制图像之前先定义一下figure(1)
在Octave中,可以使用subplot(1,2,1)命令来绘制子图,这表示我们将整幅画面划分为1*2的格子,下一幅图绘制在第一个格子里面。
在Octave中,可以使用axis([0.5 1 -1 1])命令来限制x的值在0.5~1之间,y的值在-1到1之间。
在Octave中,可以使用clf命令来清除figure的所有信息。
在Octave中,可以使用imagesc(A)命令来可视化一个矩阵,绘制出一个矩阵的彩色格图,不同的颜色代表不同的数值。在此基础上,可以使用colorbar命令来显示数字与颜色的对应情况。还可以使用colormap gray命令来使得这个彩色格图变成灰度格图。

1-5、Control Statements: for,while,if statement 控制语句

这里仅给出几个例子进行模仿使用
for

1
2
3
for i=1:10,
v(i)=2^i;
end;
1
2
3
4
indices=1:10;
for i=indices,
disp(i);
end;

while

1
2
3
4
5
i=1;
while i<=5,
v(i)=100;
i=i+1;
end;

1
2
3
4
5
6
7
8
i=1;
while true,
v(i)=999;
i=i+1;
if i==6,
break;
end;
end;

if-else

1
2
3
4
5
6
7
8
v(1)=2;
if v(1)==1,
disp('The value is one.');
elseif v(1)==2,
disp('The value is two.');
else
disp('The value is not one or two.');
end;

函数定义和调用

1
2
function y=squarethisnumber(x)
y=x^2;

在Octave中,可以使用addpath('C:\Users\Tammy\Desktop')来添加Octave的搜索路径,Octave寻找函数名称是会在搜索路径的同名文件夹中寻找。
在Octave中,可以定义函数返回值是多个。

1
2
3
function [y1, y2]=squareandcubethisnumber(x)
y1=x^2;
y2=x^3;

1-6、Vectorization 向量化

无论我们使用哪种语言,我们都能获得这种语言的线性代数库。第一,这些写好的库是十分高效的,直接调用它们,运行速度更加快。第二,我们可以使用更少的代码来实现我们所需要的功能,实现的方式更加简单,代码出现问题的可能性也越小。
Unvectorized implementation
$h_\theta(x)=\displaystyle\sum_{j=0}^n\theta_jx_j\\=\theta^Tx$
$\theta=
\begin{bmatrix}
\theta_0 \\
\theta_1 \\
\theta_2
\end{bmatrix}
$
$x=
\begin{bmatrix}
x_0 \\
x_1 \\
x_2
\end{bmatrix}
$
Unvectorized implementation–Matlab

1
2
3
4
prediction = 0.0;
for j = 1:n+1,
prediction = prediction + theta(j) * x(j);
end;

Vectorized implementation–Matlab

1
prediction = theta' * x;

Unvectorized implementation–C++

1
2
3
double prediction = 0.0;
for(int j = 0; j <= n; j++)
prediction += theta[j] * x[j];

Vectorized implementation–C++

1
double prediction = theta.transpose() * x;