Octave/Matlab Tutorial
Octave/Matlab Tutorial
Basic Operations
你现在已经掌握不少机器学习知识了 在这段视频中 我将教你一种编程语言 Octave语言 你能够用它来非常迅速地 实现这门课中我们已经学过 或者将要学的 机器学习算法
过去我一直尝试用不同的编程语言 来教授机器学习 包括C++、Java、 Python、Numpy 和 Octave 我发现当使用像 Octave这样的 高级语言时 学生能够更快 更好地学习 并掌握这些算法
事实上 在硅谷 我经常看到的情况是 进行大规模的 机器学习项目的人 通常会使用的 程序语言 就是Octave, Octave是一种很好的原始语言(prototyping language) 使用Octave 你能快速地实现你的算法 剩下的事情 你只需要 进行大规模的资源配置 你只用再花时间 用C++或Java这些语言 把算法重新实现就行了 因为我们知道 开发项目的时间 或者说你的时间 是很宝贵的 机器学习的时间也是很宝贵的 所以 如果你能 让你的学习算法在Octave上快速的实现 基本的想法实现以后 再用C++或者Java去改写 这样 你就能节省出 大量的时间
据我所见 人们使用最多的 用于机器学习的原始语言 是Octave、MATLAB Python、NumPy 和 R Octave很好 因为它是开源的 当然 MATLAB也很好 但它不是每个人都 买得起的 但是 如果你能够使用MATLAB 你也可以在这门课里面使用 如果你会Python、NumPy 或者R语言 我也见过有人用 R 的 但是 据我所知 这些人不得不中途放弃了 因为这些语言在开发上比较慢 而且 因为这些语言 Python、NumPy的语法 相较于Octave来说 还是更麻烦一点 正因为这样 也因为我们最开始 用Octave来写程序 所以我强烈建议你 不要用NumPy或者R来完整这门课的作业 我建议你 在这门课中 用Octave来写程序 接下来 本视频将快速地介绍 一系列的命令 目标是迅速地展示 通过这一系列Octave的命令 让你知道Octave能用来做什么 我们的网站会提供 所有我在视频中提到的 内容的文本 所以 当你看完这个视频 想查询一些命令时 你可以查看这些资料 这些都放在网上了
总之 我建议你 先看教学视频 之后 把Octave安装到电脑上 最后 去这门课的网站上 下载这门课的 相关文档和视频 然后 你可以试着 在Octave中键入一些 有趣的命令 让程序运行在你的电脑上 这样你可以看到程序是怎么运行的
让我们开始吧 这里是我的Windows桌面 启动Octave 现在打开Octave 这是Octave命令行 现在让我示范 最基本的Octave代码
输入5 + 6 然后得到11 ;输入3 - 2; 5×8;1/2;2 ^ 6 得到64; 这些都是基本的数学运算
>> 5+6 ans = 11 >> 3-2 ans = 1 >> 5*8 ans = 40 >> 1/2 ans = 0.50000 >> 2^6 ans = 64
你也可以做逻辑运算 例如 1==2 计算结果为 false ( 假 ) 这里的百分号命令表示注释, 1==2 计算结果为假 这里用0表示;
1 ~= 2 这是真的 因此返回1 请注意 不等于符号的写法 是这个波浪线加上等于符号 ( ~= ) 而不是等于感叹号加等号 ( != ) 这是和其他一些 编程语言中不太一样的地方
让我们看看逻辑运算 1 && 0 使用双&符号 表示逻辑与 1 && 0判断为假 1和0的或运算 1 || 0 其计算结果为真
还有异或运算 如XOR ( 1, 0 ) 其返回值为1
>> 1 == 2 %false ans = 0 >> 1 ~= 2 %true ans = 1 >> 8>1 && 0 %AND ans = 0 >> 9>1 || 1 %OR ans = 1 >> xor(1,0) ans = 1
从左向右写着 Octave 324.x版本 其计算结果等于11 这是默认的Octave提示 它显示了当前Octave的版本 以及相关的其它信息 如果你不想看到那个提示 这里有一个隐藏的命令 输入命令 PS(‘>> ‘); 现在你看到的就是等待命令的快捷提示 这句话在中间有一个字符串 (‘>> ‘); 这是我喜欢的命令行样子 这里敲一个回车 抱歉 写错了 这样才对 要写成PS1这样 现在命令提示已经变得简化了 这样看起来很棒
>> PS1(‘>>>‘); >>>
接下来 我们将谈到Octave的变量 现在写一个变量 对变量A赋值为3 并按下回车键 显示变量A等于3 如果你想分配一个变量 但不希望在屏幕上显示结果 你可以在命令后加一个分号 可以抑制打印输出 敲入回车后 不打印任何东西。 A等于3 只是不显示出来 其中这句命令不打印任何东西 现在举一个字符串的例子 变量b等于"hi" 现在 如果我输入b 则会显示字符串变量b的值"hi" C等于3大于等于1 所以 现在C变量的值是真 如果你想打印出变量 或显示一个变量 你可以像下面这么做 设置A等于圆周率π 如果我要打印该值 那么只需键入A 像这样 就打印出来了
>>>a = 3 a = 3 >>>a = 3; #分号抑制打印 >>>
对于更复杂的屏幕输出 也可以用DISP命令显示 Disp( A )就相当于像这样打印出A 你也可以用该命令来显示字符串 输入disp sprintf 小数 0.2% 逗号 A 像这样 通过这条命令将打印出字符串 打印显示为“两位小数:3.14” 这是一种 旧风格的C语言语法 如果 就学过C语言的同学来说 你可以使用这种基本的语法来将结果打印到屏幕 Sprintf命令生成一个字符串 不仅仅是 字符串“2 decimal:3.14” 其中的“0.2%F”表示 代替A放在这里 并显示A值的小数点后两位数字 同时DISP 命令对字符串做出操作 DISP命令输出 Sprintf产生的字符串 Sprintf命令 和DISP命令显示字符串 再说一个细节 例如 sprintf命令的六个小数 0.6%F ,A 这应该打印π 的6位小数形式 最后 看起来像这样 也有一些控制输出长短格式的快捷命令 默认情况下 是字符串 显示出的小数位有点多 短 ( short ) 格式 是默认的输出格式 只是打印小数数位的第一位 相关这方面的内容还需要你继续练习
>>>a = 3.14; >>>a a = 3.1400 >>>disp(a); 3.1400 >>>disp(sprintf(‘2 decimals: %0.2f‘, a)); 2 decimals: 3.14
>>>a=pi a = 3.1416 >>>format long >>>a a = 3.14159265358979 >>>format short >>>a a = 3.1416
下面 让我们来看看向量和矩阵 比方说 建立一个矩阵A 输入1 2 ; 3 4 ; 5 6 这会产生一个 三行两列的矩阵A 其第一行是1 2 第二行是3 4 第三行是5 6 分号的作用 从本质上来说 就是在矩阵内换行到下一行 此外 还有其他的方法来建立矩阵A 输入A矩阵的值 1 2 分号 3 4 分号 5 6 这是另一种方法 对A矩阵进行赋值 考虑到这是一个三行两列的矩阵
>>>A = [1 2; 3 4; 5 6] A = 1 2 3 4 5 6 >>>a = [1 2; 3 4; 5 6] a = 1 2 3 4 5 6
你同样可以用向量 建立向量V并赋值1 2 3 V是一个行向量 或者说是一个3 ( 列 )×1 ( 行 ) 的向量 一个胖胖的Y向量 或者说 一行三列的矩阵 注意不是三行一列 如果我想 分配一个列向量 我可以写“1;2;3” 现在便有了一个 3 行 1 列 的向量 同时这是一个列向量 下面是一些更为有用的符号 V等于1:0.1:2 这个该如何理解呢 这个集合V是一组值 从数值1开始 增量或说是步长为0.1 直到增加到2 按照这样的方法对向量V操作 可以得到一个行向量 这是一个1行11列的矩阵 其矩阵的元素是1 1.1 1.2 1.3 依此类推 直到数值2
>>>v = [1 2 3] v = 1 2 3 >>>v = [1; 2; 3] v = 1 2 3
>>>v = 1:0.1:2 v = Columns 1 through 4: 1.0000 1.1000 1.2000 1.3000 Columns 5 through 8: 1.4000 1.5000 1.6000 1.7000 Columns 9 through 11: 1.8000 1.9000 2.0000
>>>v = 1:6 v = 1 2 3 4 5 6
现在 我也可以 建立一个集合V并用命令“1:6”进行赋值 这样V就被赋值了 1至6的六个整数 这里还有一些其他的方法来生成矩阵 例如“ones(2, 3)” 也可以用来生成矩阵 其结果为一个两行三列的矩阵 不过矩阵中的所有元素都为1 当我想生成一个 元素都为2 两行三列的矩阵 就可以使用这个命令 你可以把这个方法当成一个 生成矩阵的快速方法 当你想生成一个三维2×2×2的矩阵时 你就可以用这个“ones”命令 比方说 w是一个有三个1的 行向量 或者说一行 由三个同样的1组成的向量 你也可以说 w为一个 一行三列的零矩阵 一行三列的A矩阵里的元素全部是零
>>>ones(2,3) ans = 1 1 1 1 1 1 >>>w = ones(1,3) w = 1 1 1
还有很多的方式来生成矩阵 如果我对W进行赋值 用Rand命令建立一个一行三列的矩阵 因为使用了Rand命令 则其一行三列的元素均为随机值 如果我使用 “rand(3, 3)”命令 这就生成了一个 3×3的矩阵 并且其所有元素均为随机 数值介于0和1之间 所以 正是因为这一点 我们可以得到 数值均匀介于0和1之间的元素
>>>w = rand(3,3) w = 0.91025 0.82671 0.14067 0.90400 0.34350 0.51289 0.25501 0.24975 0.80750
如果 你知道什么是高斯随机变量 或者 你知道什么是正态分布的随机变量 你可以设置集合W 使其等于一个一行三列的N矩阵 并且 来自三个值 一个平均值为0的高斯分布 方差 或者等于1的标准偏差 还可以设置地更复杂
?>>>w = randn(1,3) w = -0.052546 -1.786869 0.754202
例如 W减去6 再加上10的平方 两者相乘 Rand命令生成一个1行10000列的矩阵 把分号放到末尾 这样结果就打印不出来 那这样会得到什么呢 这样就可以 得到 一个有10000元素的向量 想知道具体是多少 我们也可把它打印出来 这将产生一个这样的矩阵 生成了这个叫做 data 的对象 是吧? 这就是一个 有着10000个元素的矩阵W 如果我现在 用绘制直方图命令 绘制出一个直方图 使用Octave的 打印直方图命令 你只需要数秒钟就可以将它绘制出来 这是一个对随机变量W 绘制出的直方图 这里是-6+0 乘上十倍的高斯随机变量 这样 可以绘制出一个 有着更多条的 乃至50个条的直方图来 这样 就有一个 均值减去6的高斯直方图 因为这里是 -6加10的平方根并与这项相乘 因此 这个高斯随机变量的方差 是10 且其标准偏差为10的平方根 3.1
w = -6 + sqrt(10)*(randn(1,10000)); hist(w) hist(w, 50)
最后 说一个生成矩阵的 特殊命令I 其实 I也可说是一个双关语字标识 设置一个4阶单位矩阵 这是一个4×4矩阵 所以I为“eye(4)” 通过上面的命令得到4×4矩阵 I可以等于5阶单位阵 6阶单位阵 那么就有 6阶单位阵 eye( 3 )是一个3阶方阵
>> eye(4) ans = Diagonal Matrix 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1
在本节视频的最后 还有一个比较有用的命令 那就是帮助命令 例如 你可以键入help i 它就会将矩阵的相关信息显示出来 命令Q可以退出Octave 你也可以键入help rand 将会显示出有关rand函数的相关帮助文档 以及相关的随机数生成函数 甚至可以使用命令help help 将会显示出help命令的使用方法
>> help For help with individual commands and functions type help NAME (replace NAME with the name of the command or function you would like to learn more about). For a more detailed introduction to GNU Octave, please consult the manual. To read the manual from the prompt type doc GNU Octave is supported and developed by its user community. For more information visit http://www.octave.org.
以上讲解的内容 都是Octave的基本操作 希望你能通过上面的讲解 自己练习一些矩阵、乘、加等操作 将这些操作在Octave中熟练 在接下来的视频中 将会涉及 更多复杂的命令 并使用它们在Octave中对数据进行更多的操作
Moving Data Around移动数据
在第二段关于 Octave的 辅导课视频中 我将开始介绍 如何在 Octave 中移动数据 具体来说 如果你有一个机器学习问题 你怎样把数据加载到 Octave 中? 怎样把数据存入一个矩阵? 如何对矩阵进行相乘? 如何保存计算结果? 如何移动这些数据 并用数据进行操作?
和之前一样 这是我的 Octave 窗口 我们继续沿用上次的窗口 我键入 A 得到我们之前构建的矩阵 A 也就是用这个命令生成的 A = 这是一个三行二列的矩阵
Octave 中的 size() 命令 返回矩阵的尺寸 所以 size(A) 命令返回3 2 实际上 size() 命令返回的 是一个 1×2 的矩阵 我们可以用 sz 来存放 设置 sz = size(A) 因此 sz 就是一个1×2的矩阵 第一个元素是3 第二个元素是2 所以如果键入 size(sz) 看看 sz 的尺寸 返回的是1 2 表示是一个1×2的矩阵 1 和 2 分别表示 矩阵 A 的维度 (此处口误 应为 sz 的维度 译者注)
>> A = [1 2; 3 4; 5 6] A = 1 2 3 4 5 6 >> size(A) ans = 3 2 >> sz = size(A) sz = 3 2 >> size(sz) ans = 1 2
>> size(A,1) ans = 3 >> size(A,2) ans = 2
你也可以键入 size(A, 1) 这个命令会返回 A 矩阵的第一个元素 A 矩阵的第一个维度的尺寸 也就是 A 矩阵的行数 同样 命令 size(A, 2) 将返回2 也就是 A 矩阵的列数 也就是 A 矩阵的列数 如果你有一个向量 v 假如 v = 假如 v = 然后键入 length(v) 这个命令将返回 最大维度的大小 你也可以键入 length(A) 由于矩阵 A 是一个3×2的矩阵 因此最大的维度 应该是3 因此该命令会返回3 但通常我们还是对向量使用 length 命令 比如 length() 比如 length() 而不是对矩阵使用 length 命令 因为毕竟有点容易让人弄混
>> V = [1 2 3 4] V = 1 2 3 4 >> length(V) ans = 4 >> length(A) ans = 3
下面让我们来看看 如何在系统中 加载数据和寻找数据 当我们打开 Octave 时 我们通常已经在一个 默认路径中 这个路径是 Octave 的安装位置 pwd 命令可以显示出 Octave 当前所处路径 Octave 当前所处路径 所以现在我们就在这个目录下 cd 命令 意思是改变路径 我可以把路径改为C:\Users\ang\Desktop 这样当前目录就变为了桌面 如果键入 ls ls 来自于一个 Unix 或者 Linux 命令 ls 命令将列出 我桌面上的所有路径 因此这些就是 我桌面上的所有文件了
>> pwd ans = C:\Users\xin >> cd ‘E:\TEMPsrc\octave‘ >> pwd ans = E:\TEMPsrc\octave >> ls
事实上 我的桌面上 有两个文件 featuresX.dat 和 priceY.dat 是两个我想解决的机器学习问题 这是我的桌面 这是 featuresX 文件 featuresX 文件如这个窗口所示 是一个含有两列数据的文件 这其实就是我的房屋价格数据 我想应该是 数据集中有47行 第一个房子样本 面积是2104平方英尺 有3个卧室 第二套房子面积为1600 有3个卧室 等等 priceY 是这个文件 也就是 训练集中的价格数据 所以 featuresX 和 priceY 就是两个存放数据的文档 那么应该怎样把数据读入 Octave 呢? 好的 我们只需要键 键入 featuresX.dat 这样 我将加载了 featuresX 文件 同样地我可以加载 priceY.dat 其实有好多种办法可以完成 如果你把命令写成 字符串的形式 load(‘featureX.dat‘) 也是可以的 这里打错了 这跟刚才的命令效果是相同的 只不过是把文件名 写成了一个字符串的形式 现在文件名被存在一个 字符串中 Octave 中使用引号 来表示字符串 就像这样 这就是一个字符串 因此我们读取的文件 文件名由这个字符串给出
load featuresX.dat load priceY.dat load(‘featuresX.dat‘)
另外 who 命令 能显示出 在我的 Octave 工作空间中的所有变量 因此 who 命令显示出 当前 Octave 储存的变量 包括 featureX 和 priceY 同样还包括 在此之前你创建的 那些变量
>> who Variables in the current scope: a ans b c
所以我可以键入 featuresX 回车 来显示 featuresX 这些就是存在里面的数据 还可以键入 size(featuresX) 得出的结果是 47 2 代表这是一个47×2的矩阵 类似地 输入 size(priceY) 结果是 47 1 表示这是一个47维的向量 是一个列矩阵 存放的是训练集中的所有价格 Y 的值 who 函数能让你看到 当前工作空间中的所有变量
同样还有另一个 whos 命令 能更详细地进行查看 因此 在 who 后面加一个 s 同样也列出我所有的变量 不仅如此 还列出了变量的维度 我们看到 A 是一个 3×2的矩阵 X 是一个47×2的矩阵 priceY 是一个47×1的矩阵 也就是一个向量 同时还显示出 需要占用多少内存空间 以及数据类型是什么 double 意思是双精度浮点型 这也就是说 这些数都是实数 是浮点数
>> whos Variables in the current scope: Attr Name Size Bytes Class ==== ==== ==== ===== ===== a 1x1 8 doubl e ans 1x17 17 char b 1x1 8 doubl e c 1x1 8 doubl e d 3x2 48 doubl e Total is 26 elements using 89 bytes
如果你想删除某个变量 你可以使用 clear 命令 因此 我们键入 clear featuresX 然后再输入 whos 命令 你会发现 featuresX 消失了
>> who Variables in the current scope: a ans b c d >> clear a >> who Variables in the current scope: ans b c d
另外 我们怎么储存数据呢? 我们来看 我们设变量 v 为 priceY(1:10) 这表示的是将向量 Y 的 前10个元素存入 v 中 我们输入 who 或者 whos Y 是一个47×1的向量 因此现在 v 就是10×1的向量 因为刚才设置了 v = priceY(1:10) 这便将 v 的值 设为了 Y 的前十个元素 假如我们想把它存入硬盘 那么用 save hello.mat v 命令 这个命令 会将变量 v 存成一个叫 hello.mat 的文件 让我们回车 现在我的桌面上 就出现了一个新文件 名为 hello.mat 由于我的电脑里 也同时安装了 MATLAB 所以这个图标 上面有 MATLAB 的标识 因为操作系统把文件识别为 MATLAB 文件 所以如果在你的电脑上 图标显示的不一样的话 也没有关系
>> save hello.mat d
现在我们清除所有变量 直接键入 clear 这样将删除工作空间中的所有变量 所以现在工作空间中啥都没了
>> clear >> who
但如果我载入 hello.mat 文件 我又重新读取了变量 v 因为我之前 把变量 v存入了 hello.mat 文件中 所以我们刚才用 save 命令做了什么 这个命令把数据 按照二进制形式储存 或者说是更压缩的二进制形式 因此 如果 v 是很大的数据 那么压缩幅度也更大 占用空间也更小 如果你想把数据 存成一个人能看懂的形式 那么可以键入 save hello.txt v -ascii 这样就会把数据 存成一个文本文档 或者将数据的 ascii 码存成文本文档 现在 我键入了这个命令以后 我的桌面上 就有了 hello.txt 文件 就有了 hello.txt 文件 如果打开它 我们可以发现 这个文本文档存放着我们的数据 这就是读取和储存数据的方法
>> v = [1 2; 3 4; 5 6; 7 8; 9 0] v = 1 2 3 4 5 6 7 8 9 0 < -ascii %save as text(ASCII)
接下来我们再来讲讲操作数据的方法 假如 A 还是那个矩阵 跟刚才一样还是那个 3×2 的矩阵 现在我们加上索引值 比如键入 A(3,2) 这将索引到 A 矩阵的 (3,2) 元素 A 矩阵的 (3,2) 元素 这就是我们通常 书写矩阵的形式 写成 A 下标32 下标32
3和2分别表示 矩阵的第三行 和第二列对应的元素 因此也就对应 6 我也可以键入 A(2,:) 来返回 第二列的所有元素 因此 冒号表示 该行或该列的所有元素 因此 A(2,:) 表示 A 矩阵的第二行的所有元素 类似地 如果我键入 A(:,2) 这将返回 A 矩阵第二列的所有元素 这将得到 2 4 6 这表示返回 A 矩阵的第二列的所有元素 因此这就是 矩阵 A 的第二列 就是 2 4 6 你也可以在运算中 使用这些较为复杂的索引
>> A = [1 2; 3 4; 5 6] A = 1 2 3 4 5 6 >> A(3,2) ans = 6 >> A(2,:) ans = 3 4 >> A(:,2) ans = 2 4 6
我再给你展示几个例子 可能你也不会经常使用 但我还是输入给你看 A(,:) 这个命令意思是 取 A 矩阵第一个索引值为1或3的元素 也就是说我取的是 A 矩阵的第一行和 第三行的每一列 第三行的每一列 这是 A 矩阵 因此 输入 A(, :) 返回第一行 返回第三行 冒号表示的是 取这两行的每一列元素 也就是第一行 和第二行的所有元素(此处口误 应为第三行 译者注) 因此返回结果为 1 2 5 6
>> A([1 3], :) ans = 1 2 5 6
可能这些比较复杂一点的 索引操作 你不会经常用到 我们还能做什么呢 这依然是 A 矩阵 A(:,2) 命令返回第二列 你也可以为它赋值 所以我可以取 A 矩阵的第二列 然后将它赋值为 10 11 12 如果我这样做的话 我实际上是取出了 A 的第二列 然后把一个列向量赋给了它 因此现在 A 矩阵的第一列还是 1 3 5 第二列就被替换为 10 11 12 接下来一个操作 让我们把 A 设为 A = ] 这样做的结果是 在原矩阵的右边 附加了一个新的列矩阵 附加了一个新的列矩阵 现在 见证奇迹的时刻... 噢 我又犯错了 应该放分号的 现在 A 矩阵就是这样了 明白吗? 我希望你听懂了 所以 这是个列矩阵 而我们所做的 就是把 A 矩阵设置为 原来的 A 矩阵 再在右边附上一个 新添加的列矩阵 我们的原矩阵 A 就是右边这个6个元素 就是右边这个6个元素 所以我们就是把 A 矩阵 右边加上了一个 新的列向量 所以现在 A 矩阵 变成这样一个 3×3 的矩阵
>> A(:,2) = [10;11;12] A = 1 10 3 11 5 12 >> A = [A, [100;101;102]] A = 1 10 100 3 11 101 5 12 102
最后 还有一个小技巧 我也经常使用 如果你就输入 A(:) 这是一个很特别的语法结构 意思是把 A 中的所有元素 放入一个单独的列向量 这样我们就得到了一个 9×1 的向量 这些元素都是 A 中的元素排列起来的
>> A(:) ans = 1 3 5 10 11 12 100 101 102
再来几个例子好了 我还是把 A 重新设为 假如说 我再设一个 B 为 我可以新建一个矩阵 C C = 这个意思就是 这是我的矩阵 A 这是我的矩阵 B 我设 C = 这样做的结果就是 把这两个矩阵直接连在一起 矩阵 A 在左边 矩阵 B 在右边 这样组成了 C 矩阵 就是直接把 A 和 B 合起来 我还可以设 C = 这里的分号表示 把分号后面的东西放到下面 所以 的作用 依然还是把两个矩阵 放在一起 只不过现在是上下排列 所以现在 A 在上面 B 在下面 C 就是一个 6×2 矩阵 简单地说 分号的意思就是换到下一行 所以 C 就包括上面的 A 然后换行到下面 然后在下面放上一个 B 另外顺便说一下 这个命令 跟 是一样的 这两种写法的结果是相同的
>> A = [1 2; 3 4; 5 6]; >> B = [11 12; 13 14; 15 16]; >> C = [A B] C = 1 2 11 12 3 4 13 14 5 6 15 16
>> C = [A; B] C = 1 2 3 4 5 6 11 12 13 14 15 16
好了 通过以上这些操作 希望你现在掌握了 怎样构建矩阵 也希望我展示的这些命令 能让你很快地学会 怎样把矩阵放到一起 怎样取出矩阵 并且把它们放到一起 组成更大的矩阵 通过几句简单的代码 Octave 能够很方便地 很快速地帮助我们 组合复杂的矩阵以及对数据进行移动 这就是移动数据这一节课
在下一段视频中 我们将一起来谈谈 怎样利用数据进行更为复杂的计算 希望这节课的内容 能让你明白 在 Octave 中 怎样用几句简单的命令 很快地对数据进行移动 包括加载和储存一个向量 或矩阵 加载和存储数据 把矩阵放在一起 构建更大的矩阵 用索引对矩阵某个特定元素进行操作等等 我知道可能我一下子 讲了很多命令 所以我认为对你来讲
最好的学习方法是 下课后复习一下我键入的这些代码 好好地看一看 从课程的网上 把代码的副本下载下来 重新好好看看这些副本 然后自己在 Octave 中 把这些命令重新输一遍 慢慢开始学会使用这些命令 当然 没有必要把这些命令都记住 你也不可能记得住 你要做的就是 从这段视频里 了解一下你可以用哪些命令 做哪些事 这样在你今后需要 编写学习算法时 如果你要找到某个 Octave 中的命令 你可能回想起 你之前在这里学到过 然后你就可以查找 课程中提供的程序副本 这样就能很轻松地找到 你想使用的命令了 好了 这就是 移动数据这节课的全部内容
在下一段视频中 我将开始向你介绍 怎样进行一些 更复杂的计算 怎样对数据进行计算 怎样对数据进行计算 同时开始实现学习算法
Computing on Data
现在 你已经学会了在Octave中 如何加载或存储数据 如何把数据存入矩阵 等等 在这段视频中 我将向你介绍 如何对数据进行运算 稍后我们将使用这些 运算操作来实现我们的学习算法
现在我们开始吧 这是我的 Octave 窗口 我现在快速地 初始化一些变量 比如设置A 为一个3×2的矩阵 设置B为 一个3 × 2矩阵 设置C为 2 × 2矩阵 现在 我想算两个矩阵的乘积 比如说 A × C 我只需键入A×C 这是一个 3×2 矩阵乘以 2×2 矩阵 得到这样一个3×2矩阵 你也可以对每一个元素 做运算 方法是做点乘运算A .*B 这么做 Octave将矩阵 A 中的每一个元素 与矩阵 B 中的 对应元素相乘 这是A 这是B 这是A .* B 比如说 这里第一个元素 1乘以11得到11 第二个元素是 2乘以12得到24 这就是两个矩阵的 元素位运算 通常来说 在Octave中 点号一般 用来表示元素位运算 这里是一个矩阵A 这里我输入A .^ 2 这将对矩阵A中 每一个元素平方 所以 1的平方是1 2的平方是4 等等
>> A = [1 2; 3 4; 5 6]; >> B = [11 12; 13 14; 15 16]; >> C = [1 1; 2 2]; >> A*C ans = 5 5 11 11 17 17 >> A .* B ans = 11 24 39 56 75 96 >> A .^ 2 ans = 1 4 9 16 25 36
我们设V是一个向量 设V为 是列向量 你也可以输入 1 ./ V 得到每一个元素的倒数 所以这样一来 就会分别算出 1/1 1/2 1/3 矩阵也可以这样操作 1 ./ A 得到 A中每一个元素的倒数
>> V = [1; 2; 3]; >> 1 ./ V ans = 1.00000 0.50000 0.33333 >> 1 ./ A ans = 1.00000 0.50000 0.33333 0.25000 0.20000 0.16667
同样地 这里的点号 还是表示对每一个元素进行操作 我们还可以进行求对数运算 也就是对每个元素 进行求对数运算 还有自然数e的幂次运算 就是以e为底 以这些元素为幂的运算 所以这是e 这是e的平方 这是e的立方 v 矩阵是这样的 我还可以用 abs 来对 v 的每一个元素 求绝对值 当然这里 v 都是正数 我们换成另一个 这样对每个元素求绝对值 得到的结果就是 这些非负的元素 还有 -v 给出V中每个元素的相反数 这等价于 -1 乘以 v 不过一般就直接用 -v 就好了 其实就等于 -1*v 还有什么呢?
>> log(V) ans = 0.00000 0.69315 1.09861 >> exp(V) ans = 2.7183 7.3891 20.0855 >> abs(V) ans = 1 2 3
还有一个技巧 比如说 我们想对v中的每个元素都加1 那么我们可以这么做 首先构造一个 3行1列的1向量 然后把这个1向量跟原来的向量相加 因此 v 向量从 增至 我用了一个 length(v) 命令 因此这样一来 ones(length(v) ,1) 就相当于 ones(3,1) 所以这是ones(3,1) 对吧 然后我做的是 v + ones(3,1) 也就是将 v 的各元素 都加上这些1 这样就将 v 的每个元素 增加了1 另一种更简单的方法是 直接用 v+1 所以这是 v v + 1 也就等于 把 v 中的每一个元素 都加上1
>> v = [1;2;3] v = 1 2 3 >> v + ones(length(v), 1) ans = 2 3 4 >> v + ones(3,1) ans = 2 3 4 >> v + 1 ans = 2 3 4
现在 让我们来谈谈更多的操作 这是我的矩阵A 如果你想要求它的转置 那么方法是用A‘ 这是单引号符号 并且是左引号 可能你的键盘上 有一个左引号 和一个右引号 这里用的是左引号 也就是标准的引号 因此 A’ 将得出 A 的转置矩阵 当然 如果我写 (A‘)’ 也就是 A 转置两次 那么我又重新得到矩阵 A
>> A A = 1 2 3 4 5 6 >> A‘ ans = 1 3 5 2 4 6
还有一些有用的函数 假如说 小写a 是 这是一个1行4列矩阵 假如说 val=max(a) 这将返回 A矩阵中的最大值 在这里是15 我还可以写 = max(a) 这将返回 a矩阵中的最大值 存入val 以及该值对应的索引 因此元素15对应的索引值为2 存入ind 所以 ind 等于2
>> a = [1 15 2 0.5] a = 1.00000 15.00000 2.00000 0.50000 >> val = max(a) val = 15 >> [val, ind] = max(a) val = 15 ind = 2
特别注意一下 如果你用命令 max(A) A是一个矩阵的话 这样做就是对每一列 求最大值 等下再仔细讲讲
我们还是用这个例子 这个 小a 矩阵 如果输入 a<3 这将进行逐元素的运算 所以 第一个元素 是小于3的 因此返回1 a的第二个元素 不小于3 所以 这个值是0 表示"非" 第三个和第四个数字 仍然是小于3 2和0.5都小于3 因此 这返回 也就是说 对a矩阵的每一个元素 与3进行比较 然后根据每一个元素与3的大小关系 返回1和0表示真与假
现在 如果我写 find(a<3) 这将告诉我 a 中的哪些元素 是小于3的 是小于3的 在这里就是第一 第三和第四个元素 是小于3的
a = 1.00000 15.00000 2.00000 0.50000 >> a < 3 ans = 1 0 1 1 >> find(a < 3) ans = 1 3 4
下一个例子 设A = magic(3) magic 函数返回什么呢 让我们查看 magic 函数的帮助文件
magic 函数将返回 一个矩阵 称为魔方阵或幻方 (magic squares) 它们具有以下 这样的数学性质 它们所有的行和列和对角线 加起来都等于相同的值 当然据我所知 这在机器学习里 基本用不上 但我可以用这个方法 很方便地生成一个 3行3列的矩阵 而这个魔方矩阵这神奇的方形屏幕。 每一行 每一列 每一个对角线 三个数字加起来 都是等于同一个数 我只有在演示功能 或者上课教 Octave 的时候 会用到这个矩阵 在其他有用的机器学习应用中 这个矩阵其实没多大作用 让我来看看别的 如果我输入 = find( A>=7 ) 这将找出所有A矩阵中 大于等于7的元素 因此 r 和 c 分别表示行和列 这就表示 第一行第一列的元素大于等于7 第三行第二列的元素大于等于7 第二行第三列的元素大于等于7 我们来看看 第二行第三列的元素 就是 A(2,3) 是等于7的 就是这个元素 确实是大于等于7的 顺便说一句 其实我从来都 不去刻意记住这个 find 函数 到底是怎么用的 我只需要会用 help 函数就可以了 每当我在使用这个函数 忘记怎么用的时候 我就可以用 help 函数 键入 help find 来找到帮助文档
>> A = magic(3) A = 8 1 6 3 5 7 4 9 2 >> [r, c] = find(A >= 7) r = 1 3 2 c = 1 2 3
好吧 最后再讲两个内容 一个是求和函数 这是 a 矩阵 键入 sum(a) 就把 a 中所有元素加起来了 如果我想把它们都乘起来 键入 prod(a) prod 意思是 product(乘积) 它将返回 这四个元素的乘积 floor(a) 是向下四舍五入 因此对于 a 中的元素 0.5将被下舍入变成0 还有 ceil(A) 表示向上四舍五入 所以0.5将上舍入变为 最接近的整数 也就是1
>> a a = 1.00000 15.00000 2.00000 0.50000 >> sum(a) ans = 18.500 >> prod(a) ans = 15 >> floor(a) ans = 1 15 2 0 >> ceil(a) ans = 1 15 2 1
还有 我们来看 键入 type(3) 这通常得到一个3×3的矩阵 如果键入 max(rand(3), rand(3)) 这样做的结果是 返回两个3×3的随机矩阵 并且逐元素比较 取最大值 所以 你会发现所有这些 数字几乎都比较大 因为这里的每个元素 都实际上是 两个随机生成的矩阵 逐元素进行比较 取最大的那个值 这是刚才生成的 3×3魔方阵 A 假如我输入 max(A,[],1) 这样做会得到 每一列的最大值 所以第一例的最大值 就是8 第二列是9 第三列的最大值是7 这里的1表示 取A矩阵第一个维度的最大值 相对地 如果我键入 max(A,[],2) 这将得到每一行的最大值 所以 第一行的最大值 是等于8 第二行最大值是7 第三行是9 所以你可以用这个方法 来求得每一行或每一列的最值
>> max(rand(3), rand(3)) ans = 0.957477 0.083887 0.459507 0.799441 0.975439 0.927632 0.888604 0.942436 0.612661 >> A A = 8 1 6 3 5 7 4 9 2 >> max(A, [], 1) ans = 8 9 7
另外 你要知道 默认情况下 max(A)返回的是 每一列的最大值 如果你想要 找出整个矩阵A的最大值 你可以输入 max(max(A)) 像这样 或者你可以将 A 矩阵转成 一个向量 然后键入 max(A(:)) 这样做就是把 A 当做一个向量 并返回 A 向量中的最大值
>> max(max(A)) ans = 9 >> max(A(:)) ans = 9
最后 让我们把 A 设为一个 9行9列的魔方阵 别忘了 魔方阵具有的特性是 每行每列和对角线的求和都是相等的 这是一个9×9的魔方阵 我们来求一个 sum(A,1) 这样就得到每一列的总和 所以这样做就是 把 A 的每一列进行求和 从这里我们也可以看出 这也验证了 一个9×9的魔方阵 确实每一列加起来都相等 都为369 现在我们来求每一行的和 键入sum(A,2) 这样就得到了 A 中每一行的和 A 中每一行的和 加起来还是369
>> A = magic(5) A = 17 24 1 8 15 23 5 7 14 16 4 6 13 20 22 10 12 19 21 3 11 18 25 2 9 >> sum(A,1) ans = 65 65 65 65 65 >> sum(A,2) ans = 65 65 65 65 65
现在我们来算 A 的对角线元素的和 看看它们的和 是不是也相等 我们现在构造一个 9×9 的单位矩阵 键入 eye(9) 设为I9 然后我们要用 A 逐点乘以这个单位矩阵 这是矩阵A 我现在用 A 逐点乘以 eye(9) 这样做的结果是 两个矩阵对应元素 将进行相乘 除了对角线元素外 其他元素都会得到0 然后我对刚才求到的结果 键入sum(sum(A.*eye(9)) 这实际上是求得了 这个矩阵对角线元素的和 确实是369
>> sum(sum(A.*eye(5))) ans = 65
你也可以求另一条对角线的和 这个是从左上角到右下角的 你也可以求另一条对角线 从左下角到右上角 这个和 这个命令会有点麻烦 其实你不需要知道这个 我只是想给你看 如果你感兴趣的话可以听听 让我们来看看 flipup/flipud 表示向上/向下翻转 如果你用这个命令的话 计算的就是副对角线上 所有元素的和 还是会得到369 我来给你演示一下 eye(9) 矩阵是这样 那么 flipup(eye(9)) 将得到一个单位矩阵 并且将它翻转 不好意思打错了 应该是flipud 翻转以后所有的1就变成副对角线了
>> eye(9) ans = Diagonal Matrix 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 >> flipud(eye(9)) ans = Permutation Matrix 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
最后再说一个命令 然后就下课 假如 A 是一个 3×3的魔方阵 同样地 如果你想 这个矩阵的逆矩阵 键入 pinv(A) 通常称为伪逆矩阵 但这个名字不重要 你就把它看成是 矩阵 A 求逆 因此这就是 A 矩阵的逆矩阵 设 temp = pinv(A) 然后再用temp 乘以 A 这实际上得到的就是 单位矩阵 对角线为1 其他元素为0 稍微圆整一下就是 好了 这样我们就介绍了 如何对矩阵中的数字 进行各种操作
>> A = magic(3) A = 8 1 6 3 5 7 4 9 2 >> pinv(A) ans = 0.147222 -0.144444 0.063889 -0.061111 0.022222 0.105556 -0.019444 0.188889 -0.102778 >> temp = pinv(A) temp = 0.147222 -0.144444 0.063889 -0.061111 0.022222 0.105556 -0.019444 0.188889 -0.102778 >> temp * A ans = 1.00000 0.00000 -0.00000 -0.00000 1.00000 0.00000 0.00000 0.00000 1.00000
在运行完某个 学习算法之后 通常一件最有用的事情 是看看你的结果 或者说让你的结果可视化 在接下来的视频中 我会非常迅速地告诉你 如何很快地画出 如何只用一两行代码 你就可以快速地可视化你的数据 画出你的数据 这样你就能更好地理解 你使用的学习算法