机器学习基石课程精讲PPT全面解析
简介:《机器学习基石》是林軒田教授在Coursera平台主讲的经典入门课程,其配套PPT系统梳理了机器学习的核心理论与关键算法,涵盖从基础概念到实际应用的完整知识体系。内容包括监督、无监督与半监督学习的分类框架,线性回归与逻辑回归模型原理,决策树与随机森林的构建机制,支持向量机与核技巧的应用,正则化技术防止过拟合的方法,以及神经网络和深度学习的基础架构。同时讲解模型评估方法如交叉验证、优化算法如梯度下降,及超参数调优策略。本PPT为初学者构建扎实理论基础,助力掌握机器学习核心技能,是通往高级AI学习的重要起点。
机器学习的底层逻辑:从公式到实战的全链路穿透
在当今这个数据爆炸的时代,机器学习早已不再是实验室里的高冷理论,而是实实在在驱动着推荐系统、金融风控、医疗诊断和自动驾驶的核心引擎。但你有没有发现一个现象?——很多人学了好久“机器学习”,调参靠试,模型靠套,一旦遇到新问题就束手无策。
为什么?
因为他们只记住了“怎么做”,却没搞懂“为什么能做”。
今天我们就来一次彻底的 思维翻转 :不讲概念堆砌,不列算法清单,而是从最基础的数据流动开始,一步步拆解那些藏在代码背后的数学直觉、工程权衡与认知跃迁。准备好了吗?🚀
样本、特征与模型的本质关系
我们先抛开所有术语,回到最初的问题:
计算机怎么学会“看懂”世界?
答案是:它不会“理解”,但它会“拟合”。
就像小孩通过反复观察猫狗图片来建立印象一样,机器通过成千上万条 样本 (sample)去捕捉某种模式。
每条样本都由一组 特征 (feature)描述,比如一个人的年龄、收入、职业;而我们要预测的目标则是 标签 (label),比如是否会购买某产品。
于是整个建模过程变成了这样一个链条:
特征 → 模型函数 → 预测值 → 和真实值比对 → 计算误差 → 调整模型
这听起来像不像人在学习的过程?犯错 → 反思 → 改进。只不过机器用的是数学语言。
来看一段极简代码,揭示这个闭环的核心机制:
import numpy as np
# 假设我们想预测房价:y = 2 * x (比如面积乘以单价)
X = np.array([[1], [2], [3]]) # 特征:房屋面积(百平米)
y = np.array([2, 4, 6]) # 标签:实际价格(百万)
w = 2 # 初始猜测参数
y_pred = X * w # 模型前向输出
loss = np.mean((y - y_pred)**2) # 均方误差损失
就这么几行,已经包含了机器学习的所有关键要素!
X是输入空间中的点;w是我们要找的规律;y_pred是模型当前的认知;loss是它的“自我批评分数”。
如果 loss == 0 ,说明模型完全掌握了真相;否则就得继续调整 w —— 这就是所谓的“训练”。
💡 洞察时刻 :
真正决定模型能力的,从来不是用了多复杂的神经网络,而是你能否让这个“感知-反馈”循环高效运转起来。一切优化手段,都是为了加速收敛、避免误入歧途。
线性回归不只是直线拟合
说到线性回归,大多数人的第一反应是:“哦,画一条最佳拟合直线嘛。”
但这太肤浅了。线性回归的背后,其实是一场关于 概率假设 与 最优估计 的深刻对话。
最小二乘法从哪来的?
假设我们观测到的数据存在噪声,即:
$$
y = \mathbf{w}^\top \mathbf{x} + b + \epsilon,\quad \epsilon \sim \mathcal{N}(0, \sigma^2)
$$
也就是说,真实输出是在理想线性关系上加了一个正态分布的扰动项。根据最大似然估计(MLE),要使得观测数据出现的概率最大,等价于最小化负对数似然:
$$
\log P(\mathbf{y}|\mathbf{X},\mathbf{w}) = -\frac{1}{2\sigma^2}\sum_i(y_i - \hat{y}_i)^2 + \text{const}
$$
瞧!最大化这个表达式,就等于最小化平方误差之和。所以最小二乘法本质上是对误差服从高斯分布这一前提下的 最优解 。
这才是你应该记住的: 最小二乘不是人为规定的损失函数,它是特定概率假设下的自然推论。
下面我们动手实现一下闭式解(正规方程):
def linear_regression_ls(X, y):
n_samples, n_features = X.shape
X_aug = np.column_stack([X, np.ones(n_samples)]) # 加偏置列
try:
w_aug = np.linalg.solve(X_aug.T @ X_aug, X_aug.T @ y)
except np.linalg.LinAlgError:
w_aug = np.linalg.pinv(X_aug.T @ X_aug) @ X_aug.T @ y # 伪逆防奇异
return w_aug[:-1], w_aug[-1]
# 测试
np.random.seed(42)
X = np.random.randn(100, 3)
true_w = [2.5, -1.3, 0.8]
true_b = 1.2
y = X @ true_w + true_b + np.random.randn(100) * 0.1
w_est, b_est = linear_regression_ls(X, y)
print("Estimated:", w_est, b_est)
print("True:", true_w, true_b)
运行结果几乎完美还原参数 👏
但注意这里有个坑:当特征之间高度相关或样本数少于维度时,$\mathbf{X}^\top\mathbf{X}$ 会不可逆。这时候直接求解失败,必须引入正则化或者使用 SVD 分解(如伪逆)来稳定数值计算。
🔧 工程建议 :
对于中小规模数据(<10万样本),正规方程速度快且精确;但对于大规模或高维数据,应优先考虑梯度下降类方法,避免矩阵求逆带来的 $O(d^3)$ 时间开销。
不止一种“线性回归”:L2、L1、Elastic Net 对比一览
| 方法 | 损失函数形式 | 是否有闭式解 | 正则化类型 | 关键优势 | 典型场景 |
|---|---|---|---|---|---|
| 普通最小二乘 | $|\mathbf{y}-\mathbf{X}\mathbf{w}|^2$ | ✅ | 无 | 快速求解 | 数据干净、低共线性 |
| Ridge (L2) | $|\mathbf{y}-\mathbf{X}\mathbf{w}|^2 + \lambda|\mathbf{w}|^2$ | ✅ | L2 | 缓解多重共线性 | 特征间强相关 |
| Lasso (L1) | $|\mathbf{y}-\mathbf{X}\mathbf{w}|^2 + \lambda|\mathbf{w}|_1$ | ❌ | L1 | 自动特征选择 | 高维稀疏、可解释性要求高 |
| Elastic Net | 同上 + 组合项 | ❌ | L1+L2 | 平衡稀疏与稳定性 | 多重共线性 + 特征选择 |
👉 一句话总结它们的区别 :
- Ridge 把所有权重往零“压”,但不会真的归零;
- Lasso 敢于把无关特征的权重直接“砍”到零;
- Elastic Net 是两者的合体技,在复杂场景下更鲁棒。
逻辑回归:不只是分类器,更是概率发生器 🎯
很多人以为逻辑回归就是个简单的分类模型,“sigmoid一包,交叉熵一算,完事。”
错!它其实是 广义线性模型 (GLM)的经典范例,背后藏着深刻的统计思想。
它到底在建模什么?
不是类别本身,而是 事件发生的条件概率 :
$$
P(y=1|\mathbf{x}; \mathbf{w}) = \sigma(\mathbf{w}^\top \mathbf{x} + b)
$$
其中 $\sigma(z) = \frac{1}{1+e^{-z}}$ 就是我们熟悉的 Sigmoid 函数。
但别忘了,Sigmoid 的真正身份是 Logit 函数的逆变换 !
定义 log-odds(对数几率)为:
$$
\log\left(\frac{p}{1-p}\right) = \mathbf{w}^\top\mathbf{x} + b
$$
这意味着:我们假设“某个事件的优势比取对数后与输入呈线性关系”。这是一种非常合理的建模方式——因为概率本身是非线性的,但在 log-odds 空间里可以变得线性。
🧠 类比理解 :
就像地图投影一样,地球表面是弯曲的,但我们可以通过墨卡托投影把它展平以便导航。同理,Sigmoid 就是把非线性的概率空间“拉直”成线性可分的形式。
手写逻辑回归训练流程
下面这段代码虽然简单,却是现代深度学习反向传播的雏形:
def sigmoid(z):
z = np.clip(z, -500, 500) # 防止溢出
return 1 / (1 + np.exp(-z))
def logistic_regression_gd(X, y, lr=0.01, epochs=1000, tol=1e-6):
m, n = X.shape
w = np.zeros(n)
b = 0.0
losses = []
for i in range(epochs):
z = X.dot(w) + b
y_hat = sigmoid(z)
# 交叉熵损失(加小常数防 log(0))
loss = -np.mean(y * np.log(y_hat + 1e-15) + (1-y)*np.log(1-y_hat + 1e-15))
losses.append(loss)
# 梯度计算
dw = (1/m) * X.T.dot(y_hat - y)
db = (1/m) * np.sum(y_hat - y)
# 参数更新
w -= lr * dw
b -= lr * db
if i > 0 and abs(losses[-2] - losses[-1]) < tol:
print(f"✅ 收敛于第 {i} 轮")
break
return w, b, losses
🔍 逐行拆解亮点 :
- 第9行:
clip操作防止指数爆炸导致 NaN; - 第15行:加入
1e-15是为了避免浮点精度问题引发log(0); - 第21–22行:梯度形式极其简洁,$(\hat{y} - y)$ 实际上就是“预测偏差”,说明每次更新都在纠正错误方向;
- 第25行:学习率控制步长,太大震荡,太小龟速。
我们可以画出训练过程中的损失曲线:
import matplotlib.pyplot as plt
_, _, losses = logistic_regression_gd(X_bin, y_bin, lr=0.1)
plt.plot(losses)
plt.title("Training Loss over Epochs")
plt.xlabel("Epoch"); plt.ylabel("Loss")
plt.show()
你会看到一条平滑下降的曲线,最终趋于平稳 —— 这就是模型“学会”的证据 💪
Sigmoid vs Tanh vs ReLU:激活函数全家福对比
| 函数 | 公式 | 输出范围 | 导数特性 | 应用场景 |
|---|---|---|---|---|
| Sigmoid | $\frac{1}{1+e^{-z}}$ | (0,1) | $f’(z)=f(z)(1-f(z))$ | 二分类输出层 |
| Tanh | $\tanh(z)$ | (-1,1) | $1 - f^2(z)$ | 隐层激活(早期) |
| ReLU | $\max(0,z)$ | [0,∞) | $\mathbb{I}(z>0)$ | 深层网络主流 |
| Softmax | $\frac{e^{z_i}}{\sum_j e^{z_j}}$ | (0,1), sum=1 | 复杂 | 多分类输出 |
📌 重要提醒 :
Sigmoid 在深层网络中已被淘汰,因为它会导致 梯度消失 !当输入过大或过小时,导数趋近于零,反向传播时信号无法传递下去。这也是为什么现代神经网络普遍采用 ReLU 或其变体(LeakyReLU、ELU 等)。
正则化:给模型戴上“紧箍咒” 🔒
你以为模型越复杂越好?Too young.
现实中,很多模型不是学不会,而是学得太好——把训练集里的噪声和异常值也记住了,导致在新数据上表现糟糕。这就是传说中的 过拟合 。
解决办法?不让它太自由。
L2 正则化(Ridge):温柔地压制权重
我们在原始损失中加入一项:
$$
\mathcal{L}_{\text{ridge}} = \text{MSE} + \lambda |\mathbf{w}|_2^2
$$
直观效果就是:迫使所有权重尽可能小,但不强制为零。想象你在打靶,L2让你尽量靠近中心,但允许轻微偏移。
使用 Scikit-learn 实现非常简单:
from sklearn.linear_model import Ridge
ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)
print("Ridge weights:", ridge.coef_)
你可以尝试不同 alpha 值,观察权重如何被压缩:
| alpha | 权重均值 | 零权重数量 |
|---|---|---|
| 0.01 | ~0.8 | 0 |
| 0.1 | ~0.5 | 0 |
| 1.0 | ~0.2 | 0 |
随着 λ 增大,整体权重趋向缩小,模型变得更保守。
L1 正则化(Lasso):敢于做减法的艺术
Lasso 的损失函数是:
$$
\mathcal{L}_{\text{lasso}} = \text{MSE} + \lambda |\mathbf{w}|_1
$$
由于 L1 范数在原点不可导,优化过程中更容易将某些权重精确置零。这就实现了 自动特征选择 !
from sklearn.linear_model import Lasso
lasso = Lasso(alpha=0.1, max_iter=2000)
lasso.fit(X_train, y_train)
print("Lasso weights:", lasso.coef_)
print("🎯 零权重数量:", np.sum(lasso.coef_ == 0))
输出可能是这样的:
Lasso weights: [ 0. 1.23 0. 0.87 0. 0. 1.02 ]
🎯 零权重数量: 4
看!7个特征中有4个被自动剔除。这对解释性和部署效率都有巨大帮助。
🧠 几何解释 :
L1 正则化的约束区域是菱形(二维下),顶点落在坐标轴上,因此最优解更容易出现在轴上,对应某一维权重为零。
Elastic Net:左右逢源的组合拳高手
单一 L1 或 L2 都有局限:
- Lasso 在高度相关的特征中不稳定,可能随机选一个保留;
- Ridge 不能降维。
那怎么办?两个一起上呗!
$$
\mathcal{L}_{\text{enet}} = \text{MSE} + \lambda \left( \alpha |\mathbf{w}|_1 + (1-\alpha)|\mathbf{w}|_2^2 \right)
$$
参数 l1_ratio = α 控制比例,通常设置为 0.5 左右即可取得良好平衡。
from sklearn.linear_model import ElasticNetCV
enet_cv = ElasticNetCV(cv=5, alphas=[0.01, 0.1, 1.0], l1_ratio=[0.3, 0.5, 0.7])
enet_cv.fit(X_train, y_train)
print("Best alpha:", enet_cv.alpha_)
print("Best l1_ratio:", enet_cv.l1_ratio_)
print("Sparsity:", np.sum(enet_cv.coef_ == 0))
这种方法特别适合既有冗余特征又存在共线性的现实业务场景,比如广告点击率预估、用户画像构建等。
优化算法的选择:快、准、稳的三角博弈 ⚖️
模型训练说白了就是一场参数搜索游戏。目标函数已知,现在要找到使它最小的一组参数。不同的“搜索策略”决定了效率和稳定性。
Batch GD:稳重派,一步到位
每次用全部数据计算梯度:
$$
\nabla_{\text{batch}} = \frac{1}{n} \sum_{i=1}^n \nabla \mathcal{L}_i
$$
优点:方向准确,收敛平稳;
缺点:每轮都要扫全量数据,慢得让人抓狂 😤
适用于小数据集(<1万样本),或者作为调试基准。
SGD:激进派,边走边改
每次只用一个样本更新:
$$
\mathbf{w}^{(t+1)} = \mathbf{w}^{(t)} - \eta \nabla \mathcal{L}_i
$$
优点:更新频率高,内存占用低,适合在线学习;
缺点:路径抖动剧烈,容易错过最优解。
但它也有神奇之处: 噪声可以帮助跳出局部极小值 !尤其在非凸函数中(比如神经网络),这种“随机性”反而成了优势。
🔥 妙用技巧 :配合学习率衰减(learning rate decay),前期大胆探索,后期精细微调。
Mini-batch GD:现代深度学习的绝对主力
折中方案:每次用 32~128 个样本组成一个小批次进行更新。
好处多多:
- 利用向量化加速计算;
- 梯度估计相对稳定;
- 可并行处理,GPU 上跑得飞起 🚀
几乎所有框架(PyTorch、TensorFlow)默认都用这个。
graph LR
A[全量数据] --> B{选择优化方式}
B --> C[Batch GD: 精确但慢]
B --> D[SGD: 快但抖动大]
B --> E[Mini-batch: 平衡之选]
E --> F[广泛用于神经网络训练]
📌 经验法则 :
| 场景 | 推荐方法 |
|---|---|
| 小数据 + 精确需求 | Batch GD |
| 在线学习 / 内存受限 | SGD |
| 深度学习 / 大数据 | Mini-batch GD |
特征工程:决定模型上限的关键环节 🛠️
再厉害的模型,喂给它垃圾数据,也只能吐出垃圾结果。
所谓“数据决定上限,模型逼近上限”,说的就是这个道理。
缺失值处理:不要轻易删除!
很多人一看见 NaN 就删行,这是大忌!
正确做法取决于缺失机制:
- MCAR (完全随机缺失):可用均值/中位数填充;
- MAR (依赖其他变量):可用模型预测填补(如 KNNImputer);
- MNAR (非随机):需深入分析原因,甚至构造“是否缺失”作为新特征。
from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy='mean') # 还支持 median, most_frequent
data[['age', 'income']] = imputer.fit_transform(data[['age', 'income']])
标准化 vs 归一化:别再傻傻分不清
| 方法 | 公式 | 目的 | 适用场景 |
|---|---|---|---|
| StandardScaler | $(x - \mu)/\sigma$ | 使特征符合标准正态分布 | 线性模型、PCA、距离计算 |
| MinMaxScaler | $(x - x_{\min})/(x_{\max} - x_{\min})$ | 压缩至 [0,1] 区间 | 神经网络、图像像素 |
⚠️ 注意:标准化对异常值敏感,若数据有明显离群点,建议先做截断或使用 RobustScaler。
类别特征编码:One-Hot 不是唯一选择!
对于部门、城市这类有限类别,常用 One-Hot:
pd.get_dummies(df, columns=['dept'], prefix='d')
但如果类别太多(比如百万级用户 ID),One-Hot 会导致维度爆炸。此时应使用 嵌入表示 (Embedding):
- 将每个 ID 映射为低维稠密向量(如 64 维);
- 向量通过训练自动学习,相似用户靠近,差异大者远离;
- 广泛应用于推荐系统、CTR 预估。
PCA:降维不只是为了提速
主成分分析不仅能减少计算量,更重要的是去除冗余信息、提升信噪比。
from sklearn.decomposition import PCA
pca = PCA(n_components=0.95) # 保留95%方差
X_pca = pca.fit_transform(X_scaled)
print(f"原始维度: {X.shape[1]}, PCA后: {X_pca.shape[1]}")
但要注意:PCA 是线性变换,无法捕捉非线性结构。对于复杂分布,可考虑 t-SNE、UMAP 等非线性降维方法。
特征重要性评估:让模型开口说话
树模型自带 feature importance:
from sklearn.ensemble import RandomForestRegressor
rf = RandomForestRegressor().fit(X, y)
importance = rf.feature_importances_
# 可视化
import seaborn as sns
sns.barplot(x=importance, y=X.columns)
plt.title("Feature Importance from Random Forest")
plt.show()
你会发现有些看似无关的特征其实贡献不小,而一些直觉重要的反而排名靠后 —— 这正是数据分析的魅力所在:挑战你的先验认知。
graph TD
A[原始数据] --> B{是否存在缺失值?}
B -->|是| C[使用Imputer填充]
B -->|否| D[跳过缺失处理]
C --> E[标准化/归一化]
D --> E
E --> F{是否有类别特征?}
F -->|是| G[One-Hot或Embedding]
F -->|否| H[进入建模阶段]
G --> H
H --> I[PCA或特征选择]
I --> J[最终特征矩阵]
这张图概括了完整的特征工程流水线。记住: 没有放之四海皆准的标准流程,只有因地制宜的灵活组合 。
总结:通往高级建模的思维阶梯
今天我们完成了一次从基础到实战的完整穿越。回顾一下,有哪些核心收获?
🔹 模型本质 :不是魔法盒,而是基于数据的经验归纳系统;
🔹 数学根源 :最小二乘来自正态误差假设,交叉熵来自伯努利分布 MLE;
🔹 正则化哲学 :L1 是“做减法”,L2 是“控幅度”,Elastic Net 是“两手抓”;
🔹 优化选择 :Batch 稳、SGD 快、Mini-batch 最实用;
🔹 特征工程 :决定模型天花板,远比调参更重要。
最后送大家一句我常说的话:
“ 初学者调模型,高手调数据,大师调认知。 ”
当你不再执着于“哪个模型最强”,而是开始思考“我的假设是否合理”、“数据是否反映真相”、“误差来自哪里”……那一刻,你就真正进入了机器学习的自由王国 🌟
简介:《机器学习基石》是林軒田教授在Coursera平台主讲的经典入门课程,其配套PPT系统梳理了机器学习的核心理论与关键算法,涵盖从基础概念到实际应用的完整知识体系。内容包括监督、无监督与半监督学习的分类框架,线性回归与逻辑回归模型原理,决策树与随机森林的构建机制,支持向量机与核技巧的应用,正则化技术防止过拟合的方法,以及神经网络和深度学习的基础架构。同时讲解模型评估方法如交叉验证、优化算法如梯度下降,及超参数调优策略。本PPT为初学者构建扎实理论基础,助力掌握机器学习核心技能,是通往高级AI学习的重要起点。
更多推荐

所有评论(0)