numpy ndarray 之內功心法

numpy ndarray 之內功心法

來自專欄機器學習演算法與自然語言處理95 人贊了文章

一、多維數據的形象表示

import numpy as np# 一維數據不用贅言data_1d = np.array([0, 1, 2, 3])# 二維數據作為 m 行 n 列的表格,例如 2 行 3 列data_2d = np.arange(6).reshape(2, 3)# 三維數據作為 k 層 m 行 n 列 的積木塊, 例如 2 層 3 行 4 列data_3d = np.arange(24).reshape(2, 3, 4)

檢查一個 ndarray 數據的維度和大小,分別用 ndim 和 shape 屬性。

>>> print(data_3d.ndim)3>>> print(data_3d.shape)(2, 3, 4)

shape 是一個很關鍵的屬性,我是這樣把它和各個軸對應的:

shape: (2, 3, 4) k, m, n z, y, x

心法1: x, y, z 對應的shape元組是從右往左數的。

這是我的個人習慣,也符合主流的用法。

二、圖像數據的小誤會

打開一幅 640 x 480 的圖像:

import numpy as npimport matplotlib.pylab as pltimage = plt.imread("lena.jpg")print(image.shape)# --- 結果 ---# (480, 640, 3)# (y, x, c)

不是 640 x 480 嗎, 怎麼倒過來了?我寫代碼的時候在這裡總是犯迷糊。

在口頭表達中,我們先說寬640,再說高480,而在計算機中是先高(y) 後寬(x),注意了!

每個像素有三個顏色分量(color),所以這個維度放在了最右邊,可以理解,順序就是 (y, x, c)

三、抽象軸上的操作

對於4維及更高維度的數據,無法在3維空間圖示。這個時候,就不要考慮形象思維了,直接按照規則做處理。

用 shape 屬性返回的元組,從左到右,座標軸分別命名為 axis 0, axis 1, ...,請注意,現在是從左向右數,正好是這個元組的 index,在以後的運算中,都按此規定。

>>> print(data.shape)(3, 3, 2, 5)# axis 0: 3# axis 1: 3# axis 2: 2# axis 3: 5

心法2: 抽象座標軸順序從左向右。指定哪個軸,就只在哪個軸向操作,其他軸不受影響。

  1. 排序(sorting)

data = np.array(np.arange(12))np.random.shuffle(data)data = data.reshape(3, 4)print(data)# [[10 8 3 2]# [ 5 6 0 7]# [11 4 9 1]]print( np.sort(data, axis=0) )# [[ 5 4 0 1] | 小# [10 6 3 2] | 到# [11 8 9 7]] | 大print( np.sort(data, axis=1) ) # 小 到 大# ---------># [[ 2 3 8 10]# [ 0 5 6 7]# [ 1 4 9 11]]

如果你在心中能把抽象軸和 x, y, z 對應起來,則理解軸向排序很容易。

shape: (3, 4)axis: 0, 1AXIS: y, x

2. 求和、均值、方差、最大、最小、累加、累乘

這幾個函數調用,一般會指定軸向,注意適用 心法2

sum,mean,std,var,min,max 會導致這個軸被壓扁,縮減為一個數值,降維打擊??

data = np.arange(24).reshape(2, 3, 4)print(data)# [[[ 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( np.sum(data, axis=0) )# 0軸被sum壓扁,1軸2軸不變# [[12 14 16 18]# [20 22 24 26]# [28 30 32 34]]print( np.sum(data, axis=1) )# 1軸被sum壓扁,0軸2軸不變# [[12 15 18 21]# [48 51 54 57]]

cumsum,cumprod 不縮減軸向,只在指定軸向操作,請讀者自己試驗。

3. 索引和切片(indexing and slicing)

心法3: 在索引中出現冒號(:),則本軸繼續存在,如果只是一個數值,則本軸消失。

例如,像 :, :1, 1: 這樣的索引,保留此軸, data[:, :1, 2:] 中,三個軸都保留。 data[1, 4, 2] 三個軸都消失,只返回一個數值。

data[1:2, 0:1, 0:1] 中,三個軸都保留,但只有一個數據元素,很神奇吧。

data = np.arange(24).reshape(2, 3, 4)print( data )# [[[ 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( data[0, :, :] )# axis 0,即 z 軸,是數值,則 z 軸消失,切了一片 x-y # [[ 0 1 2 3]# [ 4 5 6 7]# [ 8 9 10 11]]print( data[0, 1, 2] )# 所有軸都消失,只返回一個標量數據# 6 print( data[0:1, 1:2, 2:3] )# 返回三維數據,雖然只有一個元素# [[[6]]]

如何查看 ndarray 的維度呢?可以訪問 shape 屬性;如果列印出來了,那麼就數一數起始的中括弧個數,比如 [[[6]]], 有三個 [,那麼就是三維數組。你記住了嗎?

4. 拼接(concatenating)

同樣遵循心法2,指定哪個軸,就在哪個軸向拼接:

data = np.arange(4).reshape(2, 2)print( np.concatenate([data, data], axis=0) )# 在軸向 0 拼接,即 y 方向# [[0 1]# [2 3]# [0 1]# [2 3]]print( np.concatenate([data, data], axis=1) )# 在軸向 1 拼接,即 x 方向# [[0 1 0 1]# [2 3 2 3]]

四、reshape 之迷亂

你有沒有這個困惑:在 reshape 之後,數據在各個軸上是如何重新分配的?

搞清楚 ndarray 的數據在內存里的存放方式,以及各個維度的訪問方式,reshape 困惑就迎刃而解了。

心法4: ndarray 的數據在內存里以一維線性存放,reshape 之後,數據並沒有移動,只是訪問方式變了而已。

數據優先填充 X 軸向,其次 Y 軸,其次 Z 軸 。。。

有 C 語言基礎的,很容易理解 ndarray 的實現,就是 C 中的多維數組而已。

int data[2][3][4];int data[4][6];

五、總結

就說這麼多,看了本文請親自動手寫代碼體驗一下。掌握此心法,可以縱橫 numpy 世界而無大礙。

心法1: x, y, z 對應的shape元組是從右往左數的。

心法2: 抽象座標軸順序從左向右。指定哪個軸,就只在哪個軸向操作,其他軸不受影響。

心法3: 在索引中出現冒號(:),則結果中本軸繼續存在,如果只是一個數值,則本軸消失。

心法4: ndarray 的數據在內存里以一維線性存放,reshape 之後,數據並沒有移動,只是訪問方式變了而已。


推薦閱讀:

今日芯聲 | 煙花匯演已經OUT啦!現在都看這!
[VFR]Quality Aware Network閱讀筆記
機器學習筆記五--正則化
【直播】智鈾科技CEO夏粉:大規模機器學習及未來技術發展

TAG:Python | 機器學習 | 科學計算 |