【问题标题】:Change n-th entry of NumPy array that fulfills condition更改满足条件的 NumPy 数组的第 n 个条目
【发布时间】:2016-01-12 03:38:41
【问题描述】:

我有一个 NumPy 数组 arr 和一个(反向)掩码 mask。为简单起见,我们假设它们都是 1d。我想更改arr 中的nth 非屏蔽值。

一个例子:

import numpy as np
arr = np.arange(5)
mask = np.array((True, False, True, True, False))

很遗憾,

arr[mask][-1] = 100

我预计会返回的

array([0, 1, 2, 100, 4])

由于NumPy array views on non-consecutive items 中列出的原因而无法正常工作。

一种解决方法是将允许的值存储在一个新变量中,更改相应的值,然后将所有值复制回原始数组:

tmp = arr[mask]
tmp[-1] = 100
arr[mask] = tmp

但是,这种解决方案是丑陋且低效的,因为我必须复制许多根本不想更改的值。

有没有人有优雅的方法来处理这类问题?我会对最通用的解决方案感兴趣,这样我就可以使用tmp 进行所有经典的赋值操作。但是,如果有一种仅适用于具体描述的情况的有效方法,我仍然会对它感兴趣!

【问题讨论】:

    标签: python arrays numpy indexing


    【解决方案1】:

    一种选择是使用np.where 来获取您的mask 条件为True 的索引集。然后,您可以使用这些索引的子集对arr 进行索引并进行分配:

    # np.where returns a tuple of index arrays, one per dimension
    arr[np.where(mask)[0][-1]] = 100
    
    print(repr(arr))
    # array([  0,   1,   2, 100,   4])
    

    您可以将此方法与切片索引、布尔索引等结合使用。例如:

    arr[np.where(mask)[0][::-1]] = 100, 200, 300
    print(repr(arr))
    # array([300,   1, 200, 100,   4])
    

    【讨论】:

    • 感谢您的解决方案,@ali_m!这足以满足我的需要。不过,令我困扰的是,我必须创建一个 arr.size 数组的顺序,以便执行应该可以通过恒定内存执行的操作...
    【解决方案2】:

    您也可以使用np.nonzero 从您的掩码中获取索引?

    index = mask.nonzero()[0][-1]
    
    arr[index] = 100
    
    In [29]: arr 
    Out[29]: array([  0,   1,   2, 100,   4])
    

    或者,您可以将np.array 转换为列表并使用列表的index 方法查找最后一个值的索引:

    index = arr.tolist().index(arr[mask][-1])
    arr[index] = 100
    
    In [78]: arr
    Out[78]: array([  0,   1,   2, 100,   4])
    

    基准测试

    In [87]: %timeit arr[mask.nonzero()[0][-1]] = 100
    1000000 loops, best of 3: 897 ns per loop
    
    In [88]: %timeit arr[np.where(mask)[0][-1]] = 100
    1000000 loops, best of 3: 980 ns per loop
    
    In [91]: %timeit arr[arr.tolist().index(arr[mask][-1])] = 100
    100000 loops, best of 3: 2.44 us per loop
    

    所以nonzero 方法比np.where 快一点。

    编辑

    我认为nonzero 更快一点,因为对于来自文档的np.where

    如果只给出条件,则返回condition.nonzero()

    所以基本上你是通过np.where 调用np.nonzero,因为在这种情况下你只传递了一个条件。

    【讨论】:

    • 感谢nonzero、@Anton 的替代方案——虽然我不太明白,为什么它更快...
    • 我认为是因为nonzero 是从np.where 调用的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-14
    • 2017-06-30
    • 1970-01-01
    • 1970-01-01
    • 2019-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多