资讯动态

基金相关性预测:多源时序+文本+行业特征融合建模

发布时间:2026/9/11 16:10:19 来源:尧图企业网站定制
简介本资源是面向高校机器学习课程学生的完整大作业解决方案基于CCF-BDCI基金相关性预测训练赛题设计覆盖从数据建模、代码实现到成果汇报的全流程特别适合课程设计、期末大作业及初学者快速上手。压缩包共5个文件681KB含核心Python训练脚本带详细注释、基金预测结果CSV数据、技术报告.docx、答辩PPT.pptx及项目说明文档.md类型互补、结构清晰便于理解算法逻辑、复现实验结果并完成成果展示。已有266人学习下载资源经实践验证为满分作业级方案不仅提供可直接部署运行的代码还包含问题分析思路、特征工程方法、模型调参过程及可视化呈现方式显著降低学习门槛助力学生高效完成高分课程任务。1. 这不是“预测基金涨跌”而是用多源时序特征建模资产关联强度——CCF-BDCI基金相关性赛题的完整复现路径很多同学拿到这个资源第一反应是“又一个股票预测项目”但实际打开ML18大作业报告-第5组-技术报告.docx和ML18大作业报告-第5组-代码实现.py后会发现它不预测价格也不做分类而是在构建一种可解释、可验证的资产间动态关联度量化模型。任务定义来自 CCF-BDCI 官方赛题给定若干只公募基金含股票型、混合型、指数型在连续 250 个交易日的日频净值数据、持仓披露文本季报摘要、行业配置权重申万一级行业占比预测任意两只基金在未来 5 日内的 Pearson 相关系数区间分 0–0.3 / 0.3–0.6 / 0.6–1.0 三档。这不是黑箱打分而是要求模型输出具备金融逻辑支撑——比如当两只基金同时大幅增持“电力设备”且减持“房地产”其相关性应显著上升。该方案最终在训练赛中进入 Top3见ML18-top3预测.csv代码含逐行中文注释README.md明确标注了 Python 3.8 scikit-learn 1.2.2 pandas 1.5.3 numpy 1.23.5 环境依赖且所有数据预处理、特征工程、模型训练、评估逻辑全部封装在单个.py文件中无外部服务调用本地 CPU 即可完成全流程复现。适合机器学习课程设计、期末大作业、金融方向课程实践尤其对“如何把非结构化文本结构化时序行业标签融合建模”这一高频需求提供可拆解范式。2. 从净值序列到关联强度基金相关性预测的三层特征工程设计原理与实现2.1 为什么不能直接用净值收益率计算相关性——任务本质与数据陷阱识别赛题明确要求“预测未来 5 日相关性”而非“用历史相关性做标签”。若直接用 t−5 到 t−1 日的收益率计算 Pearson 相关系数作为标签会导致严重的信息泄露——因为该值本身已包含未来 5 日窗口内部分信息如 t−1 日收益率即为未来窗口首日。官方 baseline 文档指出真实标签应基于 t1 到 t5 日的实际净值变化计算且需排除停牌、净值异常跳变单日涨跌幅 15%等无效样本。本项目在code_implementation.py第 127 行起定义了严格标签生成函数def generate_correlation_label(df_netvalue, fund_a, fund_b, future_days5): df_netvalue: pd.DataFrame, indexdate, columns[fund_id1, fund_id2, ...], valuesnav fund_a, fund_b: str, 基金代码 future_days: int, 预测窗口长度 返回: float, [0,1] 区间内 Pearson 相关系数或 np.nan若任一基金在窗口内缺失 ≥2 天数据 # 提取两基金未来5日净值序列需确保日期对齐 series_a df_netvalue[fund_a].loc[df_netvalue.index[-future_days]:] series_b df_netvalue[fund_b].loc[df_netvalue.index[-future_days]:] # 过滤无效值剔除 NaN、inf、单日涨跌幅 0.15 的点 valid_mask (~series_a.isna()) (~series_b.isna()) \ (abs(series_a.pct_change().fillna(0)) 0.15) \ (abs(series_b.pct_change().fillna(0)) 0.15) if valid_mask.sum() 3: # 至少需3个有效配对点才计算相关性 return np.nan corr series_a[valid_mask].corr(series_b[valid_mask]) return max(0.0, min(1.0, corr)) # 截断至[0,1]提示此函数必须在滚动窗口中调用如每滑动 1 天重新计算一次标签否则无法构建时序样本。项目在main()函数中通过for i in range(len(dates)-255):实现滑动确保每个样本的特征来自 t−250 到 t−6 日标签来自 t1 到 t5 日严格满足时间一致性。2.2 三层特征体系时序统计 文本语义 行业耦合的协同编码项目未采用端到端深度学习而是构建了可解释性强、计算开销低的三层手工特征对应技术报告中“特征工程”章节的三大模块特征类型具体内容计算逻辑维度关键作用时序层T收益率滚动统计、波动率、最大回撤、Beta相对沪深300、滚动相关性滞后窗口pd.Series.rolling(60).mean/std/min/maxstatsmodels.api.OLS拟合 Beta12捕捉基金自身风险收益特征及历史联动惯性文本层N季报持仓关键词 TF-IDF 加权向量、行业词共现矩阵、主题模型LDA主题分布sklearn.feature_extraction.text.TfidfVectorizer(max_features500)gensim.models.LdaModelk8512将“重仓宁德时代”“增持光伏”等非结构化描述转化为数值表征行业层I申万一级行业配置权重差值绝对值、行业集中度Herfindahl指数、共同持仓行业交集占比abs(weight_a - weight_b).sum()np.sum(weights**2)len(set(industry_a) set(industry_b)) / len(set(industry_a)set(industry_b))32特征拼接后总维度为 556远低于原始文本向量10k且每一维均有明确金融含义。例如T_Beta_diff两只基金 Beta 值之差若接近 0说明二者系统性风险暴露一致I_common_industry_ratio共同持仓行业占比0.7 时相关性预测值普遍高于 0.6。这种设计规避了纯黑箱模型在金融场景中的可信度危机。2.3 特征对齐与缺失值处理跨模态数据的时间戳统一策略最大难点在于三类数据的时间粒度不一致净值日频、季报季频每年 4 月/8月/10月发布、行业配置季频。项目采用“向前填充 时间映射”策略净值数据以交易日为索引天然对齐季报文本与行业权重将每份季报生效时间设为“报告期后第一个交易日”如 2023 年一季报于 4 月 22 日发布则从 4 月 23 日起生效并用pandas.DataFrame.asfreq(D, methodffill)向前填充至下一季报发布日特征生成时机仅在季报更新日及之后才用最新文本/行业特征参与建模。代码中通过if date in quarterly_update_dates:控制特征更新开关避免用未来信息污染历史样本。# 特征对齐核心逻辑code_implementation.py 第 321 行 quarterly_features {} # {date: {fund_id: feature_vector}} for q_date in sorted(quarterly_update_dates): # 加载该季报对应的文本TF-IDF和行业权重向量 tfidf_vec load_tfidf_vector(q_date, fund_list) industry_vec load_industry_vector(q_date, fund_list) # 合并为单只基金特征 for fund in fund_list: quarterly_features[q_date][fund] np.hstack([ tfidf_vec[fund], industry_vec[fund] ]) # 构建样本时查找距离当前date最近的quarterly_features[date] def get_quarterly_feature(date, fund_a, fund_b): valid_dates [d for d in quarterly_features.keys() if d date] if not valid_dates: return np.zeros(544) # 退回零向量 latest_q_date max(valid_dates) return np.hstack([ quarterly_features[latest_q_date][fund_a], quarterly_features[latest_q_date][fund_b] ])注意此策略导致季报特征在季度内保持不变符合现实——基金经理不会每日调整持仓季报是市场公认的风格锚点。强行插值反而引入噪声。3. 模型选型与集成策略XGBoost 为主干 LightGBM 为校准器的双阶段回归框架3.1 为何放弃深度学习——小样本、高解释性、强泛化性的三角约束技术报告第 3.2 节明确指出训练集仅含 12,843 对基金组合样本约 150 只基金两两组合远低于典型深度学习所需量级同时 CCF-BDCI 评审强调“模型决策可追溯”要求能回答“为何预测 A/B 基金相关性为 0.72”此外测试集包含大量未在训练中出现的新基金冷启动场景。在此约束下项目采用XGBoost 回归主模型 LightGBM 分位数校准器的双阶段架构Stage 1XGBoost以 556 维特征为输入直接回归预测未来 5 日 Pearson 相关系数连续值目标函数为reg:squarederror学习率 0.05树深度 6子样本率 0.8Stage 2LightGBM Quantile Regression用 XGBoost 输出值作为新特征之一叠加原始特征分别训练 0.1/0.5/0.9 分位数回归模型用于校准预测区间的置信度如输出 [0.58, 0.75] 而非单一值 0.67。该设计在code_implementation.py第 489 行起实现# Stage 1: XGBoost 主回归 xgb_model xgb.XGBRegressor( objectivereg:squarederror, learning_rate0.05, max_depth6, subsample0.8, colsample_bytree0.9, n_estimators300, random_state42 ) xgb_model.fit(X_train, y_train) # Stage 2: LightGBM 分位数校准以XGB预测值为额外特征 X_train_enhanced np.hstack([X_train, xgb_model.predict(X_train).reshape(-1,1)]) y_pred_xgb xgb_model.predict(X_test) X_test_enhanced np.hstack([X_test, y_pred_xgb.reshape(-1,1)]) # 训练三个分位数模型 quantile_models {} for alpha in [0.1, 0.5, 0.9]: lgb_quant lgb.LGBMRegressor( objectivequantile, alphaalpha, n_estimators100, learning_rate0.1, num_leaves31, random_state42 ) lgb_quant.fit(X_train_enhanced, y_train) quantile_models[alpha] lgb_quant # 最终预测取0.5分位数为点估计0.1/0.9为置信区间 y_pred_point quantile_models[0.5].predict(X_test_enhanced) y_pred_lower quantile_models[0.1].predict(X_test_enhanced) y_pred_upper quantile_models[0.9].predict(X_test_enhanced)逻辑说明XGBoost 擅长捕捉高阶交互如“当 T_volatility_a 0.02 且 I_common_industry_ratio 0.3 时相关性必然低于 0.4”而 LightGBM 分位数回归能校正其系统性偏差——实测显示 XGBoost 单独预测在 [0.6,0.8] 区间存在明显高估加入分位数校准后 MAE 从 0.127 降至 0.093。3.2 特征重要性分析验证金融逻辑是否被模型真正学习技术报告附录 B 展示了 XGBoost 的feature_importances_排序前 10 位如下已映射回原始特征名排名特征名权重金融含义解释1I_common_industry_ratio0.182共同持仓行业占比越高相关性越强符合投资常识2T_Beta_diff0.147Beta 差值越小系统性风险暴露越一致联动性越强3N_lda_topic_3_similarity0.093LDA 主题 3经人工标注为“新能源产业链”相似度反映风格趋同4T_rolling_corr_30d0.076过去 30 日滚动相关性体现历史惯性5I_herfindahl_diff0.068两只基金行业集中度差异差异越大越可能低相关这证明模型未陷入虚假相关如用基金名称字符串哈希值做特征而是聚焦于真实驱动因子。README.md中特别提醒若更换数据源需重新运行analyze_feature_importance.py未包含在 zip 中但技术报告第 4.1 节给出完整代码逻辑验证特征有效性。3.3 模型评估超越 RMSE 的多维验证协议项目未仅用 RMSE 评估而是执行 CCF-BDCI 官方指定的三重验证区间准确率Interval Accuracy预测区间[y_lower, y_upper]覆盖真实值的比例要求 ≥85%点估计 MAE预测点值与真实值绝对误差均值要求 ≤0.10分组一致性检验将预测值按 0.2 为间隔分 5 组0–0.2, 0.2–0.4…每组内真实值均值与预测均值偏差 ≤0.05。评估代码位于code_implementation.py第 621 行def evaluate_prediction(y_true, y_pred_point, y_pred_lower, y_pred_upper): # 区间覆盖率 interval_coverage np.mean((y_true y_pred_lower) (y_true y_pred_upper)) # 点估计MAE mae np.mean(np.abs(y_true - y_pred_point)) # 分组一致性按预测值分组 bins np.arange(0, 1.2, 0.2) group_errors [] for i in range(len(bins)-1): mask (y_pred_point bins[i]) (y_pred_point bins[i1]) if mask.sum() 0: pred_group_mean y_pred_point[mask].mean() true_group_mean y_true[mask].mean() group_errors.append(abs(pred_group_mean - true_group_mean)) group_consistency np.max(group_errors) if group_errors else np.inf return interval_coverage, mae, group_consistency # 输出结果示例技术报告 Table 4 # Interval Coverage: 0.892 | MAE: 0.093 | Max Group Error: 0.041参数说明bins划分依据是赛题要求的三档分类边界0.3/0.6此处细化为 5 组以增强鲁棒性group_consistency取最大偏差而非均值因评审关注最差分组表现。4. 本地部署与结果复现从解压到生成 Top3 预测 CSV 的四步实操指南4.1 环境准备与依赖安装精确匹配原始开发环境项目在README.md中声明依赖版本但未提供requirements.txt。为确保复现一致性需手动创建# 创建隔离环境推荐 conda conda create -n fund_corr python3.8 conda activate fund_corr # 安装指定版本注意scikit-learn 1.2.2 需 pip 安装conda 默认为 1.3 pip install pandas1.5.3 numpy1.23.5 scikit-learn1.2.2 pip install xgboost1.7.5 lightgbm3.3.5 pip install jieba0.42.1 gensim4.3.0 # 文本处理必需提示gensim4.3.0是关键——新版 LDA API 不兼容若用 4.3.2 会导致LdaModel初始化失败。jieba用于中文分词项目中对季报文本做“基金行业概念”三级词典增强见data_preprocess.py中custom_jieba_dict。4.2 数据目录结构与模拟数据生成原始 zip 包不含真实数据因版权限制仅含ML18-top3预测.csv样例输出。需自行构造最小可行数据集data/ ├── netvalue/ # 净值数据CSV列fund_id行date值nav │ ├── 000001.csv │ └── 000002.csv ├── reports/ # 季报文本TXT每份文件含持仓关键词如“宁德时代、隆基绿能、比亚迪” │ ├── 2023Q1_000001.txt │ └── 2023Q1_000002.txt └── industry_weights/ # 行业权重CSV列industry_name行fund_id值weight ├── 2023Q1_weights.csv项目提供generate_sample_data.py未打包但技术报告附录 C 给出伪代码可生成 10 只基金、250 日的模拟数据。核心逻辑是净值序列用np.random.normal(0, 0.01, 250).cumsum()生成基础走势再叠加行业因子如“电力设备”行业涨时重仓该行业的基金同步上扬季报文本从预设词库随机采样确保I_common_industry_ratio可控行业权重按申万一级行业 31 个类别生成总和为 1。4.3 执行训练与预测一条命令跑通全流程所有逻辑封装在ML18大作业报告-第5组-代码实现.py无需修改即可运行# 假设数据已放入 data/ 目录当前路径为 zip 解压根目录 python ML18大作业报告-第5组-代码实现.py \ --data_dir ./data \ --output_dir ./output \ --n_splits 5 \ --random_state 42参数说明--data_dir指向含netvalue/reports/industry_weights/的父目录--output_dir生成model.pklprediction.csvfeature_importance.png的位置--n_splitsTimeSeriesSplit 折数5 折保证时序不泄露--random_state确保结果可复现。运行后生成output/prediction.csv格式与ML18-top3预测.csv一致fund_a,fund_b,predicted_corr,true_corr可直接提交至 CCF-BDCI 训练赛平台。4.4 验证预测合理性用技术报告中的案例反向推演技术报告第 5.1 节给出典型案例基金 A代码 000001与基金 B代码 000002在 2023-06-01 的预测值为 0.723真实值为 0.718。可通过以下步骤验证查看output/feature_importance.png确认I_common_industry_ratio和N_lda_topic_3_similarity是否为前两位进入data/reports/2023Q2_000001.txt和2023Q2_000002.txt人工比对关键词重合度如均含“光伏”“储能”查data/industry_weights/2023Q2_weights.csv计算二者在“电力设备”“基础化工”行业的权重差值之和是否 0.1若以上均成立则预测值具有可解释性非随机噪声。注意ML18-top3预测.csv中的 Top3 结果并非全集而是按predicted_corr降序排列的前 1000 对组合用于答辩 PPT 中的可视化展示见ML18大作业报告-第5组-汇报PPT.pptx第 12 页热力图。5. 进阶技巧将基金相关性模型迁移至 ETF 或个股关联分析的三处关键改造点5.1 数据接口适配从公募基金到 ETF 的净值与持仓获取方式变更公募基金净值由托管行每日发布ETF 净值则需区分 IOPV盘中参考净值与收盘净值。项目中load_netvalue()函数需增加 ETF 专用解析def load_etf_netvalue(etf_code, start_date, end_date): 从聚宽JoinQuant或 Tushare 获取ETF收盘净值 注意ETF 季报持仓披露更频繁部分每月更新需调整 quarterly_update_dates 生成逻辑 # 示例使用 Tushare pro API需 token import tushare as ts ts.set_token(YOUR_TOKEN) pro ts.pro_api() df pro.fund_daily(ts_codef{etf_code}.SH, start_datestart_date, end_dateend_date) return df.set_index(trade_date)[nav].sort_index()关键改造点 1ETF 持仓更新频率更高quarterly_update_dates应改为monthly_update_dates且需处理“月度持仓 vs 季度持仓”的权重冲突——建议优先采用中证指数公司发布的 ETF 成分股清单权威性更高。5.2 特征维度压缩针对个股关联分析的行业标签替代方案若将任务扩展至“预测两只个股未来相关性”申万行业分类粒度太粗如“贵州茅台”与“五粮液”同属“食品饮料”但实际联动性受白酒政策影响更大。此时应替换I_common_industry_ratio为概念板块重合度使用同花顺 or 东方财富的概念分类如“白酒概念”“AI芯片概念”计算 Jaccard 相似度产业链上下游关系构建有向图若 A 是 B 的供应商如“赣锋锂业”→“宁德时代”则定义关联强度衰减因子舆情共现频率爬取股吧/雪球讨论帖统计两只股票在同一篇帖子中出现的次数。技术报告第 6.3 节提及在内部测试中用“概念共现”替代“行业权重”后对消费类个股的预测 MAE 降低 0.021但对周期股提升不明显说明需按板块定制特征。5.3 模型轻量化部署至 Flask Web 服务的内存与延迟优化原模型加载需 1.2sXGBoost 3 个 LightGBM对 Web 请求过长。可实施以下优化优化项实施方式效果模型序列化用joblib.dump(model, model.joblib)替代 pickle加载快 3×内存占用降 40%特征缓存对已计算的quarterly_features按日期哈希存储避免重复解析季报首次请求后后续同日请求特征生成耗时 10ms预测批处理Web 接口接收 JSON 数组[{fund_a:000001, fund_b:000002}, ...]一次性预测QPS 从 8 提升至 42app.py示例未包含在 zip但答辩 PPT 第 18 页有架构图from flask import Flask, request, jsonify import joblib import numpy as np app Flask(__name__) model joblib.load(output/model.joblib) feature_cache {} app.route(/predict, methods[POST]) def predict_batch(): data request.get_json() results [] for pair in data: # 特征生成含缓存逻辑 features get_cached_features(pair[fund_a], pair[fund_b], pair[date]) pred model.predict([features])[0] results.append({fund_a: pair[fund_a], fund_b: pair[fund_b], correlation: float(pred)}) return jsonify(results)最后一行技术细节get_cached_features()中使用functools.lru_cache(maxsize128)缓存最近 128 个日期-基金对组合平衡内存与速度。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价