我想通过第三个索引数组使用另一个数组中的值来更改一个数组中的值,例如:
import numpy as np
F = np.zeros((4,3)) # array I wish to change
f = np.array([[3,4,0],[0,0,1]]) # values I wish to add to F
i = np.array([2, 2]) # indices in F I wish to affect
让我们使用+=
F
上的i
执行f
操作
for id in xrange(len(i)):
F[i[id]] += f[id]
# F[2] is now equal to np.array([ 3., 4., 1.]) because
# both values in f have been correctly added to F[2]
我假设我可以在一行中执行相同的操作:
F[i] += f
# F[2] is now equal to np.array([ 0., 0., 1.])
# i expected np.array([ 3., 4., 1.])
但这失败了。我期望的结果是np.array([ 3., 4., 1.])
如果i
是不同索引的列表(例如array([0, 2])
),那么F[0]
和F[2]
就会被设置为f
中的正确项目},但在这种情况下,我想进行+=
操作,当索引重复时,我希望结果是累积的。
在一个简单的单行操作中,有没有办法做到这一点?
答案 0 :(得分:2)
您正在寻找的操作是numpy.add.at
。至关重要的是,这会在指定的标记处添加无缓冲,而F[i] += f
使用内部缓冲区。
然而,ufunc.at
因非优化而臭名昭着。如果您的阵列足够大且呈矩形,则可能需要执行一个小循环并使用bincount
。示例时间:
In [43]: n = 10**5
...: m = 10**6
...: I = np.random.randint(n, size=m)
...: f = np.random.rand(m, 3)
In [44]: %%time
...: F = np.zeros((n, 3))
...: np.add.at(F, I, f)
Wall time: 624 ms
In [45]: %%time
...: F2 = np.zeros((n, 3))
...: for dim in range(3):
...: F2[:,dim] += np.bincount(I, f[:,dim], n)t
Wall time: 94 ms
In [46]: np.allclose(F, F2)
Out[46]: True
答案 1 :(得分:1)
在这种特殊情况下(i
只包含一个唯一编号),您可以通过以下方式避免for循环:
F[i] += sum(f)
array([[ 0., 0., 0.],
[ 0., 0., 0.],
[ 3., 4., 1.],
[ 0., 0., 0.]])
如果i
包含多个数字,则以下内容可以正常工作:
F2 = np.zeros((4,3))
i2 = np.array([2, 3])
F2[i2] += f
然后F2
是:
array([[ 0., 0., 0.],
[ 0., 0., 0.],
[ 3., 4., 0.],
[ 0., 0., 1.]])
您可以使用i
检查set(i)
中不同数字的数量,然后根据F
的长度将第一个或第二个选项应用于set(i)
。< / p>