如何在R中构建用于收益分位数分析的马尔可夫(Markov)转移矩阵
问题解答
一、平衡性处理建议
不需要一刀切仅保留连续10年及以上数据的ID,该操作反而会引入严重的幸存者偏差:能连续存续10年的投资者本身就是业绩稳定性、收益率表现更优的群体,计算出的转移概率会大幅高估业绩持续性,偏离全市场真实情况。
你提到的短周期ID带来100%转移概率的问题不存在:转移概率是全样本所有转移事件的频次占比,单个仅2年数据的ID仅贡献1条转移记录,不会对大样本下的统计结果产生干扰。
可参考以下样本筛选规则:
- 计算1年期转移矩阵:仅保留至少有连续2年有效数据的ID即可
- 计算2年期转移矩阵:仅保留至少有连续3年有效数据的ID即可
如果样本量极小担心极端值干扰,可将对应转移频次小于5的格子手动设为0或缺失值,常规金融样本量下无需额外处理。
二、代码实现(Python)
以下代码基于pandas实现,可直接输出符合要求的1年期、2年期转移矩阵,行对应初始分位,列对应转移后分位。
import pandas as pd import numpy as np # 1. 数据预处理 df = pd.read_csv("你的数据集文件路径.csv") # 处理收益列的逗号小数点(仅需用到分位列的话可跳过该步) df["Return"] = df["Return"].str.replace(",", ".").astype(float) # 按ID、年份排序保证时间序列正确 df = df.sort_values(by=["ID", "Year"]).reset_index(drop=True) full_quintile = [1,2,3,4,5] # 2. 计算1年期转移概率矩阵 # 生成每个ID的上一年分位 df["prev_quintile_1y"] = df.groupby("ID")["Quintile"].shift(1) # 过滤年份不连续的错位记录,避免ID缺少年份导致的转移错误 df["year_gap_1y"] = df.groupby("ID")["Year"].diff() trans_1y = df[(df["year_gap_1y"] == 1) & df["prev_quintile_1y"].notna()] trans_1y = trans_1y[["prev_quintile_1y", "Quintile"]].astype(int) # 频次转概率 count_1y = pd.crosstab(trans_1y["prev_quintile_1y"], trans_1y["Quintile"]) trans_matrix_1y = count_1y.div(count_1y.sum(axis=1), axis=0) # 补全1-5的行列,避免无转移记录的分位缺失 trans_matrix_1y = trans_matrix_1y.reindex(index=full_quintile, columns=full_quintile, fill_value=0) # 3. 计算2年期转移概率矩阵 df["prev_quintile_2y"] = df.groupby("ID")["Quintile"].shift(2) df["year_gap_2y"] = df.groupby("ID")["Year"].diff(2) trans_2y = df[(df["year_gap_2y"] == 2) & df["prev_quintile_2y"].notna()] trans_2y = trans_2y[["prev_quintile_2y", "Quintile"]].astype(int) count_2y = pd.crosstab(trans_2y["prev_quintile_2y"], trans_2y["Quintile"]) trans_matrix_2y = count_2y.div(count_2y.sum(axis=1), axis=0) trans_matrix_2y = trans_matrix_2y.reindex(index=full_quintile, columns=full_quintile, fill_value=0) # 输出结果,保留4位小数 print("1年期转移概率矩阵:") print(trans_matrix_1y.round(4)) print("\n2年期转移概率矩阵:") print(trans_matrix_2y.round(4))
内容的提问来源于stack exchange,提问作者PCRL
相关产品推荐
相关产品推荐

