在介紹陣列的組合和分割前,我們需要先了解陣列的維(ndim)和軸(axis)概念。
如果陣列的元素是陣列,即陣列巢狀陣列,我們就稱其為多維陣列。幾層巢狀就稱幾維。比如形狀為(a,b)的二維陣列就可以看作兩個一維陣列,第一個一維陣列包含a個一維陣列,第二個一維陣列包含b個資料。
每一個一維線性陣列稱為一個軸。二維陣列的第一個軸(axis=0)就是以陣列為元素的陣列,第二個軸(axis=1)就是陣列中的陣列。因此第一個軸的方向就是沿著行的方向(垂直方向),第二個軸的方向沿著列的方向(水平方向)。
我們從巢狀陣列的角度來看,a[0],a[1],a[2],a[3]……分別是取二維陣列的第一行,二行,三行,四行……這正是先沿著第一個軸取元素(元素為行)。a[0][0],a[0][1]……則是(沿著第二個軸)取第一行的第一個元素,第二個元素……
也就是說,陣列的軸從最外層數起。
三維陣列我們應該怎麼理解呢?我們可以把它看作二維陣列的堆疊,即一個立方體。它的第一個軸(axis=0)就是以二維陣列為元素的陣列,它的方向沿著二維陣列堆疊的方向,也就是立方體的高。第二個軸自然就是立方體的寬,第三個軸就是立方體的長。舉例來說,一個形狀為(a,b,c)的三維陣列就是a個形狀為(b,c)的二維陣列巢狀在一起。
點選檢視程式碼
a=np.arange(24).reshape(2,3,4)#建立一個維度為3,形狀為(2,3,4)的三維陣列
print(a)#列印
print(a.sum(axis=0))#沿第一個軸求和
print(a.sum(axis=1))#沿第二個軸求和
print(a.sum(axis=2))#沿第三個軸求和
'''
a的形狀如下:
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
沿第一個軸求和:
[[12 14 16 18]
[20 22 24 26]
[28 30 32 34]]
沿第二個軸求和:
[[12 15 18 21]
[48 51 54 57]]
沿第三個軸求和:
[[ 6 22 38]
[54 70 86]]
'''
從這個例子可以看出,沿第一個軸求和,就是從上方把這個立方體“壓扁”,第二個軸就是沿著寬,第三個軸就是沿著長。類似投影。
我們終於明白了,reshape函式的引數順序不是我們想當然認為的長,寬;長,寬,高;因為你無法解釋為什麼三維陣列變形後的形狀與你所想的大相徑庭。它的順序是軸的順序(第一條軸,第二條軸,第三條軸……),也就是沿這條軸有多少個元素。軸的概念很重要,在很多函式中都有體現。
再直觀一點說,引數順序應該是高,寬(行方向),長(列方向)。
所以,陣列的維度就很好理解了,就是軸的數量。我們在理解多維陣列的時候,不要先入為主地認為多維陣列的元素會更多;多維陣列只是它巢狀的層數多而已。高維陣列也可能不含元素。
接下來我們介紹陣列的組合。
陣列的組合
陣列的組合有水平組合,垂直組合,深度組合等方式。實現這些組合的函式主要有vstack,dstack,hstack,column_stack,row_stack,concatenate等。
因為我們最常用的陣列也不過三維,所以用水平,垂直這樣的字眼比較形象;但我們要明白,本質上是沿軸進行的操作。
陣列組合通常不會改變陣列的維度。
1.水平組合
hstack函式與concatenate函式
1.1hstack函式:水平連線多個陣列。引數只有一個:以陣列為元素的序列。
1.2concatenate函式:沿著現有的軸連線陣列序列。
函式格式:concatenate((a1, a2, ...), axis=0, out=None)
引數說明:a1, a2, ...:為以陣列為元素的類陣列序列。其中陣列形狀必須相同。
axis=0:陣列將沿著這個軸組合,如果座標軸為None,陣列在使用前被平鋪。int型資料,可選引數,預設為零。
2.垂直組合
vstack函式與concatenate函式
2.1vstack函式:垂直連線多個陣列。引數如上。
2.2concatenate函式:改一下軸引數就好。
水平組合和垂直組合是比較直觀的說法,因為我們用的最多的陣列就是一維和二維;實際上,它們分別是沿著第二條軸(水平),第一條軸(垂直)進行組合。
點選檢視程式碼
a=np.array([1])
a=a.reshape(1,1,1,1,1)#只有一個元素的五維陣列
b=np.array([1])
b=b.reshape(1,1,1,1,1)#與a完全相同
c=np.hstack((a,b))#水平組合
d=np.vstack((a,b))#垂直組合
print(c)
print(d)
print(c.shape)
print(d.shape)
'''
水平組合
[[[[[1]]]
[[[1]]]]]
垂直組合
[[[[[1]]]]
[[[[1]]]]]
c的形狀
(1, 2, 1, 1, 1)
d的形狀
(2, 1, 1, 1, 1)
'''
3.行組合和列組合
3.1row_stack函式:行組合
將一維陣列按行方向組合起來,對於二維陣列完全等同於vstack。對於多維陣列,實際上就是沿第一個軸進行組合。
3.2colum_stack函式:列組合
將一維陣列按列方向組合起來,對於二維陣列完全等同於hstack。對於多維陣列,實際上就是沿第二個軸進行組合。
點選檢視程式碼
a=np.array([0,1,2])
b=np.array([1,2,3])
c=np.row_stack((a,b))
d=np.column_stack((a,b))
print(c)
print(d)
'''
行組合
[[0 1 2]
[1 2 3]]
列組合
[[0 1]
[1 2]
[2 3]]
'''
a=np.array([0,1,2]).reshape(1,1,1,1,3)
b=np.array([1,2,3]).reshape(1,1,1,1,3)
c=np.row_stack((a,b))
d=np.column_stack((a,b))
print(c)
print(d)
print(c.shape)
print(d.shape)
'''
行組合
[[[[[0 1 2]]]]
[[[[1 2 3]]]]]
[[[[[0 1 2]]]
列組合
[[[1 2 3]]]]]
c形狀
(2, 1, 1, 1, 3)
d形狀
(1, 2, 1, 1, 3)
'''
4.深度組合
沿著第三個軸進行組合。
點選檢視程式碼
a=np.array([0,1,2])
b=np.array([1,2,3])
c=np.dstack((a,b))#深度組合
print(c)
print(a.shape)
print(c.shape)
'''
[[[0 1]
[1 2]
[2 3]]]
(3,)
(1, 3, 2)
'''
a=np.array([0,1,2]).reshape(1,1,1,3)
b=np.array([1,2,3]).reshape(1,1,1,3)
c=np.dstack((a,b))
print(c.shape)
'''
(1, 1, 2, 3)
'''
當陣列維度比較小的時候,比如一維和二維,如果組合時沒有第二和第三引數,函式會自動為其在形狀左側補1,也就是擴充一層。這和之前說過的廣播機制十分類似。
陣列的分割
陣列可以進行水平,垂直等方式進行分割。相關函式:hsplit,vsplit,dsplit,split。
我們可以將陣列分割成相同大小(形狀)的子陣列,也可以指定分割的位置。
1.水平分割
hsplit函式和split函式。
沿水平方向,就是沿列方向,沿第二條軸(axis=1)方向。
1.1hsplit函式
格式:hsplit(ary, indices_or_sections)
第一個引數是陣列;第二個引數是一個整數或列表,如果不指定,就會分割成相同大小的子陣列。
點選檢視程式碼
a=np.arange(16).reshape(4,4)
pp.pprint(a)
pp.pprint(np.hsplit(a,2))#平均分割成兩部分
pp.pprint(np.hsplit(a,[2,3]))#沿第二,三列,分割成三部分
'''
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
分割成兩部分
[array([[ 0, 1],
[ 4, 5],
[ 8, 9],
[12, 13]]),
array([[ 2, 3],
[ 6, 7],
[10, 11],
[14, 15]])]
分割成三部分
[array([[ 0, 1],
[ 4, 5],
[ 8, 9],
[12, 13]]),
array([[ 2],
[ 6],
[10],
[14]]),
array([[ 3],
[ 7],
[11],
[15]])]
'''
1.2split函式
函式格式:split(ary, indices_or_sections, axis=0)
第一個引數:陣列。
第二個引數:整數或列表,可選引數。
第三個引數:軸,可選引數。
點選檢視程式碼
a=np.arange(24).reshape(4,6)
print(a)
pp.pprint(np.split(a,[2],axis=0))
'''
[[ 0 1 2 3 4 5]
[ 6 7 8 9 10 11]
[12 13 14 15 16 17]
[18 19 20 21 22 23]]
[array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11]]),
array([[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23]])]
'''
上面這個例子裡,我們選擇了第一條軸,也就是列方向。然後找到第二行一分為二。
點選檢視程式碼
點選檢視程式碼
a=np.arange(24).reshape(2,3,4)
print(a)
pp.pprint(np.split(a,[1],axis=0))#沿第一條軸,高
pp.pprint(np.split(a,[1],axis=1))#沿第二條軸,寬
pp.pprint(np.split(a,[1],axis=2))#沿第三條軸,長
'''
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
[array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]]]),
array([[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])]
[array([[[ 0, 1, 2, 3]],
[[12, 13, 14, 15]]]),
array([[[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[16, 17, 18, 19],
[20, 21, 22, 23]]])]
[array([[[ 0],
[ 4],
[ 8]],
[[12],
[16],
[20]]]),
array([[[ 1, 2, 3],
[ 5, 6, 7],
[ 9, 10, 11]],
[[13, 14, 15],
[17, 18, 19],
[21, 22, 23]]])]
'''
上面是一個三維陣列切割的例子。
2.垂直分割
vsplit函式和split函式
沿垂直方向,就是沿行方向,沿第一條軸(axis=0)方向。
split函式如上,改一條軸引數即可。
3.深度分割
dsplit函式
主要用於三維陣列,其實就是沿第三條軸切割,就好比從上方切蛋糕一樣。
點選檢視程式碼
a=np.arange(24).reshape(2,3,4)
b=np.dsplit(a,4)#把這個蛋糕從上切成四份
pp.pprint(b)
'''
[array([[[ 0],
[ 4],
[ 8]],
[[12],
[16],
[20]]]),
array([[[ 1],
[ 5],
[ 9]],
[[13],
[17],
[21]]]),
array([[[ 2],
[ 6],
[10]],
[[14],
[18],
[22]]]),
array([[[ 3],
[ 7],
[11]],
[[15],
[19],
[23]]])]
'''
以上。