有没有更有效(即更快)的方法来计算相关的随机游走?
Is there a more efficient (i.e. faster) way to compute correlated random walks?
有什么方法可以矢量化或以其他方式加速吗?我已经在使用 numba 来解决它了,但它仍然是一个主要瓶颈。使用 numba 在一维 numpy 数组上对我的函数进行 jit 会导致代码速度提高几个数量级,但在下面的二维数组上使用 numba 时基本上可以忽略不计的改进。 decomposition是一个numpy矩阵,表示相关矩阵的cholesky分解,x和n是常量,nrand是numpy.random
@jit
def generate_random_correlated_walks(decomposition, x, n):
uncorrelated_walks = np.empty((2*x, n))
for i in range(x):
# Generate the random uncorrelated walks
wv = nrand.normal(loc=0, scale=1, size=n)
ws = nrand.normal(loc=0, scale=1, size=n)
uncorrelated_walks[2*i] = wv
uncorrelated_walks[(2*i) + 1] = ws
# Create a matrix out of these walks
uncorrelated_walks = np.matrix(uncorrelated_walks)
m, n = uncorrelated_walks.shape
correlated_walks = np.empty((m, n))
# Go through column and correlate the walk values
for i in range(n):
correlated_timestep = np.transpose(uncorrelated_walks[:, i]) * decomposition
correlated_walks[:, i] = correlated_timestep
return correlated_walks
编辑:我已经做了建议的更改,现在我的代码如下,但不幸的是仍然是一个主要瓶颈。有什么想法吗?
@jit
def generate_random_correlated_walks(self, decomposition, x, n):
rows = 2*x
uncorrelated_walks = np.random.normal(loc=0, scale=1, size=(rows, n))
correlated_walks = np.empty((rows, n))
for i in range(n):
correlated_timestep = np.dot(np.transpose(uncorrelated_walks[:, i]), decomposition)
correlated_walks[:, i] = correlated_timestep
return correlated_walks
您可以改进的第一件事是删除 for
循环。如果您认为 np.random.normal
确实会生成随机数,那么使用相同的输入参数多次调用 np.random.normal
并没有任何好处。
而不是使用 np.matrix
, use np.array
。当您认为上一项可用于将函数的整个第一部分缩短为一个步骤时,这将使您的生活更轻松。
您当然可以通过简单的矩阵乘法完全删除最终循环:uncorrelated_walks.T @ decomposition
将为您提供当前 correlated_walks
的转置。您可以通过更改参数的顺序来避免 transposes 之一。
你最终会得到这样的结果:
def generate_random_correlated_walks(decomposition, x, n):
uncorrelated_walks = nrand.normal(loc=0, scale=1, size=(2*x, n))
correlated_walks = np.dot(decomposition.T, uncorrelated_walks)
return correlated_walks
不确定这对您有多大帮助,但删除 Python 级循环应该是一种提升,因为它会减少多个 numpy 调用的开销。
您可以牺牲易读性来将整个内容变成一行:
def generate_random_correlated_walks(decomposition, x, n):
return np.dot(decomposition.T, nrand.normal(loc=0, scale=1, size=(2*x, n)))
有什么方法可以矢量化或以其他方式加速吗?我已经在使用 numba 来解决它了,但它仍然是一个主要瓶颈。使用 numba 在一维 numpy 数组上对我的函数进行 jit 会导致代码速度提高几个数量级,但在下面的二维数组上使用 numba 时基本上可以忽略不计的改进。 decomposition是一个numpy矩阵,表示相关矩阵的cholesky分解,x和n是常量,nrand是numpy.random
@jit
def generate_random_correlated_walks(decomposition, x, n):
uncorrelated_walks = np.empty((2*x, n))
for i in range(x):
# Generate the random uncorrelated walks
wv = nrand.normal(loc=0, scale=1, size=n)
ws = nrand.normal(loc=0, scale=1, size=n)
uncorrelated_walks[2*i] = wv
uncorrelated_walks[(2*i) + 1] = ws
# Create a matrix out of these walks
uncorrelated_walks = np.matrix(uncorrelated_walks)
m, n = uncorrelated_walks.shape
correlated_walks = np.empty((m, n))
# Go through column and correlate the walk values
for i in range(n):
correlated_timestep = np.transpose(uncorrelated_walks[:, i]) * decomposition
correlated_walks[:, i] = correlated_timestep
return correlated_walks
编辑:我已经做了建议的更改,现在我的代码如下,但不幸的是仍然是一个主要瓶颈。有什么想法吗?
@jit
def generate_random_correlated_walks(self, decomposition, x, n):
rows = 2*x
uncorrelated_walks = np.random.normal(loc=0, scale=1, size=(rows, n))
correlated_walks = np.empty((rows, n))
for i in range(n):
correlated_timestep = np.dot(np.transpose(uncorrelated_walks[:, i]), decomposition)
correlated_walks[:, i] = correlated_timestep
return correlated_walks
您可以改进的第一件事是删除 for
循环。如果您认为 np.random.normal
确实会生成随机数,那么使用相同的输入参数多次调用 np.random.normal
并没有任何好处。
而不是使用 np.matrix
, use np.array
。当您认为上一项可用于将函数的整个第一部分缩短为一个步骤时,这将使您的生活更轻松。
您当然可以通过简单的矩阵乘法完全删除最终循环:uncorrelated_walks.T @ decomposition
将为您提供当前 correlated_walks
的转置。您可以通过更改参数的顺序来避免 transposes 之一。
你最终会得到这样的结果:
def generate_random_correlated_walks(decomposition, x, n):
uncorrelated_walks = nrand.normal(loc=0, scale=1, size=(2*x, n))
correlated_walks = np.dot(decomposition.T, uncorrelated_walks)
return correlated_walks
不确定这对您有多大帮助,但删除 Python 级循环应该是一种提升,因为它会减少多个 numpy 调用的开销。
您可以牺牲易读性来将整个内容变成一行:
def generate_random_correlated_walks(decomposition, x, n):
return np.dot(decomposition.T, nrand.normal(loc=0, scale=1, size=(2*x, n)))