046、数组索引进阶
本文最后更新于 67 天前,其中的信息可能已经过时,如有错误请发送邮件到wuxianglongblog@163.com

Python中的索引机制可以表示为:x[obj]。当对象obj是一个元组时,元组的括号可以省略,因此x[(exp1, exp2, ..., expN)]的索引写法与x[exp1, exp2, ..., expN]是等价的。在NumPy中,根据对象obj的不同,数组索引可以分成基础索引和高级索引两大类。

数组的基础索引

数组的基础索引满足以下条件:

  • 索引对象是整数
  • 索引对象是slice对象
  • 索引对象是一个由整数、slice对象构成的元组
  • 索引对象还可以是np.newaxis,或者Python内置的省略对象Ellipsis
import numpy as np
a = np.arange(80).reshape(8, 10)
a
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, 32, 33, 34, 35, 36, 37, 38, 39],
       [40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
       [50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
       [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
       [70, 71, 72, 73, 74, 75, 76, 77, 78, 79]])

最简单的索引,使用一个N维整数元组,索引N维数组的单个元素:

a[1, 2]
12

使用切片slice对象,索引得到一个子数组:

a[1:9:2, 3:5]
array([[13, 14],
       [33, 34],
       [53, 54],
       [73, 74]])

如果索引N维数组时,使用的元组大小小于N,NumPy会自动将后面缺失的维度补成:,例如,a[1:3]相当于a[1:3,:]

a[1:3]
array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]])
a[1:3, :]
array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]])

在索引时,还可以使用数字与slice对象进行混合使用,整数i的作用相当于slice对象i:i+1,但是维度会被消去,即每使用一个整数,得到的数组的维度就会比N小1:

a[1:2, :]
array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])
a[1, :]
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
a[1:2, :].shape
(1, 10)
a[1, :].shape
(10,)

最后的:还可以省略:

a[1]
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])

索引单个元素可以看成是一种特殊的混用。对于N维数组,如果都使用i:i+1的形式,最后会得到一个大小全1的N维数组;全部替换为整数i时,得到的数组维度要相应降低N维,得到0维数组,即普通的数字。

np.newaxis可以在数组中插入新的维度。新维度插入后,索引对应的维度位置要相应改变:

a[1:3, np.newaxis, 1:4].shape
(2, 1, 3)

Ellipsis对象“...”可以用来省略一些维度,NumPy会根据具体的索引值,将缺少的维度自动补全:

b = a.reshape(2, 4, 2, 5)
b[..., 1].shape
(2, 4, 2)
b[Ellipsis, 1].shape
(2, 4, 2)
b[0, Ellipsis, :].shape
(4, 2, 5)

可以通过基础索引修改原来数组的值。例如,修改单个值的情况:

a
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, 32, 33, 34, 35, 36, 37, 38, 39],
       [40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
       [50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
       [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
       [70, 71, 72, 73, 74, 75, 76, 77, 78, 79]])
a[0, 0] = 100
a
array([[100,   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,  32,  33,  34,  35,  36,  37,  38,  39],
       [ 40,  41,  42,  43,  44,  45,  46,  47,  48,  49],
       [ 50,  51,  52,  53,  54,  55,  56,  57,  58,  59],
       [ 60,  61,  62,  63,  64,  65,  66,  67,  68,  69],
       [ 70,  71,  72,  73,  74,  75,  76,  77,  78,  79]])

对于子数组的情况,可以使用x[obj]=value的形式进行赋值,只要数组x[obj]的形状和value的形状能够在数组广播机制下匹配即可。例如,将第二行修改为同一个值:

a[1] = 1
a[1]
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])

用一维数组给二维数组赋值,将第二三行变成同一个一维数组:

a[1:3] = np.arange(10)
a[1:3]
array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])

用形状为(1,2)的数组给第二三行赋值:

a[1:3] = np.array([[1], [2]])
a[1:3]
array([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]])

基础索引返回的是原来数组的一个引用,与原来的数组共享同一块内存:

a
array([[100,   1,   2,   3,   4,   5,   6,   7,   8,   9],
       [  1,   1,   1,   1,   1,   1,   1,   1,   1,   1],
       [  2,   2,   2,   2,   2,   2,   2,   2,   2,   2],
       [ 30,  31,  32,  33,  34,  35,  36,  37,  38,  39],
       [ 40,  41,  42,  43,  44,  45,  46,  47,  48,  49],
       [ 50,  51,  52,  53,  54,  55,  56,  57,  58,  59],
       [ 60,  61,  62,  63,  64,  65,  66,  67,  68,  69],
       [ 70,  71,  72,  73,  74,  75,  76,  77,  78,  79]])

修改基础索引赋值的变量,会导致原来的数组也发生变化:

b = a[0]
b[0] = 0
a[0, 0]
0

数组的高级索引

数组支持高级索引操作,高级索引又叫花式索引(Fancy Indexing),与基础索引不同,高级索引返回的结果始终是原来数组的一个复制。

数组的高级索引需要满足:

  • 索引对象是非元组的序列。
  • 索引对象是整型或者布尔型的数组。
  • 索引对象是包含至少一个前两种类型的元素的元组。

可以使用N个整型数组或者列表组成的索引值,来索引N维数组中的任意元素。例如:

a = np.array([[1, 2], [3, 4], [5, 6]])
a
array([[1, 2],
       [3, 4],
       [5, 6]])

在维度0使用列表索引位置[0,1,2],维度1使用列表索引位置[0,1,0],最终得到数组位置在(0,0)(1,1)(2,0)的三个元素:

a[[0, 1, 2], [0, 1, 0]]
array([1, 4, 5])

再如,有这样一个4×3的数组:

b = np.arange(12).reshape(4, 3)
b
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])

使用两个数组来索引这个数组的第一、四行的第一、三列:

rows = np.array([[0, 0], [3, 3]])
cols = np.array([[0, 2], [0, 2]])
b[rows, cols]
array([[ 0,  2],
       [ 9, 11]])

每个维度传入的索引数组的形状为(2,2),因此最后得到的数组形状为(2,2),第一行对应位置(0,0)(0,2),第二行对应位置(3,0)(3,2)

高级索引也支持广播机制,将刚才的索引进行简化:

rows = np.array([0, 3])
cols = np.array([0, 2])

它们的形状都是(2,),如果对其直接索引,会得到位置(0,0)(3,2)的两个元素:

b[rows, cols]
array([ 0, 11])

这并不是预期想要的结果。为此,可以将rows的形状修改为(2,1),再进行索引:

rows.shape = 2, 1
b[rows, cols]
array([[ 0,  2],
       [ 9, 11]])

rows的形状为(2,1),cols的形状为(2,),两个维度的索引数组形状不对应,NumPy先通过广播机制,将它们广播为匹配后的形状(2,2),最终得到与刚才一致的结果。

高级索引与基础索引可以混用,此时,情况会变得十分复杂。例如,基础索引下有:

b[1:2, 1:3]
array([[4, 5]])

1:3改成数组[1, 2],得到的结果相同,但是是高级索引:

b[1:2, [1, 2]]
array([[4, 5]])

NumPy有一套相应的规则来确定索引得到的结果。当索引中的高级索引不相邻时,高级索引对应的维度将被放在索引结果的最前面,之后是基础索引的维度。例如,数组a的形状为(10,20,30,40,50),考虑形状均为(2,3,4)的两个索引数组ind1ind2,索引a[ind1, ..., ind2]的形状为(2,3,4,20,30,40),因为ind1ind2不相邻:

a = np.ones((10, 20, 30, 40, 50))
ind = np.ones((2, 3, 4), dtype=int)
a[ind, ..., ind].shape
(2, 3, 4, 20, 30, 40)

而当所有的高级索引相邻时,它会替换掉对应的维度。例如,索引a[..., ind1, ind2, :]会得到一个(10,20,2,3,4,50)的数组,高级索引的维度(2,3,4)替换了对应位置的(30,40)

a[..., ind, ind, :].shape
(10, 20, 2, 3, 4, 50)

在高级索引与基础索引混用时,使用单个数字的维度会被当作高级索引,因此,索引a[ind1,...,1]的形状为(2,3,4,20,30,40),因为1被当作高级索引,广播成了2×3×4的大小,导致高级索引的位置不相邻:

a[ind, ..., 1].shape
(2, 3, 4, 20, 30, 40)

还可以用一个与维度大小相等的布尔数组进行索引,并把其中为True的位置拿出来。利用逻辑运算时可以得到:

a = np.array([1, 2, 3, 4, 5, 6])
a % 3 == 0
array([False, False,  True, False, False,  True])
a[a % 3 == 0]
array([3, 6])
a[a < 4]
array([1, 2, 3])
谨此笔记,记录过往。凭君阅览,如能收益,莫大奢望。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇