Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 最优化中的EWMA协方差矩阵_Python_Pandas_Python Multiprocessing_Covariance - Fatal编程技术网

Python 最优化中的EWMA协方差矩阵

Python 最优化中的EWMA协方差矩阵,python,pandas,python-multiprocessing,covariance,Python,Pandas,Python Multiprocessing,Covariance,我想使用Pandas从股票价格回报的数据框架中计算EWMA协方差矩阵,并遵循中的方法 我喜欢使用Pandas对象和函数的灵活性,但当资产集增长时,功能变得非常缓慢: import pandas as pd import numpy as np def ewma_cov_pairwise_pd(x, y, alpha=0.06): x = x.mask(y.isnull(), np.nan) y = y.mask(x.isnull(), np.nan) covariati

我想使用Pandas从股票价格回报的数据框架中计算EWMA协方差矩阵,并遵循中的方法

我喜欢使用Pandas对象和函数的灵活性,但当资产集增长时,功能变得非常缓慢:

import pandas as pd
import numpy as np

def ewma_cov_pairwise_pd(x, y, alpha=0.06):
    x = x.mask(y.isnull(), np.nan)
    y = y.mask(x.isnull(), np.nan)
    covariation = ((x - x.mean()) * (y - y.mean()).dropna()
    return covariation.ewm(alpha=0.06).mean().iloc[-1]

def ewma_cov_pd(rets, alpha=0.06):
    assets = rets.columns
    n = len(assets)
    cov = np.zeros((n, n))
    for i in range(n):
        for j in range(i, n):
            cov[i, j] = cov[j, i] = ewma_cov_pairwise_pd(
                rets.iloc[:, i], rets.iloc[:, j], alpha=alpha)
    return pd.DataFrame(cov, columns=assets, index=assets)
我希望在仍然使用Pandas的情况下提高代码的速度,但瓶颈在DataFrame.ewm()函数中,该函数使用了90%的计算时间

如果使用此函数是一种绑定约束,那么提高代码运行速度的最有效方法是什么?我正在考虑采用蛮力方法并使用concurrent.futures.ProcessPoolExecutor,但也许有更好的解决方案

n = 100  # n is typically 2000
rets = pd.DataFrame(np.random.normal(0, 1., size=(n, n)))
cov_pd = ewma_cov_pd(rets)
真正的时间序列数据可能包含前导空值和之后可能丢失的值,尽管后者不太可能

更新I

一个潜在的解决方案可以利用广亨提供的答案,并在更合理的时间内产生预期的结果,类似于:

def ewma_cov_frame_qh(rets, alpha=0.06):
    weights = (1-alpha) ** np.arange(len(df))[::-1]
    normalized = (rets-rets.mean()).to_numpy()    
    out = (weights * normalized.T) @ normalized / weights.sum()
    return pd.DataFrame(out, index=rets.columns, columns=rets.columns)


def ewma_cov_qh(rets, alpha=0.06):
    syms = rets.columns
    covar = pd.DataFrame(index=rets.columns, columns=rets.columns)
    delta = rets.isnull().sum(axis=1).shift(1) - rets.isnull().sum(axis=1)
    dates = delta.loc[delta != 0].index.tolist()
     
    for date in dates:
        frame = rets.loc[rets.index >= date].dropna(axis=1, how='any')
        cov = ewma_cov_frame_qh(frame).reindex(index=syms, columns=syms)
        covar = covar.fillna(cov)
   
    return covar

cov_qh = ewma_cov_qh(rets)
这违反了使用本机Pandas/Numpy函数计算基础协方差的要求,并且计算时间将取决于数据集中前导na的数量

更新II

在我的机器上,使用(简单的)多处理并将计算时间进一步提高42.5%的潜在改进如下所示:

from concurrent.futures import ProcessPoolExecutor, as_completed
from functools import partial
    
def ewma_cov_mp_worker(date, rets, alpha=0.06):
    syms = rets.columns
    frame = rets.loc[rets.index >= date].dropna(axis=1, how='any')
    return ewma_cov_frame_qh(frame, alpha=alpha).reindex(index=syms, columns=syms)


def ewma_cov_mp(rets, alpha=0.06):
    covar = pd.DataFrame(index=rets.columns, columns=rets.columns)
    delta = rets.isnull().sum(axis=1).shift(1) - rets.isnull().sum(axis=1)
    dates = delta.loc[delta != 0].index.tolist()

    func = partial(ewma_cov_mp_worker, rets=rets, alpha=alpha)
    covs = {}

    with ProcessPoolExecutor(max_workers=6) as exec:
        future_to_date = {exec.submit(func, date): date for date in dates}
        covs = {future_to_date[future]: future.result() for future in as_completed(future_to_date)}

    for date in dates:
        covar.fillna(covs[date], inplace=True)

    return covar

[我没有添加答案,因为没有解决原始问题,我很乐观有更好的解决方案。]

因为您并不真正关心
ewm
,也就是说,您只取最后一个值。我们可以尝试矩阵乘法:

def ewma(df, alpha=0.94):
    weights = (1-alpha) ** np.arange(len(df))[::-1]

    # fillna with 0 here
    normalized = (df-df.mean()).fillna(0).to_numpy()
    
    out =  ((weights * normalized.T) @ normalized / weights.sum()
    
    return out

 # verify
 out = ewma(df)
 print(out[0,1] == ewma_cov_pairwise(df[0],df[1]) )
 # True

在我的系统上,使用
df.shape==(20002000)
大约需要
150毫秒,而您的代码拒绝在几分钟内运行:-)。

因为您并不真正关心
ewm
,也就是说,您只取最后一个值。我们可以尝试矩阵乘法:

def ewma(df, alpha=0.94):
    weights = (1-alpha) ** np.arange(len(df))[::-1]

    # fillna with 0 here
    normalized = (df-df.mean()).fillna(0).to_numpy()
    
    out =  ((weights * normalized.T) @ normalized / weights.sum()
    
    return out

 # verify
 out = ewma(df)
 print(out[0,1] == ewma_cov_pairwise(df[0],df[1]) )
 # True

这在我使用df.shape==(20002000)
的系统上大约花费了
150 ms
,而您的代码拒绝在几分钟内运行:-)。

谢谢Quang和您的建议。问题是数据可能包含前导缺失值(我在上面没有提到)。因此,在您的示例中,如果df.iloc[0,0]=np.nan,那么将不起作用。我想我可以递归地遍历。另外,如果我将alpha替换为**kwargs,则可以利用本机函数中的任何其他参数。@user2579685将nan填充为0不起作用?我不知道当你有了领导权后会有什么变化。发生这种情况时,您会期望什么?我想计算x和y上的公共观测值的成对covar。@user2579685更新,我测试了设置
df.loc[:5,0]=np.nan
,并使用
fillna
,如答案所示。这两种方法返回相同的答案。但在不使用零填充na的情况下,pandas函数会得到我想要的结果,如果我将函数分解为两两运算,则改进会比您预期的要温和得多。谢谢Quang,就像您所建议的那样。问题是数据可能包含前导缺失值(我在上面没有提到)。因此,在您的示例中,如果df.iloc[0,0]=np.nan,那么将不起作用。我想我可以递归地遍历。另外,如果我将alpha替换为**kwargs,则可以利用本机函数中的任何其他参数。@user2579685将nan填充为0不起作用?我不知道当你有了领导权后会有什么变化。发生这种情况时,您会期望什么?我想计算x和y上的公共观测值的成对covar。@user2579685更新,我测试了设置
df.loc[:5,0]=np.nan
,并使用
fillna
,如答案所示。这两种方法返回相同的答案。但是,如果不使用零填充na,pandas函数将得到我想要的结果,如果我将函数分解为成对操作,则改进将比您预期的要温和得多。