26

我在二维数组中设置多个元素的值,但是我的数据有时包含给定索引的多个值。

似乎总是分配“稍后”的值(参见下面的示例),但是这种行为是否得到保证,或者我是否有可能得到不一致的结果?我怎么知道我可以在矢量化分配中以我想要的方式解释“稍后”?

即在我的第一个示例中a肯定会始终包含4并且在第二个示例中它会打印values[0]吗?

非常简单的例子:

import numpy as np
indices = np.zeros(5,dtype=np.int)
a[indices] = np.arange(5)
a # array([4])

另一个例子

import numpy as np

grid = np.zeros((1000, 800))

# generate indices and values
xs = np.random.randint(0, grid.shape[0], 100)
ys = np.random.randint(0, grid.shape[1], 100)
values = np.random.rand(100)

# make sure we have a duplicate index
print values[0], values[5]
xs[0] = xs[5]
ys[0] = ys[5]

grid[xs, ys] = values

print "output value is", grid[xs[0], ys[0]]
# always prints value of values[5]
4

4 回答 4

15

在 NumPy 1.9 及更高版本中,这通常不会被很好地定义。

当前的实现使用单独的迭代器同时迭代所有(广播的)花式索引(和赋值数组),并且这些迭代器都使用 C 顺序。换句话说,目前,是的,你可以。因为您可能想更准确地了解它。如果你mapping.c在处理这些事情的 NumPy 中进行比较,你会看到它使用PyArray_ITER_NEXT,它被记录为 C 顺序。

对于未来,我会以不同的方式描绘这幅画。我认为使用较新的迭代器一起迭代所有索引+赋值数组会很好。如果这样做了,那么订单可以保持开放,以便迭代器决定最快的方式。如果你保持它对迭代器开放,很难说会发生什么,但你不能确定你的例子是否有效(可能一维情况你仍然可以,但是......)。

所以,据我所知,它目前有效,但它是无证的(据我所知),所以如果你真的认为应该确保这一点,你需要游说它并最好编写一些测试以确保它可以得到保证。因为至少我很想说:如果它让事情变得更快,就没有理由确保 C-order,但当然也许有一个很好的理由隐藏在某个地方......

这里真正的问题是:你为什么要那样做?;)

于 2013-04-15T23:07:43.137 回答
8

我知道这已得到令人满意的回答,但我想提一下,它被记录为“使用索引数组索引”下的Tentative Numpy 教程中的“最后一个值”(可能是非正式的):

但是,当索引列表包含重复时,分配会进行多次,留下最后一个值:

>>> a = arange(5)
>>> a[[0,0,2]]=[1,2,3]  
>>> a
array([2, 1, 3, 3, 4])  

这是足够合理的,但要注意是否要使用 Python 的 += 构造,因为它可能无法达到您的预期:

>>> a = arange(5) 
>>> a[[0,0,2]]+=1  
>>> a
array([1, 1, 3, 3, 4])  

即使 0 在索引列表中出现两次,第 0 个元素也只会增加一次。这是因为 Python 要求a+=1等同于a=a+1.

于 2013-05-06T17:51:02.010 回答
5

我不是直接回答你的问题,我只是想指出,即使你可以依赖这种行为是一致的,你最好不要。

考虑:

a = np.zeros(4)
x = np.arange(4)
indices = np.zeros(4,dtype=np.int)
a[indices] += x

在这一点上,假设' 之前的 sum +a.sum()是否合理?ax.sum()

assert a.sum() == x.sum()
--> AssertionError 

a
= array([ 3.,  0.,  0.,  0.])

在您的情况下,当使用重复索引分配给数组时,结果很直观:对同一索引的分配发生多次,因此只有最后一个分配“坚持”(它会覆盖以前的分配)。

但在本例中并非如此。它不再是直观的。如果是这样,就地添加将发生多次,因为添加本质上是累积的。

所以,换一种说法,你有陷入这个陷阱的风险:

  • 你开始使用重复的索引
  • 你看一切都很好,行为正是你所期望的
  • 您不再关注您的操作涉及重复索引的关键事实。毕竟,这没什么区别,不是吗?
  • 您开始在不同的上下文中使用相同的索引,例如如上所述
  • 深深的遗憾:)

所以,引用@seberg:

这里真正的问题是:你为什么要那样做?;)

于 2013-04-16T09:35:21.590 回答
4

我找到了一种使用 numpy 执行此操作的方法,这显然不是最佳的,但它比循环更快(使用 python for 循环)

与:numpy.bincount

size = 5
a = np.arange(size)
index = [0,0,2]
values = [1,2,3]
a[index] += values
a
[2 1 5 3 4]

女巫不正确,但是:

size = 5
a = np.arange(size)
index = [0,0,2]
values = [1,2,3]
result = np.bincount(index, values, size)
a += result
a
[3 1 5 3 4]

这很好!

于 2015-01-14T23:50:39.313 回答