什么是机器学习:从数据中找规律 本节摘要:机器学习(Machine Learning)不是写规则,而是让计算机从数据里自己找规律。你想做一个垃圾邮件过滤器,传统做法是写几百条「如果包含『免费领奖』就标为垃圾」的规则,然后垃圾邮件发送者换个措辞,规则就失效了。机器学习把这件事反过来:你给计算机几千封已标注「垃圾/非垃圾」的邮件,让它自己悟出区分两者的规律,而且能发现你根本想不到的模式;敌人改策略,你只需用新数据重新训练,不用改代码。本节将吃透这一定式转换:监督/无监督/强化三大范式、分类与回归之别、ML 工作流与训练/验证/测试三划分、过拟合与欠拟合、偏差方差权衡,以及「什么时候不该用机器学习」。
本节摘要:机器学习(Machine Learning)不是写规则,而是让计算机从数据里自己找规律。你想做一个垃圾邮件过滤器,传统做法是写几百条「如果包含『免费领奖』就标为垃圾」的规则,然后垃圾邮件发送者换个措辞,规则就失效了。机器学习把这件事反过来:你给计算机几千封已标注「垃圾/非垃圾」的邮件,让它自己悟出区分两者的规律,而且能发现你根本想不到的模式;敌人改策略,你只需用新数据重新训练,不用改代码。本节将吃透这一定式转换:监督/无监督/强化三大范式、分类与回归之别、ML 工作流与训练/验证/测试三划分、过拟合与欠拟合、偏差方差权衡,以及「什么时候不该用机器学习」。最后从零手写一个最近质心分类器(Nearest Centroid),与随机基线对比,把「学习—预测—评估」三段式刻进肌肉记忆。
阅读完本节,你应当能够:
你想做一个垃圾邮件过滤器。传统做法:坐下来写几百条规则。「邮件里有『FREE MONEY』就标为垃圾。感叹号超过 3 个就标为垃圾。」你花了几周写规则。然后垃圾邮件发送者换了措辞,你的规则失效。你继续写规则。循环永无止境。
机器学习翻转了这件事。你不再写规则,而是给计算机几千封带标签的邮件(「垃圾」或「非垃圾」),让它自己琢磨出规则。计算机会发现你从没想到过的模式。当发送者改策略时,你用新数据重新训练,而不是重写代码。
从「编程规则」到「从数据学习」的这次转向,就是机器学习的核心。每一个推荐引擎、语音助手、自动驾驶汽车、语言模型,都是这么运作的。
传统编程和机器学习,是朝相反方向解决问题的。
传统编程:你写规则,程序套用到数据上产出输出。
机器学习:你提供数据和期望输出,算法去发现规则。
训练得到的「模型」本身就是规则,以数字(权重、参数)的形式编码。它从见过的例子里泛化,去预测从未见过的数据。
监督学习:你有输入-输出对,模型学习从输入映射到输出。
无监督学习:你只有输入,没有标签。模型自己找结构。
强化学习:一个智能体(Agent)在环境中采取动作,得到奖励或惩罚。它学习一种策略(Policy)来最大化总奖励。
实践中你要构建的大多数系统用的是监督学习。无监督学习常用于预处理和探索。强化学习驱动游戏 AI、机器人,以及语言模型的 RLHF。
上面三类很干净,但真实世界的 ML 常常模糊边界。
半监督学习(Semi-supervised Learning) 用少量标注数据加大量未标注数据。你可能有 100 张带标签的医学影像和 10 万张没标签的。技术包括:
自监督学习(Self-supervised Learning) 从数据本身制造监督信号,完全不需要人工标注。模型从数据结构里自己造预测任务。
它们并非独立于三大类,而是融合监督与无监督思想的策略。自监督学习技术上算监督(模型在预测某物),但标签是自动生成的,不来自人。
这是两大监督学习任务。
| 维度 | 分类 Classification | 回归 Regression |
|---|---|---|
| 输出 | 离散类别 | 连续数值 |
| 例子 | 「这封邮件是垃圾吗?」 | 「这房子会卖多少钱?」 |
| 输出空间 | {猫, 狗, 鸟} | 任意实数 |
| 损失函数 | 交叉熵、准确率 | 均方误差、MAE |
| 决策形态 | 类之间的边界 | 一条拟合数据的曲线 |
分类回答「属于哪一类」,回归回答「是多少」。
有些问题两种框架都行。预测股票涨跌是分类,预测精确价格是回归。
每个机器学习项目都走同一条流水线,不分算法。
收集数据:采集原始数据。数据越多几乎总是越好,但质量比数量更重要。
清洗与探索:处理缺失值、去重、可视化分布、发现异常。这一步常占总项目时间的 60~80%。
特征工程:把原始数据转成模型能用的特征。日期转成星期几,数值列归一化,类别变量编码。好特征比花哨算法更重要。
划分数据:切成训练、验证、测试三份。模型在训练数据上学习,在验证数据上调超参数,最后在测试数据上汇报成绩。
训练模型:把训练数据喂给算法,算法调整内部参数以最小化某个损失函数。
评估:在验证/测试数据上衡量表现。不达标就回去换特征、换算法、调超参数。
部署:把模型推上生产,让它对新数据做预测。
监控:长期跟踪表现。数据分布会变(数据漂移 Data Drift),模型会退化。性能一掉就重训。
这是初学者最容易搞错的概念。你必须用模型训练时没见过的数据来评估它,否则你衡量的是「背诵」而不是「学习」。
| 划分 | 用途 | 何时用 | 典型占比 |
|---|---|---|---|
| 训练集 | 模型从这里学习 | 训练期间 | 60~80% |
| 验证集 | 调超参数、比较模型 | 每次训练之后 | 10~20% |
| 测试集 | 最终无偏性能估计 | 只用一次,在最后 | 10~20% |
测试集是神圣的。你只看它一次。如果你不停根据测试成绩改模型,你实际上就是在测试集上训练,报出来的数字毫无意义。
数据集小时用 k 折交叉验证(k-fold Cross-validation):把数据切成 k 份,在 k-1 份上训练,在剩下一份上验证,轮转求平均。
欠拟合:模型太简单,捕捉不到数据里的规律。一条直线硬去拟合弯曲的关系。训练误差高,测试误差也高。
过拟合:模型太复杂,把训练数据连同噪声一起背下来。一条扭来扭去的曲线穿过每个训练点,在新数据上却崩了。训练误差低,测试误差高。
恰好拟合:模型捕捉到真实规律,没有背噪声。训练误差和测试误差都低得合理。
过拟合的迹象:
过拟合的对策:
欠拟合的对策:
这是过拟合和欠拟合背后的数学框架。
偏差(Bias):来自模型错误假设的误差。当真实关系非线性时,线性模型偏差高。高偏差导致欠拟合。
方差(Variance):来自模型对训练数据微小波动的敏感度。高方差的模型在不同数据子集上训练会给出差异很大的预测。高方差导致过拟合。
| 模型复杂度 | 偏差 | 方差 | 结果 |
|---|---|---|---|
| 过低(用线性模型拟合曲线数据) | 高 | 低 | 欠拟合 |
| 恰好 | 中 | 中 | 泛化良好 |
| 过高(10 个点用 20 次多项式拟合) | 低 | 高 | 过拟合 |
总误差 = 偏差² + 方差 + 不可约噪声
不可约噪声(数据本身的随机性)你降不了。你要找的是偏差² + 方差最小的那个甜点。
没有哪个算法在所有问题上都是最好的。在一个问题类上表现好的算法,会在另一类上表现差。所以数据科学家会试多种算法再比较。
实践中,选择取决于:
ML 很强大,但不总是对的工具。伸手用模型之前,先问问自己到底需不需要。
不要用 ML 的情况:
用这个决策流程图:
code/ml_intro.py 从零实现了一个最近质心分类器——最简单的 ML 算法。它演示核心思想:从数据学习,然后对新数据预测。
最近质心分类器算出训练数据里每个类别的中心(均值)。预测时,把每个新点分到离它最近的那个中心所属的类。
class NearestCentroid: def fit(self, X, y): self.classes = np.unique(y) self.centroids = np.array([ X[y == c].mean(axis=0) for c in self.classes ]) def predict(self, X): distances = np.array([ np.sqrt(((X - c) ** 2).sum(axis=1)) for c in self.centroids ]) return self.classes[distances.argmin(axis=0)]
这就是整个算法。fit 算两个均值,predict 算距离。没有梯度下降、没有迭代、没有超参数。
生成一个两类略有重叠的二维分类数据集。质心分类器在两个类中心之间画出一条线性决策边界。
rng = np.random.RandomState(42) X_class0 = rng.randn(100, 2) + np.array([1.0, 1.0]) X_class1 = rng.randn(100, 2) + np.array([-1.0, -1.0]) X = np.vstack([X_class0, X_class1]) y = np.array([0] * 100 + [1] * 100)
每个 ML 模型都该和一个平凡基线比。这里基线随机猜一个类。如果你的 ML 模型连随机猜测都打不过,那就是哪里出问题了。
baseline_preds = rng.choice([0, 1], size=len(y_test)) baseline_acc = np.mean(baseline_preds == y_test)
在这份干净数据上,质心分类器应该能拿到约 90% 以上的准确率,随机基线约 50%。
最近质心分类器简单到可笑。它没有超参数、没有迭代、没有梯度下降。但它抓住了 ML 的根本范式:
从逻辑回归到 Transformer,每个 ML 算法都遵循这三步。表示会变复杂,工作流不变。
最近质心分类器假设每个类是一个团块,画出线性决策边界。它在以下情况失效:
这些局限正是后续每个算法的动机。k 近邻处理多个簇,决策树处理非线性边界,特征缩放修复尺度问题。每一节都建立在前一节的局限之上。
scikit-learn 提供 NearestCentroid 和合成数据生成器:
from sklearn.neighbors import NearestCentroid from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split X, y = make_classification( n_samples=500, n_features=2, n_redundant=0, n_clusters_per_class=1, random_state=42 ) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3) clf = NearestCentroid() clf.fit(X_train, y_train) print(f"Accuracy: {clf.score(X_test, y_test):.3f}")
| 维度 | 手写实现 | scikit-learn |
|---|---|---|
| 代码量 | 十几行,用于教学 | 一行 fit/predict,工业级 |
| 依赖 | 仅 NumPy | 整套 sklearn 生态,可与流水线、交叉验证无缝拼接 |
| 适用场景 | 理解「学习—预测—评估」范式 | 真实项目快速试模型 |
本节产出 outputs/prompt-ml-problem-framer.md——一个把模糊业务问题转成具体 ML 任务的提示词。给它一个问题描述(「我们想降低流失率」或「预测下季度需求」),它会识别学习类型、定义预测目标、列出候选特征、选成功指标、立基线,并标记数据泄漏、类别不平衡等坑。在任何 ML 项目开工前用它,避免「把错误的东西建得很好」。
下一节,我们正式进入第一个监督学习算法——线性回归,从最小二乘到梯度下降,把「从数据学规律」落到一条最优拟合直线上。