python - 加快计算返回

标签 python pandas

我正在使用 python 2.7。我正在寻找计算每日返回的复合返回,而我当前的代码在计算返回时非常慢,所以我一直在寻找可以提高效率的领域。

我想做的是将两个日期和一个证券传递到价格表中,并使用提供的证券计算这些日期之间的复合返回。

我有一个价格表(prices_df):

security_id px_last    asof
    1       3.055   2015-01-05
    1       3.360   2015-01-06
    1       3.315   2015-01-07
    1       3.245   2015-01-08
    1       3.185   2015-01-09

我还有一个包含两个日期和安全性的表 (events_df):

asof            disclosed_on    security_ref_id
2015-01-05  2015-01-09 16:31:00     1
2018-03-22  2018-03-27 16:33:00     3616
2017-08-03  2018-03-27 12:13:00     2591
2018-03-22  2018-03-27 11:33:00     3615
2018-03-22  2018-03-27 10:51:00     3615

使用此表中的两个日期,我想使用价格表来计算返回。

我正在使用的两个函数:

import pandas as pd
# compounds returns
def cum_rtrn(df):
    df_out = df.add(1).cumprod()
    df_out['return'].iat[0] = 1
    return df_out

# calculates compound returns from prices between two dates
def calc_comp_returns(price_df, start_date=None, end_date=None, security=None):
    df = price_df[price_df.security_id == security]
    df = df.set_index(['asof'])
    df = df.loc[start_date:end_date]
    df['return'] = df.px_last.pct_change()
    df = df[['return']]
    df = cum_rtrn(df)
    return df.iloc[-1][0]

然后,我每次使用 .iterrows 传递 calc_comp_returns 函数来遍历 events_df。但是,这是一个非常缓慢的过程,因为我有 10K+ 次迭代,所以我正在寻求改进。解决方案不需要基于pandas

# example of how function is called
start = datetime.datetime.strptime('2015-01-05', '%Y-%m-%d').date()
end = datetime.datetime.strptime('2015-01-09', '%Y-%m-%d').date()
calc_comp_returns(prices_df, start_date=start, end_date=end, security=1)

最佳答案

这是一个解决方案(使用一些虚拟数据在我的计算机上快 100 倍)。

import numpy as np

price_df = price_df.set_index('asof')

def calc_comp_returns_fast(price_df, start_date, end_date, security):
    rows = price_df[price_df.security_id == security].loc[start_date:end_date]
    changes = rows.px_last.pct_change()
    comp_rtrn = np.prod(changes + 1)
    return comp_rtrn

或者,作为单行:

 def calc_comp_returns_fast(price_df, start_date, end_date, security):
    return np.prod(price_df[price_df.security_id == security].loc[start_date:end_date].px_last.pct_change() + 1)

并不是说我预先调用了set_index 方法,它只需要在整个price_df 数据帧上执行一次。

速度更快,因为它不会在每一步都重新创建 DataFrame。在您的代码中, df 几乎在每一行都被新数据框覆盖。 init 进程和垃圾收集(从内存中删除未使用的数据)都需要花费大量时间。

在我的代码中,rows 是原始数据的切片或“ View ”,它不需要复制或重新初始化任何对象。此外,我直接使用了 numpy product 函数,这与获取最后一个 cumprod 元素相同(无论如何 pandas 在内部使用 np.cumprod)。

建议:如果您使用的是 IPython、Jupyter 或 Spyder,您可以使用神奇的 %prun calc_comp_returns(...) 来查看哪个部分花费的时间最多。我在你的代码上运行它,它是垃圾收集器,使用了总运行时间的 50% 以上!

关于python - 加快计算返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49544207/

相关文章:

python - 如何将函数应用于自身?

python - Numpy 选择默认条件返回错误值

python - 如何从 Flask 制作 html 弹出窗口?

Python - RelaxNG 对象模型生成器/解析器

Python - 对 pandas 数据框中的两行应用 concat 函数

java - 登录 Unix 位置

python - 为什么 Pandas 中有 datetime.datetime ?

python - 创建一个函数来标准化分类变量 (python)

具有 3 级多索引的 Pandas 数据透视表

python - 如何加快距离矩阵计算?