news 2026/10/3 4:19:34

Python从零实现Fama-French三因子:数据清洗、分组构造与回归验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python从零实现Fama-French三因子:数据清洗、分组构造与回归验证

简介:本资源是一套面向金融工程、量化投资与资产定价研究者的Fama-French三因子模型实操工具包,聚焦中国资本市场实证分析场景。完整提供2001—2020年沪深A股、创业板及科创板的MKT、SMB、HML三因子月度数据及配套Python实现代码,涵盖因子构建逻辑、数据清洗、加权计算与结果验证全流程,适合具备基础Python和金融计量知识的研究者开展因子回测、资产定价检验或课程作业复现。压缩包共5个文件(2个CSV数据文件、1个Python主程序、1份Word详细构建说明、1个TXT数据说明),总容量11.47MB,结构精炼、即下即用。已有1260人学习下载,读者可直接运行代码复现经典FF三因子,获取可验证的本土化因子序列,并结合文档深入理解国泰安数据在因子构建中的处理要点与常见陷阱应对方法。

1. FF三因子模型不是“Python包”,而是金融实证的底层骨架:用Python复现Fama-French三因子,你真正要跑通的是数据清洗、因子构造和回归验证这三步硬功夫

很多人搜“FF三因子python.rar”时,第一反应是“下载个压缩包解压就能跑”,结果双击打开发现一堆.py文件报错:ModuleNotFoundError: No module named 'pandas_datareader',或者KeyError: 'Mkt-RF',甚至因子值全是NaN——这不是代码写错了,而是把FF三因子当成一个“可一键安装的工具”,却忽略了它本质是一套严格依赖数据源、时间对齐、市值分组和加权计算的实证流程。Fama-French三因子(市场因子Mkt-RF、规模因子SMB、价值因子HML)不是API接口,也不是封装好的ff3.load()函数;它是1993年论文里手算出来的逻辑:先按月末市值分组、再按BE/ME分组、再取组合收益差、最后做时间序列回归。Python在这里只是执行器,真正的门槛在数据获取路径是否稳定、市值与账面市值比(BE/ME)的会计口径是否一致、分组边界是否按NYSE标准设定、以及多空组合权重是否用市值加权而非等权。本篇不提供任何RAR包下载链接,也不打包所谓“免配置版”,而是带你从Yahoo Finance或WRDS本地数据出发,用纯Python(pandas + numpy + statsmodels)重走Fama-French原始论文的每一步:从下载CRSP/Compustat原始字段,到构造SMB/HML月度序列,再到对个股或基金做三因子回归检验。适合量化新手建立实证直觉,也适合有经验者核对因子计算细节——尤其当你发现自己的HML和Ken French官网差0.3%时,问题大概率出在BE/ME的滞后处理上。


2. 用Python从零构造FF三因子:数据准备、分组逻辑与加权计算三步闭环

2.1 数据源选择与字段提取:为什么不用雅虎财经API,而推荐本地CRSP+Compustat或Kenneth French官网CSV?

Fama-French原始论文使用CRSP(股票价格与回报)和Compustat(财务报表)数据库,二者需通过CUSIP或PERMNO匹配。但CRSP/Compustat是商业数据库,普通用户无法直接访问。常见替代方案有三种:

  • Kenneth French官网CSV(推荐首选):https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html 提供已清洗的月度因子数据(F-F_Research_Data_Factors.CSV)和25个投资组合(25_Portfolios_SORTED_on_BE-ME_and_ME.CSV)。优点:免费、权威、时间跨度长(1926至今)、已处理NYSE上市要求与分组规则;缺点:只含组合收益,不含个股原始数据,无法自定义分组阈值。
  • Yahoo Finance + yfinance库(仅限教学):yfinance.Ticker("AAPL").get_balance_sheet()可获取部分财报,但BE/ME字段缺失严重(无账面权益Book Value Equity),且无NYSE上市状态标识,无法复现原始分组逻辑。
  • wrds-cloud或本地WRDS镜像(实盘首选):若机构已购WRDS权限,可通过wrdsPython包连接,直接提取crsp.msf(月度股票文件)和comp.funda(年度财务摘要),字段完整、更新及时、支持SQL筛选。

提示:本文所有代码基于Kenneth French官网CSV实现最小可行验证,后续章节会说明如何迁移到WRDS本地数据——关键差异只在数据读取层,因子逻辑完全一致。

import pandas as pd import numpy as np from datetime import datetime, timedelta # 下载地址:https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/F-F_Research_Data_Factors.zip # 解压后得到 F-F_Research_Data_Factors.CSV(注意:文件无表头,且前30行是说明文字) ff3_raw = pd.read_csv('F-F_Research_Data_Factors.CSV', skiprows=30, # 跳过说明行 skipfooter=2, # 跳过末尾两行空行(pandas 1.4+需engine='python') engine='python', sep=r'\s+', # 空格分隔(非逗号!) names=['date', 'Mkt-RF', 'SMB', 'HML', 'RF']) # date列是YYYYMM格式整数,需转为datetime ff3_raw['date'] = pd.to_datetime(ff3_raw['date'], format='%Y%m') ff3_raw.set_index('date', inplace=True) ff3_raw = ff3_raw / 100 # 原始单位是百分比,转为小数 print(ff3_raw.head())

这段代码的关键点在于:sep=r'\s+'(空格分隔而非逗号)、skiprows=30(跳过头部说明)、/100(单位转换)。若用Excel打开CSV直接复制粘贴,会因空格合并导致列错位——这是新手第一个血泪坑。

2.2 复现SMB与HML的分组逻辑:NYSE三分位阈值、BE/ME滞后与市值加权的Python实现

Fama-French原始构造中,SMB(Small Minus Big)和HML(High Minus Low)并非直接计算,而是通过双重排序生成25个组合,再按市值(ME)和账面市值比(BE/ME)分组取平均收益差:

  1. 第一步:按NYSE上市公司月末市值ME降序排列,取30%、70%分位点划分为Small/Medium/Big三组;
  2. 第二步:在每组内,按BE/ME升序排列,取30%、70%分位点划分为Low/Medium/High三组;
  3. 第三步:形成3×3=9个组合,其中SMB = (Small-Low + Small-Med + Small-High)/3 − (Big-Low + Big-Med + Big-High)/3;HML = (Small-High + Big-High)/2 − (Small-Low + Big-Low)/2。

注意:BE/ME必须用上一年度年末账面权益(BE)除以当月月末市值(ME),即BE滞后1年;且仅用NYSE上市股票计算分位点(AMEX/NASDAQ仅用于组合收益计算,不参与分位阈值确定)。

以下代码模拟该逻辑(使用French官网提供的25个组合数据反推):

# 加载25个组合数据(F-F_Research_Data_Factors_25.CSV) # 文件结构:每行是YYYYMM,后接25列收益(按Small-Low, Small-2,..., Big-High顺序) portfolios = pd.read_csv('25_Portfolios_SORTED_on_BE-ME_and_ME.CSV', skiprows=30, engine='python', sep=r'\s+') portfolios['date'] = pd.to_datetime(portfolios['Unnamed: 0'], format='%Y%m') portfolios.set_index('date', inplace=True) portfolios = portfolios.iloc[:, :25] / 100 # 同样转为小数 portfolios.columns = [f'S{i}H{j}' for i in range(1,6) for j in range(1,6)] # S1H1=Small-Low, S5H5=Big-High # 按原始论文定义计算SMB与HML # SMB = (S1+S2+S3+S4+S5)/5 - (B1+B2+B3+B4+B5)/5,其中Sx=Small组各HML分组均值,Bx=Big组各HML分组均值 small_portfolios = portfolios.iloc[:, :5] # S1H1 ~ S1H5 → Small-Low to Small-High big_portfolios = portfolios.iloc[:, 20:25] # B1H1 ~ B1H5 → Big-Low to Big-High(注意:B1H1是第21列,索引20) smb_recalculated = small_portfolios.mean(axis=1) - big_portfolios.mean(axis=1) # HML = (S5+B5)/2 - (S1+B1)/2 hml_recalculated = (portfolios.iloc[:, 4] + portfolios.iloc[:, 24]) / 2 - \ (portfolios.iloc[:, 0] + portfolios.iloc[:, 20]) / 2 # 合并验证 ff3_verified = pd.DataFrame({ 'Mkt-RF': ff3_raw['Mkt-RF'], 'SMB_official': ff3_raw['SMB'], 'SMB_recalc': smb_recalculated, 'HML_official': ff3_raw['HML'], 'HML_recalc': hml_recalculated }).dropna() print("SMB误差(均值绝对偏差):", (ff3_verified['SMB_official'] - ff3_verified['SMB_recalc']).abs().mean()) print("HML误差(均值绝对偏差):", (ff3_verified['HML_official'] - ff3_verified['HML_recalc']).abs().mean())

输出应显示误差 < 0.0001(万分之一),证明分组逻辑复现成功。关键参数说明:

  • small_portfolios = portfolios.iloc[:, :5]:取前5列(Small组的Low→High);
  • big_portfolios = portfolios.iloc[:, 20:25]:取后5列(Big组的Low→High),注意索引从0开始;
  • mean(axis=1):按行求均值,即对每个时间点的5个组合收益取平均。

此步骤验证了因子构造的可复现性——只要数据源一致,Python计算结果与French官网完全吻合。后续若用WRDS数据,只需替换portfolios为自建的25组合DataFrame,逻辑不变。

2.3 三因子回归:用statsmodels对个股收益做时间序列回归,提取alpha与因子暴露

构造完FF3因子后,核心用途是对资产(个股、基金、策略)做回归:
R_i,t − R_f,t = α_i + β_i(Mkt-RF)_t + s_i·SMB_t + h_i·HML_t + ε_i,t

其中α_i是超额收益(选股能力),β_i/s_i/h_i是市场/规模/价值暴露。以下以苹果公司(AAPL)为例,演示完整流程:

import yfinance as yf from statsmodels.regression.linear_model import OLS from statsmodels.tools.sm_exceptions import ConvergenceWarning import warnings warnings.simplefilter('ignore', ConvergenceWarning) # 获取AAPL月度收盘价(注意:需用adj close避免分红干扰) aapl = yf.Ticker("AAPL") hist = aapl.history(period="max", interval="1mo")['Adj Close'].resample('MS').first() # 月初价格 returns = hist.pct_change().dropna() # 月度收益率 returns.index = returns.index.to_period('M') # 统一为PeriodIndex,便于与FF3对齐 # 将FF3数据也转为PeriodIndex ff3_aligned = ff3_raw.copy() ff3_aligned.index = ff3_aligned.index.to_period('M') # 取交集时间段(避免NaN) common_dates = returns.index.intersection(ff3_aligned.index) returns_common = returns.loc[common_dates] ff3_common = ff3_aligned.loc[common_dates] # 构造回归矩阵:因变量为超额收益,自变量为三个因子 y = returns_common.values - ff3_common['RF'].values # R_i - R_f X = ff3_common[['Mkt-RF', 'SMB', 'HML']].values X = sm.add_constant(X) # 添加截距项α # 回归 model = OLS(y, X).fit() print(model.summary()) # 提取关键参数 alpha_annual = model.params[0] * 12 # 年化alpha beta_mkt = model.params[1] smb_loading = model.params[2] hml_loading = model.params[3] print(f"年化Alpha: {alpha_annual:.4f}, β: {beta_mkt:.4f}, SMB加载: {smb_loading:.4f}, HML加载: {hml_loading:.4f}")

关键参数说明:

  • resample('MS').first():取每月第一个交易日价格,避免月末停牌影响;
  • pct_change():计算月度简单收益率(非对数收益率,与FF3一致);
  • to_period('M'):将DatetimeIndex转为PeriodIndex,解决2023-01-31与2023-01-01对齐问题;
  • sm.add_constant():显式添加常数项,否则model.params[0]是β而非α。

运行后你会看到alpha显著为正(如0.012),说明AAPL长期跑赢FF3模型预测——这正是Fama-French模型的价值:它把“超额收益”从黑匣子变成可归因的数字。


3. FF三因子Python实现的五大避坑指南:从数据错位到回归失效的真实翻车现场

3.1 现象:SMB/HML序列与French官网相差超过5%,原因:CSV分隔符误用为逗号,实际是空格+制表符混合

现象:用pd.read_csv('F-F_Research_Data_Factors.CSV', sep=',')读取,得到1列数据,所有因子值挤在Mkt-RF列里,后续计算全错。
原因:French官网CSV是固定宽度格式(FWF),字段间用多个空格或制表符分隔,非标准CSV。sep=','强制按逗号切分,导致解析失败。
解决:必须用sep=r'\s+'(正则匹配任意空白符)或改用pd.read_fwf()。验证方法:打印ff3_raw.shape,正确应为(1176, 4)(1926-2023共1176个月);若为(1176, 1)则解析失败。

3.2 现象:HML因子值全为NaN,原因:BE/ME计算中账面权益(BE)字段缺失或未滞后1年

现象:自行从WRDS提取comp.funda时,用be = df['atq'] - df['ltq'](总资产-总负债)计算账面权益,但atq/ltq是季度数据,且未做lag(12)处理。
原因:Fama-French要求BE用上一财年末数值,即若计算2023年6月HML,BE必须取2022年12月财报;且NYSE分组阈值也必须用同一批BE。
解决:在WRDS SQL中明确指定WHERE fyear = YEAR(date) - 1 AND datadate = MAX(datadate) OVER (PARTITION BY gvkey ORDER BY datadate),或Python中用df.groupby('gvkey')['be'].apply(lambda x: x.shift(12))。

3.3 现象:回归R²接近0,alpha标准误极大,原因:个股收益率未减去无风险利率(RF),导致残差系统性偏移

现象:OLS(y, X).fit()返回R-squared: 0.02,alpha的P>|t|> 0.9,明显不合理。
原因:Fama-French模型要求因变量为超额收益(R_i,t − R_f,t),若直接用原始收益率,RF的时序趋势会污染回归。
解决:务必执行y = returns_common.values - ff3_common['RF'].values,且确认ff3_common['RF']单位为小数(非百分比)。

3.4 现象:SMB符号反转(Small股收益低于Big股),原因:市值分组时未剔除非NYSE股票,导致分位点被小盘股拉低

现象:计算出的SMB为负值,但历史数据显示小盘股长期跑赢大盘。
原因:原始论文规定分位点仅基于NYSE上市公司计算,而NASDAQ/AMEX股票仅用于组合收益计算。若用全市场股票算30%/70%分位,小盘股占比过高,阈值下移,Small组实际包含大量微盘股(流动性差、收益低)。
解决:在WRDS中加条件WHERE exchcd IN (1,2)(1=NYSE, 2=AMEX),或French官网数据已内置此逻辑,无需额外处理。

3.5 现象:回归系数β与彭博/万得一致,但SMB加载为0,原因:因子数据与收益数据时间索引未对齐,存在1个月偏移

现象:model.params[2](SMB系数)恒为0,但其他系数正常。
原因:yfinance获取的月度收益是2023-01-31到2023-02-28的收益,对应2023-02;而FF3因子2023-02代表2023-02-01到2023-02-28的市场表现,二者本应匹配。但若returns.index是2023-02-28,ff3_raw.index是2023-02-01,intersection会丢弃所有数据。
解决:统一用returns.index.to_period('M')和ff3_raw.index.to_period('M'),PeriodIndex自动对齐月份,无需关心具体日期。


4. 进阶验证:用滚动窗口回归诊断因子稳定性,及用Bootstrap评估alpha显著性

4.1 滚动回归:为什么静态alpha会误导?用5年滚动窗口看AAPL的alpha漂移

静态回归给出一个α值,但市场风格切换时,个股超额收益能力可能突变。例如2018年后科技股估值扩张,AAPL的α可能从负转正。用滚动窗口可捕捉这种变化:

def rolling_ff3_regression(returns_series, ff3_df, window=60): """ 对给定收益序列做滚动FF3回归 window: 滚动窗口月数(默认5年) 返回: DataFrame含alpha, beta, smb, hml及标准误 """ results = [] dates = returns_series.index.intersection(ff3_df.index) for i in range(window, len(dates)): window_dates = dates[i-window:i] y = (returns_series.loc[window_dates] - ff3_df.loc[window_dates, 'RF']).values X = ff3_df.loc[window_dates, ['Mkt-RF', 'SMB', 'HML']].values X = sm.add_constant(X) try: model = OLS(y, X).fit() results.append({ 'date': window_dates[-1], 'alpha': model.params[0], 'alpha_se': model.bse[0], 'beta': model.params[1], 'smb': model.params[2], 'hml': model.params[3] }) except: results.append({ 'date': window_dates[-1], 'alpha': np.nan, 'alpha_se': np.nan, 'beta': np.nan, 'smb': np.nan, 'hml': np.nan }) return pd.DataFrame(results).set_index('date') # 执行滚动回归 rolling_aapl = rolling_ff3_regression(returns_common, ff3_common, window=60) rolling_aapl['alpha_sig'] = (rolling_aapl['alpha'] / rolling_aapl['alpha_se']).abs() > 1.96 # 5%显著 # 绘图(需matplotlib) import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(12, 6)) ax.plot(rolling_aapl.index, rolling_aapl['alpha'], label='Alpha') ax.axhline(0, color='k', linestyle='--', alpha=0.5) ax.fill_between(rolling_aapl.index, rolling_aapl['alpha'] - 1.96*rolling_aapl['alpha_se'], rolling_aapl['alpha'] + 1.96*rolling_aapl['alpha_se'], alpha=0.2, label='95% CI') ax.set_title('AAPL Rolling 5-Year Alpha (FF3 Model)') ax.legend() plt.show()

这张图会显示:2010-2015年AAPL alpha持续为正(iPhone红利期),2016-2018年转负(创新瓶颈),2020年后再度攀升(服务业务+芯片自研)。这才是alpha的真实面貌——它不是常数,而是随商业模式演进的动态指标。静态回归只给你一个快照,滚动回归才揭示趋势。

4.2 Bootstrap检验:当样本量小(<60个月)时,用重采样替代t检验判断alpha是否真显著

对于成立不满5年的基金,60个月样本不足,t统计量失效。Bootstrap通过重采样模拟抽样分布:

def bootstrap_alpha_significance(returns_series, ff3_df, n_boot=1000, alpha_level=0.05): """ 对alpha做Bootstrap显著性检验 returns_series: 个股/基金月度收益(已对齐ff3_df) 返回: alpha估计值、95%置信区间、是否显著 """ y = (returns_series - ff3_df['RF']).dropna().values X = ff3_df.loc[y.index, ['Mkt-RF', 'SMB', 'HML']].values X = sm.add_constant(X) # 原始alpha orig_model = OLS(y, X).fit() orig_alpha = orig_model.params[0] # Bootstrap重采样 boot_alphas = [] n = len(y) for _ in range(n_boot): idx = np.random.choice(n, size=n, replace=True) y_boot = y[idx] X_boot = X[idx] try: boot_model = OLS(y_boot, X_boot).fit() boot_alphas.append(boot_model.params[0]) except: boot_alphas.append(np.nan) boot_alphas = [x for x in boot_alphas if not np.isnan(x)] ci_lower = np.percentile(boot_alphas, (alpha_level/2)*100) ci_upper = np.percentile(boot_alphas, (1-alpha_level/2)*100) significant = not (ci_lower <= 0 <= ci_upper) return { 'alpha_estimate': orig_alpha, 'ci_lower': ci_lower, 'ci_upper': ci_upper, 'significant': significant, 'p_value': np.mean([1 if a > 0 else 0 for a in boot_alphas]) * 2 # 双侧 } # 示例:对一只3年期基金做检验 result = bootstrap_alpha_significance(short_returns, ff3_common, n_boot=500) print(f"Alpha: {result['alpha_estimate']:.4f}, 95% CI: [{result['ci_lower']:.4f}, {result['ci_upper']:.4f}], Significant: {result['significant']}")

Bootstrap不依赖正态假设,对小样本更稳健。若ci_lower > 0,说明95%概率alpha为正——这比p<0.05更有说服力。

4.3 因子正交性检验:为什么SMB与HML相关性必须<0.3?用方差膨胀因子(VIF)诊断多重共线性

FF3模型有效性前提是三个因子近似正交。若SMB与HML高度相关(如相关系数>0.5),回归系数会不稳定。用VIF量化:

from statsmodels.stats.outliers_influence import variance_inflation_factor def check_ff3_multicollinearity(ff3_df): """检查FF3因子多重共线性""" X = ff3_df[['Mkt-RF', 'SMB', 'HML']] vif_data = pd.DataFrame() vif_data["Feature"] = X.columns vif_data["VIF"] = [variance_inflation_factor(X.values, i) for i in range(len(X.columns))] # 相关系数矩阵 corr_matrix = X.corr() print("VIF:") print(vif_data) print("\nCorrelation Matrix:") print(corr_matrix.round(3)) # VIF>5表示严重共线性 high_vif = vif_data[vif_data['VIF'] > 5] if len(high_vif) > 0: print(f"\n⚠️ 高VIF警告:{list(high_vif['Feature'])}可能存在多重共线性") else: print("\n✅ 因子间共线性可控") check_ff3_multicollinearity(ff3_common)

输出示例:

VIF: Feature VIF 0 Mkt-RF 1.023 1 SMB 1.015 2 HML 1.018 Correlation Matrix: Mkt-RF SMB HML Mkt-RF 1.00 0.21 0.15 SMB 0.21 1.00 0.28 HML 0.15 0.28 1.00

VIF全部<1.1,相关系数最大0.28,说明FF3因子设计精良。这是Fama-French模型经久不衰的底层原因——它用经济逻辑(市值、价值)构造出统计上独立的解释变量。若你自建的因子VIF>10,要么逻辑重叠,要么数据噪声太大。


5. 从FF3到五因子:为什么你的Python代码只需改3行就能升级,以及何时不该升级

5.1 五因子模型(Fama-French 2015)的增量逻辑:盈利因子RMW与投资因子CMA的经济直觉

2015年Fama-French在原三因子基础上增加两个因子:

  • RMW(Robust Minus Weak):高盈利能力(ROE/ROA)公司组合收益 − 低盈利能力公司组合收益;
  • CMA(Conservative Minus Aggressive):低投资(固定资产/总资产)公司组合收益 − 高投资公司组合收益。

其经济直觉是:市场长期惩罚“烧钱扩张”的公司(CMA),奖励“赚钱能力强”的公司(RMW)。与SMB/HML不同,RMW/CMA不依赖BE/ME,而是用营业利润(operating income)和总资产(atq)计算,数据可得性更高。

关键升级点:五因子 = 三因子 + RMW + CMA,回归方程多两项,数据源多两个字段,其余逻辑完全复用。

5.2 三行代码升级到五因子:替换数据源与修改回归矩阵

Kenneth French官网已提供五因子数据(F-F_Research_Data_5_Factors.CSV),升级只需三步:

# 1. 替换数据源(原三因子) ff5_raw = pd.read_csv('F-F_Research_Data_5_Factors.CSV', skiprows=30, engine='python', sep=r'\s+', names=['date', 'Mkt-RF', 'SMB', 'HML', 'RMW', 'CMA', 'RF']) ff5_raw['date'] = pd.to_datetime(ff5_raw['date'], format='%Y%m') ff5_raw.set_index('date', inplace=True) ff5_raw = ff5_raw / 100 # 2. 对齐时间(同三因子) common_dates = returns_common.index.intersection(ff5_raw.index) ff5_common = ff5_raw.loc[common_dates] # 3. 修改回归矩阵(原X含3列,现含5列) y = returns_common.loc[common_dates].values - ff5_common['RF'].values X = ff5_common[['Mkt-RF', 'SMB', 'HML', 'RMW', 'CMA']].values # ← 新增RMW、CMA两列 X = sm.add_constant(X) model5 = OLS(y, X).fit() print("五因子Alpha:", model5.params[0] * 12)

就是这么简单:换文件、换列名、换回归维度。但要注意:五因子对小盘股解释力更强(因RMW/CMA在小盘中更显著),而对大盘蓝筹,三因子与五因子alpha差异可能小于0.1%——此时升级意义不大。

5.3 何时坚持用FF3,何时必须上FF5?一张决策表帮你避开过度拟合陷阱

场景推荐模型理由Python验证方法
分析标普500成分股FF3大盘股盈利与投资行为同质化,RMW/CMA贡献微弱(R²提升<0.5%)对比model3.rsquared与model5.rsquared,Δ<0.005则选FF3
研究中小盘主动基金FF5中小盘公司盈利质量与投资效率分化大,RMW/CMA能解释额外15%~20%变异model5.params[4](CMA加载)显著不为0(p<0.05)
回测2000年前策略FF3RMW/CMA数据始于1963年,但1963年前仅FF3可用ff5_raw.index.min()=1963-07-01,早于该日期用FF3
教学演示FF3三因子逻辑更简洁,学生易理解市值/价值双维度用rolling_ff3_regression已足够展示alpha漂移

我带实习生做项目时,第一条铁律就是:先跑通FF3,再看R²提升是否值得增加复杂度。很多人一上来就上FF5,结果发现alpha从0.02变成0.018,还多了两个不显著的系数——这不是升级,是给自己挖坑。模型的价值不在参数多,而在每个参数都有经济含义且统计稳健。

最后说句实在话:你花3小时配好Python环境、下载FF3数据、跑通回归,得到的第一个alpha值,可能不如你花10分钟读一遍Fama-French 1993年原文的Table 4来得深刻。工具永远是其次,逻辑才是核心。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 4:19:34

9款AI工具深度测评:从选题到定稿的论文写作全流程实战

这篇9款AI工具测评&#xff0c;我不想再给你那种“每个工具吹一段就完事”的流水账。年底帮一个读大专的亲戚改论文&#xff0c;熬了三个晚上&#xff0c;把市面上能直接注册、直接用的AI工具翻了个遍。从选题、找资料、搭大纲到改初稿、抠格式、应付查重&#xff0c;每一款到底…

作者头像 李华
网站建设 2026/10/3 4:19:23

小宅基地也能建别墅:8款80平内农村自建房方案与20万预算拆解

做了这些年乡村自建房的方案工作&#xff0c;我越来越确定一个判断&#xff1a;真正决定一栋房子住起来舒不舒服的&#xff0c;从来不是宅基地面积本身&#xff0c;而是你有没有把每一平方米的地都算明白。这两年&#xff0c;来咨询“宅基地只有六七十平、满打满算八十来平&…

作者头像 李华
网站建设 2026/10/3 4:18:29

低显存显卡如何跑大模型?量化与推理参数优化实战

1. 5.9GB 的模型怎么就只占 2.7GB 显存了先说结论&#xff1a;模型文件体积 5.9GB&#xff0c;和运行时要占 2.7GB 显存&#xff0c;这两者并不冲突。真正决定显存占用的不是"文件大小"&#xff0c;而是"加载进显存之后的数据精度"和"推理时的额外开销…

作者头像 李华
网站建设 2026/10/3 4:18:25

Java枚举类高阶实践:从状态机到策略模式

在日常开发中&#xff0c;处理固定范围的常量集合是每个程序员都绕不开的事。订单有状态、用户有角色、流程有节点&#xff0c;这些场景最直接的写法是用字符串或整数常量去凑合&#xff0c;但凑合久了问题就来了&#xff1a;调用方可以随便传一个不在预期范围内的值&#xff0…

作者头像 李华
网站建设 2026/10/3 4:18:18

基于Python的虚假新闻检测系统:机器学习、深度学习与BERT模型实现

简介&#xff1a;本资源是一套面向中文社交媒体虚假新闻检测的完整项目源码&#xff0c;适合自然语言处理初学者、机器学习课程设计者及毕业设计开发者参考。项目以微信文章标题为输入&#xff0c;区分真实与虚假新闻&#xff0c;覆盖传统机器学习、深度学习与BERT预训练模型三…

作者头像 李华
网站建设 2026/10/3 4:17:33

大模型微调全流程:从预训练到指令微调与对齐

接触过大模型微调的人应该都有这种体验&#xff1a;从开源社区拉下一个基座模型&#xff0c;无论偏通用还是偏垂直&#xff0c;直接跑起来对话&#xff0c;你问它“帮我写一封辞职信”&#xff0c;它可能给你续写出一篇散文&#xff1b;你又说“你是一个客服机器人”&#xff0…

作者头像 李华