我是Numpy新手。
我想创建一个包含一百万个数字的数组,该数组具有振幅呈指数衰减的正弦波。
换句话说,我希望每个单元格n
的值sin(n) * 2 ** (-n * factor)
。
最有效的方法是什么?
Numpy 有自己的sin
函数,它可以高效地完成你想做的任务。效率低下的主要原因是指数2 ** (-n * factor)
.
但是,numpy 在其exp
函数中确实具有有效的幂。因此,我们可以将基数转换为e
以使用exp
exp(-n * factor * log(2))
其中log
是另一个 numpy 函数,使用基本e
。通过在 numpy 在其矢量化中设置的循环之外进行尽可能多的计算,您可以进一步加快代码速度。换句话说,您首先设置标量
newfactor = -np.log(2) * factor
并使用x = np.linspace(0, 10, 1000000)
或类似的东西设置x
阵列。然后创建您的y
数组
y = np.sin(x) * np.exp(newfactor * x)
现在y
是一个数组,其中包含与x
数组中的值相对应的所有计算值。
Numpy 自己做循环,对于当前的技术来说非常有效。我的实验表明,以这种方式做幂所需的时间不到np.power(2, -factor * x)
或2 ** (-x * factor)
或np.exp2(-x * factor)
时间的 1/5。查看整个表达式,对于x
长度为一百万的数组,我的代码总共需要29.2 ms
才能执行。@ComplicatedPhenomenon的代码看起来不错,总共需要81.3 ms
才能执行,这几乎是它的 3 倍。(指出我的代码中的错误@ComplicatedPhenomenon帽子提示 - 我已经纠正了它,现在似乎运行良好。
Numexpr
Numpy 对简单的操作(如 sin(array)、exp(array)具有高效的实现,..问题是每个表达式(sin(n); -n * factor, 2 ** previous_Temp_array
)都是使用临时数组单独完成的中间结果。这会导致相当高的内存占用,并且还会对性能产生负面影响。
法典
import numpy as np
import numexpr as ne
def orig(n_max,factor):
n=np.arange(n_max)
return np.sin(n) * 2 ** (-n * factor)
#Rory Daulton's solution
def mod(n_max,factor):
n=np.arange(n_max)
newfactor = -np.log(2) * factor
return np.sin(n) * np.exp(newfactor * n)
def mod_2(n_max,factor):
n=np.arange(n_max)
return ne.evaluate("sin(n) * 2**(-n * factor)")
#Rory Daulton's solution using Numexpr
def mod_3(n_max,factor):
n=np.arange(n_max)
newfactor = -np.log(2) * factor
return ne.evaluate("sin(n) * exp(newfactor * n)")
计时
%timeit res=orig(1e6,0.5)
81 ms ± 4.75 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit res=mod(1e6,0.5)
46.3 ms ± 5.29 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit res=mod_2(1e6,0.5)
16 ms ± 214 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit res=mod_3(1e6,0.5)
11.1 ms ± 48.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)