📖 导读
欢迎来到机器学习实战!本篇博客是结合章节宏观架构微观代码实战的融合产物。

  • 宏观上:你将看到这段代码如何对应“线性模型战区”和“模型评估战区”。
  • 微观上:我们将对每一行代码进行“手术刀式”的拆解,重点攻克 new_x_trainfit_transform 等新手最容易卡壳的概念。
  • 目标:不仅让你能跑通代码,更要让你理解数据是如何一步步变身,最终让模型学会“看病”的。

🗺️ 一、本章定位:我们在学什么?

在之前的《章节全景指南》中,我们提到了机器学习的四大战区。本文件 01_逻辑回归API_预测癌症案例.py 正是第一战区(线性模型)的开篇之作,同时也贯穿了第四战区(模型评估)。

  • 核心算法:**逻辑回归 **(Logistic Regression)。
    • 误区纠正:名字带“回归”,实则是分类算法之王。它不预测具体数值(如房价),而是预测概率(患癌的可能性是 0 还是 1)。
  • 核心流程
    1. 数据清洗:处理脏数据(? 缺失值)。
    2. 特征工程:标准化(Standardization),让数据公平。
    3. 模型训练:让机器从历史病例中学习规律。
    4. 模型评估:用准确率打分,但要注意其局限性。

📦 第二部分:导包(准备工具箱)

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

💡 变量与工具详解

这里没有定义新变量,而是引入了工具库。想象你要做一道菜,这是去厨房拿工具:

  • **pandas **(别名 pd):Excel 增强版。用来读取表格数据(CSV),处理行列。它是数据处理的“瑞士军刀”。
  • **numpy **(别名 np):数学计算核心。用来处理数字运算,特别是这里的 np.nan(代表“非数字/缺失值”)。
  • train_test_split切分器。用来把数据切成“练习题”和“考试题”,防止模型作弊。
  • StandardScaler统一度量衡的工具。用来做标准化处理,这是线性模型成功的关键前置步骤。
  • LogisticRegression主厨(算法模型)。虽然名字带“回归”,但它是用来做二分类(判断良性还是恶性)的。
  • accuracy_score阅卷老师。用来给模型的考试结果打分(计算准确率)。

📂 第三部分:读取数据(拿到原材料)

# 1.读取文件获取数据
data = pd.read_csv('data/breast-cancer-wisconsin.csv', sep=',')
print(data.shape, data.ndim)  # 形状:(699, 11) 维度:2

🔍 变量详解:data

  • 是什么data 是一个 DataFrame(可以理解为 Python 里的 Excel 表格对象)。
  • 从哪来:通过 pd.read_csv 读取硬盘上的文件得到。
  • 内容:包含了 699 行(699 个病人),11 列(11 项指标,如 ID、半径、纹理、诊断结果等)。
  • 状态:此时的数据是原始数据(Raw Data)。
    • 隐患:里面可能包含无效字符(如 ?),直接喂给模型会报错,必须清洗。

🧹 第四部分:数据预处理(清洗原材料)

# 2.0 注意:数据中有"?"无效字符,需要先转换为 numpy 中的 nan,然后使用 dropna() 删除或者 fillna() 填充
new_data = data.replace('?', np.nan).dropna()
print(new_data.shape, new_data.ndim)  # 形状:(683, 11) 维度:2

🔍 变量详解:new_data

  • 是什么:清洗后的 DataFrame
  • 怎么变的(两步走):
    1. data.replace('?', np.nan)翻译。把表格里所有的问号 ?(人类看得懂,机器看不懂)替换成计算机认可的缺失值标记 NaN (Not a Number)。
    2. .dropna()丢弃。直接删除任何包含 NaN 的行。
  • 结果变化
    • 行数从 699 变成了 683
    • 含义:说明有 16 个病人的数据不完整(有问号)。为了保证模型学习的严谨性,我们忍痛割爱,把这 16 行直接删掉了。
    • 列数保持 11 列不变。
  • 为什么这么做:机器学习模型是数学公式,无法处理 ? 这种符号,也无法处理空缺。要么填补(用平均值),要么删除。这里为了简单直接,选择了删除。

✂️ 第五部分:拆分特征与标签(区分题目和答案)

# 2.1 分别获取特征和标签
# 拓展:iloc 格式 : 数据.iloc[行索引,列索引]
x = new_data.iloc[:, 1:-1]
y = new_data.iloc[:, -1]
print(x.shape, x.ndim)  # 形状:(683, 9) 维度:2
print(y.shape, y.ndim)  # 形状:(683,) 维度:1

🔍 变量详解:xy

这是机器学习中最重要的两个变量命名习惯,贯穿所有算法:

  • **x **(小写):**特征矩阵 **(Features) —— “题目”

    • 含义:包含了病人的各项检查指标(半径、纹理、周长等),是模型用来判断的依据。
    • 切片逻辑 iloc[:, 1:-1]
      • ::取所有行(683 个病人)。
      • 1:-1:取第 2 列 到 倒数第 2 列。
      • 去掉第 1 列:通常是 ID 号(如 1001, 1002),这对病情预测毫无用处,属于噪声。
      • 去掉最后 1 列:那是答案(诊断结果),训练时如果让模型看到答案,它就学会作弊了。
    • 形状(683, 9)。表示 683 个样本,每个样本有 9 个特征。
  • **y **(小写):**标签向量 **(Labels) —— “标准答案”

    • 含义:包含了病人的确诊结果(2=良性,4=恶性)。
    • 切片逻辑 iloc[:, -1]:取所有行的最后一列。
    • 形状(683,)。表示 683 个答案,是一维数组(向量)。

🎲 第六部分:划分训练集与测试集(模拟考试)

# 2.2 使用 train_test_split() 按比例切割成 4 部分
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=666)

🔍 变量详解:四大金刚

这一行代码把之前的 xy 切成了 4 份。注意变量名变成了大写,这是 sklearn 的惯例,代表经过划分后的数据集。

  1. **X_train **(训练集特征):
    • 含义:“平时的练习题(题目部分)”。
    • 大小:占总数据的 80% (约 546 行)。
    • 用途:喂给模型,让模型从中学习规律。
  2. **y_train **(训练集标签):
    • 含义:“平时的练习题(答案部分)”。
    • 用途:告诉模型,上面的题目对应的正确答案是什么。
  3. **X_test **(测试集特征):
    • 含义:“期末考试题(题目部分)”。
    • 大小:占总数据的 20% (约 137 行)。
    • 用途训练时严禁使用!等模型学完后,用它来考模型,检验泛化能力。
  4. **y_test **(测试集标签):
    • 含义:“期末考试题(答案部分/保密卷)”。
    • 用途:老师(程序员)拿着它来核对模型的预测结果,计算分数。
  • 关键参数解读
    • test_size=0.2:切 20% 出来当考题,80% 当练习。
    • random_state=666随机种子(定海神针)。
      • 作用:保证每次运行代码,切分出来的题目都一模一样
      • 意义:如果没有它,每次运行结果都可能不同,你就无法判断是模型改进了,还是仅仅因为运气好分到了简单的数据。

⚖️ 第七部分:特征标准化(统一度量衡)⭐核心难点

# 3.特征处理 (标准化)
ss = StandardScaler()  # 初始化标准化工具
new_x_train = ss.fit_transform(X_train)
new_x_test = ss.transform(X_test)

❓ 灵魂拷问:new_x_train 到底是什么?

很多教程只说“这是标准化后的数据”,但不解释过程区别。这里是本文件的最高频考点

1. 为什么要搞个 new_x_train
  • 原始问题:在 X_train 中,不同特征的数值范围(量纲)差异巨大。
    • 比如“细胞核半径”可能是 10.030.0
    • 比如“细胞核周长”可能是 60.0180.0
    • 后果:如果不处理,数值大的特征(周长)在计算距离或权重时会占据主导地位,数值小的特征(半径)会被忽略。就像让大象和蚂蚁拔河,大象必胜,但这不公平,也不科学。
  • 目标:把所有特征转换成均值为 0,标准差为 1的标准正态分布。让所有特征站在同一起跑线上。
2. new_x_train 是怎么生成的? (fit_transform)
  • 代码ss.fit_transform(X_train)
  • 动作分解(两步合一):
    • **fit (学习/制定标准):计算器先扫描 X_train,算出每一列的平均值 **(Mean) 和 **标准差 **(Std)。
      • 注意这一步只在训练集上做!相当于制定了“评分标准”。
    • **transform **(转换/执行标准):利用刚才算出的均值和标准差,把 X_train 里的每一个数字都进行公式转换:
      image-20260318204504342
  • 结果new_x_train 是一个新的 NumPy 数组(不再是 DataFrame)。里面的数字变了,变成了以 0 为中心的小数(如 -1.2, 0.5, 2.1 等),但行列顺序和 X_train 保持一致。
  • 含义:这是“已经按标准处理好的练习题”,可以直接交给模型学习了。
3. 为什么还有一个 new_x_test?且只用 transform
  • 代码ss.transform(X_test)
  • 动作
    • 注意:这里没有 fit!绝对不能写 fit_transform(X_test)
    • 原因:测试集模拟的是未来的未知数据。我们不能让测试集自己算平均值(那是作弊,叫数据泄露)。
    • 做法:必须强行使用训练集 (X_train) 制定的标准(之前 fit 学到的均值和方差)来转换测试集。
  • 结果new_x_test 是“用同一套标准处理好的考试题”。
✅ 总结对比表
变量名 来源 处理方式 含义
X_train 原始切分 原始的练习题(数值范围不统一,不能直接喂给线性模型)
new_x_train X_train fit + transform 标准化的练习题(既学习了标准,又完成了转换,模型真正吃进去的数据
X_test 原始切分 原始的考试题
new_x_test X_test 仅 transform 标准化的考试题(沿用练习题的标准进行转换,用于公平考试)

🤖 第八部分:创建与训练模型(老师上课)

# 4.创建模型
lr_model = LogisticRegression()  # 实例化模型
# 5.模型训练
lr_model.fit(new_x_train, y_train)

🔍 过程详解

  • lr_model = LogisticRegression()
    • 创建了一个空的逻辑回归模型对象。此时它脑子里空空如也,内部参数(权重和偏置)都是初始值。
  • lr_model.fit(new_x_train, y_train)
    • 输入:把**处理好的练习题 **(new_x_train) 和 **练习答案 **(y_train) 喂给它。
    • 内部发生的事:模型开始疯狂计算(通常使用梯度下降法),调整内部的权重参数,试图找到一条数学曲线(决策边界),能最好地把“良性”和“恶性”分开。
    • 结果:训练结束后,lr_model 这个对象内部就保存了学到的规律。它现在是一个**“Trained Model **(训练好的模型),具备了预测能力。

📝 第九部分:预测与评估(期末考试与打分)

# 6.模型预测和评估:准确率
y_pred = lr_model.predict(new_x_test)  # 1.先预测
print(y_pred)          # 打印模型猜的结果
print(y_test.tolist()) # 打印真实答案
print(f"准确率:{accuracy_score(y_test, y_pred)}")  # 2.再计算
print('---------------------------------------------------')
print(f"准确率:{lr_model.score(new_x_test, y_test)}")  # 底层也是先预测再计算

🔍 变量详解:y_pred

  • 是什么:模型的预测结果数组
  • 怎么来的lr_model.predict(new_x_test)
    • 模型拿着**处理好的考试题 **(new_x_test),运用之前学到的规律,对每一个病人进行判断。
    • 输出结果是一串数字(如 [2, 4, 2, 2, 4, ...]),代表模型认为每个病人是良性 (2) 还是恶性 (4)。
  • 用途:用来和真实答案 y_test 做对比。

🌟 核心概念:准确率 (Accuracy)

  • 计算逻辑
    image-20260318204546188
  • 代码实现
    • accuracy_score(y_test, y_pred)
      • y_test:真实答案(老师手里的标准卷)。
      • y_pred:模型的答案(学生交的卷)。
      • 函数会逐个比对,统计相同的个数,除以总数。
    • lr_model.score(new_x_test, y_test)
      • 这是模型对象自带的快捷方法。
      • 内部流程:它其实偷偷先执行了 predict(new_x_test) 得到预测值,然后再调用 accuracy_score 计算。所以两行代码输出的结果是一模一样的。

⚠️ 重要提醒:准确率的局限性(进阶思考)

虽然代码输出了准确率(比如 0.96),但在医疗场景下要警惕:

  • 场景:如果有 100 个人,只有 5 个癌症(样本不平衡)。
  • 摆烂模型:如果模型全部预测“没病”,它能对 95 个,准确率高达 95%
  • 后果:虽然分数高,但 5 个癌症病人全被漏诊了(这是最严重的错误,假阴性)。
  • 结论:准确率是一个基础指标。在后续课程中,你还需要关注:
    • **召回率 **(Recall):能不能把所有的病人都找出来?(宁可错杀,不可放过)
    • **精确率 **(Precision):预测是癌症的人里,真的有多少是癌症?
    • AUC 曲线:综合评估模型好坏的金标准。

🎯 全文数据流向总结图

为了让你彻底明白 new_x_train 在整个流程中的位置,请看这个数据变身记

  1. 原始文件 (csv)
    ⬇️ read_csv
  2. data (脏表格,含 ?)
    ⬇️ replace + dropna (清洗)
  3. new_data (干净表格)
    ⬇️ iloc 切片 (分离题目和答案)
  4. x (题目), y (答案)
    ⬇️ train_test_split (划分考场)
  5. X_train (原始练习题), X_test (原始考试题)
    ⬇️ StandardScaler (关键变身点:统一度量衡)
  6. new_x_train (标准化练习题 👉 喂给模型训练)
    new_x_test (标准化考试题 👉 喂给模型考试)
    ⬇️ model.predict
  7. y_pred (模型给出的猜测)
    ⬇️ 对比 y_test
  8. 准确率 (最终得分)

🚀 下一步行动建议

恭喜你!你已经彻底拿下了逻辑回归的完整流程。

  • 复习建议:重点回顾 new_x_train 的生成过程(fit vs transform),这是面试和实战中最容易出错的地方。
  • 扩展思考:如果数据中缺失值很多,dropna() 会丢失大量信息,有没有更好的填充方法?(提示:均值填充、中位数填充)。
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐