如何用类似rolling().corr()的方式计算DataFrame的成对差值?
计算DataFrame的成对差值(匹配滚动相关性的输出格式)
先明确你的核心需求:想要得到和rolling(3).corr()完全一致的**多层索引(time + fsym)**格式的列间成对差值结果,对吧?
先还原你的原始DataFrame方便演示:
import pandas as pd # 构造示例数据 data = { 'EOS': [-0.051903, 0.026936, -0.034843, -0.108108, -0.048583], 'BTC': [-0.069088, 0.044739, -0.012935, -0.070375, 0.019509], 'BNB': [-0.058162, 0.040303, -0.005900, -0.028180, 0.131986] } pt = pd.DataFrame(data, index=pd.to_datetime(['2018-11-30', '2018-12-01', '2018-12-02', '2018-12-03', '2018-12-04'], utc=True))
方法1:高效广播法(推荐)
利用pandas的数组广播特性,可以快速生成符合要求的结果,代码简洁且性能优秀:
import pandas as pd # 获取列名列表 cols = pt.columns.tolist() # 通过广播计算所有列间差值:(时间数, 列数) → (时间数, 列数, 列数) diff_array = pt.values[:, :, None] - pt.values[:, None, :] # 构造和corr输出一致的多层索引 multi_idx = pd.MultiIndex.from_product([pt.index, cols], names=['time', 'fsym']) # 转换为目标格式的DataFrame pair_diff = pd.DataFrame(diff_array.reshape(-1, len(cols)), index=multi_idx, columns=cols)
运行后得到的结果结构和rolling(3).corr()完全对齐:
sym EOS BTC BNB time fsym 2018-11-30 00:00:00+00:00 EOS 0.000000 0.017185 0.006259 BTC -0.017185 0.000000 -0.010926 BNB -0.006259 0.010926 0.000000 2018-12-01 00:00:00+00:00 EOS 0.000000 -0.017803 -0.013367 BTC 0.017803 0.000000 0.004436 BNB 0.013367 -0.004436 0.000000 ...
方法2:手动遍历构造(更直观)
如果你想更清晰地理解每一步的逻辑,可以用遍历的方式实现:
import pandas as pd import itertools cols = pt.columns.tolist() # 生成所有列的两两组合 all_pairs = list(itertools.product(cols, cols)) result_frames = [] for date in pt.index: # 取出当前时间点的所有数据 current_row = pt.loc[date] # 计算每一对的差值 pair_values = {pair: current_row[pair[0]] - current_row[pair[1]] for pair in all_pairs} # 转换为临时DataFrame并调整索引 temp_df = pd.DataFrame(pair_values.values(), index=all_pairs, columns=[date]).T result_frames.append(temp_df) # 合并所有结果并调整索引层级 pair_diff = pd.concat(result_frames) pair_diff = pair_diff.stack().unstack(0).T.swaplevel().sort_index()
补充说明
你提到的“窗口大小为1的rolling窗口”理解完全正确——因为列间差值是基于单个时间点的计算,不需要跨时间窗口的聚合,只需要把每个时间点的列间差值整理成和corr()一致的多层索引格式即可。
内容的提问来源于stack exchange,提问作者Incompetent Perfectionist
相关产品推荐
相关产品推荐

