关于 build-ml-pipeline
build-ml-pipeline 是面向数据科学家的工作流技能,用于声明 skrub DataOps 图,并配置拆分器及非默认评分。它包含冒烟测试,但构建阶段不拟合模型或执行完整评估。
主要功能
- 01声明 skrub DataOps 图
- 02标记特征并附加估算器
- 03配置拆分器和自定义评分
- 04生成未拟合学习器快照
- 05运行工作流冒烟测试
适用场景
- 01构建已批准的 ML 工作流
- 02配置符合部署方式的交叉验证
- 03附加非默认评估评分
- 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.mdcustom-splitter.mdlayer_examples.mdreproducibility_mechanics.mdsnapshot.mdsource-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分别是来源、网格加标记,以及标记之后的特征。
流程
python -m skore_skills status。若有待处理设置 → S0。然后运行python -m skore_skills design consent --stem <stem>。JSONaction为准。ask/stop→ 不要声明 (“构建它”不代表已批准)。proceed则继续。然后运行python -m skore_skills frame show,不要加--revise。 若结果不是proceed,则加载frame-ml-problem并停止。若proceed的translation为 null,则停止:没有分割器翻译。- 在首次写入前输出 1–3 句话:这是对未拟合的
build_learner、Method 单元格和流水线快照进行本地 准备,然后运行 smoke。不会训练或运行 全数据集评估。不要编造时长。只说一次。若尚待批准,只预览。 - 输出 Pre-flight。仅在本轮有证据时勾选方框。
- 声明
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。除非用户要求,否则不要添加警告过滤器。 - 未拟合快照:
references/snapshot.md。 - 当此 stem 对应的
experiments/NN_*.py存在时,仅在已安装smoke-test-ml-pipeline技能的情况下加载该技能。 若缺少该技能 → 输出一行;不要编造 pytest 文件。 然后运行python -m skore_skills smoke run --stem <stem>。JSONstop/red/smoke_missing→ 在此处修复图。 不要放宽断言。不要评估。未运行此命令,不要声称 pytest 已通过。 smoke run返回proceed后,先输出下面的检查点,再运行python -m skore_skills evaluate consent --stem <stem>。ask— 引用 JSONcontext(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。
schemedate_time— 打开references/custom-splitter.md中的时间序列部分。cv=是该部分所述的项目本地类。为translation.horizons中的每个条目构建一个此类拆分器。每个拆分器对应一个预测器。split_kwargs携带时间戳值。时间戳列应使用 EDA 或随数据提供的文本中已命名的列。只有在这些来源均未命名该列时,才询问时间戳位于哪一列。time_rolecovariate会将该列保留在特征中。sort_key会将其从特征中移除,但仍通过split_kwargs传递。splitterGroupKFold— 使用cv=GroupKFold(n_splits=<folds>)和split_kwargs={"groups": data["<translation.groups>"]}。splitterKFold— 使用cv=KFold(n_splits=<folds>)和空的split_kwargs。splitterprefit— 数据已包含训练表和测试表。不要使用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 默认值的评分。