【问题标题】:Numpy 3D array transposed when indexed in single step vs two stepsNumpy 3D 数组在单步索引与两步索引时转置
【发布时间】:2016-05-03 03:34:37
【问题描述】:
import numpy as np
x = np.random.randn(2, 3, 4)
mask = np.array([1, 0, 1, 0], dtype=np.bool)
y = x[0, :, mask]
z = x[0, :, :][:, mask]
print(y)
print(z)
print(y.T)

为什么分两步做上面的操作会导致一步做的转置?

【问题讨论】:

    标签: python numpy indexing


    【解决方案1】:

    以下是列表索引的相同行为:

    In [87]: x=np.arange(2*3*4).reshape(2,3,4)
    In [88]: x[0,:,[0,2]]
    Out[88]: 
    array([[ 0,  4,  8],
           [ 2,  6, 10]])
    In [89]: x[0,:,:][:,[0,2]]
    Out[89]: 
    array([[ 0,  2],
           [ 4,  6],
           [ 8, 10]])
    

    在第二种情况下,x[0,:,:] 返回一个 (3,4) 数组,下一个索引选择 2 列。

    在第一种情况下,它首先选择第一个和最后一个维度,并附加切片(中间维度)。 0[0,2] 生成 2 维度,并附加中间的 3,给出 (2,3) 形状。

    这是一个混合基本索引和高级索引的情况。

    http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#combining-advanced-and-basic-indexing

    在第一种情况下,高级索引操作产生的维度在结果数组中首先出现,然后是子空间维度。

    这不是一个容易理解或解释的案例。基本上对于最终维度应该是什么存在一些歧义。它试图用一个例子来说明x[:,ind_1,:,ind_2],其中ind_1ind_2 是3d(或一起广播到那个)。

    早期的解释是:

    How does numpy order array slice indices?

    Combining slicing and broadcasted indexing for multi-dimensional numpy arrays

    ============================

    解决此问题的一种方法是将切片替换为数组 - 列向量

    In [221]: x[0,np.array([0,1,2])[:,None],[0,2]]
    Out[221]: 
    array([[ 0,  2],
           [ 4,  6],
           [ 8, 10]])
    In [222]: np.ix_([0],[0,1,2],[0,2])
    Out[222]: 
    (array([[[0]]]), array([[[0],
             [1],
             [2]]]), array([[[0, 2]]]))
    In [223]: x[np.ix_([0],[0,1,2],[0,2])]
    Out[223]: 
    array([[[ 0,  2],
            [ 4,  6],
            [ 8, 10]]])
    

    虽然最后一种情况是 3d, (1,3,2)。 ix_ 不喜欢标量 0。使用 ix_ 的另一种方式:

    In [224]: i,j=np.ix_([0,1,2],[0,2])
    In [225]: x[0,i,j]
    Out[225]: 
    array([[ 0,  2],
           [ 4,  6],
           [ 8, 10]])
    

    这是一种获取相同数字的方法,但在 (2,1,3) 数组中:

    In [232]: i,j=np.ix_([0,2],[0])
    In [233]: x[j,:,i]
    Out[233]: 
    array([[[ 0,  4,  8]],
    
           [[ 2,  6, 10]]])
    

    【讨论】:

    • 我还是不明白,但我很欣赏这个答案,而且它很难解释,所以我会接受它。更难理解的是,为什么这是所需的行为,与代码内部的工作方式无关。您链接到的文档不是很完整的恕我直言。我的教训是不要将基本索引和高级索引结合起来。
    • 我添加了用索引替换切片的示例。
    • 需要明确的是,这不是理想的行为,尽管它有很好的(历史)原因。我们(numpy 开发人员)初步计划在未来的版本中弃用它,并提供更易于理解的功能,如您所期望的那样工作。有关详细信息,请参阅github.com/numpy/numpy/pull/6256
    • 我一直在努力用标量第一索引证明这种情况下的行为是正确的。它不像更复杂的混合索引示例那样模棱两可。但是改变像索引这样基本的东西充满了向后兼容性问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-23
    • 2019-05-26
    • 1970-01-01
    • 1970-01-01
    • 2019-02-06
    • 1970-01-01
    相关资源
    最近更新 更多