3

我将从问题的陈述开始。之后,我将演示一个简短的编码序列,逐步构建解决方案,直到解决问题。显然,这里的目标是计算 b。我在问如何最有效地做到这一点,理想情况下使用元素 numpy 向量表达式,根本没有迭代或循环:

b = sum(v)-a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.6/site-packages/numpy/core/fromnumeric.py", line 1251, in sum
return _wrapit(a, 'sum', axis, dtype, out)
File "/usr/lib64/python2.6/site-packages/numpy/core/fromnumeric.py", line 37, in _wrapit
result = getattr(asarray(obj),method)(*args, **kwds)
File "/usr/lib64/python2.6/site-packages/numpy/core/numeric.py", line 230, in asarray
return array(a, dtype, copy=False, order=order)
ValueError: setting an array element with a sequence.

这是我尝试执行的导致该错误的代码的最佳版本。为了清楚起见,我添加了一些打印语句:

a = array([0,1,0,1,1])
b = +a
print b
array([0, 1, 0, 1, 1])

b = array([sum(a[0:2]), sum(a[0:3]), sum(a[1:4]), sum(a[2:5]), sum(a[3:5])])
print b
array([1, 1, 2, 2, 2])

b = array([sum(a[0:2])-a[0], sum(a[0:3])-a[1], sum(a[1:4])-a[2], sum(a[2:5])-a[3], sum(a[3:5])-a[4]])
print b
array([1, 0, 2, 1, 1])

v = [a[0:2], a[0:3], a[1:4], a[2:5], a[3:5]]
print v
[array([0, 1]), array([0, 1, 0]), array([1, 0, 1]), array([0, 1, 1]), array([1, 1])]

注意 v 是一个视图列表。这些视图是指支持数组 a。

print a
array([0, 1, 0, 1, 1])

a[0]=9
print v
[array([9, 1]), array([9, 1, 0]), array([1, 0, 1]), array([0, 1, 1]), array([1, 1])]

a[0]=0
print v
[array([0, 1]), array([0, 1, 0]), array([1, 0, 1]), array([0, 1, 1]), array([1, 1])]

到目前为止一切都很好:变量 v 是一个真实的视图,这意味着当 a 更新时 v 也会更新。

b = array([sum(v[0])-a[0], sum(v[1])-a[1], sum(v[2])-a[2], sum(v[3])-a[3], sum(v[4])-a[4]])
print b
array([1, 0, 2, 1, 1])

太好了,到目前为止还不错。现在让我们进一步简化代码行……请注意变量 b、v 和 a 都具有相同数量的元素。

b = sum(v)-a
Traceback (most recent call last)...(error messages)...

哦,哦,糟糕的代码!现在,我也尝试了其他的方式来表达b,但它们同样是错误的,我不需要在这里展示更多糟糕的代码。问题是如何正确且最有效地表达赋值表达式。如果在这个特定的应用程序中可能的话,对计算特别有帮助,那就是在设置视图之后完全避免循环表达式并避免列表推导。

在这个应用程序中可以使用慢循环设置视图。观点不会经常改变。后备数组 a 会经常变化,而且会非常大。

感谢您的阅读和您的任何最佳建议!

4

4 回答 4

2

对于v您发布的特定视图,计算可以表示为与内核的卷积[1, 1, 1]

In [78]: import numpy as np    

In [80]: a = np.array([0,1,0,1,1])

In [81]: b = np.convolve(a, [1,1,1], 'same') - a

In [82]: b
Out[82]: array([1, 0, 2, 1, 1])

你没有说你是如何v随时间变化的,但也许如果它们相似,你可以继续将计算表示为内核变化的卷积。

于 2012-08-14T16:22:33.163 回答
0

关于什么:

b = [sum(i) for i in v] - a

(之所以有效,是因为v与 的项目数量相同a,并且它们都是一维的)?

于 2012-08-17T01:48:36.030 回答
0

我认为unutbu的答案是正确的。但只是为了多样性,这里有一种在基本数组上使用滚动窗口的方法,这a也是一种视图。这假设我们事先知道 的长度a

首先我们创建一个过度分配的数组:

>>> datalen = 5
>>> base = numpy.zeros(datalen + 2, dtype='i8')

然后我们定义a为该数组的截断视图并对其进行初始化:

>>> a = base[1:-1]
>>> a[:] = [0, 1, 0, 1, 1]

现在我们使用stride_tricks. 形状数组的正常(5, 3)步幅dtype='i8'(24, 8); 通过减少248,我们确保每一行的起点向前移动一项而不是 3。

>>> window = numpy.lib.stride_tricks.as_strided(base, shape=(5, 3), 
                                                      strides=(8, 8))
>>> window
array([[0, 0, 1],
       [0, 1, 0],
       [1, 0, 1],
       [0, 1, 1],
       [1, 1, 0]])

现在我们可以调用sum(axis=1)

>>> window.sum(axis=1) - a
array([1, 0, 2, 1, 1])

awindow指向相同的内存,因此更新可以正常工作:

>>> a[0] = 9
>>> window
array([[0, 9, 1],
       [9, 1, 0],
       [1, 0, 1],
       [0, 1, 1],
       [1, 1, 0]])
>>> window.sum(axis=1) - a
array([1, 9, 2, 1, 1])

我还要指出,对于您在此处提供的特定示例,就像这样简单的工作:

>>> base[:5] + base[-5:]
array([1, 9, 2, 1, 1])
>>> a[0] = 0
>>> base[:5] + base[-5:]
array([1, 0, 2, 1, 1])

但我想你的实际需求更复杂。

于 2012-08-14T23:24:59.587 回答
0

怎么样:

numpy.vectorize(sum)(v) - a

例如:

>>> import numpy
>>> a = numpy.array([0,1,0,1,1])
>>> v = [a[0:2], a[0:3], a[1:4], a[2:5], a[3:5]]
>>> numpy.vectorize(sum)(v) - a
array([1, 0, 2, 1, 1])
于 2012-08-14T16:15:13.257 回答