将 pandas MultiIndex (k x n x n) 乘以 DataFrame (k x n x 1)

Multiply a pandas MultiIndex (k x n x n) by a DataFrame (k x n x 1)

我有一个时间序列的协方差矩阵存储为 MultiIndex(我们称之为“A”)和一个时间序列的标量存储为 DataFrame(我们称之为“b”)。

“A”的形状为“k”x“n”x“n”,“b”的形状为“k”x“n”,所以我有协方差矩阵的“k”个日期的 MultiIndex形状为“n”x“n”,我想乘以标量的“k”x“n”x 1 DataFrame以获得“k”x“n”x 1 DataFrame。

当我尝试类似 A.multiply(b) 的操作时,它不起作用,因为 MultiIndex 维度是 (kxn, n) 并且不严格匹配 (k, n) 的 DataFrame 维度。

我能够使用列表理解来执行计算并将 MultiIndex 和 DataFrame 转换为 numpy 数组,但这需要非常非常长的时间,所以我的效率肯定很低。

这方面的一个例子是:

[np.dot( np.array( A.loc[timestamp,:] ), np.array( b.loc[timestamp,:] ) ) for timestamp in b.index]

这需要非常长的时间来计算。有没有快速的方法来执行此计算?

这是大小为 A 5×3×3 和 b 5×3 的随机值数据帧:

>>> A
                              0         1         2
2021-08-14 11:14:00 0  0.309559  0.286455  0.080467
                    1  0.996128  0.666138  0.354322
                    2  0.113316  0.208389  0.197855
2021-08-14 11:15:00 0  0.299459  0.650561  0.481504
                    1  0.570308  0.298572  0.677013
                    2  0.476066  0.610945  0.750575
2021-08-14 11:16:00 0  0.861801  0.692752  0.046450
                    1  0.587891  0.389874  0.779039
                    2  0.009947  0.647356  0.735746
2021-08-14 11:17:00 0  0.990027  0.185747  0.286276
                    1  0.831238  0.474372  0.459076
                    2  0.885953  0.768626  0.866064
2021-08-14 11:18:00 0  0.952294  0.106072  0.477348
                    1  0.370116  0.646081  0.873394
                    2  0.439066  0.568404  0.227528
>>> b
                            0         1         2
2021-08-14 11:14:00  0.113316  0.208389  0.197855
2021-08-14 11:15:00  0.476066  0.610945  0.750575
2021-08-14 11:16:00  0.009947  0.647356  0.735746
2021-08-14 11:17:00  0.885953  0.768626  0.866064
2021-08-14 11:18:00  0.439066  0.568404  0.227528

如果要将 A 中的每一行乘以 b 的单个值,即 b 列应与 A 索引的第二级对齐, 你应该使用 stack:

>>> A.mul(b.stack(), axis='index')
                              0         1         2
2021-08-14 11:14:00 0  0.035078  0.032460  0.009118
                    1  0.207582  0.138816  0.073837
                    2  0.022420  0.041231  0.039147
2021-08-14 11:15:00 0  0.142562  0.309710  0.229227
                    1  0.348427  0.182411  0.413618
                    2  0.357323  0.458560  0.563363
2021-08-14 11:16:00 0  0.008572  0.006891  0.000462
                    1  0.380575  0.252387  0.504315
                    2  0.007318  0.476290  0.541322
2021-08-14 11:17:00 0  0.877118  0.164563  0.253627
                    1  0.638911  0.364615  0.352858
                    2  0.767292  0.665679  0.750067
2021-08-14 11:18:00 0  0.418120  0.046573  0.209587
                    1  0.210376  0.367235  0.496441
                    2  0.099900  0.129328  0.051769

另一方面,如果您希望 b 列与 A 列对齐,您可以使用 pd.DataFrame.align(),两者的 returns 对齐版本数据框。这里 A 将保持不变,如 .compare() 所确认,并且 b_aligned 将在每个二级索引中重复其行以匹配 A 的索引:

>>> b_aligned, A_aligned = b.align(A, level=0)
>>> A_aligned.compare(A)
Empty DataFrame
Columns: []
Index: []
>>> b_aligned
                              0         1         2
2021-08-14 11:14:00 0  0.113316  0.208389  0.197855
                    1  0.113316  0.208389  0.197855
                    2  0.113316  0.208389  0.197855
2021-08-14 11:15:00 0  0.476066  0.610945  0.750575
                    1  0.476066  0.610945  0.750575
                    2  0.476066  0.610945  0.750575
2021-08-14 11:16:00 0  0.009947  0.647356  0.735746
                    1  0.009947  0.647356  0.735746
                    2  0.009947  0.647356  0.735746
2021-08-14 11:17:00 0  0.885953  0.768626  0.866064
                    1  0.885953  0.768626  0.866064
                    2  0.885953  0.768626  0.866064
2021-08-14 11:18:00 0  0.439066  0.568404  0.227528
                    1  0.439066  0.568404  0.227528
                    2  0.439066  0.568404  0.227528
>>> A_aligned.mul(b_aligned)
                              0         1         2
2021-08-14 11:14:00 0  0.035078  0.059694  0.015921
                    1  0.112877  0.138816  0.070104
                    2  0.012840  0.043426  0.039147
2021-08-14 11:15:00 0  0.142562  0.397457  0.361405
                    1  0.271504  0.182411  0.508149
                    2  0.226639  0.373254  0.563363
2021-08-14 11:16:00 0  0.008572  0.448457  0.034176
                    1  0.005848  0.252387  0.573175
                    2  0.000099  0.419070  0.541322
2021-08-14 11:17:00 0  0.877118  0.142770  0.247933
                    1  0.736438  0.364615  0.397589
                    2  0.784913  0.590785  0.750067
2021-08-14 11:18:00 0  0.418120  0.060292  0.108610
                    1  0.162505  0.367235  0.198722
                    2  0.192779  0.323083  0.051769

我只是猜测你真正在做什么,因为你没有指定轴等,但这给出了与你的代码相同的结果:

>>> A.mul(b.align(A, level=0)[0]).sum(axis='columns').unstack(1)
                            0         1         2
2021-08-14 11:14:00  0.110693  0.321797  0.095413
2021-08-14 11:15:00  0.901424  0.962065  1.163256
2021-08-14 11:16:00  0.491205  0.831409  0.960491
2021-08-14 11:17:00  1.267821  1.498642  2.125765
2021-08-14 11:18:00  0.587022  0.728462  0.567631