news 2026/9/23 1:39:24

Python Machine Learning 第3章实战:使用 Scikit-Learn 完成分类算法全景巡礼

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python Machine Learning 第3章实战:使用 Scikit-Learn 完成分类算法全景巡礼

Python Machine Learning 第3章实战:使用 Scikit-Learn 完成分类算法全景巡礼

【免费下载链接】python-machine-learning-bookThe "Python Machine Learning (1st edition)" book code repository and info resource项目地址: https://gitcode.com/gh_mirrors/py/python-machine-learning-book

导读

本文基于开源仓库python-machine-learning-book中第 3 章的代码与文档(code/ch03/README.md、code/ch03/ch03.ipynb)编写。本章围绕"用 scikit-learn 训练机器学习分类器"这一核心主题,从感知机出发,依次讲解逻辑回归、线性 SVM、核 SVM、决策树、随机森林与 K 近邻六类经典分类算法。读完本文,你将掌握一套完整可复用的 Iris 分类实验流程:数据加载、训练/测试集划分、特征标准化、决策区域可视化,以及每种算法的核心参数调优与过拟合控制思路,并能直接对照仓库中的 Jupyter Notebook 与可选 Python 脚本动手复现。

本文所有代码均来源于 code/ch03/ch03.ipynb,其可运行的合并脚本位于 code/optional-py-scripts/ch03.py;决策树可视化产物见 code/ch03/tree.dot。


1. 如何选择分类算法:经验法则与本章路线图

「Choosing a classification algorithm」是本章的起点:不存在对所有问题都最优的万能分类器,选择哪种算法取决于训练样本数量、特征维度、数据是否线性可分、对模型可解释性的要求,以及训练/预测的时延预算。

从源码结构看,code/ch03/ch03.ipynb 的 91 个单元格(54 个 Markdown + 37 个代码单元格)按以下路线循序渐进,这也是本仓库第 3 章目录(code/ch03/README.md)给出的正式大纲:

算法核心思想适用场景
感知机(Perceptron)线性决策边界 + 错误驱动学习线性可分数据的入门基线
逻辑回归(Logistic Regression)用 sigmoid 建模类别概率需要概率输出、可解释性强的分类
线性 SVM最大间隔超平面线性可分/近似可分数据
核 SVM核技巧映射到高维空间非线性决策边界
决策树递归划分、信息增益最大化可解释性优先、特征含义明确
随机森林多棵决策树集成投票降低单树过拟合、提升鲁棒性
K 近邻惰性学习、基于距离投票低维小样本、决策边界复杂

本章全部实验统一使用Iris(鸢尾花)数据集,它包含 3 个类别(Iris-Setosa、Iris-Versicolor、Iris-Virginica)与 4 个数值特征,是 scikit-learn 内置的标准多分类基准数据,便于不同算法在同一数据上横向对比。


2. scikit-learn 第一步:Iris 数据加载、划分与标准化

本节对应源码中的 "First steps with scikit-learn" 部分,是整个实验的公共数据管线,后续所有算法都复用这套数据。

2.1 加载数据集并选取特征

仓库代码只取iris.data的第 3 列(花瓣长度)与第 4 列(花瓣宽度)作为特征X,类别标签已由 scikit-learn 转换为整数:0=Iris-Setosa,1=Iris-Versicolor,2=Iris-Virginica:

from sklearn import datasets import numpy as np iris = datasets.load_iris() X = iris.data[:, [2, 3]] # petal length, petal width y = iris.target print('Class labels:', np.unique(y)) # 输出: Class labels: [0 1 2]

选取两个特征是为了能够在二维平面上可视化决策区域——这是本章贯穿始终的直观验证手段。

2.2 划分训练集与测试集(含 sklearn 0.18 兼容处理)

仓库代码用一个版本判断来兼容新旧版 scikit-learn(0.18train_test_split迁移到sklearn.model_selection):

from distutils.version import LooseVersion as Version from sklearn import __version__ as sklearn_version if Version(sklearn_version) < '0.18': from sklearn.cross_validation import train_test_split else: from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=0)
  • test_size=0.3:30% 的数据(45 个样本,见源码输出y_test.shape(45,))留作测试集,70% 用于训练;
  • random_state=0:固定随机种子,保证每次运行得到相同划分,便于复现书中结果。

2.3 特征标准化:为什么训练集和测试集必须用同一套参数

标准化的目的,是让不同量纲的特征统一到均值为 0、方差为 1 的尺度,避免大数值特征在距离计算与梯度下降中主导学习。关键操作顺序是:先用StandardScaler训练集fit(仅计算均值与标准差),再用同一套参数transform训练集和测试集:

from sklearn.preprocessing import StandardScaler sc = StandardScaler() sc.fit(X_train) # 只在训练集上估计 μ 和 σ X_train_std = sc.transform(X_train) # 应用同一 μ、σ X_test_std = sc.transform(X_test)

从源码结构看,后续感知机、逻辑回归、线性 SVM、核 SVM、KNN 全部使用标准化后的X_train_std / X_test_std;而决策树与随机森林因为不依赖距离/梯度,直接使用原始特征(见 code/ch03/ch03.ipynb 的决策树、随机森林单元格)。这一点提示了实用经验:距离类与梯度类模型必须标准化,树模型通常不必


3. 决策区域可视化辅助函数

本章多次复用第二章定义的plot_decision_regions函数,它把整个特征平面网格化后交给分类器预测,用等高线填充色块表示决策区域,同时叠加训练样本与测试样本:

from matplotlib.colors import ListedColormap import matplotlib.pyplot as plt import warnings def versiontuple(v): return tuple(map(int, (v.split(".")))) def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02): # setup marker generator and color map markers = ('s', 'x', 'o', '^', 'v') colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan') cmap = ListedColormap(colors[:len(np.unique(y))]) # plot the decision surface x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1 x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution), np.arange(x2_min, x2_max, resolution)) Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T) Z = Z.reshape(xx1.shape) plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap) plt.xlim(xx1.min(), xx1.max()) plt.ylim(xx2.min(), xx2.max()) for idx, cl in enumerate(np.unique(y)): plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1], alpha=0.6, c=cmap(idx), edgecolor='black', marker=markers[idx], label=cl) # highlight test samples if test_idx: if not versiontuple(np.__version__) >= versiontuple('1.9.0'): X_test, y_test = X[list(test_idx), :], y[list(test_idx)] warnings.warn('Please update to NumPy 1.9.0 or newer') else: X_test, y_test = X[test_idx, :], y[test_idx] plt.scatter(X_test[:, 0], X_test[:, 1], c='', alpha=1.0, edgecolor='black', linewidths=1, marker='o', s=55, label='test set')

调用时通常先拼接训练与测试数据,并用test_idx=range(105, 150)高亮测试样本:

X_combined_std = np.vstack((X_train_std, X_test_std)) y_combined = np.hstack((y_train, y_test))

可视化函数是贯穿全章的"仪表盘":同一张图上,决策区域的形状、边界的光滑程度、测试样本是否落入正确区域,能直观反映每种算法的偏差-方差特性。


4. 用 scikit-learn 训练感知机

4.1 模型训练

Perceptron是 scikit-learn 对第二章手写感知机的现成封装,训练过程与手写版一致——逐样本错误驱动更新权重:

from sklearn.linear_model import Perceptron ppn = Perceptron(n_iter=40, eta0=0.1, random_state=0) ppn.fit(X_train_std, y_train)
  • n_iter=40:遍历训练集的轮数(epochs);
  • eta0=0.1:学习率;
  • random_state=0:固定随机种子(配合内部shuffle=True保证可复现)。

4.2 评估

仓库代码同时给出误分类样本数准确率两种评估口径:

y_pred = ppn.predict(X_test_std) print('Misclassified samples: %d' % (y_test != y_pred).sum()) # 输出: Misclassified samples: 4 from sklearn.metrics import accuracy_score print('Accuracy: %.2f' % accuracy_score(y_test, y_pred)) # 输出: Accuracy: 0.91

在 45 个测试样本上仅错 4 个(准确率 91%),对线性可分数据而言已经是不错的基线。绘制决策区域后可以看到,感知机在 Iris 两个特征上的决策边界呈直线,且收敛依赖数据严格线性可分——这是感知机的天然局限,也自然引出下一节具备概率建模能力的逻辑回归。


5. 用逻辑回归建模类别概率

5.1 直觉与条件概率:从净输入到 sigmoid

逻辑回归的起点与 Adaline 相同:对特征做加权求和得到净输入z = w0 + w1·x1 + ... + wm·xm,但不再直接输出实数值,而是将其送入sigmoid 函数φ(z) = 1 / (1 + e^(-z)),把任意实数压缩到 (0, 1) 区间,解释为类别 1 的条件概率 P(y=1|x):

import matplotlib.pyplot as plt import numpy as np def sigmoid(z): return 1.0 / (1.0 + np.exp(-z)) z = np.arange(-7, 7, 0.1) phi_z = sigmoid(z) plt.plot(z, phi_z) plt.axvline(0.0, color='k') plt.ylim(-0.1, 1.1) plt.xlabel('z') plt.ylabel('$\phi (z)$') plt.yticks([0.0, 0.5, 1.0]) ax = plt.gca() ax.yaxis.grid(True) plt.show()

从源码结构看,sigmoid 曲线是逻辑回归的原理基石:当z=0φ(z)=0.5,对应决策边界;z>0时概率超过 0.5,预测类别 1。上图中的 sigmoid 曲线即 code/ch03/ch03.ipynb 单元格 35 的运行结果,与该章书籍配图03_03(逻辑回归模型工作流程图:净输入 → sigmoid 激活 → 量化器输出)相互印证,完整说明了逻辑回归将"线性模型 + 概率输出"结合的结构。

5.2 逻辑代价函数:为什么用对数似然而非平方误差

逻辑回归不再使用平方误差,而是采用基于最大似然估计的对数代价函数。仓库代码用两张代价曲线直观解释其动机:

def cost_1(z): return - np.log(sigmoid(z)) def cost_0(z): return - np.log(1 - sigmoid(z)) z = np.arange(-10, 10, 0.1) phi_z = sigmoid(z) c1 = [cost_1(x) for x in z] plt.plot(phi_z, c1, label='J(w) if y=1') c0 = [cost_0(x) for x in z] plt.plot(phi_z, c0, linestyle='--', label='J(w) if y=0') plt.ylim(0.0, 5.1) plt.xlim([0, 1]) plt.xlabel('$\phi$(z)') plt.ylabel('J(w)') plt.legend(loc='best') plt.show()

两张曲线都是凸的且单调:当真实标签y=1时,若φ(z)→1(预测正确且自信),代价趋近 0;若φ(z)→0(严重误判),代价趋近无穷,从而对错误预测施加强烈惩罚。整个训练过程即通过梯度下降最小化这一代价函数来学习权重。

5.3 用 scikit-learn 训练逻辑回归并预测概率

from sklearn.linear_model import LogisticRegression lr = LogisticRegression(C=1000.0, random_state=0) lr.fit(X_train_std, y_train) plot_decision_regions(X_combined_std, y_combined, classifier=lr, test_idx=range(105, 150)) plt.xlabel('petal length [standardized]') plt.ylabel('petal width [standardized]') plt.legend(loc='upper left') plt.show()

训练完成后,可以用predict_proba查看每个测试样本的类别概率:

if Version(sklearn_version) < '0.17': lr.predict_proba(X_test_std[0, :]) else: lr.predict_proba(X_test_std[0, :].reshape(1, -1))

这段代码同样包含版本兼容分支:旧版允许直接传入一维样本,新版要求显式reshape(1, -1)成二维。C=1000.0在这里取值较大,意味着正则化强度较弱,先观察"几乎不约束"的拟合效果,为下一节的过拟合讨论做铺垫。

5.4 用正则化缓解过拟合:C 参数的权重路径实验

过拟合的本质是模型对训练数据的噪声过度敏感、泛化能力下降。逻辑回归通过给代价函数添加 L2 惩罚项λ/2 · ‖w‖²来控制模型复杂度,scikit-learn 用正则化强度的倒数C = 1/λ暴露该控制旋钮:C 越小,正则化越强,权重被压缩得越厉害

仓库代码用一个"权重路径"实验直观展示 C 的影响——遍历C = 10^-5 ... 10^4,记录每个 C 下类别 1(Versicolor)的两个特征系数:

weights, params = [], [] for c in np.arange(-5., 5.): lr = LogisticRegression(C=10.**c, random_state=0) lr.fit(X_train_std, y_train) weights.append(lr.coef_[1]) params.append(10**c) weights = np.array(weights) plt.plot(params, weights[:, 0], label='petal length') plt.plot(params, weights[:, 1], linestyle='--', label='petal width') plt.ylabel('weight coefficient') plt.xlabel('C') plt.legend(loc='upper left') plt.xscale('log') plt.show()

实验结果(对应书籍配图03_06的"欠拟合 / 良好拟合 / 过拟合"对比)可以总结为:

C 值正则化强度权重幅值模型状态
C 很小(如 10⁻⁵)极强趋近 0欠拟合(高偏差),边界过于简单
C 适中(如 10⁰)适中适中良好拟合
C 很大(如 10³)极弱较大过拟合(高方差),边界过度复杂

调参经验:C 是逻辑回归最重要的超参数,实践中应结合交叉验证在10^-3 ~ 10^3的对数尺度上网格搜索,而非直接取极值。本章在 code/ch06 的模型评估章节还会系统讲解交叉验证与网格搜索。


6. 最大间隔分类:支持向量机(SVM)

6.1 最大间隔直觉:不只要分对,还要分得"稳"

与逻辑回归关注概率不同,SVM 的目标是找到一条离最近训练样本(支持向量)距离最大的决策边界(最大间隔超平面)。间隔越大,边界对轻微扰动的鲁棒性越强,泛化能力通常越好。仓库代码用SVC(kernel='linear')在标准化 Iris 数据上训练线性 SVM:

from sklearn.svm import SVC svm = SVC(kernel='linear', C=1.0, random_state=0) svm.fit(X_train_std, y_train) plot_decision_regions(X_combined_std, y_combined, classifier=svm, test_idx=range(105, 150)) plt.xlabel('petal length [standardized]') plt.ylabel('petal width [standardized]') plt.legend(loc='upper left') plt.show()

kernel='linear'表示使用线性核,即原始特征空间中的直线/超平面决策边界。

6.2 用松弛变量处理近似线性可分数据

现实中数据往往并非严格线性可分。SVM 为此引入松弛变量(slack variables, ξ),允许少量样本落在间隔之内甚至错误一侧,同时通过惩罚参数C在"间隔最大化"与"误分类惩罚"之间权衡:

  • C 大:对误分类惩罚重,间隔变窄,倾向完美拟合训练集(易过拟合);
  • C 小:容忍更多误分类,间隔更宽(易欠拟合)。

从源码结构看,C=1.0是仓库示例的默认取值,也是实践中最常用的起点。惩罚项的思想与上一节逻辑回归的 L2 正则化殊途同归——都是通过"约束复杂度"来平衡偏差与方差。

6.3 scikit-learn 中的替代实现

SVC外,scikit-learn 针对不同场景还提供线性 SVM 的替代实现,例如LinearSVC(线性核专用、对大数据集更快)与SGDClassifier(随机梯度下降、支持在线学习)。仓库本章主体仍以SVC为主,因为它的kernel参数可以无缝切换到下一节的非线性核。


7. 用核 SVM 解决非线性问题

7.1 为什么线性模型失效:XOR 数据集

线性分类器在"线性不可分"的数据上会彻底失效。仓库代码构造了一个经典的XOR 数据集来演示:200 个随机二维样本,类别由异或逻辑生成,正负类呈交叉分布:

np.random.seed(0) X_xor = np.random.randn(200, 2) y_xor = np.logical_xor(X_xor[:, 0] > 0, X_xor[:, 1] > 0) y_xor = np.where(y_xor, 1, -1) plt.scatter(X_xor[y_xor == 1, 0], X_xor[y_xor == 1, 1], c='b', marker='x', label='1') plt.scatter(X_xor[y_xor == -1, 0], X_xor[y_xor == -1, 1], c='r', marker='s', label='-1') plt.xlim([-3, 3]); plt.ylim([-3, 3]) plt.legend(loc='best') plt.show()

没有任何一条直线能分开这类数据,必须先做特征映射再分类。

7.2 核技巧:在隐式高维空间找超平面

核技巧的精妙之处在于:不必显式计算高维映射φ(x),只需用核函数在原始空间中计算样本对的高维内积。常用的RBF 径向基核K(x, x') = exp(-γ·‖x - x'‖²),其中γ(gamma)控制单个训练样本的影响半径。

先在 XOR 数据上验证 RBF 核 SVM 能学出非线性边界:

svm = SVC(kernel='rbf', random_state=0, gamma=0.10, C=10.0) svm.fit(X_xor, y_xor) plot_decision_regions(X_xor, y_xor, classifier=svm) plt.legend(loc='upper left') plt.show()

再将 RBF 核应用到 Iris 数据,仓库代码特意对比了两个 gamma 值的效果:

# gamma=0.2:决策边界较平滑 svm = SVC(kernel='rbf', random_state=0, gamma=0.2, C=1.0) svm.fit(X_train_std, y_train) plot_decision_regions(X_combined_std, y_combined, classifier=svm, test_idx=range(105, 150)) plt.xlabel('petal length [standardized]') plt.ylabel('petal width [standardized]') plt.legend(loc='upper left') plt.show() # gamma=100.0:每个训练样本的影响范围极小,边界剧烈扭曲 svm = SVC(kernel='rbf', random_state=0, gamma=100.0, C=1.0) svm.fit(X_train_std, y_train) plot_decision_regions(X_combined_std, y_combined, classifier=svm, test_idx=range(105, 150)) plt.xlabel('petal length [standardized]') plt.ylabel('petal width [standardized]') plt.legend(loc='upper left') plt.show()

gamma 与 C 是两个核心旋钮

参数含义取值过大取值过小
gamma单个样本的影响半径每个样本只影响极小邻域,边界严重过拟合决策边界过于平滑,近似线性
C误分类惩罚过拟合训练噪声边界过宽、欠拟合

gamma=0.2得到平滑合理的非线性边界;gamma=100.0时每个训练点周围都"圈出"自己的小区域,决策区域碎裂——这是过拟合的可视化典型样例,也是理解"高方差"最直观的教材。


8. 决策树学习:递归划分与信息增益

8.1 最大化信息增益:熵、基尼不纯度与误分类率

决策树通过递归二分特征空间构建,每次分裂都试图最大化信息增益(分裂前后不纯度的降低)。仓库代码对比了三种常用的不纯度度量,画出它们随类别概率p(i=1)变化的曲线:

def gini(p): return p * (1 - p) + (1 - p) * (1 - (1 - p)) def entropy(p): return - p * np.log2(p) - (1 - p) * np.log2((1 - p)) def error(p): return 1 - np.max([p, 1 - p]) x = np.arange(0.0, 1.0, 0.01) ent = [entropy(p) if p != 0 else None for p in x] sc_ent = [e * 0.5 if e else None for e in ent] err = [error(i) for i in x] fig = plt.figure() ax = plt.subplot(111) for i, lab, ls, c, in zip([ent, sc_ent, gini(x), err], ['Entropy', 'Entropy (scaled)', 'Gini Impurity', 'Misclassification Error'], ['-', '-', '--', '-.'], ['black', 'lightgray', 'red', 'green', 'cyan']): line = ax.plot(x, i, label=lab, linestyle=ls, lw=2, color=c) ax.legend(loc='upper center', bbox_to_anchor=(0.5, 1.15), ncol=3, fancybox=True, shadow=False) ax.axhline(y=0.5, linewidth=1, color='k', linestyle='--') ax.axhline(y=1.0, linewidth=1, color='k', linestyle='--') plt.ylim([0, 1.1]) plt.xlabel('p(i=1)') plt.ylabel('Impurity Index') plt.show()

三种度量在p=0.5(最不纯)时都取最大值、在p=0p=1(完全纯)时归零,因此在实践中选择哪一种对结果影响通常不大;熵与基尼不纯度在类别极不平衡时比误分类率更敏感。

8.2 构建决策树:criterion 与 max_depth

from sklearn.tree import DecisionTreeClassifier tree = DecisionTreeClassifier(criterion='entropy', max_depth=3, random_state=0) tree.fit(X_train, y_train) X_combined = np.vstack((X_train, X_test)) y_combined = np.hstack((y_train, y_test)) plot_decision_regions(X_combined, y_combined, classifier=tree, test_idx=range(105, 150)) plt.xlabel('petal length [cm]') plt.ylabel('petal width [cm]') plt.legend(loc='upper left') plt.show()

注意这里直接使用原始特征(未标准化)——决策树按特征值阈值分裂,对特征尺度不敏感。

  • criterion='entropy':用信息熵作为分裂度量;
  • max_depth=3:限制树的深度为 3,是防止决策树无限生长、过拟合训练数据的最直接手段;
  • random_state=0:固定分裂评估的随机性。

8.3 用 Graphviz 导出并可视化决策树

仓库代码把训练好的树导出为 DOT 文件(code/ch03/tree.dot),这是决策树"可解释性"的直接体现:

from sklearn.tree import export_graphviz export_graphviz(tree, out_file='tree.dot', feature_names=['petal length', 'petal width'])

code/ch03/tree.dot 中保存了完整的树结构,根节点即为petal width <= 0.75(熵 1.5799、105 个样本、类别分布 [34, 32, 39]),随后逐层分裂:左子树在petal width <= 1.65处继续划分 Versicolor,右子树在petal length <= 4.95处继续区分 Virginica,最终得到熵为 0 的纯叶子节点。整棵树的每个节点都标注了分裂特征、阈值、熵、样本数与类别计数,可以逐节点核对分类逻辑。

如果安装了pydotpluspip install pydotplus)且 scikit-learn 版本 ≥ 0.18,还可以在 Notebook 内直接渲染带类别名、填充色与圆角样式的树图(利用filled=True, rounded=True, class_names=['setosa', 'versicolor', 'virginica']等新参数),无需先生成 dot 文件;未安装时仓库代码会打印pydotplus is not installed.的提示。

8.4 随机森林:从弱学习器到强学习器

单棵决策树容易过拟合,随机森林通过"装袋 + 特征随机化"把多棵弱树集成为强分类器:每棵树在训练集的有放回抽样(bootstrap)子集上训练,且每次分裂只考虑随机选取的部分特征,最后以多数投票决定类别(对应书籍配图03_20的多数投票示意)。

from sklearn.ensemble import RandomForestClassifier forest = RandomForestClassifier(criterion='entropy', n_estimators=10, random_state=1, n_jobs=2) forest.fit(X_train, y_train) plot_decision_regions(X_combined, y_combined, classifier=forest, test_idx=range(105, 150)) plt.xlabel('petal length [cm]') plt.ylabel('petal width [cm]') plt.legend(loc='upper left') plt.show()
  • n_estimators=10:森林中的决策树数量,越多通常越稳健(代价是训练时间);
  • criterion='entropy':单棵树的熵分裂准则;
  • n_jobs=2:并行使用 2 个 CPU 核训练,体现集成方法的计算开销与并行化收益;
  • 与单棵树相同,随机森林也直接使用原始特征。

相比单棵决策树,随机森林的决策边界明显更平滑、更稳健,且对噪声与轻微过拟合有更强的抵抗力,是"从弱到强"集成思想的经典示范。


9. K 近邻:一种惰性学习算法

KNN 是本章收尾算法,与前面所有"急切学习"(训练阶段学出模型参数)方法不同,它属于惰性学习——训练阶段只是把样本"记住",真正的计算发生在预测时:对新样本,找出训练集中距离最近的 K 个邻居,按多数投票决定类别。

from sklearn.neighbors import KNeighborsClassifier knn = KNeighborsClassifier(n_neighbors=5, p=2, metric='minkowski') knn.fit(X_train_std, y_train) plot_decision_regions(X_combined_std, y_combined, classifier=knn, test_idx=range(105, 150)) plt.xlabel('petal length [standardized]') plt.ylabel('petal width [standardized]') plt.legend(loc='upper left') plt.show()

参数含义:

参数取值说明
n_neighbors5投票邻居数 K;K 越小边界越复杂(易过拟合),K 越大边界越平滑
metric'minkowski'闵可夫斯基距离族,是欧氏距离与曼哈顿距离的推广
p2闵可夫斯基距离的阶数,p=2即欧氏距离,p=1为曼哈顿距离

KNN 必须使用标准化后的特征(X_train_std / X_test_std),因为距离计算对特征量纲高度敏感;这也是它与树模型在数据预处理上的关键差异。它的优势是实现简单、无需训练,但预测时需要与全部训练样本计算距离,样本量大时开销显著,且高维空间下距离区分度会下降("维度灾难")。


10. 本章小结

第 3 章用同一份 Iris 数据串起了 scikit-learn 的六类经典分类算法,形成了一条完整的实战主线:

  1. 数据管线先行:加载 →train_test_split划分(test_size=0.3, random_state=0)→StandardScaler只在训练集上fit再统一transform
  2. 线性模型三连:感知机(Perceptron,91% 准确率基线)→ 逻辑回归(sigmoid 概率输出 +C正则化权重路径实验)→ 线性 SVM(最大间隔 + 松弛变量);
  3. 非线性进阶:核 SVM 用 RBF 核解决 XOR 等线性不可分问题,gammaC联合控制偏差-方差权衡;
  4. 树模型与集成:决策树(熵/基尼不纯度、max_depth防过拟合、Graphviz 导出)→ 随机森林(bootstrap + 特征随机化 + 多数投票);
  5. 惰性学习收尾:KNN(n_neighborspmetric)展示"零训练"的另一种建模范式。

贯穿始终的方法论是偏差-方差权衡:从逻辑回归的C、SVM 的gamma/C,到决策树的max_depth、KNN 的K,每个超参数都在"拟合训练数据"与"保持泛化能力"之间寻找平衡点,而plot_decision_regions让这种权衡变得肉眼可见。

本文所有代码均可直接在 code/ch03/ch03.ipynb 中逐单元格运行,或运行合并脚本 code/optional-py-scripts/ch03.py 一次跑完;决策树导出文件 code/ch03/tree.dot 可用 Graphviz 渲染成树形图。如果你需要先搭建 Python 与 Jupyter Notebook 环境,可参考 code/ch01/README.md 中的环境搭建说明;第 4、5 章(数据预处理、降维)与第 6 章(模型评估与超参数优化)会在此基础上继续深入,把本文中提到的交叉验证、网格搜索等方法系统化。

后续章节的进阶路线:若想了解模型评估与超参数调优的系统方法(交叉验证、网格搜索),可继续学习 code/ch06/ch06.ipynb;若关注特征工程与降维对分类器的影响,可阅读 code/ch04/ch04.ipynb 与 code/ch05/ch05.ipynb。

【免费下载链接】python-machine-learning-bookThe "Python Machine Learning (1st edition)" book code repository and info resource项目地址: https://gitcode.com/gh_mirrors/py/python-machine-learning-book

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 1:38:37

Java汽车推荐系统实战:Spring Boot+Redis+MySQL构建数据驱动闭环

简介&#xff1a;本资源是一套面向计算机专业本科生的Java毕业设计实战项目——个性化汽车推荐系统&#xff0c;聚焦推荐算法工程化落地&#xff0c;适用于软件开发、数据挖掘与智能系统方向的学习与课程设计。项目采用Spring BootMyBatis技术栈构建后端服务&#xff0c;前端基…

作者头像 李华
网站建设 2026/9/23 1:37:57

Forest Pack 7 植被分布系统原理与工业级配置指南

简介&#xff1a;本资源是Forest Pack 7官方帮助文档PDF&#xff0c;面向3ds Max中高级用户、建筑可视化设计师、游戏场景美术师及影视特效从业者&#xff0c;解决大规模自然与城市环境建模中树木、植物、岩石、人群等对象高效散布与真实渲染的核心难题。文档共1个PDF文件&…

作者头像 李华
网站建设 2026/9/23 1:37:07

Flet flet-video 的 VideoSpacer 控件栏弹性间隔布局指南

前端跨平台桌面应用移动开发 【免费下载链接】flet Build realtime web, mobile and desktop apps in Python only. No frontend experience required. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/fl/flet 点击查看 免费下载 导读 VideoSpacer 是 Flet 官方视频扩…

作者头像 李华