我有一个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],...
对数组。任何帮助,或完全不同的想法,甚至完成主要任务,非常感谢: - )
答案 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的解决方案更好,因为它不会复制像这样的数据。