数组的提取操作

在数据处理的工程中,经常会涉及到数组提取的操作。很多时候都需要从一个大数组中按维度,按长度等提取出一个小数组。本文将总结一些常用的提取操作。

用在方括号提取数组

对于tensor, pytorch, numpy这些拥有数组处理能力的库而言,其本身具备很强大的数据处理功能。大部分的数据提取操作都可以通过方括号操作符完成数据提取的任务。我们以pytorch为例,pytorch的数组方括号操作符中支持3类对象:

  1. 使用冒号: 描述某个维度中提取的范围。例如a[0:4, 4: -1]
  2. 使用一个整数数字指定某个维度中的特定项目。例如a[2, 8]
  3. 使用一个可迭代的整数队列指定某个维度中的一几个或者一个特定的项目。例如a[[0,1,2], [0,1,5]]

这3类对象在同一个提取操作中可以同时存在。这里,前2个提取操作都非常好理解。而3个提取操作会有一些麻烦。

冒号的应用和python常规中常规操作一样,a[:10, 4:7]表示对a数组的0维度,提取从0开始到第10项结尾的数据。在第1维度,提取从第4项开始到第7项结尾的数据。

单个整数数字表示对某个维度提取指定的某个元素。采用这样的提取方法,得到的数组会比原始数组减少一个维度。例如:

>>> a
tensor([[0., 1., 2.],
        [1., 3., 3.]])
>>> a[:,1]
tensor([1., 3.])
>>> a.shape
torch.Size([2, 3])
>>> a[:,1].shape
torch.Size([2])

上面例子可以看到a[:,1]变成了1维数组。

使用可迭代的整数队列指定项目提取时,情况就要复杂一些。它有以下几条规则:

  1. 在方括号中所有采用迭代对象做提取应用的,所有迭代对象必须拥有同样的长度,或者长度维1。
  2. 如果迭代对象的最大长度不是1, 而所有迭代对象中存在长度为1的。则长度为1的迭代对象在应用中将会被看做迭代对象长度为那个统一的最大长度。且,其数值全部为其原始整数的拷贝。例如a[[0], [1,2,3]]将被视作a[[0,0,0], [1,2,3]]。关于这一点,我们可以通过代码轻松验证:
>>> b = torch.tensor([[[0,1,2], [3,4,5]],[[6,7,8], [9,10,11]]])
>>> b[[0], [0,1], [0,1]]
tensor([0, 4])
>>> b[[0], :, [0,1]]
tensor([[0, 3],
        [1, 4]])

在这里b[[0], :, [0,1]]显然被当作了b[[0,0], : , [0,1]]来运算。然后又会被当作[b[0,:,0], b[0,:,1]]来看待。这里我们又要注意一个非常重要的点了。这个例子中前面的[0,0]的意义在于在第0维度选择两个相同的项目,后面的[0,1]则并不是每次都在第2维度选择第0个和第1两个项目的意思。后面的[0,1]的意义是在前面对应的第0个项目中在第2维度选择第0个项目,然后在前面对应的第1个项目中在第2维度选择第1个项目。它并没有在前面第0个项目中选择第0和第1,而是只选择0。这里就注意了,由于第2个迭代选择器选择的都是唯一项目,因此这就会发生维度的减少。例如前面的例子中b本来是2*2*3,总共3个维度的数据,而b[[0,0], :, [0,1]]变成了2*2两个维度的数据。这一切都因为后面的[0,1]选择了指定的一个数据(0只对应0, 1也只对应另外一个0),这一点就让b数组的最后一个维度发生了坍缩。

如果一个提取操作使用了n个迭代选择器,m个单1整数选择器,而原来数组的维度如果是t,则提取之后的数组的维度为 t - m - n + 1。

维度坍缩总结起来就是,如果遇见在某一个维度上只作整数式选择一个特定项目时,该维度就会发生坍缩。例如a[0:10, 4:5]在第1维度上4:5是选择了一个项目,但这里是作为数组来选择一个项目的,因此第1维度不会坍缩。但是如果a[0:10, 4]那就会发生坍缩了。然后,如果选择器中存在超过1个的迭代选择器,那么从第2个迭代选择器开始,每一个迭代选择器都等价于在前面的基础上只做整数式的选择。例如a[[0,1], [2,3]]。前面的[0,1]仍然是做数组式的选择,如果其后面没有[2,3],那么[0,1]几乎等价与0:2的效果。这里后面的[2,3]就不再是做数组式选择了,而是整数式地对前面的0, 做整数2的选择,对前面的1,做整数3的选择。

按步距提取

上文中提到过的提取方式,其实还有一个进一步的增强。那就是按照步距提取数据。方括号中的冒号可以再增加一个,然后第3个参数表示步距值。例如:

# array[start:end:step]
a = [1,2,3,4,5]
a[::2] = [1,3,5]
a[::-2] = [5,3,1]

#以上操作换成numpy.array也是一样的效果

步距的引入,可以进一步增强使用方括号做数据的提取操作。

发表评论

邮箱地址不会被公开。 必填项已用*标注