Day 2: 传统机器学习算法(上)—— 从线性模型到SVM

写在前面:如果说数学是内功,那么算法就是招式。今天我们将正式踏入机器学习的江湖,从最简单直观的线性模型开始,一路打怪升级,直到掌握曾经的"算法之王" SVM。我们将遵循由易到难、从直觉到原理的路径,揭开这些经典算法的面纱。


目录

  1. 线性模型:回归与分类的基石
  2. 朴素贝叶斯:概率的力量
  3. 决策树与随机森林:从规则到集成
  4. 支持向量机 (SVM):数学美学的巅峰
  5. 算法大比拼与总结

1. 线性模型:回归与分类的基石

一切复杂的模型,往往都源于最简单的线性关系。

1.1 线性回归 (Linear Regression)

直觉:试图画一条直线(或高维平面),让它尽可能穿过所有的数据点。

数学表达
f(x)=wTx+bf(\mathbf{x}) = \mathbf{w}^T \mathbf{x} + bf(x)=wTx+b

怎么才算"好"?
我们要最小化预测值与真实值之间的差距。最常用的是均方误差 (MSE)

L(w,b)=∑i=1n(yi−(wTxi+b))2L(\mathbf{w}, b) = \sum_{i=1}^{n} (y_i - (\mathbf{w}^T \mathbf{x}_i + b))^2L(w,b)=i=1n(yi(wTxi+b))2

这就变成了一个优化问题(Day 1 中的凸优化)。

代码实战 (numpy手写 vs sklearn)

import numpy as np
from sklearn.linear_model import LinearRegression

# 生成数据
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)

# 方式1: sklearn一把梭
lin_reg = LinearRegression()
lin_reg.fit(X, y)
print(f"Sklearn截距: {lin_reg.intercept_}, 系数: {lin_reg.coef_}")

# 方式2: 解析解 (Normal Equation) theta = (X^T X)^-1 X^T y
X_b = np.c_[np.ones((100, 1)), X]  # 添加偏置项x0=1
theta_best = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)
print(f"解析解截距: {theta_best[0]}, 系数: {theta_best[1]}")

1.2 逻辑回归 (Logistic Regression)

不要被名字骗了,它是分类算法,不是回归算法。

核心思想:线性回归输出的是 (−∞,+∞)(-\infty, +\infty)(,+) 的实数,怎么变成概率 [0,1][0, 1][0,1] 呢?
答案是Sigmoid函数

σ(z)=11+e−z\sigma(z) = \frac{1}{1 + e^{-z}}σ(z)=1+ez1

将线性输出 z=wTx+bz = \mathbf{w}^T \mathbf{x} + bz=wTx+b 压缩到 (0,1)(0, 1)(0,1) 之间。

决策边界

  • P(y=1∣x)>0.5⇒P(y=1|x) > 0.5 \RightarrowP(y=1∣x)>0.5 预测为正类
  • 这一步等价于 wTx+b>0\mathbf{w}^T \mathbf{x} + b > 0wTx+b>0

损失函数
MSE 不再适用(非凸),我们使用对数损失 (Log Loss),也就是交叉熵

J(θ)=−1m∑i=1m[y(i)log⁡(p^(i))+(1−y(i))log⁡(1−p^(i))]J(\theta) = - \frac{1}{m} \sum_{i=1}^{m} [y^{(i)}\log(\hat{p}^{(i)}) + (1-y^{(i)})\log(1-\hat{p}^{(i)})]J(θ)=m1i=1m[y(i)log(p^(i))+(1y(i))log(1p^(i))]

面试考点:逻辑回归是线性分类器还是非线性?
答:本质是线性分类器,因为它的决策边界 wTx+b=0\mathbf{w}^T \mathbf{x} + b = 0wTx+b=0 是线性的。但我们可以通过引入多项式特征,使其具备处理非线性数据的能力。


2. 朴素贝叶斯 (Naive Bayes)

这是基于 Day 1 讲过的贝叶斯定理的算法。

2.1 为什么叫"朴素"?

它做了一个极强的假设:特征之间相互独立
P(x1,x2∣y)=P(x1∣y)P(x2∣y)P(x_1, x_2 | y) = P(x_1 | y) P(x_2 | y)P(x1,x2y)=P(x1y)P(x2y)
虽然这在现实中几乎不可能成立(比如"虽然"和"但是"在文本中显然相关),但在垃圾邮件过滤、文本分类等任务中,它却出奇地有效且高效。

2.2 核心公式

P(y∣x1,…,xn)∝P(y)∏i=1nP(xi∣y)P(y|x_1, \dots, x_n) \propto P(y) \prod_{i=1}^{n} P(x_i|y)P(yx1,,xn)P(y)i=1nP(xiy)

  • P(y)P(y)P(y):先验概率(直接统计类别占比)
  • P(xi∣y)P(x_i|y)P(xiy):似然概率(统计每个特征在各类中出现的频率)
from sklearn.naive_bayes import GaussianNB, MultinomialNB

# GaussianNB: 假设特征服从高斯分布(适合连续变量)
# MultinomialNB: 假设特征服从多项分布(适合文本词频)

clf = GaussianNB()
clf.fit(X_train, y_train)
# 预测就是查表+乘法,速度极快

3. 决策树与随机森林

如果说线性模型是数学家的工具,那决策树就是程序员的逻辑。

3.1 决策树 (Decision Tree)

直觉:就是一堆 if-else 规则的集合。
关键问题是:如何自动生成这些规则?先判断哪个特征?

这就用到了 Day 1 的信息论知识:我们希望每次分裂,都能让数据变得更"纯"。

常用的分裂指标

  1. 信息增益 (ID3):分裂前后熵减少了多少?
    Gain(D,A)=H(D)−∑∣Dv∣∣D∣H(Dv)Gain(D, A) = H(D) - \sum \frac{|D_v|}{|D|} H(D_v)Gain(D,A)=H(D)DDvH(Dv)
  2. 信息增益比 (C4.5):解决了ID3偏向取值多特征的问题。
  3. 基尼系数 (CART):Sklearn 默认使用。
    Gini(p)=1−∑pk2Gini(p) = 1 - \sum p_k^2Gini(p)=1pk2
    Gini系数越小,纯度越高。

3.2 随机森林 (Random Forest)

一棵树的问题:容易过拟合。如果树太深,它会记住每一个训练样本,但对新数据束手无策。

解决方案:三个臭皮匠,顶个诸葛亮——集成学习 (Ensemble Learning)

随机森林属于 Bagging 类集成:

  1. 样本随机:有放回地采样 (Bootstrap),每棵树训练集不同。
  2. 特征随机:每个节点分裂时,只考虑随机选取的一部分特征。

优势

  • 准确率高,抗过拟合能力强。
  • 可以并行训练(速度快)。
  • 能输出特征重要性 (Feature Importance),这在工业界非常有用。
from sklearn.ensemble import RandomForestClassifier

# n_estimators: 树的数量
# max_depth: 树的最大深度(防止过拟合)
rf = RandomForestClassifier(n_estimators=100, max_depth=5, random_state=42)
rf.fit(X_train, y_train)

# 查看特征重要性
importances = rf.feature_importances_

4. 支持向量机 (SVM)

这是传统机器学习时代的"王者",数学推导最为优美,但也最难理解。

4.1 直觉:最大间隔

对于二分类问题,可能有无数条线能把两类分开。SVM 寻找的是中间那条最宽的马路

  • 这条马路中间的线就是决策边界。
  • 马路边缘碰到样本点,这些点就是支持向量 (Support Vectors)
  • 其他样本点对模型没有任何影响(这让SVM具有很好的鲁棒性)。

4.2 核技巧 (Kernel Trick)

如果数据是线性不可分的怎么办?(比如圆环状数据)

核心思想:将低维空间的数据映射到高维空间,在低维纠缠不清的数据,在高维可能只需要切一刀就能分开。

直接计算高维映射 ϕ(x)\phi(x)ϕ(x) 计算量太大,核技巧允许我们在低维直接计算高维的内积:
K(xi,xj)=⟨ϕ(xi),ϕ(xj)⟩K(x_i, x_j) = \langle \phi(x_i), \phi(x_j) \rangleK(xi,xj)=ϕ(xi),ϕ(xj)⟩

常见核函数

  • Linear Kernel:线性核,不做映射(快,适合高维稀疏数据如文本)。
  • RBF Kernel (高斯核):最常用,将数据映射到无穷维空间。
    K(x,y)=exp⁡(−γ∥x−y∥2)K(x, y) = \exp(-\gamma \|x-y\|^2)K(x,y)=exp(γxy2)

4.3 软间隔与C参数

现实数据往往有噪声,不仅不可分,还可能有一些异常点混在对方阵营里。
我们允许犯一点错,这就是软间隔

参数 C 控制着对错误的容忍度:

  • C 很大:容忍度低,试图把所有点都分对(容易过拟合)。
  • C 很小:容忍度高,追求更宽的间隔(容易欠拟合,但泛化好)。
from sklearn.svm import SVC

# C: 正则化参数
# kernel: 核函数 ('linear', 'rbf', 'poly')
# gamma: 核系数,控制高斯核的"宽度"
svm_clf = SVC(kernel="rbf", C=1.0, gamma='scale')
svm_clf.fit(X_train, y_train)

5. 总结与算法大比拼

我们今天学习了四类经典算法,它们各有千秋:

算法优点缺点适用场景
逻辑回归简单、解释性强、训练快只能处理线性边界(除非特征工程)搜广推基线、二分类
朴素贝叶斯极快、对缺失数据不敏感独立性假设太强文本分类、垃圾邮件
随机森林准确率高、抗过拟合、无需特征缩放模型较大、预测稍慢表格数据竞赛首选
SVM小样本效果好、数学理论完备对噪声敏感、大样本训练慢小样本、高维数据

实战建议

  1. 拿到数据,先跑一个 Baseline(通常用逻辑回归或随机森林)。
  2. 如果是表格数据 (Tabular Data),XGBoost/LightGBM (Day 3 内容) 通常是 SOTA。
  3. 如果是稀疏高维数据(如文本 TF-IDF),SVM (Linear)LR 往往表现不错。
  4. 特征工程的重要性往往大于算法选择。

思考题

  1. 为什么逻辑回归在工业界(如广告点击率预测)这么受欢迎?
  2. 随机森林需要做特征归一化吗?SVM呢?

(答案将在评论区揭晓)


📚 参考资源

  • sklearn官方文档:机器学习的百科全书
  • 《统计学习方法》李航:推导SVM的必读经典
  • Visualizing SVM:网上有很多SVM的可视化演示,推荐搜来看看

明日预告:Day 3 我们将迎来集成学习的盛宴。XGBoost、LightGBM 这些在 Kaggle 拿奖拿到手软的神器,到底强在哪里?敬请期待!

如果有更多问题,欢迎关注公众号【算法最TOP】进一步讨论!

更多推荐