☰
鸢尾花线性回归:sklearn实现回归模型训练与评估
2026/10/19 2:19:15 网站建设 项目流程

简介:鸢尾花数据集是机器学习入门最经典的多元分类数据之一,由花萼长度、花萼宽度、花瓣长度、花瓣宽度四个属性构成,用来区分Setosa、Versicolour和Virginica三个鸢尾花品种。这份资源面向正在学习Python机器学习与基础统计建模的初学者,通过线性回归方式对特征进行拟合,演示从数据读取、模型训练到分类预测的完整流程,能帮助读者理解特征与标签之间的关系,以及回归模型在判别任务中的实际用法。压缩包只有2KB,共包含1个数据文件和1个Python脚本,结构非常精简,适合快速上手、对照学习代码写法,也可作为课堂演示或自主练习的小型案例。目前已有11537人学习下载,对刚接触机器学习的同学来说,省去了搜寻和整理数据集的麻烦,拿到后即可运行脚本复现实验。通过该资源还能学习基础的数据预处理、模型拟合和评价思路,并在现成代码基础上调整参数或更换算法,进一步巩固机器学习基础。

1. 鸢尾花线性回归:一个被误当分类的入门项目

第一次看到“鸢尾花线性回归”这个标题时,很多人的第一反应是“鸢尾花不是分类问题吗?用 KNN 或者逻辑回归才对”。这恰恰是这个项目最有意思的地方——它把那个所有教程都在用的经典分类数据集,硬生生做成了回归任务。你以为自己拿错了数据,其实没有,只是切入角度变了:把花瓣长度当特征,去回归预测花萼宽度,或者在四个特征之间互相回归。这个项目适合两类人:一类是刚入门机器学习、想搞懂数据到底怎么变成模型的初学者;另一类是已经跑过分类教程、想换个视角看看同一份数据能挖掘出什么信息的开发者。它会带你走完一条从加载数据到训练模型再到可视化评估的完整链路,而且全程只用 Python 和 sklearn,代码量不到 60 行。

2. 项目定位与技术选型:为什么鸢尾花常被拿来做线性回归

2.1 鸢尾花数据集到底长什么样

鸢尾花数据集诞生于 1936 年,统计学界的老古董了,但到今天依然是机器学习入门的第一站。它内置在 sklearn 的 datasets 模块里,不需要单独下载数据文件。数据一共 150 条样本,每条样本有 4 个数值型特征(花萼长度、花萼宽度、花瓣长度、花瓣宽度),标签是 3 种鸢尾花(Setosa、Versicolour、Virginica),每种 50 条。

# 在 Python 中快速查看数据集基本信息 from sklearn.datasets import load_iris iris = load_iris() print(iris.data.shape) # (150, 4) print(iris.feature_names) # ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)'] print(iris.target_names) # ['setosa' 'versicolor' 'virginica']

输出结果里(150, 4)告诉你这是 150 行、4 列的数据。特征名分别是花萼长度、花萼宽度、花瓣长度、花瓣宽度,单位是厘米。target_names 是三种鸢尾花的品种名。这里有一个容易被忽略的细节:iris.data是二维数组,iris.target是一维数组,它们按行一一对应——第 i 行特征就对应第 i 个标签。

数据集的数值范围差异不算大,都在 0.1 到 7.9 之间,所以做线性回归时通常不需要做标准化。这一点和做 SVM 或 KNN 不一样,那些算法对特征尺度敏感,而线性回归的系数会天然适应特征的尺度。

2.2 技术栈:sklearn + pandas + matplotlib

这个项目选型非常克制,核心就三个库,各有各的活。

  • scikit-learn:负责加载数据、划分训练集测试集、提供线性回归模型LinearRegression、计算评估指标。项目最主要的逻辑都在这个库里。
  • pandas:把数据转换成 DataFrame 去做探索性分析。虽然直接用 numpy 数组也能跑,但项目里一般会转成 DataFrame,这样列名清晰、画图时也好指定 x 轴和 y 轴。
  • matplotlib:画散点图和回归线。机器学习项目里可视化是刚需,没有图你很难直观判断回归效果到底怎么样。

看一个典型的加载过程:

import pandas as pd from sklearn.datasets import load_iris iris = load_iris() df = pd.DataFrame(iris.data, columns=iris.feature_names) df['species'] = iris.target_names[iris.target] print(df.head())

转成 DataFrame 之后,df.head()会输出前 5 行数据,列名就是前面打印的四个特征名,外加品种列。如果你用df.describe()还能看到每个特征的均值、标准差、最小值、最大值。pandas 在这条链路里的角色是数据探索和可视化准备,真正建模时喂给模型的仍然是 numpy 数组。

2.3 线性回归和逻辑回归的分水岭

很多初学者在这个项目上会问一个问题:明明目标是预测花的品种,为什么要用线性回归?这个问题的本质是混淆了两个名字里都有“回归”的算法。线性回归(LinearRegression)做的是拟合连续数值,比如根据花瓣长度预测花萼宽度,预测结果是一个浮点数,比如 3.26 厘米。逻辑回归(LogisticRegression)虽然名字带回归,但做的是分类,输出的是一个概率值。

鸢尾花原始数据集是一个三分类任务,目标是预测花的品种,所以如果你拿品种当 y,那确实应该用逻辑回归,而不是线性回归。但当这个项目把回归目标改成了“用花瓣长度预测花萼宽度”时,问题就变成了连续值预测,线性回归就是正确选择。

这里有个判断技巧:看你的 y 是连续数值还是离散类别。连续数值(身高、房价、温度)用线性回归;离散类别(是/否、品种 A/B/C)用逻辑回归或其他分类算法。把这个分清了,你就不会在跑这个项目时怀疑自己拿错了代码。

3. 从数据到模型的完整链路:数据集加载、划分与回归拟合

3.1 加载鸢尾花数据集

项目的第一步永远是加载数据。用 sklearn 内置的数据集有一个好处:数据已经清洗好了,没有缺失值、没有乱码,你只需要调用load_iris()就能拿到一份可以直接用于训练的干净数据。

from sklearn.datasets import load_iris # 加载鸢尾花数据集 iris = load_iris() # 提取特征和标签 X = iris.data # 150x4 的特征矩阵 y = iris.target # 150 个标签值 # 打印数据结构信息 print("特征矩阵形状:", X.shape) print("标签数组形状:", y.shape)

X是特征矩阵,形状为(150, 4),每一行是一朵鸢尾花的四个测量值;y是目标变量,也是一维数组。在回归场景里,这个y可以是品种编码吗?不建议。因为品种是离散的类别,用连续回归去拟合一个 0/1/2 的编码,模型会认为 1 和 2 之间的距离是有意义的,实际情况并非如此。这个项目更合理的做法是:从四个特征里选一个当目标,其余当特征;或者直接只取两个特征做一元回归,方便在二维平面上画图。

3.2 数据探索与特征选择

数据加载完,先别急着训练。用pd.DataFrame把数据转换成表格,然后用一行df.describe()查看分布情况。做这一步不是为了走形式,而是为了选对特征做回归。

import pandas as pd from sklearn.datasets import load_iris iris = load_iris() df = pd.DataFrame(iris.data, columns=iris.feature_names) # 查看每个特征的分布情况 print(df.describe()) # 查看特征之间的相关性 print(df.corr())

df.describe()给出每个特征的均值、标准差、最小最大值,df.corr()给出特征之间的相关系数矩阵。鸢尾花数据集里,花瓣长度和花瓣宽度的相关性极高,相关系数通常在 0.94 左右;花萼长度和花瓣长度的相关性也接近 0.87。相关性强意味着回归效果好,散点图上是明显的线性趋势。

所以常见的做法是选花瓣长度作为 X,花瓣宽度作为 y,因为这两个特征线性关系最明显,拟合出来的回归线看起来最“像样”。如果你的目标是用多个特征做多元回归,那可以留下花萼长度、花萼宽度、花瓣宽度来共同预测花瓣长度。特征选择决定了模型效果的天花板,这一步值得花几分钟看一眼相关性矩阵再做决定。

3.3 训练集测试集划分与模型训练

数据准备好了,接下来要划分训练集和测试集。这个操作是机器学习流程里绝对不能省的环节:你用训练集去拟合模型,用测试集去评估模型在未见数据上的表现。如果把全部数据都拿去训练再拿去评估,得到的指标会虚高,因为模型已经“背下”了那 150 条数据。

from sklearn.model_selection import train_test_split # X 是花瓣长度,y 是花萼宽度,reshape(-1, 1) 把一维数组变成列向量 X = iris.data[:, 2].reshape(-1, 1) # 取花瓣长度特征 y = iris.data[:, 1] # 取花萼宽度作为回归目标 # 划分训练集和测试集,80% 训练,20% 测试 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) print("训练集样本数:", X_train.shape[0]) print("测试集样本数:", X_test.shape[0])

reshape(-1, 1)是把一维数组转成二维列向量的标准写法。sklearn 的LinearRegression要求特征是二维的,如果你直接传一维数组会报错。test_size=0.2表示取 20% 的数据作为测试集,random_state=42是随机种子,固定之后每次跑代码,划分结果都一样。这个细节很重要:不固定随机种子,你每次跑代码都会得到不同的划分,模型的评估结果也会跟着波动,你就没法稳定复现实验了。

然后就是训练模型,核心代码只有三行:

from sklearn.linear_model import LinearRegression # 创建线性回归模型 model = LinearRegression() # 用训练数据拟合模型 model.fit(X_train, y_train) # 查看模型系数和截距 print("系数(斜率):", model.coef_) print("截距:", model.intercept_)

fit方法会计算出一条直线y = w*x + b,其中w就是斜率,b是截距。打印出来的系数如果是负数,说明特征与目标负相关;如果是正数,就是正相关。以花瓣长度预测花萼宽度为例,斜率大约在 0.4 左右,意味着花瓣每增长 1 厘米,花萼宽度大约增加 0.4 厘米。

3.4 模型评估:MSE、R² 与可视化

模型训练完,关键一步是评估效果好不好。这里用三个手段:均方误差(MSE)、R² 分数、散点图加回归线可视化。

from sklearn.metrics import mean_squared_error, r2_score # 在测试集上做预测 y_pred = model.predict(X_test) # 计算评估指标 mse = mean_squared_error(y_test, y_pred) r2 = r2_score(y_test, y_pred) print("均方误差 (MSE):", mse) print("R² 分数:", r2)

MSE 是预测值与真实值差距的平方的平均值,越小越好。R² 的取值范围通常在 0 到 1 之间,越接近 1 说明模型解释了越多的数据变化。用花瓣长度预测花萼宽度时,R² 大约在 0.35 到 0.45 之间——听起来不高,但这在真实数据里其实是正常的。如果换成用花瓣长度预测花瓣宽度,R² 能上到 0.93,效果会明显好得多。很多初学者看到 R² = 0.4 就觉得项目失败了,其实不是,这取决于你预测的目标本身和特征的相关性有多强。

可视化这一步用 matplotlib 就能搞定。

import matplotlib.pyplot as plt # 绘制测试集样本点 plt.scatter(X_test, y_test, color='blue', label='真实数据') # 绘制回归线(按特征值从小到大排序,保证线条连续) import numpy as np X_line = np.linspace(X_test.min(), X_test.max(), 100).reshape(-1, 1) y_line = model.predict(X_line) plt.plot(X_line, y_line, color='red', label='回归线') plt.xlabel('花瓣长度 (cm)') plt.ylabel('花萼宽度 (cm)') plt.title('鸢尾花:花瓣长度 vs 花萼宽度 线性回归') plt.legend() plt.show()

散点图上的每个蓝点是一朵真实的鸢尾花,红线是学到的回归直线。这条线不一定穿过所有点,但它的位置是让所有点到这条线的垂直距离之和最小的解——这就是“最小二乘法”的直观含义。看到这张图,你对回归拟合的理解会比背十遍公式都深刻。

4. 核心模块拆解:训练脚本中每一段代码的作用

4.1 完整代码结构与逐段讲解

把前几章的代码拼起来,就是一个完整的 60 行不到的训练脚本。放进单个文件iris_regression.py就能直接运行。脚本结构分为六段:导入库、加载数据、特征选择、划分数据集、训练模型、评估与可视化。

# iris_regression.py # 依赖:numpy, pandas, matplotlib, scikit-learn import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, r2_score # 1. 加载数据 iris = load_iris() df = pd.DataFrame(iris.data, columns=iris.feature_names) # 2. 特征选择:用花瓣长度预测花瓣宽度(相关性高达 0.96) X = df[['petal length (cm)']].values # 返回 (150, 1) 的二维数组 y = df['petal width (cm)'].values # 返回 (150,) 的一维数组 # 3. 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) # 4. 创建并训练线性回归模型 model = LinearRegression() model.fit(X_train, y_train) # 5. 在测试集上预测 y_pred = model.predict(X_test) # 6. 评估与输出 mse = mean_squared_error(y_test, y_pred) r2 = r2_score(y_test, y_pred) print(f"系数(斜率): {model.coef_[0]:.4f}") print(f"截距: {model.intercept_:.4f}") print(f"均方误差 (MSE): {mse:.6f}") print(f"R² 分数: {r2:.4f}") # 7. 可视化 plt.scatter(X_test, y_test, color='blue', alpha=0.7, label='真实数据') x_line = np.linspace(X_test.min(), X_test.max(), 100).reshape(-1, 1) y_line = model.predict(x_line) plt.plot(x_line, y_line, color='red', linewidth=2, label='回归线') plt.xlabel('花瓣长度 (cm)') plt.ylabel('花瓣宽度 (cm)') plt.title('鸢尾花数据集线性回归结果') plt.legend() plt.grid(alpha=0.3) plt.show()

这个脚本里有两处容易翻车的地方。第一处是df[['petal length (cm)']].values用了双层方括号,取出的是 DataFrame,转成数组后是(150, 1)的二维结构;如果改成df['petal length (cm)'].values,取出的是 Series,转成数组后是(150,)的一维结构。LinearRegression在fit时接受一维的 y,但不接受一维的 X,所以 X 必须保持二维。第二处是可视化部分的np.linspace,它的作用是在最小值和最大值之间均匀生成 100 个点,这样回归线画出来是一条平滑直线,而不是连成一团的锯齿线。

4.2 参数说明与可调点

脚本里有几个参数值得专门列出来讲清楚,它们各自影响着模型的行为和最终效果。

model = LinearRegression(fit_intercept=True) # 默认就是 True

fit_intercept控制模型是否计算截距 b。如果设为 False,模型会强制直线过原点(0, 0),也就是说当花瓣长度为 0 时花萼宽度也为 0。实际情况下这个假设通常不成立,所以这个参数一般保持默认。

X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42 )

test_size控制测试集比例,常见取值有 0.2、0.3,数据量小的时候也有用 0.1 的。random_state是随机种子,换成任何整数都行,但同一个项目里要固定住,否则每次跑的结果都不一样,没法对比实验。

model.coef_ # 回归系数 model.intercept_ # 截距

这两个属性是训练完之后的模型参数。在fit之前访问它们会得到None或直接报错,因为它们是在训练过程中被计算出来的。训练完成后,它们就是这条回归线的分子分母:y = coef_ * x + intercept_。你可以拿这个公式手动算一个预测结果,跟model.predict的输出对比,应该完全一致,这也是理解线性回归内部机制的好方法。

4.3 常见报错与处理

跑代码时最容易碰到的报错我来盘一盘,基本都是初学者必踩的:

ValueError: Expected 2D array, got 1D array instead
这是最经典的报错,几乎每个跑 sklearn 的新手都会遇到一次。原因是你传给fit的 X 是一维数组,而 sklearn 要求 X 是二维矩阵。解决方法是把X = df['petal length (cm)'].values改成X = df[['petal length (cm)']].values,或者加一句X = X.reshape(-1, 1)。

AttributeError: 'LinearRegression' object has no attribute 'coef_'
这出现在你还没训练模型就直接访问coef_的时候。coef_是在fit之后才生成的属性,不是初始化时就有的。训练之前检查一下是否调用了model.fit(X_train, y_train)。

matplotlib 画的图没有显示出来
脚本最后单独跑的时候,plt.show()会阻塞进程等待关图窗口。如果在 Jupyter Notebook 里,你需要先执行%matplotlib inline,否则图形会弹到独立窗口甚至不显示。如果在无图形界面的服务器上跑,把plt.show()改成plt.savefig('result.png'),图形会保存到本地文件。

5. 避坑指南:线性回归做鸢尾花的四个典型坑

5.1 坑一:把三种鸢尾花的品种标签当作回归目标

现象:用iris.target(0、1、2 三个值)作为 y,跑线性回归,打印出来的 R² 还挺高,但把预测结果拿去和实际品种对比时完全对不上。

原因:iris.target是离散类别编码,0 代表 Setosa,1 代表 Versicolour,2 代表 Virginica。线性回归拟合的是连续数值,它会把 1.5 这种不存在的中间值当成合理输出。分类问题用回归模型,方向就错了。

解决:确认你的任务是“预测连续数值”还是“预测类别”。预测连续值用LinearRegression,预测种类请换LogisticRegression或KNeighborsClassifier。跑这个项目时,回归目标应该从四个特征里选一列,而不是从target里拿。

5.2 坑二:特征与目标相关性太低,导致 R² 几乎为 0

现象:拿花萼宽度去预测花萼长度,训练完发现 R² 只有 0.08 左右,散点图上的点糊成一片,没有明显的线性趋势,开始怀疑代码写错了。

原因:线性回归只能捕捉线性关系。花萼宽度和花萼长度在鸢尾花数据集里相关性确实很低,相关系数只有 0.1 上下。两个变量之间本来就没有线性关系,回归模型再有本事也白搭。

解决:先做数据探索,用df.corr()查看特征之间的相关系数,选择相关性高的特征对来做回归。鸢尾花数据集里花瓣长度和花瓣宽度相关性高达 0.96,用这一对特征效果最好。如果你跑出来的模型效果奇差,先看特征选对没有,再怀疑代码。

5.3 坑三:随机种子不固定,每次跑出来的模型和指标都不一样

现象:同一份数据、同一个脚本,今天跑 R² 是 0.93,明天跑变成了 0.89,甚至斜率都不一样。想记录实验结果,却发现前后对不上。

原因:train_test_split默认是随机切分。不固定随机种子,每次划分的训练集和测试集都不一样,模型在不同数据子集上训练自然得到不同参数,评估指标也会上下波动。

解决:划分数据时固定random_state,比如random_state=42。固定之后,每次运行脚本都会得到完全一样的划分、一样的训练结果、一样的评估指标,实验可复现。这是机器学习工程里的基本素养,不是可选项。

5.4 坑四:把全部数据拿去训练,然后用同一批数据评估

现象:X_train = X,y_train = y,直接fit全部数据,再在同样的数据上predict,得到的 R² 高得惊人,但换到真实场景一用就露馅。

原因:模型已经“见过”全部数据,相当于考试前把答案背下来,然后试卷出的还是原题,分数当然好看。这种评估方式衡量的是模型的记忆能力,不是泛化能力。

解决:坚持划分训练集和测试集。标准做法是留出 20% 到 30% 的数据不参与训练,只用来评估。如果数据量紧张,可以改用交叉验证(cross_val_score),把数据切成几折轮流做训练集和验证集,这是小数据集上更稳妥的评估方式。

6. 二次开发:把鸢尾花回归改成你自己的项目

6.1 换数据集:从鸢尾花切换到波士顿房价

鸢尾花跑通之后,把这个脚本改到其他数据集上,只需要动两行代码。以波士顿房价数据为例,特征换成房价相关的 13 个指标之一,目标换成房价(MEDV),其他流程完全不动。

from sklearn.datasets import fetch_openml # 加载波士顿房价数据集(sklearn 1.2 之后不再内置,改用 openml 获取) boston = fetch_openml(name="boston", version=1, as_frame=True) df = boston.frame # 找一个和目标相关性高的特征 X = df[['LSTAT']].values # 低收入人口比例,与房价负相关 y = df['MEDV'].values # 房价中位数

fetch_openml需要联网下载数据,as_frame=True让它以 DataFrame 格式返回。换数据集之后,重点关注两件事:第一,形状对不对——X 必须是二维的,y 必须是一维的,和数据规模无关;第二,特征和目标的相关性高不高——先用df.corr()里的矩阵挑一条相关性最强的特征,避免换完数据后回归线变成一条平线。

6.2 加特征组合与多项式回归

鸢尾花的四个特征单独做回归,效果最好的也只有花瓣长对花瓣宽这一对。如果你想把多个特征一起喂进模型做多元回归,直接多加几列就行;如果想捕捉非线性关系,可以做多项式回归。这是同一个算法思路的两种延伸。

from sklearn.preprocessing import PolynomialFeatures from sklearn.pipeline import make_pipeline # 用多项式特征扩展现有特征,degree=2 会生成 x^2 和 x1*x2 这类组合 poly_model = make_pipeline( PolynomialFeatures(degree=2, include_bias=False), LinearRegression() ) # X_multi 是多个原始特征的组合 X_multi = iris.data[:, [2, 3]] # 花瓣长度 + 花瓣宽度 poly_model.fit(X_train, y_train)

PolynomialFeatures(degree=2)会把原来的一个特征x扩展成x, x^2等多个特征,让线性回归能拟合曲线。但要注意:多项式特征的维度会随着 degree 和原始特征数量迅速爆炸,鸢尾花数据量只有 150 条,degree 超过 3 就非常容易过拟合,训练集上 R² 极高、测试集上一塌糊涂。这是个经典教训——模型复杂度不是越高越好。

6.3 从线性回归到逻辑回归的分类改造

如果你最终想把鸢尾花项目改回分类任务——预测花的品种——那只需要把模型换掉,数据分割逻辑兼容。这个改造能让你同时掌握回归和分类两条技术路线。

from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score, confusion_matrix # 分类任务:特征用全部 4 列,目标用品种标签 X = iris.data y = iris.target X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) clf = LogisticRegression(max_iter=1000) clf.fit(X_train, y_train) y_pred = clf.predict(X_test) print("准确率:", accuracy_score(y_test, y_pred)) print("混淆矩阵: ", confusion_matrix(y_test, y_pred))

逻辑回归这里有个参数要专门说明:max_iter=1000。鸢尾花数据集特征不多,但默认的max_iter=100偶尔会触发收敛警告,把迭代次数调大到 1000 就稳定了。混淆矩阵是分类任务里比准确率更重要的评估手段,它告诉你三类花各自被预测对多少、错分到哪一类。改造完成后你会看到,同一个数据集,回归视角和分类视角的模型、评估指标、画图方式完全不同——这才是机器学习项目最值钱的体验。

从鸢尾花回归到分类的这次切换,让我养成一个习惯:拿到任何数据集,先问一句“目标变量是连续值还是离散值”,再决定算法方向。这个习惯帮我少走了很多弯路。希望这份拆解对你有用,下载代码后先从特征相关性和回归可视化开始跑,跑通了再动手改,你会看到数据在不同算法手里呈现出完全不同的面貌。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询