【问题标题】:Indexing multi-dimensional array with tuple of indices from an indexing array - NumPy / Python使用索引数组中的索引元组索引多维数组 - NumPy / Python
【发布时间】:2019-07-08 15:53:24
【问题描述】:

我有一个尺寸为 (6,m,n) 的 3-D numpy 数组 a。我还有一个 6-D 布尔 numpy 数组 b,其维度为 (20,20,20,20,20,20),可以有效地用作掩码。

我想使用第一个数组中每个位置(m,n) 的6 个值来检索第二个数组中的相应值。实际上,我会将 3D int 数组压缩为 2D 布尔数组。我认为解决方案是使用np.where,但我认为它不能处理使用值作为索引。

天真的实现是这样的:

for i in range(m):
    for j in range(n):
         new_arr[i,j]=b[tuple(a[:,i,j])]

有什么方法可以在不使用循环的情况下实现这一点?

【问题讨论】:

    标签: python numpy vectorization


    【解决方案1】:

    方法#1

    将a 重塑为2D,保持第一个轴长度相同。将每个二维扁平块转换为一个元组,然后索引到b。这种元组转换导致沿第一个轴将每个元素打包为 indexer,以选择每个离开 b 的元素。最后需要进行整形以获得2D 输出。因此,实现看起来像这样 -

    b[tuple(a.reshape(6,-1))].reshape(m,n)
    

    或者,跳过所有的重塑混乱,直接做 -

    b[tuple(a)]
    

    这会创建相同的索引器并解决问题。

    方法 #2

    或者,我们也可以计算扁平化索引,然后使用这些索引到扁平化 b 并从中提取相关的布尔值 -

    b.ravel()[np.ravel_multi_index(a,b.shape)]
    

    大型数据集的时序 -

    In [89]: np.random.seed(0)
        ...: m,n = 500,500
        ...: b = np.random.rand(20,20,20,20,20,20)>0.5
        ...: a = np.random.randint(0,20,(6,m,n))
    
    In [90]: %timeit b[tuple(a)]
    14.6 ms ± 184 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    In [91]: %timeit b.ravel()[np.ravel_multi_index(a,b.shape)]
    7.35 ms ± 136 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    

    【讨论】:

    • 一如既往的精彩
    • 谢谢!为什么tuple() 可以在 2-D 数组上工作,但不能在 3-D 数组上工作?我以为它只适用于一维。
    • @rboz22 它也适用于 3D 数组,如 b[tuple(a)] 方法所示。在元组转换之后,这些元组之间的包装是逐元素的,以形成一个索引器并从b 中选择一个元素。帖子中也提到了这一点。
    • 对不起,我在编辑之前发布了评论。对于 n 维数组,tuple() 沿哪个维度将值转换为索引? tuple(a) 似乎产生了非常大的值,而不是 0<=i<20。
    • @rboz22 tuple(a) 只会将 a 的元素收集到元组中。如果 a 中的元素在 0tuple(a) 也将被限制在 0 到 20 的范围内。
    猜你喜欢
    • 2018-01-22
    • 1970-01-01
    • 1970-01-01
    • 2015-04-19
    • 1970-01-01
    • 1970-01-01
    • 2013-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多