[[ 0.0 0.2 0.4 0.6 ]
[ 0.0 0.0 2.0 4.0 6.0 ]
[ 0.0 0.0 0.0 20.0 40.0 60.0 ]]
是一个衣衫褴褛的名单。我们可以用viectorized阵列魔法来构建它,至少不是用普通的东西。
为了解决这个问题,我们需要或者变平或垫这种结构
[[ 0.0 0.2 0.4 0.6 0.0 0.0]
[ 0.0 0.0 2.0 4.0 6.0 0.0 ]
[ 0.0 0.0 0.0 20.0 40.0 60.0 ]]
或
[ 0.0 0.2 0.4 0.6 0.0 0.0 2.0 4.0 6.0 0.0 0.0 0.0 20.0 40.0 60.0 ]
sum.reduceat
让我们平坦的阵列的总和块,但你想跳过总和。我想我可以探索平移转置。
我的第一个想法是,填充阵列看起来像是一个对角化阵列,[.2,2,20]放置在对角线上,在下一个偏移处放置[.4,4,40],等等。 。我知道sparse
可以从一个矩阵和一组偏移量构建矩阵,但我不认为在numpy
中有这样的函数。他们一次只能使用一个胶印。
但它也看起来像stride_tricks
可以产生的偏移类型。
让我们探索:
In [458]: as_strided =np.lib.index_tricks.as_strided
In [459]: Z=np.pad(z,[[0,0],[3,3]],mode='constant')
In [460]: Z
Out[460]:
array([[ 0. , 0. , 0. , 0.2, 0.4, 0.6, 0. , 0. , 0. ],
[ 0. , 0. , 0. , 2. , 4. , 6. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 20. , 40. , 60. , 0. , 0. , 0. ]])
In [461]: Z.strides
Out[461]: (72, 8) # prod an offset with (72+8, 8)
In [462]: as_strided(Z,shape=(3,6),strides=(80,8))
Out[462]:
array([[ 0. , 0. , 0. , 0.2, 0.4, 0.6],
[ 0. , 0. , 2. , 4. , 6. , 0. ],
[ 0. , 20. , 40. , 60. , 0. , 0. ]])
这就是那种我们想要转移的,但方向是错误的;所以让翻盖Z
:
In [463]: Z1=Z[::-1,:].copy()
In [464]: as_strided(Z1,shape=(3,6),strides=(80,8))
Out[464]:
array([[ 0. , 0. , 0. , 20. , 40. , 60. ],
[ 0. , 0. , 2. , 4. , 6. , 0. ],
[ 0. , 0.2, 0.4, 0.6, 0. , 0. ]])
In [465]: as_strided(Z1,shape=(3,6),strides=(80,8)).sum(0)
Out[465]: array([ 0. , 0.2, 2.4, 24.6, 46. , 60. ])
泛化可以留给读者。
是否有任何速度优势未知。可能不是这个小案子,也许是一个非常大的案件。
此清理填充和跨越位
In [497]: Z=np.pad(z,[[0,0],[1,4]],mode='constant')
In [498]: Z.strides
Out[498]: (64, 8)
In [499]: as_strided(Z,shape=(3,6),strides=(64-8,8))
Out[499]:
array([[ 0. , 0.2, 0.4, 0.6, 0. , 0. ],
[ 0. , 0. , 2. , 4. , 6. , 0. ],
[ 0. , 0. , 0. , 20. , 40. , 60. ]])
这忽略z
是如何构造的。如果外部产品是问题的核心,我可能会尝试在1d y
上大步前进,并使用x
执行加权求和。
In [553]: x=np.array([1,10,100]); y=np.array([.2,.4,.6])
In [554]: z=np.concatenate(([0,0],y[::-1],[0,0,0]))
In [555]: z
Out[555]: array([ 0. , 0. , 0.6, 0.4, 0.2, 0. , 0. , 0. ])
In [556]: Z=as_strided(z,shape=(3,6), strides=(8,8))
In [557]: Z
Out[557]:
array([[ 0. , 0. , 0.6, 0.4, 0.2, 0. ],
[ 0. , 0.6, 0.4, 0.2, 0. , 0. ],
[ 0.6, 0.4, 0.2, 0. , 0. , 0. ]])
In [558]: np.dot(x,Z)
Out[558]: array([ 60. , 46. , 24.6, 2.4, 0.2, 0. ])
在这种结构中Z
是z
的图,所以是比上的Z
小。但我确信dot
将它发送到编译代码时会生成副本。 np.einsum('i,ij',x,Z)
可能会避免这种情况,在不扩展它的情况下对其进行编译迭代。处理非常大的数组时,这可能会有所不同。
结果相反,但这很容易修复。我甚至可以在施工期间修复它。
小心时间测试。非迭代答案会创建一个数组,其大小是原始数据的两倍。迭代地,您可以在没有这些的情况下对偏移行进行求和。 – hpaulj
“外部”是问题的重要组成部分,还是创建'z'的便捷方式?这真的是某种内在产品或加权移动总和? – hpaulj