python學習筆記-目錄索引html
第2章「NumPy數組」介紹NumPy和數組的基礎知識。經過閱讀本章,讀者可以基本掌握NumPy數組及其相關函數。python
本章涉及的主題以下。數據庫
2.1NumPy數組對象windows
NumPy提供了一個名爲ndarray的多維數組對象。NumPy數組是具備固定大小的類型化數組。Python的列表是異構的,所以列表的元素能夠包含任何對象類型,而NumPy數組是同質的,只能存放同一種類型的對象。數組由兩部分組成,分別以下。數組
實際數據存儲在連續的內存塊中,所以當大型數據集做爲ndarray進行加載時,咱們就要看有沒有足夠多的連續內存塊了。NumPy中的大部分數組方法和函數都不會直接修改實際數據,而只能修改元數據。dom
在以前的章節中,咱們曾經用arange()函數來生成數組。實際上,那是用來存放一組數值的一維數組,這裏的ndarray則能夠具備一個以上的維度。函數
NumPy數組的優點post
NumPy數組一般是同質的(有一種特殊的記錄數組類型,它能夠是異質的),即數組中的數據項的類型必須一致。NumPy數組元素類型一致的好處是:由於知道數組元素的類型相同,因此能輕鬆肯定存儲數組所需空間的大小。同時,NumPy數組還可以運用向量化運算來處理整個數組;而完成一樣的任務,Python的列表則一般須要藉助循環語句遍歷列表並對逐個元素進行相應的處理。NumPy數組的索引方法與Python相似,下標從0開始。此外,NumPy使用了優化過的C API,因此運算速度格外快。學習
從此,咱們會常常利用arange()子例程來創建數組。一般,向量就是一個一維數組。優化
注意:雖然windows操做系統,JDK,python都是64位,可是Numpy默認創建的int類型便是32位。這與原書中做者的描述不一樣,若是你須要64位,能夠經過上面的示例修改默認值。以上示例可能對不少場景下的Numpy數據類型與python數據類型不一致時特別有用。
如你所見,該向量有5個元素,它們的值分別是從0~4。該數組的shape屬性是一個元組,就本例而言,這是一個單元素元組,存放的是數組在每個維度的長度。
2.2建立多維數組
1 m = np.array([np.arange(2), np.arange(2)]) 2 print(m) 3 print(m.shape) 4 # [[0 1] 5 # [0 1]] 6 # (2, 2)
以上用arange()子例程直接創建了一個2×2的數組,而利用array()函數建立數組時,則須要傳遞給它一個對象,同時這個對象還必須是數組類型的,如Python的列表。在上面的例子中,咱們傳給它的是由兩個數組組成的一個列表。該對象是array()函數惟一所需的參數,而NumPy的函數每每有多個可選參數,並且這些參數都帶有預約義的缺省選項。
2.3選擇NumPy數組元素
1 a = np.array([[1,2],[3,4]])
此時,a[0,0]=1,...a[1,1]=4
2.4.1 數據類型對象
數據類型對象是numpy.dtype類的實例。再強調一次,數組也有數據類型。嚴格地講,NumPy數組中的每一個元素都要具備相同的數據類型。數據類型對象代表了數據佔用的字節數。所佔用字節的具體數目通常存放在類dtype的itemsize屬性中。
1 print(a.dtype.itemsize) 2 # 4
64位對應的是8
2.4.2 字符碼
NumPy之因此提供字符碼,是爲了與其前身Numeric向後兼容。通常咱們不建議使用字符碼,這裏爲何又提供這些代碼呢?由於咱們會在許多地方碰到它們,可是,編寫代碼時咱們應當使用dtype對象。下表展現了常見的一些數據類型及其相應的字符碼。
1 1 np.arange(7, dtype='f') #生成一個單精度浮點型的數組。 2 2 np.arange(7, dtype='D')#生成一個複數類型的數組。注意複數轉化爲int會報錯
/* array([0., 1., 2., 3., 4., 5., 6.], dtype=float32) array([0.+0.j, 1.+0.j, 2.+0.j, 3.+0.j, 4.+0.j, 5.+0.j, 6.+0.j]) */
2.4.3 dtype構造函數
1 print(np.sctypeDict.keys())
/* dict_keys(['?', 0, 'byte', 'b', 1, 'ubyte', 'B', 2, 'short', 'h', 3, 'ushort', 'H', 4, 'i', 5, 'uint', 'I', 6, 'intp', 'p', 9, 'uintp', 'P', 10,
'long', 'l', 7, 'L', 8, 'longlong', 'q', 'ulonglong', 'Q', 'half', 'e', 23, 'f', 11, 'double', 'd', 12, 'longdouble', 'g', 13, 'cfloat', 'F', 14,
'cdouble', 'D', 15, 'clongdouble', 'G', 16, 'O', 17, 'S', 18, 'unicode', 'U', 19, 'void', 'V', 20, 'M', 21, 'm', 22, 'bool8', 'Bool', 'b1',
'int64', 'Int64', 'i8', 'uint64', 'Uint64', 'u8', 'float16', 'Float16', 'f2', 'float32', 'Float32', 'f4', 'float64', 'Float64', 'f8',
'complex64', 'Complex32', 'c8', 'complex128', 'Complex64', 'c16', 'object0', 'Object0', 'bytes0', 'Bytes0', 'str0', 'Str0', 'void0',
'Void0', 'datetime64', 'Datetime64', 'M8', 'timedelta64', 'Timedelta64', 'm8', 'int32', 'Int32', 'i4', 'uint32', 'UInt32', 'u4', 'UInt64',
'int16', 'Int16', 'i2', 'uint16', 'UInt16', 'u2', 'int8', 'Int8', 'i1', 'uint8', 'UInt8', 'u1', 'complex_', 'int0', 'uint0', 'single',
'csingle', 'singlecomplex', 'float_', 'intc', 'uintc', 'int_', 'longfloat', 'clongfloat', 'longcomplex', 'bool_', 'bytes_', 'string_',
'unicode_', 'object_', 'str_', 'int', 'float', 'complex', 'bool', 'object', 'str', 'bytes', 'a']) */
2.5一維數組的切片與索引
一維NumPy數組的切片操做與Python列表的切片同樣。下面先來定義包含數字0、一、2, …, 8的一個數組,而後經過指定下標3~7來選擇該數組的部分元素,這實際上就是提取數組中值爲3~6的那些元素。
1 a = np.arange(9) 2 a[3:7]
Out:
array([3, 4, 5, 6])
咱們能夠用下標選擇元素,下標範圍從0~7,並且下標每次遞增2,以下所示。
a[:7:2]
Out:
array([0, 2, 4, 6])
正如使用Python那樣,咱們也可用負值下標來反轉數組。
a[::-1]
Out:
[8, 7, 6, 5, 4, 3, 2, 1, 0]
2.6處理數組形狀
前面咱們學習過reshape()函數,實際上,除了數組形狀的調整外,數組的擴充也是一個常常碰到的乏味工做。好比,咱們能夠想象一下將多維數組轉換成一維數組時的情形。咱們建立一個數組b,下面的多個例子都會用到它。
1 b = np.arange(24).reshape(2,3,4) 2 print(b)
Out:
[[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]],這個過程能夠理解爲先2,再3,後4,最後獲得一個2×3×4的數組
咱們能夠利用如下函數處理數組的形狀。
拆解:能夠用ravel()函數將多維數組變成一維數組,代碼以下。
1 print(b.ravel())
Out:
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]
拉直(Flatten):flatten()函數的名字取得很是貼切,其功能與ravel()相同。但是,flatten()返回的是真實的數組,須要分配新的內存空間;而ravel()函數返回的只是數組的視圖。這意味着,咱們能夠像下面這樣直接操做數組。
1 print(b.flatten())
Out:
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]
用元組指定數組形狀:除reshape()函數外,還能夠用元組來輕鬆定義數組的形狀,代碼以下。
1 b.shape = (6,4) 2 print(b)
Out:
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]
可見,上述代碼直接改變了數組的形狀。這樣,咱們就獲得了一個6×4的數組。
轉置:在線性代數中,矩陣的轉置操做很是常見。轉置是一種數據變換方法,對於二維表而言,轉置就意味着行變成列,同時列變成行。轉置也能夠經過下列代碼完成。
1 print(b.transpose())
Out:
[[ 0, 4, 8, 12, 16, 20],
[ 1, 5, 9, 13, 17, 21],
[ 2, 6, 10, 14, 18, 22],
[ 3, 7, 11, 15, 19, 23]]
調整大小:函數resize()的做用相似於reshape(),可是會改變所做用的數組。
1 b.resize((2,12))
Out:
[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]]
2.6.1 堆疊數組
從深度看,數組既能夠橫向疊放,也能夠豎向疊放。爲此,可使用vstack()、dstack()、hstack()、column_stack()、row_stack()和concatenate()等函數。在此以前,咱們先要創建某些數組。
1 a = np.arange(9).reshape(3,3) 2 print(a)
Out:
[[0, 1, 2],
[3, 4, 5],
[6, 7, 8]]
1 b = 2 * a 2 print(b)
Out:
[[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]]
就像前面所說的,能夠用下列技術來堆放數組。
水平疊加:先介紹水平疊加方式,即用元組肯定ndarrays數組的形狀,而後交給hstack()函數來碼放這些數組,具體以下。
np.hstack((a, b))
Out:
[[ 0, 1, 2, 0, 2, 4],
[ 3, 4, 5, 6, 8, 10],
[ 6, 7, 8, 12, 14, 16]]
用concatenate()函數也能達到一樣的效果,代碼以下。
np.concatenate((a, b), axis=1)
Out:
[[ 0, 1, 2, 0, 2, 4],
[ 3, 4, 5, 6, 8, 10],
[ 6, 7, 8, 12, 14, 16]]
水平疊加過程的示意圖如圖2-2所示。
垂直疊加:使用垂直疊加方法時,先要構建一個元組,而後將元組交給vstack()函數來碼放數組,代碼以下。
np.vstack((a, b))
Out:
[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]]
當參數axis設置爲0時,concatenate()函數也會獲得一樣的效果。實際上,這是該參數的缺省值,代碼以下。
np.concatenate((a, b), axis=0)
Out:
[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]]
垂直疊加過程的示意圖如圖2-3所示。
深度疊加:除此以外,還有一種深度疊加方法,這要用到dstack()函數和一個元組。這種方法是沿着第三個座標軸(縱向)的方向來疊加一摞數組。舉例來講,咱們能夠在一個圖像數據的二維數組上疊加另外一幅圖像的數據,代碼以下。
np.dstack((a, b))
Out:
Array([[[ 0, 0],
[ 1, 2],
[ 2, 4]],
[[ 3, 6],
[ 4, 8],
[ 5, 10]],
[[ 6, 12],
[ 7, 14],
[ 8, 16]]])
列式堆疊:column_stack()函數以列方式對一維數組進行堆疊,代碼以下。
oned = np.arange(2) print(oned)
Out: [0, 1]
twice_oned = 2 * oned print(twice_oned)
Out: [0, 2]
np.column_stack((oned, twice_oned))
Out:
Array([[0, 0],
[1, 2]])
用這種方法堆疊二維數組時,過程相似於hstack()函數,代碼以下。
np.column_stack((a, b))
Out:
[[ 0, 1, 2, 0, 2, 4],
[ 3, 4, 5, 6, 8, 10],
[ 6, 7, 8, 12, 14, 16]]
np.column_stack((a, b)) == np.hstack((a, b))
Out:
Array([[ True, True, True, True, True, True],
[ True, True, True, True, True, True],
[ True, True, True, True, True, True]],
Dtype=bool)
是的,你猜得沒錯!咱們用「==」運算符對兩個數組進行了比對。
行式堆疊:同時,NumPy天然也有以行方式對數組進行堆疊的函數,這個用於一維數組的函數名爲row_stack(),它將數組做爲行碼放到二維數組中,代碼以下。
np.row_stack((oned, twice_oned))
Out:
[[0, 1],
[0, 2]]
對於二維數組,row_stack()函數至關於vstack()函數,代碼以下。
np.row_stack((a, b))
Out:
Array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]])
np.row_stack((a,b)) == np.vstack((a, b))
Out:
Array([[ True, True, True],
[ True, True, True],
[ True, True, True],
[ True, True, True],
[ True, True, True],
[ True, True, True]], dtype=bool)
2.6.2 拆分NumPy數組
我能夠從縱向、橫向和深度方向來拆分數組,相關函數有hsplit()、vsplit()、dsplit()和split()。咱們既能夠把數組分紅相同形狀的數組,也能夠從規定的位置開始切取數組。下面對相關函數逐個詳解。
橫向拆分:對於一個3×3數組,能夠沿着橫軸方向將其分解爲3部分,而且各部分的大小和形狀徹底一致,代碼(它取自本書代碼包中的splitting.py文件)以下。
a = np.arange(9).reshape(3,3) print(a)
Out:
[[0, 1, 2],
[3, 4, 5],
[6, 7, 8]]
np.hsplit(a, 3)
Out:
[array([[0],
[3],
[6]]),
Array([[1],
[4],
[7]]),
Array([[2],
[5],
[8]])]
這至關於調用了參數axis=1的split()函數。
np.split(a, 3, axis=1) #print(a)
Out:
[array([[0],
[3],
[6]]),
Array([[1],
[4],
[7]]),
Array([[2],
[5],
[8]])]
縱向拆分:vsplit()函數將沿着縱軸方向分解數組。
np.vsplit(a, 3)
Out: [array([[0, 1, 2]]), array([[3, 4, 5]]),
Array([[6, 7, 8]])]
當參數axis=0時,split()函數也會沿着縱軸方向分解數組,代碼以下
np.split(a, 3, axis=0)
Out: [array([[0, 1, 2]]), array([[3, 4, 5]]),
Array([[6, 7, 8]])]
深向拆分:dsplit()函數會沿着深度方向分解數組。下面以秩爲3的數組爲例進行說明。
c = np.arange(27).reshape(3, 3, 3) print(c)
Out:
[[[ 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, 25, 26]]]
np.dsplit(c, 3)
Out:
[array([[[ 0],
[ 3],
[ 6]],
[[ 9],
[12],
[15]],
[[18],
[21],
[24]]]),
Array([[[ 1],
[ 4],
[ 7]],
[[10],
[13],
[16]],
[[19],
[22],
[25]]]),
Array([[[ 2],
[ 5],
[ 8]],
[[11],
[14],
[17]],
[[20],
[23],
[26]]])]
2.6.3 NumPy數組的屬性
下面舉例說明NumPy數組各類屬性的詳細用法。咱們建立一個數組b,以便後面的例子使用。
b = np.arange(24).reshape(2, 12) print(b)
Out:
[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]]
除shape和dtype屬性外,ndarray類型的屬性還不少,下面逐一列出。
Ndim屬性存儲的是維度的數量,下面舉例說明。
print(b.ndim)
Out: 2
Size屬性用來保存元素的數量,用法以下。
print(b.size)
Out: 24
Itemsize屬性能夠返回數組中各個元素所佔用的字節數,代碼以下。
print(b.itemsize)
Out: 8
若是想知道存儲整個數組所需的字節數量,能夠求助於nbytes屬性。這個屬性的值正好是itemsize屬性值和size屬性值之積。
print( b.nbytes)
Out: 192
print(b.size * b.itemsize)
Out: 192
T屬性的做用與transpose()函數相同,下面舉例說明。
print(b=b.resize(6,4))
Out:
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]])
print(b.T)
Out:
[[ 0, 4, 8, 12, 16, 20],
[ 1, 5, 9, 13, 17, 21],
[ 2, 6, 10, 14, 18, 22],
[ 3, 7, 11, 15, 19, 23]]
若是數組的秩(rank)小於2,那麼所得只是一個數組的視圖。
b.ndim
Out: 1
b.T
Out: array([0, 1, 2, 3, 4])
對於NumPy來講,複數用j表示,下面舉例說明如何用複數生成一個數組。
b = np.array([1.j + 1, 2.j + 3]) print(b)
Out: [ 1.+1.j, 3.+2.j]
Real屬性將返回數組的實部;當數組元素全爲實數時,就返回數組自己,代碼以下。
print(b.real)
Out: [ 1., 3.]
Imag屬性存放的是數組的虛部。
print(b.imag)
Out: [ 1., 2.]
若是數組含有複數,那麼它的數據類型將自動變爲複數類型,代碼以下。
print(b.dtype)
Out: dtype(‘complex128’)
print(b.dtype.str)
Out: ‘<c16’
Flat屬性可返回一個numpy.flatiter對象,這是得到flatiter對象的惟一方法,但咱們沒法訪問flatiter的構造函數。咱們可使用flat的迭代器來遍歷數組,就像遍歷「胖」數組那樣,代碼以下。
b = np.arange(4).reshape(2,2) print(b)
Out:
Array([[0, 1],
[2, 3]])
f = b.flat print(f)
Out: <numpy.flatiter object at 0x103013e00>
for item in f: print(item)
Out:
0
1
2
3
固然,取得flatiter對象的元素也不難,代碼以下。
print(b.flat[2])
Out: 2
此外,還能夠請求多個元素,代碼以下。
print(b.flat[[1,3]])
Out: array([1, 3])
同時,還能夠給flat屬性賦值。不過,須要注意的是,這個值將會覆蓋整個數組內全部元素的值,下面舉例說明。
b.flat = 7
print(b)
Out:
[[7, 7],
[7, 7]]
此外,還能夠返回指定的元素,代碼以下。
b.flat[[1,3]] = 1
print(b)
Out:
[[7, 1],
[7, 1]]
圖2-4是對ndarray各類屬性的一個小結。
2.6.4 數組的轉換
咱們能夠把NumPy數組轉換成Python列表,使用tolist()函數便可。下面簡單解釋一下。
轉換成列表:
b = np.array([1.j + 1, 2.j + 3]) print(b)
Out: [ 1.+1.j, 3.+2.j]
b.tolist()
Out: [(1+1j), (3+2j)]
Astype()函數能夠把數組元素轉換成指定類型,代碼以下。
b = np.array([1.j + 1, 2.j + 3]) print(b)
Out: array([ 1.+1.j, 3.+2.j])
b.astype(int)
/* d:\tools\python37\lib\site-packages\ipykernel_launcher.py:1: ComplexWarning: Casting complex values to real discards the imaginary part """Entry point for launching an IPython kernel. */
b.astype(‘complex’)
Out: [ 1.+1.j, 3.+2.j]
提示:當complex類型轉換成int類型時,虛部將被丟棄。另外,咱們還須要將數據類型的名稱以字符串的形式傳遞給astype()函數。
上述代碼沒有顯示警告信息,由於此次使用的是正確的數據類型。
2.7建立數組的視圖和拷貝
在介紹ravel()函數的示例中,咱們提到了視圖的概念。不過,請不要與數據庫中的視圖概念混淆。在NumPy的世界裏,視圖不是隻讀的,由於你不可能守着基礎數據一動不動。關鍵在於要知道當前處理的是共享的數組視圖仍是數組數據的副本。舉例來講,咱們能夠取數組的一部分來生成視圖。這意味着,若是先將數組的某部分賦給一個變量,而後修改原數組中相應位置的數據,那麼這個變量的值也會隨之變化。咱們能夠根據SciPy包中的面部照片來建立數組,而後建立視圖,隨後修改它。這裏,萊娜肖像的數組是從SciPy函數得到的。
(1) 獲取面部圖片。
(2) Face = scipy.misc.face()
(3) 爲該面部數組建立副本。
(4) Acopy = face.copy()
(3)爲該數組建立一個視圖。
Aview = face.view()
(5) 經過flat迭代器將視圖中全部的值所有設爲0。
(6) Aview.flat = 0
最後,只有一幅圖片能夠看到圖像,而其餘圖片根本看不到什麼,如圖2-5所示。
下面的代碼很好地展現了數組的視圖和副本的特色。
Import scipy.misc Import matplotlib.pyplot as plt Face = scipy.misc.face() Acopy = face.copy() Aview = face.view() #Aview.flags.writeable = True ####執行報錯:ValueError: cannot set WRITEABLE flag to True of this array Aview.flat = 0 ####ValueError: array is read-only Plt.subplot(221) Plt.imshow(face) Plt.subplot(222) Plt.imshow(acopy) Plt.subplot(223) Plt.imshow(aview) Plt.show()
可見,在程序結束部分修改視圖,同時改變了原來的萊娜數組。這致使3副圖片所有變藍(若是閱讀的是本書的印刷版,也可能顯示爲黑色),複製的數組則沒有任何變化。因此必定要記住:視圖不是隻讀的。
邀月注:原書結論偏偏相反。
2.8花式索引
花式索引是一種傳統的索引方法,它不使用整數或者切片。這裏,咱們將利用花式索引把萊娜照片對角線上的值所有設置爲0,至關於沿着兩條交叉的對角線畫兩條黑線。
下面咱們給出本例中的相應代碼。
Import scipy.misc Import matplotlib.pyplot as plt Face = scipy.misc.face() Xmax = face.shape[0] Ymax = face.shape[1] Face=face[:min(xmax,ymax),:min(xmax,ymax)] Xmax = face.shape[0] Ymax = face.shape[1] #Face[range(xmax), range(ymax)] = 0#ValueError: assignment destination is read-only #Face[range(xmax-1,-1,-1), range(ymax)] = 0 #ValueError: assignment destination is read-only Plt.imshow(face) Plt.show()
下面咱們對上述代碼進行簡單說明。
(1) 將第一條對角線上的值設爲0。
(2) 爲了將對角線上的值設置爲0,咱們須要給x和y值(直角座標系中的座標)規定兩個不一樣的範圍。
Face[range(xmax), range(ymax)] = 0
(3) 將另外一條對角線上的值設爲0。
(4) 要設置另外一條對角線上的值,須要規定兩個不一樣的取值範圍,可是規則不變。
Face[range(xmax-1,-1,-1), range(ymax)] = 0
劃掉相片對角線後,最後獲得圖2-6所示的效果。
運行報錯
咱們給x和y規定了不一樣的取值範圍,這些範圍用來索引萊娜數組。花式索引是在一個內部的NumPy迭代器對象的基礎上實現的,分3步完成。
(1)建立迭代器對象。
(2)將迭代器對象綁定到數組。
(3)經由迭代器訪問數組元素,利用位置列表進行索引。
2.9基於位置列表的索引方法
1 import scipy.misc 2 import matplotlib.pyplot as plt 3 import numpy as np 4 5 face = scipy.misc.face() 6 xmax = face.shape[0] 7 ymax = face.shape[1] 8 9 def shuffle_indices(size): 10 arr = np.arange(size) 11 np.random.shuffle(arr) 12 13 return arr 14 15 xindices = shuffle_indices(xmax) 16 np.testing.assert_equal(len(xindices), xmax) 17 yindices = shuffle_indices(ymax) 18 np.testing.assert_equal(len(yindices), ymax) 19 plt.imshow(face[np.ix_(xindices, yindices)]) 20 plt.show()
下面利用ix_()函數將萊娜照片中的像素徹底打亂。注意,本例中的代碼沒有提供註釋。完整的代碼請參考本書代碼包中的ix.py文件。
這個函數能夠根據多個序列生成一個網格,它須要一個一維序列做爲參數並返回一個由NumPy數組構成的元組。
In : ix_([0,1], [2,3])
Out:
(array([[0],[1]]), array([[2, 3]]))
利用位置列表索引NumPy數組的過程以下。
(1) 打亂數組的索引。
(2) 咱們用numpy.random子程序包中的shuffle()函數把數組中的元素按隨機的索引號從新排列,使得數組產生相應的變化。
1 Def shuffle_indices(size): 2 Arr = np.arange(size) 3 Np.random.shuffle(arr) 4 Return arr
(3) 使用下面的代碼畫出打亂後的索引。
(4) Plt.imshow( face[np.ix_(xindices, yindices)])
(3)萊娜照片的像素被徹底打亂後,變成圖2-7所示的樣子。
2.10用布爾型變量索引NumPy數組
布爾型索引是指根據布爾型數組來索引元素的方法,屬於花式索引系列。由於布爾型索引是花式索引的一個分類,因此它們的使用方法基本相同。
下面用代碼(詳見本書代碼包中的boolean_indexing.py文件)具體演示其使用方法。
1 import scipy.misc 2 import matplotlib.pyplot as plt 3 import numpy as np 4 5 face = scipy.misc.face() 6 xmax = face.shape[0] 7 ymax = face.shape[1] 8 face=face[:min(xmax,ymax),:min(xmax,ymax)] 9 10 def get_indices(size): 11 arr = np.arange(size) 12 return arr % 4 == 0 13 14 face1 = face.copy() 15 xindices = get_indices(face.shape[0]) 16 yindices = get_indices(face.shape[1]) 17 face1[xindices, yindices] = 0 18 plt.subplot(211) 19 plt.imshow(face1) 20 face2 = face.copy() 21 face2[(face > face.max()/4) & (face < 3 * face.max()/4)] = 0 22 plt.subplot(212) 23 plt.imshow(face2) 24 plt.show()
上述代碼利用一種特殊的迭代器對象來索引元素,下面進行簡單說明。
(1) 在對角線上畫點。
(2) 這相似於花式索引,不過這裏選擇的是照片對角線上能夠被4整除的那些位置上的點。
Def get_indices(size):
Arr = np.arange(size)
Return arr % 4 == 0
而後咱們僅繪出選定的那些點。
Face1 = face.copy()
Xindices = get_indices(face.shape[0])
Yindices = get_indices(face.shape[1])
Face1[xindices, yindices] = 0
Plt.subplot(211)
Plt.imshow(face1)
(3) 根據元素值的狀況置零。
(4) 選取數組值介於最大值的1/4~3/4的那些元素,將其設置爲0。
Face2[(face > face.max()/4) & (face < 3 * face.max()/4)] = 0
(3)兩幅新照片如圖2-8所示。
2.11NumPy數組的廣播
當操做對象的形狀不同時,NumPy會盡力進行處理。
例如,假設一個數組要跟一個標量相乘,這時標量須要根據數組的形狀進行擴展,而後才能夠執行乘法運算。這個擴展的過程叫做廣播(broadcasting)。下面用代碼加以說明。
1 import scipy.io.wavfile as sw 2 import matplotlib.pyplot as plt 3 import urllib 4 import numpy as np 5 6 request = urllib.request.Request('http://www.thesoundarchive.com/austinpowers/smashingbaby.wav') 7 response = urllib.request.urlopen(request) 8 print(response.info()) 9 WAV_FILE = 'smashingbaby.wav' 10 filehandle = open(WAV_FILE, 'wb') 11 filehandle.write(response.read()) 12 filehandle.close() 13 sample_rate, data = sw.read(WAV_FILE) 14 print("Data type", data.dtype, "Shape", data.shape) 15 16 plt.subplot(2, 1, 1) 17 plt.title("Original") 18 plt.plot(data) 19 20 newdata = data * 0.2 21 newdata = newdata.astype(np.uint8) 22 print("Data type", newdata.dtype, "Shape", newdata.shape) 23 24 sw.write("quiet.wav", 25 sample_rate, newdata) 26 27 plt.subplot(2, 1, 2) 28 plt.title("Quiet") 29 plt.plot(newdata) 30 31 plt.show()
下面,咱們將下載一個音頻文件,而後以此爲基礎,生成一個新的靜音版本。
(1) 讀取WAV文件。
(2) 咱們將使用標準的Python代碼來下載電影《王牌大賤諜》(Austin Powers)中的狂嚎式歌曲《Smashing, baby》的聲音文件。SciPy中有一個wavfile子程序包,能夠用來加載音頻數據,或者生成WAV格式的文件。若是此前已經安裝了SciPy,那麼如今就能夠直接使用這個子程序包了。咱們可使用函數read()讀取文件,它返回一個數據陣列及採樣率,不過,這裏只對數據自己感興趣。
Sample_rate, data = scipy.io.wavfile.read(WAV_FILE)
(3) 繪製原WAV數據。
(4) 這裏,咱們利用matplotlib繪製原始WAV數據並用一個子圖來顯示標題「Original」,代碼以下。
Plt.subplot(2, 1, 1)
Plt.title(「Original」)
Plt.plot(data)
(3)新建一個數組。
如今,咱們要用NumPy來生成一段「寂靜的」聲音。實際上就是將原數組的值乘以一個常數,從而獲得一個新數組,由於這個新數組的元素值確定是變小了。這正是廣播技術的用武之地。最後,咱們要確保新數組與原數組的類型一致,即WAV格式。
Newdata = data * 0.2
Newdata = newdata.astype(np.uint8)
(5) 寫入一個WAV文件中。
(6) 咱們將新數組保存到一個新的WAV文件中,代碼以下。
Scipy.io.wavfile.write(「quiet.wav」,
Sample_rate, newdata)
(5) 繪製出新的WAV數據。
(6) 咱們可使用matplotlib來畫出新數組中的數據,以下所示。
1 Plt.subplot(2, 1, 2) 2 Plt.title(「Quiet」) 3 Plt.plot(newdata) 4 Plt.show()
圖2-9展現了原始的WAV文件中的數據的圖像以及數值變小後新數組的圖像。
2.12
小結
本章,咱們學習了NumPy的基礎知識:數據類型和數組。數組具備許多屬性,這些屬性都是用來描述該數組的特性的。咱們探討的屬性之一即是數據類型,實際上,NumPy是經過一個成熟完備的對象來表示這個屬性的。
與Python標準的列表相比,NumPy數組使用的切片和索引方法更加高效。此外,NumPy數組還可以對多維度數組進行處理。
咱們能夠用各類方式改變數組的形狀,如堆疊、重定尺寸、重塑形狀以及拆分等。在本章中,咱們還爲處理數組的形狀介紹了許多簡便易用的函數。
有了這些基礎知識後,從第4章開始,咱們就要學習如何經過常見的函數來分析數據了,這將涉及主要統計函數和數值函數的用法。
咱們鼓勵讀者閱讀「參考文獻」部分中提到的書籍,以拓展你們在NumPy庫知識方面的深度和廣度。
第2章完。
隨書源碼官方下載:
https://www.ptpress.com.cn/shopping/buy?bookId=bae24ecb-a1a1-41c7-be7c-d913b163c111
須要登陸後免費下載。