提高脚本的性能(当前使用np.putmask的方法)



所以我想知道是否有比这更快的方法在数组上应用两个方程。D84、slope、q_dis、recking_parameter都是3000 * 3000的浮点数组。

# Work out the equation for over 100
depth_100 = 1 / (3.2 * np.power((9.81 * slope), 0.3) * np.power(d84, 3 * 0.3 - 1) * np.power(q_dis, (-2 * 0.3)))
# Work out the equation for under 100
depth_1 = 1 / (1.6 * np.power((9.81 * slope), 0.23) * np.power(d84, 3 * 0.23 - 1) * np.power(q_dis, (-2 * 0.23)))
depth_fin = np.zeros_like(slope, dtype = float)
# Use np.putmask to place the calculated values into the array based on the conditional.
np.putmask(depth_fin, recking_parameter >= 100, depth_100)
np.putmask(depth_fin, recking_parameter < 100, depth_1)

在你的题目中,你强调了np.putmask的使用,但实际上大部分时间都花在了算术上。取幂在计算上是昂贵的,但是您仍然可以通过避免临时数组来改善运行时间。您可以使用inplace操作符(如@ davidh的回答),也可以使用numexpr模块,例如:

import numexpr
depth_100 = '1 / (3.2 * (9.81 * slope)**0.3 * d84**-0.1 * q_dis**-0.6)'
depth_1 = '1 / (1.6 * (9.81 * slope)**0.23 * d84**-0.31 * q_dis**-0.46)'
depth_fin = 'where(recking_parameter < 100, '+depth_1+', '+depth_100+')'
depth_fin = numexpr.evaluate(depth_fin)

关于numexpr的好处是它也将使用多个核心。在我对双核的测试中,它的速度大约是原始代码的4倍,但根据CPU的不同,可能会获得更大的加速。

如果不能依赖numexpr(如moarningsun所示),则可以就地进行计算。例如:

pre_slope = 9.81 * slope
depth_100 = 1 / (3.2 * pre_slope**0.3 * d84**-0.1 * q_dis**-0.6)

pre_slope**0.3创建一个临时副本,为d84**-0.1创建另一个临时副本,以此类推,然后为每个操作创建一个全新的副本(并根据需要丢弃)。这是很大的内存需求。

可以避免:

depth_100 = d841**0.1
depth_100 *= q_dis**0.6
depth_100 /= pre_slope**0.3
depth_100 *= 1/3.2    # Note that multiplying is faster than dividing.

现在我需要更少的时间副本。对于depth1,如果你不需要保存所有其他数组,你可以做得更好:

d84 **=0.31
q_dis **=0.46
pre_slope **= 0.23
depth_1 = d84
depth_1 *= q_dis
depth_1 /= pre_slope
depth_1 *= 1/1.6

您可以通过预先计算9.81*slope数组并将zeros_like调用切换为empty_like调用来获得~14%的改进(我已经压缩了这里的代码,以便它适合页面):

slope_pre = 9.81 * slope
depth_100 = 1 / (3.2 * slope_pre**0.3 * d84**-0.1 * q_dis**-0.6)
depth_1 = 1 / (1.6 * slope_pre**0.23 * d84**-0.31 * q_dis**-0.46)
depth_fin = np.empty_like(slope)
np.putmask(depth_fin, recking_parameter >= 100, depth_100)
np.putmask(depth_fin, recking_parameter < 100, depth_1)
编辑:

另一个选择是研究使用Numba jit编译器来尝试得到一个编译的解决方案。诚然,我已经尝试过了,但并没有走得很远,但从Numba代码比纯python慢的问题中可以清楚地看出,在这样的简单计算上有可能获得很大的速度提升。

相关内容