数组基本切片
数组切片与列表切片形式上相同,但有重要区别:数组切片得到的是原始数组的视图,对视图也就是切片的任何修改都会直接影响到原始数组;若要避免此情况发生,需对切片进行复制操作。
In [1]: import numpy as np
In [2]: arr=np.array([1,2,3,4,5,6,7,8,9,])
# 获取切片
In [3]: arr1=arr[5:8]
In [4]: arr1
Out[4]: array([6, 7, 8])
# 修改切片内容
In [5]: arr1[1]=99
In [6]: arr1
Out[6]: array([ 6, 99, 8])
# 原始数组被修改
In [7]: arr
Out[7]: array([ 1, 2, 3, 4, 5, 6, 99, 8, 9])
# 获取切片副本
In [8]: arr2=arr[1:4].copy()
# 修改切片副本
In [9]: arr2[:]=88
In [10]: arr2
Out[10]: array([88, 88, 88])
# 原始数组未被修改
In [11]: arr
Out[11]: array([ 1, 2, 3, 4, 5, 6, 99, 8, 9])
多维数组索引
多维数组中,索引位置的元素是索引位置的低一维度数组:
In [15]: arr3d
Out[15]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
# 三维数组索引位置元素为二维数组
In [16]: arr3d[0]
Out[16]:
array([[1, 2, 3],
[4, 5, 6]])
# 二维数组arr3d[0]的索引位置元素为一维数组
In [18]: arr3d[0][1]
Out[18]: array([4, 5, 6])
# 以上写法等价于
In [19]: arr3d[0,1]
Out[19]: array([4, 5, 6])
# 注意所得到的所有数组都是原数组的视图,修改后会影响到原数组
In [20]: arr3d[0,1]=99
In [21]: arr3d
Out[21]:
array([[[ 1, 2, 3],
[99, 99, 99]],
[[ 7, 8, 9],
[10, 11, 12]]])
多维数组切片
关于轴的概念:N维数组[0轴,1轴,2轴…]
0轴代表数组里的下一维度的所有数组,如三维数组的0轴代表里面的所有二维数组,若在0轴进行切片,则根据索引位置得到符合切片条件的二维数组组成的三维数组
In [22]: arr3d=np.random.randn(3,3,3)
In [23]: arr3d
Out[23]:
array([[[ 1.02094993, -0.25748933, 0.49529658],
[-0.73540525, 0.03011562, -0.11699791],
[-0.66396291, 0.47977574, -0.86229023]],
[[-0.39319381, 0.84935699, -1.72054416],
[-0.36710115, 0.54590238, 0.12768586],
[ 0.006033 , 1.26805717, -0.85041817]],
[[ 2.23066809, -0.03880021, 0.62391508],
[-0.51181805, 0.55001299, -0.52990981],
[ 0.50243183, -1.29463259, 0.2809969 ]]])
# 在0轴选取索引为1的数组,得到一个二维数组
In [24]: arr3d[1]
Out[24]:
array([[-0.39319381, 0.84935699, -1.72054416],
[-0.36710115, 0.54590238, 0.12768586],
[ 0.006033 , 1.26805717, -0.85041817]])
# 选取整个0轴所有数组,得到一个与原数组相同的三维数组
In [25]: arr3d[:]
Out[25]:
array([[[ 1.02094993, -0.25748933, 0.49529658],
[-0.73540525, 0.03011562, -0.11699791],
[-0.66396291, 0.47977574, -0.86229023]],
[[-0.39319381, 0.84935699, -1.72054416],
[-0.36710115, 0.54590238, 0.12768586],
[ 0.006033 , 1.26805717, -0.85041817]],
[[ 2.23066809, -0.03880021, 0.62391508],
[-0.51181805, 0.55001299, -0.52990981],
[ 0.50243183, -1.29463259, 0.2809969 ]]])
# 选取0轴索引1及其之后的所有数组,得到三维数组
In [26]: arr3d[1:]
Out[26]:
array([[[-0.39319381, 0.84935699, -1.72054416],
[-0.36710115, 0.54590238, 0.12768586],
[ 0.006033 , 1.26805717, -0.85041817]],
[[ 2.23066809, -0.03880021, 0.62391508],
[-0.51181805, 0.55001299, -0.52990981],
[ 0.50243183, -1.29463259, 0.2809969 ]]])
# 继续对第一轴切片
In [27]: arr3d[1:,:2]
Out[27]:
array([[[-0.39319381, 0.84935699, -1.72054416],
[-0.36710115, 0.54590238, 0.12768586]],
[[ 2.23066809, -0.03880021, 0.62391508],
[-0.51181805, 0.55001299, -0.52990981]]])
# 对第二轴切片
In [28]: arr3d[1:,:2,:2]
Out[28]:
array([[[-0.39319381, 0.84935699],
[-0.36710115, 0.54590238]],
[[ 2.23066809, -0.03880021],
[-0.51181805, 0.55001299]]])
如果是整数索引值和切片混合的形式,得到的是低维数组,用了几个整数索引,就降低几个维度
# 1个整数索引,得到二维数组
In [29]: arr3d[1:,:2,1]
Out[29]:
array([[ 0.84935699, 0.54590238],
[-0.03880021, 0.55001299]])
# 2个整数索引,得到一维数组
In [30]: arr3d[1:,2,1]
Out[30]: array([ 1.26805717, -1.29463259])
# 1个整数索引,得到二维数组
In [31]: arr3d[1:,2,:1]
Out[31]:
array([[0.006033 ],
[0.50243183]])
布尔型索引
首先看一下布尔型数组:将数组的每一项进行比较运算,得到一个布尔型数组,布尔型数组长度与被比较运算的数组长度一致。
In [1]: import numpy as np
In [5]: arr=np.array(['a','b','c','a','c','a','b'])
# 进行比较运算,得到布尔型数组
In [6]: arr=='a'
Out[6]: array([ True, False, False, True, False, True, False])
布尔型数组可以用于数组索引,注意布尔型数组长度必须与被索引的轴长度一致,否则会报错。
In [7]: data=np.random.randn(7,5)
In [8]: data
Out[8]:
array([[-1.0421789 , 0.41829044, 0.08944954, 0.12645803, -0.40935427],
[ 1.21961155, -0.02031749, -0.13001254, 0.29300447, 0.38276386],
[-0.35819886, 0.76682037, -0.41631962, -0.87569041, 0.09891561],
[ 1.04279164, 0.91863713, -1.32444645, 0.17339838, -0.13449775],
[ 0.86258146, -0.1482636 , 0.22699184, 1.49022121, -1.33382424],
[ 1.31024788, -1.64080733, 1.18200595, 0.02418984, -0.52658514],
[-1.67317396, 1.02168529, 0.35032796, -0.04599171, 0.97521544]])
# 在数组data中选取0轴的索引位置与布尔型数组中内容为true的索引位置相同的内容
In [9]: data[arr=='a']
Out[9]:
array([[-1.0421789 , 0.41829044, 0.08944954, 0.12645803, -0.40935427],
[ 1.04279164, 0.91863713, -1.32444645, 0.17339838, -0.13449775],
[ 1.31024788, -1.64080733, 1.18200595, 0.02418984, -0.52658514]])
# 使用布尔值索引的时候也可以与切片或者其他索引混合使用
In [10]: data[arr=='a',1:3]
Out[10]:
array([[ 0.41829044, 0.08944954],
[ 0.91863713, -1.32444645],
[-1.64080733, 1.18200595]])
# 也可以对其他轴进行布尔值索引,下面对1轴进行布尔值索引
In [15]: data[:,arr[1:6]=='a']
Out[15]:
array([[ 0.08944954, -0.40935427],
[-0.13001254, 0.38276386],
[-0.41631962, 0.09891561],
[-1.32444645, -0.13449775],
[ 0.22699184, -1.33382424],
[ 1.18200595, -0.52658514],
[ 0.35032796, 0.97521544]])
使用布尔型索引还能进行反选,使用!=
或者使用~
表示对条件表达式否定;也可使用逻辑运算符|
、&
组合多个条件():
In [26]: data[arr!='a']
Out[26]:
array([[ 1.21961155, -0.02031749, -0.13001254, 0.29300447, 0.38276386],
[-0.35819886, 0.76682037, -0.41631962, -0.87569041, 0.09891561],
[ 0.86258146, -0.1482636 , 0.22699184, 1.49022121, -1.33382424],
[-1.67317396, 1.02168529, 0.35032796, -0.04599171, 0.97521544]])
In [27]: data[~(arr=='a')]
Out[27]:
array([[ 1.21961155, -0.02031749, -0.13001254, 0.29300447, 0.38276386],
[-0.35819886, 0.76682037, -0.41631962, -0.87569041, 0.09891561],
[ 0.86258146, -0.1482636 , 0.22699184, 1.49022121, -1.33382424],
[-1.67317396, 1.02168529, 0.35032796, -0.04599171, 0.97521544]])
In [31]: data[(arr=='a')|(arr=='c')]
Out[31]:
array([[-1.0421789 , 0.41829044, 0.08944954, 0.12645803, -0.40935427],
[-0.35819886, 0.76682037, -0.41631962, -0.87569041, 0.09891561],
[ 1.04279164, 0.91863713, -1.32444645, 0.17339838, -0.13449775],
[ 0.86258146, -0.1482636 , 0.22699184, 1.49022121, -1.33382424],
[ 1.31024788, -1.64080733, 1.18200595, 0.02418984, -0.52658514]])
注意:Python关键字and和or在布尔型数组中无效。要使用&与|。
几个布尔型索引的典型使用场景:
# 批量修改符合条件的数组元素,如将所有负数设置为0:
In [38]: data[data<0]=0
In [39]: data
Out[39]:
array([[0. , 0.41829044, 0.08944954, 0.12645803, 0. ],
[1.21961155, 0. , 0. , 0.29300447, 0.38276386],
[0. , 0.76682037, 0. , 0. , 0.09891561],
[1.04279164, 0.91863713, 0. , 0.17339838, 0. ],
[0.86258146, 0. , 0.22699184, 1.49022121, 0. ],
[1.31024788, 0. , 1.18200595, 0.02418984, 0. ],
[0. , 1.02168529, 0.35032796, 0. , 0.97521544]])
# 修改整行数据
In [51]: data[arr=='c']=0.99
In [52]: data
Out[52]:
array([[0. , 0.41829044, 0.08944954, 0.12645803, 0. ],
[1.21961155, 0. , 0. , 0.29300447, 0.38276386],
[0.99 , 0.99 , 0.99 , 0.99 , 0.99 ],
[1.04279164, 0.91863713, 0. , 0.17339838, 0. ],
[0.99 , 0.99 , 0.99 , 0.99 , 0.99 ],
[1.31024788, 0. , 1.18200595, 0.02418984, 0. ],
[0. , 1.02168529, 0.35032796, 0. , 0.97521544]])
# 修改整列数据
In [53]: arr1=np.array(['x','y','x','z','y'])
In [54]: data[:,arr1=='y']=0.88
In [55]: data
Out[55]:
array([[0. , 0.88 , 0.08944954, 0.12645803, 0.88 ],
[1.21961155, 0.88 , 0. , 0.29300447, 0.88 ],
[0.99 , 0.88 , 0.99 , 0.99 , 0.88 ],
[1.04279164, 0.88 , 0. , 0.17339838, 0.88 ],
[0.99 , 0.88 , 0.99 , 0.99 , 0.88 ],
[1.31024788, 0.88 , 1.18200595, 0.02418984, 0.88 ],
[0. , 0.88 , 0.35032796, 0. , 0.88 ]])
花式索引
花式索引使用一个整数数组进行索引,这个整数数组必须是一维数组,数组里的每个整数代表索引号,选取得到的数组内容按照整数数组内部的顺序排列。若整数为负数,则从末尾开始选取。
In [1]: import numpy as np
In [2]: arr=np.arange(32).reshape((8,4))
In [3]: arr
Out[3]:
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, 27],
[28, 29, 30, 31]])
# 建立一个整数数组作为花式索引
In [4]: index_list=[4,2,5,7]
# 得到一个arr数组中按索引位置4,2,5,7顺序组成的数组
In [5]: arr[index_list]
Out[5]:
array([[16, 17, 18, 19],
[ 8, 9, 10, 11],
[20, 21, 22, 23],
[28, 29, 30, 31]])
# 负数从末尾开始选取
In [6]: arr[[-3,-1,-2]]
Out[6]:
array([[20, 21, 22, 23],
[28, 29, 30, 31],
[24, 25, 26, 27]])
若同时传入多个索引数组,比如在传入的第一个数组之外再传入一个数组,希望将第一个数组选取之后得到的数组再按[0, 3, 1, 2]的顺序进行列排序,但得到的结果并不是我们想要的,而是一个包含由两个数组内容组成的坐标点位置所代表的元素的数组:
# 以下选取的结果其实是arr数组中(1,0)、(5,3)、(7,1)、(2,2)位置的元素
In [7]: arr[[1, 5, 7, 2], [0, 3, 1, 2]]
Out[7]: array([ 4, 23, 29, 10])
若想使用第二个索引数组对列的内容进行排序和选取,则应该这样:
In [8]: arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]]
Out[8]:
array([[ 4, 7, 5, 6],
[20, 23, 21, 22],
[28, 31, 29, 30],
[ 8, 11, 9, 10]])
对花式索引得到的数组进行修改,不会影响到原数组内容,这与数组切片不一样。
数组转置和轴对换
使用T属性进行转置
In [23]: arr
Out[23]:
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, 27],
[28, 29, 30, 31]])
In [24]: arr.T
Out[24]:
array([[ 0, 4, 8, 12, 16, 20, 24, 28],
[ 1, 5, 9, 13, 17, 21, 25, 29],
[ 2, 6, 10, 14, 18, 22, 26, 30],
[ 3, 7, 11, 15, 19, 23, 27, 31]])
使用transpose对高维数组进行转置:每个多维数组的最底层元素X,都有一个坐标值,如 :X(a,b,c),这个(a,b,c)顺序可以使用元组(0,1,2)的来表示;transpose要指定一个元组来表示如何进行转置,数组元素的坐标(a,b,c)的排列顺序根据元组的顺序来确定,最终根据坐标重新排列,得到一个按照元组顺序转置后的数组。
In [27]: arr = np.arange(16).reshape((2, 2, 4))
In [28]: arr
Out[28]:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
In [29]: arr.transpose((1, 0, 2))
Out[29]:
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15]]])
此表为arr数组所有元素及坐标列表,初始坐标顺序是(0,1,2)
索引位置 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
0 | 0(0,0,0) | 1(0,0,1) | 2(0,0,2) | 3(0,0,3) |
1 | 4(0,1,0) | 5(0,1,1) | 6(0,1,2) | 7(0,1,3) |
2 | 8(1,0,0) | 9(1,0,1) | 10(1,0,2) | 11(1,0,3) |
3 | 12(1,1,0) | 13(1,1,1) | 14(1,1,2) | 15(1,1,3) |
transpose使用的元组顺序是(1,0,2),也就是要将第1,2坐标的位置互换,比如4(0,1,0)互换坐标后得到4(1,0,0),以此类推调整所有元素坐标,并重新按索引顺序排列,得到的结果与上面运算得到的一致。
索引位置 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
0 | 0(0,0,0) | 1(0,0,1) | 2(0,0,2) | 3(0,0,3) |
1 | 8(0,1,0) | 9(0,1,1) | 10(0,1,2) | 11(0,1,3) |
2 | 4(1,0,0) | 5(1,0,1) | 6(1,0,2) | 7(1,0,3) |
3 | 12(1,1,0) | 13(1,1,1) | 14(1,1,2) | 15(1,1,3) |
swapaxes方法:接受2个轴编号,将这两个轴进行对换,可以按transpose的思路去理解,就是把指定位置的元素坐标值进行对换,比如swapaxes(2,0)是对换0和2坐标的位置。
In [41]: arr.swapaxes(2,0)
Out[41]:
array([[[ 0, 8],
[ 4, 12]],
[[ 1, 9],
[ 5, 13]],
[[ 2, 10],
[ 6, 14]],
[[ 3, 11],
[ 7, 15]]])
转换后的元素坐标
索引位置 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
0 | 0(0,0,0) | 1(1,0,0) | 2(2,0,0) | 3(3,0,0) |
1 | 4(0,1,0) | 5(1,1,0) | 6(2,1,0) | 7(3,1,0) |
2 | 8(0,0,1) | 9(1,0,1) | 10(2,0,1) | 11(3,0,1) |
3 | 12(0,1,1) | 13(1,1,1) | 14(2,1,1) | 15(3,1,1) |
重新进行排序后
索引位置 | 0 | 1 |
---|---|---|
0 | 0(0,0,0) | 8(0,0,1) |
1 | 4(0,1,0) | 12(0,1,1) |
2 | 1(1,0,0) | 9(1,0,1) |
3 | 5(1,1,0) | 13(1,1,1) |
4 | 2(2,0,0) | 10(2,0,1) |
5 | 6(2,1,0) | 14(2,1,1) |
6 | 3(3,0,0) | 11(3,0,1) |
7 | 7(3,1,0) | 15(3,1,1) |