最後一次更新日期: 2019/4/13
NumPy 是一個 Python 包。 它代表 “Numeric Python”。 它是一個由多維陣列物件(ndarray)和用於處理陣列的例程集合組成的庫。 使用NumPy,開發人員可以執行以下操作:
- 陣列的算數和邏輯運算。
- 傅立葉變換和用於圖形操作的例程。
- 與線性代數有關的操作。 NumPy 擁有線性代數和隨機數生成的內建函式。
使用前先匯入模組:
import numpy as np
點選下方連結可前往各小節
使用指南1 - 屬性 (資料型別,形狀,維數,元素數,元素大小,位元組數,順序)
一. 屬性
1. 資料型別
ndarray.dtype
numpy常用資料型別
dtype | type | 型別名 | 說明 |
---|---|---|---|
np.dtype('bool') | np.bool_ | 布林型別 | True or False |
np.dtype('int8' | 'i1' | 'b') | np.int8 | 8位整數(位元組) | -2^7 to 2^7-1 |
np.dtype('int16' | 'i2') | np.int16 | 16位整數 | -2^15 to 2^15-1 |
np.dtype('int32' | 'i4' | 'int' | 'i') | np.int32 | 32位整數 | -2^31 to 2^31-1 |
np.dtype('int64' | 'i8') | np.int64 | 64位整數 | -2^63 to 2^63-1 |
np.dtype('uint8' | 'u1' | 'B') | np.uint8 | 8位無符號整數 | 0 to 2^8-1 |
np.dtype('uint16' | 'u2') | np.uint16 | 16位無符號整數 | 0 to 2^16-1 |
np.dtype('uint32' | 'u4' | 'uint') | np.uint32 | 32位無符號整數 | 0 to 2^32-1 |
np.dtype('uint64' | 'u8') | np.uint64 | 64位無符號整數 | 0 to 2^64-1 |
np.dtype('float16' | 'f2') | np.float16 | 半精度浮點數 | 1符號位+5指數位+10尾數位 |
np.dtype('float32' | 'f4' | 'f') | np.float32 | 單精度浮點數 | 1符號位+8指數位+23尾數位 |
np.dtype('float64' | 'f8' | 'float' | 'd') | np.float64 | 雙精度浮點數 | 1符號位+11指數位+52尾數位 |
np.dtype('complex64' | 'c8') | np.complex64 | 64位複數 | 雙32位浮點數(實部+虛部) |
np.dtype('complex128' | 'complex' | 'c16') | np.complex128 | 128位複數 | 雙64位浮點數(實部+虛部) |
np.dtype('object' | 'O') | object | 物件 | 可用於儲存引用型別 |
np.dtype('string_' | 'S' | 'S1' | 'S2' ...) | np.bytes_ | 定長字串 | 需要宣告長度 |
np.dtype('unicode' | 'U' | 'U1' | 'U2' ...) | np.str_ | 定長Unicode字串 | 需要宣告長度 |
np.dtype('datetime64' | 'M') | np.datetime64 | 日期時間 | 可指定日期單位 |
注:同一種dtype可以通過多種字串標識去宣告的,見 | 分割的多項。
python的基本資料型別可被numpy識別,轉換為對應類別下的預設型別,int
對應np.int32
,float
對應np.float64
,complex
對應np.complex128
。
dtype與type的轉換
獲取dtype的type:dtype.type
通過type建立dtype:dtype(type)
dtype與type可以直接進行比較
np.dtype('int')==np.int32
dtype的位元組順序
np.dtype('<i8')
位元組順序是通過對資料型別預先設定"<"或">"來決定的。"<"意味著小端法(最小值儲存在最小的地址,即低位組放在最前面)。">"意味著大端法(最重要的位元組儲存在最小的地址,即高位組放在最前面)。一般情況下采用預設設定即可。
2. 元素個數
ndarray.size
3. 元素的子節大小
ndarray.itemsize
由資料型別決定,每8位為1位元組。
4. 總位元組數
ndarray.nbytes
由size和itemsize計算得到。
5. 維數
ndarray.ndim
ndarray的每一個維度被描述為軸(axis),維數即軸的個數,軸的編號從0開始。
6. 形狀
ndarray.shape
tuple型別,每一位對應到每個軸,例如0軸方向長為10個元素,1軸方向長為5個元素的陣列形狀為(10,5)
。
7. 記憶體佈局
numpy有兩種資料儲存的方式,一種是C-order,即行序優先,另一種是Fortran-order,即列序優先,未顯式指定時預設C-order。由於內部的優化機制,多數情況下兩者在使用時沒有明顯區別,一般不需要更改預設設定。
但在使用諸如迭代器之類的方法時,可通過order
引數指定元素訪問順序,其中'C'指代C-order,'F'指代F-order。
二. 建立
1. 從已有資料建立
(1). 從list建立
#一維陣列
a1=np.array([1,2])
#二維陣列
a2=np.array([[1.,2.],[3.,4.]])
#三維陣列
a3=np.array([[[1,2],[3,4]],[[5,6],[7,8]]],dtype='float')
#以此類推
複製程式碼
從巢狀的序列結構建立多維陣列時,最外面的一層對應陣列第一個軸,以此類推。
第二個引數dtype
可以顯式宣告陣列的資料型別,可傳入dtype
或type
(python基礎資料型別或numpy資料型別)或與dtype
對應的字串標識,不宣告的情況下會根據傳入資料自動採用最合適的資料型別。
(2). 從tuple建立
a=np.array((1,2))
複製程式碼
與list
是一樣,list
與tuple
的巢狀同理。
(3). 從dict建立(不合適)
In [138]: np.array({"x1":1,"x2":2})
Out[138]: array({'x1': 1, 'x2': 2}, dtype=object)
複製程式碼
無法正常轉換,整個dict
會作為一個物件存入陣列,可以嘗試用pandas庫去處理。
(4). 從其他類陣列結構中建立,如PIL的圖片型別
from PIL import Image
image= Image.open("D:\\test.jpg")
a=np.asarray(image)
複製程式碼
np.asarray
在多數情況下與np.array
等效,區別在於np.asarray
會避免沒有必要的重複建立,當資料來源同樣是ndarray
且dtype
無變化時,不會返回新的陣列。
2. 快速填充
(1). 0/1填充
#填充0
a1=np.zeros((2,2))
#填充1
a2=np.ones((2,2))
#宣告型別
a2=np.ones((2,2),dtype='int')
複製程式碼
第一個引數shape
為陣列形狀,必須賦值;
預設資料型別為float64
,可通過dtype
引數指定型別。
(2). 對角矩陣
In [151]: np.eye(3,3,0)
Out[151]:
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
In [150]: np.eye(3,3,1)
Out[150]:
array([[ 0., 1., 0.],
[ 0., 0., 1.],
[ 0., 0., 0.]])
複製程式碼
第一個引數N
為0軸長度,必須賦值;
第二個引數M
為1軸長度,不賦值時與N
值一致;
第一個引數k
為對角線偏移量,預設0,正數向上偏移,負數向下偏移。
對角矩陣固定為二維陣列。
(3).單位矩陣
In [5]: np.identity(1)
Out[5]: array([[ 1.]])
In [6]: np.identity(2)
Out[6]:
array([[ 1., 0.],
[ 0., 1.]])
複製程式碼
第一個引數n
為統一的軸長度,必須賦值;
單位矩陣固定為二維陣列。
(4). 指定值填充
a=np.full((2,2),'a')
複製程式碼
第一個引數shape
為陣列形狀,必須賦值;
第二個引數fill_value
為填充值,必須賦值。
(5). 空值填充
a=np.empty((2,2))
複製程式碼
第一個引數shape
為陣列形狀,必須賦值。
建立一個陣列,但不初始化其中的值。
(6). 參考已有陣列形狀建立
a=np.ones((2,2))
a2=np.zeros_like(a)
a3=np.full_like(a,'a')
複製程式碼
(7). 等差數列
#方法一
a1=np.arange(0,100,1)
#方法二
a2=np.linspace(0,99,100)
複製程式碼
方法一,類似range
函式,預設int
型別,
三個引數分別為:開始,結束,步長(區間前閉後開);
方法二,線性空間,預設float
型別,
和range
不一樣,結束值預設是包含於區間的,
且第三個引數不是步長而是元素個數。
(8). 隨機數
浮點數隨機數
#[0,1]浮點隨機數
a1=np.random.rand(5,5)
#標準正太分佈隨機數
a2=np.random.randn(5,5)
複製程式碼
需要注意的是,上面的方法不通過shape
而通過全部引數來定義陣列形狀。
整數隨機數
#產生指定範圍的整數隨機數
a=np.random.randint(0,10,(4,3))
複製程式碼
第一個引數low
表示區間下限,必須賦值;
第二個引數high
表示區間上限,未賦值時會將low
作為上限,0作為下限;
第三個引數size
表示陣列形狀,未賦值時函式會返回標量值。
正態分佈隨機數
a=np.random.normal(100,10,(4,3))
複製程式碼
第一個引數loc
表示分佈的平均值;
第二個引數scale
表示分佈的標準偏差;
第三個引數size
表示陣列形狀,未賦值時函式會返回標量值。
均勻分佈隨機數
a=np.random.uniform(0,10,(4,3))
複製程式碼
第一個引數low
表示區間下限,必須賦值;
第二個引數high
表示區間上限,未賦值時會將low
作為上限,0作為下限;
第三個引數size
表示陣列形狀,未賦值時函式會返回標量值。
泊松分佈隨機數
a=np.random.poisson(1.0,(4,3))
複製程式碼
第一個引數lam
是lambda係數;
第二個引數size
表示陣列形狀,未賦值時函式會返回標量值。
(9). 網格資料
In [26]: X,Y=np.mgrid[1:2:2j,1:3:3j]
In [27]: X
Out[27]:
array([[ 1., 1., 1.],
[ 2., 2., 2.]])
In [28]: Y
Out[28]:
array([[ 1., 2., 3.],
[ 1., 2., 3.]])
In [33]: x=np.array([1,2,3])
In [34]: y=np.array([1,2])
In [35]: X,Y=np.meshgrid(x,y)
In [36]: X
Out[36]:
array([[1, 2, 3],
[1, 2, 3]])
In [37]: Y
Out[37]:
array([[1, 1, 1],
[2, 2, 2]])
複製程式碼
np.mgrid
通過索引選取的方式直接獲得網格資料,j
表示步數且包含停止值,去掉j
該項代表步長且不包含停止值,第一個索引位宣告X
在軸0方向上的增長,第二個索引位宣告Y
在軸1方向上的增長,然後將X
和Y
廣播至相同大小,存在更多索引位時以此類推。
np.meshgrid
在已有資料基礎上構造網格資料,跟mgrid
不一樣,第一個引數是表示第二個軸方向上增長的向量,第二個引數對應第一個軸,第三個引數對應第三個軸,第四個引數對應第四個軸,之後以此類推。
網格資料常用於繪圖。
(10). 複製
a1=np.zeros((2,2))
a2=np.copy(a1)
複製程式碼
三. 運算
1. 運算子
numpy對python中的運算子作了過載,可通過同樣的用法實現陣列運算。
陣列與標量值的運算
In [191]: a=np.arange(0, 4)
In [192]: a
Out[192]: array([0, 1, 2, 3])
In [193]: a+1
Out[193]: array([1, 2, 3, 4])
In [193]: a*2
Out[194]: array([0, 2, 4, 6])
複製程式碼
陣列與陣列的運算
In [199]: a1=np.arange(0, 4);a2=np.arange(4, 8)
In [200]: a1,a2
Out[200]: (array([0, 1, 2, 3]), array([4, 5, 6, 7]))
In [201]: a1+a2
Out[201]: array([ 4, 6, 8, 10])
In [202]: a2**a1
Out[202]: array([ 1, 5, 36, 343], dtype=int32)
複製程式碼
2. 標量值函式
標量值函式會對陣列中每一個元素進行同樣的計算。
一元函式
函式 | 作用 | 說明 |
---|---|---|
np.abs | 絕對值 | 計算浮點數/整數/複數的絕對值 |
np.fabs | 絕對值 | 計算浮點數/整數的絕對值,速度更快(?) |
np.sqrt | 平方根 | x^0.5 |
np.square | 平方 | x^2 |
np.log | 自然對數 | - |
np.log2 | 2為底的對數 | - |
np.log10 | 10為底的對數 | |
np.log1p | x+1的自然對數 | 用於數值過小時保證計算的有效性 |
np.ceil | 向上取整 | - |
np.floor | 向下取整 | - |
np.rint | 舍入取整 | - |
np.around | 舍入指定位數 | 第二個引數decimals 為舍入位數 |
np.exp | 自然指數 | e^x |
np.sign | 符號值 | 三種值:1(正)、0(0)、-1(負) |
np.modf | 拆分小數和整數部分 | 以兩個獨立的陣列方式返回 |
np.isnan | 判斷是否為NaN | 返回bool型陣列 |
np.isfinite | 判斷是否是有窮 | 值非inf,非NaN;返回bool型陣列 |
np.isinf | 判斷是否是有窮 | 值為inf或-inf;返回bool型陣列 |
np.sin,np.sinh | 正弦,雙曲正弦 | - |
np.cos,np.cosh | 餘弦,雙曲餘弦 | - |
np.tan,np.tanh | 正切,雙曲正切 | - |
np.arcsin,np.arcsinh | 反正弦,反雙曲正弦 | - |
np.arccos,np.arccosh | 反餘弦,反雙曲餘弦 | - |
np.arctan,np.arctanh | 反正切,反雙曲正切 | - |
np.logical_not | 邏輯非 | - |
多元函式
函式 | 作用 | 說明 |
---|---|---|
np.add(a1,a2) | 相加 | a1+a2 |
np.sub(a1,a2) | 相減 | a1-a2 |
np.multiply(a1,a2) | 相乘 | a1*a2 |
np.divide(a1,a2) | 相除 | a1/a2 |
np.power(a1,a2) | 乘冪 | a1**a2 |
np.floor_divide(a1,a2) | 整除 | a1//a2 |
np.mod(a1,a2) | 取模 | a1%a2 |
np.maxinum(a1,a2,a3) | 最大值 | 逐個元素進行比較,返回全部最大值的陣列 |
np.fmax(a1,a2,a3) | 最大值(忽略NaN) | 逐個元素進行比較,返回全部最大值的陣列 |
np.mininum(a1,a2,a3) | 最小值 | 逐個元素進行比較,返回全部最小值的陣列 |
np.fmin(a1,a2,a3) | 最小值(忽略NaN) | 逐個元素進行比較,返回全部最小值的陣列 |
np.copysign(a1,a2) | 複製符號 | 將a2的符號複製到a1中 |
np.greater(a1,a2) | 大於 | a1>a2 |
np.greater_equal(a1,a2) | 大於等於 | a1>=a2 |
np.less(a1,a2) | 小於 | a1<a2 |
np.less_equal(a1,a2) | 小於等於 | a1<=a2 |
np.equal(a1,a2) | 等於 | a1==a2 |
np.not_equal(a1,a2) | 不等於 | a1!=a2 |
np.logical_and(a1,a2) | 邏輯與 | - |
np.logical_or(a1,a2) | 邏輯或 | - |
np.logical_xor(a1,a2) | 邏輯異或 | - |
3. 聚合函式
聚合函式會減少陣列的維數,通常可以指定一個軸方向axis
進行聚合,結果陣列會減少一個維度,不指定方向時會在所有軸方向上聚合,結果為一個標量值。
大多數既可以靜態呼叫,也可以直接呼叫ndarray物件的方法。
函式 | 作用 | 說明 |
---|---|---|
np.sum | 求和 | - |
np.mean | 平均值 | - |
np.max | 最大值 | - |
np.min | 最小值 | - |
np.prod | 連乘 | - |
np.any | 至少一個為True | 返回True/False |
np.all | 全部為True | 返回True/False |
np.max
和np.min
有對應的np.argmax
和np.argmin
的方法用於返回索引,詳見查詢章節。
(以下是部分示例)
np.sum
In [313]: a=np.array([[1,3],[4,2]])
In [314]: a
Out[314]:
array([[1, 3],
[4, 2]])
In [315]: a.sum()
Out[315]: 10
In [316]: a.sum(axis=0)
Out[316]: array([5, 5])
In [317]: a.sum(axis=1)
Out[317]: array([4, 6])
複製程式碼
np.all
In [322]: a=np.array([[True,False],[True,True]])
In [323]: a
Out[323]:
array([[ True, False],
[ True, True]], dtype=bool)
In [324]: a.all()
Out[324]: False
In [325]: a.all(axis=0)
Out[325]: array([ True, False], dtype=bool)
複製程式碼
4. 複合統計函式
函式 | 作用 | 說明 |
---|---|---|
np.cumsum | 累加 | - |
np.cumprod | 累乘 | - |
np.std | 標準差 | ((a-a.mean())**2).sum()/a.size |
np.var | 方差 | np.sqrt(((a-a.mean())**2).sum()/a.size) |
np.average | 加權平均數 | 第三個引數weights 為權重;ndarray無對應方法 |
np.bincount | 分箱計數 | 只支援整數,分箱區間根據最大最小值自動生成,間隔為1 |
np.histogram | 直方圖統計 | 第二個引數bins 指定分箱方式,比np.bincount 更靈活 |
(以下是部分示例)
np.cumsum
In [317]: a=np.array([[1,3],[4,2]])
In [319]: a.cumsum()
Out[319]: array([ 1, 4, 8, 10], dtype=int32)
In [320]: a.cumsum(axis=0)
Out[320]:
array([[1, 3],
[5, 5]], dtype=int32)
複製程式碼
np.average
In [331]: a=np.array([[1,3],[4,2]])
In [332]: w=np.array([[0.4,0.1],[0.2,0.3]])
In [333]: np.average(a)
Out[333]: 2.5
In [334]: np.average(a,weights=w)
Out[334]: 2.1000000000000001
複製程式碼
5. 字串函式
函式 | 作用 | 說明 |
---|---|---|
np.char.add | 字串相加 | 逐個元素執行字串相加 |
np.char.multiply | 字串重複 | 第二個引數i 為重複次數 |
np.char.center | 字串居中 | 第二個引數width 為長度,第三個引數fillchar 為填充字元 |
np.char.capitalize | 首字母大寫 | - |
np.char.title | 單詞首字母大寫 | - |
np.char.lower | 轉換為小寫 | - |
np.char.upper | 轉換為大寫 | - |
np.char.split | 字串分割 | 第二個引數sep 為分隔符,返回list陣列 |
np.char.splitlines | 行分割 | 以換行符分割,返回list陣列 |
np.char.strip | 移除頭尾指定字元 | 第二個引數chars 為需要移除的字元 |
np.char.join | 以指定分隔符拼接字元 | 第一個引數sep 為分隔符 |
np.char.replace | 替換字串 | 第二個引數old 為舊字串,第三個引數new 為新字串 |
np.char.decode | 解碼 | 對每個元素呼叫str.decode |
np.char.encode | 編碼 | 對每個元素呼叫str.encode |
(以下是部分示例)
np.char.add
In [301]: a1=np.array(['a','b']);a2=np.array(['c','d'])
In [302]: np.char.add(a1,a2)
Out[302]:
array(['ac', 'bd'],
dtype='<U2')
複製程式碼
np.char.multiply
In [303]: a=np.array(['a','b'])
In [304]: np.char.multiply(a,3)
Out[304]:
array(['aaa', 'bbb'],
dtype='<U3')
複製程式碼
np.char.center
In [305]: a=np.array(['a','b'])
In [306]: np.char.center(a,10,'*')
Out[306]:
array(['****a*****', '****b*****'],
dtype='<U10')
複製程式碼
np.char.split
In [307]: a=np.array(['a,b','c,d'])
In [308]: np.char.split(a,',')
Out[308]: array([list(['a', 'b']), list(['c', 'd'])], dtype=object)
複製程式碼
np.char.join
In [309]: a=np.array(['ab','cd'])
In [310]: np.char.join(',',a)
Out[310]:
array(['a,b', 'c,d'],
dtype='<U3')
In [311]: a=np.array(['a,b','c,d'])
In [312]: np.char.join(',',np.char.split(a,','))
Out[312]:
array(['a,b', 'c,d'],
dtype='<U3')
複製程式碼
注意,該方法無法實現多維陣列的聚合計算。在陣列元素為字串時,會對字串中的每個元素進行拼接;在陣列元素為字串序列時,會對序列中的字串進行拼接。 與split互為逆運算。
6. 線性代數運算
函式 | 作用 | 說明 |
---|---|---|
np.dot(a1,a2) | 點乘 | 多維陣列下會將a1的最後一個軸和a2的倒數第二個軸作為向量的維度,可視作向量的棧 |
np.vdot(a1,a2) | 向量點乘 | 高維陣列會被展開計算 |
np.inner(a1,a2) | 向量內積 | 多維陣列會將最後一個軸作為向量的維度 |
np.matmul(a1,a2) | 矩陣乘積 | 多維陣列下會將最後兩個軸作為矩陣的維度,可視作元素是矩陣的陣列 |
np.linalg.det(a) | 行列式 | 行列式描述的是矩陣所表示的線性變換對“體積”的影響 |
np.linalg.solve(A,b) | 求解線性方程組 | 求解線性方程組Ax = b,A為係數矩陣(方陣),b為常數矩陣 |
np.linalg.lstsq(A,b) | 求解線性方程組 | 求線性方程組Ax = b的最小二乘解,A為係數矩陣,b為常數矩陣 |
np.linalg.inv(a) | 逆矩陣 | AB=BA=E,E為單位矩陣,則B為A的逆矩陣 |
np.linalg.pinv(a) | 廣義逆矩陣 | 可以輸入非方陣 |
np.linalg.eig(a) | 特徵值和特徵向量 | 返回兩個陣列 |
np.linalg.qr(a) | 正交分解 | - |
np.linalg.svd(a) | 奇異值分解 | - |
ndarray.T | 轉置 | 對一維陣列轉置是無效的 |
(以下是部分示例)
np.dot, np.vdot, np.inner, np.matmul
In [339]: a=np.array([1,2]);b=np.array([[3,4],[5,6]])
In [340]: np.dot(a,a), np.vdot(a,a), np.inner(a,a), np.matmul(a,a)
Out[340]: (5, 5, 5, 5)
In [341]: np.dot(a,b), np.dot(b,a)
Out[341]: (array([13, 16]), array([11, 17]))
In [342]: np.vdot(a,b)
Traceback (most recent call last):
File "<ipython-input-358-f2388a21d848>", line 1, in <module>
np.vdot(a,b)
ValueError: cannot reshape array of size 4 into shape (2,)
In [343]: np.inner(a,b), np.inner(b,a)
Out[343]: (array([11, 17]), array([11, 17]))
In [344]: np.matmul(a,b), np.matmul(b,a)
Out[344]: (array([13, 16]), array([11, 17]))
In [345]: np.dot(b,b)
Out[345]:
array([[29, 36],
[45, 56]])
In [346]: np.vdot(b,b)
Out[346]: 86
In [347]: np.inner(b,b)
Out[347]:
array([[25, 39],
[39, 61]])
In [348]: np.matmul(b,b)
Out[348]:
array([[29, 36],
[45, 56]])
複製程式碼
這四個方法執行的運算都基於向量內積,非常相似,但在具體行為上有區別,很容易混淆。
dot
是將陣列看作向量的集合,第一個陣列的最後一個軸和第二個陣列的倒數第二個軸作為向量的軸,抽取每個向量兩兩匹配進行點積運算,因此這兩個軸需要長度一致。例如,a.shape=(2,3,4)
,b.shape=(5,4,6)
,則np.dot(a,b).shape=(2,3,5,6)
。在二維情況下,實現的計算即是矩陣乘法。
vdot
的規則比較簡單,會將陣列展開為向量再計算點積,要求陣列的size
一致。
inner
與dot
類似,但規則更簡單,兩個陣列均以最後一個軸作為向量的軸,即最後一個軸長度要保持一致。例如,a.shape=(2,3,4)
,b.shape=(5,6,4)
,則np.dot(a,b).shape=(2,3,5,6)
。
matmul
的計算針對矩陣,和dot
一樣在二維情況下表示矩陣乘法,二維以上視作元素為矩陣的陣列,參與運算的兩個陣列均以最後兩個軸作為矩陣的軸,逐個元素進行矩陣乘法並向其他軸方向上廣播。例如,a.shape=(1,3,4)
,b.shape=(5,4,6)
,則np.dot(a,b).shape=(5,3,6)
,如果a.shape=(2,3,4)
,計算就會報錯,因為不滿足廣播的規則。
7. 集合運算
函式 | 作用 | 說明 |
---|---|---|
np.intersect1d(x, y) | 交集 | x 和y 的公共元素 |
np.union1d(x, y) | 並集 | x 和y 的所有元素 |
np.setdiff1d(x, y) | 集合差 | x 中存在,y 中不存在的元素 |
np.setxor1d(x, y) | 集合異或 | x 和y 的獨佔元素 |
以上方法適用於一維陣列。
(以下是部分示例)
In [810]: x=np.array([1,3,4])
In [811]: y=np.array([2,3,5])
In [812]: np.intersect1d(x,y)
Out[812]: array([3])
In [813]: np.union1d(x,y)
Out[813]: array([1, 2, 3, 4, 5])
In [814]: np.setdiff1d(x,y)
Out[814]: array([1, 4])
In [815]: np.setxor1d(x,y)
Out[815]: array([1, 2, 4, 5])
複製程式碼
8. 位運算
函式 | 作用 | 說明 |
---|---|---|
np.invert | 按位取反 | 等效於~ 運算子 |
np.bitwise_and | 按位與 | 等效於& 運算子 |
np.bitwise_or | 按位或 | 等效於\| 運算子 |
np.bitwise_xor | 按位異或 | 等效於^ 運算子 |
np.left_shift | 位左移 | 等效於<< 運算子 |
np.right_shift | 位右移 | 等效於>> 運算子 |
(以下是部分示例)
In [858]: a=np.array([2,3,5,8,13])
In [859]: b=np.array([3,4,7,11,18])
In [860]: np.invert(a)
Out[860]: array([ -3, -4, -6, -9, -14], dtype=int32)
In [862]: bin(a[4]),bin(~a[4])
Out[862]: ('0b1101', '-0b1110')
In [863]: np.bitwise_and(a,b)
Out[863]: array([2, 0, 5, 8, 0], dtype=int32)
bin(a[3]),bin(b[3]),bin(a[3]&b[3])
Out[865]: ('0b1000', '0b1011', '0b1000')
複製程式碼
np.invert
對於有符號整數,取對應二進位制數的補碼,然後 +1。二進位制數形式的最高位為0表示正數,最高位為 1 表示負數。
9. 廣播
numpy在進行不同形狀的陣列之間的計算時,會自動沿長度不足且長度為1的軸方向進行廣播。當維數不一致時,會向前補齊,這要求後面的軸長度相同或是有一方長度等於1,即從後至前進行軸長比對,例如形狀(a,b,c)與(b,c)可計算,(a,b,c)與(b,1)可計算,(a,b,c)與(a,b,1)可計算,(a,b,c)與(a,b)不可計算,(a,b,c)與(a,c,b)不可計算。
In [414]: a1=np.zeros((2,3,4))
...: a2=np.random.randint(0,10,(3,4))
...: a3=np.random.randint(0,10,(2,3))
...: a4=np.random.randint(0,10,(2,3,1))
In [418]: a1+a2
Out[418]:
array([[[ 3., 6., 0., 6.],
[ 9., 6., 3., 4.],
[ 2., 3., 1., 5.]],
[[ 3., 6., 0., 6.],
[ 9., 6., 3., 4.],
[ 2., 3., 1., 5.]]])
In [419]: a1+a3
Traceback (most recent call last):
File "<ipython-input-419-d778f9717621>", line 1, in <module>
a1+a3
ValueError: operands could not be broadcast together with shapes (2,3,4) (2,3)
In [420]: a1+a4
Out[420]:
array([[[ 0., 0., 0., 0.],
[ 9., 9., 9., 9.],
[ 1., 1., 1., 1.]],
[[ 4., 4., 4., 4.],
[ 0., 0., 0., 0.],
[ 2., 2., 2., 2.]]])
複製程式碼
10. 常量
屬性名 | 常量名 | 值 |
---|---|---|
np.e | 自然指數 | 2.718281828459045 |
np.pi | 圓周率 | 3.141592653589793 |
np.euler_gamma | 尤拉常數 | 0.5772156649015329 |
np.inf | 無窮大 | - |
np.nan | 非數值 | - |
四. 查詢
1. 索引
通過ndarray[index1,index2...]
的形式指定索引。
(1). 定位元素
In [452]: a=np.array([[1,2],[3,4]])
In [453]: a[1,1]
Out[453]: 4
複製程式碼
(2). 資料切片
In [454]: a[:,1]
Out[454]: array([2, 4])
In [455]: a[0:1,:]
Out[455]: array([[1, 2]])
複製程式碼
通過low:high
的形式限定索引範圍,區間前閉後開,上下限留空表示不限制。
標量值索引會使對應維度消失,範圍索引則不會。
(3). 倒序索引
In [457]: a[-1,:-1]
Out[457]: array([3])
複製程式碼
-n
表示倒數第n個。
(4). 按步長選取
In [458]: a[0:2:2]
Out[458]: array([[1, 2]])
複製程式碼
通過low:high:step
的形式限定索引範圍和步長。
(5). 序列反轉
In [459]: a[::-1]
Out[459]:
array([[3, 4],
[1, 2]])
複製程式碼
等效於a[-1:-len(a)-1:-1]
。
(6). 布林索引
In [460]: a>2
Out[460]:
array([[False, False],
[ True, True]], dtype=bool)
In [461]: (a>2)&(a<4)
Out[461]:
array([[False, False],
[ True, False]], dtype=bool)
In [462]: a[(a>2)&(a<4)]
Out[462]: array([3])
複製程式碼
對ndarray
應用邏輯運算子會得到布林索引,布林索引標識了每個元素符合邏輯判斷條件的情況,使用該索引篩選陣列將得到所有滿足條件的元素構成的一維陣列。
(7). 陣列索引
In [463]: a[[0,1],[1]]
Out[463]: array([2, 4])
In [464]: a[[0,1],[1,0]]
Out[464]: array([2, 3])
複製程式碼
將對應軸上需要選取的索引以陣列形式傳入,當在多個軸上傳入陣列索引時,索引會被一一對應。支援list,tuple,ndarray,支援倒序索引。
(8). 綜合示例
獲取第二列大於2的行的第一列
In [465]: a[a[:,1]>2,0]
Out[465]: array([3])
複製程式碼
獲取二維陣列的頂角元素
In [466]: a[[0,-1]][:,[0,-1]]
Out[466]:
array([[1, 2],
[3, 4]])
In [467]: a[[0,0,-1,-1],[0,-1,0,-1]].reshape((2,2))
Out[467]:
array([[1, 2],
[3, 4]])
複製程式碼
此處使用的reshape
重塑方法會在重構章節講到。
(9). 獲取布林索引指示的位置
In [473]: a>2
Out[473]:
array([[False, False],
[ True, True]], dtype=bool)
In [474]: np.where(a>2)
Out[474]: (array([1, 1], dtype=int64), array([0, 1], dtype=int64))
In [476]: a[np.where(a>2)]
Out[476]: array([3, 4])
In [477]: np.where(a>2,a,-a)
Out[477]:
array([[-1, -2],
[ 3, 4]])
複製程式碼
只輸入陣列時,內部會呼叫nonzero
方法,返回值為一個tuple
,包含每個軸上的索引值序列。
通過第二個引數x
和第三個引數y
,可以根據是否滿足條件對元素進行不同的計算,返回同樣形狀的陣列。
(10). 特定值查詢
指定值序列
In [655]: a=np.arange(5)
In [656]: np.isin(a,[3,4])
Out[656]: array([False, False, False, True, True], dtype=bool)
複製程式碼
第二個引數test_elements
為指定值序列,返回布林索引。
值排序搜尋
In [683]: a=np.array([1,3,5,7,9])
In [684]: np.searchsorted(a,[3,6])
Out[684]: array([1, 3], dtype=int64)
複製程式碼
第一個引數a
為升序一維陣列,非升序可通過第四個引數指定排序sorter=np.argsort(a)
,第二個引數v
為需要被插入a
的值或值序列,第三個引數side
為判斷方式,'left'
表示a[i-1] < v <= a[i]
,'right'
表示a[i-1] <= v < a[i]
。該方法將逐個搜尋v的每個元素在升序陣列a中合適的插入位置,返回陣列索引。
空值
In [661]: a=np.array([np.nan,1,2,3])
In [662]: np.isnan(a)
Out[662]: array([ True, False, False, False], dtype=bool)
複製程式碼
返回布林索引。
(11). 返回索引的方法
函式 | 作用 | 說明 |
---|---|---|
np.argsort | 返回排序後索引 | - |
np.argmax | 返回最大值索引 | - |
np.argmin | 返回最小值索引 | - |
np.argpartition | 返回分割槽索引 | 第二個引數kth 指定用於分割槽的元素索引 |
np.argwhere | 返回符合條件的值索引 | 和np.where 類似,但返回值的形式不太適合索引 |
np.where | 返回符合條件的值索引 | - |
np.isin | 返回判斷元素是否在指定列表中的布林索引 | 第二個引數test_elements 為指定的值序列 |
np.isnan | 返回判斷元素是否nan值的布林索引 | - |
np.searchsorted | 返回待插入值在升序序列中的插入位置 | 第一個引數a 為升序一維陣列,第二個引數v 為待插入值 |
np.digitize | 返回分箱後的索引 | 第二個引數bins 指定分箱方式 |
2. 遍歷
(1). 序列結構遍歷
a=np.array([[1,2],[3,4]])
for buf1 in a:
for buf2 in buf1:
print(buf2)
複製程式碼
(2). 索引遍歷
for i in range(a.shape[0]):
for j in range(a.shape[1]):
print(a[i,j])
複製程式碼
以上兩種方法在遍歷元素時,維數是多少就要巢狀多少層迴圈,效率不算高,但可以在每一層迴圈中嵌入額外的計算。
(3). 快速迭代器遍歷
for item in np.nditer(a):
print(item)
複製程式碼
預設選擇元素的順序是和陣列記憶體佈局一致的,而不是使用標準C或者Fortran順序。這是為了使用效率而設計的,這反映了預設情況下只需訪問每個元素,而無需考慮其特定順序。可通過order
引數來指定特定的順序來訪問陣列。
(4). 平鋪迭代器遍歷
for item in a.flat:
print(item)
複製程式碼
將陣列轉換為1-D的迭代器。
3. 抽樣
(1). 無放回抽樣
In [506]: a=np.array([[1,2],[3,4]])
In [507]: idx=np.random.choice(np.arange(a.shape[0]),size=1,replace=False)
In [508]: a[idx]
Out[508]: array([[3, 4]])
複製程式碼
(2). 有放回抽樣
In [511]: idx=np.random.randint(0,a.shape[0],size=3)
In [512]: a[idx]
Out[512]:
array([[1, 2],
[3, 4],
[1, 2]])
複製程式碼
也可使用np.random.choice(np.arange(a.shape[0]),size=3)
生成索引。
以上都是在單個軸方向上抽樣,如果想在多個軸方向上抽樣,由於抽樣後必然會破壞陣列結構,建議先將用於抽樣的軸展開,比如用reshape
方法,見下面的示例,關於reshape
方法的說明在重構章節。
(3). 多軸方向抽樣
In [524]: a=np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
In [525]: a2=a.reshape((2,4))
In [526]: idx=np.random.randint(0,a2.shape[0],size=2)
In [527]: a2[:,idx]
Out[527]:
array([[1, 2],
[5, 6]])
複製程式碼
4. 檢視
在對陣列進行了索引切片後,返回的通常是原陣列的一個檢視,不會完整的拷貝資料,因此在這種情況下進行更新操作會影響到原陣列和所有檢視。
可通過ndarray.view()
方法獲得一個完整檢視,等效於ndarray[:,:,...]
。
想將檢視轉換為拷貝可使用ndarray.copy()
方法。
In [542]: a=np.array([[1,2],[3,4]])
In [543]: a2=a[1,:]
In [544]: a2
Out[544]: array([3, 4])
In [545]: a2[:]=0
In [546]: a
Out[546]:
array([[1, 2],
[0, 0]])
複製程式碼
五. 變更
1. 更新
(1). 更新整個陣列
In [555]: a=np.array([[1,2],[3,4]])
In [556]: a=a+1
In [557]: a
Out[557]:
array([[2, 3],
[4, 5]])
In [558]: a[:,:]=a-1
In [559]: a
Out[559]:
array([[1, 2],
[3, 4]])
複製程式碼
兩種方式都能更新整個陣列,第一種將計算得到的新陣列的引用重新賦給了a,第二種根據計算得到的新陣列更新了原陣列中相應位置的值。
(2). 更新指定位置
In [569]: a[a>2]+=1
In [570]: a
Out[570]:
array([[1, 2],
[4, 5]])
In [571]: a[a>2]=a[a>2]+1
In [572]: a
Out[572]:
array([[1, 2],
[5, 6]])
In [573]: a[0,:]=0
In [574]: a
Out[574]:
array([[0, 0],
[5, 6]])
In [575]: a[a>2]=[3,4]
In [576]: a
Out[576]:
array([[0, 0],
[3, 4]])
複製程式碼
值陣列形狀需要與篩選後的原陣列一致或遵循廣播的規則。
(3). 定值填充
In [9]: a.fill(1)
In [10]: a
Out[10]:
array([[1, 1],
[1, 1]])
複製程式碼
當填充值資料型別與陣列資料型別不一致時,會嘗試轉換,失敗時才會報錯。
2. 擴增
(1). 插入
In [577]: a=np.array([[1,2],[3,4]])
In [578]: np.insert(a,1,[5,6],axis=0)
Out[578]:
array([[1, 2],
[5, 6],
[3, 4]])
複製程式碼
第二個引數obj
是插入的位置索引,第三個引數values
是待插入的值,需要與指定軸方向上的切片形狀一致或滿足廣播規則,第四個引數axis
是指定的軸。不影響原陣列,返回的是一個拷貝。
(2). 附加
In [578]: np.append(a,[[5,6]],axis=0)
Out[578]:
array([[1, 2],
[3, 4],
[5, 6]])
複製程式碼
第二個引數values
是待插入的值,需要與指定軸方向上的切片形狀一致或滿足廣播規則,第三個引數axis
是指定的軸。只能將新資料附加到陣列末尾。不影響原陣列,返回的是一個拷貝。
(3). 堆疊
In [589]: np.c_[a,a]
Out[589]:
array([[1, 2, 1, 2],
[3, 4, 3, 4]])
In [590]: np.column_stack((a,a))
Out[590]:
array([[1, 2, 1, 2],
[3, 4, 3, 4]])
In [591]: np.concatenate((a,a),axis=1)
Out[591]:
array([[1, 2, 1, 2],
[3, 4, 3, 4]])
In [592]: np.r_[a,a]
Out[592]:
array([[1, 2],
[3, 4],
[1, 2],
[3, 4]])
In [593]: np.row_stack((a,a))
Out[593]:
array([[1, 2],
[3, 4],
[1, 2],
[3, 4]])
In [594]: np.concatenate((a,a),axis=0)
Out[594]:
array([[1, 2],
[3, 4],
[1, 2],
[3, 4]])
In [595]: np.stack((a,a),axis=0)
Out[595]:
array([[[1, 2],
[3, 4]],
[[1, 2],
[3, 4]]])
複製程式碼
np.c_
和np.column_stack
是沿軸1進行堆疊,其他軸長度需要相同或滿足廣播規則,等效於np.concatenate(axis=1)
。
np.r_
和np.row_stack
是沿軸0進行堆疊,其他軸長度需要相同或滿足廣播規則,等效於np.concatenate(axis=0)
。
np.stack
是沿新軸進行堆疊,所有軸長度需要相同或滿足廣播規則。
(4). 重複
In [93]: a.repeat(3,axis=1)
Out[93]:
array([[1, 1, 1, 2, 2, 2],
[3, 3, 3, 4, 4, 4]])
In [96]: a.reshape((2,2,1)).repeat(3,axis=2)
Out[96]:
array([[[1, 1, 1],
[2, 2, 2]],
[[3, 3, 3],
[4, 4, 4]]])
In [98]: a.repeat(3).reshape((2,2,3))
Out[98]:
array([[[1, 1, 1],
[2, 2, 2]],
[[3, 3, 3],
[4, 4, 4]]])
In [99]: np.tile(a,2)
Out[99]:
array([[1, 2, 1, 2],
[3, 4, 3, 4]])
In [100]: np.tile(a,[2,2])
Out[100]:
array([[1, 2, 1, 2],
[3, 4, 3, 4],
[1, 2, 1, 2],
[3, 4, 3, 4]])
In [101]: np.tile(a.ravel(),2)
Out[101]: array([1, 2, 3, 4, 1, 2, 3, 4])
複製程式碼
repeat
方法將陣列中的元素重複,可通過axis
引數指定軸方向,預設會將陣列展開後在唯一的軸方向上重複元素。可配合ndarray.reshape
在新軸上覆制元素。
tile
方法將陣列重複,注意,重複的是整個陣列,不是單個元素,得到的結果中同元素不一定是緊挨著的。
3. 刪除
(1). 索引篩選
In [616]: a[~(a[0]==1),:]
Out[616]: array([[3, 4]])
複製程式碼
通過索引篩選可得到刪除指定內容的陣列。
(2). 刪除方法
In [617]: np.delete(a,[0,1],axis=0)
Out[617]: array([], shape=(0, 2), dtype=int32)
複製程式碼
通過相應方法獲得刪除指定索引位置內容的陣列。第二個引數obj
為索引位置,第三個引數axis
為指定軸。
六. 重構
1. 型別轉換
In [619]: a=np.array([[1,2],[3,4]])
In [620]: a.dtype
Out[620]: dtype('int32')
In [621]: a=a.astype('float64')
In [622]: a.dtype
Out[622]: dtype('float64')
In [623]: a=np.int32(a)
In [624]: a.dtype
Out[624]: dtype('int32')
複製程式碼
使用ndarray.astype
方法或是使用資料型別同名方法都可以轉換型別,關於numpy支援的資料型別可以檢視屬性章節。轉換型別後返回一個新陣列。
2. 重塑
(1). 改變形狀
In [625]: a=np.array([[1,2],[3,4]])
In [626]: a.reshape((1,4))
Out[626]: array([[1, 2, 3, 4]])
In [627]: a.reshape((-1,4))
Out[627]: array([[1, 2, 3, 4]])
複製程式碼
使用tuple型別的引數宣告新的形狀。允許有一個新軸的大小為-1,表示自動計算。
改變前後元素數size
需要保持一致。元素在軸上的排列是從最後一個軸開始往前面的軸方向上堆疊,見如下圖示,可通過order
引數指定其他排序方式。軸的相對位置不會改變,所以一些複雜的變形可能需要結合transpose
或swapaxes
此類軸交換方法使用。
(2). 平鋪
In [640]: a.ravel()
Out[640]: array([1, 2, 3, 4])
In [641]: a.flatten()
Out[641]: array([1, 2, 3, 4])
複製程式碼
將陣列平鋪為向量,等效於reshape((-1,)),可通過order
引數指定其他排序方式。
(3). 轉置
In [643]: a.T
Out[643]:
array([[1, 3],
[2, 4]])
複製程式碼
陣列為一維時轉置無效,為二維時即矩陣的轉置,多於二維時交換第一個和最後一個軸。
(4). 軸交換
In [646]: a.swapaxes(0,1)
Out[646]:
array([[1, 3],
[2, 4]])
In [647]: a.transpose([1,0])
Out[647]:
array([[1, 3],
[2, 4]])
複製程式碼
swapaxes
一次只能指定兩個軸進行交換,transpose
可以重新為所有軸排序。
3. 排序
(1). 直接排序
In [734]: a=np.array([[2,3],[1,4]])
In [735]: np.sort(a,axis=None)
Out[735]: array([1, 2, 3, 4])
In [736]: a.sort(axis=0)
In [737]: a
Out[737]:
array([[1, 3],
[2, 4]])
複製程式碼
ndarray.sort
會直接在原陣列上排序,可通過第一個引數axis
指定排序的軸,會將沿著該軸方向的每個向量單獨排序,預設-1
,除沿最後一個軸外,指定其他軸都會在排序時生成資料的臨時副本,因此沿最後一個軸排序最快。
等效方法np.sort
,返回的是排序後的副本,還可指定axis=None
,會將陣列展開再排序。
當陣列的維度具備實際含義時,直接排序會打亂資料結構,得到不被期望的結果,這種情況下需要使用間接排序。
(2). 間接排序
In [740]: a=np.array([[2,3,5],[1,1,4],[1,2,3]])
In [741]: a
Out[741]:
array([[2, 3, 5],
[1, 1, 4],
[1, 2, 3]])
In [742]: idx1=np.argsort(a[:,0])
In [743]: a[idx1]
Out[743]:
array([[1, 1, 4],
[1, 2, 3],
[2, 3, 5]])
In [744]: idx2=np.lexsort((a[:,0],a[:,2]))
In [745]: a[idx2]
Out[745]:
array([[1, 2, 3],
[1, 1, 4],
[2, 3, 5]])
複製程式碼
argsort
可用於單鍵間接排序,lexsort
可用於多鍵間接排序。
(3). 隨機排序
In [763]: a=np.arange(12).reshape((3,4))
In [764]: a
Out[764]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [765]: np.random.shuffle(a)
In [766]: a
Out[766]:
array([[ 4, 5, 6, 7],
[ 0, 1, 2, 3],
[ 8, 9, 10, 11]])
In [768]: idx=np.random.permutation(a.shape[1])
In [769]: a[:,idx]
Out[769]:
array([[ 4, 5, 7, 6],
[ 0, 1, 3, 2],
[ 8, 9, 11, 10]])
複製程式碼
方法一np.random.shuffle
只能沿第一個軸進行隨機排序,方法二是通過np.random.permutation
,該方法也只能沿第一個軸隨機排序,但在輸入引數x
為int
型別時,會對np.arange(x)進行隨機排序,可以快速生成亂序索引,再通過索引查詢得到亂序陣列。
(4). 分割槽排序
In [799]: a=np.array([2,3,1,5,4,0,8])
In [800]: np.partition(a,1)
Out[800]: array([0, 1, 3, 5, 4, 2, 8])
In [801]: np.partition(a,4)
Out[801]: array([0, 1, 2, 3, 4, 5, 8])
複製程式碼
分割槽排序是一種不完整的排序,用於不需要獲取完整排序序列的情況下。該方法只保證kth
指定位置的元素是正確排序的,其他小於該元素的元素前移,大於的後移。可用於快速找出第k大或第k小的元素。
也可通過ndarray.partition
呼叫,axis
引數指定軸方向,還有對應的np.argpartition
用於獲取分割槽後的索引。
4. 去重
In [775]: a=np.array([3,2,2,3,1,1,4])
In [776]: np.unique(a,return_index=True,return_inverse=True,return_counts=True,axis=None)
Out[776]:
(array([1, 2, 3, 4]),
array([4, 1, 0, 6], dtype=int64),
array([2, 1, 1, 2, 0, 0, 3], dtype=int64),
array([2, 2, 2, 1], dtype=int64))
In [777]: a=np.array([[1,3],[2,4],[1,3]])
In [778]: np.unique(a,axis=0)
Out[778]:
array([[1, 3],
[2, 4]])
複製程式碼
axis
指定去重的軸,預設None
會將陣列展開後再去重。
返回值一為去重後的有序值列表;
返回值二為唯一值在原陣列中的索引,僅在return_index=True
時提供;
返回值三為根據唯一值重建原陣列的索引,僅在return_inverse=True
時提供;
返回值四為唯一值的出現計數,僅在return_counts=True
時提供。
5. 拆分
(1). 索引拆分
In [780]: a=np.arange(9).reshape((3,3))
In [781]: a[:2,:],a[2:,:]
Out[781]:
(array([[0, 1, 2],
[3, 4, 5]]), array([[6, 7, 8]]))
In [782]: a[a>2],a[~(a>2)]
Out[782]: (array([3, 4, 5, 6, 7, 8]), array([0, 1, 2]))
In [790]: idx=np.random.permutation(a.shape[0])
In [791]: sp_idx=int(a.shape[0]*0.8)
In [792]: a[idx[:sp_idx]],a[idx[sp_idx:]]
Out[792]:
(array([[3, 4, 5],
[6, 7, 8]]), array([[0, 1, 2]]))
複製程式碼
最靈活的方式,複雜的拆分需要寫較多的程式碼,可使用其他方法配合生成用於拆分的索引,比如使用np.digitize
進行分箱。
(2). 拆分方法
In [802]: a=np.arange(8)
In [803]: np.split(a,2)
Out[803]: [array([0, 1, 2, 3]), array([4, 5, 6, 7])]
In [805]: np.split(a,[2,5])
Out[805]: [array([0, 1]), array([2, 3, 4]), array([5, 6, 7])]
In [806]: a=a.reshape((2,4))
In [807]: a
Out[807]:
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
In [809]: np.split(a,[1,3],axis=1)
Out[809]:
[array([[0],
[4]]), array([[1, 2],
[5, 6]]), array([[3],
[7]])]
複製程式碼
第二個引數indices_or_sections
指定分割方式,int
型別表示等分數量,一維陣列型別表示用於分割的索引值,例如[2,5]
表示分割為a[:2],a[2:5],a[5:]
。
第三個引數axis
可以指定軸方向。
七. 讀寫
numpy 可使用專用的npy
和npz
格式或常見的txt
格式儲存ndarray
的資料。
1. 儲存
In [803]: a=np.array([1,2,3,4])
In [804]: b=np.array([[5,6],[7,8]])
In [805]: np.save('D:\\out.npy',a)
In [806]: np.savez('D:\\out.npz',a,b=b)
In [807]: np.savetxt('D:\\out.txt',b,fmt="%d", delimiter=",")
複製程式碼
擴充名可以省略,會自動補全。無法自動建立資料夾。
save
用於儲存單個陣列為npy
格式檔案。
savez
用於儲存多個陣列為npz
格式檔案,沒有使用關鍵字引數傳遞的陣列會自動命名為arr_0,arr_1,...
。
savetxt
用於儲存單個陣列為txt
格式檔案,引數fmt
指定儲存時的字串轉換,引數delimiter
指定分隔符,注意在讀取時也需要指定分隔符。分隔符的設定對一維陣列無效,二維以上的陣列不適合用該方法儲存。
2. 載入
In [835]: np.load('D:\\out.npy')
Out[835]: array([1, 2, 3, 4])
In [836]: npz=np.load('D:\\out.npz')
In [837]: npz['arr_0']
Out[837]: array([1, 2, 3, 4])
In [838]: npz['b']
Out[838]:
array([[5, 6],
[7, 8]])
In [841]: np.loadtxt('D:\\out.txt',dtype='int',delimiter=',')
Out[841]:
array([[5, 6],
[7, 8]])
複製程式碼
np.load
讀取npz
格式檔案會得到一個NpzFile
物件,之後通過儲存時設定的名稱進行[]
索引可以取得每一個陣列。
八. 其他
1. 矩陣型別
numpy提供了一個專用的矩陣物件matrix
,是基於 ndarray
作了進一步的封裝得到的,能夠更加快捷地進行一些矩陣相關的運算,但相比ndarray
沒有效能上的優勢且維數限制在二維,並不推薦使用。
(1). 建立
In [79]: m1=np.matrix([[1,2],[3,4]])
In [81]: m1
Out[81]:
matrix([[1, 2],
[3, 4]])
複製程式碼
建立方式與ndarray
類似。
(2). 與 ndarray
的相互轉換
In [82]: a=np.array([[5,6],[7,8]])
In [83]: m2=np.matrix([[5,6],[7,8]])
In [84]: np.asmatrix(a)
Out[84]:
matrix([[5, 6],
[7, 8]])
In [85]: np.matrix(a)
Out[85]:
matrix([[5, 6],
[7, 8]])
In [88]: np.asarray(m2)
Out[88]:
array([[5, 6],
[7, 8]])
In [89]: np.array(m2)
Out[89]:
array([[5, 6],
[7, 8]])
In [90]: m2.base
Out[90]:
array([[5, 6],
[7, 8]])
複製程式碼
(3). 矩陣運算
In [94]: m1*m2
Out[94]:
matrix([[19, 22],
[43, 50]])
In [95]: m1.I
Out[95]:
matrix([[-2. , 1. ],
[ 1.5, -0.5]])
In [96]: m1.T
Out[96]:
matrix([[1, 3],
[2, 4]])
複製程式碼
運算子*
用在matrix
上表示矩陣乘法,等效於np.dot(m1,m2)
,要實現元素相乘需要使用np.multiply(m1,m2)
。
matrix.T
表示轉置矩陣,matrix.I
表示逆矩陣。
matrix
可以使用大部分ndarray
的方法,比如max
、sum
、sort
等。
2. 張量運算
張量是向量、矩陣這類概念的推廣,標量是0階張量,向量是1階張量,矩陣是2階張量。
numpy提供了廣義的張量點積運算np.tensordot
。
In [2]: a=np.arange(1,9).reshape((2,2,2))
In [3]: b=np.arange(1,5).reshape((2,2))
In [4]: a
Out[4]:
array([[[1, 2],
[3, 4]],
[[5, 6],
[7, 8]]])
In [5]: b
Out[5]:
array([[1, 2],
[3, 4]])
In [8]: np.tensordot(a,b,axes=1)
Out[8]:
array([[[ 7, 10],
[15, 22]],
[[23, 34],
[31, 46]]])
In [9]: np.tensordot(a,b,axes=(-1,0))
Out[9]:
array([[[ 7, 10],
[15, 22]],
[[23, 34],
[31, 46]]])
In [10]: np.tensordot(a,b,axes=2)
Out[10]: array([30, 70])
In [12]: np.tensordot(a,b,axes=([-2,-1],[0,1]))
Out[12]: array([30, 70])
In [13]: np.dot(a,b)
Out[13]:
array([[[ 7, 10],
[15, 22]],
[[23, 34],
[31, 46]]])
In [14]: np.tensordot(a,b,axes=(-1,-2))
Out[14]:
array([[[ 7, 10],
[15, 22]],
[[23, 34],
[31, 46]]])
In [15]: np.inner(a,b)
Out[15]:
array([[[ 5, 11],
[11, 25]],
[[17, 39],
[23, 53]]])
In [16]: np.tensordot(a,b,axes=(-1,-1))
Out[16]:
array([[[ 5, 11],
[11, 25]],
[[17, 39],
[23, 53]]])
複製程式碼
前兩個引數a
和b
為參與運算的兩個張量。
第三個引數axes
用於指定收縮的軸,完整格式形如([a_axis1,a_axis2,...],[b_axis1,b_axis2,...])
,兩個序列分別指定a
和b
的軸,軸方向上的元素會按照被指定的順序對應、相乘並相加;可使用(a_axis,b_axis)
的形式僅指定一個軸;
可使用int
型別快速指定a
中最後N個軸和b
中前N個軸用於收縮,即0
等效於([],[])
,對應張量積運算,1
等效於([-1],[0])
,對應張量內積運算,2
等效於([-2,-1],[0,1])
,對應張量雙收縮運算,axes
的預設值為2
。
np.dot
、np.inner
這類運算可視作該函式表示的幾個特例,np.dot(a1,a2)
等效於np.tensordot(a1,a2,axes=(-1,-2))
,np.inner(a1,a2)
等效於np.tensordot(a1,a2,axes=(-1,-1))
。
3. 傅立葉變換
(1) 頻率序列
In [12]: np.fft.fftfreq(10,1.0)
Out[12]: array([ 0. , 0.1, 0.2, 0.3, 0.4, -0.5, -0.4, -0.3, -0.2, -0.1])
複製程式碼
返回離散傅立葉變換取樣頻率,第一個引數n
為視窗長度,int
型別,第二個引數d
為取樣間距(取樣率的倒數),預設為1.0,返回值單位與取樣間距單位相對應。
返回值序列的計算方式:
如果n
是偶數,f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n)
;
如果n
是奇數,f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n)
。
(2) 快速傅立葉變換
In [13]: x=np.cos(np.linspace(0,2*np.pi,30))
In [14]: y=np.fft.fft(x)
In [15]: x2=np.fft.ifft(y)
In [16]: np.abs(x2-x).max()
Out[16]: 3.8864883384594504e-16
複製程式碼
np.fft
和np.ifft
互為逆運算,用於一維快速傅立葉變換,經np.fft
變換後的序列可通過np.ifft
近似還原為原序列。
第二個引數n
指定輸出的變換軸長度,超長裁剪,不足補0;
第三個引數axis
指定用於變換的軸,預設最後一個軸。
(3) 移頻
In [21]: x=np.linspace(0,2*np.pi,8)
In [22]: y=np.fft.fft(x)
In [23]: y2=np.fft.fftshift(y)
In [24]: y3=np.fft.ifftshift(y2)
In [32]: np.abs(y3-y).max()
Out[32]: 0.0
複製程式碼
np.fftshift
和np.ifftshift
互為逆運算,用於將傅立葉變換輸出中的直流分量移動到頻譜的中央。第二個引數axis
可指定用於轉移的軸。
4. 影像處理
影像資料的儲存方式是類似於陣列的,可藉助PIL
庫讀取圖片,再將影像資料轉成ndarray
進行計算處理。
以下提供一些使用numpy
配合PIL
處理圖片資料的方法:
(1) 圖片的建立、讀取、縮放、儲存
In [2]: from PIL import Image
...: image1= Image.open("D:\\test.jpg")
In [3]: image1.size
Out[3]: (1015, 610)
In [4]: image2=image1.resize((500,300))
In [5]: image2.save("D:\\test2.jpg")
In [6]: image0=Image.new('RGB',image2.size)
In [7]: image2
Out[7]:
複製程式碼
Image.open
用於開啟一張圖片,mode
可以設定讀取模式,最常用的是'L'
灰度圖和'RGB'
彩色圖,一般會自動匹配不需要設定。
圖片物件的resize
方法可以縮放圖片,大小引數以tuple
型別(width,height)
格式傳入。
圖片物件的save
方法可以儲存圖片,通過儲存路徑中的檔案擴充名或是format
引數指定儲存檔案型別,quality
引數可以設定儲存影像的質量,取值1(最差)~ 95(最佳),預設75。
Image.new
用於建立一個新的圖片,mode
引數指定模式,size
指定大小。
在IPython
中,直接輸入圖片變數名就可以顯示圖片。
(2) 圖片與陣列之間的轉換
In [7]: a=np.asarray(image2)
In [8]: a.shape
Out[8]: (300, 500, 3)
In [9]: image3=Image.fromarray(a,'RGB')
複製程式碼
np.asarray
或np.array
可以將圖片轉換為ndarray
,np.asarray
返回圖片資料的ndarray
型別檢視,不能更改。根據型別的不同,得到的陣列形狀也不一樣,常見的兩種,灰度圖轉換得到形狀為(height,width)
的陣列,彩色圖轉換得到形狀為(height,width,channel)
的陣列,channel
即顏色通道,RGB
模式下channel=3
,分別對應紅綠藍。
Image.fromarray
可以將ndarray
轉換為圖片,可通過mode
引數指定模式,預設會根據陣列形狀自動匹配,當指定某個模式時,陣列形狀也需要匹配。
注意,陣列轉圖片需要是uint8
資料型別,取值0~255
,如不符合要進行另外的轉換。
(3) 畫素點繪製
In [10]: a0=np.array(image0)
In [11]: a0+=np.random.randint(0,256,a.shape,dtype='uint8')
In [12]: image4=Image.fromarray(a0)
In [13]: image4.putpixel((0,0),(255,255,255))
In [14]: image4
Out[14]:
複製程式碼
圖片物件的putpixel
方法可以新增單個畫素點,第一個引數xy
以(x,y)
的形式宣告新增畫素點的位置,第二個引數value
指定畫素點的值,例如,L
灰度圖模式下為標量值,RGB
彩色圖模式下為(r,g,b)
形式的tuple
,取值均在0~255
之間。該方法一次只能繪製一個畫素點,效率低,在需要批量繪製時建議轉換為ndarray
處理。
上面的示例中使用ndarray
的方法為新圖片的每一個畫素點新增了隨機色彩。
(4) 灰度圖和彩色圖之間的轉換
In [72]: a2=np.asarray(image2,dtype='float')
In [73]: a5=(11*a2[:,:,0]+16*a2[:,:,1]+5*a2[:,:,2])/32
In [74]: image5=Image.fromarray(np.uint8(a5))
In [75]: a6=a5.repeat(3).reshape(a5.shape+(3,))
In [76]: image6=Image.fromarray(np.uint8(a6))
In [77]: image5
Out[77]:
複製程式碼
彩色圖轉灰度圖,L=11*R+16*G+5*B
只是一種可行的公式,也有其他公式可用。
灰度圖轉彩色圖,較為簡單,即將灰度值拷貝到RGB
3個通道上,轉換後顏色還是灰色,因為灰度圖不具備色彩方面的資訊,即使先將彩色圖轉灰度圖,再轉換回彩色圖,色彩資訊同樣會丟失。
(5) 圖片的翻轉、旋轉、裁剪
In [84]:a2=np.asarray(image2)
In [85]:Image.fromarray(a2[::-1,::-1,:])
Out[85]:
複製程式碼
In [90]:Image.fromarray(a2.transpose([1,0,2]))
Out[90]:
複製程式碼
In [91]:Image.fromarray(a2[:150,:,:])
Out[91]:
複製程式碼
以上示例展示了 左右翻轉+上下翻轉,左右翻轉+逆時針轉90°,擷取上半部分 三種情況,藉助倒序索引和軸交換的組合可以得到90°倍數旋轉和上下左右翻轉的所有組合情形。精確的旋轉需要使用矩陣運算,此處不作展開。