使用Octave來學習Machine Learning(二)

WeaponZhi發表於2019-02-27

小之的公眾號 : WeaponZhi

前言

上一篇我們介紹了 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 的平方,很有趣吧。

矩陣的操作

講述矩陣的操作之前,讓我們先來定義一個 3×2 的矩陣 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 的下面。

使用Octave來學習Machine Learning(二)

矩陣的運算

這節將講一些矩陣運算的操作,涉及到一些線代的知識,如果有疑惑,可以自己去重溫下,你大概只要知道矩陣相乘和逆矩陣是怎麼一回事就行了。先來看一段程式碼

>> 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
複製程式碼

除數必須得是 1×1 的矩陣或者是個數,總而言之它這是真正的算數除法運算了。

當然還有一些對元素做操作的運算,比如 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來學習Machine Learning(二)

總結

Octave 矩陣方面的介紹就這麼多了,寫的很多,權當一個筆記吧,實際上還有很多操作,大家可以使用 help 指令或者觀看官方文件來進行學習。


歡迎關注我的公眾號

使用Octave來學習Machine Learning(二)

相關文章