第 01 章 · 环境安装与数据准备
这一章要解决什么:把环境装好、数据验证到位,确认你能跑出和书上一样的数字。 这一章结束时,你手上应该有一个干净隔离、可复现的机器学习环境。
最容易踩的坑:
pip install sklearn会失败 —— 装包名是scikit-learn, 只有导入名才是sklearn。这是新手第一个卡点。
本章没有示例代码 —— 这一章全是命令和验证,从第 03 章开始才写 Python。
1.1 先说清楚:这一章做完,你应该看到什么
按顺序做完本章,你应该能:
- 在命令行里运行
python --version,看到 3.10 以上的版本号; - 解压下载包,看到
code/目录里有data/battery/soh_features.csv; - 运行
python check_env.py,看到全部 ✅; - 确认数据的 SHA-256 与书上一致(这一步最重要);
- 跑出第一份数据体检报告(四行代码)。
如果这 5 步有任意一步不通过,请在这一章解决掉,不要带着问题往下学。 机器学习最怕"环境问题"和"模型问题"混在一起 —— 你分不清是哪个错了。
1.2 三个概念:解释器、包、虚拟环境
点开:为什么必须用虚拟环境(不想看可跳过,但建议看)
① 解释器(Python 本身)
负责执行你的 .py 文件。你电脑上可能装了多个版本(系统自带的、官网下的、conda 的)。
python --version # 看当前用的是哪个版本
which python # macOS / Linux:看具体是哪个文件
where python # Windows② 包(第三方库)
numpy、pandas、scikit-learn 这些都不是 Python 自带的,要单独安装。
③ 虚拟环境(venv)
一个给项目专用的"包仓库"。
为什么必须要它:
项目 A 需要 scikit-learn 1.3
项目 B 需要 scikit-learn 1.5
↓
如果都装在全局:必然打架,A 或 B 跑不起来
↓
虚拟环境:每个项目一套独立的包,互不影响你要建立的直觉:
"我装了这个包"这句话是不完整的 —— 你应该说"我在这个虚拟环境里装了这个包"。
怎么判断自己是不是在虚拟环境里:
# 激活后,命令行提示符前面会出现 (.venv)
(.venv) $ python -c "import sys; print(sys.executable)"
/path/to/code/.venv/bin/python ← 路径里有 .venv 就对了最后一个检查很重要:90% 的"我明明装了包,为什么说找不到", 都是因为包装在了全局,而运行时用的是虚拟环境(或反过来)。
1.3 安装 Python
要求 3.10 以上,推荐 3.12 或 3.13。
点开:Windows / macOS / Linux 分别怎么装
Windows
方式一:官网安装包(推荐新手)
- 打开 https://www.python.org/downloads/windows/,下载最新稳定版;
- 安装时务必勾选
Add python.exe to PATH—— 这一步不做,后面所有命令都会报'python' 不是内部或外部命令; - 勾选后点
Install Now。
方式二:winget(Win10/11 自带)
winget install Python.Python.3.13验证:
python --version
# 如果报错,试试 py --version(Windows 的 Python 启动器)macOS
方式一:官网安装包 —— https://www.python.org/downloads/macos/
方式二:Homebrew
brew install python@3.13⚠️ 注意:macOS 系统自带的 /usr/bin/python3 是给系统工具用的,不要动它。 用 Homebrew 或官网装的版本。
python3 --version # macOS 上通常要写 python3 而不是 pythonLinux
# Debian / Ubuntu
sudo apt update && sudo apt install python3 python3-venv python3-pip
# RHEL / CentOS / Fedora
sudo dnf install python3 python3-pip⚠️ 必须装 python3-venv —— 很多精简发行版默认不带它, 后面 python -m venv .venv 会报 ensurepip is not available。
1.4 拿到配套数据包
★ 先明确一件事:本课程不提供示例代码和练习答案
下载包里只有数据和环境工具,没有代码。
这不是省事,是教学决策。
机器学习有个特点:每一步都很"轻"。切 X/y、fit、score —— 三五行就出结果。
正因为轻,直接跑别人的代码,你只会看到一串数字, 不会去质疑它。而这本书的全部价值就是教你去质疑:
"R² = 0.987,不错。"
↓ 自己敲过一遍的人会想:
"等等 —— 这个划分方式对吗?"所以代码在书里:每章都有完整代码 + 真实输出,照着敲进 demos/ 即可。 练习答案在书里是折叠的,先自己写再对照。
下载
请下载 regression-model-selection-code.zip(约 400 KB), 解压后结构如下:
regression-model-selection/
└── code/ ← 你的工作目录(后面命令都在这里执行)
├── README.md 依赖 / 数据说明 / 校验和 / 常见问题
├── requirements.txt 需要装哪些包
├── check_env.py 环境自检
└── data/
└── battery/
├── soh_features.csv 特征表(21,239 行 × 9 列)
└── README.md 字段说明与数据特点包里没有的,要你自己边学边建:
code/
├── demos/ ← 第 03 章起,你自己敲的示例
│ └── ch03-what-is-supervised.py
├── exercises/ ← 你自己敲的练习
│ └── ex04-04-features-labels/
└── outputs/ ← 脚本产出的图和表(会自动创建)1.5 创建虚拟环境并安装依赖
打开终端,cd 到 code/ 目录,然后按你的情况选一条路。
点开:路线 A —— 标准做法(venv + pip)
cd code
# ① 创建虚拟环境(只需一次,几秒钟)
python -m venv .venv
# ② 激活(每次开新终端都要做)
source .venv/bin/activate # macOS / Linux
.venv\Scripts\Activate.ps1 # Windows PowerShell
.venv\Scripts\activate.bat # Windows CMD
# ③ 确认激活成功:提示符前应有 (.venv)
python -c "import sys; print(sys.executable)"
# ④ 装依赖
pip install -r requirements.txtrequirements.txt 的内容:
numpy>=2.0
pandas>=2.0
matplotlib>=3.8
scikit-learn>=1.3看到 Successfully installed ... 就成功了。
⚠️ 关于 scikit-learn 的包名:
pip install scikit-learn # ✅ 正确的装包名
pip install sklearn # ❌ 会装到一个 2015 年的废弃占位包,或者直接找不到
import sklearn # ✅ 但代码里导入时用的是 sklearn装包名 ≠ 导入名,这是 Python 生态里很常见的坑(另一个例子是 Pillow / PIL)。
国内下载慢:
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple点开:路线 B —— uv(更快,推荐)
uv 是新一代 Python 包管理工具,比 pip 快一个数量级,而且不需要手动激活。
# 安装 uv(macOS / Linux)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows PowerShell
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"用法:
cd code
uv venv # 建虚拟环境
uv pip install -r requirements.txt # 装依赖(很快)
# 运行脚本时不用激活,直接:
uv run python check_env.py为什么快:uv 有全局缓存,第二次建环境时包直接从缓存链接,不重新下载。
你可以两条路线都试,但一个项目只用一种 —— 混用容易搞乱包的位置。
点开:装依赖出错时的排查表
| 报错 | 原因 | 修复 |
|---|---|---|
pip: command not found | pip 没装或不在 PATH | python -m pip install ... 代替 pip install ... |
ensurepip is not available | Linux 缺 python3-venv | sudo apt install python3-venv |
No module named venv | Python 装得不完整 | 换官网安装包重装,或装 python3-venv |
error: externally-managed-environment | 在"外部管理"的系统 Python 里 pip(新版 Debian/Ubuntu) | 说明你没激活虚拟环境 —— 回到第 ① 步 |
Could not find a version that satisfies... | 包名写错或网络问题 | 检查包名;换国内镜像 |
Permission denied | 试图装到系统目录 | 虚拟环境没激活;不要用 sudo pip |
装完 import sklearn 还是失败 | 装到了别的环境 | python -c "import sys; print(sys.executable)" 确认路径 |
externally-managed-environment 这个错误特别值得说: 它看起来像"Python 坏了",其实是保护机制在提醒你"不该往系统 Python 里装包"。 正解不是加 --break-system-packages,而是去创建并激活虚拟环境。
1.6 安装编辑器:VS Code
可选,但强烈建议。 纯命令行也能读完这本书。
点开:VS Code 装上后必须做的三件事
- 下载安装 https://code.visualstudio.com/;
- 装扩展:Python(Microsoft 出品,装这一个就够,它会自动带上 Pylance);
- 打开
code/文件夹(不是打开单个文件 —— 打开文件夹才能让终端和路径正确)。
必须做的第四件事:选对解释器。
Ctrl+Shift+P(macOS 是 Cmd+Shift+P)→ 输入 Python: Select Interpreter → 选那个路径里带 .venv 的。
怎么验证选对了:
- 打开
check_env.py,左下角应显示Python 3.x.x ('.venv': venv); - 打开终端(
Ctrl+`),提示符前面应有(.venv)。
为什么这一步重要:VS Code 和终端用的是两套解释器设置。 你以为在虚拟环境里跑,其实用的是全局解释器 —— 然后 import sklearn 报错。 这是 VS Code 用户最常见的问题。
1.7 确认数据就位
数据已经生成好了,就在下载包里,你不需要运行任何脚本去生成它。
cd code/data/battery
ls -la # 应该看到 soh_features.csv 和 README.md
wc -l soh_features.csv # 应该输出 21240校验一致性(重要,建议一定做):
# macOS / Linux
shasum -a 256 soh_features.csv
# Windows PowerShell
Get-FileHash soh_features.csv -Algorithm SHA256应该得到:
f01210e620c61d35b5645f5e0a2c84030748e0a84bb7fbca90e1dbce5d1fd9a5 soh_features.csv行数对照:21,240 行 = 21,239 条数据 + 1 行表头。
★ 为什么这一步不能跳过
这本书的每一个结论都建立在同一份数据上。
校验通过 → 之后任何数字不一致,都是【代码问题】
校验不过 → 你永远分不清是"我写错了"还是"数据不同"这能省掉大量无意义的排查时间。 而且——这本书的核心是"质疑自己的分数", 如果连数据是不是同一份都不确定,你没法质疑任何东西。
数据里最该先知道的三件事
完整说明在 data/battery/README.md(建议第 03 章之前读一遍),先记住三条:
| 特点 | 为什么重要 |
|---|---|
| 一行 = 一支设备的一个 100 圈窗口 | 同一支设备有 235~464 行,相邻行只差 2~4 圈、soh 只差 0.0003 量级 → 不能按行随机划分 |
标签 soh 的最大值是 1.0017 | 标签也是测出来的 → "健康度"是估算量,不是真值 |
| R² 上不了 0.999,最好约 0.96 | 每个通道有"每支设备固定"的误差 → 谁报出 0.99 就是泄漏了 |
这三条会在后面的章节反复出现。 现在不理解没关系,记住有这回事就行。
1.8 环境自检
python check_env.py全部通过时你应该看到:
============================================================
《监督学习实战:回归建模与模型选型》环境自检
============================================================
✅ Python 版本:CPython 3.13.x (/path/to/.venv/bin/python)
✅ numpy 2.x.x
✅ pandas 3.x.x
✅ matplotlib 3.x.x
✅ sklearn 1.x.x
✅ 数据文件:/path/to/code/data/battery
soh_features.csv(共 1221 KB,21,240 行含表头)
------------------------------------------------------------
⚠️ xgboost 未安装(可选)
不影响学习:第 19 章会用 sklearn 自带的梯度提升做替代,两条路都能跑通。
------------------------------------------------------------
✅ 全部通过。下一步:从第 03 章开始,把代码敲进 demos/ 里跑起来。关于那条 ⚠️:xgboost 是可选的。 没装完全不影响 —— 第 19 章会讲怎么用 sklearn 自带的梯度提升替代, 以及为什么"没有 xgboost 也能跑通"本身就是一个重要的工程习惯。
点开:自检项逐一说明(不通过时怎么修)
| 检查项 | 不通过的表现 | 修复 |
|---|---|---|
| Python 版本 | ❌ Python 版本过低 | 装 3.10+;或确认虚拟环境用的是新解释器 |
| numpy / pandas / matplotlib | ❌ xxx 未安装 | pip install -r requirements.txt(先确认虚拟环境已激活) |
| sklearn | ❌ sklearn 未安装 | pip install scikit-learn —— 注意包名 |
| 数据文件 | ⚠️ 数据文件缺失 | 重新解压下载包,确认 data/battery/soh_features.csv 存在 |
四个包分别干什么(知道这个,报错时能判断影响范围):
| 包 | 负责 | 少了它哪一章会挂 |
|---|---|---|
numpy | 数值数组 | 全书 |
pandas | 表格读写 | 全书 |
matplotlib | 画图 | 第 07 章起(诊断图、置信带) |
scikit-learn | 模型与评估 | 第 06 章起(全书主角) |
1.9 敲通你的第一个文件:一份数据体检
现在开始写代码。 在 code/ 下新建 demos/ 目录, 然后新建文件 demos/ch01-checklist.py,把下面四行敲进去:
import pandas as pd
df = pd.read_csv("data/battery/soh_features.csv")
print(df.shape)
print(df["cell_id"].nunique())
print(df.groupby("cell_id").size().describe())
print(df["soh"].describe())在 code/ 目录下运行:
python demos/ch01-checklist.py你应该看到(数值必须一致):
(21239, 9)
60
count 60.000000
mean 353.983333
std 74.044991
min 235.000000
25% 275.500000
50% 356.500000
75% 421.250000
max 464.000000
Name: cell_id, dtype: float64
count 21239.000000
mean 0.908804
std 0.054821
min 0.803200
25% 0.861600
50% 0.911000
75% 0.957400
max 1.001700点开:这四行在告诉你什么(别只是跑通就过)
第一行 (21239, 9):21,239 行、9 列。规模适中,你的笔记本几秒钟就能跑完。
第二行 60:这张表里只有 60 支设备。
第三行:每支设备有 235~464 行(中位约 356 行)。
★ 第二行 + 第三行合起来,就是全书最重要的一条认知:
21,239 行数据 ≠ 21,239 个独立样本
21,239 行数据 = 60 支设备 × 每支约 354 个时间窗口同一支设备的相邻窗口几乎一模一样(窗口长 100 圈,相邻两行只错开 2~4 圈)。
这个认知会在第 09 章决定一切:如果你把 21,239 行当成独立样本随机划分, 同一支设备的相邻行会一个进训练、一个进测试 —— 模型只要"记住这支设备的特征"就能答对,分数虚高、上线就崩。
第四行:标签 soh 的范围是 0.8032 ~ 1.0017。
注意最大值 1.0017 > 1.0 —— 这不是 bug,是标签也是测出来的。 "健康度"是个估算量,不是物理真值。
这个细节在真实项目里很重要:如果有人拿一个"理论上限 1.0"的指标做出 1.0017 的预测, 它可能是对的 —— 因为真值本身就有测量噪声。
一个建议:故意制造一个报错
把第一行改成:
df = pd.read_csv("data/battery/soh_feature.csv") # 少一个 s再运行:
FileNotFoundError: [Errno 2] No such file or directory: 'data/battery/soh_feature.csv'看清楚这个报错:它说的文件名就是错的(少了个 s)。 这类"文件找不到"的报错,第一件事是核对路径拼写和当前目录,不要去怀疑 pandas。
1.10 常见报错速查表
| 报错信息 | 原因 | 修复 |
|---|---|---|
'python' 不是内部或外部命令 | Windows 装 Python 没勾 Add to PATH | 重装并勾选;或改用 py |
command not found: python | macOS/Linux 上命令名是 python3 | 用 python3,或 alias python=python3 |
No module named 'sklearn' | 装了但不在当前环境 / 装的是 sklearn 包 | 激活虚拟环境;pip install scikit-learn |
externally-managed-environment | 试图往系统 Python 装包 | 创建并激活虚拟环境,不要加 --break-system-packages |
ModuleNotFoundError: No module named 'pandas' | 虚拟环境没激活 | python -c "import sys; print(sys.executable)" 看路径 |
FileNotFoundError: data/battery/soh_features.csv | 当前目录不对(相对路径是相对当前工作目录的) | cd code 再运行;或用 __file__ 反推(第 04 章讲) |
ImportError: DLL load failed | Windows 上 numpy/scipy 装得不对 | pip uninstall 后重装;确保用的是 64 位 Python |
pip 慢到超时 | 默认源在国外 | -i https://pypi.tuna.tsinghua.edu.cn/simple |
VS Code 里 import sklearn 标红但能跑 | 编辑器选错了解释器 | Cmd/Ctrl+Shift+P → Python: Select Interpreter → 选带 .venv 的 |
1.11 本章检查清单
读完这一章,请逐条确认(勾选状态会存在你自己的浏览器里,下次打开还在):
已勾选 0 / 0 项
全部打勾了? 你已经有了一台可复现的"工作台"。
下一章我们看这张地图,然后从第 03 章正式开始建模。
本章练习
本章的练习是动手确认,不涉及建模:
练习 1:把环境信息打印出来存档
写一个脚本 demos/ch01-env-report.py,打印:
- Python 版本(
sys.version)和解释器路径(sys.executable); - 四个包的版本(
numpy/pandas/matplotlib/sklearn); - 数据的形状、行数、设备数。
为什么要做这件事:以后报告结果时,这几行就是"我的结论在什么环境下得到的"。 第 02 章会讲为什么它重要。
参考答案
import sys
import matplotlib
import numpy as np
import pandas as pd
import sklearn
print("=== 环境信息 ===")
print(f"Python {sys.version.split()[0]} ({sys.executable})")
print(f"numpy {np.__version__}")
print(f"pandas {pd.__version__}")
print(f"matplotlib {matplotlib.__version__}")
print(f"sklearn {sklearn.__version__}")
print("\n=== 数据 ===")
df = pd.read_csv("data/battery/soh_features.csv")
print(f"形状 {df.shape}")
print(f"行数 {len(df):,d}")
print(f"设备数 {df['cell_id'].nunique()}")期望输出(版本号会不同,形状必须一致):
=== 环境信息 ===
Python 3.13.13 (/path/to/.venv/bin/python)
numpy 2.5.3
pandas 3.0.6
matplotlib 3.11.2
sklearn 1.9.1
=== 数据 ===
形状 (21239, 9)
行数 21,239
设备数 60三个要点
① 为什么 sklearn 的版本用 sklearn.__version__ 读
因为导入名是 sklearn、装包名是 scikit-learn。想知道装了什么版本,用导入名读。
② 为什么要存解释器路径
同一台机器上可能有多个 Python 环境。半年后你回看这份记录, /path/to/.venv/bin/python 能告诉你"当时是在哪个环境跑的" —— 这比 "Python 3.13" 有用得多。
③ 为什么这个脚本值得留着
它不是练习,是工具。后面每次得到重要结论时, 把它一起贴进报告 —— 别人(包括三个月后的你)才知道这个结论在什么条件下成立。
练习 2:验证"一行不是一个独立样本"
用 pandas 回答三个问题,并写一句话总结:
- 这张表有多少行?多少支设备?
- 每支设备有多少行?(给出最小值、中位数、最大值)
- 取第一支设备的前 3 行,看看它们的
cycle和soh差多少。
参考答案
import pandas as pd
df = pd.read_csv("data/battery/soh_features.csv")
# ①②
print(f"行数 : {len(df):,d}")
print(f"设备数 : {df['cell_id'].nunique()}")
sizes = df.groupby("cell_id").size()
print(f"每支行数: min {sizes.min()} / 中位 {int(sizes.median())} / max {sizes.max()}")
# ③
first = df[df["cell_id"] == df["cell_id"].iloc[0]].head(3)
print("\n第一支设备的前 3 行:")
print(first[["cell_id", "cycle", "soh"]].to_string(index=False))
print(f"\ncycle 相邻差:{first['cycle'].diff().dropna().tolist()}")
print(f"soh 相邻差:{first['soh'].diff().dropna().round(4).tolist()}")期望输出:
行数 : 21,239
设备数 : 60
每支行数: min 235 / 中位 356 / max 464
第一支设备的前 3 行:
cell_id cycle soh
C001 50 0.9921
C001 54 0.9901
C001 56 0.9898
cycle 相邻差:[4.0, 2.0]
soh 相邻差:[-0.002, -0.0003]注意到一个细节:相邻两行的 cycle 差是 4 和 2 交替,不是固定值。
为什么:滑窗的步长设定是 3 圈,但窗口边界要取整到整数圈, 所以实际相邻行落在 2~4 圈之间 —— 全局看,步长 4 出现 10,607 次、步长 2 出现 10,572 次。
这不影响任何结论,关键是它们都远小于窗口长度 100 圈。
一句话总结:
21,239 行只来自 60 支设备;相邻两行只差 2~4 圈循环,
soh只差 0.0003 量级 —— 它们高度相似,不能当成独立样本。
★ 这个数(0.0003)值得记住
它是"泄漏有多容易"的度量:
相邻两行的 soh 只差 0.0003
↓
如果一行进训练、它的邻居进测试
↓
模型只要"预测得和邻居差不多",误差就小于 0.0003
↓
而正常的模型误差(RMSE)是 0.010 量级 —— 也就是说
泄漏能让误差【凭空变小 30 倍】这就是第 09~10 章要量化的东西。 现在你已经有直觉了。
练习 3:为什么"装包名"和"导入名"会不一样?
试着执行下面两条命令,观察结果(不要在虚拟环境外做):
pip install sklearn
python -c "import sklearn; print(sklearn.__version__, sklearn.__file__)"要求:说出发生了什么,以及它为什么是个"坑"。
参考答案
会发生什么:
pip install sklearn 不会报错,但它装的不是 scikit-learn —— PyPI 上存在一个名为 sklearn 的废弃占位包(2015 年发布,最后更新于 2015 年)。
它的作用是:装上后打印一段弃用警告,提醒你应该装 scikit-learn。
所以你可能会看到:
DEPRECATION: sklearn is deprecated. Use scikit-learn instead.或者(取决于版本)import sklearn 失败。
为什么这是个坑
| 现象 | 你的推断 | 真相 |
|---|---|---|
pip install sklearn 显示成功 | "装好了" | 装的是空壳占位包 |
import sklearn 报错 | "Python 坏了 / 环境有问题" | 真正的包从没装上 |
| 花时间重装 Python | 越走越远 | 一行 pip install scikit-learn 解决 |
★ 这类"装包名 ≠ 导入名"的坑在 Python 里很常见
| 装包名(pip) | 导入名(import) |
|---|---|
scikit-learn | sklearn |
Pillow | PIL |
opencv-python | cv2 |
beautifulsoup4 | bs4 |
PyYAML | yaml |
规律:装包名往往更"完整/正式"(带连字符、描述性), 导入名更"短"(方便敲)。
怎么避免:
- 以官方文档为准 —— 文档的安装章节写的一定是装包名;
- 用
pip show <导入名>反查:
pip show sklearn # 看 Name 字段
# Name: scikit-learn- 记住报错的方向:
No module named 'X' → 查 X 的【装包名】是不是也叫 X一条通用经验:
报
ModuleNotFoundError时,先确认"我装的是不是同一个东西", 再怀疑环境。 九成的ModuleNotFoundError是这两个原因之一: 环境不对,或者装包名写错。
面向工程实践:为什么第 0 步永远是"固定环境"
机器学习项目里,"能复现"比"分数高"更重要。而可复现的第一步就是环境。
① 报告结果时必须带环境信息。
❌ "我用随机森林得到 R² = 0.965。"
✅ "sklearn 1.9.1 / numpy 2.5.3 / Python 3.13.13 下,
随机森林(n_estimators=200, random_state=42)测试集 R² = 0.96503。"为什么:不同版本的 sklearn,同一个模型可能给出不同的数字 (默认参数会变、随机数实现会变)。没有环境信息的分数是不可复现的。
② 真实项目用锁文件,而不是"最低版本"。
requirements.txt 里写 scikit-learn>=1.3 对学习是合适的, 但生产环境应该锁定精确版本:
# 学习的写法:允许升级(灵活)
scikit-learn>=1.3
# 生产的写法:锁死(可复现)
scikit-learn==1.9.1pip freeze > requirements.lock.txt 可以生成锁文件。
③ 容器化是"环境固定"的终极方案。
FROM python:3.13-slim
WORKDIR /app
COPY requirements.lock.txt .
RUN pip install --no-cache-dir -r requirements.lock.txt
COPY . .
CMD ["python", "src/train.py"]这条命令解决了一个经典难题:
"在我的机器上能跑" → "在任何机器上都能跑"为什么这本书特别强调这件事
因为这本书的主题是质疑分数。而怀疑一个分数的第一步是:
"这个分数是在什么环境下、用什么代码、在哪份数据上得到的?"
三问里有两问(环境、数据)在这一章解决。第三问(代码)在后面的每一章解决。
★ 一个可操作的习惯
每做完一个"有结论"的实验,把这三样存下来:
# 1. 环境(本章的 demos/ch01-env-report.py)
# 2. 数据指纹
import hashlib
print(hashlib.sha256(open("data/battery/soh_features.csv", "rb").read()).hexdigest())
# 3. 代码的 random_state(后面每章都要求写)
# 存成一份报告:
# outputs/exp001_env.txt三个月后你回看这个结论时,这三样决定了你能否相信它。