我如何加快配置文件NumPy代码的使用-矢量化,Numba?

我正在运行一个大型Python程序来优化金融中(Markowitz)投资组合优化的投资组合权重.当我分析代码时,要花费90%的运行时间来计算投资组合的收益,这需要进行数百万次.我该怎么做才能加快代码执行速度?我努力了:

>向量化收益计算:使代码变慢,从1.5毫秒降低到3毫秒
>使用Numba中的autojit函数来加速代码:无变化

请参见下面的示例-有什么建议吗?

import numpy as np


def get_pf_returns(weights, asset_returns, horizon=60):
    '''
    Get portfolio returns: Calculates portfolio return for N simulations,
    assuming monthly rebalancing.

    Input
    -----
    weights: Portfolio weight for each asset
    asset_returns: Monthly returns for each asset, potentially many simulations
    horizon: 60 months (hard-coded)

    Returns
    -------
    Avg. annual portfolio return for each simulation at the end of 5 years
    '''
    pf = np.ones(asset_returns.shape[1])
    for t in np.arange(horizon):
        pf *= (1 + asset_returns[t, :, :].dot(weights))
    return pf ** (12.0 / horizon) - 1


def get_pf_returns2(weights, asset_returns):
    ''' Alternative '''
    return np.prod(1 + asset_returns.dot(weights), axis=0) ** (12.0 / 60) - 1

# Example
N, T, sims = 12, 60, 1000  # Settings
weights = np.random.rand(N)
weights *= 1 / np.sum(weights)  # Sample weights
asset_returns = np.random.randn(T, sims, N) / 100  # Sample returns

# Calculate portfolio risk/return
pf_returns = get_pf_returns(weights, asset_returns)
print np.mean(pf_returns), np.std(pf_returns)

# Timer
%timeit get_pf_returns(weights, asset_returns)
%timeit get_pf_returns2(weights, asset_returns)

编辑

解决方案:Matmul在我的机器上最快:

def get_pf_returns(weights, asset_returns):
    return np.prod(1 + np.matmul(asset_returns, weights), axis=0) ** (12.0 / 60) - 1

解决方法:

在我的环境中,mutmul(@)比einsum和dot具有适度的时间优势:

In [27]: np.allclose(np.einsum('ijk,k',asset_returns,weights),asset_returns@weig
    ...: hts)
Out[27]: True
In [28]: %timeit asset_returns@weights
100 loops, best of 3: 3.91 ms per loop
In [29]: %timeit np.einsum('ijk,k',asset_returns,weights)
100 loops, best of 3: 4.73 ms per loop
In [30]: %timeit np.dot(asset_returns,weights)
100 loops, best of 3: 6.8 ms per loop

我认为时间受计算总数的限制,而不是编码细节.所有这些都将计算结果传递给已编译的numpy代码.您的原始循环版本相对较快的事实可能与循环数量少(仅60个)以及内存管理问题有关.

numba可能不会替换点代码.

因此,在此处或此处进行调整可能会将您的代码速度提高2倍,但不要期望数量级的提高.

上一篇:面试题中关于String的常见操作


下一篇:python-在NumPy中向量化嵌套嵌套循环的循环