使用Octave来学习Machine Learning(二)

前言

上一篇我们介绍了 Octave 的一些基本情况,大家对 Octave 应该已经有了一个基本的了解,我相信看这篇文章的朋友已经在自己的电脑中安装好 Ocatve 了。矩阵的操作是 Octave 的一大特色。这一节,我将讲述 Octave 对于矩阵的一些操作,希望大家在看文章的过程中可以跟着一起敲一下代码,加深一下印象。

矩阵的生成

Octave 中,我们用一个中括号来表示一个矩阵,用分号来分隔每一行,即使在输入的时候不在同一行就像下面这样:

>> 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

>> A = [1,2; 3,4; 5,6]
A = 
   1  2
   3  4
   5  6

注意到,你可以通过逗号来区分每行中的每一个元素,但我们一般不这样用,这样看起来不太清晰。那么如果要表示向量该怎么做呢?我们知道,行向量和列向量分别是一行三列和三行一列的矩阵,那举一反三的你一定知道该怎么定义了吧?

>> A = [1 2 3]
A = 
    1  2  3

>> A = [1; 2; 3]
A = 
    1
    2
    3

可以通过冒号来实现具有递进规则的行向量,两个冒号之间的数代表递进的 step 大小,很容易理解,和 Python 的操作有点像。

>> A = 1:0.1:1.5
A = 
   1.0000 1.1000 1.2000 1.3000 1.4000 1.5000

>> A = 1:5
A = 
   1 2 3 4 5

通过一些函数可以快速生成一些特殊矩阵

>> ones(2,3)
ans = 
    1 1 1
    1 1 1

>> 2*ones(2,3)
ans = 
    2 2 2
    2 2 2

>> zeros(2,3)
ans = 
    0 0 0
    0 0 0

>> eye(3)
ans = 
Diagonal Matrix
    1 0 0
    0 1 0
    0 0 1

>> rand(2,3)
ans = 
    0.480397 0.505024 0.056767
    0.336853 0.774152 0.535887

>> magic(3)
ans = 
    8 1 6
    3 5 7
    4 9 2

ones() 生成全是 1 的矩阵,你可以使用数字和 ones() 生成的矩阵相乘,它和 zeros() 还有 rand() 一样,第一个参数代表行数,第二个参数代表列数。zeros() 生成元素全是 0 的矩阵,而 rand() 可以生成元素是 0-1 之间随机数的矩阵。eye()可以生成单位矩阵,熟悉线性代数的朋友可能会对单位矩阵比较熟悉,它很有用,但线性代数的知识不是本文的重点。形式上可以理解为正斜对角线都是 1 的矩阵。

magic(n) 生成一个 n 阶矩阵,这个矩阵的特点就是不论横线,竖线还是对角线,加起来的值都是一样的,数字还不能重复,必须是从 1 到 n 的平方,很有趣吧。

矩阵的操作

讲述矩阵的操作之前,让我们先来定义一个 3x2 的矩阵 A,方便我们理解代码

>> A = [1 2; 3 4; 5 6]
A = 
   1 2
   3 4
   5 6

我们可以通过 size 和 length 函数来获取矩阵维度的相关信息

>> size(A)
ans = 
     3 2

>> size(A,1)
ans = 3

>> size(A,2)
ans = 2

>> length(A)
ans = 3

size(A) 返回一个行向量,这个行向量代表了 A 的维度,这里输出的 3 2 代表 A 是一个 3 行 2 列的矩阵。size()还可以添加第二个参数,size(A,1) 输出 A 的第一个维度的数量,也就是行数,2 代表的是列数。length(A) 返回的是 A 矩阵中最大维度的大小,所以这里返回的是 A 的行数 3,一般我们都是对向量使用 length() 来直接返回向量的长度。

我们来看看对于矩阵的各种读取操作吧。

>> A(3,2)
ans = 6

>> A(:)
ans =
     1
     2
     3
     4
     5
     6

>> A(1:6)
ans =
     1 3 5 2 4 6

A(3,2) 代表取 A 矩阵第三行第二列的元素,这个比较好理解。A(:) 会将矩阵转化为一个列向量,A(1:6) 将按列顺序输出 A 矩阵第 1 到 第 6 个元素。这些都还是比较简单的,后两个往往在求和的时候用的比较多,我们后面会说到。

我们来看一波天秀操作

>> A(:,2)
ans = 
     2
     4
     6

>> A(2,:)
ans = 
     3 4

>> A([2,3],:)
ans = 
     3 4
     5 6

>> A(:,2) = [1; 3; 5]
A = 
    1 1
    3 3
    5 5

>> A = [A,[1; 2; 3]]
A = 
    1 1 1 
    3 3 2
    5 5 3 

>> B = 5*ones(3)
B = 
    5 5 5
    5 5 5 
    5 5 5

>> [A B] % [A,B] % 号是注释
ans = 
     1 1 1 5 5 5 
     3 3 2 5 5 5
     5 5 3 5 5 5

>> [A; B]
ans = 
     1 1 1
     3 3 2
     5 5 3
     5 5 5 
     5 5 5

来,我们一点点看。A(:,2) 输出 A 的第二列,A(2,:) 输出 A 的第二行,A([2,3],:) 输出第二行和第三行,你可以把冒号换成数字这样就可以输出这几行的第几个元素了。A(:,2) = [1; 3; 5] 将 A 的第二列替换成 [1; 3; 5] 这个列向量。[A B] 和 [A, B] 的含义一样,将 B 并到 A 的右边。[A; B] 则是把 B 并到 A 的下面。

矩阵的运算

这节将讲一些矩阵运算的操作,涉及到一些线代的知识,如果有疑惑,可以自己去重温下,你大概只要知道矩阵相乘和逆矩阵是怎么一回事就行了。先来看一段代码

>> A = [1 2; 3 4; 5 6];
>> B = [1 1 1;2 2 2;];
>> C = [11 12; 13 14; 15 16];

>> A * B
ans =
      5  5  5
      11 11 11
      17 17 17

>> A .* C
ans = 
      11 24
      39 56
      75 96

我们先定义了三个矩阵,还记得吗,末尾加分号将不会打印出来。A * B 代表矩阵 A 和 B 的乘积,这是数学上的乘积方式,所以一个三行两列的矩阵乘以两行三列的矩阵,将得到一个三行三列的矩阵,这里就不具体说乘积运算的规则了。A .* C 会将 A 和 C 的同位置元素相乘,这就代表了 A 和 C 的维度必须要一样。

我们来看下矩阵和数字的操作

>> A + 1
ans =
     2   3
     4   5
     5   6

>> A * 2
ans = 
     2   4
     6   8
     10 12

>> A .^ 2
ans = 
      1  4
      9 16
     25 36

>> A / 2
ans = 
     0.50000 1.00000
     1.50000 2.00000
     2.50000 3.00000

>> 1 ./ A
ans = 
     1.00000 0.50000
     0.33333 0.25000
     0.20000 0.16667

A+1 将每个元素作加法,A * 2 把 A 中每个元素都乘以 2,当然 2 * A 也可以,结果一致,我们在上面曾经使用 5 * ones(3) 来快速生成三阶全是 5 的矩阵。A .^ 2 代表对 A 每个元素进行次方操作。A / 和 ./ 含义是一样的,但 1 / A 将会报错

>> 1 / A
error:operator /:nonconformat arguments

>> 1 / [2]
ans = 0.50000

>> 1 / 2
ans = 0.50000

除数必须得是 1x1 的矩阵或者是个数,总而言之它这是真正的算数除法运算了。

当然还有一些对元素做操作的运算,比如 log(A) 是每个元素求对数,exp(A) 是对每个元素求 e 的指数,abs(A) 是求绝对值,当然还有很多,就不一一列举了。大家可以通过 help 指令直接进行文档查阅。

下面看看转置矩阵和逆矩阵如何表示

>> A'
ans = 
     1 3 5
     2 4 6

>> (A')'
ans =
     1 2
     3 4
     5 6

>> flipud(A)
ans = 
     5 6
     3 4
     1 2

>> B = pinv(A)
B =
     -1.33333 -0.33333  0.66667
      1.08333  0.33333 -0.41667

>> A * B   % B * A
ans = 
     1.00000 0.00000
    -0.00000 1.00000

用单引号 ' 来表示矩阵的转置矩阵。flipud(A) 将矩阵翻转,这个函数一般用在翻转范围矩阵 flipud(eye(n)) ,这样就可以获得一个反对角线单位矩阵了。

pinv(A) 表示 A 的逆矩阵,逆矩阵和原矩阵相乘是单位矩阵,值得注意的是,不是每一个矩阵都有逆矩阵,但 pinv() 始终都能得到结果,实际上 pinv() 获取的是一个伪逆矩阵,但这不重要,你可以把 pinv() 当作对矩阵的求逆,这里就不具体深究了。

到目前为止,矩阵的运算还是比较简单的,相比起来,下面的运算就有点蒂花之秀了。

>> max(A)
ans =
      5 6

>> max(A,[],1)
ans = 
      5 6
     
>> max(A,[],2)
ans =
      2
      4
      6
 
>> [val, ind] = max(A)
val = 
      5 6
ind = 
      3 3

>> max(A,[3 3; 3 3; 3 3])
ans =
     3 3
     3 4
     5 6

>> A > 3
ans =
      0 0
      0 1
      1 1

>> find([1 2 3] > 1)
ans = 
      2 3

>> [r,c] = find(A > 3)
r = 
    3
    2 
    3

c = 
    1
    2
    2

max(A) 将求每列的最大值,并以行向量形式输出,默认形式等同于 max(A,[],1),如果求每列最大值,则把第三个参数改为2。用 [val, ind] 接收的话,val 的值为最大值,ind 为这个值在该列的索引位置。max(A,B) 将取每个位置中 A 与 B 较大的元素。min 和 max 操作是一样的。

A > 3 输出一个同维度的矩阵,符合条件的为 1 ,不符合条件的为 0。find() 函数中如果是一个向量,则返回符合条件的索引位置,如果是一个矩阵,则用 [r,c] 返回元素的索引,r 代表行号,c 代表列号,比如例子中第一个匹配值 A(3,1) 是 5 ,的确大于 3。

最后看下求和

>> sum(A,1)
ans = 
      9 12

>> sum(A,2)
ans = 
       3
       7
      11

>> sum(sum(A))
ans = 21

sum 和 max 一样,默认情况下是列运算,行向量输出,但参数设置为 2 的时候,则是行求和,列向量输出。所以就像例子中一样,如果我们要求一个矩阵所有元素的和,只需要做两次 sum(sum(A)) 即可。

总结

Octave 矩阵方面的介绍就这么多了,写的很多,权当一个笔记吧,实际上还有很多操作,大家可以使用 help 指令或者观看官方文档来进行学习。

原文发布于微信公众号 - WeaponZhi(WeaponZhi)

原文发表时间:2017-12-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏人工智能

Tensorflow下Char-RNN项目代码详解

前言 Char-RNN,字符级循环神经网络,出自于Andrej Karpathy写的The Unreasonable Effectiveness of Recu...

4409
来自专栏C语言及其他语言

【优秀题解】1175:台球碰撞

题号1174,原题见下图: ? 解题思路: 解题思路: 把台球看做质点(台球坐标不变,球桌坐标各个边界向里收缩R,得到新的球桌); 假设没边界,求出小球沿着直...

2566
来自专栏钱塘大数据

R语言的常用函数速查

一、基本 1.数据管理 vector:向量 numeric:数值型向量 logical:逻辑型向量character;字符型向量 list:列表 data....

2749
来自专栏向治洪

java解决hash算法冲突

看了ConcurrentHashMap的实现, 使用的是拉链法. 虽然我们不希望发生冲突,但实际上发生冲突的可能性仍是存在的。当关键字值域远大于哈希表的长度...

1989
来自专栏Bay的专栏

如何使用 scikit-learn 为机器学习准备文本数据

文本数据需要特殊处理,然后才能开始将其用于预测建模。

2105
来自专栏人工智能

如何使用 scikit-learn 为机器学习准备文本数据

文本数据需要特殊处理,然后才能开始将其用于预测建模。

6568
来自专栏懒人开发

(2.4)James Stewart Calculus 5th Edition: The Precise Definition of a Limit

后面是 经典的叙述(记得大学,epsilon【ε】,delta【δ】 这段话都快背疯了)

722
来自专栏数据结构与算法

T4701 【卜卜】树状数组模板

题目描述 在二维平面内给定n个点: 0 x y v表示给(x,y)的权值减去v 1 x y v表示给(x,y)的权值加上v 然后有m个操作 0 x y v ,...

2647
来自专栏Golang语言社区

【Go 语言社区】 golang 算法课程 第一季 第2节 洗牌算法

扑克牌洗牌是我们生活中比较喜欢玩的一个游戏。那么我们有没有什么办法自己设计一个扑克牌洗牌的方法呢?在运行库当中有一个随机函数rand,它可以生成0~32767之...

3837
来自专栏racaljk

Leetcode 566. Reshape the Matrix 矩阵变形(数组,模拟,矩阵操作)

在MATLAB中,reshape是一个非常有用的函数,它可以将矩阵变为另一种形状且保持数据不变。 已知一个由二维数组表示的矩阵,和两个正整数r(行),c(列)...

502

扫描关注云+社区