是否有更有效(即更快)的方式来计算相关随机游走?

时间:2017-10-10 19:55:03

标签: python numpy numba

有没有办法对其进行矢量化或加速?我已经使用numba进行了测试,但它仍然是一个主要的瓶颈。使用numba在1-d numpy数组上运行我的函数会导致代码快几个数量级,但在下面的2-d数组上使用numba时,基本上可以忽略不计。分解是一个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

1 个答案:

答案 0 :(得分:3)

您可以改进的第一件事是删除for循环。如果您认为它确实生成随机数,则使用相同的输入参数多次调用np.random.normal没有任何优势。

不使用np.matrix,而是使用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)))