python 处理NumPy赋值中的重复索引

disho6za  于 2023-01-04  发布在  Python
关注(0)|答案(5)|浏览(178)

我正在设置一个二维数组中多个元素的值,但是我的数据有时包含给定索引的多个值。
看起来"later"值总是被赋值的(见下面的例子),但是这种行为是否得到保证,或者是否有可能得到不一致的结果?我如何知道我可以在向量化赋值中以我希望的方式解释"later"?
也就是说,在我的第一个示例中,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]
3npbholx

3npbholx1#

在NumPy 1.9和更高版本中,这通常不会得到很好的定义。
当前实现将遍历所有(广播的)花式索引(和赋值数组)同时使用单独的迭代器,这些迭代器都使用C序,换句话说,目前,是的,你可以,因为你可能想知道它更准确,如果你在处理这些事情的NumPy中比较mapping.c,你会看到它使用PyArray_ITER_NEXT,也就是documented是C阶的。
对于未来,我会用不同的方式来描述。我认为使用较新的迭代器来迭代所有索引+赋值数组会很好。如果这样做了,那么顺序可以保持开放,以便迭代器决定最快的方式。如果你保持它对迭代器开放,很难说会发生什么。但是你不能确定你的例子是否有效(可能是1-D的情况,你仍然可以,但是...)。
所以,据我所知,它目前的工作,但它是没有文件(据我所知),所以如果你真的认为这应该得到保证,你需要游说它,最好写一些测试,以确保它可以得到保证.因为至少我忍不住要说:如果它使事情更快,那么就没有理由确保C阶,但当然可能在某个地方隐藏着一个很好的理由...
真实的的问题是:你到底为什么要那个?)

e7arh2l6

e7arh2l62#

我知道这个问题已经得到了令人满意的回答,但我想提一下,它在Tentative Numpy Tutorial中的“last value”(可能是非正式的)是在使用索引数组进行索引下记录的:
但是,当索引列表包含重复时,赋值将执行多次,并留下最后一个值:

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

k75qkfdt

k75qkfdt3#

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

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

此时,假设a.sum()a的前一个和+x.sum()是否合理?

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

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

在您的示例中,当使用重复索引为数组赋值时,结果是直观的:对同一索引的赋值会发生多次,因此只有最后一次赋值会"保留"(它会覆盖以前的赋值)。
但是这个例子中的情况不是这样的,它不再是直观的,如果是直观的,就地加法就会发生多次,因为加法本质上是累积的。
所以,换句话说,你正冒着陷入这个陷阱的风险:

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

所以,引用@seberg的话:
真正的问题是:你到底为什么要那个?)

acruukt9

acruukt94#

我找到了一种方法,用with numpy来做这个操作,这显然不是最佳的,但它比循环(用python for循环)更快
与:麻木。双计数

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]

味道不错!

xfb7svmp

xfb7svmp5#

时间在变,应该给出最新的答案。

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

相关问题