第6章 Python 迁移与通用片段
现行主案例执行入口(2026-09-19)
Myocardial_Infarction_Complications的唯一执行根位于仓库 04_Cases/Myocardial_Infarction_Complications/,参数由analysis_config.R维护。按案例运行指南执行,不能复制本章技术Demo的变量、折数或数值替代主案例。
| 任务 | 主案例脚本 |
|---|---|
| 读取与描述、固定成员 | L01_Read_Check_Demo.R、L02_Data_Preparation.R |
| LASSO lambda.min按原始变量筛选、普通Logistic | L03_Feature_Selection_Logistic.R |
| 完整训练内筛选/调参的外层OOF | L04_Internal_Validation.R |
| 共享特征的RF/XGBoost/SVM与SHAP | L05_ML_Comparison_SHAP.R |
| 第5课集中纠错、Kappa冻结与留出对照 | L06_Data_Audit_T0_Correction.R |
| 单变量整体LRT与AIC机制展示 | Teacher_Selection_Demonstrations.R |
| 冻结系数列线图及验证 | Export_Classroom_Artifacts.R、Validate_Review_Run.R、Check_Separation.py |
| Python完整统计主链快速展示 | Export_Python_Raw.R、Python_Statistical_Workflow.py |
Python演示保留原始缺失与固定成员,在各训练范围独立筛查、插补和选择lambda.min,再按原始变量拟合普通Logistic,训练OOF最大Kappa阈值冻结后用于测试。使用scikit-learn 1.9的SAGA,与R glmnet内层实现不同,不要求数值完全一致;R维护正式四模型比较。完整脚本课前预跑,最后一课仅快速展示数据→描述→筛选→拟合→评价,课后可依据代码与浓缩讲义复现。
All111是异常教学反例;Corrected执行已确认的时间、稀疏/零格、无变异和极低观测比例筛查。旧版T0_102不是最终纠正版。不要用已全训练插补的矩阵做CV,不从测试选变量、调参或选阈值。具体统计边界见教学契约。
通用技术Demo与原有代码片段
以下Demo_R_Project及其数值属于独立技术示范,保留作为片段查阅;本节默认值不覆盖上面的主案例配置。
本章解决什么问题: 前五章的分析全部用 R 完成。当同一条流程需要搬到 Python(团队协作、部署环境、工具链限制)时,怎么搬才不算”另起炉灶”?本章给出代码库的标准答案:R 导出同一批成员与同一份契约,Python 直接读取,不做任何重新抽样。文末附五个与医学分析相关的高频通用片段,随用随查。
本章定位: 本章全部数字来自 Demo_R_Project/ 的真实运行:R 端由 R/06_export_python_bridge.R 导出迁移契约,Python 端由 python/01_contract_migration_demo.py 按契约复跑并对测试集预测一次。迁移演示回答的问题只有一个——换一门语言,什么必须一致、什么允许不同。
Demo_R_Project/ 是技术演示(MASS::Pima.tr2 二分类数据),不是第三个正式教学 Case。正式教学数据只有 Myocardial Infarction Complication(直播主案例)与 Early Stage Diabetes Risk Prediction(Mini Project,均见 ../../04_Cases/)。本章演示的是迁移方法与工程纪律,数字只用于核对流程是否搬对。
什么时候用
- 已有 R 分析产物(清理后数据、划分成员、锁定模型),需要在 Python 环境复现同一条流程;
- 团队以 Python 为主,但划分、变量契约与结果口径必须以已完成的 R 分析为准;
- 任何”同一个分析,两种语言各跑一遍”的场合——例如审稿复核、部署改写。
反过来,如果你还没有固定的划分与锁定模型,先回到第 2 章与第 5 章把 R 主线做完——迁移的前提是存在一份已经冻结的契约,没有契约就没有可迁移的东西。
迁移总原则:两份清单
早期常见的做法是”两边设同一个 seed,祈祷抽样一致”。这条路在工程上走不通:同一个种子值在 R 与 Python 的随机流里产生的成员不保证逐行一致。代码库的做法是把”一致”从概率问题变成文件问题——划分只做一次(R 端第 2 章),结果写成 CSV,Python 照单读取。
必须保持一致(任务契约):
| 契约项 | 载体 |
|---|---|
row_id(样本主键) |
python_model_data.csv、两个 manifest |
| outcome 与正类方向 | python_feature_contract.csv(positive_class) |
| split(train / test 成员) | split_manifest.csv |
| fold membership(折成员) | fold_manifest.csv |
| predictor contract(变量、类型、水平、参照、缺失处理、标准化) | python_feature_contract.csv |
| metric definition(指标定义与锁定阈值) | locked_model_config.csv、第 5 章口径 |
允许实现不同(不追求逐位一致):
- API 与函数名(
glm↔︎LogisticRegression); - solver 与优化路径(IRLS ↔︎
lbfgs); - 对象结构(
data.frame↔︎DataFrame、公式接口 ↔︎ 矩阵接口); - package 选择(pROC ↔︎ sklearn.metrics)与区间估计口径;
- 图形样式(ggplot2 ↔︎ matplotlib)。
契约内的项逐行一致,由断言强制执行;契约外的实现差异如实记录、不调参对齐。Python 端 AUC 与 R 不逐位一致是预期现象,不是错误。
输入与输出
输入(全部来自 R 端已冻结产物):
results/tables/python_model_data.csv:row_id+ 结局y+ 8 个原始尺度预测变量,缺失保持 NA(插补留给 Python Pipeline 内部学习);results/tables/split_manifest.csv与results/tables/fold_manifest.csv:第 2 章唯一生成的成员清单;results/tables/python_feature_contract.csv:特征契约;results/models/locked_model_config.csv:锁定模型类型、超参与阈值(第 5 章产物)。
输出:
results/tables/python_test_predictions.csv:带row_id的测试集预测(概率与分类);results/tables/python_test_metrics.csv:测试集指标;results/book_fragments/ch06_python_run.md:运行记录与实现差异(本章直接引用)。
脚本与产物
| 脚本 | 职责 | 关键产物 |
|---|---|---|
Demo_R_Project/R/06_export_python_bridge.R |
导出建模数据、校验 manifest 在场、写特征契约与契约片段 | python_model_data.csv、python_feature_contract.csv、ch06_python_contract.md |
Demo_R_Project/python/01_contract_migration_demo.py |
读契约、按 manifest 取成员、Pipeline 内预处理、训练同类型模型、对 test 预测一次 | python_test_predictions.csv、python_test_metrics.csv、ch06_python_run.md |
R 导出脚本由 run_all.R 统一调用;Python 脚本从 Demo 项目根单独运行:python python/01_contract_migration_demo.py。
让 Agent 执行
完整 Prompt 见 prompts/06_Python迁移.md;下面是可直接复制的紧凑版。
让 Agent 运行 R → Python 迁移演示并核对契约。替换方括号后整体复制发送。
【背景】我的医学数据分析项目已用 R 完成全部正式分析并冻结产物(划分成员、特征契约、
锁定模型 logistic、锁定阈值 0.2497)。现在做 R → Python 契约迁移演示。
【当前任务】在 Demo 项目根目录依次执行:
1) Rscript R/06_export_python_bridge.R(如产物已冻结可跳过,先报告 4 个 CSV 是否在场)
2) python python/01_contract_migration_demo.py
【约束】1. 原样运行,不改代码与任何参数;2. Python 端禁止 train_test_split、
禁止重建 fold、禁止重设 seed 抽样,成员必须严格按 split_manifest.csv 取;
3. 不为让 Python 指标"对齐 R"而修改任何超参;4. 在 [你的虚拟环境] 中运行,
缺包先报告包名与版本,经我确认后再安装。
【输出要求】报告:train/test 成员数、fold 校验结果、Pipeline 结构、模型类型、
测试集 AUC 与 Brier、脚本列出的实现差异。
【验收/暂停条件】train=211 / test=89;AUC 参考值 0.7447(R 端 0.7442),
Brier 参考值 0.1905(R 端 0.1888),不要求逐位一致。若断言失败或 ImportError,
停下报告完整报错,不自行改代码。
核心实现
完整实现只在 Demo_R_Project/R/06_export_python_bridge.R 与 Demo_R_Project/python/01_contract_migration_demo.py 维护,这里只摘四处关键结构。
R 端:导出原始尺度数据与特征契约
R/06_export_python_bridge.R(摘录 1:导出建模数据)
# ---- 原始尺度建模数据(不插补、不标准化;Python 端在 Pipeline 内学习)-----------
py_data <- cohort[, c("row_id", "y", config$predictors)]
write_table(py_data, "results/tables/python_model_data.csv")
register_artifact("results/tables/python_model_data.csv", "ch06", "table",
"R/06_export_python_bridge.R", "data/derived/cohort_clean.csv",
"full cohort", "original scale; NA kept for Python-side pipeline imputation")注意导出的不是 R 端建好的模型矩阵,而是原始尺度、缺失保留的数据——插补与标准化的”学习”必须发生在 Python Pipeline 内部,否则等于把 R 端学到的预处理信息偷渡过去。特征契约则逐行写明每个变量的角色与处理规则:
R/06_export_python_bridge.R(摘录 2:特征契约)
contract <- rbind(
data.frame(role = "id", name = "row_id", type = "character",
positive_class = NA_character_, factor_levels = NA_character_,
missing_handling = NA_character_, standardization = NA_character_,
reference_level = NA_character_, stringsAsFactors = FALSE),
data.frame(role = "outcome", name = "y", type = "numeric",
positive_class = config$positive_class, factor_levels = NA_character_,
missing_handling = "none", standardization = "no",
reference_level = NA_character_, stringsAsFactors = FALSE),
data.frame(role = "predictor", name = config$predictors_numeric, type = "numeric",
positive_class = NA_character_, factor_levels = NA_character_,
missing_handling = "median", standardization = "yes",
reference_level = NA_character_, stringsAsFactors = FALSE),
data.frame(role = "predictor", name = config$predictor_factor, type = "factor",
positive_class = NA_character_,
factor_levels = paste(config$bmi_cat_labels, collapse = ";"),
missing_handling = "mode", standardization = "no",
reference_level = config$bmi_cat_labels[1], stringsAsFactors = FALSE))
write_table(contract, "results/tables/python_feature_contract.csv")契约的每一行都来自单一配置源 config/config.R——参照水平、因子水平、正类不是 Python 端猜出来的,而是 R 端写死的。
Python 端:定位、读取与契约校验
python/01_contract_migration_demo.py(摘录 1:路径与契约校验)
ROOT = Path(__file__).resolve().parents[1]
TABLES = ROOT / "results" / "tables"
# (中略:读入 4 个 CSV 与 locked_model_config.csv)
# ---- 契约校验:fold 只在 train 内且恰好划分 train;split 无交叠 --------------
train_ids = split_manifest.loc[split_manifest["split"] == "train", "row_id"]
test_ids = split_manifest.loc[split_manifest["split"] == "test", "row_id"]
assert set(train_ids).isdisjoint(test_ids), "train/test overlap in split_manifest"
assert set(fold_manifest["row_id"]) == set(train_ids), \
"fold_manifest must partition the training set exactly"
assert fold_manifest["fold"].nunique() > 1, "fold_manifest degenerate"pathlib 让脚本与运行目录解耦(不出现任何个人绝对路径);三道 assert 对应 R 端的铁律——成员清单有任何交叠或缺漏,脚本直接停,不带着错契约往下跑。
Python 端:按 manifest 取成员、契约驱动 Pipeline、预测一次
python/01_contract_migration_demo.py(摘录 2:按 manifest 取成员)
# ---- 严格按 manifest 取成员(不重新划分)--------------------------------------
train_df = data[data["row_id"].isin(train_ids)].copy()
test_df = data[data["row_id"].isin(test_ids)].copy()
X_train, y_train = train_df[num_feats + fac_feats], train_df[outcome].astype(int)
X_test, y_test = test_df[num_feats + fac_feats], test_df[outcome].astype(int)python/01_contract_migration_demo.py(摘录 3:契约驱动的预处理 Pipeline)
# ---- 预处理 Pipeline(契约驱动)------------------------------------------------
numeric_pipe = Pipeline([
("imputer", SimpleImputer(strategy="median")),
("scaler", StandardScaler()),
])
factor_pipe = Pipeline([
("imputer", SimpleImputer(strategy="most_frequent")),
("onehot", OneHotEncoder(categories=fac_categories,
drop=fac_references,
handle_unknown="error")),
])
pre = ColumnTransformer([
("num", numeric_pipe, num_feats),
("fac", factor_pipe, fac_feats),
])OneHotEncoder 的 categories 与 drop(参照水平)全部来自契约文件而非数据现算;预处理包在 Pipeline 里,保证任何重采样场景下预处理都在折内重新学习——防泄漏在 sklearn 里是结构而不是自觉。
python/01_contract_migration_demo.py(摘录 4:训练一次,预测一次)
pipe = Pipeline([("preprocess", pre), ("model", model)])
# ---- 训练一次,对 test 成员预测一次 ---------------------------------------------
pipe.fit(X_train, y_train)
p_test = pipe.predict_proba(X_test)[:, 1]
threshold = float(locked["threshold"])
pred_bin = (p_test >= threshold).astype(int)模型类型读取 R 端锁定配置(本次为 logistic,以 penalty=None + lbfgs 近似 R 的无惩罚 glm);阈值 0.2497 来自锁定配置,Python 端不重新选阈值。
实际运行结果
迁移契约由 R 脚本生成,原文如下:
R → Python 迁移契约要点 · 本片段由 Demo 脚本自动生成,供教材引用
- 数据文件:
results/tables/python_model_data.csv(row_id + 结局 y + 8 个原始尺度预测变量;缺失保持 NA)。 - 成员文件:
results/tables/split_manifest.csv与results/tables/fold_manifest.csv(由 R/02 唯一生成;Python 端禁止 train_test_split / 重建 fold / 重设 seed 抽样)。 - 特征契约:
results/tables/python_feature_contract.csv。- 数值变量(7 个):SimpleImputer(median) + StandardScaler。
- 因子变量
bmi_cat:水平bmi_lt25 / bmi_25_29 / bmi_ge30;SimpleImputer(most_frequent) + OneHotEncoder,参照水平bmi_lt25。
- 结局:y(1 =
Yes)。 - 模型类型:以
results/models/locked_model_config.csv的model_type为准,Python 端训练同类型 sklearn 模型,仅对 test 成员预测一次。 - 实现差异(solver、惩罚、编码细节等)由 Python 脚本写入
results/book_fragments/ch06_python_run.md;不为追求与 R 完全一致的 AUC 反复调参。
契约文件 python_feature_contract.csv 的正文版(完整文件以 CSV 为准):
results/tables/python_feature_contract.csv)
| role | name | type | missing_handling | standardization | factor_levels / reference | positive_class |
|---|---|---|---|---|---|---|
| id | row_id |
character | — | — | — | — |
| outcome | y |
numeric | none | no | — | Yes |
| predictor | npreg glu bp skin bmi ped age(7 个) |
numeric | median | yes | — | — |
| predictor | bmi_cat |
factor | mode | no | levels bmi_lt25;bmi_25_29;bmi_ge30,reference bmi_lt25 |
— |
Python 端运行记录与实现差异由脚本自动写入片段,原文如下:
Python 迁移运行记录 · 本片段由 Python 脚本自动生成,供教材引用
数据与成员 - 输入:results/tables/python_model_data.csv(原始尺度,NA 由 Pipeline 内插补)。 - 成员:严格按 split_manifest.csv 取 train=211 / test=89; 并校验 fold_manifest.csv 恰好划分训练集。全程未使用 train_test_split, 未重建 fold,未做基于 seed 的重新抽样。
Pipeline 与模型 - 预处理:数值 7 个 → SimpleImputer(median) + StandardScaler; 因子 1 个(bmi_cat)→ SimpleImputer(most_frequent) + OneHotEncoder(levels 与 reference 来自契约)。 - 模型:logistic(与 R 锁定模型同类型);超参映射:{}。 - 锁定阈值(来自 R,训练集 OOF + Youden):0.249745。
本次测试指标(Python 端,预测一次) | 指标 | 值 | |—|—| | AUC | 0.7447 | | Brier | 0.1905 | | Sensitivity / Specificity / Accuracy | 0.7419 / 0.5862 / 0.6404 | | TP / FP / TN / FN | 23 / 24 / 34 / 8 |
与 R 的实现差异(不为对齐 AUC 而调参) - R glm 为无惩罚最大似然(IRLS);sklearn 以 penalty=None + lbfgs 近似,优化路径不同,系数可有微小数值差。 - AUC:R 端报告 DeLong 95% CI;sklearn roc_auc_score 仅给点估计,CI 口径不同。 - 因子编码:R model.matrix 处理对比(treatment contrast)与 sklearn OneHotEncoder(drop=reference) 等价于参照编码,但列顺序/名称不同。 - 标准化:R 端 glmnet/svm 内部标准化;Python 端在 Pipeline 显式标准化, Logistic 两支线均未惩罚,差异应很小但不必逐位一致。
结果怎么读
把 Python 端指标与 R 端第 5 章的锁定测试评价并排,核对的重点是量级一致、口径差异可解释:
results/tables/final_test_metrics.csv 与 results/tables/python_test_metrics.csv)
| 指标 | R 端(正式口径) | Python 端(迁移演示) |
|---|---|---|
| test n / 事件数 | 89 / 31 | 89 / 31(逐行同一批成员) |
| 锁定阈值 | 0.2497(训练集 OOF + Youden) | 0.2497(从锁定配置读取,不重选) |
| AUC | 0.7442(DeLong 95%CI 0.6362–0.8521) | 0.7447(roc_auc_score 点估计,未算 CI) |
| Brier | 0.1888 | 0.1905 |
| Sensitivity / Specificity / Accuracy | 0.7742 / 0.5862 / 0.6517 | 0.7419 / 0.5862 / 0.6404 |
| TP / FP / TN / FN | 24 / 24 / 34 / 7 | 23 / 24 / 34 / 8 |
读这张表的三条纪律:
- 成员一致是硬指标:train=211 / test=89、事件 31 必须逐行对上,对不上就是契约破坏,其余数字都不必看。
- AUC 差 0.0005 量级属预期:差异来自 solver(无惩罚 IRLS ↔︎
lbfgs)、CI 口径(DeLong ↔︎ 仅点估计)、因子编码的列序细节(treatment contrast ↔︎OneHotEncoder(drop=reference)),脚本已逐条记录在运行片段里。 - 混淆矩阵差 1 例也属预期:Python 端把 R 端的 1 个 TP 划到了 FN(23/8 vs 24/7),来自概率的微小数值差跨过同一锁定阈值——这正是”允许实现不同”的含义,不是模型变了。
首次出现的指标缩写:受试者工作特征曲线下面积(Area Under the ROC Curve, AUC)、折外(Out-of-Fold, OOF)预测、置信区间(Confidence Interval, CI)在第 4、5 章有完整定义,本章沿用同一口径。
验收清单
逐项核对,全部通过才算迁移完成:
常见错误
按翻车频率排序:
- 在 Python 端重新划分数据。 症状:图省事
train_test_split(..., random_state=同一个数),以为 seed 相同成员就相同。处理:R 与 Python 随机流实现不同,seed 值相同不等于成员相同;成员只能读 manifest。 - 为对齐 AUC 反复调参。 症状:改
penalty、改C、改 solver 直到小数点后三位一致。处理:实现差异是答案的一部分,如实记录即可;调参对齐制造的是虚假确定性。 - 预处理放在 Pipeline 外。 症状:先
fit_transform全数据再进模型。处理:插补与标准化必须进Pipeline,否则全体数据信息泄漏;这与 R 端的折内红线是同一条。 - 因子水平让数据”自己决定”。 症状:
OneHotEncoder不写categories,水平顺序随数据出现顺序变化。处理:levels 与参照从契约读;契约来自 R 端配置,是单一事实源。 - 阈值在 Python 端重选。 症状:对测试集重新找 Youden 阈值。处理:阈值是第 5 章锁定产物,从
locked_model_config.csv读;测试集只被评价一次,不参与任何选择。 - 把迁移演示当第二次正式验证。 症状:报告写”Python 复测 AUC 0.7447,与 R 相互印证”。处理:同一批数据上的复跑不提供新的独立证据;正式口径只有 R 端一条线。
复用时替换什么
把本章脚本搬进你的课题时,按清单替换:
| 固定不动的部分 | 需要替换的部分 |
|---|---|
| 两清单原则(契约一致、实现可不同) | Demo 数据与变量集(换你的队列与数据字典) |
| manifest 断言与”取成员”写法 | config.R 中的 outcome、正类、预测变量、因子水平与参照 |
| Pipeline 骨架(插补 + 编码 + 标准化 + 模型) | 预处理细节(如偏态变量的变换、更多因子变量) |
| 锁定配置读取逻辑 | 锁定模型类型与超参映射(脚本已支持 logistic / rf / svm / xgb 四支) |
| 差异记录与验收清单 | 你的报告口径(仍以先完成并锁定的一端为正式口径) |
迁移到正式案例(../../04_Cases/ 下的 Myocardial Infarction Complication 或 Early Stage Diabetes Risk Prediction)时,同样先完成 R 端主线并冻结契约,再启动 Python 复跑;顺序不可颠倒。
通用速查片段
五个短片段,与医学分析的日常动作对应,均用模拟数据可直接运行;复制后按”复用时检查”改造。交给 Agent 的标准说法:“先原样跑通模拟数据版本,再按检查清单换成我的数据。”
片段 1:R 读 CSV(显式列类型)
quick_io.R
# 做什么:显式声明列类型读入 CSV,核对后立即落盘派生文件
# 复用时检查:标识列按字符读;col_types 逐列对照数据字典;派生文件不覆盖原始文件
library(readr)
demo <- tibble::tibble(id = c("P001", "P002"), age = c(45, 62)) # 模拟数据
write_csv(demo, "demo_in.csv")
dat <- read_csv("demo_in.csv",
col_types = cols(id = col_character(), age = col_double()))
stopifnot(nrow(dat) == 2, is.character(dat$id), is.numeric(dat$age))
write_csv(dat, "processed.csv")片段 2:Python 读 CSV 与按键合并
quick_merge.py
# 做什么:读入结局表与检验表,按患者主键一对一合并
# 复用时检查:主键唯一性先断言;合并后行数与主表一致;validate="1:1" 不放过重复键
import pandas as pd
outcomes = pd.DataFrame({"id": ["P001", "P002", "P003"], "y": [0, 1, 0]}) # 模拟
labs = pd.DataFrame({"id": ["P001", "P002", "P003"], "crp": [3.1, 8.7, 2.4]})
assert outcomes["id"].is_unique and labs["id"].is_unique
df = outcomes.merge(labs, on="id", how="left", validate="1:1")
assert len(df) == len(outcomes)
print(df)片段 3:R 长宽转换(多次随访测量)
quick_pivot.R
# 做什么:把每个时点一列的宽表转成长表(每行一次测量),供分组汇总与画图
# 复用时检查:时点列的命名规律;转换后行数 = 例数 x 时点数;缺失时点如实保留
library(tidyr)
library(dplyr)
wide <- tibble::tibble(id = c("P001", "P002"),
sbp_v1 = c(128, 145), sbp_v2 = c(122, 139)) # 模拟数据
long <- wide %>%
pivot_longer(cols = starts_with("sbp_"), names_to = "visit",
names_prefix = "sbp_", values_to = "sbp")
print(long)片段 4:R 基础 ggplot(分组分布速查)
quick_ggplot.R
# 做什么:画连续变量按结局分组的直方图,快速看分布形态
# 复用时检查:连续变量才画直方图;导出用 ggsave 并指定 dpi;图只展示形态不替代检验
library(ggplot2)
set.seed(2026)
dat <- data.frame(y = rep(c("neg", "pos"), each = 50),
value = c(rnorm(50, 5.0, 1.2), rnorm(50, 6.1, 1.4))) # 模拟数据
ggplot(dat, aes(x = value, fill = y)) +
geom_histogram(bins = 20, alpha = 0.7, position = "identity") +
labs(x = "测量值", y = "例数", fill = "结局")片段 5:Python sklearn Pipeline 骨架
quick_pipeline.py
# 做什么:契约驱动的最小 Pipeline 骨架(数值插补+标准化,因子插补+独热),接任意模型
# 复用时检查:levels 与参照从契约读,不让数据自定;预处理永远进 Pipeline;模型只换一个格子
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
num_feats, fac_feats = ["age", "crp"], ["stage"] # 按契约替换
fac_categories = [["I", "II", "III"]] # 按契约替换
pre = ColumnTransformer([
("num", Pipeline([("imp", SimpleImputer(strategy="median")),
("sc", StandardScaler())]), num_feats),
("fac", Pipeline([("imp", SimpleImputer(strategy="most_frequent")),
("oh", OneHotEncoder(categories=fac_categories,
drop=["I"]))]), fac_feats),
])
pipe = Pipeline([("preprocess", pre),
("model", LogisticRegression(penalty=None, max_iter=1000))])相关资源
- 迁移的概念背景(为什么机器学习换语言不换流程):
../Book1_Course_Lectures/05_机器学习迁移与最终评价.qmd; - 内部验证与评价口径(OOF、ROC、Calibration、DCA 的定义):
../Book1_Course_Lectures/04_模型评价与内部验证.qmd; - Python 环境、虚拟环境与”让 Agent 装包”的纪律:
../Book2_Tools_Manual/05_让Agent使用R与Python.qmd; - 出错时的排查路线:
../Book2_Tools_Manual/06_出错了怎么办.qmd; - scikit-learn 官方文档(Pipeline、ColumnTransformer、OneHotEncoder、LogisticRegression):https://scikit-learn.org/stable/;
- 正式案例与运行指南:
../../04_Cases/README_案例运行指南.md。