更改满足条件的NumPy数组的第n个条目

时间:2016-01-12 03:38:41

标签: python arrays numpy indexing

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

一个例子:

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完成所有经典赋值操作。但是,如果有一种有效的方法只适用于具体的案例,我仍然会对它感兴趣!

2 个答案:

答案 0 :(得分:2)

一种选择是使用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])

答案 1 :(得分:0)

您还可以使用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有点快,因为来自docs的np.where

  

如果仅提供条件,请返回condition.nonzero()

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