1. 程式人生 > >Numpy的學習筆記一

Numpy的學習筆記一

NumPy簡單入門教程

NumPy是Python中的一個運算速度非常快的一個數學庫,它非常重視陣列。它允許你在Python中進行向量和矩陣計算,並且由於許多底層函式實際上是用C編寫的,因此你可以體驗在原生Python中永遠無法體驗到的速度。

NumPy絕對是科學Python成功的關鍵之一,如果你想要進入Python中的資料科學和/或機器學習,你就要必須學習它。在我看來,NumPy的API設計得很好,所以我們要開始使用它並不困難。

陣列基礎

建立一個數組

NumPy圍繞這些稱為陣列的事物展開。實際上它被稱之為 ndarrays,你不知道沒事兒。使用NumPy提供的這些陣列,我們就可以以閃電般的速度執行各種有用的操作,如向量和矩陣、線性代數等數學運算!(開個玩笑,本文章中我們不會做任何繁重的數學運算)

# 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

上面的程式碼顯示了建立陣列的4種不同方法。最基本的方法是將序列傳遞給NumPy的array()函式; 你可以傳遞任何序列(類陣列),而不僅僅是常見的列表(list)資料型別。

請注意,當我們列印具有不同長度數字的陣列時,它會自動將它們填充出來。這對於檢視矩陣很有用。對陣列進行索引就像列表或任何其他Python序列一樣。

上面的陣列示例是如何使用NumPy表示向量的,接下來我們將看看如何使用多維陣列表示矩陣和更多的資訊。

# 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

為了建立一個2D(二維)陣列,我們傳遞一個列表的列表(或者是一個序列的序列)給array()函式。如果我們想要一個3D(三維)陣列,我們就要傳遞一個列表的列表的列表,如果是一個4D(四維)陣列,那就是列表的列表的列表的列表,以此類推。

請注意2D(二維)陣列(在我們的朋友空格鍵的幫助下)是如何按行和列排列的。要索引2D(二維)陣列,我們只需引用行數和列數即可。

它背後的一些數學知識

要正確理解這一點,我們應該真正瞭解一下向量和矩陣是什麼。

向量是具有方向和幅度的量。它們通常用於表示速度,加速度和動量等事物。向量可以用多種方式編寫,儘管對我們最有用的是它們被寫為n元組的形式,如(1,4,6,9)。這就是我們在NumPy中表示他們的方式。

矩陣類似於向量,除了它由行和列組成; 很像一個網格。可以通過給出它所在的行和列來引用矩陣中的值。在NumPy中,我們通過傳遞一系列序列來製作陣列,就像我們之前所做的那樣。

多維陣列切片

切片多維陣列比1D陣列複雜一點,並且在使用NumPy時你也會經常需要使用到。

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

如你所見,通過對每個以逗號分隔的維度執行單獨的切片,你可以對多維陣列進行切片。因此,對於2D陣列,我們的第一片定義了行的切片,第二片定義了列的切片。

注意,只需輸入數字就可以指定行或列。上面的第一個示例從陣列中選擇第0列。

下面的圖表說明了給定的示例切片是如何進行工作的。

https://www.numpy.org.cn/static/images/article/numpy_2D_slicing_diagram-1.jpg

陣列屬性

在使用 NumPy 時,你會想知道陣列的某些資訊。很幸運,在這個包裡邊包含了很多便捷的方法,可以給你想要的資訊。

# 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) # >>>int64
print(a.size) # >>>25
print(a.shape) # >>>(5, 5)
print(a.itemsize) # >>>8
print(a.ndim) # >>>2
print(a.nbytes) # >>>200

正如你在上面的程式碼中看到的,NumPy陣列實際上被稱為ndarray。我不知道為什麼他媽的它叫ndarray,如果有人知道請留言!我猜它代表n維陣列。

陣列的形狀是它有多少行和列,上面的陣列有5行和5列,所以它的形狀是(5,5)。

itemsize屬性是每個項佔用的位元組數。這個陣列的資料型別是int 64,一個int 64中有64位,一個位元組中有8位,除以64除以8,你就可以得到它佔用了多少位元組,在本例中是8。

ndim 屬性是陣列的維數。這個有2個。例如,向量只有1。

nbytes 屬性是陣列中的所有資料消耗掉的位元組數。你應該注意到,這並不計算陣列的開銷,因此陣列佔用的實際空間將稍微大一點。

使用陣列

基本操作符

只是能夠從陣列中建立和檢索元素和屬性不能滿足你的需求,你有時也需要對它們進行數學運算。 你完全可以使用四則運算子 +、- 、/ 來完成運算操作。

# Basic Operators
a = np.arange(25)
a = a.reshape((5, 5))

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(a + b)
print(a - b)
print(a * b)
print(a / b)
print(a ** 2)
print(a < b) print(a > b)

print(a.dot(b))

除了 dot() 之外,這些操作符都是對陣列進行逐元素運算。比如 (a, b, c) + (d, e, f) 的結果就是 (a+d, b+e, c+f)。它將分別對每一個元素進行配對,然後對它們進行運算。它返回的結果是一個數組。注意,當使用邏輯運算子比如 “<” 和 “>” 的時候,返回的將是一個布林型陣列,這點有一個很好的用處,後邊我們會提到。

dot() 函式計算兩個陣列的點積。它返回的是一個標量(只有大小沒有方向的一個值)而不是陣列。

陣列特殊運算子

NumPy還提供了一些別的用於處理陣列的好用的運算子。

# dot, sum, min, max, cumsum
a = np.arange(10)

print(a.sum()) # >>>45
print(a.min()) # >>>0
print(a.max()) # >>>9
print(a.cumsum()) # >>>[ 0  1  3  6 10 15 21 28 36 45]

sum()、min()和max()函式的作用非常明顯。將所有元素相加,找出最小和最大元素。

然而,cumsum()函式就不那麼明顯了。它將像sum()這樣的每個元素相加,但是它首先將第一個元素和第二個元素相加,並將計算結果儲存在一個列表中,然後將該結果新增到第三個元素中,然後再將該結果儲存在一個列表中。這將對陣列中的所有元素執行此操作,並返回作為列表的陣列之和的執行總數。

索引進階

花式索引

花式索引 是獲取陣列中我們想要的特定元素的有效方法。

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

布林遮蔽

布林遮蔽是一個有用的功能,它允許我們根據我們指定的條件檢索陣列中的元素。

# Boolean masking
import matplotlib.pyplot as plt

a = np.linspace(0, 2 * np.pi, 50)
b = np.sin(a)
plt.plot(a,b)
mask = b >= 0
plt.plot(a[mask], b[mask], 'bo')
mask = (b >= 0) & (a <= np.pi / 2)
plt.plot(a[mask], b[mask], 'go')
plt.show()

該示例生成以下圖:

預設索引

不完全索引是從多維陣列的第一個維度獲取索引或切片的一種方便方法。例如,如果陣列a=[1,2,3,4,5],[6,7,8,9,10],那麼[3]將在陣列的第一個維度中給出索引為3的元素,這裡是值4。

a = np.arange(0, 100, 10)
b = a[:5]
c = a[a >= 50]
print(b) # >>>[ 0 10 20 30 40]
print(c) # >>>[50 60 70 80 90]

Where 函式

where() 函式是另外一個根據條件返回陣列中的值的有效方法。只需要把條件傳遞給它,它就會返回一個使得條件為真的元素的列表。

# Where
a = np.arange(0, 100, 10)
b = np.where(a < 50) 
c = np.where(a >= 50)[0]
print(b) # >>>(array([0, 1, 2, 3, 4]),)
print(c) # >>>[5 6 7 8 9]

文章出處