1.數(shù)組的索引和切片(可類比于list的索引和切片,注意區(qū)別)
數(shù)組
選取數(shù)據(jù)子集或單個(gè)元素的方式有很多。一維數(shù)組跟list很相似桃煎,多維數(shù)組的花樣更多, 下面來看。
1. 1基本的索引和切片
先來看一下例子筐骇,體會(huì)一下一維數(shù)組與list的區(qū)別:
import numpy as np
temp_array = np.arange(15) # array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
temp_list = list(range(15)) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
# 索引比較
temp_array[10] #返回值: 10
temp_list[10] #返回值: 10
# 切片比較
temp_array[1:5] #返回值 array([1, 2, 3, 4])
temp_list[1:5] #返回值 [1, 2, 3, 4]
# 對(duì)單個(gè)值賦值比較
temp_list[1] = 6
temp_list # 返回值 [0, 6, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
temp_array[1] = 6
temp_array # 返回值 array([ 0, 6, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
# 對(duì)切片賦值比較
temp_array[1:5] = 6
temp_array # 返回值 array([ 0, 6, 6, 6, 6, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
# temp_list[1:5] = 6 # 報(bào)錯(cuò) TypeError: can only assign an iterable
# 切片之后索引賦值比較
#先來看list
temp_list2 = temp_list[1:5]
temp_list2 # [6, 2, 3, 4]
temp_list2[2] = 1234
temp_list #返回值: [0, 6, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
temp_list2 # 返回值 [6, 2, 1234, 4]
temp_list[3] = 12341234 #對(duì)原始list修改
temp_list2 # 返回值:[6, 2, 1234, 4]
#再來看array
temp_array2 = temp_array[2:8]
temp_array2 # array([6, 6, 6, 5, 6, 7])
temp_array2[2] = 1234
temp_array2 #返回值:array([ 6, 6, 1234, 5, 6, 7])
temp_array # 返回值 array([ 0, 6, 6, 6, 1234, 5, 6, 7, 8, 9, 10,11, 12, 13, 14])
temp_array[5] = 123123 # 對(duì)原始數(shù)組的修改
temp_array2 # 返回值: array([ 6, 6, 1234, 123123, 6, 7])
通過看上邊的例子, 不難發(fā)現(xiàn)ndarray和list的索引江滨、切片铛纬、對(duì)單個(gè)值賦值基本都一樣, 區(qū)別在于對(duì)切片直接賦值唬滑、切片單個(gè)值的賦值告唆,list的切片賦值直接報(bào)錯(cuò),數(shù)組的切片修改间雀,該值會(huì)自動(dòng)廣播到整個(gè)選區(qū)的元素悔详。
ndarray切片是原始數(shù)組的視圖
(可以理解為地址指向,類比于淺拷貝.),視圖上的任何修改都會(huì)直接反應(yīng)到原數(shù)組上惹挟,源數(shù)據(jù)的修改也會(huì)影響視圖茄螃。Numpy的這種做法其實(shí)不難理解,Numpy是用來處理大數(shù)據(jù)的连锯,如果將其中的數(shù)據(jù)多次復(fù)制的話那得是多大的內(nèi)存和性能的消耗归苍。
當(dāng)然,如果想要的得到的數(shù)組的切片是一個(gè)副本而不是視圖的話运怖,需要進(jìn)行復(fù)制操作拼弃,即 temp_array[1:5].copy()
,如果非必須,還是不要辣么做了摇展!
來看一下多維數(shù)組的例子(拿二維為例):
# 二維:
temp_array5 = np.eye(4)
temp_array5
#返回值: array([[1., 0., 0., 0.],
# [0., 1., 0., 0.],
# [0., 0., 1., 0.],
# [0., 0., 0., 1.]])
temp_array5[2]# 返回值:array([0., 0., 1., 0.])
temp_array5[2][2] # 返回值 1.0
temp_array5[:3] # [:3]的切片
# 返回值: array([[1., 0., 0., 0.],
# [0., 1., 0., 0.],
# [0., 0., 1., 0.]])
temp_array5[:3:2] # 類比于list吻氧,這就是[:3]的切片, 步長為2
# 返回值: array([[1., 0., 0., 0.],
# [0., 0., 1., 0.]])
temp_array5[:3] = 42 # 視圖賦值
temp_array5
#返回值: array([[42., 42., 42., 42.],
# [42., 42., 42., 42.],
# [42., 42., 42., 42.],
# [ 0., 0., 0., 1.]])
temp_array5[1,2] = 88 #與 temp_array5[1][2] 一樣
temp_array5
# 返回值:array([[42., 42., 42., 42.],
# [42., 42., 88., 42.],
# [42., 42., 42., 42.],
# [ 0., 0., 0., 1.]])
1.2切片索引
低維度的切片索引其實(shí)在1.1已經(jīng)用到過了咏连, 現(xiàn)在咱們直接用多維的來為例:
temp_list = [[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]
temp_array = np.array(temp_list)
temp_array.shape # 返回值: (2, 2, 3)
temp_array[1, :1] # 返回值 array([[7, 8, 9]])
temp_array[:2, :1] # array([[[1, 2, 3]],[[7, 8, 9]]])
# 注:相當(dāng)于temp_array[0][:1]與temp_array[1][:1] 的結(jié)合盯孙,不是相加,相加會(huì)廣播到元素級(jí)祟滴。
# 這里需要注意
temp_array[1,0,1] # 返回值 8
# temp_array[1,0,1]的元素和 temp_array[1,1,1]的元素組成的列表
temp_array[1,:,1] #array([ 8, 11])
# 請(qǐng)參考上一種請(qǐng)情況
temp_array[:,:,1]
# 返回值:array([[ 2, 5],
# [ 8, 11]])
temp_array[:,:,1] = 110
temp_array
# array([[[ 1, 110, 3],
# [ 4, 110, 6]],
# [[ 7, 110, 9],
# [ 10, 110, 12]]])
# 注:只寫一個(gè)冒號(hào)振惰, 表示選取的對(duì)應(yīng)的整個(gè)維度。
1.3 布爾型索引
值的注意的是布爾型索引返回的值是副本而不是視圖垄懂,不是視圖F锞А!草慧!
#數(shù)據(jù)準(zhǔn)備
temp_array1 = np.array('a b c d e f'.split(' '))
temp_array1 #array(['a', 'b', 'c', 'd', 'e', 'f'], dtype='<U1')
temp_array2 = np.random.randn(6,3)
temp_array2
# array([[-1.75405219, -0.33932199, 0.16753136],
# [-0.40832969, 0.28943606, -0.29946825],
# [-1.15116563, -1.93324644, 0.04890539],
# [-2.55618941, -0.55516265, 0.13617437],
# [ 2.11503851, 1.84211619, 0.35172968],
# [ 0.75279809, 0.63056373, -1.1371636 ]])
# 單獨(dú)的判斷可以廣播到元素級(jí)桶蛔,這不是中點(diǎn), 布爾切片才是重點(diǎn)
temp_array1 == 'a' # 返回值 array([ True, False, False, False, False, False])
temp_array2>0
# array([[ True, True, True],
# [False, True, False],
# [False, False, True],
# [False, False, True],
# [ True, True, True],
# [ True, True, False]])
temp_array2[temp_array1 == 'a'] #返回值:array([[-1.75405219, -0.33932199, 0.16753136]])
temp_array3 = temp_array2[temp_array1 == 'a']
temp_array2[0] = 5
temp_array3 #返回值:array([[-1.75405219, -0.33932199, 0.16753136]])
temp_array2
# array([[ 5. , 5. , 5. ],
# [-0.40832969, 0.28943606, -0.29946825],
# [-1.15116563, -1.93324644, 0.04890539],
# [-2.55618941, -0.55516265, 0.13617437],
# [ 2.11503851, 1.84211619, 0.35172968],
# [ 0.75279809, 0.63056373, -1.1371636 ]])
# 注: 這里返回的并不是視圖漫谷, 而是副本羽圃,是副本不是視圖 不是視圖。
# 可以寫為并列形式
temp_array2[(temp_array1 == 'a') | (temp_array1 == 'b')]
# 注:and 和or在布爾型數(shù)組中無效
# 返回值:array([[ 5. , 5. , 5. ],
# [-0.40832969, 0.28943606, -0.29946825]])
# 當(dāng)然還有這種形式
temp_array2[(temp_array1 == 'a'),:2] # array([[5., 5.]])
1.4 花式索引
花式索引是Numpy術(shù)語,指的是利用整數(shù)數(shù)組進(jìn)行索引朽寞。返回的并不是視圖识窿, 也是副本。
temp_array = np.eye(6)
temp_array[[1,2]]
# 返回值: array([[0., 1., 0., 0., 0., 0.],
# [0., 0., 1., 0., 0., 0.]])
temp_array[[1,-2]]
# array([[0., 1., 0., 0., 0., 0.],
# [0., 0., 0., 0., 1., 0.]])
temp_array[[1,-2],[1,2]] # 返回值 array([1., 0.])脑融, 我擦喻频, 這種看不出來啊, 咱們換一種
temp_array = np.arange(24).reshape((6,4))
temp_array
# 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]])
temp_array[[1,2,3]]
# array([[ 4, 5, 6, 7],
# [ 8, 9, 10, 11],
# [12, 13, 14, 15]])
temp_array[[1,2,3],[2,3,1]] #最終選取的元素是(1,2),(2,3), (3,1)返回值: array([ 6, 11, 13])
temp_array[[1,2,3]][:,[2,3,1]] # 這個(gè)是選取的方形區(qū)域肘迎, 注意以上兩種的寫法區(qū)別
# 返回值 array([[ 6, 7, 5],
# [10, 11, 9],
# [14, 15, 13]])
#注:花式索引返回的是副本甥温, 而不是視圖。
2.數(shù)組的轉(zhuǎn)置和軸的對(duì)換
轉(zhuǎn)置
是重塑的一種特殊形式妓布,它返回的是源數(shù)據(jù)的視圖姻蚓, 轉(zhuǎn)置最少要兩維。
#兩維數(shù)組
temp_array = np.arange(9).reshape((3,3))
# 兩維數(shù)組的轉(zhuǎn)置匣沼, 這兩種方式等價(jià)
temp_array.transpose(1,0)
# 返回值:array([[0, 3, 6],
# [1, 4, 7],
# [2, 5, 8]])
temp_array.T
# 返回值:array([[0, 3, 6],
# [1, 4, 7],
# [2, 5, 8]])
# 更高維度的數(shù)組轉(zhuǎn)置
temp_array2 = np.arange(27).reshape((3,3,3))
temp_array2
# 返回值: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],
# [24, 25, 26]]])
temp_array2.transpose((1,0,2))
# 返回值:array([[[ 0, 1, 2],
# [ 9, 10, 11],
# [18, 19, 20]],
# [[ 3, 4, 5],
# [12, 13, 14],
# [21, 22, 23]],
# [[ 6, 7, 8],
# [15, 16, 17],
# [24, 25, 26]]])
temp_array2.transpose((1,2,0))
# 返回值:array([[[ 0, 9, 18],
# [ 1, 10, 19],
# [ 2, 11, 20]],
# [[ 3, 12, 21],
# [ 4, 13, 22],
# [ 5, 14, 23]],
# [[ 6, 15, 24],
# [ 7, 16, 25],
# [ 8, 17, 26]]])
temp_array2.T # 等價(jià)于 temp_array2.transpose((2,1,0))
#返回值: array([[[ 0, 9, 18],
# [ 3, 12, 21],
# [ 6, 15, 24]],
# [[ 1, 10, 19],
# [ 4, 13, 22],
# [ 7, 16, 25]],
# [[ 2, 11, 20],
# [ 5, 14, 23],
# [ 8, 17, 26]]])
是不是看的恍恍惚惚狰挡,迷迷瞪瞪.... 哈哈,我當(dāng)時(shí)看的時(shí)候也是如此释涛,那下邊再來看一個(gè)例子(拿三維來講):
temp_array = np.arange(24).reshape((2,3,4))
temp_array # 原始數(shù)組
# 返回值: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]]])
temp_array.transpose(1,0,2).shape # 返回值:(3, 2, 4)
temp_array.transpose(1,0,2)
# 返回值:array([[[ 0, 1, 2, 3],
# [12, 13, 14, 15]],
# [[ 4, 5, 6, 7],
# [16, 17, 18, 19]],
# [[ 8, 9, 10, 11],
# [20, 21, 22, 23]]])
temp_array.transpose(1,2,0) # 其形狀為(3加叁,4,2)
# 返回值:array([[[ 0, 12],
# [ 1, 13],
# [ 2, 14],
# [ 3, 15]],
# [[ 4, 16],
# [ 5, 17],
# [ 6, 18],
# [ 7, 19]],
# [[ 8, 20],
# [ 9, 21],
# [10, 22],
# [11, 23]]])
temp_array.transpose(2,1,0)# 其形狀為(4唇撬,3它匕,2)
#返回值: array([[[ 0, 12],
# [ 4, 16],
# [ 8, 20]],
# [[ 1, 13],
# [ 5, 17],
# [ 9, 21]],
# [[ 2, 14],
# [ 6, 18],
# [10, 22]],
# [[ 3, 15],
# [ 7, 19],
# [11, 23]]])
從例子可以看出,數(shù)組的轉(zhuǎn)置是按照軸來轉(zhuǎn)換的窖认,軸的編號(hào)即對(duì)應(yīng)維度的下標(biāo)豫柬,比如原始數(shù)據(jù)temp_array的形狀(2,3,4),則0軸對(duì)應(yīng)的維度是2扑浸,即第一層中括號(hào)里的數(shù)據(jù)烧给,1號(hào)周對(duì)應(yīng)的維度是3,即第二層括號(hào)里的數(shù)據(jù)首装,3軸對(duì)應(yīng)的維度是4,即第三層里的數(shù)據(jù)杭跪,即元素仙逻。那么軸的轉(zhuǎn)換,比如原始數(shù)據(jù)(0,1,2)涧尿,轉(zhuǎn)換為(1,0,2),也就是1號(hào)軸沿著0軸拼數(shù)據(jù)系奉, 然后組成形狀為 (3,2,4)的數(shù)據(jù), 咱們依次看圖:
注:temp_array.transpose(1,2,0)的數(shù)據(jù)可在temp_array.transpose(1,0,2)的基礎(chǔ)上求得在此不再展示。