ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

金融机器学习练习实践:从三重障碍到特征重要度的代码实现与踩坑记录

金融机器学习练习实践:从三重障碍到特征重要度的代码实现与踩坑记录 简介精选《金融机器学习进展》一书中的实验性练习解答面向希望把书中策略与模型落地为可运行代码的量化研究者、数据科学家和金融工程学习者。资源以交互式笔记本和脚本为主体覆盖标签与元标签、金融交叉验证、样本权重、分数差分特征、成交量柱状图以及第四章练习等核心主题帮助读者在真实数据环境中复现书中实验理解止损、样本权重和交叉验证等技术难点。压缩包共43个文件包含18个Python脚本、6个Notebook笔记、3个文档另有构建脚本、配置、说明和图片等整体仅2.8MB目录层次分明源码目录下的两个模块可直接复用。目前已有314人学习下载适合具有一定机器学习基础并希望按章节逐步演练、深化金融建模能力的进阶读者。 第一次翻开 Marcos Lopez de Prado 那本《金融机器学习进展》时我读得挺快前六章的公式和概念都觉得懂了。直到有朋友问我分数差分到底解决什么问题为什么不能直接用一阶差分我嘴上讲着要保留记忆性、又得保证平稳性手却完全不知道这段逻辑该写成什么样的代码。那次卡壳让我意识到读这种密度很高的专业书光靠看和划线是不够的。书里到处是简写后的数学表达、算法伪代码落到真实的时间序列数据上时各种边界条件会直接把人打回原形。为了不让自己继续停留在读过的状态我把书里那些练习挑出来逐个用代码实现建了一个叫Adv_Fin_ML_Exercises的仓库专门存放这些实验性解法。这篇博客就聊聊这个仓库背后的思路、我踩过的几个比较大的坑以及解这些金融机器学习练习到底能带来什么。1. 为什么把这个实验性练习库单独当成一个项目来维护1.1 阅读闭环里有个断点只能靠动手补齐金融机器学习这个交叉领域很有意思它一边是金融数据的特殊结构——非独立同分布、信噪比极低、标签经常不明确另一边是机器学习方法论里那些默认样本独立的漂亮假设。书里把这些矛盾讲得特别清楚但清楚归清楚真正动手时你才会发现原来自己连一个标签到底应该怎么生成都没想明白。书中的大部分章节末尾都配有练习这些练习不是那种验证你记住了公式的题而是让你自己去实现一个方法、复现一个结论、或者对比几种方案的差异。我一开始也想偷懒去网上找现成的答案。后来发现这类练习的答案从来都只有一个方向没有标准实现因为金融数据本身没有标准形状不同市场、不同频率、不同质量的数据会让同一个算法表现出完全不同的行为。所以我把练习当成项目来维护而不是当成作业去完成。每道题都是一个小的实验单元先写实现再构造数据验证最后把整个过程记录下来。这样做的收益是——以后再有人问我书里某个概念到底怎么落地我可以直接打开仓库里的代码一行行讲给他听。1.2 实验性这三个字是我给自己留的安全区这个仓库名字里带着 Experimental Solutions实验性解法不是我谦虚是我真的认为这些解法不值得被当作权威答案。原因很简单同一个练习我换一种数据生成方式可能就会得到不同的最优参数换一种索引对齐方式也可能出现完全不同的实验结果。给自己留出实验的余地最大的好处是心理上的我不再追求一次做对而是允许自己在探索中犯错、改错、记录错。这个心态对金融机器学习特别重要因为很多方法本身就是在有偏估计和方差控制之间反复权衡没有绝对正确只有相对更合适。基于这个定位我搭了一个很轻量但也足够清晰的目录结构Adv_Fin_ML_Exercises/ ├── data/ # 生成的模拟数据尽量可复现 ├── notebooks/ # 每个练习一个 notebook步骤完整 ├── utils/ # 跨练习复用的工具函数 ├── reports/ # 练习结论和实验记录markdown 形式 └── tests/ # 用极端数据写的小型校验这套结构没什么高深的就是想把代码和结论分开。代码只是实现结论才是练习真正想让你体会的东西。2. 精选练习覆盖的知识地图以及我刻意没碰的部分2.1 从标签到交叉验证练习主线其实很连贯书的主体内容可以粗略划成几个技术域。我在收集练习时也是按这张图来控制的技术域核心问题练习题要解决的事标签体系金融数据没有现成的因变量用三重障碍等方法生成可用于训练的目标样本权重事件重叠让样本不再独立计算唯一性、重叠度、时间衰减权重分数差分价格序列既要不平稳又要可训练实现分数差分并折中记忆性和平稳性特征重要度非线性模型里怎么衡量特征贡献对比 MDI、MDA、SFI 三种方法的差异交叉验证普通 K-Fold 在时间序列上等于泄漏设计并发事件的切分策略验证 CPCV 等方案这些主题不是孤立的。标签决定了模型要拟合什么样本权重决定了哪些样本更值得模型关注分数差分决定了喂给模型的特征是不是干净的特征重要度帮你理解模型内部逻辑交叉验证则保证你评估模型时不是在自欺欺人。整套练习做下来就像是替自己把特征—标签—训练—验证这条完整链路重新铺设了一遍。单看每一个练习难度并不高但它们串在一起以后你对整本书的理解会明显厚一层。比如说你单独看三重障碍法会以为那只是一个止盈止损的标记技巧可等做到样本权重那节你会突然意识到这些标签背后的事件重叠问题直接决定了你的训练集到底有多少独立信息。2.2 哪些章节我没有收进仓库以及为什么书后面的内容有一部分——比如高频数据、分布式计算、端到端的回测框架——我没有收进练习库。不是说那部分不重要而是那些主题的练习一旦做起来工程量会迅速膨胀动辄要写一个能处理海量 tick 数据的回测引擎这已经超出了一道练习题的范畴。我更愿意把重心放在概念密度最高、也最容易出错的中间部分数据标注、样本权重、特征处理、交叉验证。这些模块是所有金融机器学习应用的地基地基如果理解歪了后面盖什么都悬。而且这部分练习的数据需求很小用模拟数据就能完成非常适合个人项目级别去研究和记录。3. 几道练完对我认知冲击很大的练习3.1 三重障碍标注画线以外还有时间管理书里讲金融数据标注那部分有个特别基础的操作给每一条样本打标签不是简单看未来是涨是跌而是设置三层障碍——一个垂直障碍代表最长持有期限两个水平障碍分别代表止盈线和止损线。多空哪条障碍先触发就按照对应方向给样本打上 1 或 -1如果持有到期还没有碰到任何水平障碍就标记为 0。听起来很直观对吧真上手做才发现至少有三处细节会影响最终标签分布。第一水平障碍是按收益率还是按价格百分比设置结果完全不同。第二垂直障碍到底按固定时间窗口还是按波动率调整后的动态窗口会直接改变样本里 0 标签的比例。第三也是最容易忽略的两段事件之间的重叠如何处理。我最初的实现很简单逐条样本往后扫窗口谁先触发就标谁。结果在测试时发现当数据里有缺失交易日时事件窗口会被拉长导致标签整体偏移。后来改成对每一条事件单独计算障碍触发的时间点并显式处理缺口数据结果才稳定下来。def triple_barrier_label(close, event_idx, pt_sl, max_hold): start close.loc[event_idx] window close.loc[event_idx:] if len(window) max_hold 1: window window.iloc[:max_hold 1] returns window / start - 1.0 first_profit returns[returns pt_sl[0]].index.min() first_loss returns[returns -pt_sl[1]].index.min() if pd.notna(first_profit) and pd.isna(first_loss): return 1, first_profit if pd.notna(first_loss) and pd.isna(first_profit): return -1, first_loss if pd.notna(first_profit) and pd.notna(first_loss): return 1 if first_profit first_loss else -1 return 0, window.index[-1]这段代码本身不复杂但它把金融事件和机器学习分类之间的边界给打通了。你会发现机器学习真正学习的不是涨跌而是在某种退场机制下哪些路径最终止盈、哪些路径最终止损。3.2 样本权重中的重叠与时间衰减做样本权重练习之前我对样本权重的理解停留在 class_weight 这种层间加权上。书里那套通过重叠度降权的思路直接把我对样本独立性的认知刷新了。在事件法标注下多个标签对应的时间区间可能互相重叠。比如第 1 天产生的样本覆盖到第 10 天第 3 天产生的样本也会覆盖到第 10 天。两个样本共享了一段行情它们就不是独立的。如果直接把这些样本丢进模型训练相当于给重叠的行情信息暗暗加了权模型会不知不觉过拟合到那段时间的特殊结构上。书里给的解法是计算每个事件的平均唯一性越是被其他事件共享的时点其信息增量越少权重就越低。这个过程用代码实现时需要构造一个巨大的重叠矩阵在事件很长时非常占内存。我一开始天真地用双重循环去算几万个事件直接卡死。后来改成按时间段扫区间把复杂度降下来才算把这题跑通。时间衰减权重又是另一层越早的事件对现在的参考价值越低所以按事件的时间远近做指数衰减。这里有个很有意思的问题——衰减系数选多少选太小和没衰减没区别选太大则模型基本只盯着最近一小段数据。书里给了参考范围但没有标准答案我最后把衰减系数当成一个超参数和模型一起做交叉验证。这种练习题里冒出超参调优的时刻正是这类练习最有魅力的地方。3.3 MDI、MDA 与 SFI特征重要性没有唯一答案特征重要性这一章的练习我只做一个对比实验用同一份模拟数据、同一个随机森林模型分别计算平均不纯度减少MDI、平均准确率下降MDA和单特征重要性SFI看结果是否一致。结果相当打脸——结论真的不一致而且不一致得非常典型。MDI 倾向于给高基数特征更高的分数因为切分时高基数特征更容易碰巧把样本分得很纯MDA 对特征间的共线性敏感两个强相关特征互相分担重要性拆开看时每个都显得不重要SFI 则完全不考虑特征组合效应单独一个特征可能很强和别的特征放在一起反而冲突。方法优点典型陷阱MDI计算快结果稳定高基数特征被高估MDA体现真实预测贡献共线性特征互相稀释SFI快速识别单点信号忽视组合效应可能误杀可用特征做完这个对比之后我再也不轻信任何单张特征重要性图了。现在看模型报告第一件事就是问这里用的重要度是哪种基尼系数还是排列重要性两者结论经常是两回事。4. 练习过程中踩过的最典型的三个坑4.1 数据泄漏不会写在变量名里练习题里最容易犯、也最难察觉的错误是数据泄漏。我没有在某个变量名里看到future才意识到问题恰恰相反大多数泄漏都包装得很无辜。举个例子在计算特征时如果用整个数据集的均值去填充缺失值训练集和测试集就共享了未来的统计信息又比如做标准化时先把全局均值方差算好再切分这也是一种泄漏。尤其在时间序列里切分的方式会让泄漏更隐蔽标准的 K-Fold 随机抽样在金融数据上本质就是巨大的泄漏因为相邻样本高度相关模型等于提前见过了邻近答案。解决这个问题的笨办法也是我现在一直在用的办法所有涉及统计量的预处理全部放进 Pipeline并且强制在每折交叉验证内部重新 fit。这样做虽然代码繁琐但它从结构上堵住了最可怕的那一类泄漏。4.2 时间索引与特征对齐pandas 有时候太贴心第二个大坑来自 pandas 的索引对齐。刚开始写练习时我经常会写出这样的代码先按时间索引算出一个标签序列再直接 concat 到特征表上。pandas 会按照索引自动对齐如果两边索引有细微错位它不会报错只会静默地在对齐不了的位置填上 NaN。我遇到过最诡异的一次现象是模型线上训练准确率莫名其妙的高但换到新数据后一塌糊涂。排查了很久才发现生成标签的时候我用了未来第 t1 根K线的收盘价去计算当前标签但是由于索引错位pandas 在对齐时把标签整体往前挪了一根模型提前看到了未来信息。自那之后我的所有练习代码里都强制增加一步检查特征的索引和标签索引是否完全一致不一致就抛异常。这个习惯在写小练习时显得多余但一旦数据量大了它能救你一命。4.3 在跑和跑对之间隔着一组断言练习题不是工程级代码很多时候你写出来的函数能跑它已经算是成功了。但能跑离跑对还有很大距离。我在做特征重要度对比练习时写了一个 MDA 的实现跑完输出结果怎么看都觉得不对但代码不报错我只能干瞪眼。后来我把书里对 MDA 的数学定义又仔细看了一遍发现问题出在我对打乱某一列特征的范围理解错了。书里说的是在验证集上打乱我写成了在训练集上打乱虽然代码照样能计算出一个重要度分数但这个分数和书里要表达的含义完全不是一回事。这件事教会我一个习惯每个核心函数至少配一个极端测试。比如测试三重障碍函数时构造一个瞬间暴涨后暴跌的序列手动推算出期望标签再去跑函数如果函数输出和人肉推演不一致那说明实现必有问题。“能跑”只是起点和人肉推演对齐才是真正做完的底线。5. 我是怎么判断一个练习算不算做完的5.1 极端数据是天然的标尺判断一个练习做没做完我不用代码有没有跑出结果作为标准而是用一系列极端数据来验证。比如标签模块我会故意构造一段连续上涨的行情期望所有样本都应该被打成 1再构造一段急剧震荡的行情期望大部分样本被打成 0。如果函数在这些场景下的输出和我预期的不同我就知道实现里还藏着我没有考虑到的边界条件。这招是我做工程时留下的习惯没想到用在解书后练习上特别顺手。金融数据最大的特点就是各种意外缺数据、停牌、极端涨跌。练习里的模拟数据往往很规整你的实现可能只在规整数据上是对的。测试极端数据本质上是强行把那些现实泥泞提前拖进来逼着代码更健壮。5.2 结论写下来才算完成闭环我这个仓库还有一个硬性习惯每个练习 notebook 必须有结论区块。哪怕结论只是在当前模拟数据下MDI 与 MDA 排序差异明显推测和特征共线性有关也要写下来。因为练习的目的是理解因果关系而不只是输出一个数字写结论的过程会强迫你回看实验过程把发生了什么和为什么发生两件事粘合在一起。如果没有结论代码过两周我再打开基本上只能看懂做了什么完全想不起当时为什么这么做。而有了文字记录整个练习才有积累价值——下次换了数据、换了场景我可以快速回顾之前是怎样推导的而不是重新从头推理一遍。6. 给准备动手解这本书的人一些具体建议6.1 不要从第 1 章顺序做到第 18 章这本书不是小说练习更不是非要从头做到尾。我的建议是先把自己最感兴趣、或者最近工作里最头疼的那个主题选出来只做那一章的练习。比如你正在研究因子有效性评估那就先做特征重要度那一章如果正在发愁训练集怎么构造那就先做标签体系那一章。顺序做题最大的问题是书后段的练习经常依赖前段实现做到后面发现前面的代码写得不顺手又得回头重构容易消磨耐心。反过来挑一个具体场景切入做完一个练习后会立刻获得原来自己的理解不够细的反馈这种反馈才是继续往下做的最真实动力。6.2 善用最小反例去验证书里每一条断言书里有很多斩钉截铁的断言比如普通交叉验证在金融数据上会导致严重过拟合。读这句话时你可能点点头就过去了但当我真的构造出一个带时间相关性的模拟数据分别跑普通 K-Fold 和 CPCV直观看到测试分数被高估这才真正理解为什么书里反复强调需要用并发事件感知的验证方案。所以我建议你在做练习时顺手把书里的断言改写成可验证的小实验。不一定要完整复现论文只要做出一个反例让自己亲眼看到断言成立或不成立的条件就算赚到了。这个习惯会让你从接受结论过渡到理解结论这也是 Adv_Fin_ML_Exercises 这种练习类小项目存在的最大价值。对我来说这个仓库的价值不在于里面的代码有多严谨而在于它逼着我把那些看似已经被我读懂的知识重新在数据上摔打了一遍。练习做多了以后最直接的变化是再看到新的金融机器学习论文我会下意识地把它拆成标签怎么定义、样本怎么加权、验证怎么切分这三个模块来读。这种拆解的眼光几乎全是在解练习时被那些坑给磨出来的。本文还有配套的精品资源点击获取
返回列表