本文的主要學習目標:
- 熟練的掌握 numpy 數組相關的運算;
- 熟練的使用 numpy 創建矩陣;
- 理解矩陣轉置和乘法;
- 熟練的計算數據的相關系數、方差、協方差、標準差;
- 理解并能夠計算特征值與特征向量;
- 理解可逆矩陣并能夠計算矩陣的逆;
- 熟練求解線性方程組;
- 熟練計算向量和矩陣的范數;
- 理解并計算奇異值分解;
numpy 數組及運算
擴展庫 numpy 是 Python 支持科學計算的重要擴展庫,是數據分析和科學計算領域如 scipy、pandas、sklearn 等眾多擴展庫中必備的擴展庫之一,提供了強大的 N 維數組及其相關的運算、復雜的廣播函數、C/C++和Fortran代碼集成工具以及線性代數、傅里葉變換和隨機數生成等功能。本次重點講解數組和矩陣及其相關的運算。
創建數組
數組是用來存儲若干數據的連續內存空間,其中的元素一般是相同類型的,例如都是浮點數。數組運算是學習數據分析和機器學習相關算法的重要基礎。在我們處理實際數據的時候,總會用到大量的數組運算或者矩陣的運算,這些數據有的是通過文件直接讀取的,有的則是根據實際需要生成的,當然還有些數據是實時采集的。
import numpy as np
np.array([1, 2, 3, 4, 5])
# -> array([1, 2, 3, 4, 5])
np.array(range(5))
# -> array([0, 1, 2, 3, 4])
np.array([1, 2, 3],[4, 5, 6])
# -> array([[1, 2, 3],
# [4, 5, 6]])
np.arange(5)
#-> array([0, 1, 2, 3, 4])
np.arange(1, 10, 2)
#-> array([1, 3, 5, 7, 9])
np.linspace(0, 10, 11)
#-> array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.])
np.linspace(0, 10, 11, endpoint=False)
#-> array([0. , 0.90909091, 1.81818182, 2.72727273, 3.63636364,
# 4.54545455, 5.45454545, 6.36363636, 7.27272727, 8.18181818,
# 9.09090909])
np.logspace(0, 100, 10)
#-> array([1.00000000e+000, 1.29154967e+011, 1.66810054e+022, 2.15443469e+033,
# 2.78255940e+044, 3.59381366e+055, 4.64158883e+066, 5.99484250e+077,
# 7.74263683e+088, 1.00000000e+100])
np.logspace(1, 6, 5, base=2)
#-> array([ 2. , 4.75682846, 11.3137085 , 26.90868529, 64. ])
np.zeros(3)
#-> array([0., 0., 0.])
np.ones(3)
#-> array([1., 1., 1.])
np.zeros((3, 3))
#-> array([[0., 0., 0.],
# [0., 0., 0.],
# [0., 0., 0.]])
np.ones((3, 3))
#-> array([[1., 1., 1.],
# [1., 1., 1.],
# [1., 1., 1.]])
np.identity(3)
#-> array([[1., 0., 0.],
# [0., 1., 0.],
# [0., 0., 1.]])
np.empty((3, 3))
#-> array([[1., 0., 0.],
# [0., 1., 0.],
# [0., 0., 1.]])
np.hamming(20)
#-> array([0.08 , 0.10492407, 0.17699537, 0.28840385, 0.42707668,
# 0.5779865 , 0.7247799 , 0.85154952, 0.94455793, 0.9937262 ,
# 0.9937262 , 0.94455793, 0.85154952, 0.7247799 , 0.5779865 ,
# 0.42707668, 0.28840385, 0.17699537, 0.10492407, 0.08 ])
np.blackman(20)
#-> array([-1.38777878e-17, 1.02226199e-02, 4.50685843e-02, 1.14390287e-01,
# 2.26899356e-01, 3.82380768e-01, 5.66665187e-01, 7.52034438e-01,
# 9.03492728e-01, 9.88846031e-01, 9.88846031e-01, 9.03492728e-01,
# 7.52034438e-01, 5.66665187e-01, 3.82380768e-01, 2.26899356e-01,
# 1.14390287e-01, 4.50685843e-02, 1.02226199e-02, -1.38777878e-17])
np.kaiser(12, 5)
#-> array([0.03671089, 0.16199525, 0.36683806, 0.61609304, 0.84458838,
# 0.98167828, 0.98167828, 0.84458838, 0.61609304, 0.36683806,
# 0.16199525, 0.03671089])
np.random.randint(0, 50, 5)
#-> array([ 6, 43, 33, 11, 5])
np.random.randint(0, 50, (3,5))
#-> array([[45, 30, 17, 31, 25],
# [11, 32, 47, 48, 5],
# [22, 29, 3, 9, 28]])
np.random.rand(10)
#-> array([0.53459796, 0.59163821, 0.11611952, 0.68199147, 0.03725451,
# 0.57498382, 0.15140171, 0.33914725, 0.90706282, 0.68518446])
np.random.standard_normal(5)
#-> array([-0.62939386, -0.16023864, 1.67463293, -0.44869975, 0.97008488])
np.random.standard_normal(size=(3, 4, 2))
#-> array([[[-0.7924237 , -2.02222271],
# [-0.7360387 , -1.88832641],
# [-0.43188511, -0.40672139],
# [ 2.03058394, 1.007505 ]],
#
# [[ 0.35664297, 1.9308035 ],
# [ 0.56456596, -1.02357394],
# [ 1.45042549, -0.59816538],
# [-0.00659242, 0.15439743]],
#
# [[-1.31088702, -0.167339 ],
# [ 0.44439704, 0.00819551],
# [-2.39637084, -0.07890167],
# [ 0.53474018, 1.18425122]]])
np.diag([1, 2, 3, 4])
#-> array([[1, 0, 0, 0],
# [0, 2, 0, 0],
# [0, 0, 3, 0],
# [0, 0, 0, 4]])
測試兩個數組的對應元素是否足夠接近
擴展庫 numpy 提供了 isclose() 和 allclose() 函數來測試兩個數組中對應位置的元素在允許誤差的范圍內是否相等,并可以接收絕對誤差參數和相對誤差參數.isclose()函數用來測試每一對元素是否相等并返回包含若干個 True/False 的列表。
isclose(a, b, rtol=le-05, atol=le-08, equal_man=False)
1
allclose()函數用來測試所有對應位置上的元素是否都相等并返回單個的True/False。
allclose(a, b, rtol=le-05, atol=le-08, equal_man=False)
1
下面以代碼為例子講解用法:
import numpy as np
x = np.array([1, 2, 3, 4.0001, 5])
y = np.array([1, 1.999, 3, 4.01, 5.1])
np.allclose(x, y)
#-> False
np.allclose(x, y, rtol=0.2)
#-> True
np.allclose(x, y, atol=0.2)
#-> True
np.isclose(x, y)
#-> [True False True False False]
np.isclose(x, y, atol=0.2)
#-> [True True True True True]
修改數組中的元素值
擴展庫 numpy 支持多種方式修改數組中元素的值,既可以使用 Append()、insert() 函數在原數組的基礎上追加或插入元素并返回新數組,也可以使用下標的方式直接修改數組中一個或多個元素的值。
import numpy as np
x = np.arange(8)
print(x)
#-> array([0, 1, 2, 3, 4, 5, 6, 7])
np.append(x, 8)
#-> array([0, 1, 2, 3, 4, 5, 6, 7, 8])
np.append(x, [9, 10])
#-> array([0, 1, 2, 3, 4, 5, 6, 7, 9, 10])
np.insert(x, 1, 8)
#-> array([0, 8 ,1, 2, 3, 4, 5, 6, 7])
print(x)
#-> array([0, 1, 2, 3, 4, 5, 6, 7])
x[3] = 8
print(x)
#-> array([0, 1, 2, 8, 4, 5, 6, 7])
x = np.array([[1, 2, 3],[4, 5, 6]])
x[0, 2] = 4
x[1:, 1:] = 1
print(x)
#-> array([[1, 2, 4],
# [4, 1, 1]])
x[1:, 1:] = [1, 2]
print(x)
#-> array([[1, 2, 4],
# [4, 1, 2]])
數組與標量的運算
擴展庫 numpy 中的數組支持加減乘除冪運算等操作,計算結果為一個新的數組,其中每個元素為標量與原數組中每個元素進行計算的結果。使用時需要注意的是標量在前和在后的時候計算結果是截然不同的。
import numpy as np
x = np.array([1, 2, 3, 4, 5])
print(x)
#-> array([1, 2, 3, 4, 5])
print(x * 2)
#-> array([ 2, 4, 6, 8, 10])
print(x / 2)
#-> array([0.5, 1. , 1.5, 2. , 2.5])
print(x // 2)
#-> array([0, 1, 1, 2, 2], dtype=int32)
print(x ** 2)
#-> array([ 1, 4, 9, 16, 25], dtype=int32)
print(2 ** x)
#-> array([ 2, 4, 8, 16, 32], dtype=int32)
print(63 // x)
#-> array([63, 31, 21, 15, 12], dtype=int32)
數組與數組的運算
對兩個等長數組進行算數運算后,得到一個新的數組,其中每個元素的值為原來的兩個數組上對應的位置上的元素進行算數運算的結果。當數組大小不一樣時,如果符合廣播要求則進行廣播,否則就報錯并結束運行。
import numpy as np
np.array([1, 2, 3, 4]) + np.array([5, 6, 7, 8])
#-> array([ 6, 8, 10, 12])
np.array([1, 2, 3, 4]) + np.array([4])
#_> array([5, 6, 7, 8])
a = np.array([1, 2, 3])
print(a + a)
#-> array([2, 4, 6])
print(a * a)
#-> array([1, 4, 9])
print(a / a)
#-> array([1, 1, 1])
b = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])
print(a * b)
#-> array([[ 1, 4, 9],
# [ 4, 10, 18],
# [ 7, 16, 27]])
數組排序
擴展庫 numpy 的 argsort() 函數用來返回一個數組,其中的每個元素為原數組中元素的索引,表示應該把原數組中哪個位置的元素放到這個位置上面。另外, numpy 還提供了argmax() 函數和argmin() 函數,分布用來返回數組最大元素和最小元素的下標,而數組本身也提供了原地排序的方法 sort()。
import numpy as np
x = np.array([3, 1, 2])
np.argsort(x)
#-> array([1, 2, 0], dtype=int64)
x[_]
#-> array([1, 2, 3])
x.argmax(), x.argmin()
#-> (0, 1)
x.sort()
print(x)
#-> array([1, 2, 3])
x = np.random.randint(1, 10, (2, 5))
print(x)
#-> array([[2, 3, 6, 2, 3],
# [1, 9, 7, 5, 3]])
x.sort(axis = 1)
print(x)
#-> array([[2, 2, 3, 3, 6],
# [1, 3, 5, 7, 9]])
數據的內積運算
對于兩個等長的數組 x 和 y ,其內積為兩數組中對應的位置的元素乘積之和,計算公式如下:x*y = ∑ni=1sum_{i=1}^n∑i=1nxiyi擴展庫 numpy 提供了 dot() 函數用來計算兩個數組的內積,擴展庫 numpy 中的數組也提供了 dot() 方法方法來計算另一個數組的內積,也可以借用內置 sum() 函數來計算兩個數組的內積。
import numpy as np
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])
print(np.dot(x, y))
#-> 32
print(x.dot(y))
#-> 32
print(sum(x*y))
#-> 32
訪問數組中的元素
用戶可以使用下標和切片的方法來訪問數組中的某個或多個元素,形式非常靈活。
import numpy as np
b = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])
print(b)
#-> array([[1, 2, 3],
# [4, 5, 6],
# [7, 8, 9]])
print(b[0][0])
#-> 1
print(b[0,2])
#-> 3
print(b[[0, 1]])
#-> array([[1, 2, 3],
# [4, 5, 6]])
print(b[[0, 2, 1],[2, 1, 0]])
#-> array([3, 8, 4])
a = np.arange(10)
print(a)
#-> array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
print(a[::-1])
#-> array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
c = np.arange(25)
c.shape = 5, 5
print(c)
#-> array([[ 0, 1, 2, 3, 4],
# [ 5, 6, 7, 8, 9],
# [10, 11, 12, 13, 14],
# [15, 16, 17, 18, 19],
# [20, 21, 22, 23, 24]])
print(c[0, 2:5])
#-> array([2, 3, 4])
print(c[2:5, 2:5])
#->array([[12, 13, 14],
# [17, 18, 19],
# [22, 23, 24]])
print(c[:, [2,4]])
#->array([[ 2, 4],
# [ 7, 9],
# [12, 14],
# [17, 19],
# [22, 24]])
print(c[[1,3]][:,[2, 4]])
#-> array([[ 7, 9],
# [17, 19]])
數組對函數運算的支持
擴展庫 numpy 提供了大量用于對數組進行計算的函數,可以用于對數組中所有元素進行同樣的計算并返回新的數組,處理速度比使用循環要快得多。
import numpy as np
x = np.arange(0, 100, 10, dtype=np.floating)
print(x)
#-> array([ 0., 10., 20., 30., 40., 50., 60., 70., 80., 90.])
print(np.sin(x))
#-> array([ 0. , -0.54402111, 0.91294525, -0.98803162, 0.74511316,
# -0.26237485, -0.30481062, 0.77389068, -0.99388865, 0.89399666])
x = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])
print(np.cos(x))
#->array([[ 0.54030231, -0.41614684, -0.9899925 ],
# [-0.65364362, 0.28366219, 0.96017029],
# [ 0.75390225, -0.14550003, -0.91113026]])
print(np.round(np.cos(x)))
#->array([[ 1., -0., -1.],
# [-1., 0., 1.],
# [ 1., -0., -1.]])
print(np.ceil(x/2))
#->array([[1., 1., 2.],
# [2., 3., 3.],
# [4., 4., 5.]])
改變數組形狀
擴展庫 numpy 中的數組提供了 reshape() 和 resize() 兩種方法,用來修改數組的形狀,其中 reshape() 返回新數組但不會改變數組中的總數量,而 resize() 對數組進行原地修改后能根據需要進行補零或者丟棄某些元素。另外,還可以通過數組的 shape 屬性直接原地修改數組的大小,除了 reshape() 和 resize() 方法,numpy 還提供同名的函數實現類似的功能并返回新的數組。
import numpy as np
x = np.arange(1, 11, 1)
print(x)
#-> array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
x.shape
#-> (10,)
x.size
#-> 10
x.shape = 2, 5
#-> array([[ 1, 2, 3, 4, 5],
# [ 6, 7, 8, 9, 10]])
x.shape
#-> (2, 5)
x.shape = 5,-1
#-> array([[ 1, 2],
# [ 3, 4],
# [ 5, 6],
# [ 7, 8],
# [ 9, 10]])
x = x.reshape(2, 5)
print(x)
#-> array([[ 1, 2, 3, 4, 5],
# [ 6, 7, 8, 9, 10]])
x = np.array(range(5))
x.reshape(1, 10)
#-> Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
#ValueError: cannot reshape array of size 5 into shape (1,10)
x.resize((1, 10))
#-> array([[0, 1, 2, 3, 4, 0, 0, 0, 0, 0]])
np.resize(x, (1,3))
#-> array([[0, 1, 2]])
數組布爾運算
數組可以和標量或等長的數組進行關系運算,返回包含若干個 True/False 的數組。其中每個元素是原數組中元素與標量或另一個數組中對應位置上的元素的運算結果。數組也支持使用包含 True/False 的登場數組作為下標來訪問其中的元素,返回 True 對應位置上的元素組成的數組。
import numpy as np
x = np.random.rand(10)
print(x)
#->array([0.07997063, 0.49599796, 0.6803197 , 0.03469489, 0.82135573,
# 0.74242199, 0.5898134 , 0.46247891, 0.3777993 , 0.23361106])
x > 0.5
#-> array([False, False, True, False, True, True, True, False, False, False])
x[x > 0.5]
#-> array([0.6803197 , 0.82135573, 0.74242199, 0.5898134 ])
sum((x > 0.4) & (x < 0.6))
#-> 3
np.all(x < 1)
#-> True
np.any(x > 0.8)
#-> True
a = np.array([1, 2, 3])
b = np.array([3, 2, 1])
a > b
#-> array([False, False, True])
a[a > b]
#-> array([3])
a == b
#-> array([False, True, False])
x = np.arange(10)
x[(x % 2 == 0) & (x>5)]
#-> array([6, 8])
x[(x % 2 == 0) | (x>5)]
#-> array([0, 2, 4, 6, 7, 8, 9])
分段函數
擴展庫 numpy 提供了 where() 和 pircewise() 兩個函數支持分段函數對數組的處理,其中 where() 函數適合對原數組中的元素進行“二值化”,根據數組中的元素是否滿足指定的條件來決定返回 x 還是 y 。where() 函數的語法格式如下:where(condition, [x, y])piecewise() 函數可以實現更復雜的處理,函數格式如下:piecewise(x, condlist, funclist, *args, **kw)
import numpy as np
x = np.random.randint(0, 10, size = (1, 10))
print(x)
#-> array([[4, 6, 2, 2, 8, 5, 4, 8, 6, 8]])
np.where(x < 5, 0, 1)
#-> array([[0, 1, 0, 0, 1, 1, 0, 1, 1, 1]])
x.resize((2,5))
#-> array([[4, 6, 2, 2, 8],
# [5, 4, 8, 6, 8]])
np.piecewise(x, [x<4, x>7], [lambda x:x*2, lambda x:x*3])
#-> array([[ 0, 0, 4, 4, 24],
# [ 0, 0, 24, 0, 24]])
np.piecewise(x, [x<3, (3<x)&(x<5), x>7], [-1, 1, lambda x:x*4])
#-> array([[ 1, 0, -1, -1, 32],
# [ 0, 1, 32, 0, 32]])
數組堆疊與合并
堆疊數組是指沿著特定的方向把多個數組合并到一起, numpy 的 hstack() 和 vsack() 函數分別用于多個數組的水平堆疊和垂直堆疊。
import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
np.hstack((arr1, arr2))
#-> array([1, 2, 3, 4, 5, 6])
arr3 = np.array([[1], [2], [3]])
arr4 = np.array([[4], [5], [6]])
print(arr3)
#-> array([[1],
# [2],
# [3]])
print(arr4)
#-> array([[4],
# [5],
# [6]])
np.hstack((arr3, arr4))
#-> array([[1, 4],
# [2, 5],
# [3, 6]])
np.vstack((arr3,arr4))
#-> array([[1],
# [2],
# [3],
# [4],
# [5],
# [6]])
另外,numpy 的 concatenate() 函數也提供了類似的數組合并功能。其參數 axis 用于指定沿哪個方向或緯度進行合并,默認為0,也就是按行進行合并。
np.concatenate((arr1, arr2))
#-> array([1, 2, 3, 4, 5, 6])
np.concatenate((arr3, arr4))
#-> array([[1],
# [2],
# [3],
# [4],
# [5],
# [6]])
np.concatenate((arr3, arr4),axis = 1)
#-> array([[1, 4],
# [2, 5],
# [3, 6]])
矩陣生成與常規操作
矩陣生成
矩陣和數組雖然在形式上很像,但矩陣是數學上的概念,而數組只是一種數據存儲方式,二者是有本質區別的。例如,矩陣只能包含數字,而數組可以包含任意類型的數據;矩陣必須是二維的,數組可以是任意維的;乘法、冪運算等很多運算規則在矩陣和數組中都不一樣。擴展庫 numpy 中提供了 matrix() 函數可以用來把列表、元組、range()對象等python可迭代的對象轉換為矩陣。
import numpy as np
x = np.matrix([[1, 2, 3],[4, 5, 6],[7, 8, 9]])
y = np.matrix([1, 2, 3, 4, 5, 6])
print(x, y, x[1, 1], sep="nn")
#-> [[1 2 3]
# [4 5 6]
# [7 8 9]]
#
#[[1 2 3 4 5 6]]
#
#5
矩陣轉置
矩陣轉置是指對矩陣的行和列互換得到新矩陣的操作,原矩陣的第 i 行變為新矩陣的第 i 列,原矩陣的第 j 列變成新矩陣的第 j 行,一個 mn 的矩陣轉置之后得到 nm 的矩陣。在 numpy 中,矩陣對象的屬性 T 實現了轉置的功能。
import numpy as np
x = np.matrix([[1, 2, 3],[4, 5, 6]])
y = np.matrix([1, 2, 3, 4, 5, 6])
print(x.T, y.T, sep="nn")
#-> [[1 4]
# [2 5]
# [3 6]]
#
#[[1]
# [2]
# [3]
# [4]
# [5]
# [6]]
查看矩陣特征
這里的矩陣特征主要是指矩陣的最大值、最小值、元素求和、平均值等,擴展庫 numpy 中的矩陣提供了相應的 max() min() sum() mean()等方法。在大部分的矩陣方法中,都支持 axis 來指定計算方向,axis = 1 表示橫向計算,axis = 0 表示縱向計算。對于 mn 的矩陣,沿 axis = 0 方向計算相當于對矩陣的從上到下“壓扁”,最終得到 1n 的矩陣;沿 axis = 1 方向計算相當于對矩陣從左向右“壓扁”,最終得到 m*1 的矩陣。
import numpy as np
x = np.matrix([[1, 2, 3],[4, 5, 6]])
print(x.mean(), end = "n===n")
print(x.mean(axis = 0), end = "n===n")
print(x.mean(axis = 0).shape, end = "n===n")
print(x.mean(axis = 1), end = "n===n")
print(x.mean(axis = 1).shape, end = "n===n")
print(x.sum(), end = "n===n")
print(x.max(axis = 1), end = "n===n")
print(x.argmax(axis = 1), end = "n===n")
print(x.diagonal(), end = "n===n")
print(x.nonzero(), end = "n===n")
#-> 3.5
#===
#[[2.5 3.5 4.5]]
#===
#(1, 3)
#===
#[[2.]
# [5.]]
#===
#(2, 1)
#===
#21
#===
#[[3]
# [6]]
#===
#[[2]
# [2]]
#===
#[[1 5]]
#===
#(array([0, 0, 0, 1, 1, 1], dtype=int64), #array([0, 1, 2, 0, 1, 2], dtype=int64))
#===
計算相關系數矩陣
相關系數矩陣是一個對稱矩陣,其中對角線上的元素都為1,表示自相關系數。非對角線上的元素表示互相關系數,每個元素的絕對值都小于等于1,反映變量變化趨勢的相似程度。例如,如果 2*2 的相關系數矩陣中非對角線元素的值都大于0,表示兩個信號正相關,其中一個信號變大時另一個信號也變大,變化方向一致,或者說一個信號的變化對另一個信號的影響是“正面的”、積極的。相關系數的絕對值越大,表示兩個信號互相影響的程度就越大。擴展庫 numpy 提供了 corrcoef() 函數用來計算相關系數矩陣。
import numpy as np
print(np.corrcoef([1, 2, 3, 4],[4, 3, 2, 1]))
#-> [[ 1. -1.]
# [-1. 1.]]
print(np.corrcoef([1, 2, 3, 4],[8, 3, 2, 1]))
#-> [[ 1. -0.91350028]
# [-0.91350028 1. ]]
print(np.corrcoef([1, 2, 3, 4],[1, 2, 3, 4]))
#-> [[1. 1.]
# [1. 1.]]
print(np.corrcoef([1, 2, 3, 4],[1, 2, 3, 40]))
#-> [[1. 0.8010362]
# [0.8010362 1. ]]
計算方差、協方差、標準差
擴展庫 numpy 提供了用來計算協方差 cov() 函數和用來計算標準差的 std() 函數。
import numpy as np
print(np.cov([1, 1, 1, 1, 1]))
#-> 0.0
print(np.std([1, 1, 1, 1, 1]))
#-> 0.0
x = [-2.1, -1, 4.3]
y = [3, 1.1, 0.12]
x = np.vstack((x,y))
print(x)
#-> array([[-2.1 , -1. , 4.3 ],
# [ 3. , 1.1 , 0.12]])
print(np.cov(x))
#-> array([[11.71 , -4.286 ],
# [-4.286 , 2.14413333]])
print(np.cov(x, y))
#-> array([[11.71 , -4.286 , -4.286 ],
# [-4.286 , 2.14413333, 2.14413333],
# [-4.286 , 2.14413333, 2.14413333]])
print(np.std(x))
#-> 2.2071223094538484
print(np.std(x, axis = 1))
#-> array([2.79404128, 1.19558447])
print(np.cov(x))
#-> array([[11.71 , -4.286 ],
# [-4.286 , 2.14413333]])
計算特征值與特征向量
對于 n*n 方陣A,如果存在標量 λ 和 n為非0向量x,使得UA˙x = λx 成立,那么稱 λ 是方陣A的一個特征值,x為對應于λ的特征向量。從幾何意義來講,矩陣乘以一個向量,是對這個向量進行了一個變換,從一個坐標系變到另一個坐標系。在變換過程中,向量主要進行旋轉和縮放這兩種變化。如果矩陣乘以一個向量之后,向量只發生了縮放變化而沒有進行旋轉,那么這個向量本身就是該矩陣的一個特征向量,縮放的比例就是特征值。換句話說,特征向量是對向量進行旋轉之后理想的坐標軸之一,而特征值則是原向量在坐標軸上的投影或者該坐標軸對原向量的貢獻。特征值越大,有特征向量組成了該矩陣的一組基,也就是新坐標系的軸。有了特征值和特征向量之后,向量就可以在另一個坐標系中進行表示。擴展庫 numpy 的線性代數子模塊 linalg 中提供了用來計算特征值與特征向量的 eig() 函數,參數可以是列表、numpy的數組、矩陣等等。
a = np.array([[1,-3,3],[3,-5,3],[6,-6,4]])
e, v = np.linalg.eig(a) # 特征值與特征向量
print(e, v)
#-> [ 4.+0.00000000e+00j -2.+1.10465796e-15j -2.-1.10465796e-15j] [[-0.40824829+0.j 0.24400118-0.40702229j 0.24400118+0.40702229j]
# [-0.40824829+0.j -0.41621909-0.40702229j -0.41621909+0.40702229j]
# [-0.81649658+0.j -0.66022027+0.j -0.66022027-0.j ]]
print(np.dot(e, v))
#-> [0.81649658+4.50974724e-16j 3.12888345-8.14044580e-01j
# 3.12888345+8.14044580e-01j]
print(e*v)
#-> [[-1.63299316+0.00000000e+00j -0.48800237+8.14044580e-01j
# -0.48800237-8.14044580e-01j]
# [-1.63299316+0.00000000e+00j 0.83243817+8.14044580e-01j
# 0.83243817-8.14044580e-01j]
# [-3.26598632+0.00000000e+00j 1.32044054-7.29317578e-16j
# 1.32044054+7.29317578e-16j]]
print(np.isclose(np.dot(a, v),e*v)) # 驗證兩者是否相等
#-> [[ True True True]
# [ True True True]
# [ True True True]]
print(np.linalg.det(a-np.eye(3,3)*e)) # 行列式|a-λe|的值應該是0,det()是計算行列式的函數
#-> 5.965152994198125e-14j
計算機矩陣
對于 n*n 的矩陣
如果存在另一個矩陣
使得二者乘積為單位矩陣,即A˙B=B˙A=I那么稱矩陣 A是可逆矩陣或者非奇異矩陣,稱矩陣B為矩陣A的逆矩陣,即B=A<sup>-1</sup>.可逆矩陣的行列式不為0。擴展庫 numpy 的線性代數子模塊 linalg 中提供了用來計算逆矩陣的函數 inv() 。要求參數是可逆矩陣,形式可以是列表、numpy數組、矩陣等等。
x = np.matrix([[1,2,3],[4,5,6],[7,8,0]])
y = np.linalg.inv(x)
print(y)
#-> matrix([[-1.77777778, 0.88888889, -0.11111111],
# [ 1.55555556, -0.77777778, 0.22222222],
# [-0.11111111, 0.22222222, -0.11111111]])
print(x*y) # 對角線元素為1,其他元素為0或近似0
#-> matrix([[ 1.00000000e+00, 5.55111512e-17, 1.38777878e-17],
# [ 5.55111512e-17, 1.00000000e+00, 2.77555756e-17],
# [ 1.77635684e-15, -8.88178420e-16, 1.00000000e+00]])
print(y*x)
#-> matrix([[ 1.00000000e+00, -1.11022302e-16, 0.00000000e+00],
# [ 8.32667268e-17, 1.00000000e+00, 2.22044605e-16],
# [ 6.93889390e-17, 0.00000000e+00, 1.00000000e+00]])
求解線性方程組
線性方程組
可以寫成矩陣相乘的形式ax=b
其中,a 為 n * n 的矩陣,x 和 b 為 n * 1 的矩陣。
擴展庫 numpy 的線性代數子模塊 linalg 中提供了求解線性方程組的 solve() 函數和求解線性方程組最小二乘解的 lstsq() 函數,參數可以是列表、numpy數組、矩陣。
a = np.array([[3,1],[1,2]])
b = np.array([9,8])
x = np.linalg.solve(a,b)
print(x)
#-> array([2., 3.])
print(np.dot(a,x)) # 驗證
#-> array([9., 8.])
print(np.linalg.lstsq(a,b)) # 最小二乘解,返回解、余項、a的秩、a的奇異值
#-> (array([2., 3.]), array([], dtype=float64), 2, array([3.61803399, 1.38196601]))
函數向量化
python 的擴展庫 numpy 本身提供了大量函數都具有向量化的特點,并且可以把普通的函數向量化,從而python操作向量更方便。例如 numpy 中矩陣不支持 math 標準庫中的階乘函數 factorial() ,而擴展庫 numpy 也沒有直接提供這個功能,這個時候就可以通過函數向量化來解決這個問題。
import numpy as np
mat = np.matrix([[1,2,3],[4,5,6]])
print(mat)
#-> matrix([[1, 2, 3],
# [4, 5, 6]])
import math
math.factorial(mat) #不支持,出錯
#-> TypeError: only size-1 arrays can be converted to Python scalars
vec = np.vectorize(math.factorial) # 函數向量化
print(vec(mat))
#-> matrix([[ 1, 2, 6],
# [ 24, 120, 720]])