【发布时间】:2021-12-13 06:16:03
【问题描述】:
现在我有 1 个循环来填充 3D NumPy 矩阵。尽管我知道它实际上只是我习惯于在(2D)中思考的正常 XxY 的 XxYxZ 表示,但我并不是最擅长理解 3D 数组结构。因此,如果您想知道这是什么,它是用于财务问题的蒙特卡洛模拟中的布朗桥 (BB) 结构。原始代码的信用(源自修复作者 Kenta Oono 的原始帖子的评论,位于此处):https://gist.github.com/delta2323/6bb572d9473f3b523e6e。你真的不需要知道它背后的数学。它基本上只是切断了一个步骤路径(在本例中为 21),从 0 开始,应用正态分布的冲击(因此 np.random.randn)直到它到达终点,这也是 0。每条路径都应用于模拟价格随时间随机“冲击”它,生成资产在到期时可能遵循的潜在路径。虽然这些是完全不相关的,所以我想我也会传入一个 V 矩阵来关联正确的路径,但是,让我们保持简单:
import numpy as np
from matplotlib import pyplot
import timeit
steps = 21
underlyings = 3
sims = 131072
seed = 0 # fix the seed for replicating results
np.random.seed(seed)
def sample_path_batches(underlyings, steps, sims):
dt = 1.0 / (steps-1)
dt_sqrt = np.sqrt(dt)
B = np.empty((underlyings, steps, sims), dtype=float)
B[:,0, :] = 0 # set first step to 0
for n in range(steps - 2):
t = n * dt
xi = np.random.randn(underlyings, sims) * dt_sqrt
B[:, n + 1, :] = B[:, n, :] * (1 - dt / (1 - t)) + xi
B[:, -1, :] = 0 # set last step to 0
return B
start_time = timeit.default_timer()
B = sample_path_batches(underlyings, steps, sims)
print('\n' + 'Run time for ', sims, ' simulation steps * underlyings: ',
np.round((timeit.default_timer() - start_time),3), ' seconds')
pyplot.plot(B[:,:,np.random.randint(0,sims)].T); # plot a random simulation set of paths
pyplot.show()
131072 个模拟步骤的运行时间 * 底层代码:2.014 秒
无论如何,这对我的应用程序来说太慢了,尽管我最初的带有第二个内循环的版本大约需要 15 秒。所以我已经看到人们通过 np.vectorize 对 NumPy 进行矢量化或使用映射来“展平”循环,但我无法想象自己如何实际做到这一点。我正在寻找将产生相同数字的最佳“本机 Python”实现。 B 是 3D NumPy 数组。如果需要,您可以复制并粘贴它并在线运行它:https://mybinder.org/v2/gh/jupyterlab/jupyterlab-demo/HEAD?urlpath=lab/tree/demo
欢迎提出任何建议!!!即使它只是“像这样重组循环,然后应用 np.vectorize”或其他什么,我也很擅长提出建议并使其从一个简单的“新观点”中解决如何可视化问题。我通常只会在 Cython(nogil / OpenMP / prange)中做这种类型的事情,但我想知道在一般情况下“扁平化”一个循环,在 NumPy 或 Pandas 中内置普通数学库或其他任何工作。
【问题讨论】:
-
不,
np.vectorize和map都不会显着提升与普通for循环相比的性能。 -
map或np.vectorize都不会加快您的代码速度。 -
感谢 cmets - 我想 Cython 是最好的选择。
-
您可以尝试
@numba.vectorize以尽量减少重写,但您可能会遇到 Numba 限制。 Cython 需要大量类型注释才能工作,但总体而言这可能是一件好事。 -
是的,numba @jit 从来没有为我编写代码的方式带来任何加速;称它为我不了解编译更快例程所需的格式,或者我的例程无法使用该软件加速。过去,真正加快我的代码速度的唯一因素是 Cython / nogil / inline / OpenMP / prange 语句,尽管转换它的努力和时间很长;全部使用 NumPy 内存视图。是的,有一个函数可以在 Cython 中执行 Mersenne Twister,但它不使用任何这些优化:github.com/ananswam/cython_random
标签: python numpy vectorization montecarlo