如何使用索引和布尔索引有效地设置numpy数组的值?

时间:2017-01-17 16:11:02

标签: python numpy multidimensional-array

当要使用偏移量应用蒙版时,使用蒙版选择多维numpy数组元素的最有效方法是什么?例如:

import numpy as np

# in real application, following line would read an image
figure = np.random.uniform(size=(4, 4))  # used as a mask
canvas = np.zeros((10, 10))

# The following doesn't do anything, because a copy is modified
canvas[np.ix_(np.arange(4) + 3, range(4))][figure > 0.5] = 1.0

print np.mean(figure > 0.5)  # should be ~ 0.5
print canvas.max()  # prints 0.0

此处发布了类似的问题: Setting values of Numpy array when indexing an indexed array 但我正在使用面具,我不会问为什么它不起作用。

4 个答案:

答案 0 :(得分:2)

问题似乎是使用np.ix_返回的数组作为索引意味着你正在进行高级索引,as the documentation of NumPy states

  

高级索引始终返回数据的副本(与返回view的基本切片形成对比)。

但在这种情况下,如果真实的应用程序与您发布的代码类似(也就是说,如果您真的只需要一个偏移量),那么您可以放弃基本的切片:

import numpy as np

figure = np.random.uniform(size=(4, 4))
canvas = np.zeros((10, 10))

# Either of the following works fine
canvas[3:(3 + 4), :4][figure > 0.5] = 1.0
canvas[slice(3, 3 + 4), slice(4)][figure > 0.5] = 1.0

print np.mean(figure > 0.5)  # ~ 0.5
print canvas.max()  # Prints 1.0 now

答案 1 :(得分:1)

一种方法是使用线性指数。因此,我们将从np.ix_获取行索引和列索引,从中获取线性索引等价物。然后,使用mask选择有效的值,最后使用有效的线性索引为数据数组赋值。

因此,实施将是 -

# Get the open mesh arrays from np.ix_ corresponding to row, col indices
row, col = np.ix_(np.arange(4) + 3, range(4))

# Get the linear indices from those row and column index arrays 
linear_index = (row*canvas.shape[1] + col)[figure>0.5]

# Finally, assign values
np.put(canvas, linear_index, 1.0) # Or canvas.ravel()[linear_index] = 1.0

答案 2 :(得分:1)

我通常使用辅助函数来创建数组的适当形状的部分(视图):

arr = np.ones((10, 10)) * 10
mask = np.random.uniform(size=(4, 4))

def get_part(arr, shape, offs_x, offs_y):
    # This example just does 2D but can easily be expanded for ND-arrays
    return arr[offs_x : (offs_x + shape[0]), 
               offs_y : (offs_y + shape[1])]

get_part(arr, mask.shape, offs_x=3, offs_y=4)[mask > 0.5] = 1.0

ND实施将如下所示:

def get_part(arr, shape, offsets):
    slices = tuple(slice(offs, offs+length) for offs, length in zip(offsets, shape))
    return arr[slices]

get_part(arr, mask.shape, (3, 4))

答案 3 :(得分:0)

mask=figure>0.5

如果ix索引确实是范围,则可以用@jdehesa显示的切片替换它们:

canvas[3:3+4,:4][mask]=1

如果使用arange只是一个方便的例子,我们可以使用两阶段分配

In [277]: idx=np.ix_(np.arange(4) + 3, range(4))
In [278]: canvas = np.zeros((10, 10))
In [279]: subcanvas=np.zeros_like(figure)
In [280]: subcanvas[mask] = 1
In [281]: subcanvas
Out[281]: 
array([[ 0.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  1.],
       [ 1.,  0.,  0.,  1.],
       [ 1.,  0.,  0.,  1.]])
In [282]: canvas[idx]=subcanvas
In [283]: canvas
Out[283]: 
array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 1.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 1.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]])