从每日到每分钟更快地重采样每日协方差矩阵(MultiIndex)

Faster Resampling Daily Covariance Matrix (MultiIndex) from Daily to Minutely

我查看了类似的答案,但找不到适合我问题的答案。

我有一个构造为 MultiIndex 的每日协方差矩阵。它有“k”个日期,对于每个“k”日期,它都有一个大小为“n”דn”的矩阵。维度在技术上是 (k, n, n) 但因为这是一个 MultiIndex pandas 将其视为形状 (kxn, n)。

作为最低限度的工作示例,我可以提供以下内容:

dates = pd.date_range(start='20120101', end='20210101', freq='D')
X = pd.DataFrame( {'A' : np.random.rand(len(dates)), 'B' : np.random.rand(len(dates)), 'C' : np.random.rand(len(dates)), 'D' : np.random.rand(len(dates)), 'E' : np.random.rand(len(dates)) }, index=dates).ewm(halflife=30, min_periods=1).cov()

我想从每天到每分钟重新采样。假设我的 MultiIndex 协方差矩阵被称为“X”,我已经设法让下面的工作:

X.unstack().resample("T").first().ffill().stack()

但是,这需要很长时间来计算。有没有更快更有效的方法来执行这个操作?

对于在 pandas 0.24 之后弃用的面板,这曾经是快速的。从我自己的分析工作来看,内存最密集的部分似乎是 'stack()'

IIUC

使用 resample 添加信息 ('D' -> 'T') 不是一个正确的选择,尤其是当您想要填充前向值时。您可以使用 np.vsplit 创建一个类似面板的面板,然后根据您的 DatetimeIndex 重复您的数组,最后重塑数据:

# Create new MultiIndex
dates2 = pd.date_range(X.index.levels[0].min(),
                       X.index.levels[0].max() + pd.DateOffset(days=1), 
                       freq='T', closed='left')
mi = pd.MultiIndex.from_product([dates2, X.index.levels[1]])

# Manipulate your array
vals = np.array(np.repeat(np.vsplit(X.values, len(X.index.levels[0])), 24*60, axis=0))
vals = vals.reshape(vals.shape[0]*vals.shape[1], vals.shape[2])

# New dataframe
out = pd.DataFrame(vals, index=mi, columns=X.columns)

对于较小的样本:

>>> df
               A   B
2012-01-01 A  11  12
           B  13  14
2012-01-02 A  21  22
           B  23  24
2012-01-03 A  31  32
           B  33  34

# Resample: 12H and 2 values per day
# dates2 = pd.date_range(df.index.levels[0].min(), df.index.levels[0].max() + pd.DateOffset(days=1), freq='12H', closed='left')
# mi = pd.MultiIndex.from_product([dates2, df.index.levels[1]])
# vals = np.array(np.repeat(np.vsplit(df.values, len(df.index.levels[0])), 2, axis=0))
# vals = vals.reshape(vals.shape[0]*vals.shape[1], vals.shape[2])
# out = pd.DataFrame(vals, index=mi, columns=df.columns)

>>> out
                        A   B
2012-01-01 00:00:00 A  11  12
                    B  13  14
2012-01-01 12:00:00 A  11  12
                    B  13  14
2012-01-02 00:00:00 A  21  22
                    B  23  24
2012-01-02 12:00:00 A  21  22
                    B  23  24
2012-01-03 00:00:00 A  31  32
                    B  33  34
2012-01-03 12:00:00 A  31  32
                    B  33  34

使用您的代码:

>>> df.unstack().resample("12H").first().ffill().stack()
                          A     B
2012-01-01 00:00:00 A  11.0  12.0
                    B  13.0  14.0
2012-01-01 12:00:00 A  11.0  12.0
                    B  13.0  14.0
2012-01-02 00:00:00 A  21.0  22.0
                    B  23.0  24.0
2012-01-02 12:00:00 A  21.0  22.0
                    B  23.0  24.0
2012-01-03 00:00:00 A  31.0  32.0
                    B  33.0  34.0
                                   # <- Lost 2012-01-03 12:00:00

在 X

上的表现
>>> %timeit op_resample()
9.1 s ± 568 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>> %timeit new_array()
1.86 s ± 23 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)