我在2D数组中设置多个元素的值,但是我的数据有时包含给定索引的多个值.
似乎总是分配"后来的"值(参见下面的示例),但这种行为是否得到保证,或者我有可能得到不一致的结果?我怎么知道我可以在矢量化作业中以"我想要的方式"解释"以后"?
即在我的第一个例子a肯定会包含4,在第二个例子中它会打印values[0]吗?
很简单的例子:
import numpy as np
indices = np.zeros(5,dtype=np.int)
a[indices] = np.arange(5)
a # array([4])
Run Code Online (Sandbox Code Playgroud)
另一个例子
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]
Run Code Online (Sandbox Code Playgroud)
seb*_*erg 14
在NumPy 1.9及更高版本中,这通常不会很好地定义.
当前实现使用单独的迭代器同时迭代所有(广播的)花哨索引(和赋值数组),并且这些迭代器都使用C顺序.换句话说,目前,是的,你可以.因为您可能想要更准确地了解它.如果你mapping.c在处理这些事情的NumPy中进行比较,你会看到它使用PyArray_ITER_NEXT,它被记录为C顺序.
对于未来,我会以不同的方式描绘图片.我认为使用较新的迭代器将所有索引+赋值数组一起迭代会很好.如果这样做,那么订单可以保持打开,以便迭代器决定最快的方式.如果你对迭代器保持开放状态,很难说会发生什么,但是你不能确定你的例子是否有效(可能是1-d情况你仍然可以,但......).
所以,据我所知它目前有效,但它没有记录(据我所知),所以如果你真的认为应该确保这一点,你需要游说它并最好写一些测试以确保它可以保证.因为至少我很想说:如果它让事情变得更快,就没有理由确保C阶,但当然也许有一个很好的理由隐藏在某个地方......
这里真正的问题是:你为什么要这样呢?;)
我知道这已经得到了令人满意的答案,但我想提一下,它被记录为在指数数组索引下的暂定Numpy教程中的" 最后一个值 "(可能是非正式的):
但是,当索引列表包含重复时,分配会多次完成,留下最后一个值:
Run Code Online (Sandbox Code Playgroud)>>> a = arange(5) >>> a[[0,0,2]]=[1,2,3] >>> a array([2, 1, 3, 3, 4])这是合理的,但请注意是否要使用Python的+ =构造,因为它可能无法达到您的预期:
Run Code Online (Sandbox Code Playgroud)>>> a = arange(5) >>> a[[0,0,2]]+=1 >>> a array([1, 1, 3, 3, 4])即使0在索引列表中出现两次,第0个元素也只增加一次.这是因为Python需要
a+=1等同于a=a+1.
我找到了一种使用 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]
Run Code Online (Sandbox Code Playgroud)
女巫的说法不正确,但是:
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]
Run Code Online (Sandbox Code Playgroud)
这很好!
我不是直接回答你的问题,我只是想表明即使你可以依赖这种行为保持一致,你最好也不要.
考虑:
a = np.zeros(4)
x = np.arange(4)
indices = np.zeros(4,dtype=np.int)
a[indices] += x
Run Code Online (Sandbox Code Playgroud)
在这一点上,假设这a.sum()是a以前的总和+ x.sum()是否合理?
assert a.sum() == x.sum()
--> AssertionError
a
= array([ 3., 0., 0., 0.])
Run Code Online (Sandbox Code Playgroud)
在您的情况下,当使用重复索引分配给数组时,结果是直观的:对同一索引的赋值会多次发生,因此只有最后一个赋值"粘住"(它会覆盖以前的赋值).
但在这个例子中并非如此.它不再直观.如果是的话,就地添加会多次发生,因为添加本质上是累积的.
所以换句话说,你冒着陷入这个陷阱的危险:
所以,引用@seberg:
这里真正的问题是:你为什么要这样呢?;)