numpy数组与权重的部分和

时间:2013-11-23 12:59:23

标签: python arrays numpy split slice

我有一个numpy数组,比如[a,b,c,d,e,...],并且想要计算一个看起来像[x*a+y*b, x*b+y*c, x*c+y*d,...]的数组。我的想法是首先将原始数组拆分为类似[[a,b],[b,c],[c,d],[d,e],...]的内容,然后使用np.average指定轴和权重(在我的情况下为x+y=1)攻击此生物,甚至使用np.dot。不幸的是,我不知道如何创建这样的[a,b],[b,c],...对数组。任何帮助,或完全不同的想法,甚至完成主要任务,非常感谢: - )

4 个答案:

答案 0 :(得分:5)

最快,最简单的方法是手动提取阵列的两个切片并将它们一起添加:

>>> arr = np.arange(5)
>>> x, y = 10, 1
>>> x*arr[:-1] + y*arr[1:]
array([ 1, 12, 23, 34])

如果你想将它推广到三倍,四倍......这将变成一种痛苦......但你可以用更为一般的形式用as_strided从原始数组创建你的数组对象:

>>> from numpy.lib.stride_tricks import as_strided

>>> arr_pairs = as_strided(arr, shape=(len(arr)-2+1,2), strides=arr.strides*2)
>>> arr_pairs
array([[0, 1],
       [1, 2],
       [2, 3],
       [3, 4]])

当然,使用as_strided的好处是,就像数组切片一样,不涉及数据复制,只是搞乱内存的查看方式,所以创建这个数组实际上是无成本的。 / p>

现在可能最快的是使用np.dot

>>> xy = [x, y]
>>> np.dot(arr_pairs, xy)
array([ 1, 12, 23, 34])

答案 1 :(得分:3)

这看起来像correlate问题。

a
Out[61]: array([0, 1, 2, 3, 4, 5, 6, 7])

b
Out[62]: array([1, 2])

np.correlate(a,b,mode='valid')
Out[63]: array([ 2,  5,  8, 11, 14, 17, 20])

根据阵列大小和BLAS点可以更快,您的milage会有很大差异:

arr = np.random.rand(1E6)

b = np.random.rand(2)

np.allclose(jamie_dot(arr,b),np.convolve(arr,b[::-1],mode='valid'))
True

%timeit jamie_dot(arr,b)
100 loops, best of 3: 16.1 ms per loop

%timeit np.correlate(arr,b,mode='valid')
10 loops, best of 3: 28.8 ms per loop

这是针对intel mkl BLAS和8核,np.correlate对于大多数实现来说可能更快。

@ Jamie的帖子也是一个有趣的观察结果:

%timeit b[0]*arr[:-1] + b[1]*arr[1:]
100 loops, best of 3: 8.43 ms per loop

他的评论也消除了np.convolve(a,b[::-1],mode=valid)对更简单的correlate语法的使用。

答案 2 :(得分:1)

如果你有一个小数组,我会创建一个移位副本:

shifted_array=numpy.append(original_array[1:],0)
result_array=x*original_array+y*shifted_array

这里你必须将你的数组存储在内存中两次,所以这个解决方案的内存效率非常低,但你可以摆脱for循环。

如果你有大型数组,你真的需要一个循环(但更像是一个列表理解):

result_array=[x*original_array[i]+y*original_array[i+1] for i in xrange(len(original_array)-1)]

它给你的结果与python列表相同,除了最后一项,无论如何应该区别对待。

基于一些随机试验,适用于小于2000项的阵列。第一个解决方案似乎比第二个解决方案更快,但即使对于相对较小的阵列(在我的PC上几十万个),也会遇到MemoryError。

所以一般来说,使用列表理解,但如果你肯定知道你只会在小(最大1-2千)数组上运行它,你就会有更好的镜头。

创建像[[a,b],[b,c],[c,d],[d,e],...]这样的新列表既有内存又有时间效率低,因为你还需要一个for循环(或类似的)来创建它,你必须将每个旧值存储在一个新数组中两次,因此,您最终会将原始阵列存储三次。

答案 3 :(得分:0)

另一种方法是在数组a = np.array([a,b,c,d,e,...])中创建正确的对,根据数组b = np.array([x, y, ...])的大小重新整形,然后利用numpy广播规则:

a = np.arange(8) 
b = np.array([1, 2])

a = a.repeat(2)[1:-1]
ans = a.reshape(-1, b.shape[0]).dot(b)

计时(在我的电脑上):

@Ophion's solution:
# 100000 loops, best of 3: 4.67 µs per loop

This solution:
# 100000 loops, best of 3: 9.78 µs per loop

所以,它更慢。 @ Jaime的解决方案更好,因为它不会复制像这样的数据。