python、numpy、Pytorch中的索引方式
能用索引方式过多,不止下标索引。自己写程序还好,关键是看人家写的程序,有时候会晕掉,不知所云。故在此总结。
首先对Numpy的下标索引、切片索引、布尔索引和花式索引进行介绍和分析,然后研究Python和Pytorch中的索引方式是否包括以上四种。
Numpy
下标索引
>>> a = numpy.arange(6)
>>> a[2]
>>> 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]
1
>>> a[0]
array([[0, 1],
[2, 3]])
切片索引
>>> a = numpy.arange(6)
array([0, 1, 2, 3, 4, 5])
>>> a[4:]
array([4, 5])
>>> a[4:100]
array([4, 5])
>>> a[1:5:2]
array([1, 3])
>>>a[::2]
array([0, 2, 4])
>>> 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]]])
>>>a[0:100,1:100,:]
array([[[ 2, 3],
[ 4, 5]],
[[ 8, 9],
[10, 11]]])
>>>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,...]
array([[ 6, 7],
[ 8, 9],
[10, 11]])
>>> a[...,1]
array([[ 1, 3, 5],
[ 7, 9, 11]])
>>> 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]]])
>>> a>6
array([[[False, False],
[False, False],
[False, False]],
[[False, True],
>>>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
>>> a[[1],[2],[0]]
array([10])
>>>a[[1,0],[2,1],[0,1]]
array([10, 3])
稍微复杂点的切片
刚才是直接指定了三个维度,那么切片怎么做?少指定一个维度就行了
>>> a[[1],[2]]
array([[10, 11]])
>>> a[1,2,:]
array([10, 11])
>>>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]
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]])
>>> 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]])
参考
- https://blog.csdn.net/weixin_43569478/article/details/108079868
- https://zhuanlan.zhihu.com/p/123858781
|