使用+ =使用来自不同数组的值通过索引列表更改numpy数组中的特定值

时间:2016-02-19 23:22:58

标签: python arrays numpy

我想通过第三个索引数组使用另一个数组中的值来更改一个数组中的值,例如:

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中的正确项目},但在这种情况下,我想进行+=操作,当索引重复时,我希望结果是累积的。

在一个简单的单行操作中,有没有办法做到这一点?

2 个答案:

答案 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>