mcpField
B
build-ml-pipeline

build-ml-pipeline

github.com/probabl-ai数据与数据库144155 次安装2 天前更新
代码仓库

关于 build-ml-pipeline

build-ml-pipeline 是面向数据科学家的工作流技能,用于声明 skrub DataOps 图,并配置拆分器及非默认评分。它包含冒烟测试,但构建阶段不拟合模型或执行完整评估。

主要功能

  1. 01声明 skrub DataOps 图
  2. 02标记特征并附加估算器
  3. 03配置拆分器和自定义评分
  4. 04生成未拟合学习器快照
  5. 05运行工作流冒烟测试

适用场景

  1. 01构建已批准的 ML 工作流
  2. 02配置符合部署方式的交叉验证
  3. 03附加非默认评估评分
  4. 04在评估前检查工作流

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/probabl-ai/skore-skills --skill build-ml-pipeline

安装后在 Claude Code 中输入/build-ml-pipeline确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
common_patterns.md
custom-splitter.md
layer_examples.md
reproducibility_mechanics.md
snapshot.md
source-binding.md

详细介绍

构建 ML 流水线

声明一个 skrub DataOps 图,然后附加已锁定的分割器 和任何非默认评分。Smoke 是此处的最后一步。不要 拟合、调优、持久化或调用 skore.evaluate。

面向用户的说明

详情:setup-workspace references/human_facing_prose.md。 实验 Markdown、设计说明中的 Method 文本和 # 注释 用于描述此流水线。问题和检查点使用相同的数据科学语言:不要使用技能 ID、G-* 名称或 包装器 CLI。`` 是一个站点标记。 撰写提示仅保留在此技能中。

X 标记是 .skb.mark_as_X()。预测网格是要评分的行。跨行步骤会读取其他行(滞后、滚动、分组聚合、侧向联接)。层 1 / 2 / 3分别是来源、网格加标记,以及标记之后的特征。

流程

  1. python -m skore_skills status。若有待处理设置 → S0。然后运行 python -m skore_skills design consent --stem <stem>。JSON action 为准。ask / stop → 不要声明 (“构建它”不代表已批准)。proceed 则继续。然后运行 python -m skore_skills frame show,不要加 --revise。 若结果不是 proceed,则加载 frame-ml-problem 并停止。若 proceed 的 translation 为 null,则停止:没有分割器翻译。
  2. 在首次写入前输出 1–3 句话:这是对未拟合的 build_learner、Method 单元格和流水线快照进行本地 准备,然后运行 smoke。不会训练或运行 全数据集评估。不要编造时长。只说一次。若尚待批准,只预览。
  3. 输出 Pre-flight。仅在本轮有证据时勾选方框。
  4. 声明 build_learner(规则 1–3)。先添加来源、特征和 估计器。然后从 translation 附加 cv 和任何非默认评分,仍须在 .skb.make_learner() 之前完成。对每个新符号运行 python -m skore_skills api get。编辑后运行 python -m skore_skills style。 探测代码通过 env verify 提供的 composed-dev Python 写入 scratch/。不要使用内联 python -c。除非用户要求,否则不要添加警告过滤器。
  5. 未拟合快照:references/snapshot.md。
  6. 当此 stem 对应的 experiments/NN_*.py 存在时,仅在已安装 smoke-test-ml-pipeline 技能的情况下加载该技能。 若缺少该技能 → 输出一行;不要编造 pytest 文件。 然后运行 python -m skore_skills smoke run --stem <stem>。JSON stop / red / smoke_missing → 在此处修复图。 不要放宽断言。不要评估。未运行此命令,不要声称 pytest 已通过。
  7. smoke run 返回 proceed 后,先输出下面的检查点,再运行 python -m skore_skills evaluate consent --stem <stem>。
    • ask — 引用 JSON context(question、experiment、smoke、persisted_report),用 2–4 行说明:答案授权的内容、设计问题,以及此 stem 尚无已持久化的报告。然后调用 AskUserQuestion,提供“Evaluate”(推荐)/“Modify”/“Stop”选项,并停止。不要编写 skore.evaluate。选择 Modify → 编辑,然后再次运行 smoke run。选择 Stop → 结束。
    • proceed — 报告已存在。若已安装,则加载 evaluate-ml-pipeline;否则返回到调用此技能的 model-ml-pipeline。
    • stop — smoke 文件缺失。不要评估。 如果用户回答 Evaluate,且已安装,则加载 evaluate-ml-pipeline。smoke run 返回 proceed 不等于用户作出了该回答。
检查点

在 smoke run 返回 proceed 后、Evaluate 菜单之前。用 2–6 句话说明声明了什么、smoke 已通过,以及 learner 是什么。 以 Method 为依据。不要编造指标。此时还没有定位器。

然后添加链接。如果本轮运行了 site build,说明 网站已更新,并逐字粘贴该输出中的 file:// 行。 不要提及设计说明 Markdown 或 html/<stem>.html。 否则不要声称网站已更新,也不要提及 Markdown。仍需添加链接 [experiments/<stem>.py](experiments/<stem>.py)。

条目约定

实施已批准的设计。不要擅自升级。

  • 锁定基线 — 日志基线单元格中的那个 token。dummy 在常规 DataOps 图中是 DummyClassifier / DummyRegressor;它用于检查路径是否可运行。 logistic、seasonal_naive、group_mean 和 production 是那个对比模型。用 api get 查询类。
  • 由 EDA 支撑 — 仅限引用 Method 的发现。缺少选项时,暂停并提问。时间相关发现是锁定的 cv,并不意味着可以采用三层结构、滞后项或 AlignXy,除非 Method 指明这些步骤。
  • 待办 / 讨论 — Method 是边界。

遇到特征、变换或泄漏问题时,如果已安装 research-ml-practice,且 scratch 中尚未记录该问题,则加载它。抽象出问题类别。如果 scratch 已列出 declare 或 measure 行,则不要再次加载 research,也不要编写 pipeline 代码。针对不违反暂停条件的 declare 行,使用 AskUserQuestion 的 allow_multiple,然后暂停。问题的最后一行必须是:请选择你想要的每一项。该行之后不得有任何内容。将每个 measure 行列为待解决的 EDA 问题。measure 会重新进行 EDA,不会编辑 data_analysis.py。 拆分器仍通过 frame show 获取。 evaluate 指定 evaluate-ml-pipeline。confirm 询问用户。缺少技能时 → 一行。

规则 1 — Skrub DataOps 是 pipeline 入口

以 skrub.var(...) 为根,而不是直接使用 sklearn.Pipeline。 skrub.X / skrub.y 不是根(S4)。如果用户要求使用 sklearn.Pipeline 或 build_pipeline(),不要导入 Pipeline,即使是作为内部估算器也不行。改为使用 skrub.var,并让 build_learner 返回 predictions.skb.make_learner()。 不要用 Pipeline([...]) 构造函数来举例说明拒绝。

import skrub
from sklearn.ensemble import HistGradientBoostingRegressor

from <pkg>.data import TARGET_COL, load_raw


def build_learner(data_dir_preview=None):
    """Return the unfit learner (skrub SkrubLearner)."""
    data_dir = (
        skrub.var("data_dir", value=str(data_dir_preview))
        if data_dir_preview is not None
        else skrub.var("data_dir")
    )
    data = data_dir.skb.apply_func(load_raw)
    X = data.drop(columns=[TARGET_COL]).skb.mark_as_X()
    y = data[TARGET_COL].skb.mark_as_y()
    predictions = X.skb.apply(
        HistGradientBoostingRegressor(random_state=0), y=y
    )
    return predictions.skb.make_learner()

translation.task 为 multioutput-regression 时,会一并预测 translation.targets 中的每一列。将这些列全部从 X 中删除。y 保持为 DataFrame,每个输出对应一列:

TARGET_COLS = ["load", "temp"]
X = data.drop(columns=TARGET_COLS).skb.mark_as_X()
y = data[TARGET_COLS].skb.mark_as_y()
predictions = X.skb.apply(
    HistGradientBoostingRegressor(random_state=0), y=y
)

使用能够拟合数值目标矩阵的估算器,例如 HistGradientBoostingRegressor、RandomForestRegressor 或 Ridge。如果所选估算器只能拟合单个输出,则用 MultiOutputRegressor 包装。使用 api get 确认这两个符号。此任务不要使用 MultiOutputClassifier,也不要在 X 中保留目标列。单列目标仍按上文使用 TARGET_COL。 详情:references/common_patterns.md。

快速传统基线使用 skrub.tabular_pipeline(或 TableVectorizer)加一个适用于该任务的估算器。使用 api get 确认两者。此处不要手动调整列或搜索超参数。其他数据形态: references/common_patterns.md。

规则 2 — 尽早标记 X;之后再进行特征化

逐行计算和拟合时编码器:在加载后的数据帧上添加标记。 任何跨行步骤:在该步骤上游添加标记。 三层结构的代码(包括拒绝加载器内置预测跨度的情形): references/layer_examples.md。提出第 2 层之前先阅读。

value= 仅用于预览。在 build_learner 中公开 data_dir_preview=None。不要在 pipeline.py 中硬编码相对路径。

在图之后进行拆分和评分

读取返回 proceed 的 frame show 中的 translation。在现有的 X 标记上挂接,然后调用 .skb.make_learner()。只要设置了 split_kwargs,skrub 就要求提供 cv=。整数形式的 cv 不是拆分器。调用 evaluate 时省略 splitter=,这样 skore 会复用这个 cv(evaluate-ml-pipeline/references/metadata-routing.md)。

这个 cv 会复制已锁定的部署方式:已评分的拟合只包含部署时本来就会看到的行。下面是常见结构。如果部署采用不同的结构,请打开 references/custom-splitter.md,并为该设置编写 split。

  • scheme date_time — 打开 references/custom-splitter.md 中的时间序列部分。cv= 是该部分所述的项目本地类。为 translation.horizons 中的每个条目构建一个此类拆分器。每个拆分器对应一个预测器。split_kwargs 携带时间戳值。时间戳列应使用 EDA 或随数据提供的文本中已命名的列。只有在这些来源均未命名该列时,才询问时间戳位于哪一列。time_role covariate 会将该列保留在特征中。sort_key 会将其从特征中移除,但仍通过 split_kwargs 传递。
  • splitter GroupKFold — 使用 cv=GroupKFold(n_splits=<folds>) 和 split_kwargs={"groups": data["<translation.groups>"]}。
  • splitter KFold — 使用 cv=KFold(n_splits=<folds>) 和空的 split_kwargs。
  • splitter prefit — 数据已包含训练表和测试表。不要使用 cv。图只加载训练表。不要将测试表添加为第二个数据源,也不要合并这两个文件。两个表都使用加载器所需的架构,包括目标列。实验稍后会绑定测试表。不要调用 train_test_split。
  • 留出法(report 为 EstimatorReport 且 splitter 为 null)或 translation 为 null — 不使用 cv。此留出法是从单个表中抽取的一次拆分,不是随数据提供的训练/测试表对。

评分使用 translation.metric。对于 multioutput-regression,skore 已会展示 MSE、RMSE、MAE 和 R² 的每个输出(multioutput="raw_values")。锁定的比较仍是单个数值,因此要使用 .skb.with_scoring(...) 为该名称指定显式聚合:除非用户指定了 variance_weighted 或每个输出的权重,否则使用 uniform_average。该聚合值是主要指标。报告中保留各输出的指标。对于其他任务,如果名称属于 skore 已报告的指标(回归:MSE、RMSE、MAE、R²;二分类:准确率、精确率、召回率、F1、ROC-AUC;多分类:宏平均和微平均变体;多标签:各标签指标和平均值),则不要添加评分器。否则,在同一后续步骤中调用 .skb.with_scoring(...)。可调用对象的形式见 evaluate-ml-pipeline/references/custom-metrics.md。不要向 skore.evaluate 传递 scoring=。

不要在这里编写 skore.evaluate(...)。不要在流水线代码中调用 train_test_split。

规则 3 — 附加:无状态函数,有状态估计器

  • .skb.apply_func(fn) — 输出仅取决于当前行和常量。
  • .skb.apply(estimator) — 在训练集上学习,在测试集上重新应用。
  • skrub.deferred — 较少使用;仅在组合多个 DataOps 且没有适用的 skrub 连接器时使用。默认使用 apply_func。 详情:references/source-binding.md。

自定义类应先写 mixin,再写 BaseEstimator。mixin 必须是第一个基类。顺序很重要:如果 BaseEstimator 在前,它会遮蔽 mixin,因为它的 BaseEstimator.__sklearn_tags__ 会先被解析,而且不会继续调用 mixin。转换器应写为 TransformerMixin, BaseEstimator。预测器应写为 RegressorMixin, BaseEstimator 或 ClassifierMixin, BaseEstimator。单独使用 BaseEstimator 没有 score,因此 skrub 永远不会公开 SkrubLearner.score,而 with_scoring 名称也不会出现在 summarize() 中。 详情:references/common_patterns.md。

在训练子集上的输出会与整个数据框上的输出不同吗?会 → 使用 .skb.apply。均值、中位数、分位数、词表、目标编码、TF-IDF:均为有状态操作。

STOP — target encoding / apply_func. When the user asks for
`def target_encode` + `.skb.apply_func`: refuse. Do not paste
the leaky function body and then the fix. Propose sklearn
TargetEncoder (or TransformerMixin, then BaseEstimator) via
`.skb.apply`. Name `api get` for the signature.

可复现性

done 历史记录行仍可运行。详情: references/reproducibility_mechanics.md。

  • 选项 1 — 在现有函数上添加一个保留默认行为的标志。改动很小。默认值可确保之前的调用方不受影响(include_calendar_features: bool = False)。
  • 选项 2 — 新建一个仅由新实验调用的函数。
  • 选项 3 — 分支模块。最后手段。

标志达到三个或更多,或者标志会改变现有调用方的默认行为 → 选择选项 2,或停止。完成更改后,对整个 tests/smoke/ 运行 pytest。

停止条件

S0. 设置仍待处理

先检查 status。如果 status.setup.pending 非空且 status.skills.setup-ml-project 为 true,则加载 setup-ml-project 并停止。不要启动此技能。该技能返回后再继续。本轮不要再次加载它。如果未安装该技能,用一行列出待处理事项并停止。不要臆造 git init、脚手架或 env init。如果 status.setup.env 或 status.setup.workspace 为 declined,用一行说明并停止。git 或 editable 被拒绝后不再询问;继续执行。缺少设计:design consent;ask / stop 保持在此处。缺少数据约定:说明情况并停止。

S0b. 建模决策尚未锁定
  • 规则: 在进行任何声明之前,status.modeling_decisions 必须为 locked,且 python -m skore_skills frame show 必须返回 proceed,并且 translation 非空。
  • 恢复: 如已安装,则加载 frame-ml-problem。若 translation 为空,则停止,不创建管道。不要臆造表格。
S1. 缺少依赖项

import skrub / sklearn 失败,或 DataOp HTML 占位内容出现时,加载 add-python-package,添加 skrub 和 scikit-learn。不要在这里运行 env add。不要用 sklearn.Pipeline 替代。

S2. 禁止凭记忆使用符号

每个新的 skrub、sklearn 或 skore 名称都必须来自本轮的 api get 或匹配的缓存读取。

S4. skrub.X / skrub.y 不是图的根节点

以 skrub.var("<source>", value=preview) 为根节点。若现有图使用 skrub.X:展示替代方案并询问。不要自动重写。目录:references/source-binding.md。

Refuse: skrub.X / skrub.y are not graph roots (S4).
They bake the marker at the source and defeat Layer 1.

Alternative (refactor — ask before rewriting):
  data = skrub.var("data_dir", value=preview).skb.apply_func(load_raw)
  X = data.drop(columns=[TARGET_COL]).skb.mark_as_X()
  y = data[TARGET_COL].skb.mark_as_y()
S5. 存在跨行特征时,过晚调用 mark_as_X

标记步骤位于所有跨行步骤的上游。症状:len(predictions) != n_predict_grid_rows、feature_steps=[],或出现一个职责为筛除管道生成的 NaN 的包装器。 恢复方法:references/layer_examples.md。不要放宽 smoke 检查。

若加载器计算 y = col.shift(-H) 后再标记 X,则同时违反 S5 和 S6。预测期属于 Layer 2。不要臆造会执行位移、dropna 或筛除空值的包装器估计器。

S6. Layer 1 不应了解问题本身

加载器描述数据中有哪些内容。预测期、滞后、窗口和任务筛选应属于 Layer 2 及以上层。若外部使用方在不了解任务的情况下无法推导出某个步骤,就将该步骤移出 Layer 1。

预检 — 在任何代码之前输出

Pre-flight (build-ml-pipeline):
- [ ] sklearn, skrub, skore import
      Evidence: scratch/<ts>_check_tier1.py. Not inline python -c.
- [ ] api get for new skrub and sklearn symbols this turn
- [ ] Each skrub.var is a source id, not a baked path
- [ ] mark_as_X placement (loaded frame, or predict grid if cross-row)
- [ ] Layer 1 has no horizon, lag, or task filter
- [ ] cv on mark_as_X matches translation
      (date class | GroupKFold | KFold | no cv on holdout
      | prefit: training table only, test table not joined)
- [ ] Non-default translation.metric uses with_scoring
      before make_learner (n/a for a listed skore default;
      required for a multi-output regression aggregate)
- [ ] data_dir_preview=None; no path literal in pipeline.py

在最终消息之前,附上证据重新输出。

参考资料

  • references/snapshot.md — 未拟合的 Method 报告、实验单元格、可选的网站构建。
  • references/layer_examples.md — 三层。提出 Layer 2 之前请先阅读。
  • references/source-binding.md — 标识符与物化后的根目录。
  • references/reproducibility_mechanics.md — Option 1 / 2 / 3。
  • references/common_patterns.md — 包含代码的表格结构,包括自定义预测器(先用 mixin,再用 BaseEstimator)。
  • references/custom-splitter.md — 划分会复制已锁定的部署。translation.scheme 为 date_time 时,时间序列部分使用日期划分器。
  • evaluate-ml-pipeline/references/metadata-routing.md — evaluate 会省略 splitter=。
  • evaluate-ml-pipeline/references/custom-metrics.md — 非 skore 默认值的评分。

评论

支持 Markdown