【发布时间】:2018-10-30 14:57:07
【问题描述】:
我有以下一段代码,它基本上评估一些数值表达式,并使用它来整合特定范围的值。当前的代码在8.6 s 内运行,但我只是使用模拟值,而我的实际数组要大得多。特别是,我的实际大小为freq_c= (3800, 101) 和number_bin = (3800, 100),这使得下面的代码效率非常低,因为实际数组的总执行时间将接近 9 分钟。相当慢的一部分代码是对k_one_third 和k_two_third 的评估,为此我还使用了numexpr.evaluate(".."),这将代码加速了大约10-20%。但是,我避免了下面的numexpr,这样任何人都可以运行它而无需安装包。还有其他方法可以提高此代码的速度吗?几个因素的改进也足够了。请注意for loop 几乎是不可避免的,由于内存问题,由于数组非常大,我通过循环一次操作每个轴。我也想知道numba jit是否可以在这里优化。
import numpy as np
import scipy
from scipy.integrate import simps as simps
import time
def k_one_third(x):
return (2.*np.exp(-x**2)/x**(1/3) + 4./x**(1/6)*np.exp(-x)/(1+x**(1/3)))**2
def k_two_third(x):
return (np.exp(-x**2)/x**(2/3) + 2.*x**(5/2)*np.exp(-x)/(6.+x**3))**2
def spectrum(freq_c, number_bin, frequency, gamma, theta):
theta_gamma_factor = np.einsum('i,j->ij', theta**2, gamma**2)
theta_gamma_factor += 1.
t_g_bessel_factor = 1.-1./theta_gamma_factor
number = np.concatenate((number_bin, np.zeros((number_bin.shape[0], 1), dtype=number_bin.dtype)), axis=1)
number_theta_gamma = np.einsum('jk, ik->ijk', theta_gamma_factor**2*1./gamma**3, number)
final = np.zeros((np.size(freq_c[:,0]), np.size(theta), np.size(frequency)))
for i in xrange(np.size(frequency)):
b_n_omega_theta_gamma = frequency[i]**2*number_theta_gamma
eta = theta_gamma_factor**(1.5)*frequency[i]/2.
eta = np.einsum('jk, ik->ijk', eta, 1./freq_c)
bessel_eta = np.einsum('jl, ijl->ijl',t_g_bessel_factor, k_one_third(eta))
bessel_eta += k_two_third(eta)
eta = None
integrand = np.multiply(bessel_eta, b_n_omega_theta_gamma, out= bessel_eta)
final[:,:, i] = simps(integrand, gamma)
integrand = None
return final
frequency = np.linspace(1, 100, 100)
theta = np.linspace(1, 3, 100)
gamma = np.linspace(2, 200, 101)
freq_c = np.random.randint(1, 200, size=(50, 101))
number_bin = np.random.randint(1, 100, size=(50, 100))
time1 = time.time()
spectra = spectrum(freq_c, number_bin, frequency, gamma, theta)
print(time.time()-time1)
【问题讨论】:
-
代替 for 循环,您可以对数组执行 numpy 操作。这样可以节省一些时间
-
@Kalyan 我明确地使用了循环,因为我的数组太大而无法在没有得到
MemoryError的情况下一次执行所有numpy 操作。 -
至少将你的内部循环体重写为简单的循环(没有 np.einsums,没有乘法,如果可能的话没有临时数组)。对于像 Numba 和 Cython 这样的编译器,这将更容易优化。
标签: python arrays performance numpy numba