如何在分时段Fama-MacBeth回归中计算Newey-West调整t统计量
分时段Fama-MacBeth回归合并后Newey-West调整t值的计算方案
核心逻辑说明
分时段合并Fama-MacBeth结果时,正确路径是按各时段的样本量/回归期数加权平均系数,再基于全时段的系数序列计算Newey-West调整的协方差矩阵——Newey-West调整的是系数的标准误,而非系数本身,t值直接用「合并系数 ÷ Newey-West调整后的标准误」即可,你之前的误区是误以为参数需要调整。
方案一:基于statsmodels手动实现完整流程
步骤1:分时段执行横截面回归并保存系数序列
假设数据集已按日期拆分为df_pre(2023-05-31前,不含HML)和df_post(2023-05-31后,含HML),先逐期跑横截面回归,保存所有系数:
import pandas as pd import numpy as np import statsmodels.api as sm # 定义单期横截面回归函数 def run_cs_reg(df, formula): coeff_list = [] for date, group in df.groupby('date'): y = group['return'] # 替换为你的因变量列名 x_vars = formula.split('~')[1].split('+') X = sm.add_constant(group[x_vars]) model = sm.OLS(y, X).fit() coeff_list.append(pd.Series(model.params, name=date)) return pd.concat(coeff_list, axis=1).T # 分时段跑回归,输出系数时间序列 coeffs_pre = run_cs_reg(df_pre, 'return ~ MRT + SMB') coeffs_post = run_cs_reg(df_post, 'return ~ MRT + SMB + HML') # 对齐系数列:前时段补HML的0值 coeffs_pre['HML'] = 0.0 all_coeffs = pd.concat([coeffs_pre, coeffs_post])
步骤2:计算加权平均系数
优先用总观测数加权(比回归期数加权更精准,因为单期样本量可能差异大):
# 计算各时段总观测数 obs_pre = df_pre.groupby('date').size().sum() obs_post = df_post.groupby('date').size().sum() total_obs = obs_pre + obs_post # 加权平均系数 avg_coeffs = ( coeffs_pre.multiply(df_pre.groupby('date').size().values, axis=0).sum() + coeffs_post.multiply(df_post.groupby('date').size().values, axis=0).sum() ) / total_obs
步骤3:计算Newey-West调整的标准误与t值
用statsmodels的NeweyWest模块计算协方差矩阵,再推导标准误和t值:
from statsmodels.stats.sandwich_covariance import NeweyWest # 计算Newey-West协方差矩阵(滞后阶数按数据频率调整,月度数据建议选3) nw_cov = NeweyWest(all_coeffs.values, lag=3, prewhite=False) # 提取标准误(协方差矩阵对角线开平方) nw_se = np.sqrt(np.diag(nw_cov)) # 计算t值 t_values = avg_coeffs.values / nw_se # 整理结果表格 result_df = pd.DataFrame({ '系数': avg_coeffs.values, 'Newey-West标准误': nw_se, 't值': t_values }, index=avg_coeffs.index) print(result_df)
方案二:基于linearmodels分时段处理后合并
linearmodels原生支持Newey-West调整的Fama-MacBeth回归,可分时段跑回归后手动加权合并:
步骤1:分时段跑带Newey-West调整的回归
from linearmodels import FamaMacBeth # 转为linearmodels要求的Panel格式(替换为你的个体标识列) df_pre_panel = df_pre.set_index(['date', 'firm_id']) df_post_panel = df_post.set_index(['date', 'firm_id']) # 前时段回归(不含HML) model_pre = FamaMacBeth.from_formula( 'return ~ 1 + MRT + SMB', data=df_pre_panel, cov_type='kernel', kernel='bartlett', # Newey-West对应bartlett核 bandwidth=3 ) results_pre = model_pre.fit() # 后时段回归(含HML) model_post = FamaMacBeth.from_formula( 'return ~ 1 + MRT + SMB + HML', data=df_post_panel, cov_type='kernel', kernel='bartlett', bandwidth=3 ) results_post = model_post.fit()
步骤2:加权合并结果
# 补全前时段的HML系数与标准误 coeffs_pre = results_pre.params coeffs_pre['HML'] = 0.0 se_pre = results_pre.std_errors se_pre['HML'] = 0.0 # 用总观测数加权 weight_pre = results_pre.nobs_per_period.sum() weight_post = results_post.nobs_per_period.sum() total_weight = weight_pre + weight_post # 加权平均系数 avg_coeffs = (coeffs_pre * weight_pre + results_post.params * weight_post) / total_weight # 合并全时段系数序列,重新计算Newey-West协方差 all_period_coeffs = pd.concat([results_pre.params_per_period, results_post.params_per_period]) all_period_resids = pd.concat([results_pre.resids, results_post.resids]) from linearmodels.panel import kernel_covariance nw_cov_all = kernel_covariance( all_period_coeffs.values, all_period_resids.values.reshape(-1,1), kernel='bartlett', bandwidth=3 ) nw_se_all = np.sqrt(np.diag(nw_cov_all)) t_values_all = avg_coeffs.values / nw_se_all # 整理结果 result_df = pd.DataFrame({ '系数': avg_coeffs.values, 'Newey-West标准误': nw_se_all, 't值': t_values_all }, index=avg_coeffs.index) print(result_df)
关键注意点
- 加权选择:优先用总观测数加权,避免因单期样本量差异导致结果偏差。
- 滞后阶数:可按公式
int(4*(T/100)^(2/9))计算(T为总回归期数),月度数据一般选3-6,日度数据选5-10。 - 系数对齐:前时段缺失的HML系数必须补0,否则合并时会出现列不匹配问题。
内容的提问来源于stack exchange,提问作者Korvex91
相关产品推荐
相关产品推荐

