类似于'numpy.take'的Numpy赋值

10

能否像take功能一样在numpy数组上进行赋值操作?

比如,如果我有一个数组a,一个索引列表inds和一个需要操作的轴,我可以使用take来实现:

import numpy as np
a = np.arange(12).reshape((3, -1))
inds = np.array([1, 2])
print(np.take(a, inds, axis=1))

[[ 1  2]
 [ 5  6]
 [ 9 10]]

这在运行时需要改变索引/轴的情况下非常有用。但是,numpy不允许你这样做:
np.take(a, inds, axis=1) = 0
print(a)

看起来通过numpy.put有一些有限的(1-D)支持,但我想知道是否有更简洁的方法来做到这一点?


a[:,inds] = 0 怎么样? - Divakar
4
我的意思是我希望能够以编程方式执行a[inds, :] = 0a[:, inds] = 0或(在三维情况下)a[:, :, inds] = 0等操作,而不需要编写大量的if语句。 - arghdos
3个回答

7
In [222]: a = np.arange(12).reshape((3, -1))
     ...: inds = np.array([1, 2])
     ...: 
In [223]: np.take(a, inds, axis=1)
Out[223]: 
array([[ 1,  2],
       [ 5,  6],
       [ 9, 10]])
In [225]: a[:,inds]
Out[225]: 
array([[ 1,  2],
       [ 5,  6],
       [ 9, 10]])

构建索引元组。
In [226]: idx=[slice(None)]*a.ndim
In [227]: axis=1
In [228]: idx[axis]=inds
In [229]: a[tuple(idx)]
Out[229]: 
array([[ 1,  2],
       [ 5,  6],
       [ 9, 10]])
In [230]: a[tuple(idx)] = 0
In [231]: a
Out[231]: 
array([[ 0,  0,  0,  3],
       [ 4,  0,  0,  7],
       [ 8,  0,  0, 11]])

或者对于a[inds,:]
In [232]: idx=[slice(None)]*a.ndim
In [233]: idx[0]=inds
In [234]: a[tuple(idx)]
Out[234]: 
array([[ 4,  0,  0,  7],
       [ 8,  0,  0, 11]])
In [235]: a[tuple(idx)]=1
In [236]: a
Out[236]: 
array([[0, 0, 0, 3],
       [1, 1, 1, 1],
       [1, 1, 1, 1]])

PP的建议:

def put_at(inds, axis=-1, slc=(slice(None),)): 
    return (axis<0)*(Ellipsis,) + axis*slc + (inds,) + (-1-axis)*slc 

用法示例:a[put_at(ind_list,axis=axis)]

我在numpy函数中看到了这两种样式。这个看起来像是在extend_dims中使用的,我的则是在apply_along/over_axis中使用的。

之前的想法

在最近一个take问题中,我/我们发现它等同于某些展平索引的arr.flat[ind]。我需要查一下。

有一个np.put与对flat进行赋值相当:

Signature: np.put(a, ind, v, mode='raise')
Docstring:
Replaces specified elements of an array with given values.

The indexing works on the flattened target array. `put` is roughly
equivalent to:

    a.flat[ind] = v

它的文档还提到了placeputmaskcopyto

numpy多维索引和函数'take'

我评论说,没有轴的take等价于:

lut.flat[np.ravel_multi_index(arr.T, lut.shape)].T

使用 ravel

In [257]: a = np.arange(12).reshape((3, -1))
In [258]: IJ=np.ix_(np.arange(a.shape[0]), inds)
In [259]: np.ravel_multi_index(IJ, a.shape)
Out[259]: 
array([[ 1,  2],
       [ 5,  6],
       [ 9, 10]], dtype=int32)
In [260]: np.take(a,np.ravel_multi_index(IJ, a.shape))
Out[260]: 
array([[ 1,  2],
       [ 5,  6],
       [ 9, 10]])
In [261]: a.flat[np.ravel_multi_index(IJ, a.shape)] = 100
In [262]: a
Out[262]: 
array([[  0, 100, 100,   3],
       [  4, 100, 100,   7],
       [  8, 100, 100,  11]])

并且使用 put:

In [264]: np.put(a, np.ravel_multi_index(IJ, a.shape), np.arange(1,7))
In [265]: a
Out[265]: 
array([[ 0,  1,  2,  3],
       [ 4,  3,  4,  7],
       [ 8,  5,  6, 11]])

在这种情况下,使用ravel是不必要的,但在其他情况下可能会有用。

你似乎忽略了使用“axis”参数的用法。 - user2357112
谢谢!如果put函数在轴参数方面与take函数具有类似的功能,那将是很好的,但对于索引元组的构建,这对我来说已足够。 - arghdos
1
这里有一个方便的索引构建函数,它不需要知道数组的 ndim: def put_at(inds, axis=-1, slc=(slice(None),)): return (axis<0)*(Ellipsis,) + axis*slc + (inds,) + (-1-axis)*slc 可以像这样使用:a[put_at(ind_list,axis=axis)]。@hpaulj 如果它通过了审核,请随意将其添加到您的帖子中。 - Paul Panzer

0

-1
你可以这样使用索引:
a[:,[1,2]]=0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接