【機器學習python教程】【1】向量、矩陣

1.0 Numpy 介紹

numpy是python機器學習的基礎,因爲它能夠對機器學習中經常處理的向量、矩陣、張量、等數據結構進行有效快速的處理

1.1 聲明向量

# 導入包
import numpy as np
# 行向量
v_row = np.array([1,2,3])
# 列向量
v_column = np.array([[1],
                    [2],
                    [3]])

numpy的主要數據結構就是多維數組,創建向量就是在創建一維數組

1.2 創建矩陣

m = np.matrix([[1,2],
              [2,3],
              [3,4]])
matrix = np.array([[1,2],
                  [2,3],
                  [3,4]])

numpy中有兩種創建矩陣的方法,但實際上我們更傾向於使用array方法,理由如下:
1、數組是numpy事實上的標準數據結構。
2、絕大多數numpy操作返回的是數組,而不是矩陣對象。

1.3 創建稀疏矩陣

# 導入需要的包
import numpy as np
from scipy import sparse
# 創建矩陣並稀疏化
mt = np.array([[1,0,1],
              [0,1,0],
              [4,0,2]])
mt_sparse = sparse.csr_matrix(mt)

# 打印查看
print(mt)
print(mt_sparse)
[[1 0 1]
 [0 1 0]
 [4 0 2]]
  (0, 0)	1
  (0, 2)	1
  (1, 1)	1
  (2, 0)	4
  (2, 2)	2

可以看出稀疏化之後只儲存了非零的值,大大壓縮了存儲空間。在機器學習中,我們遇到地大多數矩陣都有很多0元素,例如有一個矩陣,它的行向量代表清華大學的每一門課,列向量代表清華的每一個學生,因爲大多數學生都只選了自己專業的一小部分課程,所以這個龐大的矩陣中會含有相當多的0元素。

csr_matrix函數(compressed sparse row)壓縮稀疏行
即使我們在矩陣中填入更多的0擴展矩陣的行和列,都不會改變該矩陣的存儲大小。

有許多不同類型的稀疏矩陣,如壓縮稀疏列、列表列表和鍵字典。雖然對不同類型及其含義的解釋超出了本書的範圍,但值得注意的是,雖然沒有“最佳”的稀疏矩陣類型,但它們之間存在有意義的區別,我們應該意識到爲什麼我們選擇一種類型而不是另一種類型。

1.4 進行元素的選擇

注意,就像在python絕大多數包中的那樣,numpy也是零索引的(zero-indexed),即從0開始索引:

v_row = np.array([1,2,3])
v_row[2]
3

matrix = np.array([[1,2],
                  [2,3],
                  [3,4]])
matrix[1,1]
3

numpy中的切片選擇操作是前開後閉

v_row = np.array([1,2,3,4,5,6,7])

# 選擇所有元素
print(v_row[:])
# 選擇從第一個元素開始到第二個元素的所有元素
print(v_row[:2])
# 選擇第六個元素之後的所有元素
print(v_row[6:])
# 選擇倒數第二個元素
print(v_row[-2])

[1 2 3 4 5 6 7]
[1 2]
[7]
6

1.5 矩陣的描述

numpy中有可以描述矩陣行列數、元素數、以及維數(即矩陣的秩)的函數

m = np.matrix([[1,2,3,4],
              [5,6,7,8],
              [9,10,11,12]])
# 行列數
print(m.shape)
# 大小
print(m.size)
# 矩陣的秩
print(m.ndim)

(3, 4)
12
2

如圖,原矩陣可以化爲如圖所示的階梯形矩陣,即矩陣的秩爲2
在這裏插入圖片描述

1.6 對元素進行操作

這裏涉及到一個可以將函數向量化的vectorize函數,NumPy的vectorize類將函數轉換爲可以應用於數組或數組切片中的所有元素的函數,詳細文檔請看vectorize

m = np.matrix([[1,2,3,4],
              [5,6,7,8],
              [9,10,11,12]])
fun = lambda i : i ** 2

fun_square = np.vectorize(fun)
fun_square(m)

matrix([[  1,   4,   9,  16],
        [ 25,  36,  49,  64],
        [ 81, 100, 121, 144]])

這裏的fun函數使用lambda表達式定義了一個函數,vectorize將它向量化使其作用於每一個矩陣元素

而且,NumPy數組允許我們在數組之間執行操作,即使它們的維數不相同(這個過程稱爲行列擴充)。例如,我們可以創建一個更簡單的版本,實現矩陣和整數之間的 運算

m+100

matrix([[101, 102, 103, 104],
        [105, 106, 107, 108],
        [109, 110, 111, 112]])

1.7 找出最大最小值

np.max(m)
np.min(m)

很簡單吧,但是有時候我們會想知道每一行或者每一列的最大值最小值:

m = np.matrix([[1,2,3,4],
              [5,6,7,8],
              [9,1,11,12]])
# 輸出每一列最大的數的集合
print(np.max(m,axis=0))
#輸出每一行最小數的集合
print(np.min(m,axis=1))

[[ 9 6 11 12]]
[[1]
[5]
[1]]

如上所示,求出了每一行每一列的極值整合輸出

1.8 計算平均值、方差、標準差

matrix([[ 1,  2,  3,  4],
        [ 5,  6,  7,  8],
        [ 9,  1, 11, 12]])
# 平均值
print(np.mean(m))
# 方差
print(np.var(m))
# 標準差
print(np.std(m))

5.75
12.854166666666666
3.5852707940498254

就像求極值一樣,我們也可以對整行或者整列進行計算

# 每列的平均值
print(np.mean(m,axis=0))
# 每行的方差
print(np.var(m,axis=1))

[[5. 3. 7. 8.]]
[[ 1.25  ]
 [ 1.25  ]
 [18.6875]]

1.9 修改矩陣的行列(重塑)reshape

matrix([[ 1,  2,  3,  4],
        [ 5,  6,  7,  8],
        [ 9,  1, 11, 12]])
# 重塑爲2x6
m.reshape(2,6)
matrix([[ 1,  2,  3,  4,  5,  6],
        [ 7,  8,  9,  1, 11, 12]])
# -1這個參數以爲儘可能多,所以下面意爲儘可能多的行,一列
m.reshape(-1,1)
matrix([[ 1],
        [ 2],
        [ 3],
        [ 4],
        [ 5],
        [ 6],
        [ 7],
        [ 8],
        [ 9],
        [ 1],
        [11],
        [12]])

1.10 轉置向量和矩陣

matrix([[ 1,  2,  3,  4],
        [ 5,  6,  7,  8],
        [ 9,  1, 11, 12]])
m.T
matrix([[ 1,  5,  9],
        [ 2,  6,  1],
        [ 3,  7, 11],
        [ 4,  8, 12]])

轉置是線性代數中一種常見的操作,它交換每個元素的行和列的索引。在線性代數課程之外,一個微妙的問題通常會被忽視,那就是,從技術上講,一個向量不能被置換,因爲它只是一個值的集合:

# Transpose vector np.array([1, 2, 3, 4, 5, 6]).T
array([1, 2, 3, 4, 5, 6])

然而,通常把轉置一個向量稱爲把一個行向量轉換成一個列向量(注意第二對括號),反之亦然:

# Tranpose row vector 
np.array([[1, 2, 3, 4, 5, 6]]).T
array([[1], 
[2], 
[3],
[4],
[5],
[6]]) 

1.11 壓縮矩陣

matrix([[ 1,  2,  3,  4],
        [ 5,  6,  7,  8],
        [ 9,  1, 11, 12]])
m.flatten()
matrix([[ 1,  2,  3,  4,  5,  6,  7,  8,  9,  1, 11, 12]])

同樣的,我們可以使用reshape方法m.reshape(1,-1)來完成這項工作

1.12 求矩陣的秩

np.linalg.matrix_rank(m)
3

這個函數讓求矩陣的秩非常簡單

1.13 計算行列式

m = np.array([[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9]])
np.linalg.det(m)
0.0

1.14 求主對角線的元素

m = np.array([[ 1,  2,  3],
              [ 4,  5,  6],
              [ 7,  8,  9]])
# 主對角線元素
m.diagonal()
array([1, 5, 9])
# 右上一位對角元素
m.diagonal(offset=1)
array([2, 6])
# 左下一位對角元素
m.diagonal(offset = -1)
array([4, 8])

diagonal函數中的offset參數可以從主對角線向右上或左下移動對應的數值

1.15 計算矩陣的跡

m = np.array([[ 1,  2,  3],
              [ 4,  5,  6],
              [ 7,  8,  9]])
m.trace()

15
# 或者可以使用對角元素的和
sum(m.diagonal())

1.16 尋找特徵值和特徵向量

m = np.array([[ 1,  2,  3],
              [ 3,  5,  6],
              [ 7,  8,  2]])
eigenvalues,eigenvectors=np.linalg.eig(m)

print(eigenvalues)
print(eigenvectors)
[12.6069345  -0.01728267 -4.58965183]
[[-0.29252753 -0.70944096 -0.298811  ]
 [-0.66066352  0.67328277 -0.43724833]
 [-0.69134026 -0.20828785  0.84824871]]

1.17 計算點積

a = np.array([1,2,3])
b = np.array([1,2,3])
np.dot(a,b)

14

點積是每個向量中的元素對應相乘再相加

在Python3.5+中,我們還可以這樣計算點積

a @ b
14

1.18 矩陣的加減法

a = np.array([[1,2,3],
             [5,2,1],
             [9,5,7]])
b = np.array([[1,4,3],
             [5,7,1],
             [9,2,7]])
np.add(a,b)
array([[ 2,  6,  6],
       [10,  9,  2],
       [18,  7, 14]])

np.subtract(a,b)
array([[ 0, -2,  0],
       [ 0, -5,  0],
       [ 0,  3,  0]])

實際上,我們還可以使用直接的+ -號來實現

1.19 矩陣相乘

# 矩陣中元素逐個相乘
print(a*b)
# 矩陣相乘的兩種方式
print(a @ b)
print(np.dot(a,b))

[[ 1  8  9]
 [25 14  1]
 [81 10 49]]
 
[[38 24 26]
 [24 36 24]
 [97 85 81]]
 
[[38 24 26]
 [24 36 24]
 [97 85 81]]

1.20 矩陣求逆

a = np.array([[1,2,3],
             [5,2,1],
             [9,5,7]])
np.linalg.inv(a)
array([[-0.40909091, -0.04545455,  0.18181818],
       [ 1.18181818,  0.90909091, -0.63636364],
       [-0.31818182, -0.59090909,  0.36363636]])

矩陣與其逆矩陣的乘積爲單位矩陣
AA1=IAA^{-1} = I

我們來驗證一下

a @ np.linalg.inv(a)
array([[ 1.00000000e+00, -1.11022302e-16,  0.00000000e+00],
       [-1.11022302e-16,  1.00000000e+00,  0.00000000e+00],
       [ 1.11022302e-16, -1.11022302e-16,  1.00000000e+00]])

1.11022302e-16可以近似爲0

1.21 生成隨機值

和C++一樣,python在生成隨機值之前也需要設置種子

np.random.seed(100)
np.random.random(3)
array([0.54340494, 0.27836939, 0.42451759])
# 0-1整數
np.random.randint(1,10,3)
array([1, 5, 3])
# 以正態分佈平均值爲5,標準差爲2
np.random.normal(5,2,3)
array([0.54340494, 0.27836939, 0.42451759])
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章