Python 之 Numpy 框架入门
NumPy
目錄-
NumPy
-
基礎使用
- 基本數據類型
- 創建基本數組
- 數組屬性
-
數組生成
-
zeros、ones、empty 數組生成
- numpy.zeros
- numpy.ones
- numpy.empty
- 其它說明
- numpy.random
- numpy.arange
- numpy.linspace
-
zeros、ones、empty 數組生成
-
數組操作
- 數組排序
- 切片索引
- 數組運算符
- 廣播規則
-
修改數組
- 修改數組的形狀
- 翻轉數組
- 修改數組維度
- 連接數組
- 分割數組
- 增刪數組元素
- 數組迭代
-
基礎使用
NumPy 是 Python 中用于科學計算的基本包。它是一個 Python 庫,提供了一個多維數組對象、各種派生對象(比如屏蔽數組和矩陣) ,以及一系列用于數組快速操作的例程,包括數學、邏輯、形狀操作、排序、選擇、 i/o、離散傅里葉變換、基本線性代數、基本統計操作、隨機模擬等等。
官網文檔地址:https://numpy.org/
單純學習 Numpy 會比較悶,因為 Numpy 是用于科學計算的。只是學習了各種 API 的使用,會很苦悶學來干啥,跟人工智能有什么關系?
安裝 numpy 比較簡單,直接使用命令安裝即可:
pip install numpy
測試是否正常:
import numpy as np
print(np.__version__)
基礎使用
基本數據類型
下表列舉了常用 NumPy 基本類型。
| 名稱 | 描述 |
|---|---|
| bool_ | 布爾型數據類型(True 或者 False) |
| int_ | 默認的整數類型(類似于 C 語言中的 long,int32 或 int64) |
| intc | 與 C 的 int 類型一樣,一般是 int32 或 int 64 |
| intp | 用于索引的整數類型(類似于 C 的 ssize_t,一般情況下仍然是 int32 或 int64) |
| int8 | 字節(-128 to 127) |
| int16 | 整數(-32768 to 32767) |
| int32 | 整數(-2147483648 to 2147483647) |
| int64 | 整數(-9223372036854775808 to 9223372036854775807) |
| uint8 | 無符號整數(0 to 255) |
| uint16 | 無符號整數(0 to 65535) |
| uint32 | 無符號整數(0 to 4294967295) |
| uint64 | 無符號整數(0 to 18446744073709551615) |
| float_ | float64 類型的簡寫 |
| float16 | 半精度浮點數,包括:1 個符號位,5 個指數位,10 個尾數位 |
| float32 | 單精度浮點數,包括:1 個符號位,8 個指數位,23 個尾數位 |
| float64 | 雙精度浮點數,包括:1 個符號位,11 個指數位,52 個尾數位 |
| complex_ | complex128 類型的簡寫,即 128 位復數 |
| complex64 | 復數,表示雙 32 位浮點數(實數部分和虛數部分) |
| complex128 | 復數,表示雙 64 位浮點數(實數部分和虛數部分) |
每個內建類型都有一個唯一定義它的字符代碼,如下:
| 字符 | 對應類型 |
|---|---|
| b | 布爾型 |
| i | (有符號) 整型 |
| u | 無符號整型 integer |
| f | 浮點型 |
| c | 復數浮點型 |
| m | timedelta(時間間隔) |
| M | datetime(日期時間) |
| O | (Python) 對象 |
| S, a | (byte-)字符串 |
| U | Unicode |
| V | 原始數據 (void) |
numpy 有個 dtype 函數,用于定義變量類型,其定義如下:
class numpy.dtype(dtype, align=False, copy=False[, metadata])
比如這段代碼定義了一個numpy 中 int32 類型的變量:
import numpy as np
a = np.dtype(dtype="int32")
print(a)
也可以使用短代碼:
import numpy as np
a = np.dtype("i")
print(a)
等效代碼:
import numpy as np
a = np.dtype(np.int32)
print(a)
運行代碼后,都會打印:
int32
這個類型是 numpy 中的類型,不是 Python 中的類型,要注意區分。numpy 的數值類型實際上是 dtype 對象的實例,并對應唯一的字符,包括 np.bool_,np.int32,np.float32,等等。
因為 Python 是弱類型,沒有 int32 a = ... 這種語法,所以為了明確定義這個變量是何種類型,需要使用類型的字符串名稱。
這句話現在可以先不管,后面會在很多地方使用 dtype,用熟了就知道了。
要注意的是 np.dtype 是創建一個類型標識,本身并沒有存儲變量值。
示例:
import numpy as np
def test(object, dtype):
if dtype == np.int32:
print(f"{object} int32")
elif dtype == np.int64:
print(f"{object} int64")
elif dtype == np.str_:
print(f"{object} str_")
a = 111
b = np.dtype(dtype="int32")
test(a, b)
c = '111'
d = np.dtype(dtype="str")
test(c, d)
創建基本數組
Numpy 提供了一個多維數組對象、各種派生對象(比如屏蔽數組和矩陣) ,numpy 中最重要的對象是數組和矩陣。所以要學會 numpy ,最基本的是學會 numpy 數組。
numpy 創建數組的定義:
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
參數說明:
| 名稱 | 描述 |
|---|---|
| object | 數組或嵌套的數列 |
| dtype | 數組元素的數據類型,可選 |
| copy | 對象是否需要復制,可選 |
| order | 創建數組的樣式,C為行方向,F為列方向,A為任意方向(默認) |
| subok | 默認返回一個與基類類型一致的數組 |
| ndmin | 指定生成數組的最小維度 |
創建一個基本數組:
import numpy as np
a = np.array([1, 2, 3])
創建多維數組
import numpy as np
a = np.array([[1, 2], [3, 4]])
print (a)
定義一個數組,然后生成多維數組:
import numpy as np
a = np.array([1, 2, 3, 4, 5], ndmin = 2)
# 相當于 np.array([[1, 2, 3, 4, 5]])
print (a)
b = np.array([1, 2, 3, 4, 5], ndmin = 3)
# 相當于 np.array([[[1, 2, 3, 4, 5]]])
print (b)
c = np.array([[1, 2, 3, 4, 5],[1, 2, 3, 4, 5]], ndmin = 3)
# 相當于 np.array([[[1, 2, 3, 4, 5],[1, 2, 3, 4, 5]]])
print (c)
數組屬性
由于 Python 是弱類型,所以想學習和了解細節的時候,會比較懵逼。因此,我們盡量在編寫 Python 代碼時,獲取代碼的一些文檔注釋。
如下面代碼中,定義了一個數組:
import numpy as np
a = np.array([[1, 2], [3, 4]])
print (a)
numpy 的數組,其類型為 ndarray[Any, dtype],完整文檔如下:
a: ndarray[Any, dtype] = np.array([[1, 2], [3, 4]])
所以,要掌握 numpy 數組,實際上就是在了解 ndarray。
ndarray 中比較重要的屬性如下:
| 屬性 | 說明 |
|---|---|
| ndarray.ndim | 秩,即軸的數量或維度的數量 |
| ndarray.shape | 數組的維度,對于矩陣,n 行 m 列 |
| ndarray.size | 數組元素的總個數,相當于 .shape 中 n*m 的值 |
| ndarray.dtype | ndarray 對象的元素類型 |
| ndarray.itemsize | ndarray 對象中每個元素的大小,以字節為單位 |
| ndarray.flags | ndarray 對象的內存信息 |
| ndarray.real | ndarray元素的實部 |
| ndarray.imag | ndarray 元素的虛部 |
| ndarray.data | 包含實際數組元素的緩沖區,由于一般通過數組的索引獲取元素,所以通常不需要使用這個屬性。 |
回到之前提到過的 numpy.dtype,結合 numpy.array,其示例代碼如下:
import numpy
import numpy as np
a = np.array([1, 2])
print(a.dtype)
print(a)
t = np.dtype(numpy.float64)
b = np.array(object=[1, 2], dtype=t)
print(b.dtype)
print(b)
如果我們不配置 dtype 參數,那么數組的 dtype 會以數組元素類型為依據。如果配置了 dtype,那么數組元素都會被轉換為對應的類型,如 np.array(object=[1, 2], dtype='float64') 。
數組生成
zeros、ones、empty 數組生成
numpy.zeros
numpy.zeros 的作用是創建一個元素全部為 0 的數組。
其定義如下:
def zeros(shape, dtype=float, order='C', *, like=None, /)
| 參數 | 描述 |
|---|---|
| shape | 數組形狀 |
| dtype | 數據類型,可選 |
| order | 有"C"和"F"兩個選項,分別代表,行優先和列優先,在計算機內存中的存儲元素的順序。 |
創建一個全部由 0 填充的數組:
import numpy as np
# 長度為 2
a = np.zeros(2)
print(a)
np.zeros() 默認創建的數組是 float64 類型,如果需要自定義類型,可以使用 dtype:
import numpy as np
# 長度為 2
a = np.zeros(2,dtype=int)
print(a)
numpy.ones
ones 創建一個元素值均為 1 的數組。
其定義如下:
def ones(shape, dtype=None, order='C', *, like=None)
示例如下:
import numpy as np
# 長度為 2
a = np.ones(2,dtype=int)
print(a)
由于其 API 與 numpy.zeros 一致,因此不再贅述。
numpy.empty
創建一個指定長度的空數組,但是不會對內存區域進行初始化,所以其被分配的內存區域可能已經有值。
其定義如下:
def empty(shape, dtype=None, order='C', *args, **kwargs)
示例:
import numpy as np
# 長度為 2
a = np.empty(2)
print(a)
由于其沒有初始化內存,因此內存區域會殘留數據。
其它說明
此外,還有三個對應的原型復制函數:
def empty_like(prototype, dtype=None, order=None, subok=None, shape=None
def zeros_like(prototype, dtype=None, order='K', subok=True, shape=None)
def ones_like(prototype, dtype=None, order='K', subok=True, shape=None)
它們的作用是根據數組類型,拷貝一個相同的結構,然后填充對應值。
如下示例,復制數組相同的結構,但是填充的值為 0。
import numpy as np
a = np.array([[1],[1]])
b = np.zeros_like(a)
print(b)
此外,這三個函數,可以傳遞元組,生成多維的數組(矩陣)。
import numpy
import numpy as np
a = np.zeros(shape=(2, 3, 4), dtype=numpy.double)
print(a)
numpy.random
numpy.random 是一個類,不是一個函數,numpy.random 中有一些隨機生成數組的函數。
以下是一些常用的 API:
#生成具有給定形狀的均勻分布的隨機樣本,范圍在[0, 1)之間。
numpy.random.rand(size)
# 生成具有給定形狀的標準正態分布(平均值為0,方差為1)的隨機樣本。隨機樣本取值范圍是[0,1)。
numpy.random.randn(size)
# 正態分布,指定均值和方差
numpy.random.normal(loc=0.0, scale=1.0, size=None)
# 隨機生成
numpy.random.random(size=None)
# 從給定的上下限范圍內生成隨機整數。
numpy.random.randint(low, high=None, size=None, dtype=int)
# 從給定的一維數組中生成隨機樣本。
numpy.random.choice(a, size=None, replace=True, p=None)
# 隨機打亂給定數組的順序。
numpy.random.shuffle(x)
隨機數值生成和正態分布生成示例如下:
import numpy as np
a = np.random.rand(10)
b = np.random.rand(10)
print(a)
print(b)
[0.39809428 0.83922059 0.10808865 0.00332159 0.75922001 0.26850704
0.04497839 0.59012908 0.0438718 0.59988563]
[0.78161896 0.91401858 0.10980276 0.89723959 0.06802148 0.18993732
0.10664519 0.14121531 0.27353601 0.56878734]
x1 = np.random.randint(10, size=6) # 一維數組
x2 = np.random.randint(10, size=(3, 4)) # 二維數組
x3 = np.random.randint(10, size=(3, 4, 5)) # 三維數組
對于其它 API,由于篇幅有限,不再贅述。
numpy.arange
numpy.arange 用于有規律地生成數組。
其定義如下:
numpy.arange([start, ]stop, [step, ]dtype=None, *, like=None)
| 參數 | 描述 |
|---|---|
start |
起始值,默認為0
|
stop |
終止值(不包含) |
step |
步長,默認為1
|
dtype |
返回ndarray的數據類型,如果沒有提供,則會使用輸入數據的類型。 |
numpy.arange 默認從 0 開始生成數組,間隔為 1。
比如,下面代碼會生成一個元素值不超過 4 的數組,即范圍是 [0,4) 。
import numpy as np
# 長度為 4
a = np.arange(4)
print(a)
arange(start, stop) 指定開始結束范圍,但是依然步長為 1。
import numpy as np
# 長度為 4
a = np.arange(1,4)
print(a)
arange(start, stop, step) 自定義設置范圍和步長。
import numpy as np
# 長度為 4
a = np.arange(1,10,3)
print(a)
numpy.linspace
numpy.linspace 可以使用線性間隔的方式生成數組:
np.linspace(0, 10, num=5)
num=5 的含義是從來的之間平均取得 5 個數值。
[ 0.
2.5
5.
7.5
10. ]
但是跟我們預料的結果可能不太一樣,因為 linspace() 是包括起始點的,所以 0-10 其實個數是 11 個。
import numpy as np
# 長度為 4
a = np.linspace(0, 10, num=10)
print(a)
import numpy as np
# 長度為 4
a = np.linspace(0, 10, num=11)
print(a)
數組操作
數組排序
排序會返回數組的副本。
主要排序函數如下:
sort :按照大小排序
argsort:它是沿指定軸的間接排序,
lexsort:它是對多個鍵的間接穩定排序,
searchsorted, 它將查找排序數組中的元素。
partition, 分區,這是一個部分排序。
對于 numpy 的數組,請使用 numpy 的函數排序,不要使用 Python 自帶的函數排序。
import numpy as np
# 長度為 4
a = np.random.rand(10)
print(a)
# 使用 Python 內置函數
print(sorted(a))
# 使用 numpy.sort
print(np.sort(a))
如上圖所示,使用 Python 自帶的函數,會導致精確度出現問題。
切片索引
可以使用 slice(start,stop,step) 函數或 [start:stop:step] 進行切片。
import numpy as np
a = np.arange(10)
print(a)
# 索引范圍是 2-7 ,間隔為2
# [0 1 2 3 4 5 6 7 8 9]
s1 = slice(2, 7, 2)
# 索引范圍是 2-8 ,間隔為2
# [0 1 2 3 4 5 6 7 8 9]
s2 = slice(2, 8, 2)
print(a[s1])
print(a[s2])
等同于:
import numpy as np
a = np.arange(10)
print(a)
print(a[2:7:2])
print(a[2:8:2])
對于二維數組,可以通過坐標點取值。
import numpy as np
x = np.array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[9, 10, 11]])
# 左上角、右上角、左下角、右下角 四個點
a1 = np.array([[0, 0], [3, 3]])
a2 = np.array([[0, 2], [0, 2]])
y = x[a1, a2]
print(y)
[[ 0 2]
[ 9 11]]
取值時,跟一維數組一致,可以通過索引取值。
import numpy as np
x = np.array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[9, 10, 11]])
y = x[1:2]
print(y)
數組還可以通過表達式取值,如 x>5、x<5 等。
import numpy as np
x = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]])
print(x)
print(x[x > 5])
詳細的表達式操作方法,可以查閱官網文檔,這里不再贅述。
數組運算符
numpy 數組,可以通過操作符直接操作。
如兩個數組的值相加:
import numpy as np
a1 = np.array([1, 2, 3])
a2 = np.array([4, 5, 6])
a3 = a1 + a2
a4 = a1 * a2
print(a3)
print(a4)
得到:
[5 7 9]
[ 4 10 18]
廣播規則
對于不同形狀的數組(即維數不同),numpy 可以自動補全維數。
其規則約束如下:
-
兩個數組的形狀相同
-
維數比較少的數組,需要是一維數組。
import numpy as np
a = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
b = np.array([100, 100, 100])
print(a + b)
[ [
[1, 2, 3] + [100, 100, 100]
[4, 5, 6] + [100, 100, 100]
[7, 8, 9] + [100, 100, 100]
] ]
相加后:
[
[101 102 103]
[104 105 106]
[107 108 109]
]
但是要注意,如果兩個數組的一個維中,元素個數不一致,則運算會報錯。
import numpy as np
a1 = np.array([1, 2, 3])
a2 = np.array([4, 5, 6, 7])
a3 = a1 + a2
print(a3)
如果兩個數組維度一致,但是形狀不一樣,維數少的數組必須是一維數組。
如下面代碼會報錯:
import numpy as np
a = np.array([[1, 2, 3],
[1, 1, 1],
[1, 1, 1]])
b = np.array([[1, 1, 1],
[2, 2, 2]])
print(a + b)
修改數組
Numpy 中包含了一些函數用于處理數組,大概可分為以下幾類:
- 修改數組形狀
- 翻轉數組
- 修改數組維度
- 連接數組
- 分割數組
- 數組元素的添加與刪除
修改數組的形狀
主要有以下函數:
| 函數 | 描述 |
|---|---|
reshape |
不改變數據的條件下修改形狀 |
flat |
數組元素迭代器 |
flatten |
返回一份數組拷貝,對拷貝所做的修改不會影響原始數組 |
ravel |
返回展開數組 |
將一維數組,轉換為二維數組,每個數組元素有 3 個,其示例如下:
import numpy as np
a = np.arange(6).reshape(2, 3)
b = np.array([0,1,2,3,4,5]).reshape(2, 3)
print(a)
print(b)
[[0 1 2]
[3 4 5]]
[[0 1 2]
其它幾個函數可以使用以下示例表達:
import numpy as np
a = np.arange(10)
print(a)
# 數組迭代器 .flat
for element in a.flat:
print(element)
# 將數組轉換為二維數組
b = a.reshape(2,5)
print("將數組轉換為二維:")
print(b)
print("將多維數組合并為一維:")
c = b.ravel()
print(c)
[0 1 2 3 4 5 6 7 8 9]
0
1
2
3
4
5
6
7
8
9
將數組轉換為二維:
[[0 1 2 3 4]
[5 6 7 8 9]]
將多維數組合并為一維:
[0 1 2 3 4 5 6 7 8 9]
翻轉數組
其常用函數定義如下:
| 函數 | 描述 |
|---|---|
transpose |
對換數組的維度 |
ndarray.T |
和 self.transpose() 相同 |
rollaxis |
向后滾動指定的軸 |
swapaxes |
對換數組的兩個軸 |
transpose 、ndarray.T 都可以將數組翻轉,例如將 2x5 的數組翻轉為 5x2。
import numpy
import numpy as np
a = np.arange(10).reshape(2,5)
print(a)
b = numpy.transpose(a)
c = a.T
print(b)
print(c)
[[0 1 2 3 4]
[5 6 7 8 9]]
[[0 5]
[1 6]
[2 7]
[3 8]
[4 9]]
[[0 5]
[1 6]
[2 7]
[3 8]
[4 9]]
rollaxis 、swapaxes 都有三個參數:
arr:數組
axis:要向后滾動的軸,其它軸的相對位置不會改變。取值范圍為 [0, a.ndim]
start:默認為零,表示完整的滾動。會滾動到特定位置。取值范圍為 [-a.ndim, a.ndim]
注意:二維只有 0、1 兩個軸,三維有 0、1、2 三個軸。axis、start 都是填寫軸的序號。
使用 print(a1.ndim) 可以打印數組的維數,即軸數。
swapaxes 用于指定交互兩個軸的位置。
如:
import numpy
import numpy as np
a1 = np.array([
[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3]
])
b = np.swapaxes(a1, 0, 1)
print(b)
原數組:
[[0, 0, 0, 0]
[1, 1, 1, 1]
[2, 2, 2, 2]
[3, 3, 3, 3]]
變換后的數組:
[[0 1 2 3]
[0 1 2 3]
[0 1 2 3]
[0 1 2 3]]
也可以理解成坐標系的 x 軸 和 y 軸,x 軸變成了 y 軸。
swapaxes 在更多維數組的情況下,有更多的軸,例如三維的 x、y、z 三個軸。這里不再贅述。
至于 numpy.rollaxis ,我也不會。
修改數組維度
其主要函數如下:
| 維度 | 描述 |
|---|---|
broadcast |
產生模仿廣播的對象 |
broadcast_to |
將數組廣播到新形狀 |
expand_dims |
擴展數組的形狀 |
squeeze |
從數組的形狀中刪除一維條目 |
連接數組
其主要函數如下:
| 函數 | 描述 |
|---|---|
concatenate |
連接沿現有軸的數組序列 |
stack |
沿著新的軸加入一系列數組。 |
hstack |
水平堆疊序列中的數組(列方向) |
vstack |
豎直堆疊序列中的數組(行方向) |
numpy.concatenate 將兩個數組拼接成一個新的數組:
import numpy as np
a = np.array([1, 2, 3, 4])
b = np.array([5, 6, 7, 8])
c = np.concatenate((a, b))
print(c)
分割數組
其主要函數如下:
| 函數 | 數組及操作 |
|---|---|
split |
將一個數組分割為多個子數組 |
hsplit |
將一個數組水平分割為多個子數組(按列) |
vsplit |
將一個數組垂直分割為多個子數組(按行) |
其使用方法比較簡單,這里不再贅述。
增刪數組元素
其主要函數如下:
| 函數 | 元素及描述 |
|---|---|
resize |
返回指定形狀的新數組 |
append |
將值添加到數組末尾 |
insert |
沿指定軸將值插入到指定下標之前 |
delete |
刪掉某個軸的子數組,并返回刪除后的新數組 |
unique |
查找數組內的唯一元素 |
其使用方法比較簡單,這里不再贅述。
數組迭代
前面提到過 .flat 。
import numpy as np
# 這里是二維
a = np.arange(10).reshape(2,5)
# 數組迭代器 .flat
for element in a.flat:
print(element)
.flat 會按照順序打印每一個元素。
0
1
2
3
4
5
6
7
8
9
.nditer 也是如此。
import numpy as np
a = np.arange(10).reshape(2,5)
# 數組迭代器 .flat
for element in np.nditer(a):
print(element)
.nditer 可以控制遍歷規則。
for x in np.nditer(a.T, order='C'),默認,行遍歷。
for x in np.nditer(a, order='F'),列遍歷。
import numpy as np
a = np.arange(10).reshape(2, 5)
# 數組迭代器 .flat
for element in np.nditer(a, order='F'):
print(element)
0
5
1
6
2
7
3
8
4
9
.nditer 可以控制迭代多維數組的維還是元素。
前面提到的代碼,均是迭代逐個元素。
如果設置了 flags 參數,則可以迭代維。
import numpy as np
a = np.arange(10).reshape(2, 5)
# 數組迭代器 .flat
for element in np.nditer(a, order='F', flags=['external_loop']):
print(element)
原數組:
[[0 1 2 3 4]
[5 6 7 8 9]]
按照迭代方向 F:
[0 5]
[1 6]
[2 7]
[3 8]
[4 9]
總結
以上是生活随笔為你收集整理的Python 之 Numpy 框架入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【SLAM建图和导航仿真实例】(一)-
- 下一篇: Java开发者的Python快速进修指南