首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何加快NumPy代码的分析-矢量化,Numba?

如何加快NumPy代码的分析-矢量化,Numba?
EN

Stack Overflow用户
提问于 2016-12-14 16:56:07
回答 2查看 347关注 0票数 3

我正在运行一个大型Python程序,为金融领域的投资组合优化(Markowitz)优化投资组合权重。当我分析代码时,90%的运行时间用于计算投资组合的回报,这需要花费数百万次。我能做些什么来加速我的代码?我试过:

  • 将返回的计算矢量化:使代码从1.5ms降低到3ms
  • 使用Numba中的autojit函数来加快代码速度:无更改

见下面的例子-有什么建议吗?

代码语言:javascript
复制
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是最快的:

代码语言:javascript
复制
def get_pf_returns(weights, asset_returns):
    return np.prod(1 + np.matmul(asset_returns, weights), axis=0) ** (12.0 / 60) - 1
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-12-14 18:35:53

在我的环境中,mutmul (@)相对于einsumdot具有一定的时间优势。

代码语言:javascript
复制
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代码。原来的循环版本速度相对较快,这可能与较完整的dot中的少量循环(只有60个循环)和内存管理问题有关。

numba可能不会替换dot代码。

因此,这里或那里的调整可能会使代码的速度提高2倍,但不要期望有一个数量级的改进。

票数 2
EN

Stack Overflow用户

发布于 2016-12-14 17:27:15

下面是一个使用np.einsum来加快速度的版本:

代码语言:javascript
复制
def get_pf_returns3(weights, asset_returns, horizon=60):
    pf = np.ones(asset_returns.shape[1])
    z = np.einsum("ijk,k -> ij",asset_returns[:horizon,:,:], weights)
    pf = np.multiply.reduce(1 + z)
    return pf ** (12.0 / horizon) - 1

然后计时:

代码语言:javascript
复制
%timeit get_pf_returns(weights, asset_returns)
%timeit get_pf_returns3(weights, asset_returns)
print np.allclose(get_pf_returns(weights, asset_returns), get_pf_returns3(weights, asset_returns))

# 1000 loops, best of 3: 727 µs per loop
# 1000 loops, best of 3: 638 µs per loop
# True

根据硬件的不同,机器上的时间可能是不同的,而numpy是针对这些库编译的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41148080

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档