如何在使用numpy数组时消除for循环和使用列表理解?

时间:2014-03-12 01:49:54

标签: python arrays numpy list-comprehension

我试图避免使用numpy数组的for循环。

如果我的代码如下所示:

psimaps = [np.zeros((10,10)) for i in range(len(features)-1)]

for k in range(len(features)-1):
    if k != len(features)-2:
        psimaps[k] = np.reshape(np.sum(featureParams*features[k], axis=1), (10,1)) + transitiveParams
    else:
        psimaps[k] = np.reshape(np.sum(featureParams*features[k], axis=1), (10,1)) + (np.sum(featureParams * features[k+1], axis=1)) + transitiveParams
return psimaps

如何在没有for循环的情况下将其更改为列表表示以执行此操作?谢谢。


我添加了原始代码。基本上,我正在从两个阵列生成新的阵列计算。

2 个答案:

答案 0 :(得分:3)

基本上您需要做的就是将features数组广播到Params数组。这可以通过在features末尾插入两个新轴来完成(如果Params数组不是2d,则更多)。请注意,我使用了keepdims而不是总和之后的重塑。

psimaps = np.sum(featureParams*features[..., None, None], axis=2, keepdims=True) + transitiveParams

执行上述操作后,您必须将最后两行添加到一起,然后删除最后一行,因为您有一个奇怪的循环结束:

psimaps[-2] += psimaps[-1] - transitiveParams
psimaps = psimaps[:-1]

顺便说一下,在我理解它之前,我首先必须简化原始循环。我会在这里留下我的简化版本:

伪造数据(以及我对形状的假设)

size = 30
features = np.random.rand(50)
transitiveParams = np.random.rand(size, size)
featureParams = np.random.rand(size, size)

OP的原始代码

psimaps_OP = [np.zeros((size,size)) for i in range(len(features)-1)]
for k in range(len(features)-1):
    if k != len(features)-2:
        psimaps_OP[k] = np.reshape(np.sum(featureParams*features[k], axis=1), (size,1)) + transitiveParams
    else:
        psimaps_OP[k] = np.reshape(np.sum(featureParams*features[k], axis=1), (size,1)) + (np.sum(featureParams * features[k+1], axis=1)) + transitiveParams

简化为:

psimaps_simp = np.zeros((len(features)-1, size, size))
for k in range(len(features)-1):
    psimaps_simp[k] = np.sum(featureParams*features[k], axis=1, keepdims=True) + transitiveParams
psimaps_simp[-1] += np.sum(featureParams*features[-1], axis=1)

list comp:

psimaps_comp = [np.sum(featureParams*features[k], axis=1, keepdims=True) + transitiveParams for k in xrange(len(features)-1)]
psimaps_comp[-1] += np.sum(featureParams*features[-1], axis=1)

矢量化:

psimaps_vec = np.sum(featureParams*features[..., None, None], axis=2, keepdims=True) + transitiveParams
psimaps_vec[-2] += psimaps_vec[-1] - transitiveParams
psimaps_vec = psimaps_vec[:-1]

接下来,检查以确保它们都给出相同的结果:

assert np.allclose(psimaps_simp, psimaps_OP), "simplification failed"
assert np.allclose(psimaps_simp, psimaps_vec), "vectorization failed"

最后,时间:

#OP
100 loops, best of 3: 1.99 ms per loop

#simplified:
1000 loops, best of 3: 1.94 ms per loop

#list comp:
1000 loops, best of 3: 1.63 ms per loop

#vectorised:
1000 loops, best of 3: 407 µs per loop

答案 1 :(得分:0)

如果初始化不重要,也许你可以这样做:

psimaps = [ featureParams + transitiveParams for k in xrange(1,10)]

对于每个k,将执行sum featureParams + transitiveParams。