02. 监督学习算法详解

线性回归、逻辑回归、决策树、集成学习、SVM 等核心监督学习算法的原理、实现与调优

监督学习是机器学习最广泛应用的范式。本文深入讲解从经典线性模型到现代梯度提升树的核心算法,包括数学原理、实现细节与调优策略。

1. 线性回归 (Linear Regression)

1.1 最小二乘法

假设目标 $y$ 与特征 $X$ 呈线性关系:$y = Xw + b$

目标是最小化均方误差 (MSE):

$$J(w) = \frac{1}{2n}\sum_{i=1}^{n}(y_i - \hat{y}_i)^2 = \frac{1}{2n}(y - Xw)^T(y - Xw)$$

解析解(正规方程):

$$w = (X^TX)^{-1}X^Ty$$

import numpy as np

# 正规方程实现
class LinearRegressionNormal:
    def fit(self, X, y):
        X_b = np.c_[np.ones((X.shape[0], 1)), X]  # 添加偏置列
        self.w = np.linalg.inv(X_b.T @ X_b) @ X_b.T @ y
    
    def predict(self, X):
        X_b = np.c_[np.ones((X.shape[0], 1)), X]
        return X_b @ self.w

# 梯度下降实现
class LinearRegressionGD:
    def __init__(self, lr=0.01, epochs=1000):
        self.lr = lr
        self.epochs = epochs
    
    def fit(self, X, y):
        n, m = X.shape
        self.w = np.zeros(m + 1)
        X_b = np.c_[np.ones((n, 1)), X]
        
        for _ in range(self.epochs):
            grad = (2/n) * X_b.T @ (X_b @ self.w - y)
            self.w -= self.lr * grad
    
    def predict(self, X):
        X_b = np.c_[np.ones((X.shape[0], 1)), X]
        return X_b @ self.w

1.2 梯度下降变体

方法更新方式优点缺点
批量 GD全数据集计算梯度稳定收敛大数据集慢
随机 GD单样本更新速度快,可逃离局部最优波动大
小批量 GDmini-batch (32-512)平衡速度与稳定性需调 batch size
# sklearn 实际使用解析解(小规模)或 SGD(大规模)
from sklearn.linear_model import LinearRegression, SGDRegressor

# 解析解
model = LinearRegression().fit(X_train, y_train)

# 大规模数据用 SGD
model = SGDRegressor(max_iter=1000, tol=1e-3, penalty='l2', alpha=0.0001)
model.fit(X_train, y_train)

2. 逻辑回归 (Logistic Regression)

2.1 Sigmoid 与对数几率

逻辑回归虽名"回归",实为分类算法。通过 Sigmoid 函数将线性输出映射到 (0,1) 概率:

$$\sigma(z) = \frac{1}{1 + e^{-z}}$$

$$P(y=1|x) = \sigma(w^Tx + b) = \frac{1}{1 + e^{-(w^Tx+b)}}$$

2.2 对数损失与梯度

交叉熵损失(对数损失):

$$J(w) = -\frac{1}{n}\sum_{i=1}^{n}[y_i\log(\hat{y}_i) + (1-y_i)\log(1-\hat{y}_i)]$$

梯度:

$$\frac{\partial J}{\partial w} = \frac{1}{n}X^T(\hat{y} - y)$$

from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler

# 逻辑回归需先标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

model = LogisticRegression(
    penalty='l2',        # 正则化类型
    C=1.0,               # 正则化强度倒数,越大正则越弱
    solver='lbfgs',      # 优化算法
    max_iter=1000,
    class_weight='balanced'  # 处理类别不平衡
)
model.fit(X_train_scaled, y_train)

# 预测概率
proba = model.predict_proba(X_test_scaled)[:, 1]

2.3 多项逻辑回归(多分类)

# softmax 多分类
model = LogisticRegression(
    multi_class='multinomial',  # softmax 而非 one-vs-rest
    solver='lbfgs',
    max_iter=1000
)

3. 决策树 (Decision Tree)

3.1 分裂准则

信息增益(ID3):基于熵的减少

$$H(S) = -\sum p_i \log_2(p_i)$$

$$IG(S, A) = H(S) - \sum_{v \in Values(A)} \frac{|S_v|}{|S|}H(S_v)$$

基尼指数(CART)

$$Gini(S) = 1 - \sum p_i^2$$

from sklearn.tree import DecisionTreeClassifier, export_text, plot_tree
import matplotlib.pyplot as plt

model = DecisionTreeClassifier(
    criterion='gini',      # 'gini' 或 'entropy'
    max_depth=5,           # 最大深度,防过拟合
    min_samples_split=20,  # 分裂最小样本数
    min_samples_leaf=10,   # 叶子最小样本数
    max_features='sqrt',   # 每次分裂考虑的特征数
    random_state=42
)
model.fit(X_train, y_train)

# 可视化
tree_rules = export_text(model, feature_names=list(X.columns))
print(tree_rules)

plt.figure(figsize=(20, 10))
plot_tree(model, feature_names=X.columns, filled=True, rounded=True)
plt.savefig('tree.png')

3.2 特征重要性

importances = pd.Series(model.feature_importances_, index=X.columns)
importances.sort_values(ascending=False).plot(kind='barh')

4. 集成学习

4.1 Bagging:随机森林

Bagging(Bootstrap Aggregating):有放回抽样训练多个模型,投票/平均预测。

from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor

# 随机森林分类
rf = RandomForestClassifier(
    n_estimators=200,        # 树的数量
    max_depth=10,
    min_samples_split=5,
    max_features='sqrt',     # 每棵树随机选 sqrt(n_features) 个特征
    bootstrap=True,          # 有放回抽样
    oob_score=True,          # 使用 out-of-bag 样本评估
    n_jobs=-1,               # 并行
    random_state=42
)
rf.fit(X_train, y_train)
print(f"OOB Score: {rf.oob_score_:.3f}")

# 特征重要性
importances = pd.DataFrame({
    'feature': X.columns,
    'importance': rf.feature_importances_
}).sort_values('importance', ascending=False)

4.2 Boosting:AdaBoost

每轮迭代调整样本权重,使先前错分的样本获得更多关注。

from sklearn.ensemble import AdaBoostClassifier

ada = AdaBoostClassifier(
    estimator=DecisionTreeClassifier(max_depth=1),  # 弱分类器(决策树桩)
    n_estimators=100,
    learning_rate=1.0
)
ada.fit(X_train, y_train)

4.3 Gradient Boosting

每棵新树拟合前面所有树的残差(负梯度):

$$F_m(x) = F_{m-1}(x) + \eta \cdot h_m(x)$$

from sklearn.ensemble import GradientBoostingClassifier

gb = GradientBoostingClassifier(
    n_estimators=100,
    learning_rate=0.1,       # 收缩系数,越小越稳健
    max_depth=3,             # 树深度,通常 3-8
    subsample=0.8,           # 每次迭代抽样比例(随机梯度提升)
    random_state=42
)
gb.fit(X_train, y_train)

4.4 XGBoost

工业界最常用的梯度提升框架,优化了计算效率和正则化。

import xgboost as xgb

# 原生接口
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)

params = {
    'objective': 'binary:logistic',  # 或 'multi:softmax', 'reg:squarederror'
    'max_depth': 6,
    'learning_rate': 0.1,
    'subsample': 0.8,
    'colsample_bytree': 0.8,
    'reg_alpha': 0.1,        # L1
    'reg_lambda': 1.0,       # L2
    'eval_metric': 'auc'
}

model = xgb.train(
    params,
    dtrain,
    num_boost_round=100,
    evals=[(dtrain, 'train'), (dtest, 'test')],
    early_stopping_rounds=10
)

# sklearn 风格接口
from xgboost import XGBClassifier

xgb_model = XGBClassifier(
    n_estimators=100,
    max_depth=6,
    learning_rate=0.1,
    subsample=0.8,
    colsample_bytree=0.8,
    reg_alpha=0.1,
    random_state=42,
    n_jobs=-1
)
xgb_model.fit(X_train, y_train, 
              eval_set=[(X_test, y_test)],
              early_stopping_rounds=10,
              verbose=False)

4.5 LightGBM

微软提出的高效梯度提升框架,使用直方图算法和 Leaf-wise 生长策略。

import lightgbm as lgb

lgb_model = lgb.LGBMClassifier(
    n_estimators=100,
    max_depth=-1,           # 无限制,由 min_child_samples 控制
    learning_rate=0.1,
    num_leaves=31,          # 叶子节点数,控制复杂度
    subsample=0.8,
    colsample_bytree=0.8,
    reg_alpha=0.1,
    random_state=42
)
lgb_model.fit(X_train, y_train,
              eval_set=[(X_test, y_test)],
              callbacks=[lgb.early_stopping(10, verbose=False)])

XGBoost vs LightGBM vs CatBoost

特性XGBoostLightGBMCatBoost
树生长Level-wiseLeaf-wiseSymmetric
类别特征需预处理需预处理原生支持
速度更快
内存较低更低中等
过拟合中等需注意较低

5. 支持向量机 (SVM)

5.1 最大间隔分类器

SVM 寻找使间隔最大化的超平面。引入松弛变量处理非线性可分:

$$\min_{w,b,\xi} \frac{1}{2}|w|^2 + C\sum\xi_i$$

约束:$y_i(w^Tx_i + b) \geq 1 - \xi_i$

from sklearn.svm import SVC, LinearSVC

# 线性 SVM(大规模数据)
linear_svc = LinearSVC(C=1.0, max_iter=5000)
linear_svc.fit(X_train_scaled, y_train)

# 核 SVM
rbf_svc = SVC(
    kernel='rbf',         # 'linear', 'poly', 'rbf', 'sigmoid'
    C=1.0,                # 惩罚系数
    gamma='scale',        # 核函数系数
    probability=True      # 启用概率输出(训练 Platt Scaling,较耗时)
)
rbf_svc.fit(X_train_scaled, y_train)

# 预测概率
proba = rbf_svc.predict_proba(X_test_scaled)

5.2 核技巧

核函数公式适用场景
线性$K(x, y) = x^Ty$高维稀疏数据(文本)
多项式$K(x, y) = (\gamma x^Ty + r)^d$图像处理
RBF$K(x, y) = \exp(-\gamma|x-y|^2)$通用,非线性边界
Sigmoid$\tanh(\gamma x^Ty + r)$类似神经网络

注意:SVM 对特征缩放敏感,必须标准化。

6. K 近邻 (KNN)

from sklearn.neighbors import KNeighborsClassifier

knn = KNeighborsClassifier(
    n_neighbors=5,
    weights='distance',  # 'uniform' 等权重,'distance' 按距离加权
    metric='minkowski',  # 距离度量
    p=2                  # p=2 为欧氏距离,p=1 为曼哈顿
)
knn.fit(X_train_scaled, y_train)  # KNN 实际是惰性学习,fit 只存储数据

7. 朴素贝叶斯

基于特征条件独立假设的概率分类器,文本分类首选。

from sklearn.naive_bayes import GaussianNB, MultinomialNB

# 连续特征用高斯分布
model = GaussianNB()

# 离散计数特征用多项式分布(如词频)
model = MultinomialNB(alpha=1.0)  # Laplace 平滑
model.fit(X_train, y_train)

8. 算法选择速查

场景推荐算法理由
快速基线逻辑回归快、可解释、概率输出
小规模高维线性 SVM、Lasso在高维空间表现好
表格数据竞赛XGBoost/LightGBM通常 SOTA
需可解释决策树、逻辑回归规则透明
类别不平衡调 class_weight 的 GBM内置处理
大规模实时线性模型 + SGDO(1) 预测,增量训练
缺失值多XGBoost、LightGBM自动处理缺失
非结构化数据神经网络图像/文本/语音

9. 超参数调优

9.1 网格搜索与随机搜索

from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
from scipy.stats import uniform, randint

# 网格搜索
param_grid = {
    'max_depth': [3, 5, 7],
    'learning_rate': [0.01, 0.1, 0.3],
    'n_estimators': [100, 200]
}
grid = GridSearchCV(
    XGBClassifier(random_state=42),
    param_grid,
    cv=5,
    scoring='f1_macro',
    n_jobs=-1,
    verbose=1
)
grid.fit(X_train, y_train)
print(f"最优参数: {grid.best_params_}")

# 随机搜索(更高效)
param_dist = {
    'max_depth': randint(3, 10),
    'learning_rate': uniform(0.01, 0.3),
    'subsample': uniform(0.6, 0.4),
    'colsample_bytree': uniform(0.6, 0.4)
}
random = RandomizedSearchCV(
    XGBClassifier(random_state=42),
    param_dist,
    n_iter=50,  # 采样 50 组参数
    cv=5,
    scoring='f1_macro',
    n_jobs=-1,
    random_state=42
)

9.2 Optuna 贝叶斯优化

import optuna

def objective(trial):
    params = {
        'max_depth': trial.suggest_int('max_depth', 3, 10),
        'learning_rate': trial.suggest_float('learning_rate', 0.01, 0.3),
        'n_estimators': trial.suggest_int('n_estimators', 50, 300),
        'subsample': trial.suggest_float('subsample', 0.6, 1.0),
        'colsample_bytree': trial.suggest_float('colsample_bytree', 0.6, 1.0),
        'reg_alpha': trial.suggest_float('reg_alpha', 0, 1),
        'reg_lambda': trial.suggest_float('reg_lambda', 0, 1)
    }
    
    model = XGBClassifier(**params, random_state=42, n_jobs=-1)
    scores = cross_val_score(model, X_train, y_train, cv=5, scoring='f1_macro')
    return scores.mean()

study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=100, show_progress_bar=True)
print(f"最优参数: {study.best_params}")
print(f"最优得分: {study.best_value:.3f}")

总结

算法类型核心思想调参重点
线性回归回归最小二乘无(或正则化强度)
逻辑回归分类对数几率、交叉熵C(正则化)、solver
决策树两者递归分裂最优特征max_depth、min_samples
随机森林两者Bagging + 随机特征n_estimators、max_depth
XGBoost两者梯度提升 + 正则化n_estimators、eta、max_depth、subsample
SVM分类最大间隔 + 核技巧C、kernel、gamma
朴素贝叶斯分类条件独立假设alpha(平滑系数)

实际工程中,XGBoost/LightGBM 是结构化数据的首选;逻辑回归/SVM 适合快速基线与可解释需求;随机森林 是稳健的多用途选择。超参数调优先用随机搜索缩小范围,再用贝叶斯优化精细搜索。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「ai-ml」更多文章

  1. 13. 大语言模型应用开发
  2. 12. MLOps 与实验管理
  3. 11. 模型部署与推理优化