from pathlib import Path
from urllib.request import urlretrieve # 复用本章隐藏设置单元安装的浏览器标识下载器
# 按 Linux 共享数据、Windows 共享数据、项目缓存的顺序选择财务报表文件。
financial_path = next((candidate_path for candidate_path in [Path('/home/ubuntu/r2_data_mount/data/stock/financial_statement.h5'), Path('C:/qiufei/data/stock/financial_statement.h5'), Path('data/course/financial_statement.h5')] if candidate_path.exists()), Path('data/course/financial_statement.h5'))
if not financial_path.exists():
financial_path.parent.mkdir(parents=True, exist_ok=True)
urlretrieve('https://assets.qiufei.site/data/stock/financial_statement.h5', financial_path)
# 确定年度 Q4 行条件,使大型 HDF5 在读取前先按样本期过滤。
financial_quarters = [f'{year}q4' for year in range(2015, 2025)]
# 只读取公司、季度、披露日、五项解释字段与 EPS,控制大表内存占用。
financial_columns = ['order_book_id', 'quarter', 'info_date', 'total_assets', 'total_liabilities', 'operating_revenue', 'net_profit_parent_company', 'cash_from_operating_activities', 'basic_earnings_per_share']
# 从表式 HDF5 键同时选择年度行与必要列,数据获取与后续解释逻辑保持解耦。
financial_raw = pd.read_hdf(financial_path, key='financial_data', where='quarter in financial_quarters', columns=financial_columns)
# 统一披露日期类型,为版本选择与时间切分建立可复算时点。
financial_raw['info_date'] = pd.to_datetime(financial_raw['info_date'])
# 检查 HDF 行过滤只返回事先确定年度,防止季度口径静默漂移。
assert financial_raw['quarter'].isin(financial_quarters).all(), 'HDF 行筛选返回了事先确定范围外季度'
# 从季度字段提取财年,作为严格时间留出的分组变量。
financial_raw['fiscal_year'] = financial_raw['quarter'].str[:4].astype(int)
# 对公司—财年保留最后披露版本,避免同一报告修订重复进入样本。
financial_panel = financial_raw.sort_values(['order_book_id', 'fiscal_year', 'info_date']).drop_duplicates(['order_book_id', 'fiscal_year'], keep='last')
# 固定五项财务解释字段,避免把目标或披露后信息放进模型输入。
financial_features = ['total_assets', 'total_liabilities', 'operating_revenue', 'net_profit_parent_company', 'cash_from_operating_activities']
# 删除目标或输入缺失的记录,保持模型和 SHAP 使用完全相同的行。
financial_panel = financial_panel.dropna(subset=financial_features + ['basic_earnings_per_share']).copy()
# 提取公开财务特征矩阵,按亿元缩放只改善数值可读性而不改变树的排序。
X = financial_panel[financial_features].div(1e8)
# 提取同一已披露年度报告的 EPS 响应,明确本节是同期模型解释。
y = financial_panel['basic_earnings_per_share'].astype(float)
# 用 2015—2021 财年拟合候选模型,留出后续年份作解释检查。
X_train, y_train = X.loc[financial_panel['fiscal_year'].le(2021)], y.loc[financial_panel['fiscal_year'].le(2021)]
# 用 2022—2024 财年形成留出样本,不随机打乱公司—年份记录。
X_test, y_test = X.loc[financial_panel['fiscal_year'].ge(2022)], y.loc[financial_panel['fiscal_year'].ge(2022)]
# 快速浏览一下数据
print("特征数据 (X_train) 概览:")
# 将五项财务特征改用投影友好的短中文列名,只影响展示而不改变模型输入。
training_preview = X_train.head().rename(columns={'total_assets': '资产', 'total_liabilities': '负债', 'operating_revenue': '营收', 'net_profit_parent_company': '归母净利', 'cash_from_operating_activities': '经营现金流'})
# 展示短列名训练样本,核对五项指标及亿元口径。
display(training_preview)