AB
AiBoss
Tutorials

Make

Tutorials

用 Make 构建机器学习模型:从零到可运行的最小示例

面向零基础读者的机器学习入门教程:用 Python 与 scikit-learn 搭建一个可运行的最小模型,讲清数据集、特征与标签、训练与预测的完整流程,并说明过拟合、欠拟合等常见概念。

机器学习听起来比它实际的样子复杂得多。模型、训练、特征、数据集、预测、算法——这些词堆在一起,容易让人以为必须先读完数学系课程才能写出第一段机器学习代码。其实核心只有一句话:让计算机从例子中找出规律,再用这个规律去判断新的例子。你能认出猫,是因为见过很多猫;模型也一样。这篇教程会带你用 Python 和 scikit-learn 从零搭出一个真正能跑的模型,用它根据学习时长预测学生考试是否及格。整个过程不要求任何机器学习基础,只要你会写变量、列表、if/else 和函数调用就够了。如果你希望把模型训练、评估、调参的流程放到一个可视化环境里逐步操作,可以配合 Make 一起使用,把每一步的输入输出看得更清楚。

准备工作

在动手之前,先确认环境和工具都到位。下面这些是硬性前置条件,缺一个都会卡住。

  • Python 已安装。在终端或命令提示符里执行 python --version,能看到类似 Python 3.12.0 的输出即可。版本号不必和示例完全一致。
  • 一个文本编辑器或代码编辑器,比如 VS Code,用来写 .py 文件。
  • 终端或命令提示符,用来安装依赖和运行脚本。
  • 可用的网络连接,因为需要从 PyPI 安装 scikit-learn。

Python 基础方面,你只需要能熟练做这几件事:创建和使用变量、操作列表、写基本的 if/else、调用函数、读懂并运行一个 Python 程序、在终端里执行命令。不需要事先了解 scikit-learn、统计学或高等数学,文中出现的每个概念都会随用随讲。

先理解几个词

在写代码之前,把术语对齐,后面看代码会顺很多。

机器学习模型是一个从数据中学到了规律的程序。它的定义刻意保持简单:给它看足够多的例子,它就能发现输入和输出之间的关系。比如给它看若干学生的「学习时长」和「是否及格」,它可能自己总结出「学得越久越容易及格」——这条规则不是你写进代码的,是它从例子里学到的。

传统编程和机器学习的区别在于方向相反。传统编程是「数据 + 规则 → 答案」,规则由你手写,比如 if hours >= 4: print("Likely to pass")。机器学习是「例子 + 正确答案 → 模型」,规则由模型自己归纳;训练完成后再喂新数据,得到「新数据 + 已训练模型 → 预测」。

训练就是拿例子教模型的过程。你给算法一批数据,算法不断调整模型内部的状态,让它的预测越来越贴近这些例子给出的正确答案。

数据集就是数据的集合。本教程里用两个 Python 列表表示。

特征是用来做判断的线索,标签是想要模型预测的答案。在本例中,学习时长是特征,及格与否是标签。如果每个学生还有平时成绩、作业完成率、出勤率,那这些也都是特征,模型可以综合所有特征来预测同一个标签。

本例属于监督学习:训练时每个例子都带着已知的正确答案。与之相对的是无监督学习,数据里没有答案,模型自己去发现分组或结构。此外还有强化学习等类型,但监督学习的工作流最容易上手,适合作为起点。

操作步骤

第 1 步:创建项目目录

新建一个文件夹,命名为 machine-learning-model,在里面创建一个文件 model.py。最终结构如下:

machine-learning-model/
└── model.py

第 2 步:安装 scikit-learn

scikit-learn 提供了大量现成的机器学习算法和工具,省去自己从数学公式推导实现的过程。安装命令:

pip install scikit-learn

当然,你也可以手写一个简单的算法来理解背后的数学,但作为第一个能跑的模型,用库能让你把注意力放在工作流本身。

第 3 步:导入模型类

打开 model.py,写入:

from sklearn.tree import DecisionTreeClassifier

这行的含义是:从 scikit-learn 的 tree 模块中取出 DecisionTreeClassifier 这个类。导入之后就可以实例化模型:

model = DecisionTreeClassifier()

此时 model 还是一个空模型,什么都没学到,等着被喂训练数据。

第 4 步:构造数据集

先写特征列表:

hours = [1, 2, 3, 4, 5, 6, 7, 8]

再写标签列表,用 0 表示不及格、1 表示及格:

results = [0, 0, 0, 1, 1, 1, 1, 1]

对应关系是:学 1 小时不及格,学 2 小时不及格,学 3 小时不及格,学 4 小时及格,一直到学 8 小时及格。这就是模型要学习的例子。

第 5 步:把特征整理成二维结构

这里有个容易踩的细节。scikit-learn 期望特征是一个二维结构,而不是一维列表。原因是真实数据集往往有多个特征,比如:

学习时长出勤率平时成绩
280%65
595%82
798%91

每一行是一个样本,每一列是一个特征。即使当前只有一个特征,也要保持二维形式,所以用嵌套列表:

X = [
 [1],
 [2],
 [3],
 [4],
 [5],
 [6],
 [7],
 [8]
]

每个内层列表代表一个学生,[1] 表示该学生学了 1 小时。大写 X 是特征数据的常见命名约定。标签则用小写 y

y = [0, 0, 0, 1, 1, 1, 1, 1]

可以把 X 理解为「线索在这里」,y 理解为「正确答案在这里」。

第 6 步:划分训练集与测试集

不能把全部数据都拿去训练,否则无法判断模型在没见过的数据上表现如何。用 train_test_split 把数据切开:

from sklearn.model_selection import train_test_split

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

test_size=0.25 表示留出四分之一的数据做测试,其余用于训练。random_state 固定随机种子,保证每次运行得到相同的划分结果,便于复现。

第 7 步:训练模型

调用 fit 方法,把训练数据交给模型:

model.fit(X_train, y_train)

这一行就是「训练」的全部动作。模型会在这批例子里寻找输入与输出之间的规律。

第 8 步:做预测

训练完成后,用 predict 对新数据做判断:

prediction = model.predict([[5]])
print(prediction)

注意传入的仍然是二维结构 [[5]],表示「一个学了 5 小时的学生」。输出是数组形式,例如 [1]

第 9 步:把结果转成人能读的文字

直接输出 0 或 1 不够直观,加一层转换:

if prediction[0] == 1:
 print("Likely to pass")
else:
 print("Likely to fail")

第 10 步:评估模型表现

用测试集看看模型在没见过的数据上准不准:

accuracy = model.score(X_test, y_test)
print(accuracy)

score 返回的是准确率,取值在 0 到 1 之间。

一个完整示例

把上面的步骤合起来,model.py 的完整内容如下:

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split

# 特征:每个学生学习了多少小时
X = [
 [1],
 [2],
 [3],
 [4],
 [5],
 [6],
 [7],
 [8]
]

# 标签:0 = 不及格,1 = 及格
y = [0, 0, 0, 1, 1, 1, 1, 1]

# 划分训练集与测试集
X_train, X_test, y_train, y_test = train_test_split(
 X, y, test_size=0.25, random_state=42
)

# 创建并训练模型
model = DecisionTreeClassifier()
model.fit(X_train, y_train)

# 在测试集上评估
accuracy = model.score(X_test, y_test)
print("Accuracy:", accuracy)

# 对新数据做预测
prediction = model.predict([[5]])

if prediction[0] == 1:
 print("Likely to pass")
else:
 print("Likely to fail")

在终端里进入项目目录,运行:

python model.py

你会看到准确率和一个预测结果。到这里,一个完整的监督学习流程就跑通了:构造数据、划分数据、创建模型、训练、评估、预测。

模型内部到底发生了什么

本例用的是决策树分类器。决策树通过一连串关于数据的问题来做判断。在这个极简例子里,模型可能学到的规律近似于「学习时长是否达到某个阈值」,达到就判及格,没达到就判不及格。真实的决策树会复杂得多,可能包含多层嵌套判断,但基本思路就是这样。

所谓「学习」,指的是算法在训练过程中调整模型内部的状态,使得预测结果尽可能贴近训练样本给出的正确答案。模型内部可调整的量称为参数,由训练过程自动确定;而像树的深度、划分比例这类需要你在训练前设定的量称为超参数,它们不通过训练得到,而是由你指定或通过搜索挑选。

为什么要分训练集和测试集

如果只用训练数据评估,模型可能只是把训练样本「背」了下来,在新数据上表现很差,这叫过拟合。反过来,模型过于简单、连训练数据里的规律都没抓住,训练和测试表现都不好,这叫欠拟合。留出一部分数据专门做测试,就是为了观察模型在没见过的样本上的真实水平。

扩展到多个特征

真实场景里,单一特征往往不够。给每个学生补上出勤率和平时成绩,特征矩阵就变成:

X = [
 [2, 80, 65],
 [5, 95, 82],
 [7, 98, 91],
 [1, 60, 50],
 [6, 90, 78],
 [3, 70, 60],
 [8, 99, 95],
 [4, 85, 70]
]

预测时也要按同样的列顺序传入:

prediction = model.predict([[5, 95, 82]])

当特征数量达到几十上百个时,代码结构不变,只是每个内层列表更长。真正需要额外处理的是特征缩放、缺失值填充、类别特征编码等问题,这些属于后续要学的内容。

回归与分类的区别

本例预测的是「及格 / 不及格」这种离散类别,属于分类任务。如果预测的是连续数值,比如具体考多少分,那就是回归任务。回归的代码结构几乎一样,只是把分类器换成回归器,评估指标也从准确率换成误差类指标。

注意事项

  • 准确率要谨慎解读。本教程的数据集只有 8 条样本,测试集更小,准确率数字波动很大,不能当作模型真实能力的证据。样本量越大,评估结果才越有参考价值。
  • 这个数据集不是真实数据。它是为了教学而人工构造的,规律过于干净。真实数据通常有噪声、缺失值和异常点,需要额外的清洗步骤。
  • 特征必须是二维结构。把一维列表直接传给 fitpredict 会报错,务必用嵌套列表。
  • 预测时的特征顺序必须与训练时一致。训练用「时长、出勤、成绩」的顺序,预测时也要按这个顺序传,否则结果没有意义。
  • 固定随机种子便于复现。不设置 random_state 时,每次划分结果不同,评估数字也会变化。
  • 版本与依赖信息以官网当前说明为准。scikit-learn 的接口、默认参数和可用算法会随版本变化,安装前建议确认当前版本的要求。

跑通这个最小示例之后,下一步可以学的内容包括:用真实数据集替换手工构造的数据、处理缺失值与类别特征、用交叉验证代替单次划分、以及理解更多算法之间的取舍。真正重要的不是记住某一行代码,而是建立起「数据 → 划分 → 训练 → 评估 → 预测」这条工作流的心理模型,之后换任何算法、任何数据集,骨架都是它。