【实战解析】从零构建感知机:Python代码详解鸢尾花分类

张开发
2026/4/19 23:53:01 15 分钟阅读

分享文章

【实战解析】从零构建感知机:Python代码详解鸢尾花分类
1. 感知机与鸢尾花分类入门指南第一次接触机器学习的朋友可能会被感知机这个词吓到但其实它就像是我们大脑中的一个神经元简单却强大。想象一下你在教小朋友区分苹果和橙子刚开始他们可能会犯错但通过不断纠正苹果更红、橙子更圆最终就能准确区分。感知机的工作原理和这个例子惊人地相似。鸢尾花数据集是机器学习界的Hello World包含150朵鸢尾花的测量数据每朵花有四个特征花萼长度、花萼宽度、花瓣长度和花瓣宽度。我们要做的是教会计算机区分山鸢尾Iris-setosa和变色鸢尾Iris-versicolor这两个品种。有趣的是这两个品种的花瓣尺寸差异明显就像苹果和橙子的颜色区别一样直观。为什么选择感知机因为它是最简单的线性分类器之一特别适合这种线性可分的数据。就像用尺子可以在纸上画一条线分开两种不同颜色的点感知机也能在数据空间中找到一个超平面来区分不同类别的花朵。接下来我会带你用Python一步步实现这个过程保证即使没有数学背景也能理解。2. 环境准备与数据加载2.1 搭建Python工作环境我强烈推荐使用Anaconda来管理Python环境它能避免各种依赖冲突的噩梦。安装好后创建一个新环境conda create -n perceptron python3.8 conda activate perceptron然后安装必要的库pip install numpy pandas matplotlib scikit-learn如果你喜欢交互式编程像我一样Jupyter Notebook是绝佳选择。启动方式很简单jupyter notebook2.2 获取并检查鸢尾花数据鸢尾花数据集在机器学习领域如此经典以至于scikit-learn直接内置了它。但为了理解完整的数据处理流程我们先从原始CSV文件开始。你可以从UCI机器学习仓库下载iris.data文件。用pandas加载数据时我习惯先快速浏览一下import pandas as pd df pd.read_csv(iris.data, headerNone, encodingutf-8) print(df.tail())你会看到数据长这样0 1 2 3 4 145 6.7 3.0 5.2 2.3 Iris-virginica 146 6.3 2.5 5.0 1.9 Iris-virginica 147 6.5 3.0 5.2 2.0 Iris-virginica 148 6.2 3.4 5.4 2.3 Iris-virginica 149 5.9 3.0 5.1 1.8 Iris-virginica注意最后一列是花的品种前面四列分别是花萼和花瓣的尺寸。为了简化问题我们暂时只关注前两个品种。3. 数据预处理与可视化3.1 提取并转换标签机器学习模型不理解Iris-setosa这样的文本标签我们需要转换为数值。这里用-1表示山鸢尾1表示变色鸢尾import numpy as np # 提取前100个样本两个品种各50个 y df.iloc[0:100, 4].values y np.where(y Iris-setosa, -1, 1)为什么选择-1和1而不是0和1这与感知机的数学定义有关它使用符号函数sign function做预测输出自然就是正负1。3.2 特征选择与散点图我选择花萼长度和花瓣长度这两个特征因为它们能很好地区分两个品种# 提取第一和第三列特征 X df.iloc[0:100, [0, 2]].values让我们可视化这些数据import matplotlib.pyplot as plt plt.scatter(X[:50, 0], X[:50, 1], colorred, markero, labelsetosa) plt.scatter(X[50:100, 0], X[50:100, 1], colorblue, markerx, labelversicolor) plt.xlabel(sepal length [cm]) plt.ylabel(petal length [cm]) plt.legend(locupper left) plt.show()你会看到红点和蓝点几乎可以用一条直线分开——这就是线性可分的数据这种可视化是机器学习中至关重要的步骤我每次都会先画图因为再复杂的算法也比不上一张好图的洞察力。4. 实现感知机算法4.1 感知机类设计感知机的核心思想很简单如果分类错误就调整权重。下面是我们实现的Perceptron类class Perceptron: def __init__(self, eta0.01, n_iter50, random_state1): self.eta eta # 学习率 self.n_iter n_iter # 迭代次数 self.random_state random_state # 随机种子 def fit(self, X, y): # 初始化权重小随机数 rgen np.random.RandomState(self.random_state) self.w_ rgen.normal(loc0.0, scale0.01, size1 X.shape[1]) self.errors_ [] # 记录每轮错误数 for _ in range(self.n_iter): errors 0 for xi, target in zip(X, y): update self.eta * (target - self.predict(xi)) self.w_[1:] update * xi # 更新权重 self.w_[0] update # 更新偏置 errors int(update ! 0.0) self.errors_.append(errors) return self def net_input(self, X): 计算净输入 return np.dot(X, self.w_[1:]) self.w_[0] def predict(self, X): 返回预测类别 return np.where(self.net_input(X) 0.0, 1, -1)关键点说明eta是学习率控制每次调整的幅度。太小收敛慢太大可能震荡。w_存储权重第一个元素w_[0]是偏置项相当于截距。fit方法是核心实现了权重更新规则w η * (target - prediction) * x4.2 训练与收敛分析让我们训练模型并观察错误率变化ppn Perceptron(eta0.1, n_iter10) ppn.fit(X, y) plt.plot(range(1, len(ppn.errors_) 1), ppn.errors_, markero) plt.xlabel(Epochs) plt.ylabel(Number of misclassifications) plt.show()在我的测试中感知机在第6轮迭代后就实现了完美分类错误数为0。这种快速收敛正是线性可分数据的特性。如果错误率不降反升可能需要调小学习率。5. 决策边界可视化5.1 理解决策边界决策边界是分类器的分界线在二维情况下就是一条直线。为了画出它我们需要创建一个覆盖特征空间的网格对每个网格点进行预测用不同颜色显示预测结果from matplotlib.colors import ListedColormap def plot_decision_regions(X, y, classifier, resolution0.02): # 设置标记和颜色 markers (s, x, o, ^, v) colors (red, blue, lightgreen, gray, cyan) cmap ListedColormap(colors[:len(np.unique(y))]) # 计算决策边界 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, alpha0.3, cmapcmap) plt.xlim(xx1.min(), xx1.max()) plt.ylim(xx2.min(), xx2.max()) # 绘制样本点 for idx, cl in enumerate(np.unique(y)): plt.scatter(xX[y cl, 0], yX[y cl, 1], alpha0.8, ccolors[idx], markermarkers[idx], labelcl, edgecolorblack)5.2 可视化结果调用这个函数就能看到分类效果plot_decision_regions(X, y, classifierppn) plt.xlabel(sepal length [cm]) plt.ylabel(petal length [cm]) plt.legend(locupper left) plt.show()你会看到一条清晰的直线分开了红蓝两点这正是感知机学习到的决策边界。有趣的是这条线的位置取决于初始权重和训练顺序但最终都能完美分类。6. 感知机的局限与改进6.1 线性可分的限制感知机最大的局限是只能处理线性可分数据。我尝试加入第三个品种Iris-virginica发现无论如何调整参数都无法完美分类——因为这些点在特征空间中是交织在一起的。就像你无法用一根直线完美分开三种颜色的彩笔。6.2 学习率的影响学习率η是个关键参数。我做过实验η0.01需要约50轮才收敛η0.16轮收敛我们的选择η1.0权重剧烈震荡无法收敛建议的做法是从0.1开始尝试根据训练曲线调整。6.3 扩展到多类别虽然标准感知机是二分类器但可以通过一对多策略实现多分类训练N个感知机每个负责区分一个类别和其他所有类别。不过现代更常用的是直接支持多分类的算法如softmax回归。7. 完整代码与扩展建议把上述代码整合起来就得到了完整的鸢尾花分类解决方案。如果你想进一步探索尝试用全部四个特征训练比较不同特征组合的效果实现投票感知机Averaged Perceptron用scikit-learn的Perceptron类对比结果机器学习最有趣的部分就是实验——调整参数、观察变化、理解背后的原理。感知机虽然简单但它包含了所有神经网络的核心思想。

更多文章