這段時間,LSGO軟件技術(shù)團隊正在組織 “機器學(xué)習(xí)實戰(zhàn)刻意練習(xí)”活動,這個活動是“Python基礎(chǔ)刻意練習(xí)”活動的升級,是對學(xué)員們技術(shù)的更深層次的打磨。在用 Python 寫各類機器學(xué)習(xí)算法時,我們經(jīng)常會用到 NumPy庫,故在這里總結(jié)一下,以方便學(xué)員們的學(xué)習(xí)。
什么是 NumPy 呢?
NumPy 這個詞來源于兩個單詞 -- Numerical
和Python
。其是一個功能強大的 Python 庫,可以幫助程序員輕松地進行數(shù)值計算,通常應(yīng)用于以下場景:
執(zhí)行各種數(shù)學(xué)任務(wù),如:數(shù)值積分、微分、內(nèi)插、外推等。因此,當(dāng)涉及到數(shù)學(xué)任務(wù)時,它形成了一種基于 Python 的 MATLAB 的快速替代。
計算機中的圖像表示為多維數(shù)字數(shù)組。NumPy 提供了一些優(yōu)秀的庫函數(shù)來快速處理圖像。例如,鏡像圖像、按特定角度旋轉(zhuǎn)圖像等。
在編寫機器學(xué)習(xí)算法時,需要對矩陣進行各種數(shù)值計算。如:矩陣乘法、求逆、換位、加法等。NumPy 數(shù)組用于存儲訓(xùn)練數(shù)據(jù)和機器學(xué)習(xí)模型的參數(shù)。
1. NumPy 中的數(shù)組
NumPy 提供的最重要的數(shù)據(jù)結(jié)構(gòu)是一個稱為 NumPy數(shù)組 的強大對象。NumPy數(shù)組 是通常的 Python 列表的擴展。
1.1 創(chuàng)建一個數(shù)組
import numpy as np
# 1D Array
a = np.array([0, 1, 2, 3, 4])
b = np.array((0, 1, 2, 3, 4))
c = np.arange(5)
d = np.linspace(0, 2 * np.pi, 5)
print(a) # [0 1 2 3 4]
print(b) # [0 1 2 3 4]
print(c) # [0 1 2 3 4]
print(d) # [0. 1.57079633 3.14159265 4.71238898 6.28318531]
print(a[3]) # 3
array(object[, dtype, copy, order, subok, ndmin])
從現(xiàn)有的數(shù)據(jù)創(chuàng)建一個數(shù)組。arange([start,] stop[, step,][, dtype])
返回給定間隔內(nèi)的均勻間隔的值。
linspace(start, stop[, num, endpoint, …])
返回指定間隔內(nèi)的等間隔數(shù)字。
上面的代碼顯示了創(chuàng)建數(shù)組的 4 種不同方法。最基本的方法是將序列傳遞給 NumPy 的array()
函數(shù);你可以傳遞任何序列,而不僅僅是常見的列表(list)數(shù)據(jù)類型。對數(shù)組進行索引就像列表或任何其他 Python 序列一樣。你也可以對它們進行切片。
上面的數(shù)組示例是如何使用 NumPy 表示向量的,接下來我們將看看如何使用多維數(shù)組表示矩陣和更多的信息。
import numpy as np
# MD Array,
a = np.array([[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
[26, 27, 28, 29, 30],
[31, 32, 33, 34, 35]])
print(a[2, 4]) # 25
NumPy 提供了創(chuàng)建 Zero矩陣 的方法。
zeros(shape[, dtype, order])
返回給定形狀和類型的新數(shù)組,并用零填充。import numpy as np
a = np.zeros(5)
b = np.zeros([2, 3])
print(a) # [0. 0. 0. 0. 0.]
print(b)
'''
[[0. 0. 0.]
[0. 0. 0.]]
'''
NumPy 提供了創(chuàng)建 One矩陣 的方法。
ones(shape[, dtype, order])
返回給定形狀和類型的新數(shù)組,并填充為1。import numpy as np
a = np.ones(5)
b = np.ones([2, 3])
print(a) # [1. 1. 1. 1. 1.]
print(b)
'''
[[1. 1. 1.]
[1. 1. 1.]]
'''
NumPy 提供了創(chuàng)建 Random矩陣 的方法。
import numpy as np
a = np.random.random(5)
b = np.random.random([2, 3])
print(a) # [0.94855794 0.32057893 0.47848178 0.1779337 0.86017829]
print(b)
'''
[[0.76592562 0.71543738 0.58269856]
[0.74960683 0.07028875 0.18083749]]
'''
NumPy 提供了創(chuàng)建 Eye矩陣 的方法。
eye(N[, M, k, dtype, order])
返回一個二維數(shù)組,對角線上有一個,其他地方為零。import numpy as np
a = np.eye(4)
b = np.eye(2, 3)
print(a)
'''
[[ 1. 0. 0. 0.]
[ 0. 1. 0. 0.]
[ 0. 0. 1. 0.]
[ 0. 0. 0. 1.]]
'''
print(b)
'''
[[ 1. 0. 0.]
[ 0. 1. 0.]]
'''
1.2 多維數(shù)組切片
切片多維數(shù)組比 1D數(shù)組 復(fù)雜一點,并且在使用 NumPy 時你也會經(jīng)常需要使用到。
import numpy as np
# MD Array,
a = np.array([[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
[26, 27, 28, 29, 30],
[31, 32, 33, 34, 35]])
# MD slicing
print(a[0, 1:4]) # [12 13 14]
print(a[1:4, 0]) # [16 21 26]
print(a[::2, ::2])
# [[11 13 15]
# [21 23 25]
# [31 33 35]]
print(a[:, 1]) # [12 17 22 27 32]
通過對每個以逗號分隔的維度執(zhí)行單獨的切片,你可以對多維數(shù)組進行切片。因此,對于2D數(shù)組,我們的第一片定義了行的切片,第二片定義了列的切片。
1.3 數(shù)組屬性
在使用 NumPy 時,你會想知道數(shù)組的某些信息。很幸運,在這個包里邊包含了很多便捷的方法,可以給你想要的信息。
# Array properties
a = np.array([11, 12, 13, 14, 15])
print(type(a)) # <class 'numpy.ndarray'>
print(a.dtype) # int32
print(a.size) # 5
print(a.shape) # (5, )
print(a.itemsize) # 4
print(a.ndim) # 1
print(a.nbytes) # 20
(5, )
數(shù)組的形狀,a
是一個包含5個元素的數(shù)組。
# Array properties
a = np.array([[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
[26, 27, 28, 29, 30],
[31, 32, 33, 34, 35]])
print(type(a)) # <class 'numpy.ndarray'>
print(a.dtype) # int32
print(a.size) # 25
print(a.shape) # (5, 5)
print(a.itemsize) # 4
print(a.ndim) # 2
print(a.nbytes) # 100
type
正如你在上面的代碼中看到的,NumPy 數(shù)組實際上被稱為 ndarray。shape
數(shù)組的形狀是它有多少行和列,上面的數(shù)組有5行和5列,所以它的形狀是(5,5)。
itemsize
屬性是每個項占用的字節(jié)數(shù)。這個數(shù)組的數(shù)據(jù)類型是int32
,一個int32
中有32位,一個字節(jié)中有8位,除以32除以8,你就可以得到它占用了多少字節(jié),在本例中是4。
ndim
屬性是數(shù)組的維數(shù)。這個有2個。例如,向量只有1。
nbytes
屬性是數(shù)組中的所有數(shù)據(jù)消耗掉的字節(jié)數(shù)。
2. 使用數(shù)組
2.1 基本運算符
import numpy as np
# Basic Operators
a = np.arange(25)
a = a.reshape((5, 5))
print(a)
'''
[[ 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]]
'''
b = np.array([10, 62, 1, 14, 2, 56, 79, 2, 1, 45,
4, 92, 5, 55, 63, 43, 35, 6, 53, 24,
56, 3, 56, 44, 78])
b = b.reshape((5, 5))
print(b)
'''
[[10 62 1 14 2]
[56 79 2 1 45]
[ 4 92 5 55 63]
[43 35 6 53 24]
[56 3 56 44 78]]
'''
print(a + b)
print(a - b)
print(a * b)
print(a / b)
print(a ** 2)
print(a < b)
print(a > b)
print(a.dot(b))
reshape(a, newshape[, order])
在不更改數(shù)據(jù)的情況下為數(shù)組賦予新的形狀。dot(a, b[, out])
函數(shù)計算兩個矩陣的乘積,如果是一維數(shù)組則是它們的點積。
除了 dot()
之外,這些操作符都是對數(shù)組進行逐元素運算。
2.2 數(shù)組特殊運算符
import numpy as np
a = np.arange(9)
a = np.reshape(a, [1, 9])
print(a) # [[0 1 2 3 4 5 6 7 8]]
print(np.sum(a)) # 36
print(np.min(a)) # 0
print(np.max(a)) # 8
print(np.cumsum(a)) # [ 0 1 3 6 10 15 21 28 36]
a = np.reshape(a, [3, 3])
print(a)
'''
[[0 1 2]
[3 4 5]
[6 7 8]]
'''
print(np.sum(a)) # 36
print(np.min(a)) # 0
print(np.max(a)) # 8
print(np.cumsum(a)) # [ 0 1 3 6 10 15 21 28 36]
print(np.sum(a, axis=0)) # [ 9 12 15]
print(np.sum(a, axis=1)) # [ 3 12 21]
print(np.min(a, axis=0)) # [0 1 2]
print(np.min(a, axis=1)) # [0 3 6]
print(np.max(a, axis=0)) # [6 7 8]
print(np.max(a, axis=1)) # [2 5 8]
print(np.cumsum(a, axis=0))
'''
[[ 0 1 2]
[ 3 5 7]
[ 9 12 15]]
'''
print(np.cumsum(a, axis=1))
'''
[[ 0 1 3]
[ 3 7 12]
[ 6 13 21]]
'''
sum(a[, axis, dtype, out, keepdims, …])
Sum of array elements over a given axis.cumsum(a[, axis, dtype, out])
Return the cumulative sum of the elements along a given axis.
sum()
、min()
和max()
函數(shù)的作用非常明顯。將所有元素相加,找出最小和最大元素。然而,cumsum()
函數(shù)就不那么明顯了。它將像sum()
這樣的每個元素相加,但是它將當(dāng)前元素之前的和加到當(dāng)前元素上。
3. 索引進階
3.1 花式索引
花式索引 是獲取數(shù)組中我們想要的特定元素的有效方法,即使用我們想要檢索的特定索引序列對數(shù)組進行索引,返回我們索引的元素的列表。
import numpy as np
# Fancy indexing
a = np.arange(0, 100, 10)
indices = [1, 5, -1]
b = a[indices]
print(a) # [ 0 10 20 30 40 50 60 70 80 90]
print(b) # [10 50 90]
b = a[np.array(indices)]
print(b) # [10 50 90]
3.2 布爾屏蔽
布爾屏蔽 允許我們根據(jù)我們指定的條件檢索數(shù)組中的元素。
import numpy as np
import matplotlib.pyplot as plt
# Boolean masking
a = np.linspace(0, 2 * np.pi, 50)
b = np.sin(a)
print(len(a)) # 50
plt.plot(a, b)
mask = b >= 0
print(len(a[mask])) # 25
print(mask)
'''
[ True True True True True True True True True True True True
True True True True True True True True True True True True
True False False False False False False False False False False False
False False False False False False False False False False False False
False False]
'''
plt.plot(a[mask], b[mask], 'bo')
mask = np.logical_and(b >= 0, a <= np.pi / 2)
print(mask)
'''
[ True True True True True True True True True True True True
True False False False False False False False False False False False
False False False False False False False False False False False False
False False False False False False False False False False False False
False False]
'''
plt.plot(a[mask], b[mask], 'go')
plt.show()
我們利用這些條件來選擇圖上的不同點。藍色點(在圖中還包括綠點,但綠點掩蓋了藍色點),顯示值 大于0 的所有點。綠色點表示值 大于0 且 小于0.5π 的所有點。
numpy.pi
pi = 3.1415926535897932384626433…
numpy.e
e = 2.71828182845904523536028747135266249775724709369995…
sin(x, /[, out, where, casting, order, …])
Trigonometric sine, element-wise.
logical_and(x1, x2, /[, out, where, …])
按元素計算x1和x2的真值。
logical_or(x1, x2, /[, out, where, casting, …])
按元素計算x1或x2的真值。
logical_not(x, /[, out, where, casting, …])
計算非x元素的真值。
logical_xor(x1, x2, /[, out, where, …])
按元素計算x1 XOR x2的真值。
3.3 缺省索引
不完全索引是從多維數(shù)組的第一個維度獲取索引或切片的一種方便方法。
import numpy as np
a = np.array([[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
[26, 27, 28, 29, 30],
[31, 32, 33, 34, 35]])
print(a[3])
# [26 27 28 29 30]
print(a[3:])
'''
[[26 27 28 29 30]
[31 32 33 34 35]]
'''
print(a[:3])
'''
[[11 12 13 14 15]
[16 17 18 19 20]
[21 22 23 24 25]]
'''
print(a[a >= 25])
# [25 26 27 28 29 30 31 32 33 34 35]
3.4 Where 函數(shù)
where()
函數(shù)是另外一個根據(jù)條件返回數(shù)組中的值的有效方法。只需要把條件傳遞給它,它就會返回一個使得條件為真的元素的列表。
import numpy as np
# Where
a = np.arange(0, 100, 10)
print(a)
# [ 0 10 20 30 40 50 60 70 80 90]
b = np.where(a < 50)
c = np.where(a >= 50)[0]
print(b) # (array([0, 1, 2, 3, 4], dtype=int64),)
print(c) # [5 6 7 8 9]
print(np.array(b) * 2) # [[0 2 4 6 8]]
a = np.array([[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
[26, 27, 28, 29, 30],
[31, 32, 33, 34, 35]])
b = np.where(a > 28)
c = np.where(a > 28)[1]
print(b)
# (array([3, 3, 4, 4, 4, 4, 4], dtype=int64), array([3, 4, 0, 1, 2, 3, 4], dtype=int64))
print(np.array(b))
'''
[[3 3 4 4 4 4 4]
[3 4 0 1 2 3 4]]
'''
print(c)
# [3 4 0 1 2 3 4]
4. 其它
import numpy as np
randMat = np.mat(np.random.rand(4, 4))
print(randMat)
'''
[[ 0.27583095 0.85371896 0.04477732 0.0351685 ]
[ 0.99631911 0.87780066 0.40519399 0.91468947]
[ 0.29717361 0.86168002 0.28151676 0.08364942]
[ 0.29388903 0.74111371 0.45270016 0.4220726 ]]
'''
invRandMat = randMat.I
print(invRandMat)
'''
求逆矩陣
[[-2.95048939 1.59328107 4.89236828 -4.17662009]
[ 2.24072267 -0.50472824 -1.59788475 1.22379156]
[-4.67532022 -0.10375646 5.07432839 -0.39124946]
[ 3.13454227 -0.11186758 -6.04338775 3.54823514]]
'''
myEye = randMat * invRandMat
print(myEye)
'''
矩陣乘法
[[ 1.00000000e+00 5.55111512e-17 -2.22044605e-16 -2.22044605e-16]
[ 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00]
[ 0.00000000e+00 1.11022302e-16 1.00000000e+00 -2.22044605e-16]
[ 0.00000000e+00 0.00000000e+00 -8.88178420e-16 1.00000000e+00]]
'''
print(myEye - np.eye(4))
'''
[[ 0.00000000e+00 5.55111512e-17 -2.22044605e-16 -2.22044605e-16]
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]
[ 0.00000000e+00 1.11022302e-16 2.22044605e-16 -2.22044605e-16]
[ 0.00000000e+00 0.00000000e+00 -8.88178420e-16 0.00000000e+00]]
'''
如你所見,NumPy 在其提供的庫函數(shù)方面非常強大。本文僅供學(xué)員們?nèi)腴T使用,我們在寫機器學(xué)習(xí)的算法時,慢慢補充完善。今天就到這里吧!See You!
參考文獻
https://www.pluralsight.com/guides/different-ways-create-numpy-arrays
https://www.numpy.org.cn/reference/constants.html
https://www.numpy.org.cn/article/basics/an_introduction_to_scientific_python_numpy.html
聯(lián)系客服