项目一教学文档:房价预测 —— 从基准模型到集成

项目一教学文档:房价预测 ------ 从基准模型到集成

https://gitee.com/ghaweiuptgb/machine-learning-AI.git (代码包)

使用说明 :本文档是项目一的完整教学记录 。每完成一个步骤,我会把该步骤的详细教学过程(讲解、代码解读、概念、动手任务、验收标准、参考答案)写入对应章节。你可以按章节自学,也可以在对话中让我带你做,做完后回来对照本文档复习。

配套文件

  • 总体规划见 [../机器学习实战学习路线.md](../机器学习实战学习路线.md)
  • 你的个人笔记写在 [README.md](README.md)
  • 代码写在 [src/train.py](src/train.py)

代码规范(全程遵守)

  1. 逐行注释:每一行可执行代码都必须有注释说明。
  2. 图表中文 :绘图标题、坐标轴、图例等优先使用中文;通过 setup_chinese_plot() 配置中文字体。

讲解规范(全程遵守)

  1. 详细讲解:每步说明背景、目标、操作、结果含义;逻辑清晰、层层递进,便于初学者理解。
  2. 新名词必解释:首次出现的术语须给出定义、为何需要、在本项目中的含义。
  3. Mermaid 图解 :涉及流程、数据流向、概念关系时,必须在文档中使用 Mermaid 图(见下方示例)。

目录

步骤 标题 状态
[步骤 1](#步骤 标题 状态 步骤 1 搭建项目结构与环境 ✅ 已完成教学 步骤 2 加载数据并做初步 EDA ✅ 已完成教学 步骤 3 划分训练集与测试集 ✅ 已完成教学 步骤 4 建立基准模型 —— 线性回归 ✅ 已完成教学 步骤 5 特征缩放与 Ridge / Lasso ✅ 已完成教学 步骤 6 树模型 —— 随机森林与梯度提升 ✅ 已完成教学 步骤 7 简单特征工程 ✅ 已完成教学 步骤 8 总结与模型选择 ✅ 已完成教学) 搭建项目结构与环境 ✅ 已完成教学
[步骤 2](#步骤 标题 状态 步骤 1 搭建项目结构与环境 ✅ 已完成教学 步骤 2 加载数据并做初步 EDA ✅ 已完成教学 步骤 3 划分训练集与测试集 ✅ 已完成教学 步骤 4 建立基准模型 —— 线性回归 ✅ 已完成教学 步骤 5 特征缩放与 Ridge / Lasso ✅ 已完成教学 步骤 6 树模型 —— 随机森林与梯度提升 ✅ 已完成教学 步骤 7 简单特征工程 ✅ 已完成教学 步骤 8 总结与模型选择 ✅ 已完成教学) 加载数据并做初步 EDA ✅ 已完成教学
[步骤 3](#步骤 标题 状态 步骤 1 搭建项目结构与环境 ✅ 已完成教学 步骤 2 加载数据并做初步 EDA ✅ 已完成教学 步骤 3 划分训练集与测试集 ✅ 已完成教学 步骤 4 建立基准模型 —— 线性回归 ✅ 已完成教学 步骤 5 特征缩放与 Ridge / Lasso ✅ 已完成教学 步骤 6 树模型 —— 随机森林与梯度提升 ✅ 已完成教学 步骤 7 简单特征工程 ✅ 已完成教学 步骤 8 总结与模型选择 ✅ 已完成教学) 划分训练集与测试集 ✅ 已完成教学
[步骤 4](#步骤 标题 状态 步骤 1 搭建项目结构与环境 ✅ 已完成教学 步骤 2 加载数据并做初步 EDA ✅ 已完成教学 步骤 3 划分训练集与测试集 ✅ 已完成教学 步骤 4 建立基准模型 —— 线性回归 ✅ 已完成教学 步骤 5 特征缩放与 Ridge / Lasso ✅ 已完成教学 步骤 6 树模型 —— 随机森林与梯度提升 ✅ 已完成教学 步骤 7 简单特征工程 ✅ 已完成教学 步骤 8 总结与模型选择 ✅ 已完成教学) 建立基准模型 ------ 线性回归 ✅ 已完成教学
[步骤 5](#步骤 标题 状态 步骤 1 搭建项目结构与环境 ✅ 已完成教学 步骤 2 加载数据并做初步 EDA ✅ 已完成教学 步骤 3 划分训练集与测试集 ✅ 已完成教学 步骤 4 建立基准模型 —— 线性回归 ✅ 已完成教学 步骤 5 特征缩放与 Ridge / Lasso ✅ 已完成教学 步骤 6 树模型 —— 随机森林与梯度提升 ✅ 已完成教学 步骤 7 简单特征工程 ✅ 已完成教学 步骤 8 总结与模型选择 ✅ 已完成教学) 特征缩放与 Ridge / Lasso ✅ 已完成教学
[步骤 6](#步骤 标题 状态 步骤 1 搭建项目结构与环境 ✅ 已完成教学 步骤 2 加载数据并做初步 EDA ✅ 已完成教学 步骤 3 划分训练集与测试集 ✅ 已完成教学 步骤 4 建立基准模型 —— 线性回归 ✅ 已完成教学 步骤 5 特征缩放与 Ridge / Lasso ✅ 已完成教学 步骤 6 树模型 —— 随机森林与梯度提升 ✅ 已完成教学 步骤 7 简单特征工程 ✅ 已完成教学 步骤 8 总结与模型选择 ✅ 已完成教学) 树模型 ------ 随机森林与梯度提升 ✅ 已完成教学
[步骤 7](#步骤 标题 状态 步骤 1 搭建项目结构与环境 ✅ 已完成教学 步骤 2 加载数据并做初步 EDA ✅ 已完成教学 步骤 3 划分训练集与测试集 ✅ 已完成教学 步骤 4 建立基准模型 —— 线性回归 ✅ 已完成教学 步骤 5 特征缩放与 Ridge / Lasso ✅ 已完成教学 步骤 6 树模型 —— 随机森林与梯度提升 ✅ 已完成教学 步骤 7 简单特征工程 ✅ 已完成教学 步骤 8 总结与模型选择 ✅ 已完成教学) 简单特征工程 ✅ 已完成教学
[步骤 8](#步骤 标题 状态 步骤 1 搭建项目结构与环境 ✅ 已完成教学 步骤 2 加载数据并做初步 EDA ✅ 已完成教学 步骤 3 划分训练集与测试集 ✅ 已完成教学 步骤 4 建立基准模型 —— 线性回归 ✅ 已完成教学 步骤 5 特征缩放与 Ridge / Lasso ✅ 已完成教学 步骤 6 树模型 —— 随机森林与梯度提升 ✅ 已完成教学 步骤 7 简单特征工程 ✅ 已完成教学 步骤 8 总结与模型选择 ✅ 已完成教学) 总结与模型选择 ✅ 已完成教学

步骤 1:搭建项目结构与环境

状态:✅ 已完成教学(已按详细讲解规范增补名词解释与 Mermaid 图)

1.1 本步目标

不做任何机器学习,只完成一件事:把「做项目」的工作环境搭好。后续 5 个项目都会复用同一套目录结构和编码习惯。

1.2 这一步在解决什么问题?

很多人学机器学习时,会把所有代码写在一个文件里,数据、模型、笔记混在一起。项目小的时候没问题,一旦步骤变多就很难维护。

专业做法是:

  • 代码 放在 src/
  • 数据 放在 data/
  • 学习笔记 放在 README.md
  • 教学讲解 放在 教学文档.md(就是本文件)

这叫项目化思维。现在多花 5 分钟整理,后面会省很多时间。

1.2.5 本步在整体流程中的位置

本步是整条学习链的起点:先搭好「工地」,后面才能搬砖(数据)、盖楼(模型)。
#mermaid-svg-FnjHhQu00IhPXIuC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FnjHhQu00IhPXIuC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FnjHhQu00IhPXIuC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FnjHhQu00IhPXIuC .error-icon{fill:#552222;}#mermaid-svg-FnjHhQu00IhPXIuC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FnjHhQu00IhPXIuC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FnjHhQu00IhPXIuC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FnjHhQu00IhPXIuC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FnjHhQu00IhPXIuC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FnjHhQu00IhPXIuC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FnjHhQu00IhPXIuC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FnjHhQu00IhPXIuC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FnjHhQu00IhPXIuC .marker.cross{stroke:#333333;}#mermaid-svg-FnjHhQu00IhPXIuC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FnjHhQu00IhPXIuC p{margin:0;}#mermaid-svg-FnjHhQu00IhPXIuC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FnjHhQu00IhPXIuC .cluster-label text{fill:#333;}#mermaid-svg-FnjHhQu00IhPXIuC .cluster-label span{color:#333;}#mermaid-svg-FnjHhQu00IhPXIuC .cluster-label span p{background-color:transparent;}#mermaid-svg-FnjHhQu00IhPXIuC .label text,#mermaid-svg-FnjHhQu00IhPXIuC span{fill:#333;color:#333;}#mermaid-svg-FnjHhQu00IhPXIuC .node rect,#mermaid-svg-FnjHhQu00IhPXIuC .node circle,#mermaid-svg-FnjHhQu00IhPXIuC .node ellipse,#mermaid-svg-FnjHhQu00IhPXIuC .node polygon,#mermaid-svg-FnjHhQu00IhPXIuC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FnjHhQu00IhPXIuC .rough-node .label text,#mermaid-svg-FnjHhQu00IhPXIuC .node .label text,#mermaid-svg-FnjHhQu00IhPXIuC .image-shape .label,#mermaid-svg-FnjHhQu00IhPXIuC .icon-shape .label{text-anchor:middle;}#mermaid-svg-FnjHhQu00IhPXIuC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FnjHhQu00IhPXIuC .rough-node .label,#mermaid-svg-FnjHhQu00IhPXIuC .node .label,#mermaid-svg-FnjHhQu00IhPXIuC .image-shape .label,#mermaid-svg-FnjHhQu00IhPXIuC .icon-shape .label{text-align:center;}#mermaid-svg-FnjHhQu00IhPXIuC .node.clickable{cursor:pointer;}#mermaid-svg-FnjHhQu00IhPXIuC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FnjHhQu00IhPXIuC .arrowheadPath{fill:#333333;}#mermaid-svg-FnjHhQu00IhPXIuC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FnjHhQu00IhPXIuC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FnjHhQu00IhPXIuC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FnjHhQu00IhPXIuC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FnjHhQu00IhPXIuC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FnjHhQu00IhPXIuC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FnjHhQu00IhPXIuC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FnjHhQu00IhPXIuC .cluster text{fill:#333;}#mermaid-svg-FnjHhQu00IhPXIuC .cluster span{color:#333;}#mermaid-svg-FnjHhQu00IhPXIuC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FnjHhQu00IhPXIuC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FnjHhQu00IhPXIuC rect.text{fill:none;stroke-width:0;}#mermaid-svg-FnjHhQu00IhPXIuC .icon-shape,#mermaid-svg-FnjHhQu00IhPXIuC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FnjHhQu00IhPXIuC .icon-shape p,#mermaid-svg-FnjHhQu00IhPXIuC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FnjHhQu00IhPXIuC .icon-shape .label rect,#mermaid-svg-FnjHhQu00IhPXIuC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FnjHhQu00IhPXIuC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FnjHhQu00IhPXIuC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FnjHhQu00IhPXIuC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 步骤1 搭环境与目录
步骤2 加载数据 EDA
步骤3 划分训练/测试
步骤4 基准模型
步骤5~8 优化与选型

1.2.6 名词解释(本步首次出现)

名词 是什么 为什么需要 在本项目中
项目化思维 把代码、数据、文档分目录存放的习惯 避免所有内容堆在一个文件里,后期无法维护 src/ 写代码,data/ 放数据,教学文档.md 写讲解
函数(function) 一段完成特定任务的代码块,可重复调用 把「加载数据」「训练模型」分开,职责清晰 load_data() 专门管数据,main() 管整体流程
pass Python 占位符,表示「这里先空着」 函数体不能为空,步骤 1 先搭骨架 load_data() 里暂时用 pass,步骤 2 再填真实代码
main() 程序主入口,运行脚本时从这里开始 统一执行顺序,避免代码散落各处 当前只打印「项目启动成功」,后面会扩展
if __name__ == "__main__" Python 脚本入口守卫 区分「直接运行」与「被 import」 直接运行 train.py 才执行 main()
requirements.txt 依赖清单文件 记录项目需要哪些库,便于一键安装 列出 pandas、sklearn 等
回归问题(预告) 预测连续数值(如房价 1.5万、2.3万) 本项目目标是预测房价中位数 与「分类」(预测类别)相对

1.2.7 项目目录关系图

#mermaid-svg-FtHSCbWHHlk7Mor3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FtHSCbWHHlk7Mor3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FtHSCbWHHlk7Mor3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FtHSCbWHHlk7Mor3 .error-icon{fill:#552222;}#mermaid-svg-FtHSCbWHHlk7Mor3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FtHSCbWHHlk7Mor3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FtHSCbWHHlk7Mor3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FtHSCbWHHlk7Mor3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FtHSCbWHHlk7Mor3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FtHSCbWHHlk7Mor3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FtHSCbWHHlk7Mor3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FtHSCbWHHlk7Mor3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FtHSCbWHHlk7Mor3 .marker.cross{stroke:#333333;}#mermaid-svg-FtHSCbWHHlk7Mor3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FtHSCbWHHlk7Mor3 p{margin:0;}#mermaid-svg-FtHSCbWHHlk7Mor3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FtHSCbWHHlk7Mor3 .cluster-label text{fill:#333;}#mermaid-svg-FtHSCbWHHlk7Mor3 .cluster-label span{color:#333;}#mermaid-svg-FtHSCbWHHlk7Mor3 .cluster-label span p{background-color:transparent;}#mermaid-svg-FtHSCbWHHlk7Mor3 .label text,#mermaid-svg-FtHSCbWHHlk7Mor3 span{fill:#333;color:#333;}#mermaid-svg-FtHSCbWHHlk7Mor3 .node rect,#mermaid-svg-FtHSCbWHHlk7Mor3 .node circle,#mermaid-svg-FtHSCbWHHlk7Mor3 .node ellipse,#mermaid-svg-FtHSCbWHHlk7Mor3 .node polygon,#mermaid-svg-FtHSCbWHHlk7Mor3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FtHSCbWHHlk7Mor3 .rough-node .label text,#mermaid-svg-FtHSCbWHHlk7Mor3 .node .label text,#mermaid-svg-FtHSCbWHHlk7Mor3 .image-shape .label,#mermaid-svg-FtHSCbWHHlk7Mor3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-FtHSCbWHHlk7Mor3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FtHSCbWHHlk7Mor3 .rough-node .label,#mermaid-svg-FtHSCbWHHlk7Mor3 .node .label,#mermaid-svg-FtHSCbWHHlk7Mor3 .image-shape .label,#mermaid-svg-FtHSCbWHHlk7Mor3 .icon-shape .label{text-align:center;}#mermaid-svg-FtHSCbWHHlk7Mor3 .node.clickable{cursor:pointer;}#mermaid-svg-FtHSCbWHHlk7Mor3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FtHSCbWHHlk7Mor3 .arrowheadPath{fill:#333333;}#mermaid-svg-FtHSCbWHHlk7Mor3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FtHSCbWHHlk7Mor3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FtHSCbWHHlk7Mor3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FtHSCbWHHlk7Mor3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FtHSCbWHHlk7Mor3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FtHSCbWHHlk7Mor3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FtHSCbWHHlk7Mor3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FtHSCbWHHlk7Mor3 .cluster text{fill:#333;}#mermaid-svg-FtHSCbWHHlk7Mor3 .cluster span{color:#333;}#mermaid-svg-FtHSCbWHHlk7Mor3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FtHSCbWHHlk7Mor3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FtHSCbWHHlk7Mor3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-FtHSCbWHHlk7Mor3 .icon-shape,#mermaid-svg-FtHSCbWHHlk7Mor3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FtHSCbWHHlk7Mor3 .icon-shape p,#mermaid-svg-FtHSCbWHHlk7Mor3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FtHSCbWHHlk7Mor3 .icon-shape .label rect,#mermaid-svg-FtHSCbWHHlk7Mor3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FtHSCbWHHlk7Mor3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FtHSCbWHHlk7Mor3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FtHSCbWHHlk7Mor3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 机器学习/ 根目录
机器学习实战学习路线.md 总规划
requirements.txt 依赖
project_01_housing/
教学文档.md 详细讲解
README.md 你的笔记
data/ 数据文件
src/train.py 主程序
reports/figures/ 图表输出

1.3 任务清单

  • 创建 project_01_housing/ 目录结构
  • 安装依赖:pandasnumpyscikit-learnmatplotlibseaborn
  • 编写 src/train.py 骨架(含 load_data()main()
  • 创建 requirements.txtREADME.md
  • 运行 python src/train.py 验证环境

1.4 目录结构说明

完成本步后,你的项目应如下所示:

复制代码
机器学习/
├── 机器学习实战学习路线.md      # 六个项目的总体规划
├── requirements.txt             # 全部项目共用依赖
└── project_01_housing/
    ├── 教学文档.md               # ← 你正在看的文件(详细教学过程)
    ├── README.md                 # 你的个人学习笔记
    ├── data/                     # 存放外部 CSV(本数据集由 sklearn 在线加载,此目录备用)
    ├── notebooks/                # 可选:Jupyter 交互探索
    └── src/
        └── train.py                # 主训练脚本,核心代码都写在这里

每个目录的职责:

目录/文件 职责
src/train.py 可重复运行的训练脚本,是项目的「主程序」
data/ 存放原始或下载的数据文件
notebooks/ 适合快速试验、画图;成熟代码应迁回 train.py
README.md 你自己的简短笔记:日期、结论、疑问
教学文档.md 完整教学讲解,用于复习和对照

1.5 核心代码解读

当前 src/train.py 内容:

python 复制代码
"""
项目一:加州房价预测
主训练脚本 ------ 随着学习推进,我们会逐步往这里添加代码。
"""


def load_data():
    """加载加州房价数据集(步骤 2 会实现)。"""
    pass


def main():
    print("项目启动成功")
    print("当前步骤:步骤 1 ------ 项目结构与环境搭建")


if __name__ == "__main__":
    main()

逐段理解:

(1)def load_data():
  • 专门负责「加载数据」的函数。
  • 现在里面是 pass(占位,表示「暂时什么都不做」)。
  • 步骤 2 会在这里写入真正的数据加载逻辑。
  • 为什么要单独一个函数? 职责分离------以后换数据集时,只改这一处。
(2)def main():
  • 程序的主入口,整个项目的执行流程从这里开始。
  • 随着学习推进,main() 会依次调用:加载数据 → 划分数据集 → 训练模型 → 评估结果。
  • 现在只打印两行字,用来确认环境正常。
(3)if __name__ == "__main__":

这是 Python 的标准入口写法,必须理解:

python 复制代码
if __name__ == "__main__":
    main()
运行方式 会发生什么
在终端执行 python src/train.py __name__ 等于 "__main__",会执行 main()
被其他文件 import __name__ 等于模块名,不会 自动执行 main()

好处:这个文件既可以独立运行 ,也可以被其他脚本导入复用,而不会产生副作用。
#mermaid-svg-7LzXmMwbOz5IPmBG{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7LzXmMwbOz5IPmBG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7LzXmMwbOz5IPmBG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7LzXmMwbOz5IPmBG .error-icon{fill:#552222;}#mermaid-svg-7LzXmMwbOz5IPmBG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7LzXmMwbOz5IPmBG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7LzXmMwbOz5IPmBG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7LzXmMwbOz5IPmBG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7LzXmMwbOz5IPmBG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7LzXmMwbOz5IPmBG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7LzXmMwbOz5IPmBG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7LzXmMwbOz5IPmBG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7LzXmMwbOz5IPmBG .marker.cross{stroke:#333333;}#mermaid-svg-7LzXmMwbOz5IPmBG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7LzXmMwbOz5IPmBG p{margin:0;}#mermaid-svg-7LzXmMwbOz5IPmBG .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7LzXmMwbOz5IPmBG .cluster-label text{fill:#333;}#mermaid-svg-7LzXmMwbOz5IPmBG .cluster-label span{color:#333;}#mermaid-svg-7LzXmMwbOz5IPmBG .cluster-label span p{background-color:transparent;}#mermaid-svg-7LzXmMwbOz5IPmBG .label text,#mermaid-svg-7LzXmMwbOz5IPmBG span{fill:#333;color:#333;}#mermaid-svg-7LzXmMwbOz5IPmBG .node rect,#mermaid-svg-7LzXmMwbOz5IPmBG .node circle,#mermaid-svg-7LzXmMwbOz5IPmBG .node ellipse,#mermaid-svg-7LzXmMwbOz5IPmBG .node polygon,#mermaid-svg-7LzXmMwbOz5IPmBG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7LzXmMwbOz5IPmBG .rough-node .label text,#mermaid-svg-7LzXmMwbOz5IPmBG .node .label text,#mermaid-svg-7LzXmMwbOz5IPmBG .image-shape .label,#mermaid-svg-7LzXmMwbOz5IPmBG .icon-shape .label{text-anchor:middle;}#mermaid-svg-7LzXmMwbOz5IPmBG .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7LzXmMwbOz5IPmBG .rough-node .label,#mermaid-svg-7LzXmMwbOz5IPmBG .node .label,#mermaid-svg-7LzXmMwbOz5IPmBG .image-shape .label,#mermaid-svg-7LzXmMwbOz5IPmBG .icon-shape .label{text-align:center;}#mermaid-svg-7LzXmMwbOz5IPmBG .node.clickable{cursor:pointer;}#mermaid-svg-7LzXmMwbOz5IPmBG .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7LzXmMwbOz5IPmBG .arrowheadPath{fill:#333333;}#mermaid-svg-7LzXmMwbOz5IPmBG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7LzXmMwbOz5IPmBG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7LzXmMwbOz5IPmBG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7LzXmMwbOz5IPmBG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7LzXmMwbOz5IPmBG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7LzXmMwbOz5IPmBG .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7LzXmMwbOz5IPmBG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7LzXmMwbOz5IPmBG .cluster text{fill:#333;}#mermaid-svg-7LzXmMwbOz5IPmBG .cluster span{color:#333;}#mermaid-svg-7LzXmMwbOz5IPmBG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7LzXmMwbOz5IPmBG .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7LzXmMwbOz5IPmBG rect.text{fill:none;stroke-width:0;}#mermaid-svg-7LzXmMwbOz5IPmBG .icon-shape,#mermaid-svg-7LzXmMwbOz5IPmBG .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7LzXmMwbOz5IPmBG .icon-shape p,#mermaid-svg-7LzXmMwbOz5IPmBG .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7LzXmMwbOz5IPmBG .icon-shape .label rect,#mermaid-svg-7LzXmMwbOz5IPmBG .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7LzXmMwbOz5IPmBG .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7LzXmMwbOz5IPmBG .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7LzXmMwbOz5IPmBG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否被import
运行 python src/train.py
是否为 main 模块
执行 main
不执行 main 仅加载定义
打印项目启动成功

1.6 依赖说明

根目录 requirements.txt 内容:

复制代码
pandas>=2.0
numpy>=1.24
scikit-learn>=1.3
matplotlib>=3.7
seaborn>=0.12
joblib>=1.3

安装命令(在 机器学习/ 根目录执行):

powershell 复制代码
pip install -r requirements.txt

各库用途(先有个印象,用到时再细讲):

用途
pandas 表格数据处理(类似 Excel 的编程版)
numpy 数值计算、矩阵运算
scikit-learn 机器学习算法与工具(本项目核心)
matplotlib 画图
seaborn 更美观的统计图(基于 matplotlib)
joblib 保存和加载训练好的模型(步骤 8 使用)

1.7 动手任务

请在你的电脑上依次完成:

任务 A:运行脚本

powershell 复制代码
cd "d:\JavaCode\机器学习\project_01_housing"
python src/train.py

预期输出:

复制代码
项目启动成功
当前步骤:步骤 1 ------ 项目结构与环境搭建

若终端中文显示乱码,不影响学习,只要没有报错(Traceback)即可。

任务 B:小改动(建议)

打开 src/train.py,在 main() 里加一行:

python 复制代码
def main():
    print("项目启动成功")
    print("当前步骤:步骤 1 ------ 项目结构与环境搭建")
    print("你好,机器学习!")  # ← 新增这一行

保存后再次运行,确认能看到新增输出。目的是熟悉「改代码 → 保存 → 运行 → 看结果」的循环。

任务 C:写学习笔记

打开 README.md,在步骤 1 下填写日期和一句话感受。

1.8 验收标准

  • 目录结构与上文一致
  • python src/train.py 无报错,打印「项目启动成功」
  • 能解释 load_data()main()if __name__ == "__main__" 各自的作用
  • README.md 中已记录本步完成情况

1.9 本步核心概念

1.9 动手任务与验收标准参考答案

以下为教学标准答案,便于自学对照;README.md 学习记录仍建议用自己的话写。

动手任务答案
任务 参考答案
A 运行 python src/train.py,应看到「项目启动成功」,无 Traceback。
B 增加 print("你好,机器学习!") 后多一行输出。
C 在 README 步骤 1 填写日期与一句话感受。
验收标准答案
验收项 参考答案
目录结构 src/train.pydata/reports/models/教学文档.md
脚本无报错 打印「项目启动成功」。
三个概念 load_data() 加载数据;main() 主流程;if __name__=="__main__" 仅直接运行时执行 main。
README 步骤 1 已记录。
概念 解释
项目化思维 代码、数据、文档分离,结构清晰,便于维护和复现
函数拆分 一个函数做一件事(加载、训练、评估分开)
脚本入口 if __name__ == "__main__" 保证直接运行才执行主流程

1.10 常见问题

Q: pass 是什么意思?

A:占位符,表示「这里暂时空着,以后再写」。函数体不能为空,所以用 pass 占一行。

Q:为什么不用 Jupyter Notebook 从头写到尾?

A:Notebook 适合探索;train.py 适合可重复运行的完整流程。我们会两者结合:notebooks/ 试验,成熟代码写入 src/train.py

Q: data/ 现在是空的,正常吗?

A:正常。加州房价数据由 sklearn 内置接口在线加载,不需要手动下载 CSV。data/ 为后续扩展或其他数据源备用。

1.11 项目全景预告

完成全部 8 步后,你将用 加州房价数据集 (约 20,640 条记录、8 个特征)预测房价中位数 MedHouseVal

这是典型的 回归问题

  • 回归:预测连续数值(房价可以是 1.5万、2.3万......)
  • 分类(对比理解):预测类别(如「是/否」「猫/狗」)

#mermaid-svg-Kcluvr6yyijzHXtB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Kcluvr6yyijzHXtB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Kcluvr6yyijzHXtB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Kcluvr6yyijzHXtB .error-icon{fill:#552222;}#mermaid-svg-Kcluvr6yyijzHXtB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Kcluvr6yyijzHXtB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Kcluvr6yyijzHXtB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Kcluvr6yyijzHXtB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Kcluvr6yyijzHXtB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Kcluvr6yyijzHXtB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Kcluvr6yyijzHXtB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Kcluvr6yyijzHXtB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Kcluvr6yyijzHXtB .marker.cross{stroke:#333333;}#mermaid-svg-Kcluvr6yyijzHXtB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Kcluvr6yyijzHXtB p{margin:0;}#mermaid-svg-Kcluvr6yyijzHXtB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Kcluvr6yyijzHXtB .cluster-label text{fill:#333;}#mermaid-svg-Kcluvr6yyijzHXtB .cluster-label span{color:#333;}#mermaid-svg-Kcluvr6yyijzHXtB .cluster-label span p{background-color:transparent;}#mermaid-svg-Kcluvr6yyijzHXtB .label text,#mermaid-svg-Kcluvr6yyijzHXtB span{fill:#333;color:#333;}#mermaid-svg-Kcluvr6yyijzHXtB .node rect,#mermaid-svg-Kcluvr6yyijzHXtB .node circle,#mermaid-svg-Kcluvr6yyijzHXtB .node ellipse,#mermaid-svg-Kcluvr6yyijzHXtB .node polygon,#mermaid-svg-Kcluvr6yyijzHXtB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Kcluvr6yyijzHXtB .rough-node .label text,#mermaid-svg-Kcluvr6yyijzHXtB .node .label text,#mermaid-svg-Kcluvr6yyijzHXtB .image-shape .label,#mermaid-svg-Kcluvr6yyijzHXtB .icon-shape .label{text-anchor:middle;}#mermaid-svg-Kcluvr6yyijzHXtB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Kcluvr6yyijzHXtB .rough-node .label,#mermaid-svg-Kcluvr6yyijzHXtB .node .label,#mermaid-svg-Kcluvr6yyijzHXtB .image-shape .label,#mermaid-svg-Kcluvr6yyijzHXtB .icon-shape .label{text-align:center;}#mermaid-svg-Kcluvr6yyijzHXtB .node.clickable{cursor:pointer;}#mermaid-svg-Kcluvr6yyijzHXtB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Kcluvr6yyijzHXtB .arrowheadPath{fill:#333333;}#mermaid-svg-Kcluvr6yyijzHXtB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Kcluvr6yyijzHXtB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Kcluvr6yyijzHXtB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Kcluvr6yyijzHXtB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Kcluvr6yyijzHXtB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Kcluvr6yyijzHXtB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Kcluvr6yyijzHXtB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Kcluvr6yyijzHXtB .cluster text{fill:#333;}#mermaid-svg-Kcluvr6yyijzHXtB .cluster span{color:#333;}#mermaid-svg-Kcluvr6yyijzHXtB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Kcluvr6yyijzHXtB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Kcluvr6yyijzHXtB rect.text{fill:none;stroke-width:0;}#mermaid-svg-Kcluvr6yyijzHXtB .icon-shape,#mermaid-svg-Kcluvr6yyijzHXtB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Kcluvr6yyijzHXtB .icon-shape p,#mermaid-svg-Kcluvr6yyijzHXtB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Kcluvr6yyijzHXtB .icon-shape .label rect,#mermaid-svg-Kcluvr6yyijzHXtB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Kcluvr6yyijzHXtB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Kcluvr6yyijzHXtB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Kcluvr6yyijzHXtB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 机器学习任务
回归:预测连续数值
分类:预测类别标签
例:房价 温度 销量
本项目:MedHouseVal
例:是否欺诈 猫或狗

步骤 2 将第一次真正接触数据。

1.12 学习记录(请你填写)

  • 完成日期
  • 动手任务完成情况:任务 A / B / C
  • 我的理解(用自己的话写 1~3 句):
  • 疑问(如有):

步骤 2:加载数据并做初步 EDA

状态:✅ 已完成教学(已按详细讲解规范增补名词解释与 Mermaid 图)

2.1 本步目标

第一次真正接触机器学习数据。完成三件事:

  1. 加载加州房价数据集
  2. 认识每一列代表什么(特征 vs 标签)
  3. 探索数据分布与特征和房价的关系(EDA)

EDA(Exploratory Data Analysis,探索性数据分析)是建模前的「侦察」:不急着训练模型,先把数据摸清楚。

2.2 这一步在解决什么问题?

模型不是凭空猜的,它从历史数据里学规律。若连数据长什么样、要预测什么都不知道,后面的训练容易踩坑。

本步要回答四个问题:

问题 怎么回答
有多少条数据? df.shape
每列是什么类型?有无缺失? df.info()、缺失值统计
数值大概什么范围? df.describe()
哪些因素和房价有关? 相关性、散点图

2.2.5 本步在整体流程中的位置

步骤 1 搭好了环境;步骤 2 是第一次接触真实数据。只有先「看清数据」,后面的建模才有依据。
#mermaid-svg-UgWpKNrbykqfO6vE{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UgWpKNrbykqfO6vE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UgWpKNrbykqfO6vE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UgWpKNrbykqfO6vE .error-icon{fill:#552222;}#mermaid-svg-UgWpKNrbykqfO6vE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UgWpKNrbykqfO6vE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UgWpKNrbykqfO6vE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UgWpKNrbykqfO6vE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UgWpKNrbykqfO6vE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UgWpKNrbykqfO6vE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UgWpKNrbykqfO6vE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UgWpKNrbykqfO6vE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UgWpKNrbykqfO6vE .marker.cross{stroke:#333333;}#mermaid-svg-UgWpKNrbykqfO6vE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UgWpKNrbykqfO6vE p{margin:0;}#mermaid-svg-UgWpKNrbykqfO6vE .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-UgWpKNrbykqfO6vE .cluster-label text{fill:#333;}#mermaid-svg-UgWpKNrbykqfO6vE .cluster-label span{color:#333;}#mermaid-svg-UgWpKNrbykqfO6vE .cluster-label span p{background-color:transparent;}#mermaid-svg-UgWpKNrbykqfO6vE .label text,#mermaid-svg-UgWpKNrbykqfO6vE span{fill:#333;color:#333;}#mermaid-svg-UgWpKNrbykqfO6vE .node rect,#mermaid-svg-UgWpKNrbykqfO6vE .node circle,#mermaid-svg-UgWpKNrbykqfO6vE .node ellipse,#mermaid-svg-UgWpKNrbykqfO6vE .node polygon,#mermaid-svg-UgWpKNrbykqfO6vE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UgWpKNrbykqfO6vE .rough-node .label text,#mermaid-svg-UgWpKNrbykqfO6vE .node .label text,#mermaid-svg-UgWpKNrbykqfO6vE .image-shape .label,#mermaid-svg-UgWpKNrbykqfO6vE .icon-shape .label{text-anchor:middle;}#mermaid-svg-UgWpKNrbykqfO6vE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-UgWpKNrbykqfO6vE .rough-node .label,#mermaid-svg-UgWpKNrbykqfO6vE .node .label,#mermaid-svg-UgWpKNrbykqfO6vE .image-shape .label,#mermaid-svg-UgWpKNrbykqfO6vE .icon-shape .label{text-align:center;}#mermaid-svg-UgWpKNrbykqfO6vE .node.clickable{cursor:pointer;}#mermaid-svg-UgWpKNrbykqfO6vE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-UgWpKNrbykqfO6vE .arrowheadPath{fill:#333333;}#mermaid-svg-UgWpKNrbykqfO6vE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-UgWpKNrbykqfO6vE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-UgWpKNrbykqfO6vE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UgWpKNrbykqfO6vE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UgWpKNrbykqfO6vE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UgWpKNrbykqfO6vE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-UgWpKNrbykqfO6vE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-UgWpKNrbykqfO6vE .cluster text{fill:#333;}#mermaid-svg-UgWpKNrbykqfO6vE .cluster span{color:#333;}#mermaid-svg-UgWpKNrbykqfO6vE div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-UgWpKNrbykqfO6vE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UgWpKNrbykqfO6vE rect.text{fill:none;stroke-width:0;}#mermaid-svg-UgWpKNrbykqfO6vE .icon-shape,#mermaid-svg-UgWpKNrbykqfO6vE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UgWpKNrbykqfO6vE .icon-shape p,#mermaid-svg-UgWpKNrbykqfO6vE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-UgWpKNrbykqfO6vE .icon-shape .label rect,#mermaid-svg-UgWpKNrbykqfO6vE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UgWpKNrbykqfO6vE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-UgWpKNrbykqfO6vE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-UgWpKNrbykqfO6vE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否需清洗
步骤1 环境就绪
步骤2 EDA 探索数据
数据是否可用?
步骤3 划分训练测试
先清洗数据

2.2.6 名词解释(本步首次出现)

名词 是什么 为什么需要 在本项目中 易混淆
EDA Exploratory Data Analysis,探索性数据分析 建模前必须先了解数据分布、缺失、异常 看 shape、画图、算相关性 不是建模,是「侦察」
DataFrame Pandas 的二维表格结构 机器学习表格数据的标准容器 load_data() 返回的就是 DataFrame 类似 Excel 表
特征 Feature 模型的输入变量 模型根据特征做预测 8 列:收入、房龄、房间数等 不是标签
标签 Label 要预测的目标变量 监督学习需要「标准答案」来学习 MedHouseVal 房价中位数 也称 Target
样本 Sample 一条观测记录 统计与训练的基本单位 一行 = 一个加州区域 不是单个房屋
皮尔逊相关系数 衡量两列数值线性相关程度,范围 -1~1 快速发现哪些特征与房价有关 MedInc 约 +0.69 最强 相关≠因果
右偏分布 多数值集中在左侧,右侧有长尾 影响模型与指标解读 房价 histogram 低价多、高价少 与左偏相反
数据缓存 下载一次保存本地,后续直接读取 加速、离线、可复现 data/california_housing.csv 不是每次联网下载

2.2.7 特征、标签、样本三者关系

#mermaid-svg-7nxmDwwKhTTNs8RO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7nxmDwwKhTTNs8RO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7nxmDwwKhTTNs8RO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7nxmDwwKhTTNs8RO .error-icon{fill:#552222;}#mermaid-svg-7nxmDwwKhTTNs8RO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7nxmDwwKhTTNs8RO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7nxmDwwKhTTNs8RO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7nxmDwwKhTTNs8RO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7nxmDwwKhTTNs8RO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7nxmDwwKhTTNs8RO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7nxmDwwKhTTNs8RO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7nxmDwwKhTTNs8RO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7nxmDwwKhTTNs8RO .marker.cross{stroke:#333333;}#mermaid-svg-7nxmDwwKhTTNs8RO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7nxmDwwKhTTNs8RO p{margin:0;}#mermaid-svg-7nxmDwwKhTTNs8RO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7nxmDwwKhTTNs8RO .cluster-label text{fill:#333;}#mermaid-svg-7nxmDwwKhTTNs8RO .cluster-label span{color:#333;}#mermaid-svg-7nxmDwwKhTTNs8RO .cluster-label span p{background-color:transparent;}#mermaid-svg-7nxmDwwKhTTNs8RO .label text,#mermaid-svg-7nxmDwwKhTTNs8RO span{fill:#333;color:#333;}#mermaid-svg-7nxmDwwKhTTNs8RO .node rect,#mermaid-svg-7nxmDwwKhTTNs8RO .node circle,#mermaid-svg-7nxmDwwKhTTNs8RO .node ellipse,#mermaid-svg-7nxmDwwKhTTNs8RO .node polygon,#mermaid-svg-7nxmDwwKhTTNs8RO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7nxmDwwKhTTNs8RO .rough-node .label text,#mermaid-svg-7nxmDwwKhTTNs8RO .node .label text,#mermaid-svg-7nxmDwwKhTTNs8RO .image-shape .label,#mermaid-svg-7nxmDwwKhTTNs8RO .icon-shape .label{text-anchor:middle;}#mermaid-svg-7nxmDwwKhTTNs8RO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7nxmDwwKhTTNs8RO .rough-node .label,#mermaid-svg-7nxmDwwKhTTNs8RO .node .label,#mermaid-svg-7nxmDwwKhTTNs8RO .image-shape .label,#mermaid-svg-7nxmDwwKhTTNs8RO .icon-shape .label{text-align:center;}#mermaid-svg-7nxmDwwKhTTNs8RO .node.clickable{cursor:pointer;}#mermaid-svg-7nxmDwwKhTTNs8RO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7nxmDwwKhTTNs8RO .arrowheadPath{fill:#333333;}#mermaid-svg-7nxmDwwKhTTNs8RO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7nxmDwwKhTTNs8RO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7nxmDwwKhTTNs8RO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7nxmDwwKhTTNs8RO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7nxmDwwKhTTNs8RO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7nxmDwwKhTTNs8RO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7nxmDwwKhTTNs8RO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7nxmDwwKhTTNs8RO .cluster text{fill:#333;}#mermaid-svg-7nxmDwwKhTTNs8RO .cluster span{color:#333;}#mermaid-svg-7nxmDwwKhTTNs8RO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7nxmDwwKhTTNs8RO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7nxmDwwKhTTNs8RO rect.text{fill:none;stroke-width:0;}#mermaid-svg-7nxmDwwKhTTNs8RO .icon-shape,#mermaid-svg-7nxmDwwKhTTNs8RO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7nxmDwwKhTTNs8RO .icon-shape p,#mermaid-svg-7nxmDwwKhTTNs8RO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7nxmDwwKhTTNs8RO .icon-shape .label rect,#mermaid-svg-7nxmDwwKhTTNs8RO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7nxmDwwKhTTNs8RO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7nxmDwwKhTTNs8RO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7nxmDwwKhTTNs8RO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 一条样本
MedInc 收入
HouseAge 房龄
共8个特征
MedHouseVal 房价
模型输入 X
模型目标 y

2.3 任务清单

  • fetch_california_housing / 备用源加载为 DataFrame
  • 查看 shapeinfo()describe()
  • 检查缺失值
  • 画 3 张图:目标分布、相关性条形图、收入 vs 房价散点图
  • 将数据缓存到 data/california_housing.csv

2.4 数据集说明

加州房价数据集记录的是加州各「街区 / 区域」的统计信息(不是每一套独立房屋,而是一个区域的汇总)。

列名 中文含义 角色
MedInc 该区域收入中位数 特征
HouseAge 房屋年龄中位数 特征
AveRooms 平均房间数 特征
AveBedrms 平均卧室数 特征
Population 人口 特征
AveOccup 平均入住人数 特征
Latitude 纬度 特征
Longitude 经度 特征
MedHouseVal 房价中位数(要预测的目标) 标签

三个核心概念:

概念 英文 本项目中指什么
特征 Feature 上面 8 列输入,如收入、房间数
标签 Label / Target MedHouseVal,我们要预测的房价
样本 Sample 表格中的一行,代表一个区域的一条记录

关于房价单位: MedHouseVal = 2.0 表示该区域房价中位数约为 20 万美元 (单位是「十万美元」)。数据集中上限常被截断在 5.0(即 50 万美元)。

2.5 运行本步

在项目目录执行:

powershell 复制代码
cd "d:\JavaCode\机器学习\project_01_housing"
python src/train.py

预期输出要点:

  • 样本数约 20,433 条(与 sklearn 官方 20,640 接近;备用数据源清洗后略少)
  • 无缺失值
  • 与房价相关性最强:MedInc(收入中位数) ,相关系数约 +0.69
  • 生成 3 张图到 reports/figures/

2.6 数据加载逻辑解读

load_data() 采用了「三级回退 + 本地缓存」策略(真实项目中很常见):

python 复制代码
def load_data() -> pd.DataFrame:
    # 1. 优先读本地缓存(最快、可离线)
    if DATA_PATH.exists():
        return pd.read_csv(DATA_PATH)

    # 2. 尝试 sklearn 在线下载
    try:
        housing = fetch_california_housing(as_frame=True)
        df = housing.frame.copy()
    except Exception:
        # 3. 失败则用 OpenML 备用源,并统一列名
        df = _build_from_openml()

    # 4. 首次成功后写入 data/,下次不用再下载
    df.to_csv(DATA_PATH, index=False)
    return df

为什么这样做?

你当前环境中 sklearn 官方数据源返回了 HTTP 403(被服务器拒绝),所以自动走了 OpenML 备用方案,并把结果保存到 data/california_housing.csv。之后再次运行会直接读本地文件,更快也更稳定
教学点:做项目时,数据要能稳定复现 。缓存到 data/ 是好的习惯。
#mermaid-svg-Y3lOlztOW1TlXbdI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Y3lOlztOW1TlXbdI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Y3lOlztOW1TlXbdI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Y3lOlztOW1TlXbdI .error-icon{fill:#552222;}#mermaid-svg-Y3lOlztOW1TlXbdI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Y3lOlztOW1TlXbdI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Y3lOlztOW1TlXbdI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Y3lOlztOW1TlXbdI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Y3lOlztOW1TlXbdI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Y3lOlztOW1TlXbdI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Y3lOlztOW1TlXbdI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Y3lOlztOW1TlXbdI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Y3lOlztOW1TlXbdI .marker.cross{stroke:#333333;}#mermaid-svg-Y3lOlztOW1TlXbdI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Y3lOlztOW1TlXbdI p{margin:0;}#mermaid-svg-Y3lOlztOW1TlXbdI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Y3lOlztOW1TlXbdI .cluster-label text{fill:#333;}#mermaid-svg-Y3lOlztOW1TlXbdI .cluster-label span{color:#333;}#mermaid-svg-Y3lOlztOW1TlXbdI .cluster-label span p{background-color:transparent;}#mermaid-svg-Y3lOlztOW1TlXbdI .label text,#mermaid-svg-Y3lOlztOW1TlXbdI span{fill:#333;color:#333;}#mermaid-svg-Y3lOlztOW1TlXbdI .node rect,#mermaid-svg-Y3lOlztOW1TlXbdI .node circle,#mermaid-svg-Y3lOlztOW1TlXbdI .node ellipse,#mermaid-svg-Y3lOlztOW1TlXbdI .node polygon,#mermaid-svg-Y3lOlztOW1TlXbdI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Y3lOlztOW1TlXbdI .rough-node .label text,#mermaid-svg-Y3lOlztOW1TlXbdI .node .label text,#mermaid-svg-Y3lOlztOW1TlXbdI .image-shape .label,#mermaid-svg-Y3lOlztOW1TlXbdI .icon-shape .label{text-anchor:middle;}#mermaid-svg-Y3lOlztOW1TlXbdI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Y3lOlztOW1TlXbdI .rough-node .label,#mermaid-svg-Y3lOlztOW1TlXbdI .node .label,#mermaid-svg-Y3lOlztOW1TlXbdI .image-shape .label,#mermaid-svg-Y3lOlztOW1TlXbdI .icon-shape .label{text-align:center;}#mermaid-svg-Y3lOlztOW1TlXbdI .node.clickable{cursor:pointer;}#mermaid-svg-Y3lOlztOW1TlXbdI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Y3lOlztOW1TlXbdI .arrowheadPath{fill:#333333;}#mermaid-svg-Y3lOlztOW1TlXbdI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Y3lOlztOW1TlXbdI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Y3lOlztOW1TlXbdI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Y3lOlztOW1TlXbdI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Y3lOlztOW1TlXbdI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Y3lOlztOW1TlXbdI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Y3lOlztOW1TlXbdI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Y3lOlztOW1TlXbdI .cluster text{fill:#333;}#mermaid-svg-Y3lOlztOW1TlXbdI .cluster span{color:#333;}#mermaid-svg-Y3lOlztOW1TlXbdI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Y3lOlztOW1TlXbdI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Y3lOlztOW1TlXbdI rect.text{fill:none;stroke-width:0;}#mermaid-svg-Y3lOlztOW1TlXbdI .icon-shape,#mermaid-svg-Y3lOlztOW1TlXbdI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Y3lOlztOW1TlXbdI .icon-shape p,#mermaid-svg-Y3lOlztOW1TlXbdI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Y3lOlztOW1TlXbdI .icon-shape .label rect,#mermaid-svg-Y3lOlztOW1TlXbdI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Y3lOlztOW1TlXbdI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Y3lOlztOW1TlXbdI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Y3lOlztOW1TlXbdI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

成功
失败403
load_data() 被调用
本地 CSV 存在?
pd.read_csv 直接读取
尝试 sklearn 在线下载
写入 data/ 缓存
OpenML 备用源
返回 DataFrame

2.7 EDA 整体流程

#mermaid-svg-LbXaZvBmB83lWBmT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LbXaZvBmB83lWBmT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LbXaZvBmB83lWBmT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LbXaZvBmB83lWBmT .error-icon{fill:#552222;}#mermaid-svg-LbXaZvBmB83lWBmT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LbXaZvBmB83lWBmT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LbXaZvBmB83lWBmT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LbXaZvBmB83lWBmT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LbXaZvBmB83lWBmT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LbXaZvBmB83lWBmT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LbXaZvBmB83lWBmT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LbXaZvBmB83lWBmT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LbXaZvBmB83lWBmT .marker.cross{stroke:#333333;}#mermaid-svg-LbXaZvBmB83lWBmT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LbXaZvBmB83lWBmT p{margin:0;}#mermaid-svg-LbXaZvBmB83lWBmT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-LbXaZvBmB83lWBmT .cluster-label text{fill:#333;}#mermaid-svg-LbXaZvBmB83lWBmT .cluster-label span{color:#333;}#mermaid-svg-LbXaZvBmB83lWBmT .cluster-label span p{background-color:transparent;}#mermaid-svg-LbXaZvBmB83lWBmT .label text,#mermaid-svg-LbXaZvBmB83lWBmT span{fill:#333;color:#333;}#mermaid-svg-LbXaZvBmB83lWBmT .node rect,#mermaid-svg-LbXaZvBmB83lWBmT .node circle,#mermaid-svg-LbXaZvBmB83lWBmT .node ellipse,#mermaid-svg-LbXaZvBmB83lWBmT .node polygon,#mermaid-svg-LbXaZvBmB83lWBmT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LbXaZvBmB83lWBmT .rough-node .label text,#mermaid-svg-LbXaZvBmB83lWBmT .node .label text,#mermaid-svg-LbXaZvBmB83lWBmT .image-shape .label,#mermaid-svg-LbXaZvBmB83lWBmT .icon-shape .label{text-anchor:middle;}#mermaid-svg-LbXaZvBmB83lWBmT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LbXaZvBmB83lWBmT .rough-node .label,#mermaid-svg-LbXaZvBmB83lWBmT .node .label,#mermaid-svg-LbXaZvBmB83lWBmT .image-shape .label,#mermaid-svg-LbXaZvBmB83lWBmT .icon-shape .label{text-align:center;}#mermaid-svg-LbXaZvBmB83lWBmT .node.clickable{cursor:pointer;}#mermaid-svg-LbXaZvBmB83lWBmT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LbXaZvBmB83lWBmT .arrowheadPath{fill:#333333;}#mermaid-svg-LbXaZvBmB83lWBmT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LbXaZvBmB83lWBmT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LbXaZvBmB83lWBmT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LbXaZvBmB83lWBmT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LbXaZvBmB83lWBmT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LbXaZvBmB83lWBmT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LbXaZvBmB83lWBmT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LbXaZvBmB83lWBmT .cluster text{fill:#333;}#mermaid-svg-LbXaZvBmB83lWBmT .cluster span{color:#333;}#mermaid-svg-LbXaZvBmB83lWBmT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LbXaZvBmB83lWBmT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LbXaZvBmB83lWBmT rect.text{fill:none;stroke-width:0;}#mermaid-svg-LbXaZvBmB83lWBmT .icon-shape,#mermaid-svg-LbXaZvBmB83lWBmT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LbXaZvBmB83lWBmT .icon-shape p,#mermaid-svg-LbXaZvBmB83lWBmT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LbXaZvBmB83lWBmT .icon-shape .label rect,#mermaid-svg-LbXaZvBmB83lWBmT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LbXaZvBmB83lWBmT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LbXaZvBmB83lWBmT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LbXaZvBmB83lWBmT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 加载 DataFrame
shape 看规模
info 看类型与缺失
describe 看数值范围
corr 算与房价相关性
画3张图 分布/相关/散点
得出结论 谁与房价最相关

2.8 EDA 代码解读

(1)看数据规模
python 复制代码
print(f"样本数(行): {df.shape[0]}")
print(f"字段数(列): {df.shape[1]}")
  • shape[0] = 行数 = 有多少个样本
  • shape[1] = 列数 = 有多少个字段
(2)看类型与缺失
python 复制代码
df.info()
df.isnull().sum()
  • info():每列类型、非空数量
  • 缺失值:本数据集清洗后无缺失;但检查缺失是每次 EDA 的固定动作
(3)看统计摘要
python 复制代码
df.describe()

输出 count、mean、std、min、25%、50%、75%、max。快速判断:

  • 收入 MedInc 均值约 3.87 → 典型区域收入约 3.87 万美元量级(需结合数据集定义理解)
  • 房价 MedHouseVal 最大值 5.0 → 存在截断(高价房被压在 5.0)
(4)算相关性
python 复制代码
correlations = df.corr(numeric_only=True)["MedHouseVal"].drop("MedHouseVal")

相关系数范围 -1 到 +1:

含义
接近 +1 该特征越大,房价倾向于越高
接近 -1 该特征越大,房价倾向于越低
接近 0 线性关系弱

本步实际结果(你的环境):

特征 相关系数 解读
MedInc +0.688 收入越高,房价越高(最强)
AveRooms +0.151 房间多,房价略高
Latitude -0.145 纬度与房价有弱负相关(地理位置效应)
HouseAge +0.106 弱正相关
AveBedrms -0.047 很弱
Longitude -0.045 很弱
Population -0.025 很弱
AveOccup -0.024 很弱

重要提醒:相关性 ≠ 因果关系。

收入高往往伴随房价高,但不能简单说「涨收入就能涨房价」。EDA 阶段只做「线索发现」,不做因果断言。
#mermaid-svg-AMplj2ZiTw7aABc8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AMplj2ZiTw7aABc8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AMplj2ZiTw7aABc8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AMplj2ZiTw7aABc8 .error-icon{fill:#552222;}#mermaid-svg-AMplj2ZiTw7aABc8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AMplj2ZiTw7aABc8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AMplj2ZiTw7aABc8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AMplj2ZiTw7aABc8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AMplj2ZiTw7aABc8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AMplj2ZiTw7aABc8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AMplj2ZiTw7aABc8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AMplj2ZiTw7aABc8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AMplj2ZiTw7aABc8 .marker.cross{stroke:#333333;}#mermaid-svg-AMplj2ZiTw7aABc8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AMplj2ZiTw7aABc8 p{margin:0;}#mermaid-svg-AMplj2ZiTw7aABc8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-AMplj2ZiTw7aABc8 .cluster-label text{fill:#333;}#mermaid-svg-AMplj2ZiTw7aABc8 .cluster-label span{color:#333;}#mermaid-svg-AMplj2ZiTw7aABc8 .cluster-label span p{background-color:transparent;}#mermaid-svg-AMplj2ZiTw7aABc8 .label text,#mermaid-svg-AMplj2ZiTw7aABc8 span{fill:#333;color:#333;}#mermaid-svg-AMplj2ZiTw7aABc8 .node rect,#mermaid-svg-AMplj2ZiTw7aABc8 .node circle,#mermaid-svg-AMplj2ZiTw7aABc8 .node ellipse,#mermaid-svg-AMplj2ZiTw7aABc8 .node polygon,#mermaid-svg-AMplj2ZiTw7aABc8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-AMplj2ZiTw7aABc8 .rough-node .label text,#mermaid-svg-AMplj2ZiTw7aABc8 .node .label text,#mermaid-svg-AMplj2ZiTw7aABc8 .image-shape .label,#mermaid-svg-AMplj2ZiTw7aABc8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-AMplj2ZiTw7aABc8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-AMplj2ZiTw7aABc8 .rough-node .label,#mermaid-svg-AMplj2ZiTw7aABc8 .node .label,#mermaid-svg-AMplj2ZiTw7aABc8 .image-shape .label,#mermaid-svg-AMplj2ZiTw7aABc8 .icon-shape .label{text-align:center;}#mermaid-svg-AMplj2ZiTw7aABc8 .node.clickable{cursor:pointer;}#mermaid-svg-AMplj2ZiTw7aABc8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-AMplj2ZiTw7aABc8 .arrowheadPath{fill:#333333;}#mermaid-svg-AMplj2ZiTw7aABc8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-AMplj2ZiTw7aABc8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-AMplj2ZiTw7aABc8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AMplj2ZiTw7aABc8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-AMplj2ZiTw7aABc8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AMplj2ZiTw7aABc8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-AMplj2ZiTw7aABc8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-AMplj2ZiTw7aABc8 .cluster text{fill:#333;}#mermaid-svg-AMplj2ZiTw7aABc8 .cluster span{color:#333;}#mermaid-svg-AMplj2ZiTw7aABc8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AMplj2ZiTw7aABc8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-AMplj2ZiTw7aABc8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-AMplj2ZiTw7aABc8 .icon-shape,#mermaid-svg-AMplj2ZiTw7aABc8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AMplj2ZiTw7aABc8 .icon-shape p,#mermaid-svg-AMplj2ZiTw7aABc8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-AMplj2ZiTw7aABc8 .icon-shape .label rect,#mermaid-svg-AMplj2ZiTw7aABc8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AMplj2ZiTw7aABc8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-AMplj2ZiTw7aABc8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-AMplj2ZiTw7aABc8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 相关非因果
MedInc升高
房价倾向于升高
不等于涨收入导致涨房价

2.9 三张图分别说明什么

图表保存在 reports/figures/标题与坐标轴均为中文):

图 1:01_target_distribution.png --- 房价中位数分布
  • 标题:房价中位数分布
  • 看什么MedHouseVal 的直方图 + 密度曲线
  • 典型现象右偏分布 ------ 大量区域房价集中在较低区间,右侧有长尾(少数高价区域)
  • 对建模的启示 :后面可能要对目标做 log 变换(进阶);现在先记住「分布不均匀」
图 2:02_feature_correlation.png --- 各特征与房价的相关系数
  • 标题:各特征与房价中位数的相关系数
  • 看什么:纵轴为中文特征名,横轴为皮尔逊相关系数
  • 典型现象MedInc 遥遥领先,其余特征相对较弱
  • 对建模的启示:收入是核心特征;但弱特征组合起来仍可能有价值(后续树模型会体现)
图 3:03_medinc_vs_price.png --- 收入与房价散点图
  • 标题:收入中位数与房价中位数的关系
  • 看什么:横轴收入中位数,纵轴房价中位数
  • 典型现象 :整体呈上升趋势,但点很分散 ------ 说明收入能解释一部分房价,但不是全部
  • 对建模的启示:线性关系存在,但会有较大残差(预测误差)

2.10 动手任务

任务 A:运行并核对输出

运行 python src/train.py,确认:

  • 终端打印了相关性排序,MedInc 排第一
  • reports/figures/ 下出现 3 张 PNG 图
  • data/california_housing.csv 已生成

任务 B:用 Pandas 自己试两行(建议)

在项目根目录打开 Python 交互环境:

powershell 复制代码
python
python 复制代码
import pandas as pd
df = pd.read_csv("data/california_housing.csv")
df.head()      # 看前 5 行
df.tail(3)     # 看后 3 行

思考:head() 每一行代表什么?(答:一个加州区域的记录)

任务 C:改一处代码观察变化(可选)

explore_data() 里,把散点图的 x="MedInc" 改成 x="HouseAge",重新运行,看图 3 形态如何变化。体会「不同特征与目标的关系形态不同」。

任务 D:写学习笔记

README.md 的步骤 2 记录下:最强相关特征是什么、你对右偏分布的理解。

2.11 验收标准

  • 能说出 8 个特征和 1 个标签各是什么
  • 能解释「样本 = 一行数据」
  • 能说出与房价相关性最强的特征(MedInc
  • 能描述 MedHouseVal 大致呈右偏分布
  • 能区分「相关性」与「因果关系」
  • 3 张图成功生成

2.12 本步核心概念

2.12 动手任务与验收标准参考答案

以下为教学标准答案,便于自学对照;README.md 学习记录仍建议用自己的话写。

动手任务答案
任务 参考答案
A MedInc 相关性第一;01_03_ PNG 已生成;california_housing.csv 已缓存。
B 每行 = 一个加州区域统计记录。
C 改 x=HouseAge 后关系弱于 MedInc,形态更分散。
D 示例:MedInc 最强相关;房价右偏。
验收标准答案
验收项 参考答案
8 特征 + 1 标签 8 个 MedInc 等特征;标签 MedHouseVal。
样本 一行 = 一个区域。
最强相关 MedInc,r≈+0.69。
右偏 低价多、高价长尾。
相关≠因果 相关不等于因果。
3 张图 01/02/03 三张 PNG。
概念 解释
EDA 建模前对数据的系统性探查
特征 / 标签 / 样本 输入、输出、一行观测
describe() 数值列的分布摘要统计
相关系数 两列数值的线性相关强度(-1~1)
右偏分布 多数值集中在左侧,右侧有长尾
数据缓存 下载一次存本地,保证复现与离线可用

2.13 常见问题

Q:为什么我的样本数是 20433 而不是 20640?

A:备用数据源在转换时去掉了少量含缺失卧室数的行,属于正常差异,不影响学习。

Q: MedHouseVal 为什么最大只有 5.0?

A:数据集制作时对高价区域做了截断(censoring),这是真实数据中常见的「封顶」现象。

Q:相关系数 0.69 算高吗?

A:在社会科学 / 房价这类问题里,单一特征能达到 0.6~0.7 已经相当不错;说明收入是强信号,但仍有大量方差需要其他特征或更复杂模型解释。

Q:图保存在哪?需要手动打开吗?

A:在 project_01_housing/reports/figures/,用资源管理器或 IDE 直接打开 PNG 即可。

2.14 本步小结

发现 内容
数据规模 约 2 万条区域记录,9 列(8 特征 + 1 标签)
最强相关特征 MedInc(收入中位数),r ≈ +0.69
目标分布 右偏,低价区域多,高价长尾
下一步 划分训练集与测试集,为建模做准备

2.15 学习记录(请你填写)

  • 完成日期
  • 动手任务完成情况:任务 A / B / C / D
  • 我看到的图表现象(用自己的话写 1~3 句):
  • 疑问(如有):

步骤 3:划分训练集与测试集

状态:✅ 已完成教学(已按详细讲解规范增补名词解释与 Mermaid 图)

3.1 本步目标

在正式训练模型之前,把数据切成两块:

  • 训练集(80%):给模型「学习」用
  • 测试集(20%):给模型「考试」用,模拟未来没见过的新数据

本步要建立的核心习惯:永远不要把测试集混进训练过程

3.2 这一步在解决什么问题?

想象你在备考:

  • 练习题学习 → 训练集
  • 从未见过的模拟卷检验水平 → 测试集

若用同一份题既背答案又自测,分数会虚高。机器学习也一样:若在「考过的题」上评估,模型可能只是背住了数据 ,对新区域预测很差。这叫过拟合,测试集就是用来发现这个问题的。

3.2.5 本步在整体流程中的位置

#mermaid-svg-cHvwxh1PGhIRQIFK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cHvwxh1PGhIRQIFK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cHvwxh1PGhIRQIFK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cHvwxh1PGhIRQIFK .error-icon{fill:#552222;}#mermaid-svg-cHvwxh1PGhIRQIFK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cHvwxh1PGhIRQIFK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cHvwxh1PGhIRQIFK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cHvwxh1PGhIRQIFK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cHvwxh1PGhIRQIFK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cHvwxh1PGhIRQIFK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cHvwxh1PGhIRQIFK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cHvwxh1PGhIRQIFK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cHvwxh1PGhIRQIFK .marker.cross{stroke:#333333;}#mermaid-svg-cHvwxh1PGhIRQIFK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cHvwxh1PGhIRQIFK p{margin:0;}#mermaid-svg-cHvwxh1PGhIRQIFK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cHvwxh1PGhIRQIFK .cluster-label text{fill:#333;}#mermaid-svg-cHvwxh1PGhIRQIFK .cluster-label span{color:#333;}#mermaid-svg-cHvwxh1PGhIRQIFK .cluster-label span p{background-color:transparent;}#mermaid-svg-cHvwxh1PGhIRQIFK .label text,#mermaid-svg-cHvwxh1PGhIRQIFK span{fill:#333;color:#333;}#mermaid-svg-cHvwxh1PGhIRQIFK .node rect,#mermaid-svg-cHvwxh1PGhIRQIFK .node circle,#mermaid-svg-cHvwxh1PGhIRQIFK .node ellipse,#mermaid-svg-cHvwxh1PGhIRQIFK .node polygon,#mermaid-svg-cHvwxh1PGhIRQIFK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cHvwxh1PGhIRQIFK .rough-node .label text,#mermaid-svg-cHvwxh1PGhIRQIFK .node .label text,#mermaid-svg-cHvwxh1PGhIRQIFK .image-shape .label,#mermaid-svg-cHvwxh1PGhIRQIFK .icon-shape .label{text-anchor:middle;}#mermaid-svg-cHvwxh1PGhIRQIFK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cHvwxh1PGhIRQIFK .rough-node .label,#mermaid-svg-cHvwxh1PGhIRQIFK .node .label,#mermaid-svg-cHvwxh1PGhIRQIFK .image-shape .label,#mermaid-svg-cHvwxh1PGhIRQIFK .icon-shape .label{text-align:center;}#mermaid-svg-cHvwxh1PGhIRQIFK .node.clickable{cursor:pointer;}#mermaid-svg-cHvwxh1PGhIRQIFK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cHvwxh1PGhIRQIFK .arrowheadPath{fill:#333333;}#mermaid-svg-cHvwxh1PGhIRQIFK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cHvwxh1PGhIRQIFK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cHvwxh1PGhIRQIFK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cHvwxh1PGhIRQIFK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cHvwxh1PGhIRQIFK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cHvwxh1PGhIRQIFK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cHvwxh1PGhIRQIFK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cHvwxh1PGhIRQIFK .cluster text{fill:#333;}#mermaid-svg-cHvwxh1PGhIRQIFK .cluster span{color:#333;}#mermaid-svg-cHvwxh1PGhIRQIFK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cHvwxh1PGhIRQIFK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cHvwxh1PGhIRQIFK rect.text{fill:none;stroke-width:0;}#mermaid-svg-cHvwxh1PGhIRQIFK .icon-shape,#mermaid-svg-cHvwxh1PGhIRQIFK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cHvwxh1PGhIRQIFK .icon-shape p,#mermaid-svg-cHvwxh1PGhIRQIFK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cHvwxh1PGhIRQIFK .icon-shape .label rect,#mermaid-svg-cHvwxh1PGhIRQIFK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cHvwxh1PGhIRQIFK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cHvwxh1PGhIRQIFK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cHvwxh1PGhIRQIFK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

步骤2 已了解数据
步骤3 划分 X/y 与 train/test
步骤4 只在 X_train 上 fit
步骤4 用 X_test 评估
测试集表现好?
继续优化模型
检查泄露或过拟合

3.2.6 名词解释(本步首次出现)

名词 是什么 为什么需要 在本项目中 易混淆
X(特征矩阵) 所有输入特征组成的表格 模型学习的是 X→y 的映射 8 列,16346/4087 行 不含房价列
y(标签向量) 要预测的目标一列 监督学习需要标准答案 MedHouseVal 一维,不是矩阵
train_test_split sklearn 随机划分训练/测试集的函数 公平评估泛化能力 80% 训练,20% 测试 不是按顺序切
泛化能力 模型对未见过数据的表现 部署后面对新区域能否准 用测试集 RMSE 衡量 不是训练集表现
过拟合 训练集很好、新数据变差 模型「背题」而非学规律 步骤4若 train RMSE 远小于 test 需警惕 不是欠拟合
数据泄露 测试集信息渗入训练过程 会导致评估虚高、上线后翻车 测试集不能参与 fit 与缺失值无关
random_state 随机数种子 保证每次划分结果相同,实验可复现 固定为 42 不是模型参数

3.3 任务清单

  • 分离 X(8 列特征)和 yMedHouseVal
  • 使用 train_test_split(X, y, test_size=0.2, random_state=42)
  • 打印训练集、测试集形状与占比
  • 对比训练集/测试集房价均值,检查划分是否均衡
  • 绘制中文对比图 04_train_test_split.png

3.4 运行本步

powershell 复制代码
cd "d:\JavaCode\机器学习\project_01_housing"
python src/train.py

你这步应看到的关键输出:

项目 数值
X_train 形状 (16346, 8)
X_test 形状 (4087, 8)
训练集占比 80.0%
测试集占比 20.0%
训练集房价均值 2.0664
测试集房价均值 2.0774

训练集与测试集的房价均值非常接近,说明随机划分后两边分布较均衡,评估会更公平。

3.6 数据划分与使用规则(Mermaid)

#mermaid-svg-Z0Blt145SZyMuQEc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Z0Blt145SZyMuQEc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Z0Blt145SZyMuQEc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Z0Blt145SZyMuQEc .error-icon{fill:#552222;}#mermaid-svg-Z0Blt145SZyMuQEc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Z0Blt145SZyMuQEc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Z0Blt145SZyMuQEc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Z0Blt145SZyMuQEc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Z0Blt145SZyMuQEc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Z0Blt145SZyMuQEc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Z0Blt145SZyMuQEc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Z0Blt145SZyMuQEc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Z0Blt145SZyMuQEc .marker.cross{stroke:#333333;}#mermaid-svg-Z0Blt145SZyMuQEc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Z0Blt145SZyMuQEc p{margin:0;}#mermaid-svg-Z0Blt145SZyMuQEc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Z0Blt145SZyMuQEc .cluster-label text{fill:#333;}#mermaid-svg-Z0Blt145SZyMuQEc .cluster-label span{color:#333;}#mermaid-svg-Z0Blt145SZyMuQEc .cluster-label span p{background-color:transparent;}#mermaid-svg-Z0Blt145SZyMuQEc .label text,#mermaid-svg-Z0Blt145SZyMuQEc span{fill:#333;color:#333;}#mermaid-svg-Z0Blt145SZyMuQEc .node rect,#mermaid-svg-Z0Blt145SZyMuQEc .node circle,#mermaid-svg-Z0Blt145SZyMuQEc .node ellipse,#mermaid-svg-Z0Blt145SZyMuQEc .node polygon,#mermaid-svg-Z0Blt145SZyMuQEc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Z0Blt145SZyMuQEc .rough-node .label text,#mermaid-svg-Z0Blt145SZyMuQEc .node .label text,#mermaid-svg-Z0Blt145SZyMuQEc .image-shape .label,#mermaid-svg-Z0Blt145SZyMuQEc .icon-shape .label{text-anchor:middle;}#mermaid-svg-Z0Blt145SZyMuQEc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Z0Blt145SZyMuQEc .rough-node .label,#mermaid-svg-Z0Blt145SZyMuQEc .node .label,#mermaid-svg-Z0Blt145SZyMuQEc .image-shape .label,#mermaid-svg-Z0Blt145SZyMuQEc .icon-shape .label{text-align:center;}#mermaid-svg-Z0Blt145SZyMuQEc .node.clickable{cursor:pointer;}#mermaid-svg-Z0Blt145SZyMuQEc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Z0Blt145SZyMuQEc .arrowheadPath{fill:#333333;}#mermaid-svg-Z0Blt145SZyMuQEc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Z0Blt145SZyMuQEc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Z0Blt145SZyMuQEc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Z0Blt145SZyMuQEc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Z0Blt145SZyMuQEc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Z0Blt145SZyMuQEc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Z0Blt145SZyMuQEc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Z0Blt145SZyMuQEc .cluster text{fill:#333;}#mermaid-svg-Z0Blt145SZyMuQEc .cluster span{color:#333;}#mermaid-svg-Z0Blt145SZyMuQEc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Z0Blt145SZyMuQEc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Z0Blt145SZyMuQEc rect.text{fill:none;stroke-width:0;}#mermaid-svg-Z0Blt145SZyMuQEc .icon-shape,#mermaid-svg-Z0Blt145SZyMuQEc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Z0Blt145SZyMuQEc .icon-shape p,#mermaid-svg-Z0Blt145SZyMuQEc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Z0Blt145SZyMuQEc .icon-shape .label rect,#mermaid-svg-Z0Blt145SZyMuQEc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Z0Blt145SZyMuQEc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Z0Blt145SZyMuQEc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Z0Blt145SZyMuQEc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 全部 20433 条
train_test_split 80/20
训练集 16346 条
测试集 4087 条
model.fit 训练集 允许
model.predict 测试集 允许
测试集禁止 fit

四条铁律:

  1. fit 只用 X_train, y_train
  2. predict 可对 X_test 预测,再与 y_test 对比
  3. 不要用 X_test 参与任何「学习统计量」的步骤(缩放、填充等,步骤 5 会强调)
  4. 测试集对模型来说是「未来的新区域」

3.7 核心代码解读

(1)分离特征与标签
python 复制代码
X = df.drop(columns=[TARGET_COL])  # 8 个输入特征
y = df[TARGET_COL]                 # 1 个目标:房价中位数
符号 含义 形状
X 特征矩阵 (样本数, 8)
y 标签向量 (样本数,)

一行数据X 的一行是某区域的 8 个特征,y 的对应值是该区域真实的房价中位数。

(2)随机划分
python 复制代码
X_train, X_test, y_train, y_test = train_test_split(
    X, y,
    test_size=0.2,       # 20% 测试,80% 训练
    random_state=42,     # 固定随机种子,结果可复现
)

参数说明:

参数 作用
test_size=0.2 20% 样本进测试集
random_state=42 固定随机种子,每次运行划分结果相同(便于复现与调试)

四个变量的用途:

变量 用途
X_train, y_train 步骤 4 起用于 model.fit() 训练
X_test, y_test 只在评估时用 model.predict()不参与训练
(3)可视化划分结果

新增函数 visualize_train_test_split() 生成中文条形图:

  • 标题:训练集与测试集样本数量对比
  • 柱顶数字:16346 / 4087
  • 底部说明:训练集 80.0% | 测试集 20.0%

3.8 动手任务

任务 A:运行并核对

  • X_train 约 16346 行,X_test 约 4087 行
  • 比例为 8:2
  • 生成 04_train_test_split.png

任务 B:改 random_state 观察(建议)

RANDOM_STATE = 42 改成 0100,重新运行,观察划分数量不变、但训练/测试均值可能略变。再改回 42,与文档结果对齐。

任务 C:思考一题

若把 test_size 改成 0.5,训练集和测试集各多少条?(答:各约 10216 条)训练数据变少会对模型有什么影响?(答:学得少一些,通常方差更大;此题先建立直觉即可。)

任务 D:在 README.md 记录

用一句话说明:为什么需要测试集。

3.9 验收标准

  • 能区分 X / yX_train / X_test / y_train / y_test
  • 能解释训练集与测试集各自用途
  • 能说明为何不能用全部数据既训练又评估
  • 知道 random_state 用于可复现
  • 划分比例约为 8:2

3.10 本步核心概念

3.10 动手任务与验收标准参考答案

以下为教学标准答案,便于自学对照;README.md 学习记录仍建议用自己的话写。

动手任务答案
任务 参考答案
A X_train (16346,8),X_test (4087,8);04_train_test_split.png
B 改 random_state 数量不变、均值略变;改回 42 对齐文档。
C test_size=0.5 各约 10216 条;训练变少,模型可能更不稳定。
D 测试集模拟未来新数据,检验泛化。
验收标准答案
验收项 参考答案
X/y 与划分 X 8 列特征,y 为房价;train 学、test 考。
用途 训练 fit,测试 predict 评估。
不能全量既训又评 会虚高、无法发现过拟合。
random_state 固定种子保证可复现。
8:2 16346 / 4087。
概念 解释
泛化能力 模型对未见过数据的表现好坏
过拟合 在训练集上很好、在新数据上变差(像死记硬背)
测试集 模拟未来新数据,只用于最终评估
数据泄露 测试集信息渗入训练过程,导致评估失真
random_state 控制随机划分的种子,保证实验可复现

3.11 常见问题

Q:为什么不用 100% 数据训练?

A:没有留出测试集,就无法知道模型对新数据好不好。就像没有模拟卷就无法检验真实水平。

Q: random_state=42 有什么特殊吗?

A:没有,只是社区常用的示例值。任何固定整数都可以,关键是固定下来便于复现。

Q:划分后特征数还是 8 吗?

A:是。划分只改变行数 (样本数),不改变列数(特征数)。

Q:步骤 2 的 EDA 图还能生成吗?

A:explore_data() 仍在 train.py 中,需要时可单独调用;main() 当前聚焦步骤 3,避免每次重复画图。复习步骤 2 可在 Python 里手动调用 explore_data(load_data())

3.12 本步小结

要点 内容
特征 X 8 列,不含房价
标签 y MedHouseVal
划分比例 80% 训练 / 20% 测试
下一步 X_train 上训练线性回归基准模型

3.13 学习记录(请你填写)

  • 完成日期
  • 动手任务完成情况:任务 A / B / C / D
  • 用一句话解释为何要测试集
  • 疑问(如有):

步骤 4:建立基准模型 ------ 线性回归

状态:✅ 已完成教学(已按详细讲解规范增补名词解释与 Mermaid 图)

4.1 本步目标

第一次真正训练机器学习模型 。用线性回归在训练集上学习,在测试集上评估,得到后续所有模型都要对比的 Baseline(基准) 指标。

4.2 这一步在解决什么问题?

EDA 只能「看」规律,模型才能「学」规律并给出数值预测。

线性回归是最简单的回归模型,适合作为第一条基准线:后面更复杂的模型,只有比它更好才有意义。

4.2.5 本步在整体流程中的位置

#mermaid-svg-mGoFCFeZHtsRYwJ6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mGoFCFeZHtsRYwJ6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .error-icon{fill:#552222;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .marker.cross{stroke:#333333;}#mermaid-svg-mGoFCFeZHtsRYwJ6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mGoFCFeZHtsRYwJ6 p{margin:0;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .cluster-label text{fill:#333;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .cluster-label span{color:#333;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .cluster-label span p{background-color:transparent;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .label text,#mermaid-svg-mGoFCFeZHtsRYwJ6 span{fill:#333;color:#333;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .node rect,#mermaid-svg-mGoFCFeZHtsRYwJ6 .node circle,#mermaid-svg-mGoFCFeZHtsRYwJ6 .node ellipse,#mermaid-svg-mGoFCFeZHtsRYwJ6 .node polygon,#mermaid-svg-mGoFCFeZHtsRYwJ6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .rough-node .label text,#mermaid-svg-mGoFCFeZHtsRYwJ6 .node .label text,#mermaid-svg-mGoFCFeZHtsRYwJ6 .image-shape .label,#mermaid-svg-mGoFCFeZHtsRYwJ6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .rough-node .label,#mermaid-svg-mGoFCFeZHtsRYwJ6 .node .label,#mermaid-svg-mGoFCFeZHtsRYwJ6 .image-shape .label,#mermaid-svg-mGoFCFeZHtsRYwJ6 .icon-shape .label{text-align:center;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .node.clickable{cursor:pointer;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .arrowheadPath{fill:#333333;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mGoFCFeZHtsRYwJ6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mGoFCFeZHtsRYwJ6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mGoFCFeZHtsRYwJ6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .cluster text{fill:#333;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .cluster span{color:#333;}#mermaid-svg-mGoFCFeZHtsRYwJ6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mGoFCFeZHtsRYwJ6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .icon-shape,#mermaid-svg-mGoFCFeZHtsRYwJ6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .icon-shape p,#mermaid-svg-mGoFCFeZHtsRYwJ6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .icon-shape .label rect,#mermaid-svg-mGoFCFeZHtsRYwJ6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mGoFCFeZHtsRYwJ6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mGoFCFeZHtsRYwJ6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mGoFCFeZHtsRYwJ6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 步骤3 已有 train/test
步骤4 fit 线性回归
predict 测试集
算 RMSE MAE R2
记录 Baseline
步骤5~8 与 Baseline 对比

4.2.6 名词解释(本步首次出现)

名词 是什么 为什么需要 在本项目中 易混淆
fit(拟合/训练) 用训练数据学习模型内部参数 模型不会自己变聪明,必须学习 model.fit(X_train, y_train) 不能对测试集 fit
predict(预测) 用已训练模型输出预测值 评估模型是否好用 model.predict(X_test) 不是算指标
Baseline 第一个可对比的基准成绩 后续模型需证明「比它强」 测试 RMSE=0.7514 不是最终模型
线性回归 用特征的线性组合预测目标 最简单、可解释的回归模型 LinearRegression 不是逻辑回归
系数 coef 每个特征对预测的贡献权重 理解「哪个因素影响房价」 MedInc 系数约 0.44 未缩放时不便比大小
截距 intercept 所有特征为 0 时的基准值 完整线性方程的一部分 约 -36.84 单独解读意义有限
RMSE 均方根误差,典型预测偏差大小 回归最常用的误差指标之一 测试集 0.7514 越小越好
MAE 平均绝对误差 对极端误差不那么敏感 测试集 0.5400 越小越好
R2 决定系数,解释力 比「总猜均值」好多少 测试集 0.5871 越接近 1 越好
最小二乘 使误差平方和最小的训练方法 线性回归的经典目标 sklearn 默认优化目标 不是梯度提升

4.3 任务清单

  • LinearRegression 在训练集上 fit
  • 在测试集上 predict
  • 计算 RMSE、MAE、R2
  • 画「真实值 vs 预测值」散点图(中文)
  • 保存指标报告 reports/baseline_linear_regression.txt

4.4 运行本步

powershell 复制代码
cd "d:\JavaCode\机器学习\project_01_housing"
python src/train.py

你这步应看到的关键结果:

指标 训练集 测试集(Baseline)
RMSE 0.7185 0.7514
MAE 0.5271 0.5400
R2 0.6100 0.5871
模型参数 数值 含义
截距 intercept -36.8404 线性方程的常数项
MedInc 系数 0.4447 收入每增加 1 单位,预测房价约增加 0.44(十万美元)

如何读这些数?

  • RMSE ≈ 0.75 :典型预测误差约 0.75(十万美元),即约 7500 美元量级
  • R2 ≈ 0.59 :模型能解释约 59% 的房价波动(相对「永远猜均值」)
  • 测试集 RMSE 略高于训练集 → 轻微泛化差距,正常,暂无明显严重过拟合

4.5 机器学习三步曲(本步完整走通)

测试集 训练集 模型 用户 测试集 训练集 模型 用户 #mermaid-svg-UejuGEfB8hh5JmKM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UejuGEfB8hh5JmKM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UejuGEfB8hh5JmKM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UejuGEfB8hh5JmKM .error-icon{fill:#552222;}#mermaid-svg-UejuGEfB8hh5JmKM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UejuGEfB8hh5JmKM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UejuGEfB8hh5JmKM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UejuGEfB8hh5JmKM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UejuGEfB8hh5JmKM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UejuGEfB8hh5JmKM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UejuGEfB8hh5JmKM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UejuGEfB8hh5JmKM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UejuGEfB8hh5JmKM .marker.cross{stroke:#333333;}#mermaid-svg-UejuGEfB8hh5JmKM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UejuGEfB8hh5JmKM p{margin:0;}#mermaid-svg-UejuGEfB8hh5JmKM .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UejuGEfB8hh5JmKM text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-UejuGEfB8hh5JmKM .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-UejuGEfB8hh5JmKM .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-UejuGEfB8hh5JmKM .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-UejuGEfB8hh5JmKM .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-UejuGEfB8hh5JmKM #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-UejuGEfB8hh5JmKM .sequenceNumber{fill:white;}#mermaid-svg-UejuGEfB8hh5JmKM #sequencenumber{fill:#333;}#mermaid-svg-UejuGEfB8hh5JmKM #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-UejuGEfB8hh5JmKM .messageText{fill:#333;stroke:none;}#mermaid-svg-UejuGEfB8hh5JmKM .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UejuGEfB8hh5JmKM .labelText,#mermaid-svg-UejuGEfB8hh5JmKM .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-UejuGEfB8hh5JmKM .loopText,#mermaid-svg-UejuGEfB8hh5JmKM .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-UejuGEfB8hh5JmKM .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-UejuGEfB8hh5JmKM .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-UejuGEfB8hh5JmKM .noteText,#mermaid-svg-UejuGEfB8hh5JmKM .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-UejuGEfB8hh5JmKM .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UejuGEfB8hh5JmKM .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UejuGEfB8hh5JmKM .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UejuGEfB8hh5JmKM .actorPopupMenu{position:absolute;}#mermaid-svg-UejuGEfB8hh5JmKM .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-UejuGEfB8hh5JmKM .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UejuGEfB8hh5JmKM .actor-man circle,#mermaid-svg-UejuGEfB8hh5JmKM line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-UejuGEfB8hh5JmKM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 只在训练集上学习 计算 RMSE MAE R2 创建 LinearRegression 提供 X_train y_train fit 训练集 predict 测试集 输出 y_pred 对比 y_test 与 y_pred

python 复制代码
model = LinearRegression()
model.fit(X_train, y_train)       # 只在训练集上学
y_test_pred = model.predict(X_test)  # 对测试集预测

切忌fit 时不能传入 X_test / y_test

4.6 三个评估指标

指标 全称 直觉 好坏
RMSE 均方根误差 预测偏差典型大小,与房价同单位 越小越好
MAE 平均绝对误差 绝对误差的平均,对极端值不如 RMSE 敏感 越小越好
R2 决定系数 比「总猜均值」好多少 越接近 1 越好

R2 通俗理解:

  • R2 = 0 → 和猜均值差不多
  • R2 = 0.59 → 比猜均值好很多
  • R2 = 1 → 完美预测(实际几乎达不到)

4.7 线性回归在做什么?

对每个特征学一个权重(系数) ,再加一个截距

复制代码
预测房价 = intercept + c1×MedInc + c2×HouseAge + ... + c8×Longitude

最小二乘 的目标:找一组系数,使所有训练样本的误差平方和最小。
#mermaid-svg-5AtRtJoBtPqpvCu7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5AtRtJoBtPqpvCu7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5AtRtJoBtPqpvCu7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5AtRtJoBtPqpvCu7 .error-icon{fill:#552222;}#mermaid-svg-5AtRtJoBtPqpvCu7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5AtRtJoBtPqpvCu7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5AtRtJoBtPqpvCu7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5AtRtJoBtPqpvCu7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5AtRtJoBtPqpvCu7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5AtRtJoBtPqpvCu7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5AtRtJoBtPqpvCu7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5AtRtJoBtPqpvCu7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5AtRtJoBtPqpvCu7 .marker.cross{stroke:#333333;}#mermaid-svg-5AtRtJoBtPqpvCu7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5AtRtJoBtPqpvCu7 p{margin:0;}#mermaid-svg-5AtRtJoBtPqpvCu7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5AtRtJoBtPqpvCu7 .cluster-label text{fill:#333;}#mermaid-svg-5AtRtJoBtPqpvCu7 .cluster-label span{color:#333;}#mermaid-svg-5AtRtJoBtPqpvCu7 .cluster-label span p{background-color:transparent;}#mermaid-svg-5AtRtJoBtPqpvCu7 .label text,#mermaid-svg-5AtRtJoBtPqpvCu7 span{fill:#333;color:#333;}#mermaid-svg-5AtRtJoBtPqpvCu7 .node rect,#mermaid-svg-5AtRtJoBtPqpvCu7 .node circle,#mermaid-svg-5AtRtJoBtPqpvCu7 .node ellipse,#mermaid-svg-5AtRtJoBtPqpvCu7 .node polygon,#mermaid-svg-5AtRtJoBtPqpvCu7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5AtRtJoBtPqpvCu7 .rough-node .label text,#mermaid-svg-5AtRtJoBtPqpvCu7 .node .label text,#mermaid-svg-5AtRtJoBtPqpvCu7 .image-shape .label,#mermaid-svg-5AtRtJoBtPqpvCu7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-5AtRtJoBtPqpvCu7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5AtRtJoBtPqpvCu7 .rough-node .label,#mermaid-svg-5AtRtJoBtPqpvCu7 .node .label,#mermaid-svg-5AtRtJoBtPqpvCu7 .image-shape .label,#mermaid-svg-5AtRtJoBtPqpvCu7 .icon-shape .label{text-align:center;}#mermaid-svg-5AtRtJoBtPqpvCu7 .node.clickable{cursor:pointer;}#mermaid-svg-5AtRtJoBtPqpvCu7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5AtRtJoBtPqpvCu7 .arrowheadPath{fill:#333333;}#mermaid-svg-5AtRtJoBtPqpvCu7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5AtRtJoBtPqpvCu7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5AtRtJoBtPqpvCu7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5AtRtJoBtPqpvCu7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5AtRtJoBtPqpvCu7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5AtRtJoBtPqpvCu7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5AtRtJoBtPqpvCu7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5AtRtJoBtPqpvCu7 .cluster text{fill:#333;}#mermaid-svg-5AtRtJoBtPqpvCu7 .cluster span{color:#333;}#mermaid-svg-5AtRtJoBtPqpvCu7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5AtRtJoBtPqpvCu7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5AtRtJoBtPqpvCu7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-5AtRtJoBtPqpvCu7 .icon-shape,#mermaid-svg-5AtRtJoBtPqpvCu7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5AtRtJoBtPqpvCu7 .icon-shape p,#mermaid-svg-5AtRtJoBtPqpvCu7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5AtRtJoBtPqpvCu7 .icon-shape .label rect,#mermaid-svg-5AtRtJoBtPqpvCu7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5AtRtJoBtPqpvCu7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5AtRtJoBtPqpvCu7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5AtRtJoBtPqpvCu7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 线性回归公式
预测房价 y_hat
截距 b
MedInc x w1
HouseAge x w2
共8个特征

通俗理解:模型在找一条(高维空间中的)直线/超平面,让所有训练点的预测值尽量接近真实房价。

4.8 预测效果图

reports/figures/05_baseline_pred_vs_true.png

  • 标题:线性回归:真实房价 vs 预测房价(测试集)
  • 红色虚线:理想预测线 y = x(点落在线上 = 预测完美)
  • 典型现象:点沿对角线分布,但有分散 → 模型抓住了大趋势,仍有误差

#mermaid-svg-xXyvV7A7qTuqbXn0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xXyvV7A7qTuqbXn0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xXyvV7A7qTuqbXn0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xXyvV7A7qTuqbXn0 .error-icon{fill:#552222;}#mermaid-svg-xXyvV7A7qTuqbXn0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xXyvV7A7qTuqbXn0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xXyvV7A7qTuqbXn0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xXyvV7A7qTuqbXn0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xXyvV7A7qTuqbXn0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xXyvV7A7qTuqbXn0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xXyvV7A7qTuqbXn0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xXyvV7A7qTuqbXn0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xXyvV7A7qTuqbXn0 .marker.cross{stroke:#333333;}#mermaid-svg-xXyvV7A7qTuqbXn0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xXyvV7A7qTuqbXn0 p{margin:0;}#mermaid-svg-xXyvV7A7qTuqbXn0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xXyvV7A7qTuqbXn0 .cluster-label text{fill:#333;}#mermaid-svg-xXyvV7A7qTuqbXn0 .cluster-label span{color:#333;}#mermaid-svg-xXyvV7A7qTuqbXn0 .cluster-label span p{background-color:transparent;}#mermaid-svg-xXyvV7A7qTuqbXn0 .label text,#mermaid-svg-xXyvV7A7qTuqbXn0 span{fill:#333;color:#333;}#mermaid-svg-xXyvV7A7qTuqbXn0 .node rect,#mermaid-svg-xXyvV7A7qTuqbXn0 .node circle,#mermaid-svg-xXyvV7A7qTuqbXn0 .node ellipse,#mermaid-svg-xXyvV7A7qTuqbXn0 .node polygon,#mermaid-svg-xXyvV7A7qTuqbXn0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xXyvV7A7qTuqbXn0 .rough-node .label text,#mermaid-svg-xXyvV7A7qTuqbXn0 .node .label text,#mermaid-svg-xXyvV7A7qTuqbXn0 .image-shape .label,#mermaid-svg-xXyvV7A7qTuqbXn0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-xXyvV7A7qTuqbXn0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xXyvV7A7qTuqbXn0 .rough-node .label,#mermaid-svg-xXyvV7A7qTuqbXn0 .node .label,#mermaid-svg-xXyvV7A7qTuqbXn0 .image-shape .label,#mermaid-svg-xXyvV7A7qTuqbXn0 .icon-shape .label{text-align:center;}#mermaid-svg-xXyvV7A7qTuqbXn0 .node.clickable{cursor:pointer;}#mermaid-svg-xXyvV7A7qTuqbXn0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xXyvV7A7qTuqbXn0 .arrowheadPath{fill:#333333;}#mermaid-svg-xXyvV7A7qTuqbXn0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xXyvV7A7qTuqbXn0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xXyvV7A7qTuqbXn0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xXyvV7A7qTuqbXn0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xXyvV7A7qTuqbXn0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xXyvV7A7qTuqbXn0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xXyvV7A7qTuqbXn0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xXyvV7A7qTuqbXn0 .cluster text{fill:#333;}#mermaid-svg-xXyvV7A7qTuqbXn0 .cluster span{color:#333;}#mermaid-svg-xXyvV7A7qTuqbXn0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xXyvV7A7qTuqbXn0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xXyvV7A7qTuqbXn0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-xXyvV7A7qTuqbXn0 .icon-shape,#mermaid-svg-xXyvV7A7qTuqbXn0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xXyvV7A7qTuqbXn0 .icon-shape p,#mermaid-svg-xXyvV7A7qTuqbXn0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xXyvV7A7qTuqbXn0 .icon-shape .label rect,#mermaid-svg-xXyvV7A7qTuqbXn0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xXyvV7A7qTuqbXn0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xXyvV7A7qTuqbXn0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xXyvV7A7qTuqbXn0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 散点图解读
点靠近红线 y=x
预测较准
点远离红线
预测误差大

4.9 动手任务

任务 A:运行脚本,核对测试集 RMSE ≈ 0.75、R2 ≈ 0.59

任务 B :打开 baseline_linear_regression.txt,记录 Baseline 数字

任务 C:思考------若 RMSE = 0.75(十万美元单位),大约相当于预测偏差多少美元?(答:约 7500 美元)

任务 D :在 README.md 写下你对 R2 的一句话理解

4.10 验收标准

  • 能说出 fit / predict 各自做什么
  • 能解释 RMSE、MAE、R2 的含义
  • 知道 Baseline 是后续模型的比较起点
  • 能读预测散点图,理解点离对角线越远误差越大

4.11 本步核心概念

4.11 动手任务与验收标准参考答案

以下为教学标准答案,便于自学对照;README.md 学习记录仍建议用自己的话写。

动手任务答案
任务 参考答案
A 测试 RMSE≈0.7514,R2≈0.5871。
B baseline_linear_regression.txt 记录上述数字。
C 0.75 十万美元 ≈ 7500 美元偏差。
D R2≈0.59:比永远猜均价多解释约 59% 波动。
验收标准答案
验收项 参考答案
fit/predict fit 学习;predict 输出预测。
RMSE/MAE/R2 误差越小越好;R2 越接近 1 越好。
Baseline 测试 RMSE 0.7514 为比较起点。
散点图 离 y=x 越远误差越大。
概念 解释
Baseline 第一个可参考的模型成绩
fit 用训练数据学习模型参数
predict 用学到的模型输出预测值
RMSE / MAE 回归误差指标
R2 模型解释力
最小二乘 线性回归的经典训练目标

4.12 常见问题

Q:截距 -36.84 很大且为负,正常吗?

A:线性回归的截距要和其他特征系数一起看,单独解读意义有限;未缩放时多个特征尺度不同,截距可能看起来「奇怪」。步骤 5 缩放后会改善解读。

Q:为什么看测试集指标而不是训练集?

A:训练集指标反映「背题」能力,测试集才反映「真考试」能力。

Q:R2 用 R² 还是 R2?

A:数学上常写 R²;本项目中终端打印用 R2 避免 Windows GBK 编码问题,含义相同。

4.13 本步小结

要点 内容
模型 LinearRegression
Baseline 测试集 RMSE 0.7514
Baseline 测试集 R2 0.5871
下一步 特征缩放 + Ridge / Lasso

4.14 学习记录(请你填写)

  • 完成日期
  • 动手任务完成情况:任务 A / B / C / D
  • 我对 R2 的理解
  • 疑问(如有):

步骤 5:特征缩放与 Ridge / Lasso

状态:✅ 已完成教学(已按详细讲解规范增补名词解释与 Mermaid 图)

5.1 本步目标

  1. 理解特征标准化为何对线性模型重要
  2. 学习 Ridge(L2)Lasso(L1) 正则化
  3. 对比多种线性模型,选出测试集表现最佳者

5.2 这一步在解决什么问题?

步骤 4 的线性回归在未缩放特征上训练。各特征量纲不同(收入、人口、经纬度数值范围差很多),会导致:

  • 系数大小不可直接比较
  • 正则化惩罚不公平(大数值特征更容易被「冤枉」)

本步通过 StandardScaler 统一尺度,再用 Ridge / Lasso 控制过拟合。

5.2.5 本步在整体流程中的位置

#mermaid-svg-eI8j9IQTHRbjuhxQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eI8j9IQTHRbjuhxQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eI8j9IQTHRbjuhxQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eI8j9IQTHRbjuhxQ .error-icon{fill:#552222;}#mermaid-svg-eI8j9IQTHRbjuhxQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eI8j9IQTHRbjuhxQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eI8j9IQTHRbjuhxQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eI8j9IQTHRbjuhxQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eI8j9IQTHRbjuhxQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eI8j9IQTHRbjuhxQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eI8j9IQTHRbjuhxQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eI8j9IQTHRbjuhxQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eI8j9IQTHRbjuhxQ .marker.cross{stroke:#333333;}#mermaid-svg-eI8j9IQTHRbjuhxQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eI8j9IQTHRbjuhxQ p{margin:0;}#mermaid-svg-eI8j9IQTHRbjuhxQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-eI8j9IQTHRbjuhxQ .cluster-label text{fill:#333;}#mermaid-svg-eI8j9IQTHRbjuhxQ .cluster-label span{color:#333;}#mermaid-svg-eI8j9IQTHRbjuhxQ .cluster-label span p{background-color:transparent;}#mermaid-svg-eI8j9IQTHRbjuhxQ .label text,#mermaid-svg-eI8j9IQTHRbjuhxQ span{fill:#333;color:#333;}#mermaid-svg-eI8j9IQTHRbjuhxQ .node rect,#mermaid-svg-eI8j9IQTHRbjuhxQ .node circle,#mermaid-svg-eI8j9IQTHRbjuhxQ .node ellipse,#mermaid-svg-eI8j9IQTHRbjuhxQ .node polygon,#mermaid-svg-eI8j9IQTHRbjuhxQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eI8j9IQTHRbjuhxQ .rough-node .label text,#mermaid-svg-eI8j9IQTHRbjuhxQ .node .label text,#mermaid-svg-eI8j9IQTHRbjuhxQ .image-shape .label,#mermaid-svg-eI8j9IQTHRbjuhxQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-eI8j9IQTHRbjuhxQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eI8j9IQTHRbjuhxQ .rough-node .label,#mermaid-svg-eI8j9IQTHRbjuhxQ .node .label,#mermaid-svg-eI8j9IQTHRbjuhxQ .image-shape .label,#mermaid-svg-eI8j9IQTHRbjuhxQ .icon-shape .label{text-align:center;}#mermaid-svg-eI8j9IQTHRbjuhxQ .node.clickable{cursor:pointer;}#mermaid-svg-eI8j9IQTHRbjuhxQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eI8j9IQTHRbjuhxQ .arrowheadPath{fill:#333333;}#mermaid-svg-eI8j9IQTHRbjuhxQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eI8j9IQTHRbjuhxQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eI8j9IQTHRbjuhxQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eI8j9IQTHRbjuhxQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eI8j9IQTHRbjuhxQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eI8j9IQTHRbjuhxQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eI8j9IQTHRbjuhxQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eI8j9IQTHRbjuhxQ .cluster text{fill:#333;}#mermaid-svg-eI8j9IQTHRbjuhxQ .cluster span{color:#333;}#mermaid-svg-eI8j9IQTHRbjuhxQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eI8j9IQTHRbjuhxQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eI8j9IQTHRbjuhxQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-eI8j9IQTHRbjuhxQ .icon-shape,#mermaid-svg-eI8j9IQTHRbjuhxQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eI8j9IQTHRbjuhxQ .icon-shape p,#mermaid-svg-eI8j9IQTHRbjuhxQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eI8j9IQTHRbjuhxQ .icon-shape .label rect,#mermaid-svg-eI8j9IQTHRbjuhxQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eI8j9IQTHRbjuhxQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eI8j9IQTHRbjuhxQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eI8j9IQTHRbjuhxQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

步骤4 Baseline RMSE=0.7514
步骤5 标准化特征
训练 Ridge/Lasso 多组 alpha
对比测试 RMSE
是否优于 Baseline?
记录最佳线性模型
仍保留结论供树模型对比
步骤6 树模型 不需缩放

5.2.6 名词解释(本步首次出现)

名词 是什么 为什么需要 在本项目中 易混淆
StandardScaler 标准化工具:减均值、除标准差 统一特征量纲,线性模型与正则化更公平 只在 X_train fit 不是 MinMaxScaler
Z-score 标准化 变换后均值≈0、标准差≈1 消除「人口几万 vs 纬度30多」的量纲差 缩放后各列 mean≈0 std≈1 不改变样本行数
fit_transform 先 fit 再 transform,用于训练集 学习均值/标准差并变换 scaler.fit_transform(X_train) 不能用于测试集 fit
transform 用已学到的参数变换新数据 测试集必须用训练集的统计量 scaler.transform(X_test) 不是 fit
正则化 在损失函数中加惩罚,限制系数过大 缓解过拟合、稳定求解 Ridge/Lasso 的核心 不是特征选择同义词
Ridge(L2) 惩罚系数平方和 系数整体变小,保留全部特征 alpha 大时变化明显 不做稀疏化
Lasso(L1) 惩罚系数绝对值之和 可把部分系数压到 0 alpha=0.01 最佳 不是 Ridge
alpha 正则化强度超参数 控制「简单 vs 复杂」 0.01 好,0.1 欠拟合 不是学习率
欠拟合 模型过于简单,训练/测试都差 alpha 过大时出现 Lasso 0.1 RMSE=0.8337 不是过拟合
过拟合 训练好、测试差 本数据线性回归未严重过拟合 Ridge 改善很小 步骤4 轻微差距正常

5.3 任务清单

  • StandardScaler 只在 X_trainfit
  • 训练 Ridge(4 组 alpha)、Lasso(4 组 alpha)
  • 对比线性回归、Ridge、Lasso 的测试集 RMSE
  • 保存对比报告与中文 RMSE 条形图

5.4 运行本步

powershell 复制代码
cd "d:\JavaCode\机器学习\project_01_housing"
python src/train.py

5.5 实验结果(你的环境)

模型 测试 RMSE 测试 R2
线性回归(标准化) 0.7514 0.5871
Ridge(alpha=0.01~1.0) ≈0.7514 ≈0.5871
Ridge(alpha=10.0) 0.7512 0.5874
Lasso(alpha=0.001) 0.7505 0.5881
Lasso(alpha=0.01) 0.7472 0.5917
Lasso(alpha=0.1) 0.8337 0.4917

最佳模型Lasso(alpha=0.01),测试 RMSE 0.7472

相对步骤 4 Baseline(0.7514)降低 0.0042,略有改善。

重要观察

  • alpha 太小 → 接近普通线性回归,改善有限
  • alpha 太大(如 Lasso 0.1)→ 欠拟合,RMSE 飙升到 0.8337
  • Ridge 在本数据集上变化很小 → 说明步骤 4 的线性回归并未严重过拟合

5.6 核心代码解读

(1)标准化 ------ 防止数据泄露
python 复制代码
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)   # 只在训练集 fit
X_test_scaled = scaler.transform(X_test)           # 测试集只 transform
步骤 做什么
fit_transform(X_train) 用训练集算均值/标准差,并变换训练集
transform(X_test) 训练集的均值/标准差变换测试集

切忌 :对 X_test 单独 fit,会把测试集信息泄露到预处理中。

缩放后训练集各列均值 ≈ 0,标准差 ≈ 1。
#mermaid-svg-Re0TpIICdDMfea0z{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Re0TpIICdDMfea0z .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Re0TpIICdDMfea0z .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Re0TpIICdDMfea0z .error-icon{fill:#552222;}#mermaid-svg-Re0TpIICdDMfea0z .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Re0TpIICdDMfea0z .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Re0TpIICdDMfea0z .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Re0TpIICdDMfea0z .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Re0TpIICdDMfea0z .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Re0TpIICdDMfea0z .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Re0TpIICdDMfea0z .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Re0TpIICdDMfea0z .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Re0TpIICdDMfea0z .marker.cross{stroke:#333333;}#mermaid-svg-Re0TpIICdDMfea0z svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Re0TpIICdDMfea0z p{margin:0;}#mermaid-svg-Re0TpIICdDMfea0z .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Re0TpIICdDMfea0z .cluster-label text{fill:#333;}#mermaid-svg-Re0TpIICdDMfea0z .cluster-label span{color:#333;}#mermaid-svg-Re0TpIICdDMfea0z .cluster-label span p{background-color:transparent;}#mermaid-svg-Re0TpIICdDMfea0z .label text,#mermaid-svg-Re0TpIICdDMfea0z span{fill:#333;color:#333;}#mermaid-svg-Re0TpIICdDMfea0z .node rect,#mermaid-svg-Re0TpIICdDMfea0z .node circle,#mermaid-svg-Re0TpIICdDMfea0z .node ellipse,#mermaid-svg-Re0TpIICdDMfea0z .node polygon,#mermaid-svg-Re0TpIICdDMfea0z .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Re0TpIICdDMfea0z .rough-node .label text,#mermaid-svg-Re0TpIICdDMfea0z .node .label text,#mermaid-svg-Re0TpIICdDMfea0z .image-shape .label,#mermaid-svg-Re0TpIICdDMfea0z .icon-shape .label{text-anchor:middle;}#mermaid-svg-Re0TpIICdDMfea0z .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Re0TpIICdDMfea0z .rough-node .label,#mermaid-svg-Re0TpIICdDMfea0z .node .label,#mermaid-svg-Re0TpIICdDMfea0z .image-shape .label,#mermaid-svg-Re0TpIICdDMfea0z .icon-shape .label{text-align:center;}#mermaid-svg-Re0TpIICdDMfea0z .node.clickable{cursor:pointer;}#mermaid-svg-Re0TpIICdDMfea0z .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Re0TpIICdDMfea0z .arrowheadPath{fill:#333333;}#mermaid-svg-Re0TpIICdDMfea0z .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Re0TpIICdDMfea0z .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Re0TpIICdDMfea0z .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Re0TpIICdDMfea0z .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Re0TpIICdDMfea0z .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Re0TpIICdDMfea0z .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Re0TpIICdDMfea0z .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Re0TpIICdDMfea0z .cluster text{fill:#333;}#mermaid-svg-Re0TpIICdDMfea0z .cluster span{color:#333;}#mermaid-svg-Re0TpIICdDMfea0z div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Re0TpIICdDMfea0z .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Re0TpIICdDMfea0z rect.text{fill:none;stroke-width:0;}#mermaid-svg-Re0TpIICdDMfea0z .icon-shape,#mermaid-svg-Re0TpIICdDMfea0z .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Re0TpIICdDMfea0z .icon-shape p,#mermaid-svg-Re0TpIICdDMfea0z .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Re0TpIICdDMfea0z .icon-shape .label rect,#mermaid-svg-Re0TpIICdDMfea0z .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Re0TpIICdDMfea0z .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Re0TpIICdDMfea0z .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Re0TpIICdDMfea0z :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 禁止
X_train
scaler.fit_transform
X_train_scaled
X_test
scaler.transform 只用训练集参数
X_test_scaled
对 X_test fit 会泄露

(2)Ridge 与 Lasso
模型 正则类型 效果
Ridge L2(系数平方和) 把系数整体压小,保留全部特征
Lasso L1(系数绝对值之和) 可把部分系数压到 0,做特征选择

alpha 越大 → 正则越强 → 模型越「简单」→ 过大则欠拟合。
#mermaid-svg-JbviTqlNKCSembJf{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JbviTqlNKCSembJf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JbviTqlNKCSembJf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JbviTqlNKCSembJf .error-icon{fill:#552222;}#mermaid-svg-JbviTqlNKCSembJf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JbviTqlNKCSembJf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JbviTqlNKCSembJf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JbviTqlNKCSembJf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JbviTqlNKCSembJf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JbviTqlNKCSembJf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JbviTqlNKCSembJf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JbviTqlNKCSembJf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JbviTqlNKCSembJf .marker.cross{stroke:#333333;}#mermaid-svg-JbviTqlNKCSembJf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JbviTqlNKCSembJf p{margin:0;}#mermaid-svg-JbviTqlNKCSembJf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JbviTqlNKCSembJf .cluster-label text{fill:#333;}#mermaid-svg-JbviTqlNKCSembJf .cluster-label span{color:#333;}#mermaid-svg-JbviTqlNKCSembJf .cluster-label span p{background-color:transparent;}#mermaid-svg-JbviTqlNKCSembJf .label text,#mermaid-svg-JbviTqlNKCSembJf span{fill:#333;color:#333;}#mermaid-svg-JbviTqlNKCSembJf .node rect,#mermaid-svg-JbviTqlNKCSembJf .node circle,#mermaid-svg-JbviTqlNKCSembJf .node ellipse,#mermaid-svg-JbviTqlNKCSembJf .node polygon,#mermaid-svg-JbviTqlNKCSembJf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JbviTqlNKCSembJf .rough-node .label text,#mermaid-svg-JbviTqlNKCSembJf .node .label text,#mermaid-svg-JbviTqlNKCSembJf .image-shape .label,#mermaid-svg-JbviTqlNKCSembJf .icon-shape .label{text-anchor:middle;}#mermaid-svg-JbviTqlNKCSembJf .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JbviTqlNKCSembJf .rough-node .label,#mermaid-svg-JbviTqlNKCSembJf .node .label,#mermaid-svg-JbviTqlNKCSembJf .image-shape .label,#mermaid-svg-JbviTqlNKCSembJf .icon-shape .label{text-align:center;}#mermaid-svg-JbviTqlNKCSembJf .node.clickable{cursor:pointer;}#mermaid-svg-JbviTqlNKCSembJf .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JbviTqlNKCSembJf .arrowheadPath{fill:#333333;}#mermaid-svg-JbviTqlNKCSembJf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JbviTqlNKCSembJf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JbviTqlNKCSembJf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JbviTqlNKCSembJf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JbviTqlNKCSembJf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JbviTqlNKCSembJf .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JbviTqlNKCSembJf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JbviTqlNKCSembJf .cluster text{fill:#333;}#mermaid-svg-JbviTqlNKCSembJf .cluster span{color:#333;}#mermaid-svg-JbviTqlNKCSembJf div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JbviTqlNKCSembJf .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JbviTqlNKCSembJf rect.text{fill:none;stroke-width:0;}#mermaid-svg-JbviTqlNKCSembJf .icon-shape,#mermaid-svg-JbviTqlNKCSembJf .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JbviTqlNKCSembJf .icon-shape p,#mermaid-svg-JbviTqlNKCSembJf .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JbviTqlNKCSembJf .icon-shape .label rect,#mermaid-svg-JbviTqlNKCSembJf .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JbviTqlNKCSembJf .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JbviTqlNKCSembJf .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JbviTqlNKCSembJf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alpha 对模型的影响
alpha很小
接近线性回归
alpha适中
可能略改善
alpha很大
欠拟合 RMSE升高

(3)对比实验流程

#mermaid-svg-PNzC5GecHpkl8DmI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PNzC5GecHpkl8DmI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PNzC5GecHpkl8DmI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PNzC5GecHpkl8DmI .error-icon{fill:#552222;}#mermaid-svg-PNzC5GecHpkl8DmI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PNzC5GecHpkl8DmI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PNzC5GecHpkl8DmI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PNzC5GecHpkl8DmI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PNzC5GecHpkl8DmI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PNzC5GecHpkl8DmI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PNzC5GecHpkl8DmI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PNzC5GecHpkl8DmI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PNzC5GecHpkl8DmI .marker.cross{stroke:#333333;}#mermaid-svg-PNzC5GecHpkl8DmI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PNzC5GecHpkl8DmI p{margin:0;}#mermaid-svg-PNzC5GecHpkl8DmI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PNzC5GecHpkl8DmI .cluster-label text{fill:#333;}#mermaid-svg-PNzC5GecHpkl8DmI .cluster-label span{color:#333;}#mermaid-svg-PNzC5GecHpkl8DmI .cluster-label span p{background-color:transparent;}#mermaid-svg-PNzC5GecHpkl8DmI .label text,#mermaid-svg-PNzC5GecHpkl8DmI span{fill:#333;color:#333;}#mermaid-svg-PNzC5GecHpkl8DmI .node rect,#mermaid-svg-PNzC5GecHpkl8DmI .node circle,#mermaid-svg-PNzC5GecHpkl8DmI .node ellipse,#mermaid-svg-PNzC5GecHpkl8DmI .node polygon,#mermaid-svg-PNzC5GecHpkl8DmI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PNzC5GecHpkl8DmI .rough-node .label text,#mermaid-svg-PNzC5GecHpkl8DmI .node .label text,#mermaid-svg-PNzC5GecHpkl8DmI .image-shape .label,#mermaid-svg-PNzC5GecHpkl8DmI .icon-shape .label{text-anchor:middle;}#mermaid-svg-PNzC5GecHpkl8DmI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PNzC5GecHpkl8DmI .rough-node .label,#mermaid-svg-PNzC5GecHpkl8DmI .node .label,#mermaid-svg-PNzC5GecHpkl8DmI .image-shape .label,#mermaid-svg-PNzC5GecHpkl8DmI .icon-shape .label{text-align:center;}#mermaid-svg-PNzC5GecHpkl8DmI .node.clickable{cursor:pointer;}#mermaid-svg-PNzC5GecHpkl8DmI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PNzC5GecHpkl8DmI .arrowheadPath{fill:#333333;}#mermaid-svg-PNzC5GecHpkl8DmI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PNzC5GecHpkl8DmI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PNzC5GecHpkl8DmI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PNzC5GecHpkl8DmI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PNzC5GecHpkl8DmI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PNzC5GecHpkl8DmI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PNzC5GecHpkl8DmI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PNzC5GecHpkl8DmI .cluster text{fill:#333;}#mermaid-svg-PNzC5GecHpkl8DmI .cluster span{color:#333;}#mermaid-svg-PNzC5GecHpkl8DmI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PNzC5GecHpkl8DmI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PNzC5GecHpkl8DmI rect.text{fill:none;stroke-width:0;}#mermaid-svg-PNzC5GecHpkl8DmI .icon-shape,#mermaid-svg-PNzC5GecHpkl8DmI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PNzC5GecHpkl8DmI .icon-shape p,#mermaid-svg-PNzC5GecHpkl8DmI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PNzC5GecHpkl8DmI .icon-shape .label rect,#mermaid-svg-PNzC5GecHpkl8DmI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PNzC5GecHpkl8DmI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PNzC5GecHpkl8DmI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PNzC5GecHpkl8DmI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} StandardScaler
线性回归
Ridge 多组alpha
Lasso 多组alpha
对比测试集 RMSE
选 RMSE 最小者

5.7 可视化

reports/figures/06_scaled_models_rmse.png

  • 标题:标准化后各线性模型测试集 RMSE 对比(越小越好)
  • 绿色条:RMSE 最低的模型(本步为 Lasso alpha=0.01)

#mermaid-svg-LSyuAwHEnJ0YZaBe{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LSyuAwHEnJ0YZaBe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LSyuAwHEnJ0YZaBe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LSyuAwHEnJ0YZaBe .error-icon{fill:#552222;}#mermaid-svg-LSyuAwHEnJ0YZaBe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LSyuAwHEnJ0YZaBe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LSyuAwHEnJ0YZaBe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LSyuAwHEnJ0YZaBe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LSyuAwHEnJ0YZaBe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LSyuAwHEnJ0YZaBe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LSyuAwHEnJ0YZaBe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LSyuAwHEnJ0YZaBe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LSyuAwHEnJ0YZaBe .marker.cross{stroke:#333333;}#mermaid-svg-LSyuAwHEnJ0YZaBe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LSyuAwHEnJ0YZaBe p{margin:0;}#mermaid-svg-LSyuAwHEnJ0YZaBe .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-LSyuAwHEnJ0YZaBe .cluster-label text{fill:#333;}#mermaid-svg-LSyuAwHEnJ0YZaBe .cluster-label span{color:#333;}#mermaid-svg-LSyuAwHEnJ0YZaBe .cluster-label span p{background-color:transparent;}#mermaid-svg-LSyuAwHEnJ0YZaBe .label text,#mermaid-svg-LSyuAwHEnJ0YZaBe span{fill:#333;color:#333;}#mermaid-svg-LSyuAwHEnJ0YZaBe .node rect,#mermaid-svg-LSyuAwHEnJ0YZaBe .node circle,#mermaid-svg-LSyuAwHEnJ0YZaBe .node ellipse,#mermaid-svg-LSyuAwHEnJ0YZaBe .node polygon,#mermaid-svg-LSyuAwHEnJ0YZaBe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LSyuAwHEnJ0YZaBe .rough-node .label text,#mermaid-svg-LSyuAwHEnJ0YZaBe .node .label text,#mermaid-svg-LSyuAwHEnJ0YZaBe .image-shape .label,#mermaid-svg-LSyuAwHEnJ0YZaBe .icon-shape .label{text-anchor:middle;}#mermaid-svg-LSyuAwHEnJ0YZaBe .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LSyuAwHEnJ0YZaBe .rough-node .label,#mermaid-svg-LSyuAwHEnJ0YZaBe .node .label,#mermaid-svg-LSyuAwHEnJ0YZaBe .image-shape .label,#mermaid-svg-LSyuAwHEnJ0YZaBe .icon-shape .label{text-align:center;}#mermaid-svg-LSyuAwHEnJ0YZaBe .node.clickable{cursor:pointer;}#mermaid-svg-LSyuAwHEnJ0YZaBe .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LSyuAwHEnJ0YZaBe .arrowheadPath{fill:#333333;}#mermaid-svg-LSyuAwHEnJ0YZaBe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LSyuAwHEnJ0YZaBe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LSyuAwHEnJ0YZaBe .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LSyuAwHEnJ0YZaBe .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LSyuAwHEnJ0YZaBe .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LSyuAwHEnJ0YZaBe .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LSyuAwHEnJ0YZaBe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LSyuAwHEnJ0YZaBe .cluster text{fill:#333;}#mermaid-svg-LSyuAwHEnJ0YZaBe .cluster span{color:#333;}#mermaid-svg-LSyuAwHEnJ0YZaBe div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LSyuAwHEnJ0YZaBe .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LSyuAwHEnJ0YZaBe rect.text{fill:none;stroke-width:0;}#mermaid-svg-LSyuAwHEnJ0YZaBe .icon-shape,#mermaid-svg-LSyuAwHEnJ0YZaBe .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LSyuAwHEnJ0YZaBe .icon-shape p,#mermaid-svg-LSyuAwHEnJ0YZaBe .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LSyuAwHEnJ0YZaBe .icon-shape .label rect,#mermaid-svg-LSyuAwHEnJ0YZaBe .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LSyuAwHEnJ0YZaBe .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LSyuAwHEnJ0YZaBe .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LSyuAwHEnJ0YZaBe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 本步实验结论
Baseline 0.7514
Lasso0.01 最佳 0.7472
Lasso0.1 欠拟合 0.8337

5.8 动手任务

任务 A:运行脚本,确认最佳模型为 Lasso(alpha=0.01)

任务 B:观察 Lasso(alpha=0.1)RMSE 为何变差?(答:正则过强,欠拟合)

任务 C:思考------为何 Ridge 几乎没变化?(答:本数据线性回归未严重过拟合,L2 惩罚带来的变化很小)

任务 D:在 README 写一句话:StandardScaler 为何只能 fit 训练集?

5.9 验收标准

  • 能解释 fit vs transform 的区别
  • 能说明 Ridge 与 Lasso 的差异
  • 能解释 alpha 过大/过小的影响
  • 能读 RMSE 对比图并指出最佳模型

5.10 本步核心概念

5.10 动手任务与验收标准参考答案

以下为教学标准答案,便于自学对照;README.md 学习记录仍建议用自己的话写。

动手任务答案
任务 参考答案
A 最佳 Lasso alpha=0.01,RMSE 0.7472。
B alpha=0.1 欠拟合,RMSE 0.8337。
C 线性回归未严重过拟合,Ridge 变化小。
D Scaler 只能 fit 训练集,否则泄露测试集统计量。
验收标准答案
验收项 参考答案
fit vs transform fit 学参数;transform 应用;测试集只 transform。
Ridge vs Lasso L2 缩小系数;L1 可稀疏化。
alpha 过小接近回归;过大欠拟合。
最佳模型 Lasso 0.01,RMSE 0.7472。
概念 解释
标准化(Z-score) 减均值、除标准差,统一到可比尺度
正则化 在损失函数中加惩罚,限制模型复杂度
L1 / L2 Lasso 用 L1,Ridge 用 L2
alpha 正则化强度超参数
欠拟合 模型过于简单,训练/测试都差(如 Lasso alpha=0.1)

5.11 常见问题

Q:标准化后线性回归 RMSE 与步骤 4 一样?

A:线性回归在数学上对特征缩放不敏感(预测值不变),所以 RMSE 相同是正常的。

Q:下一步树模型还需要缩放吗?

A:步骤 6 会讲------树模型不需要缩放,这是线性与树模型的重要区别。

5.12 本步小结

要点 内容
最佳模型 Lasso(alpha=0.01)
最佳测试 RMSE 0.7472
关键教训 alpha 需要调;过大正则会欠拟合
下一步 随机森林与梯度提升(树模型)

5.13 学习记录(请你填写)

  • 完成日期
  • 动手任务完成情况:任务 A / B / C / D
  • 我对 StandardScaler 的理解
  • 疑问(如有):

步骤 6:树模型 ------ 随机森林与梯度提升

状态 :✅ 已完成教学(报告见 reports/tree_models_summary.txt,图表见 07_08_ 系列 PNG)

6.1 本步目标

  1. 引入非线性模型:随机森林、梯度提升
  2. 理解树模型不需要特征缩放(与步骤 5 对比)
  3. 学会看特征重要性,并汇总步骤 4~6 模型表现

6.2 这一步在解决什么问题?

步骤 4~5 的线性模型假设:「特征与房价是直线关系」。但真实数据里可能是:

  • 收入很低时,房价随收入涨得快;很高时变缓(非线性)
  • 经纬度组合体现地理位置(分区效应)

决策树 通过「如果收入 > 3.5 则走左边,否则走右边」这种方式切分数据,能拟合非线性。

本步用两种集成方法把多棵树组合起来:

方法 代表模型 核心思想
Bagging 随机森林 多棵树并行训练,结果平均
Boosting 梯度提升 多棵树串行训练,后一棵修正前一棵错误

6.2.5 本步在整体流程中的位置

#mermaid-svg-Sv1fvlukyYW8HdqT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Sv1fvlukyYW8HdqT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Sv1fvlukyYW8HdqT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Sv1fvlukyYW8HdqT .error-icon{fill:#552222;}#mermaid-svg-Sv1fvlukyYW8HdqT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Sv1fvlukyYW8HdqT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Sv1fvlukyYW8HdqT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Sv1fvlukyYW8HdqT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Sv1fvlukyYW8HdqT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Sv1fvlukyYW8HdqT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Sv1fvlukyYW8HdqT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Sv1fvlukyYW8HdqT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Sv1fvlukyYW8HdqT .marker.cross{stroke:#333333;}#mermaid-svg-Sv1fvlukyYW8HdqT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Sv1fvlukyYW8HdqT p{margin:0;}#mermaid-svg-Sv1fvlukyYW8HdqT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Sv1fvlukyYW8HdqT .cluster-label text{fill:#333;}#mermaid-svg-Sv1fvlukyYW8HdqT .cluster-label span{color:#333;}#mermaid-svg-Sv1fvlukyYW8HdqT .cluster-label span p{background-color:transparent;}#mermaid-svg-Sv1fvlukyYW8HdqT .label text,#mermaid-svg-Sv1fvlukyYW8HdqT span{fill:#333;color:#333;}#mermaid-svg-Sv1fvlukyYW8HdqT .node rect,#mermaid-svg-Sv1fvlukyYW8HdqT .node circle,#mermaid-svg-Sv1fvlukyYW8HdqT .node ellipse,#mermaid-svg-Sv1fvlukyYW8HdqT .node polygon,#mermaid-svg-Sv1fvlukyYW8HdqT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Sv1fvlukyYW8HdqT .rough-node .label text,#mermaid-svg-Sv1fvlukyYW8HdqT .node .label text,#mermaid-svg-Sv1fvlukyYW8HdqT .image-shape .label,#mermaid-svg-Sv1fvlukyYW8HdqT .icon-shape .label{text-anchor:middle;}#mermaid-svg-Sv1fvlukyYW8HdqT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Sv1fvlukyYW8HdqT .rough-node .label,#mermaid-svg-Sv1fvlukyYW8HdqT .node .label,#mermaid-svg-Sv1fvlukyYW8HdqT .image-shape .label,#mermaid-svg-Sv1fvlukyYW8HdqT .icon-shape .label{text-align:center;}#mermaid-svg-Sv1fvlukyYW8HdqT .node.clickable{cursor:pointer;}#mermaid-svg-Sv1fvlukyYW8HdqT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Sv1fvlukyYW8HdqT .arrowheadPath{fill:#333333;}#mermaid-svg-Sv1fvlukyYW8HdqT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Sv1fvlukyYW8HdqT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Sv1fvlukyYW8HdqT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Sv1fvlukyYW8HdqT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Sv1fvlukyYW8HdqT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Sv1fvlukyYW8HdqT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Sv1fvlukyYW8HdqT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Sv1fvlukyYW8HdqT .cluster text{fill:#333;}#mermaid-svg-Sv1fvlukyYW8HdqT .cluster span{color:#333;}#mermaid-svg-Sv1fvlukyYW8HdqT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Sv1fvlukyYW8HdqT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Sv1fvlukyYW8HdqT rect.text{fill:none;stroke-width:0;}#mermaid-svg-Sv1fvlukyYW8HdqT .icon-shape,#mermaid-svg-Sv1fvlukyYW8HdqT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Sv1fvlukyYW8HdqT .icon-shape p,#mermaid-svg-Sv1fvlukyYW8HdqT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Sv1fvlukyYW8HdqT .icon-shape .label rect,#mermaid-svg-Sv1fvlukyYW8HdqT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Sv1fvlukyYW8HdqT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Sv1fvlukyYW8HdqT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Sv1fvlukyYW8HdqT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 步骤4 线性Baseline 0.75
步骤5 Lasso 0.75
步骤6 树模型
随机森林 0.52
梯度提升 0.48
步骤7 特征工程

6.2.6 名词解释(本步首次出现)

名词 是什么 为什么需要 在本项目中 易混淆
决策树 按特征阈值逐层分裂的树形规则 能表达非线性、分区关系 RF 和 GBR 的基础单元 不是流程图
随机森林 RF 多棵决策树 Bagging 集成 降低单棵树过拟合 RandomForestRegressor 不是一棵大树
梯度提升 GBR 多棵树 Boosting 串行叠加 往往比单树/RF 更准 HistGradientBoostingRegressor 不是随机森林
Bagging 自助采样训练多模型再平均 降方差、更稳定 随机森林的核心 不是 Boosting
Boosting 后续模型拟合前面模型的残差 逐步减少误差 梯度提升的核心 不是 Bagging
n_estimators 树的数量或提升轮数 影响模型容量与训练时间 本步设为 100 不是深度
特征重要性 某特征在所有分裂中的贡献度 解释模型认为什么因素关键 MedInc 约 52% 不是因果
非线性 关系不是直线 房价问题存在分区/阈值效应 树模型 RMSE 明显低于线性 不是无关

6.2.7 线性模型 vs 树模型(Mermaid)

#mermaid-svg-5gi3N2qd61HeAhI9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5gi3N2qd61HeAhI9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5gi3N2qd61HeAhI9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5gi3N2qd61HeAhI9 .error-icon{fill:#552222;}#mermaid-svg-5gi3N2qd61HeAhI9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5gi3N2qd61HeAhI9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5gi3N2qd61HeAhI9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5gi3N2qd61HeAhI9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5gi3N2qd61HeAhI9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5gi3N2qd61HeAhI9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5gi3N2qd61HeAhI9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5gi3N2qd61HeAhI9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5gi3N2qd61HeAhI9 .marker.cross{stroke:#333333;}#mermaid-svg-5gi3N2qd61HeAhI9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5gi3N2qd61HeAhI9 p{margin:0;}#mermaid-svg-5gi3N2qd61HeAhI9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5gi3N2qd61HeAhI9 .cluster-label text{fill:#333;}#mermaid-svg-5gi3N2qd61HeAhI9 .cluster-label span{color:#333;}#mermaid-svg-5gi3N2qd61HeAhI9 .cluster-label span p{background-color:transparent;}#mermaid-svg-5gi3N2qd61HeAhI9 .label text,#mermaid-svg-5gi3N2qd61HeAhI9 span{fill:#333;color:#333;}#mermaid-svg-5gi3N2qd61HeAhI9 .node rect,#mermaid-svg-5gi3N2qd61HeAhI9 .node circle,#mermaid-svg-5gi3N2qd61HeAhI9 .node ellipse,#mermaid-svg-5gi3N2qd61HeAhI9 .node polygon,#mermaid-svg-5gi3N2qd61HeAhI9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5gi3N2qd61HeAhI9 .rough-node .label text,#mermaid-svg-5gi3N2qd61HeAhI9 .node .label text,#mermaid-svg-5gi3N2qd61HeAhI9 .image-shape .label,#mermaid-svg-5gi3N2qd61HeAhI9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-5gi3N2qd61HeAhI9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5gi3N2qd61HeAhI9 .rough-node .label,#mermaid-svg-5gi3N2qd61HeAhI9 .node .label,#mermaid-svg-5gi3N2qd61HeAhI9 .image-shape .label,#mermaid-svg-5gi3N2qd61HeAhI9 .icon-shape .label{text-align:center;}#mermaid-svg-5gi3N2qd61HeAhI9 .node.clickable{cursor:pointer;}#mermaid-svg-5gi3N2qd61HeAhI9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5gi3N2qd61HeAhI9 .arrowheadPath{fill:#333333;}#mermaid-svg-5gi3N2qd61HeAhI9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5gi3N2qd61HeAhI9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5gi3N2qd61HeAhI9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5gi3N2qd61HeAhI9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5gi3N2qd61HeAhI9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5gi3N2qd61HeAhI9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5gi3N2qd61HeAhI9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5gi3N2qd61HeAhI9 .cluster text{fill:#333;}#mermaid-svg-5gi3N2qd61HeAhI9 .cluster span{color:#333;}#mermaid-svg-5gi3N2qd61HeAhI9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5gi3N2qd61HeAhI9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5gi3N2qd61HeAhI9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-5gi3N2qd61HeAhI9 .icon-shape,#mermaid-svg-5gi3N2qd61HeAhI9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5gi3N2qd61HeAhI9 .icon-shape p,#mermaid-svg-5gi3N2qd61HeAhI9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5gi3N2qd61HeAhI9 .icon-shape .label rect,#mermaid-svg-5gi3N2qd61HeAhI9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5gi3N2qd61HeAhI9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5gi3N2qd61HeAhI9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5gi3N2qd61HeAhI9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 树模型 步骤6
分区切分 可非线性
用原始特征即可
RMSE约0.48
线性模型 步骤4-5
假设直线关系
需要StandardScaler
RMSE约0.75

6.3 任务清单

  • 训练 RandomForestRegressor(100 棵树)
  • 训练 HistGradientBoostingRegressor(100 轮)
  • 使用未缩放原始特征
  • 绘制随机森林特征重要性图
  • 汇总步骤 4~6 模型 RMSE 对比

6.4 运行本步

powershell 复制代码
cd "d:\JavaCode\机器学习\project_01_housing"
python src/train.py

6.5 实验结果(你的环境)

步骤 6 树模型:

模型 测试 RMSE 测试 R2
随机森林 0.5190 0.8030
梯度提升 HistGBR 0.4763 0.8341

步骤 4~6 汇总:

模型 测试 RMSE 相对 Baseline
步骤4 线性回归 Baseline 0.7514 ---
步骤5 Lasso alpha=0.01 0.7472 略好
步骤6 随机森林 0.5190 大幅降低
步骤6 梯度提升 0.4763 最佳

关键发现:

  • 树模型 RMSE 从 0.75 → 0.48 ,R2 从 0.59 → 0.83,提升巨大
  • 说明房价与特征之间存在明显非线性,线性模型不够用
  • 随机森林特征重要性 Top3:收入 MedInc(52%)、平均入住人数、纬度

6.6 决策树如何工作(直觉)

#mermaid-svg-X4b4lqkIpdLPnNIJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-X4b4lqkIpdLPnNIJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-X4b4lqkIpdLPnNIJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-X4b4lqkIpdLPnNIJ .error-icon{fill:#552222;}#mermaid-svg-X4b4lqkIpdLPnNIJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-X4b4lqkIpdLPnNIJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-X4b4lqkIpdLPnNIJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-X4b4lqkIpdLPnNIJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-X4b4lqkIpdLPnNIJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-X4b4lqkIpdLPnNIJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-X4b4lqkIpdLPnNIJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-X4b4lqkIpdLPnNIJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-X4b4lqkIpdLPnNIJ .marker.cross{stroke:#333333;}#mermaid-svg-X4b4lqkIpdLPnNIJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-X4b4lqkIpdLPnNIJ p{margin:0;}#mermaid-svg-X4b4lqkIpdLPnNIJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-X4b4lqkIpdLPnNIJ .cluster-label text{fill:#333;}#mermaid-svg-X4b4lqkIpdLPnNIJ .cluster-label span{color:#333;}#mermaid-svg-X4b4lqkIpdLPnNIJ .cluster-label span p{background-color:transparent;}#mermaid-svg-X4b4lqkIpdLPnNIJ .label text,#mermaid-svg-X4b4lqkIpdLPnNIJ span{fill:#333;color:#333;}#mermaid-svg-X4b4lqkIpdLPnNIJ .node rect,#mermaid-svg-X4b4lqkIpdLPnNIJ .node circle,#mermaid-svg-X4b4lqkIpdLPnNIJ .node ellipse,#mermaid-svg-X4b4lqkIpdLPnNIJ .node polygon,#mermaid-svg-X4b4lqkIpdLPnNIJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-X4b4lqkIpdLPnNIJ .rough-node .label text,#mermaid-svg-X4b4lqkIpdLPnNIJ .node .label text,#mermaid-svg-X4b4lqkIpdLPnNIJ .image-shape .label,#mermaid-svg-X4b4lqkIpdLPnNIJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-X4b4lqkIpdLPnNIJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-X4b4lqkIpdLPnNIJ .rough-node .label,#mermaid-svg-X4b4lqkIpdLPnNIJ .node .label,#mermaid-svg-X4b4lqkIpdLPnNIJ .image-shape .label,#mermaid-svg-X4b4lqkIpdLPnNIJ .icon-shape .label{text-align:center;}#mermaid-svg-X4b4lqkIpdLPnNIJ .node.clickable{cursor:pointer;}#mermaid-svg-X4b4lqkIpdLPnNIJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-X4b4lqkIpdLPnNIJ .arrowheadPath{fill:#333333;}#mermaid-svg-X4b4lqkIpdLPnNIJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-X4b4lqkIpdLPnNIJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-X4b4lqkIpdLPnNIJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-X4b4lqkIpdLPnNIJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-X4b4lqkIpdLPnNIJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-X4b4lqkIpdLPnNIJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-X4b4lqkIpdLPnNIJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-X4b4lqkIpdLPnNIJ .cluster text{fill:#333;}#mermaid-svg-X4b4lqkIpdLPnNIJ .cluster span{color:#333;}#mermaid-svg-X4b4lqkIpdLPnNIJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-X4b4lqkIpdLPnNIJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-X4b4lqkIpdLPnNIJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-X4b4lqkIpdLPnNIJ .icon-shape,#mermaid-svg-X4b4lqkIpdLPnNIJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-X4b4lqkIpdLPnNIJ .icon-shape p,#mermaid-svg-X4b4lqkIpdLPnNIJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-X4b4lqkIpdLPnNIJ .icon-shape .label rect,#mermaid-svg-X4b4lqkIpdLPnNIJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-X4b4lqkIpdLPnNIJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-X4b4lqkIpdLPnNIJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-X4b4lqkIpdLPnNIJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

根节点 全部样本
MedInc <= 3.5?
左子树 低价区
右子树 高价区
预测较低房价
预测较高房价

单棵树容易过拟合 (背训练集)。随机森林训练 100 棵不同的树再平均预测,更稳定。

6.7 Bagging vs Boosting(Mermaid)

#mermaid-svg-27Z3UCGmDNIfYGQR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-27Z3UCGmDNIfYGQR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-27Z3UCGmDNIfYGQR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-27Z3UCGmDNIfYGQR .error-icon{fill:#552222;}#mermaid-svg-27Z3UCGmDNIfYGQR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-27Z3UCGmDNIfYGQR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-27Z3UCGmDNIfYGQR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-27Z3UCGmDNIfYGQR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-27Z3UCGmDNIfYGQR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-27Z3UCGmDNIfYGQR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-27Z3UCGmDNIfYGQR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-27Z3UCGmDNIfYGQR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-27Z3UCGmDNIfYGQR .marker.cross{stroke:#333333;}#mermaid-svg-27Z3UCGmDNIfYGQR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-27Z3UCGmDNIfYGQR p{margin:0;}#mermaid-svg-27Z3UCGmDNIfYGQR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-27Z3UCGmDNIfYGQR .cluster-label text{fill:#333;}#mermaid-svg-27Z3UCGmDNIfYGQR .cluster-label span{color:#333;}#mermaid-svg-27Z3UCGmDNIfYGQR .cluster-label span p{background-color:transparent;}#mermaid-svg-27Z3UCGmDNIfYGQR .label text,#mermaid-svg-27Z3UCGmDNIfYGQR span{fill:#333;color:#333;}#mermaid-svg-27Z3UCGmDNIfYGQR .node rect,#mermaid-svg-27Z3UCGmDNIfYGQR .node circle,#mermaid-svg-27Z3UCGmDNIfYGQR .node ellipse,#mermaid-svg-27Z3UCGmDNIfYGQR .node polygon,#mermaid-svg-27Z3UCGmDNIfYGQR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-27Z3UCGmDNIfYGQR .rough-node .label text,#mermaid-svg-27Z3UCGmDNIfYGQR .node .label text,#mermaid-svg-27Z3UCGmDNIfYGQR .image-shape .label,#mermaid-svg-27Z3UCGmDNIfYGQR .icon-shape .label{text-anchor:middle;}#mermaid-svg-27Z3UCGmDNIfYGQR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-27Z3UCGmDNIfYGQR .rough-node .label,#mermaid-svg-27Z3UCGmDNIfYGQR .node .label,#mermaid-svg-27Z3UCGmDNIfYGQR .image-shape .label,#mermaid-svg-27Z3UCGmDNIfYGQR .icon-shape .label{text-align:center;}#mermaid-svg-27Z3UCGmDNIfYGQR .node.clickable{cursor:pointer;}#mermaid-svg-27Z3UCGmDNIfYGQR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-27Z3UCGmDNIfYGQR .arrowheadPath{fill:#333333;}#mermaid-svg-27Z3UCGmDNIfYGQR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-27Z3UCGmDNIfYGQR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-27Z3UCGmDNIfYGQR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-27Z3UCGmDNIfYGQR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-27Z3UCGmDNIfYGQR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-27Z3UCGmDNIfYGQR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-27Z3UCGmDNIfYGQR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-27Z3UCGmDNIfYGQR .cluster text{fill:#333;}#mermaid-svg-27Z3UCGmDNIfYGQR .cluster span{color:#333;}#mermaid-svg-27Z3UCGmDNIfYGQR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-27Z3UCGmDNIfYGQR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-27Z3UCGmDNIfYGQR rect.text{fill:none;stroke-width:0;}#mermaid-svg-27Z3UCGmDNIfYGQR .icon-shape,#mermaid-svg-27Z3UCGmDNIfYGQR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-27Z3UCGmDNIfYGQR .icon-shape p,#mermaid-svg-27Z3UCGmDNIfYGQR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-27Z3UCGmDNIfYGQR .icon-shape .label rect,#mermaid-svg-27Z3UCGmDNIfYGQR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-27Z3UCGmDNIfYGQR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-27Z3UCGmDNIfYGQR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-27Z3UCGmDNIfYGQR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Boosting 梯度提升
树1 初步预测
树2 拟合残差
树3 继续修正
累加得到最终预测
Bagging 随机森林
树1
平均预测
树2
树100

6.8 核心代码解读

(1)随机森林 ------ 未缩放特征
python 复制代码
rf = RandomForestRegressor(n_estimators=100, random_state=42, n_jobs=-1)
rf.fit(X_train, y_train)  # X_train 是原始特征,未 StandardScaler
参数 含义
n_estimators=100 100 棵决策树
n_jobs=-1 并行用全部 CPU
random_state=42 可复现
(2)为何树模型不需要缩放?

树的分裂只看「谁大谁小」,不看绝对数值大小:

  • 收入 3.0 vs 3.5 的分裂点,缩放前后排序不变
  • 线性模型系数会受量纲影响,树不会
(3)特征重要性
python 复制代码
model.feature_importances_  # 随机森林有,HistGBR 无此属性

本步以随机森林 的特征重要性图为主(07_random_forest_feature_importance.png)。

6.9 输出文件

文件 说明
reports/tree_models_summary.txt 树模型 + 汇总报告
reports/figures/07_random_forest_feature_importance.png 特征重要性(中文)
reports/figures/08_steps_4_to_6_rmse.png 步骤 4~6 RMSE 对比

6.10 动手任务

任务 A:运行脚本,确认梯度提升 RMSE ≈ 0.48

任务 B:打开特征重要性图,确认 MedInc 排第一

任务 C :对比 08_steps_4_to_6_rmse.png,用一句话说树模型为何比线性好

任务 D:在 README 写:Bagging 和 Boosting 的区别

6.11 验收标准

  • 能解释树模型为何不需要 StandardScaler
  • 能区分 Bagging 与 Boosting
  • 能说出步骤 4~6 当前最佳模型及 RMSE
  • 能读特征重要性图并指出 Top 特征

6.12 动手任务与验收标准参考答案

以下为教学标准答案,便于自学对照;README.md 学习记录仍建议用自己的话写。

动手任务答案
任务 参考答案
A 梯度提升 HistGBR 测试 RMSE≈0.4763
B 特征重要性图 MedInc(收入) 排第一。
C 树模型能切分非线性边界,收入/地理位置等与房价不是简单直线关系,RMSE 从 0.75 降到 0.48。
D Bagging (随机森林):多棵树并行 训练后投票/平均;Boosting (梯度提升):多棵树串行训练,后一棵修正前一棵错误。
验收标准答案
验收项 参考答案
树模型不需缩放 树按特征值大小做分裂,只关心排序,StandardScaler 不改变分裂结果。
Bagging vs Boosting Bagging 降方差(并行集成);Boosting 降偏差(串行纠错)。
步骤 4~6 最佳 步骤 6 HistGBR ,测试 RMSE 0.4763
Top 特征 MedInc 收入中位数最重要。

6.13 常见问题

Q:RMSE 从 0.75 跳到 0.48,正常吗?

A:正常。树模型能拟合非线性,在这类表格数据上常显著优于线性回归。

Q:HistGBR 为何没有 feature_importances_?

A:sklearn 的 HistGradientBoosting 实现不同。进阶可用 permutation_importance 分析。

Q:随机森林和梯度提升选哪个?

A:本步数据上 HistGBR 更好(0.4763 vs 0.5190)。实际项目应都试,用验证集/测试集选。

Q:100 棵树够吗?

A:学习阶段够用。生产环境可配合交叉验证调 n_estimators 和深度。

6.14 本步小结

要点 内容
最佳树模型 梯度提升 HistGBR
最佳测试 RMSE 0.4763
最重要特征 收入 MedInc
关键教训 非线性问题要用非线性模型
下一步 简单特征工程

6.15 学习记录(请你填写)

  • 完成日期
  • 动手任务完成情况:任务 A / B / C / D
  • 我对 Bagging 与 Boosting 的理解
  • 疑问(如有):

步骤 7:简单特征工程

状态 :✅ 已完成教学(报告见 reports/feature_engineering_report.txt,图表见 09_feature_engineering_rmse.png

7.1 本步目标

  1. 理解特征工程:用业务知识把原始列组合成更有意义的输入
  2. 构造 2 个新特征,在同一模型(HistGBR)上对比工程前后指标
  3. 学会如实记录结论------没有提升也是有效实验结果

7.2 这一步在解决什么问题?

步骤 6 的 HistGBR 已经很强(RMSE 0.4763),但原始 8 列是「统计块级」指标,例如:

  • AveRooms:平均房间数
  • AveBedrms:平均卧室数
  • AveOccup:平均入住人数

模型虽然能自动学非线性,但不一定 能高效利用「卧室占房间比例」「人均房间数」这类比例关系

特征工程就是:我们根据对住房的理解,显式造出这些组合特征,看能否再挤一点性能。

7.3 本步在整体流程中的位置

#mermaid-svg-rINv2ABVmCn4wXqr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rINv2ABVmCn4wXqr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rINv2ABVmCn4wXqr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rINv2ABVmCn4wXqr .error-icon{fill:#552222;}#mermaid-svg-rINv2ABVmCn4wXqr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rINv2ABVmCn4wXqr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rINv2ABVmCn4wXqr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rINv2ABVmCn4wXqr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rINv2ABVmCn4wXqr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rINv2ABVmCn4wXqr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rINv2ABVmCn4wXqr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rINv2ABVmCn4wXqr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rINv2ABVmCn4wXqr .marker.cross{stroke:#333333;}#mermaid-svg-rINv2ABVmCn4wXqr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rINv2ABVmCn4wXqr p{margin:0;}#mermaid-svg-rINv2ABVmCn4wXqr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rINv2ABVmCn4wXqr .cluster-label text{fill:#333;}#mermaid-svg-rINv2ABVmCn4wXqr .cluster-label span{color:#333;}#mermaid-svg-rINv2ABVmCn4wXqr .cluster-label span p{background-color:transparent;}#mermaid-svg-rINv2ABVmCn4wXqr .label text,#mermaid-svg-rINv2ABVmCn4wXqr span{fill:#333;color:#333;}#mermaid-svg-rINv2ABVmCn4wXqr .node rect,#mermaid-svg-rINv2ABVmCn4wXqr .node circle,#mermaid-svg-rINv2ABVmCn4wXqr .node ellipse,#mermaid-svg-rINv2ABVmCn4wXqr .node polygon,#mermaid-svg-rINv2ABVmCn4wXqr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rINv2ABVmCn4wXqr .rough-node .label text,#mermaid-svg-rINv2ABVmCn4wXqr .node .label text,#mermaid-svg-rINv2ABVmCn4wXqr .image-shape .label,#mermaid-svg-rINv2ABVmCn4wXqr .icon-shape .label{text-anchor:middle;}#mermaid-svg-rINv2ABVmCn4wXqr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rINv2ABVmCn4wXqr .rough-node .label,#mermaid-svg-rINv2ABVmCn4wXqr .node .label,#mermaid-svg-rINv2ABVmCn4wXqr .image-shape .label,#mermaid-svg-rINv2ABVmCn4wXqr .icon-shape .label{text-align:center;}#mermaid-svg-rINv2ABVmCn4wXqr .node.clickable{cursor:pointer;}#mermaid-svg-rINv2ABVmCn4wXqr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rINv2ABVmCn4wXqr .arrowheadPath{fill:#333333;}#mermaid-svg-rINv2ABVmCn4wXqr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rINv2ABVmCn4wXqr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rINv2ABVmCn4wXqr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rINv2ABVmCn4wXqr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rINv2ABVmCn4wXqr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rINv2ABVmCn4wXqr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rINv2ABVmCn4wXqr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rINv2ABVmCn4wXqr .cluster text{fill:#333;}#mermaid-svg-rINv2ABVmCn4wXqr .cluster span{color:#333;}#mermaid-svg-rINv2ABVmCn4wXqr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rINv2ABVmCn4wXqr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rINv2ABVmCn4wXqr rect.text{fill:none;stroke-width:0;}#mermaid-svg-rINv2ABVmCn4wXqr .icon-shape,#mermaid-svg-rINv2ABVmCn4wXqr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rINv2ABVmCn4wXqr .icon-shape p,#mermaid-svg-rINv2ABVmCn4wXqr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rINv2ABVmCn4wXqr .icon-shape .label rect,#mermaid-svg-rINv2ABVmCn4wXqr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rINv2ABVmCn4wXqr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rINv2ABVmCn4wXqr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rINv2ABVmCn4wXqr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 步骤6 HistGBR 0.4763
步骤7 特征工程
工程前 8 特征
工程后 10 特征
RMSE 0.4763
RMSE 0.4745
步骤8 总结与选模

7.4 名词解释(本步首次出现)

名词 是什么 为什么需要 在本项目中 易混淆
特征工程 对原始特征做变换、组合、构造新列 让模型更容易学到有用模式 新增 2 列比例特征 不是调参
领域知识 对问题背景的专业理解 指导「造什么特征有意义」 房间结构、人均空间与房价相关 不是随便加减
比例特征 两列相除得到的新变量 消除量纲、表达结构关系 BedroomsRatio、RoomsPerHousehold 不是原始计数
信息泄露 用测试集或未来信息参与训练 会导致虚高指标、上线失效 本步只用行内四则运算,不用全局统计 不是过拟合
边际收益 再增加一步后带来的额外提升 判断特征工程是否值得继续 本步 RMSE 仅降 0.0018 不是总收益

7.5 新增的两个特征

新特征 公式 业务含义 直觉
BedroomsRatio AveBedrms / AveRooms 卧室占全部房间的比例 比例高可能偏紧凑;比例低可能客厅/其他空间大
RoomsPerHousehold AveRooms / AveOccup 人均可用房间数 人均房间多,空间更充裕,可能与房价正相关

训练集上新特征统计(describe()):

统计量 BedroomsRatio RoomsPerHousehold
mean 0.2131 1.9754
std 0.0578 1.1118
min 0.1000 0.0025
max 1.0000 52.0333

RoomsPerHousehold 最大值 52 说明存在极端块(入住人数极少但房间多),树模型可以处理这类离群,但实战中可进一步做截断或分箱。

7.6 特征工程流程(Mermaid)

#mermaid-svg-6RtN94wAZfIjeVOM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6RtN94wAZfIjeVOM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6RtN94wAZfIjeVOM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6RtN94wAZfIjeVOM .error-icon{fill:#552222;}#mermaid-svg-6RtN94wAZfIjeVOM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6RtN94wAZfIjeVOM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6RtN94wAZfIjeVOM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6RtN94wAZfIjeVOM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6RtN94wAZfIjeVOM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6RtN94wAZfIjeVOM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6RtN94wAZfIjeVOM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6RtN94wAZfIjeVOM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6RtN94wAZfIjeVOM .marker.cross{stroke:#333333;}#mermaid-svg-6RtN94wAZfIjeVOM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6RtN94wAZfIjeVOM p{margin:0;}#mermaid-svg-6RtN94wAZfIjeVOM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6RtN94wAZfIjeVOM .cluster-label text{fill:#333;}#mermaid-svg-6RtN94wAZfIjeVOM .cluster-label span{color:#333;}#mermaid-svg-6RtN94wAZfIjeVOM .cluster-label span p{background-color:transparent;}#mermaid-svg-6RtN94wAZfIjeVOM .label text,#mermaid-svg-6RtN94wAZfIjeVOM span{fill:#333;color:#333;}#mermaid-svg-6RtN94wAZfIjeVOM .node rect,#mermaid-svg-6RtN94wAZfIjeVOM .node circle,#mermaid-svg-6RtN94wAZfIjeVOM .node ellipse,#mermaid-svg-6RtN94wAZfIjeVOM .node polygon,#mermaid-svg-6RtN94wAZfIjeVOM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6RtN94wAZfIjeVOM .rough-node .label text,#mermaid-svg-6RtN94wAZfIjeVOM .node .label text,#mermaid-svg-6RtN94wAZfIjeVOM .image-shape .label,#mermaid-svg-6RtN94wAZfIjeVOM .icon-shape .label{text-anchor:middle;}#mermaid-svg-6RtN94wAZfIjeVOM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6RtN94wAZfIjeVOM .rough-node .label,#mermaid-svg-6RtN94wAZfIjeVOM .node .label,#mermaid-svg-6RtN94wAZfIjeVOM .image-shape .label,#mermaid-svg-6RtN94wAZfIjeVOM .icon-shape .label{text-align:center;}#mermaid-svg-6RtN94wAZfIjeVOM .node.clickable{cursor:pointer;}#mermaid-svg-6RtN94wAZfIjeVOM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6RtN94wAZfIjeVOM .arrowheadPath{fill:#333333;}#mermaid-svg-6RtN94wAZfIjeVOM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6RtN94wAZfIjeVOM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6RtN94wAZfIjeVOM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6RtN94wAZfIjeVOM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6RtN94wAZfIjeVOM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6RtN94wAZfIjeVOM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6RtN94wAZfIjeVOM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6RtN94wAZfIjeVOM .cluster text{fill:#333;}#mermaid-svg-6RtN94wAZfIjeVOM .cluster span{color:#333;}#mermaid-svg-6RtN94wAZfIjeVOM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6RtN94wAZfIjeVOM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6RtN94wAZfIjeVOM rect.text{fill:none;stroke-width:0;}#mermaid-svg-6RtN94wAZfIjeVOM .icon-shape,#mermaid-svg-6RtN94wAZfIjeVOM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6RtN94wAZfIjeVOM .icon-shape p,#mermaid-svg-6RtN94wAZfIjeVOM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6RtN94wAZfIjeVOM .icon-shape .label rect,#mermaid-svg-6RtN94wAZfIjeVOM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6RtN94wAZfIjeVOM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6RtN94wAZfIjeVOM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6RtN94wAZfIjeVOM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 输出 10 列
engineer_features
原始 8 列
MedInc
AveRooms
AveBedrms
AveOccup
其他...
BedroomsRatio = AveBedrms / AveRooms
RoomsPerHousehold = AveRooms / AveOccup
原 8 列保留

  • 2 个新列

重要原则:

  • 训练集、测试集分别 调用同一个 engineer_features(),保证变换规则一致
  • 除法用 .replace(0, np.nan) 防除零,再 fillna(0) 处理无效值
  • 用训练集均值/方差去变换测试集(本步无此类全局统计,无泄露)

7.7 任务清单

  • 实现 engineer_features(),新增 BedroomsRatioRoomsPerHousehold
  • 用 HistGBR(与步骤 6 相同参数)分别训练工程前/后
  • 对比 RMSE、R2,保存报告与对比图
  • 如实解读:小幅改善也是结论

7.8 运行本步

powershell 复制代码
cd "d:\JavaCode\机器学习\project_01_housing"
python src/train.py

7.9 实验结果(你的环境)

阶段 特征数 测试 RMSE 测试 R2
工程前 HistGBR 8 0.4763 0.8341
工程后 HistGBR 10 0.4745 0.8354
变化 +2 -0.0018 +0.0013

关键发现:

  • 新特征带来小幅 改善:RMSE 从 0.4763 → 0.4745(约 0.38% 相对降幅)
  • R2 从 0.8341 → 0.8354,方向一致但幅度很小
  • 说明:HistGBR 可能已隐式AveRoomsAveBedrmsAveOccup 学到类似交互;显式比例特征仍有一点边际收益
  • 有效结论:不是「特征越多越好」------2 个精心设计的特征略好,但远不及步骤 6 换模型带来的跃升(0.75 → 0.48)

7.10 核心代码解读

(1)engineer_features ------ 行内构造,无泄露
python 复制代码
X_new = X.copy()
X_new["BedroomsRatio"] = X["AveBedrms"] / X["AveRooms"].replace(0, np.nan)
X_new["RoomsPerHousehold"] = X["AveRooms"] / X["AveOccup"].replace(0, np.nan)
X_new = X_new.replace([np.inf, -np.inf], np.nan).fillna(0)
要点 说明
X.copy() 不修改传入的原始 DataFrame
.replace(0, np.nan) 除数为 0 时先变 NaN,避免 inf
fillna(0) 极少数无效行填 0(本数据集几乎遇不到)
fit 步骤 不依赖训练集统计量,测试集可同样应用
(2)train_best_tree_model ------ 公平对比

工程前、工程后使用相同HistGradientBoostingRegressor(max_iter=100, random_state=42),唯一变量是特征矩阵列数。这样 RMSE 差异才可归因于特征工程。

(3)对比解读阈值
python 复制代码
if rmse_diff < -0.001:
    print("结论:新特征带来小幅改善。")

差值 0.0018 略大于 0.001,脚本判定为「小幅改善」。若差值在 ±0.001 内,应视为基本持平------这在强树模型上很常见。

7.11 输出文件

文件 说明
reports/feature_engineering_report.txt 工程前后 RMSE/R2 文本报告
reports/figures/09_feature_engineering_rmse.png 工程前后 RMSE 条形对比图(中文)

7.12 动手任务

任务 A :运行脚本,确认工程后 RMSE ≈ 0.4745

任务 B :打开 09_feature_engineering_rmse.png,对比两根柱子高度

任务 C :用自己的话解释 BedroomsRatioRoomsPerHousehold 分别代表什么

任务 D:在 README 写:为什么本步提升很小?树模型已经很强时特征工程还值得做吗?

7.13 验收标准

  • 能写出两个新特征的公式与业务含义
  • 能说明为何本步用「同一模型、不同特征」做对比
  • 能解释「无提升或小幅提升」也是有效实验结论
  • 能区分「换模型(步骤 6)」与「造特征(步骤 7)」对指标的影响量级

7.14 动手任务与验收标准参考答案

以下为教学标准答案,便于自学对照;README.md 学习记录仍建议用自己的话写。

动手任务答案
任务 参考答案
A 工程后 HistGBR 测试 RMSE≈0.4745
B 工程后柱略低于工程前(0.4763→0.4745),改善很小但方向一致。
C BedroomsRatio = 卧室数/总房间数,反映卧室占比;RoomsPerHousehold = 总房间数/入住人数,反映人均可用房间数。
D 提升很小因为 HistGBR 已从原始列隐式学到类似关系;仍值得建立可复现对比流程;换模型(0.75→0.48)收益远大于造 2 个特征(0.4763→0.4745)。
验收标准答案
验收项 参考答案
两个新特征 BedroomsRatio=AveBedrms/AveRooms;RoomsPerHousehold=AveRooms/AveOccup。
同一模型对比 唯一变量是特征列,RMSE 差异才可归因于特征工程。
小幅提升也有效 没涨分也是结论,说明树已够用或特征冗余。
影响量级 换模型 RMSE 降约 0.27;造特征降约 0.002。

7.15 常见问题

Q:只降 0.0018 RMSE,算成功吗?

A:算。真实项目里,在已经很强的模型上,特征工程常常是「抠细节」。重要的是你建立了可复现的对比流程,而不是每次都必须大涨。

Q:为什么不造 10 个、20 个特征?

A:特征越多,噪声和过拟合风险越高,且难维护。本步刻意只加 2 个有业务含义的特征,练习「少而精」。

Q:工程后要不要对 10 列做 StandardScaler?

A:HistGBR 是树模型,与步骤 6 一样不需要缩放。若换回线性模型,才需重新考虑缩放。

Q:能否在划分 train/test 之前做特征工程?

A:本步的行内四则运算,先工程再划分与先划分再工程,结果等价。但若特征用到全局统计 (如全表均值),必须先划分再在训练集上 fit,否则会泄露。

7.16 本步小结

要点 内容
新增特征 BedroomsRatio、RoomsPerHousehold
对比模型 HistGBR(与步骤 6 相同)
工程前 RMSE 0.4763
工程后 RMSE 0.4745(当前项目最佳)
关键教训 特征工程是「挤水分」;强模型下边际收益有限
下一步 总结全部实验、选最终模型、joblib 保存

7.17 学习记录(请你填写)

  • 完成日期
  • 动手任务完成情况:任务 A / B / C / D
  • 我对特征工程的理解
  • 疑问(如有):

步骤 8:总结与模型选择

状态 :✅ 已完成教学(报告见 reports/final_project_summary.txt,图表见 10_final_all_models_rmse.png,模型见 models/housing_best.pkl

8.1 本步目标

  1. 汇总步骤 4~7 全部代表模型的测试集指标
  2. 按测试集 RMSE 最低选出项目一最终模型
  3. 3~5 句项目结论(最佳模型、关键特征、过拟合、改进方向)
  4. joblib.dump 保存模型,保证可复现、可部署

8.2 这一步在解决什么问题?

前面 7 步分别做了 Baseline、正则化、树模型、特征工程------每一步都有结论,但缺少一张总表回答:

  • 项目一到底哪个模型最好?
  • 相对 Baseline 提升了多少?
  • 最终模型有没有过拟合?
  • 训练好的模型如何保存、下次怎么用?

步骤 8 就是机器学习项目的收尾:实验汇总 → 模型选择 → 持久化 → 复盘。

8.3 本步在整体流程中的位置

#mermaid-svg-YVnU2V6lxhSsso9S{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-YVnU2V6lxhSsso9S .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YVnU2V6lxhSsso9S .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YVnU2V6lxhSsso9S .error-icon{fill:#552222;}#mermaid-svg-YVnU2V6lxhSsso9S .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YVnU2V6lxhSsso9S .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YVnU2V6lxhSsso9S .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YVnU2V6lxhSsso9S .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YVnU2V6lxhSsso9S .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YVnU2V6lxhSsso9S .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YVnU2V6lxhSsso9S .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YVnU2V6lxhSsso9S .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YVnU2V6lxhSsso9S .marker.cross{stroke:#333333;}#mermaid-svg-YVnU2V6lxhSsso9S svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YVnU2V6lxhSsso9S p{margin:0;}#mermaid-svg-YVnU2V6lxhSsso9S .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-YVnU2V6lxhSsso9S .cluster-label text{fill:#333;}#mermaid-svg-YVnU2V6lxhSsso9S .cluster-label span{color:#333;}#mermaid-svg-YVnU2V6lxhSsso9S .cluster-label span p{background-color:transparent;}#mermaid-svg-YVnU2V6lxhSsso9S .label text,#mermaid-svg-YVnU2V6lxhSsso9S span{fill:#333;color:#333;}#mermaid-svg-YVnU2V6lxhSsso9S .node rect,#mermaid-svg-YVnU2V6lxhSsso9S .node circle,#mermaid-svg-YVnU2V6lxhSsso9S .node ellipse,#mermaid-svg-YVnU2V6lxhSsso9S .node polygon,#mermaid-svg-YVnU2V6lxhSsso9S .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YVnU2V6lxhSsso9S .rough-node .label text,#mermaid-svg-YVnU2V6lxhSsso9S .node .label text,#mermaid-svg-YVnU2V6lxhSsso9S .image-shape .label,#mermaid-svg-YVnU2V6lxhSsso9S .icon-shape .label{text-anchor:middle;}#mermaid-svg-YVnU2V6lxhSsso9S .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-YVnU2V6lxhSsso9S .rough-node .label,#mermaid-svg-YVnU2V6lxhSsso9S .node .label,#mermaid-svg-YVnU2V6lxhSsso9S .image-shape .label,#mermaid-svg-YVnU2V6lxhSsso9S .icon-shape .label{text-align:center;}#mermaid-svg-YVnU2V6lxhSsso9S .node.clickable{cursor:pointer;}#mermaid-svg-YVnU2V6lxhSsso9S .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-YVnU2V6lxhSsso9S .arrowheadPath{fill:#333333;}#mermaid-svg-YVnU2V6lxhSsso9S .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YVnU2V6lxhSsso9S .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YVnU2V6lxhSsso9S .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YVnU2V6lxhSsso9S .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-YVnU2V6lxhSsso9S .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YVnU2V6lxhSsso9S .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-YVnU2V6lxhSsso9S .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YVnU2V6lxhSsso9S .cluster text{fill:#333;}#mermaid-svg-YVnU2V6lxhSsso9S .cluster span{color:#333;}#mermaid-svg-YVnU2V6lxhSsso9S div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-YVnU2V6lxhSsso9S .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-YVnU2V6lxhSsso9S rect.text{fill:none;stroke-width:0;}#mermaid-svg-YVnU2V6lxhSsso9S .icon-shape,#mermaid-svg-YVnU2V6lxhSsso9S .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YVnU2V6lxhSsso9S .icon-shape p,#mermaid-svg-YVnU2V6lxhSsso9S .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-YVnU2V6lxhSsso9S .icon-shape .label rect,#mermaid-svg-YVnU2V6lxhSsso9S .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YVnU2V6lxhSsso9S .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-YVnU2V6lxhSsso9S .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-YVnU2V6lxhSsso9S :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 步骤4 Baseline 0.75
步骤5 Lasso 0.75
步骤6 树模型 0.48
步骤7 特征工程 0.47
步骤8 汇总选模
final_project_summary.txt
housing_best.pkl
10_final_all_models_rmse.png

8.4 名词解释(本步首次出现)

名词 是什么 为什么需要 在本项目中 易混淆
模型选择 在多个候选模型中选出表现最好者 避免凭感觉选模型 按测试 RMSE 选 HistGBR+特征工程 不是越复杂越好
joblib Python 序列化库,擅长保存 numpy/sklearn 对象 训练一次、多次推理 models/housing_best.pkl 不是 pickle 手写
模型持久化 把训练好的模型写入磁盘 部署、复现、分享 bundle 含 model + 元数据 不是只存权重 CSV
过拟合 模型在训练集上很好、测试集变差 选模时要检查泛化 训练 RMSE 0.39 vs 测试 0.47 不是训练误差大
可复现性 同样代码、同样数据得到同样结果 实验可信、便于协作 random_state=42 固定划分与模型 不是只跑一次

8.5 模型选择流程(Mermaid)

#mermaid-svg-DKNR65IqQjHKb1Lr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DKNR65IqQjHKb1Lr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DKNR65IqQjHKb1Lr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DKNR65IqQjHKb1Lr .error-icon{fill:#552222;}#mermaid-svg-DKNR65IqQjHKb1Lr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DKNR65IqQjHKb1Lr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DKNR65IqQjHKb1Lr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DKNR65IqQjHKb1Lr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DKNR65IqQjHKb1Lr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DKNR65IqQjHKb1Lr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DKNR65IqQjHKb1Lr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DKNR65IqQjHKb1Lr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DKNR65IqQjHKb1Lr .marker.cross{stroke:#333333;}#mermaid-svg-DKNR65IqQjHKb1Lr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DKNR65IqQjHKb1Lr p{margin:0;}#mermaid-svg-DKNR65IqQjHKb1Lr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DKNR65IqQjHKb1Lr .cluster-label text{fill:#333;}#mermaid-svg-DKNR65IqQjHKb1Lr .cluster-label span{color:#333;}#mermaid-svg-DKNR65IqQjHKb1Lr .cluster-label span p{background-color:transparent;}#mermaid-svg-DKNR65IqQjHKb1Lr .label text,#mermaid-svg-DKNR65IqQjHKb1Lr span{fill:#333;color:#333;}#mermaid-svg-DKNR65IqQjHKb1Lr .node rect,#mermaid-svg-DKNR65IqQjHKb1Lr .node circle,#mermaid-svg-DKNR65IqQjHKb1Lr .node ellipse,#mermaid-svg-DKNR65IqQjHKb1Lr .node polygon,#mermaid-svg-DKNR65IqQjHKb1Lr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DKNR65IqQjHKb1Lr .rough-node .label text,#mermaid-svg-DKNR65IqQjHKb1Lr .node .label text,#mermaid-svg-DKNR65IqQjHKb1Lr .image-shape .label,#mermaid-svg-DKNR65IqQjHKb1Lr .icon-shape .label{text-anchor:middle;}#mermaid-svg-DKNR65IqQjHKb1Lr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DKNR65IqQjHKb1Lr .rough-node .label,#mermaid-svg-DKNR65IqQjHKb1Lr .node .label,#mermaid-svg-DKNR65IqQjHKb1Lr .image-shape .label,#mermaid-svg-DKNR65IqQjHKb1Lr .icon-shape .label{text-align:center;}#mermaid-svg-DKNR65IqQjHKb1Lr .node.clickable{cursor:pointer;}#mermaid-svg-DKNR65IqQjHKb1Lr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DKNR65IqQjHKb1Lr .arrowheadPath{fill:#333333;}#mermaid-svg-DKNR65IqQjHKb1Lr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DKNR65IqQjHKb1Lr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DKNR65IqQjHKb1Lr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DKNR65IqQjHKb1Lr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DKNR65IqQjHKb1Lr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DKNR65IqQjHKb1Lr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DKNR65IqQjHKb1Lr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DKNR65IqQjHKb1Lr .cluster text{fill:#333;}#mermaid-svg-DKNR65IqQjHKb1Lr .cluster span{color:#333;}#mermaid-svg-DKNR65IqQjHKb1Lr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DKNR65IqQjHKb1Lr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DKNR65IqQjHKb1Lr rect.text{fill:none;stroke-width:0;}#mermaid-svg-DKNR65IqQjHKb1Lr .icon-shape,#mermaid-svg-DKNR65IqQjHKb1Lr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DKNR65IqQjHKb1Lr .icon-shape p,#mermaid-svg-DKNR65IqQjHKb1Lr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DKNR65IqQjHKb1Lr .icon-shape .label rect,#mermaid-svg-DKNR65IqQjHKb1Lr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DKNR65IqQjHKb1Lr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DKNR65IqQjHKb1Lr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DKNR65IqQjHKb1Lr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 保存阶段
选择阶段
训练阶段
各步训练代表模型
在测试集上算 RMSE
find_best_model 取 RMSE 最小
检查 train vs test 差距
joblib.dump bundle
报告 + 对比图

选择原则:

  • 本步用同一次 train/test 划分,保证各模型指标可比
  • 测试集 RMSE 为唯一排序标准(回归任务的主指标)
  • 若多个模型 RMSE 接近,优先选更简单、更易维护的(本项目中工程后 HistGBR 仍是最优)

8.6 任务清单

  • 汇总步骤 4~7 代表模型指标表
  • 选出测试 RMSE 最低模型
  • 写 3~5 句项目结论
  • joblib.dump 保存到 models/housing_best.pkl
  • 生成全部模型 RMSE 对比图

8.7 运行本步

powershell 复制代码
cd "d:\JavaCode\机器学习\project_01_housing"
python src/train.py

8.8 全部实验汇总(你的环境)

步骤 模型 测试 RMSE 测试 R2
4 线性回归 Baseline 0.7514 0.5871
5 Lasso alpha=0.01 0.7472 0.5917
6 随机森林 0.5190 0.8030
6 梯度提升 HistGBR 0.4763 0.8341
7 工程后 HistGBR 0.4745 0.8354

最终选定模型:步骤 7 工程后 HistGBR

集合 RMSE R2
训练集 0.3918 0.8840
测试集 0.4745 0.8354
差距 +0.0826 ---

关键发现:

  • 相对 Baseline,最终 RMSE 降低约 36.9%(0.7514 → 0.4745)
  • 换模型(步骤 6)贡献最大;特征工程(步骤 7)是「挤水分」式小幅优化
  • 测试 RMSE 比训练高约 0.08,存在轻度过拟合 ,生产环境可进一步调 max_iter、深度或做交叉验证
  • 随机森林特征重要性(步骤 6)表明 MedInc 收入是最重要特征

8.9 项目结论(3~5 句)

  1. 最终模型为 HistGradientBoostingRegressor + 2 个工程特征 ,测试 RMSE=0.4745 ,R2=0.8354
  2. 相对线性 Baseline(RMSE=0.7514),RMSE 降低约 36.9% ,说明房价问题非线性强,树模型远优于线性模型。
  3. MedInc(收入中位数) 是最重要特征,区域经济实力是房价首要驱动因素。
  4. 训练/测试 RMSE 有差距,存在轻度过拟合,可通过调参或交叉验证进一步改善。
  5. 模型已用 joblib 保存至 models/housing_best.pklrandom_state=42 保证可复现。

8.10 核心代码解读

(1)build_full_project_summary ------ 一次跑完全部代表模型

在同一次 train/test 划分上,依次训练 Baseline、Lasso、RF、HistGBR、工程后 HistGBR,保证指标横向可比

(2)save_best_model_bundle ------ 打包保存
python 复制代码
bundle = {
    "model_name": best_result["name"],
    "model": best_result["model"],
    "feature_columns": feature_columns,       # 10 列名
    "uses_feature_engineering": True,
    "random_state": RANDOM_STATE,
    "test_metrics": best_result["test"],
}
joblib.dump(bundle, MODELS_DIR / "housing_best.pkl")
字段 作用
model 训练好的 HistGBR,可直接 .predict()
uses_feature_engineering 提醒加载后需先 engineer_features
feature_columns 推理时校验列名与顺序
test_metrics 记录选型时的测试表现
(3)加载与推理示例
python 复制代码
import joblib
from train import engineer_features  # 或复制 engineer_features 函数

bundle = joblib.load("models/housing_best.pkl")
X_raw = ...  # 原始 8 列 DataFrame
X_fe = engineer_features(X_raw)
y_pred = bundle["model"].predict(X_fe)

8.11 输出文件

文件 说明
reports/final_project_summary.txt 全部模型指标 + 项目结论
reports/figures/10_final_all_models_rmse.png 步骤 4~7 RMSE 对比图(中文)
models/housing_best.pkl 最终模型 joblib 打包文件

8.12 动手任务

任务 A :运行脚本,确认最终 RMSE ≈ 0.4745

任务 B :打开 10_final_all_models_rmse.png,找出绿色柱子(最佳模型)

任务 C :用 Python 加载 housing_best.pkl,打印 bundle.keys()bundle['test_metrics']

任务 D:在 README 填写项目一完整实验记录表和你的 3 句话心得

8.13 验收标准

  • 能说出项目一最终模型名称与测试 RMSE
  • 能解释为何用测试集 RMSE 选模型
  • 能说明 housing_best.pkl 里保存了什么
  • 能描述 Baseline → 树模型 → 特征工程的提升路径

8.14 动手任务与验收标准参考答案

以下为教学标准答案,便于自学对照;README.md 学习记录仍建议用自己的话写。

动手任务答案
任务 参考答案
A 最终测试 RMSE≈0.4745
B 绿色(或标注最佳)柱子对应 工程后 HistGBR
C 示例:bundle.keys()model_nametest_metrics 等;test_metrics 中 RMSE≈0.4745、R2≈0.8354。
D 在 README 填写完整实验表;心得示例:① 先 Baseline 再优化 ② 树模型适合非线性 ③ 测试集选模、joblib 便于部署。
验收标准答案
验收项 参考答案
最终模型与 RMSE 工程后 HistGradientBoostingRegressor ,测试 RMSE 0.4745
用测试集 RMSE 选模 测试集未参与训练,反映泛化;训练集 RMSE 会偏向过拟合模型。
pkl 内容 bundle 含模型对象、特征列名、random_state、test_metrics 等元数据。
提升路径 Baseline LR 0.7514 → Lasso 0.7472 → HistGBR 0.4763 → 特征工程 0.4745。

8.15 常见问题

Q:为什么不把 StandardScaler 也打进 pkl?

A:最终模型是 HistGBR,不需要缩放。若最终模型是 Lasso,则应同时保存 scaler。

Q:能否用训练集 RMSE 选模型?

A:不能。训练集指标会偏向过拟合模型,必须用未参与训练的测试集

Q:0.0826 的训练-测试差距严重吗?

A:对本学习项目属轻度过拟合。树模型常见此现象,可通过减小 max_iter、限制深度、早停等缓解。

Q:项目一完成后下一步学什么?

A:见 机器学习实战学习路线.md 项目二:信用卡欺诈检测(不平衡分类)。

8.16 本步小结

要点 内容
最终模型 步骤 7 工程后 HistGBR
测试 RMSE 0.4745
相对 Baseline 降低约 36.9%
最重要特征 MedInc 收入
模型文件 models/housing_best.pkl
项目状态 项目一 8 步全部完成

8.17 学习记录(请你填写)

  • 完成日期
  • 动手任务完成情况:任务 A / B / C / D
  • 我对模型选择与持久化的理解
  • 项目一整体收获
  • 疑问(如有):

附录:推荐学习节奏

步骤 建议用时 难度
步骤 1 30 分钟 ★☆☆
步骤 2 1~2 小时 ★★☆
步骤 3 30 分钟 ★☆☆
步骤 4 1 小时 ★★☆
步骤 5 1~2 小时 ★★☆
步骤 6 1~2 小时 ★★★
步骤 7 1 小时 ★★☆
步骤 8 30 分钟 ★☆☆

文档版本:v1.9 | 最后更新:全步骤动手任务与验收标准参考答案已补充 | 项目一全部完成