【问题标题】:Is there a faster implementation of the following code?以下代码是否有更快的实现?
【发布时间】:2019-03-27 03:54:06
【问题描述】:

我有一个很大的一维numpy 数组。对于数组的每个条目,我需要生成一个线性间隔的子数组,直到该条目值。这是我的例子。

import numpy as np
a = np.array([2, 3])
b = np.array([np.linspace(0, i, 4) for i in a])

在这种情况下,存在大小为 4 的线性空间。上面代码中的最后一条语句涉及 for loop,如果 a 非常大,则该语句相当慢。在numpy 本身中实现这一点有什么技巧吗?

【问题讨论】:

    标签: python performance loops numpy vectorization


    【解决方案1】:

    您可以将其表述为outer product

    In [37]: a = np.arange(100000)
    
    In [38]: %timeit np.array([np.linspace(0, i, 4) for i in a])
    1 loop, best of 3: 1.3 s per loop
    
    In [39]: %timeit np.outer(a, np.linspace(0, 1, 4))
    1000 loops, best of 3: 1.44 ms per loop
    

    这个想法是获取一个单位linspace,然后按a 的每个元素分别对其进行缩放。

    如您所见,这使n=100000 的速度提高了约 1000 倍。

    为了完整起见,我会提到这段代码与原始版本的舍入属性略有不同(在实际应用中可能不是问题):

    In [52]: np.max(np.abs(np.array([np.linspace(0, i, 4) for i in a]) -
        ...:               np.outer(a, np.linspace(0, 1, 4))))
    Out[52]: 1.4551915228366852e-11
    

    P。 S. 表达这个想法的另一种方法是使用元素乘法和广播(基于@Scott Gigante 的建议):

    In [55]: %timeit a[:, np.newaxis] * np.linspace(0, 1, 4)
    1000 loops, best of 3: 1.48 ms per loop
    

    P。 P.S. 请参阅下面的 cmets 以了解有关使其更快的更多想法。

    【讨论】:

    • 请注意,对于那些喜欢元素乘法而不是外积的人来说,这相当于做a[:,None] * np.linspace(0, 1, 4)
    • @ScottGigante:感谢您的建议!我已经在答案中添加了(稍微修改过的版本)。
    • 可以设置np.linspace的dtype,避免不必要的转换(如果不需要双精度,输入是单精度)
    • BTW 因为linspace(0, 1, 4)从零开始,以一结束,这两列其实根本不需要计算(只需初始化一个空数组,将乘积结果输出到其他列,然后填充第一列为零,最后一列输入)。
    • 关于舍入效果:np.outer(a/3,arange(4)) 正好是np.array([np.linspace(0, i, 4) for i in a])。而u=a/3;w=np.vstack([np.zeros(a.size),u,2*u,a]).T 则快两倍。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-26
    • 2020-01-02
    • 2011-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多