python、numpy、Pytorch中的索引方式

能用索引方式过多,不止下标索引。自己写程序还好,关键是看人家写的程序,有时候会晕掉,不知所云。故在此总结。

首先对Numpy的下标索引、切片索引、布尔索引和花式索引进行介绍和分析,然后研究Python和Pytorch中的索引方式是否包括以上四种。

Numpy

下标索引

>>> a = numpy.arange(6)
# 正向从0开始
>>> a[2]

# 反向从-1开始
>>> a[-2]
4

# 多维数组
>>> a = numpy.arange(8).reshape([2,2,2])
>>> a
array([[[0, 1],
        [2, 3]],
       [[4, 5],
        [6, 7]]])
        
# a[0][-2][1]和a[0,-2,1]输出相同。只是a[0][-2][1]先取a[0],再取[-2],最后[-1],会慢一些
>>> a[0,-2,1]
1

# 输入第一个维度值
>>> a[0]
array([[0, 1],
       [2, 3]])

切片索引

>>> a = numpy.arange(6)
array([0, 1, 2, 3, 4, 5])

# start:end, end可以省略,也可以写一个大于实际长度的值
>>> a[4:]
array([4, 5])
>>> a[4:100]
array([4, 5])

# start:end:step
# 注意切片中不包括end
>>> a[1:5:2]
array([1, 3])
# 不写start和end就是分别默认首和尾
>>>a[::2]
array([0, 2, 4])

# 反向排列::-1,
# 并不能指定部分序列反向如a[1:5:-1],此时返回空
>>> a[::-1]
array([5, 4, 3, 2, 1, 0])
>>> a[1:5:-1]
array([], dtype=int64)


# 多维数组, 
>>> a = numpy.arange(12).reshape([2,3,2])
>>> a
array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],
       [[ 6,  7],
        [ 8,  9],
        [10, 11]]])

# 返回部分值,
#(1)end仍然可以大于实际值,
#(2):表示返回该维度全部,
#(3)以start:end切片返回的维度和原数组相同
>>>a[0:100,1:100,:]
array([[[ 2,  3],
        [ 4,  5]],
       [[ 8,  9],
        [10, 11]]])

# 针对某一维度切片
# 若直接指定某一维度的值,返回数组的维度-1
>>>a[1,1,:]
array([8, 9])

>>>a[1,1:100,:]
array([[ 8,  9],
       [10, 11]])

至此,相信大多数人都能看懂,因为在每个维度上明确指出了取多少。但有一些操作,会让你眼花缭乱。 比如省略号和冒号

>>> a = numpy.arange(12).reshape([2,3,2])
>>> a
array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],
       [[ 6,  7],
        [ 8,  9],
        [10, 11]]])
 
 # 省略号表示,其余所有维度的所有值都要。还算有用。
 # a[1,...]等同于a[1,:,:],好处是无需把每个维度都写一遍
 >>> a[1,...]
array([[ 6,  7],
       [ 8,  9],
       [10, 11]])
 # a[...,1]等同于a[:,:,1]
 >>> a[...,1]
array([[ 1,  3,  5],
       [ 7,  9, 11]])
 
 # 对于三维数组,一个冒号也可以和省略号相同,
 # 表示其余所有维度的所有值都要。
 # (1)但这是一个相当不好的设计,至少我这么认为。
 # 因为读者可能不清楚这个数组到底几维,
 # 你这么写极有可能会让读者误以为是二维数组。
 >>> a[1,:]
array([[ 6,  7],
       [ 8,  9],
       [10, 11]])

布尔索引

这是个很实用的技巧

>>> a = numpy.arange(12).reshape([2,3,2])
>>> a
array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],
       [[ 6,  7],
        [ 8,  9],
        [10, 11]]])
        
 # 在Numpy中,对array做逻辑运算,返回的是同siaze的Bool型array
>>> a>6
array([[[False, False],
        [False, False],
        [False, False]],
       [[False,  True],
       
 # 可根据这个结果进行索引
 # (1)返回的总是一维数组
 >>>a[a>6] 
 array([ 7,  8,  9, 10, 11])

花式索引(Fancy indexing)

通过数组作为坐标去索引。这个方式看了一会才明白。花式索引主要是针对不连续的索引下标,是有实际用处的。

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

先从简单的情况看起

此时,a为三维数组,你想找某个位置的值,得需要三个值作为坐标吧。即a[x,y,z],比如说a[1][2][0]。而花式索引就是把每个坐标以数组的方式传入。

>>> a[1][2][0]
10

# 花式索引, 此时变成x=[1], y=[2], z=[0]
>>> a[[1],[2],[0]]
array([10])

# 此时变成x=[1,0], y=[2,1], z=[0,1]
# 即a[1,2,0]和a[0,1,1]
>>>a[[1,0],[2,1],[0,1]]
array([10,  3])

稍微复杂点的切片

刚才是直接指定了三个维度,那么切片怎么做?少指定一个维度就行了

# 指定了两个维度,相当于找a[1,2,:](暂时忽略返回维度)
>>> a[[1],[2]]
array([[10, 11]])
>>> a[1,2,:]
array([10, 11])

# 相当于找a[1,2,:]和a[1,0,:]
>>>a[[1,1],[2,0]]
array([[10, 11],
       [ 6,  7]])

此时另一个问题也可以解决了,为什么a[[1],[2]]会比a[1,2,:]多一个维度。需要首先考虑a[[1,1],[2,0]]:

  • 如果使用a[1,2,:]和a[1,0,:],需要分别查找,得到两个结果。
  • 而使用a[[1],[2]],只需一次即可得到结果,结果就是将a[1,2,:]和a[1,0,:]整合起来。
  • 为了可能存在的“整合操作”,花式索引就要多出一个维度,即便结果不需要“整合”。

考虑广播机制

比如y维度只给了一个2,Python中的广播之后,变成了寻找a[0,2,:]和a[1,2,:]

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

Python

让我们看看List有什么方式

下标索引和切片索引

只能通过a[1][0]的方式。使用的时候将其考虑为一层一层的list即可。

>>> a = [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]]]
>>> a[1][0]
[7, 8]
>>> a[1][0][1]
8

# 不可以a[1,0]
>>> a[1,0]
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: list indices must be integers or slices, not tuple

>>>a[0][0:2]
[[1, 2], [3, 4]]

# 但倒序的操作还在,只针对最外层
>>>a[::-1]
[[5, 6], [3, 4], [1, 2]]

布尔索引

Numpy中的方式失败

>>> a = [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]]]
>>> a>0
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: '>' not supported between instances of 'list' and 'int'

但也不是没有,尽管没什么用。True是1,False是0

>>> a[0][False]
[1, 2]
>>> a[0][True]
[3, 4]

花式索引

没有

>>> a[[1],[2],[0]]
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: list indices must be integers or slices, not tuple

Pytorch

终于到了令人期待的Pytorch

下标索引和切片索引

>>> a = torch.randint(low=0,high=10,size=[2,3,2])
tensor([[[1, 4],
         [5, 8],
         [0, 1]],
        [[0, 8],
         [4, 7],
         [1, 8]]])

>>> a[0,:,1]
tensor([4, 8, 1])

# 省略号省略号表示其余所有维度的所有值都要(此功能的冒号也支持)
>>> a[0,...]
tensor([[1, 4],
        [5, 8],
        [0, 1]])

# ::-1倒序不支持
>>> a[::-1]
Traceback (most recent call last):
  File "<input>", line 1, in <module>
ValueError: step must be greater than zero

布尔索引

# 支持
>>> a>5
tensor([[[False, False],
         [False,  True],
         [False, False]],
        [[False,  True],
         [False,  True],
         [False,  True]]])
>>> a[a>5]
tensor([8, 8, 7, 8])

花式索引

# 支持
>>> a[[1,0],[2,0]]
tensor([[1, 8],
        [1, 4]])
>>> a[[1,0],[2]]
tensor([[1, 8],
        [0, 1]])

参考

  1. https://blog.csdn.net/weixin_43569478/article/details/108079868
  2. https://zhuanlan.zhihu.com/p/123858781
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值