意外行为 numpy 数组索引
Unexpected behaviour numpy array indexing
在以某种意外的方式执行特定切片时,numpy 数组的形状发生变化
我尝试了几种对同一个数组进行切片的方法,但细微的差异会导致数组形状的不同结果
import numpy as np
z = np.zeros((1,9,10,2))
# This makes sense
print(z[...,[1,0]].shape)
# (1, 9, 10, 2)
print(z[0,...].shape)
# (9, 10, 2)
print(z[0:1,...,[1,0]].shape)
# (1, 9, 10, 2)
print(z[0][...,[1,0]].shape)
# (9, 10, 2)
# This doesn't, I would expect (9, 10, 2) in both cases
print(z[0,:,:,[1,0]].shape)
# (2, 9, 10)
print(z[0,...,[1,0]].shape)
# (2, 9, 10)
在最后两个例子中,我不明白为什么最后一个轴移动到第一个位置。
我正在使用 Python 3.6.4
和 numpy 1.15.1
你可能会发现最后两种情况的结果出乎意料的原因是因为数组的索引遵循 advanced indexing 的规则,即使你也使用切片进行索引。
有关此行为背后的详细解释,您可以查看 combining advanced and basic indexing。在最后这些情况下,您会得到意想不到的结果形状。在文档中,您会看到我们可能会获得意外结果的上述场景之一是:
- 高级索引由切片、省略号或新轴分隔。例如
x[arr1, :, arr2]
.
在你的例子中,虽然你只使用一个整数来沿第一个轴进行索引,但它是广播的,并且两个数组作为一个数组迭代。
在这种情况下,高级索引操作产生的维度首先出现在结果数组中,然后是切片维度。
这里的关键是要理解如文档中所述,这就像连接每个高级索引元素的索引结果。
所以本质上它与以下内容相同:
z = np.random.random((1,9,10,2))
a = np.concatenate([z[0,:,:,[1]], z[0,:,:,[0]]], axis=0)
与上次索引操作相同:
b = z[0,:,:,[1,0]]
np.allclose(a,b)
# True
这种行为背后的原因是什么?
要记住的一般规则是:
The resulting axes introduced by the arrays indexes are at the front, unless they are consecutive.
因此,由于这里的索引数组不是连续的,因此使用它们的结果轴将在前面,切片维度在后面。
虽然使用一维数组进行索引可能看起来很奇怪,但请注意,也可以使用任意维数的数组进行索引。假设我们在第一个和最后一个轴上使用 3d 数组索引相同的示例数组,都表示形状为 (3,4,2)。所以我们知道最终数组在某处也具有形状 (3,4,2),因为两个索引数组广播到相同的形状。现在的问题是,索引数组之间的完整切片应该放在哪里?
鉴于它应该放在中间不再那么清楚,在这些情况下有一个约定,即切片维度放在最后。
所以在这种情况下,我们的任务是重新排列数组的维度以匹配我们的预期输出。在上面的示例中,我们可以做的是交换最后两个轴并获得我们预期的结果,使用 swapaxes
获得按预期排列的尺寸。
在以某种意外的方式执行特定切片时,numpy 数组的形状发生变化
我尝试了几种对同一个数组进行切片的方法,但细微的差异会导致数组形状的不同结果
import numpy as np
z = np.zeros((1,9,10,2))
# This makes sense
print(z[...,[1,0]].shape)
# (1, 9, 10, 2)
print(z[0,...].shape)
# (9, 10, 2)
print(z[0:1,...,[1,0]].shape)
# (1, 9, 10, 2)
print(z[0][...,[1,0]].shape)
# (9, 10, 2)
# This doesn't, I would expect (9, 10, 2) in both cases
print(z[0,:,:,[1,0]].shape)
# (2, 9, 10)
print(z[0,...,[1,0]].shape)
# (2, 9, 10)
在最后两个例子中,我不明白为什么最后一个轴移动到第一个位置。
我正在使用 Python 3.6.4
和 numpy 1.15.1
你可能会发现最后两种情况的结果出乎意料的原因是因为数组的索引遵循 advanced indexing 的规则,即使你也使用切片进行索引。
有关此行为背后的详细解释,您可以查看 combining advanced and basic indexing。在最后这些情况下,您会得到意想不到的结果形状。在文档中,您会看到我们可能会获得意外结果的上述场景之一是:
- 高级索引由切片、省略号或新轴分隔。例如
x[arr1, :, arr2]
.
在你的例子中,虽然你只使用一个整数来沿第一个轴进行索引,但它是广播的,并且两个数组作为一个数组迭代。 在这种情况下,高级索引操作产生的维度首先出现在结果数组中,然后是切片维度。
这里的关键是要理解如文档中所述,这就像连接每个高级索引元素的索引结果。
所以本质上它与以下内容相同:
z = np.random.random((1,9,10,2))
a = np.concatenate([z[0,:,:,[1]], z[0,:,:,[0]]], axis=0)
与上次索引操作相同:
b = z[0,:,:,[1,0]]
np.allclose(a,b)
# True
这种行为背后的原因是什么?
要记住的一般规则是:
The resulting axes introduced by the arrays indexes are at the front, unless they are consecutive.
因此,由于这里的索引数组不是连续的,因此使用它们的结果轴将在前面,切片维度在后面。
虽然使用一维数组进行索引可能看起来很奇怪,但请注意,也可以使用任意维数的数组进行索引。假设我们在第一个和最后一个轴上使用 3d 数组索引相同的示例数组,都表示形状为 (3,4,2)。所以我们知道最终数组在某处也具有形状 (3,4,2),因为两个索引数组广播到相同的形状。现在的问题是,索引数组之间的完整切片应该放在哪里?
鉴于它应该放在中间不再那么清楚,在这些情况下有一个约定,即切片维度放在最后。
所以在这种情况下,我们的任务是重新排列数组的维度以匹配我们的预期输出。在上面的示例中,我们可以做的是交换最后两个轴并获得我们预期的结果,使用 swapaxes
获得按预期排列的尺寸。