机器学习

# 机器学习

# 分类大纲

学习类型主要用途核心模型 / 算法常见应用场景
监督学习分类 (Classification)1. 逻辑回归 (Logistic Regression, LR)二分类问题,如邮件是否为垃圾邮件
2. 支持向量机 (Support Vector Machine, SVM)小样本、高维度的分类问题
3. 决策树 (Decision Tree, DT)可解释性要求高的分类和回归
4. K - 近邻算法 (K-Nearest Neighbors, KNN)简单的分类和回归任务
5. 朴素贝叶斯 (Naive Bayes, NB)文本分类、情感分析
回归 (Regression)1. 线性回归 (Linear Regression)预测连续值,如房价预测
2. 多项式回归 (Polynomial Regression)解决非线性关系回归问题
集成学习 (Ensemble)分类 / 回归1. 随机森林 (Random Forest, RF)防止过拟合、特征重要性分析
2. 梯度提升 (Gradient Boosting, GB)常用:XGBoostLightGBMCatBoost
3. Adaboost (Adaptive Boosting)提升弱分类器的性能
无监督学习聚类 (Clustering)1. K - 均值 (K-Means)市场细分、图像分割
2. DBSCAN (Density-Based Spatial Clustering)发现任意形状的簇、识别异常点
3. 层次聚类 (Hierarchical Clustering)基因序列分析、构建分类树
降维 (Dimensionality Reduction)1. 主成分分析 (Principal Component Analysis, PCA)数据可视化、数据预处理
2. T-SNE (T-distributed Stochastic Neighbor Embedding)高维数据可视化
关联规则Apriori (先验算法)购物篮分析、推荐系统
深度学习感知机 / 神经网络1. 多层感知机 (Multi-Layer Perceptron, MLP)最基础的神经网络结构
图像 / 视觉2. 卷积神经网络 (Convolutional Neural Network, CNN)图像分类、目标检测、人脸识别
序列 / 文本3. 循环神经网络 (Recurrent Neural Network, RNN)文本生成、语音识别
4. 长短期记忆网络 (Long Short-Term Memory, LSTM)解决 RNN 的梯度消失问题
5. Transformer/Attention 机制BERT, GPT 等大模型的基石,取代 RNN 成为主流

# 线性回归

核心任务:预测一个连续值(例如:房价、气温、电池剩余寿命)。 它试图找到一条直线(或高维超平面)来拟合数据点。

# 核心公式

模型假设输入特征 xx 和输出 yy 之间存在线性关系:

y=wTx+by = w^T x + b

# 损失函数 (Loss Function)

线性回归通常使用 均方误差 (Mean Squared Error, MSE)。目的是最小化预测值与真实值之间差值的平方和。

J(w,b)=12mi=1m(y(i)y^(i))2J(w, b) = \frac{1}{2m} \sum_{i=1}^{m} (y^{(i)} - \hat{y}^{(i)})^2

为什么用平方? 因为平方可以消除正负误差的影响,并且是凸函数,方便求导和寻找全局最优解。

# 逻辑回归

核心任务:虽然叫 “回归”,但它实际上是解决 二分类 问题(例如:是否患病、是否点击广告)。 它预测的是事件发生的概率(0 到 1 之间的值)。

# 核心公式

它在线性回归的基础上,加了一个 激活函数 (Sigmoid Function),把输出压缩到 (0,1)(0, 1) 之间。

hθ(x)=sigmoid(wTx+b)=11+e(wTx+b)h_\theta(x) = \text{sigmoid}(w^T x + b) = \frac{1}{1 + e^{-(w^T x + b)}}

# 损失函数 (Loss Function)

逻辑回归 不能 使用 MSE(均方误差),因为引入 Sigmoid 后,MSE 不再是凸函数,会导致梯度下降陷入局部最优解。

它使用对数损失 (Log Loss),也叫 交叉熵损失 (Cross-Entropy Loss):

J(w)=1mi=1m[y(i)log(y^(i))+(1y(i))log(1y^(i))]J(w) = - \frac{1}{m} \sum_{i=1}^{m} [y^{(i)} \log(\hat{y}^{(i)}) + (1 - y^{(i)}) \log(1 - \hat{y}^{(i)})]

这个公式的物理意义是:极大似然估计 (Maximum Likelihood Estimation)。

深度思考:常见的面试坑点

  1. 逻辑回归可以处理非线性分类吗?
    • 直接用不行,因为它是线性分类器(决策边界是直线)。
    • 但在特征工程后可以,例如引入高维特征(x2,x3x^2, x^3 等),或者使用核技巧(Kernel Trick),它就可以画出曲线边界。
  2. 为什么逻辑回归要用 Sigmoid?
    • 除了将数值映射到 (0,1)(0,1) 代表概率外,Sigmoid 函数的导数非常漂亮:σ(z)=σ(z)(1σ(z))\sigma'(z) = \sigma(z)(1 - \sigma(z)),这让梯度计算非常简便。
  3. 正则化 (Regularization)
    • 为了防止过拟合,这两种模型通常都会加 L1 (Lasso)L2 (Ridge) 正则项。
    • L1 倾向于产生稀疏权重(很多 ww 变为 0),适合特征选择。
    • L2 倾向于让权重普遍变小,防止模型对单一特征过分敏感。

# 支持向量机

在逻辑回归中,只要能把两类分开的线都可以。但在 SVM 中,我们追求 **“最宽的街道”**。

  • 超平面 (Hyperplane):就是那条分类的线(在高维是面)。
  • 间隔 (Margin):由于我们希望分类器不仅能分对训练数据,还能对未知数据有好的容错性,所以我们要找到一条线,让它离最近的样本点越远越好。这个 “最远距离” 的两倍就是间隔。
  • 支持向量 (Support Vectors)重点! 并非所有的样本点都对确定这条线有贡献。只有离线最近的那几个点(即 “撑” 起街道宽度的点)决定了模型。这些点叫支持向量。

# 目标函数 (Objective Function)

我们想要最大化间隔。几何间隔的公式是 1w\frac{1}{||w||}。最大化 1w\frac{1}{||w||} 等价于 最小化 w2||w||^2

所以,硬间隔(Hard Margin)SVM 的原始优化目标是:

minw,b12w2\min_{w,b} \frac{1}{2}||w||^2

s.t.yi(wTxi+b)1,i=1,...,m\text{s.t.} \quad y_i(w^T x_i + b) \geq 1, \quad i=1, ..., m

(这里的约束条件是:所有样本点都必须被正确分类,且都在间隔之外)

# 对偶问题求解

求解过程可以分为三个阶段:构造拉格朗日函数 \rightarrow 转化为对偶问题 \rightarrow 利用 SMO 算法求解

# 第一阶段:从 “原问题” 到 “拉格朗日函数”
# 1. 回顾原问题 (Primal Problem)

我们的目标是最小化 ww 的模长,同时保证分类正确:

minw,b12w2\min_{w, b} \frac{1}{2} ||w||^2

s.t.yi(wTxi+b)1,i=1,,m\text{s.t.} \quad y_i(w^T x_i + b) \geq 1, \quad i=1, \dots, m

这是一个带约束的凸优化问题。为了消除约束,我们需要引入拉格朗日乘子 (Lagrange Multipliers) αi\alpha_i(其中 αi0\alpha_i \geq 0)。

# 2. 构造拉格朗日函数

我们将约束条件融合到目标函数中:

L(w,b,α)=12w2i=1mαi[yi(wTxi+b)1]\mathcal{L}(w, b, \alpha) = \frac{1}{2}||w||^2 - \sum_{i=1}^{m} \alpha_i [y_i(w^T x_i + b) - 1]

  • 这个函数的物理意义是:如果约束被满足,第二项为负或 0,最小化 L\mathcal{L} 等同于原问题;如果约束被违背,第二项会变得非常大,迫使优化往满足约束的方向走。
# 第二阶段:推导对偶形式 (The Dual Form)

原问题是 “极小极大” 问题(minw,bmaxαL\min_{w,b} \max_{\alpha} \mathcal{L})。对偶问题是它的交换形式,即 “极大极小” 问题(maxαminw,bL\max_{\alpha} \min_{w,b} \mathcal{L})。

我们需要先wwbb 求偏导并令其为 0(求极小值),消掉这两个变量。

# 1. 求偏导

Lw=wi=1mαiyixi=0w=i=1mαiyixi\frac{\partial \mathcal{L}}{\partial w} = w - \sum_{i=1}^{m} \alpha_i y_i x_i = 0 \quad \Rightarrow \quad w = \sum_{i=1}^{m} \alpha_i y_i x_i

Lb=i=1mαiyi=0i=1mαiyi=0\frac{\partial \mathcal{L}}{\partial b} = - \sum_{i=1}^{m} \alpha_i y_i = 0 \quad \Rightarrow \quad \sum_{i=1}^{m} \alpha_i y_i = 0

关键点:第一个公式 w=αiyixiw = \sum \alpha_i y_i x_i 告诉我们,权重向量 ww 只是数据点 xix_i 的线性组合。而且只有支持向量的 αi>0\alpha_i > 0,其他非支持向量的 αi=0\alpha_i = 0,这意味着 ww 只由少数支持向量决定。

300

# 2. 代回拉格朗日函数

将上面求出的 ww 代回 L(w,b,α)\mathcal{L}(w, b, \alpha) 中,经过化简(推导过程略去繁琐的代数运算),我们得到了只包含 α\alpha对偶目标函数

maxα(i=1mαi12i=1mj=1mαiαjyiyj(xiTxj))\max_{\alpha} \left( \sum_{i=1}^{m} \alpha_i - \frac{1}{2} \sum_{i=1}^{m} \sum_{j=1}^{m} \alpha_i \alpha_j y_i y_j (x_i^T x_j) \right)

300

300

300

# K - 近邻

KNN 没有显式的 “训练” 过程(它只是把数据存起来)。当来了一个新样本 xnewx_{new} 需要预测时,它执行以下三步:

  1. 算距离:计算 xnewx_{new} 与训练集中所有样本点的距离。
  2. 找邻居:按距离排序,选出最近的 KK 个点。
  3. 做决策
    • 分类任务少数服从多数。看这 KK 个邻居里哪一类最多。
    • 回归任务求平均值。计算这 KK 个邻居目标值的平均值作为预测结果。

三个关键要素:

  1. 距离度量

    • 欧氏距离 (Euclidean Distance):最常用。即两点间的直线距离。

      d(x,y)=i=1n(xiyi)2d(x, y) = \sqrt{\sum_{i=1}^{n} (x_i - y_i)^2}

    • 曼哈顿距离 (Manhattan Distance):城市街区距离(走直角)。

      d(x,y)=i=1nxiyid(x, y) = \sum_{i=1}^{n} |x_i - y_i|

    • 余弦相似度 (Cosine Similarity):关注方向而非距离,常用于文本分类。

    特征缩放 (Feature Scaling) KNN 对数据的量纲极度敏感!

    • 例如:特征 A 是 “身高 (米)”(1.7-1.9),特征 B 是 “工资 (元)”(5000-50000)。
    • 如果不归一化,工资的差值(几万)会完全掩盖身高的差值(零点几),导致 KNN 只看工资。
    • 结论:用 KNN 前必须进行归一化 (Normalization) 或标准化 (Standardization)。
  2. KK 值的选择:

    • K 很小 (如 K=1) 模型极不稳定,容易受噪声点影响(如果最近的一个点是噪声,就预测错了)。决策边界非常曲折、破碎。低偏差,高方差 (Overfitting)
    • K 很大 (如 K=N) 模型过于简单。无论输入什么,都预测为训练集中数量最多的那一类。决策边界过于平滑。高偏差,低方差 (Underfitting)
  3. 决策规则

    • 多数表决:默认规则。

    • 距离加权 (Weighted KNN):离得近的邻居权重更大。比如权重为 1/d1/d。这样可以缓解 KK 值较大时远距离点干扰决策的问题。

如何加速 KNN?

答案:不要暴力搜索,使用索引结构。

  1. KD-Tree (k-Dimensional Tree)
    • 一种对 kk 维空间进行划分的二叉树。
    • 核心思想:把数据像切蛋糕一样切成一块块的。查找时,先判断目标点在哪一块,通过剪枝(Pruning)排除掉大部分不可能包含最近邻的区域。
    • 缺点:当特征维度很高时(>20 维),KD-Tree 的效率会退化成线性扫描。
  2. Ball Tree
    • 使用超球面来划分空间,在高维数据上比 KD-Tree 表现稍好。

# 决策树

决策树学习的关键在于如何选择最优划分属性。一般而言,随着划分过程不断进行,我们希望决策树的分支结点所包含的样本尽可能属于同一类别,即结点的 “纯度”(purity) 越来越高。

# 经典的属性划分方法:

# 1. 信息熵 & 信息增益 (ID3)
  • 物理意义:熵越大,数据越混乱;熵越小,数据越纯。

  • 公式

H(D)=k=1Kpklog2pkH(D) = - \sum_{k=1}^{K} p_k \log_2 p_k

(其中 pkp_k 是第 kk 类样本所占的比例)

300

  • 决策逻辑:选择那个能让熵下降最快(即信息增益最大)的特征进行分裂。

Gain(D,A)=H(D)v=1VDvDH(Dv)\text{Gain}(D, A) = H(D) - \sum^{V}_{v=1}{\frac{|D^{v}|}{|D|}}H(D^{v})

300

import math
def Ent(a, b):
    if a == 0 or b == 0:
        return 0
    c = a + b
    a, b = a / c, b / c
    return -a * math.log2(a) - b * math.log2(b)
H_D = Ent(9, 5)
H_D_A1 = 5/14*Ent(2, 3) + 4/14*Ent(4, 0) + 5/14*Ent(2, 3)
Gain_A1 = H_D - H_D_A1
print(f'{Gain_A1=}')
  • ID3 的致命缺点:它特别偏爱取值多的特征。
    • 例子:如果把 “身份证号” 作为一个特征,每个样本都不一样,纯度极高,但这对预测毫无意义。
# 2. 信息增益率 (Information Gain Ratio) —— C4.5 算法
  • 为了修正 ID3 的偏见,C4.5 引入了惩罚项。它用 “信息增益” 除以该特征的 “固有熵”(Intrinsic Value)。

    Gain_Ratio(D,A)=Gain(D,A)IVA(A)\text{Gain\_Ratio}(D, A) = \frac{\text{Gain}(D, A)}{IV_A(A)}

  • 特征取值越多,IVA(A)IV_A(A) 越大,分母变大,增益率就被压低了。

300

300

import math
def Ent(a, b):
    if a == 0 or b == 0:
        return 0
    c = a + b
    a, b = a / c, b / c
    return -a * math.log2(a) - b * math.log2(b)
H_D = Ent(9, 5)
H_D_A1 = 5/14*Ent(2, 3) + 4/14*Ent(4, 0) + 5/14*Ent(2, 3)
Gain_A1 = H_D - H_D_A1
print(f'{Gain_A1=}')
IV_A1 = -5/14*math.log2(5/14) - 4/14*math.log2(4/14) - 5/14*math.log2(5/14)
Gain_Ratio_A1 = Gain_A1 / IV_A1
print(f'{Gain_Ratio_A1=}')
# 3. 基尼系数 (Gini Impurity) —— CART 算法 (最重要!)

现在的工业界主流算法(如 XGBoost, sklearn 的默认树)都使用 CART (Classification and Regression Tree)。

  • 物理意义:从集合中随机抽取两个样本,它们类别不一致的概率。

  • 公式

    Gini(p)=1k=1Kpk2\text{Gini}(p) = 1 - \sum_{k=1}^{K} p_k^2

    Giniindex(D,a)=v=1VDvDGini(Dv)\text{Gini}_{\text{index}}(D, a) = \sum^{V}_{v=1}{\frac{|D^v|}{|D|}\text{Gini}(D^v)}

  • 决策逻辑:选择让分裂后基尼系数最小的特征。

image-20251222110215402

💡 面试必问:为什么 CART 用 Gini 而不用熵?

  1. 计算快:熵需要算 log\log,计算机算对数很慢;Gini 只需要算乘法和减法。
  2. 效果近似:在绝大多数情况下,Gini 和熵生成的树结构非常相似。

# 剪枝:防止过拟合

# A. 预剪枝 (Pre-Pruning)

在树生长过程中,提前停止。

  • 策略
    • 限制最大深度 ( max_depth )。
    • 限制叶子节点最少样本数 ( min_samples_leaf )。
    • 限制信息增益的阈值(如果增益太小就不分了)。
  • 优缺点:速度快,但容易欠拟合(可能错失后续很好的分裂机会)。
# B. 后剪枝 (Post-Pruning)

先让树长到最大,然后自底向上地剪掉那些不重要的枝叶。

  • 策略:如果剪掉某个子树,模型在验证集上的准确率没有下降(甚至上升),那就剪掉。
  • 优缺点:泛化能力强,但计算代价大。

# 随机森林

随机森林属于 Bagging (Bootstrap Aggregating) 算法的代表。它的强大来自于两个 “随机”:

# A. 样本的随机性 (Bootstrap Sampling)

  • 怎么做:每棵树训练时,不是用所有的训练数据,而是有放回地随机抽取 NN 个样本(和原始数据集大小一样)。
  • 结果:因为是有放回抽取,原始数据中大约有 36.8% 的样本不会出现在某棵树的训练集中。这些没被选中的数据叫做 袋外数据 (Out-of-Bag, OOB)
  • 目的:让每棵树看到的训练数据都不太一样,增加树之间的差异性 (Diversity)。

# B. 特征的随机性 (Feature Randomness)

  • 怎么做:在决策树的每一个节点需要分裂时,不是从所有 MM 个特征中找最好的,而是先随机选出 kk 个特征(通常 k=Mk = \sqrt{M}log2M\log_2 M),然后只在这 kk 个特征里找最好的分裂点。
  • 目的:这是随机森林的点睛之笔!它防止了某些 “超级特征” 主导所有树的生长,强迫模型去关注那些次要但有用的特征,进一步降低了树之间的相关性。

# 面试问题:

Q: 随机森林能处理缺失值吗?

  • A:
    • 方法 1:简单填充(中位数 / 众数)。
    • 方法 2(进阶):利用相似度矩阵。先简单填充,然后跑一遍随机森林,计算样本间的相似度(看落在同一个叶子节点的频率),用相似样本的值加权填充,再迭代训练。

# Adaboost

Adaboost 通常使用最简单的 决策树桩 (Decision Stump) 作为基分类器(即只有一层深度的树,切一刀)。

# 算法流程

# Step 1: 初始化权重

最开始,所有 NN 个训练样本的权重是平等的,都是 1/N1/N

# Step 2: 迭代训练 (Repeat T rounds)

在每一轮 tt 中:

  1. 训练:用当前权重的样本训练一个弱分类器 ht(x)h_t(x)
  2. 算错误率 (ϵt\epsilon_t):看它分错了多少权重的数据。
  3. 算话语权 (αt\alpha_t):计算这个分类器在最终投票时的权重。
    • 公式:αt=12ln(1ϵtϵt)\alpha_t = \frac{1}{2} \ln\left(\frac{1-\epsilon_t}{\epsilon_t}\right)
    • 直觉:如果错误率越低(ϵt\epsilon_t 小),αt\alpha_t 就越大(话语权越重)。如果错误率是 50%(瞎猜),αt\alpha_t 就是 0(废话不论)。
  4. 更新样本权重 (ww)关键步骤!
    • 分错的样本:权重变大 \rightarrow w_{new} = w_{old} \cdot e^
    • 分对的样本:权重变小 \rightarrow w_{new} = w_{old} \cdot e^
    • 最后做归一化,让权重和为 1。
# Step 3: 最终组合

把这 TT 个弱分类器线性组合起来,话语权大的说了算:

H(x)=sign(t=1Tαtht(x))H(x) = \text{sign}\left(\sum_{t=1}^{T} \alpha_t h_t(x)\right)

# 图解核心差异:Adaboost vs 随机森林

特性随机森林 (Random Forest)Adaboost
训练方式并行 (大家各干各的,互不干扰)串行 (接力赛,后一个依赖前一个)
样本权重始终相同 (通过 Bootstrap 随机抽样)动态调整 (错题权重越来越大)
基分类器权重平等 (1 人 1 票)加权 (能力强的票权大)
主要作用降低方差 (防止过拟合)降低偏差 (提升准确率)
对异常值不敏感 (抗噪能力强)极度敏感 (因为异常值通常是难分样本,权重会被无限放大,带偏模型)

# 面试问题:

Q: 对于无法接受带权样本的个体学习器,应该采样什么办法调整权重?

  • A: 应该采用 “重采样法” 来处理,像决策树这种可以处理带权样本的学习器,可以直接应用到权重中去。

# XGBoost

参考:躺懂 XGBoost,学不会来打我(doge)_哔哩哔哩_bilibili

# 算法流程

# 前向分步算法

y^(t)=y^(t1)+ft(x)\hat{y}^{(t)}=\hat{y}^{(t-1)}+f_{t}(x)

# 正则化项

XGBoost 显式地定义了正则化:

Ω(ft)=γT+12λj=1Twj2\Omega(f_t) = \gamma T + \frac{1}{2} \lambda \sum_{j=1}^{T} w_j^2

  • γT\gamma T:叶子节点数量的惩罚(相当于 L0 正则,防止树太深)。
  • 12λw2\frac{1}{2} \lambda ||w||^2:叶子权重的 L2 正则(防止分数太极端)。
# 目标函数:

i=1NL(yi,y^i(t))+j=1tΩ(fj)\sum^{N}_{i=1}L(y_i, \hat{y}^{(t)}_i)+\sum^{t}_{j=1}\Omega(f_j)

t1t-1 棵树已经确定,仅需要优化第 tt 棵树的值即可。

y^i(t)\hat{y}_i^{(t)} 展开,并去掉前 t1t-1 棵树的正则化项(因为它们已经是常数了),得到:

Obj(t)=i=1nl(yi,y^i(t1)+ft(xi))+γT+12λj=1Twj2Obj^{(t)} = \sum_{i=1}^{n} l(y_i, \hat{y}_i^{(t-1)} + f_t(x_i)) + \gamma T + \frac{1}{2} \lambda \sum_{j=1}^{T} w_j^2

换成以叶子节点的形式遍历,

Obj(t)=[j=1T[iIjl(yi,y^i(t1)+wj)]+12λwj2]+γTObj^{(t)} = [\sum_{j=1}^{T} [\sum_{i \in I_j}^{} l(y_i, \hat{y}_i^{(t-1)} + w_j)] + \frac{1}{2} \lambda w_j^2] + \gamma T

这里如果确定损失函数为均方损失,可以利用贪心可以求解每个叶子节点内的最优值。但是不同任务损失函数不同,需要确立一种跨损失函数的通用方法。

image-20251222135513397

# 二阶泰勒展开 (The Magic Step)

这是 XGBoost 最核心的数学魔法。GBDT 只用到一阶导,而 XGBoost 对损失函数进行了二阶泰勒展开

回顾泰勒公式:f(x+Δx)f(x)+f(x)Δx+12f(x)Δx2f(x + \Delta x) \approx f(x) + f'(x)\Delta x + \frac{1}{2}f''(x)\Delta x^2

wjw_j 看作 Δx\Delta x,我们展开:

l(yi,y^i(t1)+wj)l(yi,y^i(t1))+l(yi,y^i(t1))wj+12l(yi,y^i(t1))wj2l(y_i, \hat{y}_i^{(t-1)} + w_j)\approx l(y_i, \hat{y}_i^{(t-1)})+l^{'}(y_i,\hat{y}_i^{(t-1)})w_j+\frac{1}{2} l^{''}(y_i, \hat{y}_i^{(t-1)})w_j^2

其中,第一项为常量,可删去,可表示为

l(yi,y^i(t1)+wj)giwj+12hiwj2l(y_i, \hat{y}_i^{(t-1)} + w_j)\approx g_iw_j+\frac{1}{2} h_iw_j^2

其中,

  • gig_i (一阶导 / 梯度)l(yi,y^i(t1))l^{'}(y_i,\hat{y}_i^{(t-1)})
  • hih_i (二阶导 / 海森矩阵)l(yi,y^i(t1))l^{''}(y_i,\hat{y}_i^{(t-1)})

因此,整体目标函数可写为:

Obj(t)=j=1T[iIj(giwj+12hiwj2)+12λwj2]+γT=j=1T[wjiIjgi+12wj2iIjhi+12λwj2]+γT=j=1T[wjiIjgi+12wj2(iIjhi+λ)]+γTObj^{(t)} = \sum_{j=1}^{T} [\sum_{i \in I_j}^{} (g_iw_j+\frac{1}{2} h_iw_j^2) + \frac{1}{2} \lambda w_j^2] + \gamma T \\ =\sum_{j=1}^{T} [w_j\sum_{i \in I_j}^{} g_i+\frac{1}{2}w_j^2\sum_{i \in I_j} h_i + \frac{1}{2} \lambda w_j^2] + \gamma T \\ =\sum_{j=1}^{T} [w_j\sum_{i \in I_j}^{} g_i+\frac{1}{2}w_j^2(\sum_{i \in I_j} h_i + \lambda) ] + \gamma T

定义该叶子上所有样本的 梯度之和:

  • Gj=iIjgiG_j = \sum_{i \in I_j} g_i
  • Hj=iIjhiH_j = \sum_{i \in I_j} h_i

目标函数变形为:

Obj(t)=j=1T[Gjwj+12(Hj+λ)wj2]+γTObj^{(t)} = \sum_{j=1}^{T} [ G_j w_j + \frac{1}{2} (H_j + \lambda) w_j^2 ] + \gamma T

# 求解最优叶子权重 (Structure Score)

现在,目标函数变成了关于 wjw_j 的一元二次函数(抛物线):

f(wj)=Awj2+Bwj+Cf(w_j) = A w_j^2 + B w_j + C

其中 A=12(Hj+λ)A = \frac{1}{2}(H_j + \lambda)B=GjB = G_j

对于一元二次方程,极值点在 w=B/2Aw = -B / 2A 处取得。

所以,给定树结构的情况下,第 jj 个叶子节点最优的叶子权重 wjw_j^* 为:

wj=GjHj+λw_j^* = - \frac{G_j}{H_j + \lambda}

wjw_j^* 代回目标函数,得到这棵树的最小损失值(打分)

Obj=12j=1TGj2Hj+λ+γTObj^* = - \frac{1}{2} \sum_{j=1}^{T} \frac{G_j^2}{H_j + \lambda} + \gamma T

💡 物理意义

  • GjG_j 代表这一堆样本的一阶梯度总和(想要移动的方向)。
  • HjH_j 代表二阶曲率(移动的阻力)。
  • λ\lambda 是正则化项,增加分母,让计算出的权重 wjw_j^* 不要太大(缩减)。
  • ObjObj^* 越小,说明这个树结构越好。
# 分裂节点 (Split Finding)

我们要找一棵树,但不可能遍历所有可能的树结构。XGBoost 使用贪心算法,从根节点开始,尝试每一次分裂。

假设我们要把一个节点分裂成左子节点 (L)右子节点 (R)

# 1. 分裂增益 (Gain)

我们要判断 “这一刀切下去值不值”。

  • 切分前的分数:Score_{Parent} =\gamma -\frac{1}{2} \frac{(G_L + G_R)^2}
  • 切分后的分数:ScoreLeft+ScoreRight=2γ12(GL2HL+λ+GR2HR+λ)Score_{Left} + Score_{Right} = 2\gamma -\frac{1}{2}(\frac{G_L^2}{H_L + \lambda} + \frac{G_R^2}{H_R + \lambda})

注意:这里每个节点的 G 和 H 都是已知的

增益公式 (Gain) = (切分后分数) - (切分前分数) - (引入新叶子的代价):

Gain=12[GL2HL+λ+GR2HR+λ(GL+GR)2HL+HR+λ]γGain = \frac{1}{2} \left[ \frac{G_L^2}{H_L + \lambda} + \frac{G_R^2}{H_R + \lambda} - \frac{(G_L + G_R)^2}{H_L + H_R + \lambda} \right] - \gamma

# 2. 决策逻辑
  1. 遍历所有特征。
  2. 对于每个特征,遍历所有可能的切分点(或者使用近 似分位数算法)。
  3. 计算 GainGain
  4. 找到 GainGain 最大的特征和切分点进行分裂。
  5. 如果 Gain<0Gain < 0(或者小于某个阈值),则停止分裂(这其实就是预剪枝)。

如何优化特征值排序:

300

  • 筛选特征:列采样:(1)按树随机:直接随机选择特征,不更改;(2)按层随机(灵活):每层都重新随机选取特征。

  • 筛选特征值:(1)分桶;(2)加权分位法:根据每个样本的hih_i 进行分桶。

    300

    image-20251222145720637

# 面试介绍

XGBoost(Extreme Gradient Boosting)本质上是 GBDT(Gradient Boosting Decision Tree)的一种高效、并行的工程实现

它的基本思想是 Boosting(提升) 策略,即通过串行地迭代训练多个弱学习器(通常是 CART 回归树),每棵树都在拟合上一轮模型的残差(或者更准确地说是负梯度),最后将所有树的预测值加权求和得到最终结果。

二阶泰勒展开(最核心的区别)

话术:

“传统的 GBDT 在优化目标函数时,通常只用到了一阶导数(梯度)。

而 XGBoost 对目标函数进行了 二阶泰勒展开。它同时利用了 一阶导数(gig_i) 和 二阶导数(hih_i, 海森矩阵) 来近似目标函数。

这样做的好处是:下降得更快,收敛更精确。这就好比牛顿法相比梯度下降法,收敛速度通常更快。”

正则化(防止过拟合)

话术:

“XGBoost 在目标函数中显式地加入了 正则化项(Regularization)。

它惩罚了叶子节点的个数(γT\gamma T) 和 叶子节点权重的 L2 模平方(12λw2\frac{1}{2}\lambda ||w||^2)。

这一项在传统的 GBDT 中通常没有,这使得 XGBoost 学习出来的树更加简单,抗过拟合能力更强。”

面试官可能会追问:“那它和 LightGBM 有什么区别?” 或者 “为什么现在不用它了?” 你可以主动在大结局提到。

话术: “总结一下,XGBoost 相比于传统 GBDT,引入了二阶导数、正则化项和特征并行化,在精度和速度上都达到了很好的平衡。不过,随着数据量达到亿级,后来的 LightGBM 通过 GOSS(单边梯度采样)和 EFB(互斥特征捆绑)进一步提升了训练速度和内存效率。 但在中小规模的表格数据上,XGBoost 依然是目前最稳健的选择之一。”

# 聚类

# K - 均值

假设数据簇是球状的。我们先随机插 KK 个旗子(质心),谁离旗子近就算谁的人;然后根据这些人的位置移动旗子,直到旗子不动为止。

# 算法流程 (EM 算法的特例)

  1. 初始化:随机选择 KK 个点作为初始质心 (Centroids)。
  2. E 步 (Assignment):计算每个样本到 KK 个质心的距离,把它归到最近的那个质心所在的簇。
  3. M 步 (Update):重新计算每个簇的平均值,将质心移动到这个平均值位置。
  4. 循环:重复 2 和 3,直到质心不再移动(收敛)。

# 目标函数 (Loss Function)

最小化 簇内平方误差和 (Within-Cluster Sum of Squares, WCSS):

J=j=1KxCjxμj2J = \sum_{j=1}^{K} \sum_{x \in C_j} ||x - \mu_j||^2

也就是让簇内尽可能紧凑。

# 面试问题

  • Q:K 怎么选?

    肘部法则 (Elbow Method):画出 K 值与 Loss 的曲线,找拐点(像手肘一样的位置)。

    轮廓系数 (Silhouette Coefficient):结合了 “簇内紧密度” 和 “簇间分离度”。值在 [1,1][-1, 1] 之间,越接近 1 越好。

  • Q:初始点敏感吗?

    非常敏感。如果运气不好,初始点选在一堆,可能陷入局部最优。

    解法:使用 K-Means++。它的策略是 “让初始质心尽可能离得远”。

# DBSCAN

DBSCAN (Density-Based Spatial Clustering of Applications with Noise) 的算法流程其实非常像是在 “传染病毒” 或者 “发展下线”。

它的核心逻辑是:只要密度够大,就继续向外扩张,直到碰壁(密度不够)为止。

以下是详细的算法流程拆解:

# 1. 核心参数准备

在开始之前,必须定好两个参数(之前复习过的):

  • ϵ\epsilon (Epsilon):扫描半径(邻域大小)。
  • MinPts:成为核心点所需的最小邻居数。

# 2. 算法详细步骤

DBSCAN 不需要预先指定 KK 个簇,它从数据集中任意一个未访问的点开始。

# 第一步:遍历所有点

我们有一个点集 DD,开始遍历每一个点 PP

  1. 如果 PP 已经被访问过(Visited),跳过,看下一个点。
  2. 如果 PP 没被访问过,标记为 已访问
# 第二步:判断是否为 “核心点” (Core Point)

计算 PP 在半径 ϵ\epsilon 内的邻居数量(包括它自己):

  • 情况 A:邻居数 < MinPts
    • 说明这里很稀疏,PP 暂时是个噪声点 (Noise)
    • 注意:这个 “噪声” 标记是暂时的,因为后面它可能会被其他核心点 “收编” 变成边界点。
    • 动作:结束对 PP 的处理,回到第一步循环。
  • 情况 B:邻居数 \ge MinPts
    • 说明 PP 是一个核心点
    • 动作:创建一个新簇 (New Cluster),把 PP 放进去,然后开始 **“扩张”**(进入第三步)。
# 第三步:扩张簇 (Expand Cluster) —— 核心逻辑

这是 DBSCAN 最关键的一步。一旦找到了一个核心点 PP,我们就有了 “火种”,现在要让火烧起来。

  1. 建立种子队列:把 PP 的所有邻居(除去 PP 自己)放到一个种子队列 (Seeds) 中。
  2. 循环处理种子队列
    • 从队列里取出一个点 QQ
    • 处理状态
      • 如果 QQ 之前是 “噪声”,把它变成当前簇的成员(边界点)。
      • 如果 QQ 之前 “未访问”,标记为 “已访问”,并把 QQ 加入当前簇。
    • 检查 QQ 的潜力
      • 计算 QQ 的邻居数量。
      • 如果 QQ 也是核心点(邻居数 \ge MinPts):说明 QQ 密度也很大,可以继续传染。QQ 的所有邻居都加到种子队列的末尾
      • 如果 QQ 不是核心点:说明它是边界点,到此为止,不再向外拉人了。
  3. 循环结束:当种子队列空了,说明这个簇能连通的地方都跑遍了。这个簇的生长结束。
# 第四步:继续遍历

回到第一步,继续找下一个未访问的点,直到所有点都被访问过。

# 层次聚类

# 算法详细流程

假设我们有 NN 个数据点。

  • Step 1: 初始化
    • 把每个数据点看作一个独立的簇
    • 此时我们有 NN 个簇:C1,C2,,CNC_1, C_2, \dots, C_N
    • 计算所有簇两两之间的距离矩阵 (Distance Matrix)(通常是 N×NN \times N 的矩阵)。
  • Step 2: 寻找最近的两个簇
    • 在距离矩阵中找到距离最小的那两个簇(比如 CiC_iCjC_j)。
  • Step 3: 合并
    • CiC_iCjC_j 合并成一个新的簇 CnewC_{new}
    • 现在的簇总数变成了 N1N-1 个。
  • Step 4: 更新距离矩阵
    • 这是最关键的一步。我们需要计算新簇 CnewC_{new} 与剩下的所有旧簇之间的距离
    • 更新距离矩阵。
  • Step 5: 循环
    • 重复 Step 2 到 Step 4。
    • 不断合并最近的簇,簇的数量从 NN11N \rightarrow N-1 \rightarrow \dots \rightarrow 1
    • 直到所有数据点都被合并到一个大簇中,算法结束。

# 优缺点

维度K-Means (划分法)DBSCAN (密度法)层次聚类 (层次法)
核心思想找质心,算距离,迭代优化找高密度区域,向外扩张自底向上合并,构建家谱
输入参数需要指定簇数量 KK需要指定半径 ϵ\epsilon 和密度阈值 MinPts不需要参数 (切分时需指定阈值或 K)
簇的形状必须是凸形 / 球状 (Convex)可以是任意形状 (非凸)取决于 Linkage (通常较灵活)
对异常值敏感 (会被拉偏质心)鲁棒 (自动识别为噪声并丢弃)较敏感 (取决于 Linkage)
时间复杂度 O(NKI)O(N \cdot K \cdot I) O(NlogN)O(N \log N) (带索引)最慢 O(N3)O(N^3)O(N2logN)O(N^2 \log N)
适用数据量大规模数据中规模数据小规模数据 (<1 万)
主要缺陷陷入局部最优、K 难定怕密度不均、高维失效计算太慢、不可撤销合并

# 降维

# 主成分分析

# 核心步骤

假设我们有 mm 个样本,每个样本有 nn 个特征(数据矩阵 XXm×nm \times n)。

  1. 去中心化 (Mean Centering)【必做】
    • 把数据的中心移到坐标原点。即每一列特征减去该列的均值。
    • 原因:如果不减均值,计算的协方差矩阵会出错。
  2. 计算协方差矩阵 (Covariance Matrix)
    • 我们需要知道特征之间是怎么相关的。
    • C=1m1XTXC = \frac{1}{m-1} X^T XCC 是一个 n×nn \times n 的对称矩阵)。
    • 矩阵对角线上的值是方差,非对角线是协方差
  3. 特征值分解 (Eigendecomposition)
    • 这是数学魔法发生的时刻。我们需要求出协方差矩阵 CC特征值 (λ\lambda)特征向量 (vv)
    • Cv=λvC v = \lambda v
  4. 排序与筛选
    • 特征向量 (vv):代表了新的坐标轴方向(主成分方向)。
    • 特征值 (λ\lambda):代表了在那个方向上数据的方差大小
    • 我们将 λ\lambda 从大到小排序,选取前 kk 个最大的 λ\lambda 对应的特征向量。
  5. 投影 (Projection)
    • 将原始数据 XX 乘以这 kk 个特征向量构成的矩阵 WW
    • Xnew=XWX_{new} = X \cdot W
    • 现在,数据从 nn 维降到了 kk 维。

# T-SNE

一句话总结:PCA 保留的是 “整体轮廓”(方差),t-SNE 保留的是 “局部邻里关系”。

# 算法原理:三步走

t-SNE 的名字里有三个关键词:t - 分布随机 (Stochastic)邻域 (Neighbor)

# 第一步:高维空间里的 “社交圈” (Gaussian)

在高维空间里,我们要衡量两个点 xix_ixjx_j 有多像。

t-SNE 假设数据符合高斯分布(正态分布)。

  • 如果 xjx_jxix_i 很近,那么 xix_i 选中 xjx_j 做邻居的概率 pjip_{j|i} 就很大。
  • 如果离得很远,概率就几乎为 0。
  • 这一步把距离转化成了概率
# 第二步:低维空间里的 “模仿秀” (t-Distribution)

我们在 2D 平面上随机撒一堆点 yi,yjy_i, y_j。我们希望这些点之间的概率分布 qjiq_{j|i} 能完美复刻高维空间里的 pjip_{j|i}

  • 重点:这里不用高斯分布,而是用 t - 分布(自由度为 1)
  • 为什么要换分布? 见下文 “拥挤问题”。
# 第三步:极小化差异 (KL Divergence)

现在我们有两套概率分布:PP(真身)和 QQ(替身)。

我们要让 QQ 尽可能像 PP

  • 使用 KL 散度 (Kullback-Leibler Divergence) 来衡量两个分布的差异。
  • 利用梯度下降,不断移动低维空间里的点 yy,直到 KL 散度最小。
    • 直观理解:如果两个点在高维本来很近,在低维却很远,KL 散度会很大,算法就会产生一个 “引力” 把它们拉近;反之则产生 “斥力”。

# 面试问题

  • Q: 为什么要用 “t - 分布”

这是 t-SNE 的灵魂所在。

拥挤问题 (The Crowding Problem):

高维空间极其巨大,而低维空间(2D)非常拥挤。想象一下,一个球体在高维空间里,它的表面积是随着维度指数增长的,但在 2D 平面上只有一点点地方。

如果你强行把高维数据压到 2D,原本中等距离的点会被迫挤在一起,破坏聚类效果。

t - 分布的解决方案:t - 分布相比高斯分布,是一个 **“长尾巴” (Heavy Tailed)** 的分布。

  • 这意味着:在低维空间里,为了表示同样的 “不相似度”,t-SNE 允许点与点之间隔得更远
  • 它给中等距离的点留出了 “缓冲空间”,避免了所有点都挤成一团。

# 问题

# 类别不平衡问题

  1. 对少样本进行过采样

  2. 对多样本进行降采样

  3. 阈值移动

更新于 阅读次数