Numpy - 如何根据条件(或匹配模式)替换元素

3 投票
3 回答
7671 浏览
提问于 2025-04-18 02:47

我有一个numpy数组,比如说:

>>> a=np.array([[0,1,2],[4,3,6],[9,5,7],[8,9,8]])
>>> a
array([[0, 1, 2],
   [4, 3, 6],
   [9, 5, 7],
   [8, 9, 8]])

我想把第二列和第三列的元素替换成它们两个中的最小值(逐行处理),但如果这两个元素中有一个小于3,就不替换。最终得到的数组应该是:

array([[0, 1, 2],# nothing changes since 1 and 2 are <3
   [4, 3, 3], #min(3,6)=3 => 6 changed to 3
   [9, 5, 5], #min(5,7)=5 => 7 changed to 5
   [8, 8, 8]]) #min(9,8)=8 => 9 changed to 8

我知道可以用clip这个方法,比如说 a[:,1:3].clip(2,6,a[:,1:3]),但是:

1) clip会对所有元素都进行处理,包括那些小于3的。

2) 我不知道怎么把clip的最小值和最大值设置成每行中这两个相关元素的最小值。

3 个回答

0

这里有一个一行代码:

a[np.where(np.sum(a,axis=1)>3),1:3]=np.min(a[np.where(np.sum(a,axis=1)>3),1:3],axis=2).reshape(1,3,1)

下面是详细解释:

>>> b = np.where(np.sum(a,axis=1)>3) # finds rows where, in a, row sums are > 3
(array([1, 2, 3]),)
>>> c = a[b,1:3] # the part of a that needs to change
array([[[3, 3],
        [5, 5],
        [8, 8]]])
>>> d = np.min(c,axis=2) # the minimum values in each row (cols 1 and 2)
array([[3, 5, 8]])
>>> e = d.reshape(1,3,1) # adjust shape for broadcast to a
array([[[3],
        [5],
        [8]]])

>>> a[np.where(np.sum(a,axis=1)>3),1:3] = e # set the values in a
>>> a

array([[0, 1, 2],
       [4, 3, 3],
       [9, 5, 5],
       [8, 8, 8]])
1

我们首先定义了一个 row_mask,用来表示小于3的条件,然后沿着一个轴使用 min 函数来找到 row_mask 中的最小值(也就是行中的最小值)。

这里的 newaxis 是为了让一维数组(最小值的数组)能够正确地扩展到二维的目标数组中。

a=np.array([[0,1,2],[4,3,6],[9,5,7],[8,9,8]])
row_mask = (a[:,0]>=3)
a[row_mask, 1:] = a[row_mask, 1:].min(axis=1)[...,np.newaxis]
a
=> 
array([[0, 1, 2],
       [4, 3, 3],
       [9, 5, 5],
       [8, 8, 8]])
3

只需要使用 >= 这个符号,先选择你感兴趣的内容:

b = a[:, 1:3]  # select the columns
matching = numpy.all(b >= 3, axis=1)  # find rows with all elements matching
b = b[matching, :]  # select rows

现在你可以用下面的方法来替换掉最小的内容,比如:

# find row minimum and convert to a column vector
b[:, :] = b.min(1, keepdims=True)

撰写回答