第 4 章 / 共 8 章

第4章:经典算法

本章将详细介绍机器学习中最重要的经典算法,包括监督学习、集成学习和无监督学习的核心方法。每种算法都包含原理简述、适用场景、优缺点分析和Python代码示例。

4.1 监督学习算法

4.1.1 线性回归 (Linear Regression)

维度 说明
原理简述 假设目标变量与特征之间存在线性关系,通过最小化预测值与真实值之间的均方误差(MSE)来拟合最佳直线:y = w₁x₁ + w₂x₂ + ... + wₙxₙ + b
适用场景 房价预测、销售预测、趋势分析、连续数值预测任务
优点 简单易懂、计算高效、可解释性强、不容易过拟合
缺点 只能拟合线性关系、对异常值敏感、假设特征间相互独立
# 线性回归示例
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np

# 生成示例数据:学习时间与考试成绩的关系
np.random.seed(42)
study_hours = np.random.uniform(1, 10, 100).reshape(-1, 1)
scores = 50 + 5 * study_hours.ravel() + np.random.normal(0, 5, 100)

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
    study_hours, scores, test_size=0.2, random_state=42
)

# 创建并训练模型
model = LinearRegression()
model.fit(X_train, y_train)

# 预测与评估
y_pred = model.predict(X_test)
print(f"R² Score: {r2_score(y_test, y_pred):.4f}")
print(f"RMSE: {np.sqrt(mean_squared_error(y_test, y_pred)):.4f}")
print(f"回归系数: {model.coef_[0]:.2f}")
print(f"截距: {model.intercept_:.2f}")

4.1.2 逻辑回归 (Logistic Regression)

维度 说明
原理简述 使用Sigmoid函数将线性回归的输出映射到[0,1]区间,表示概率:P(y=1|x) = 1 / (1 + e^-(wx+b))。通过最大似然估计求解参数。
适用场景 二分类问题(是/否)、广告点击率预测、疾病诊断、信用评分
优点 输出概率值、训练速度快、可解释性强(特征权重)、不易过拟合
缺点 只能处理线性可分问题、对特征工程依赖较大、多分类需特殊处理
# 逻辑回归示例
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import accuracy_score, classification_report

# 加载乳腺癌数据集
data = load_breast_cancer()
X, y = data.data, data.target

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 创建模型(增加迭代次数防止不收敛警告)
model = LogisticRegression(max_iter=1000, random_state=42)
model.fit(X_train, y_train)

# 预测与评估
y_pred = model.predict(X_test)
print(f"准确率: {accuracy_score(y_test, y_pred):.4f}")
print("\n分类报告:")
print(classification_report(y_test, y_pred, target_names=['恶性', '良性']))

4.1.3 决策树 (Decision Tree)

维度 说明
原理简述 通过递归地选择最优特征进行数据分割,构建树形结构。分类树使用信息增益/基尼指数,回归树使用均方误差来选择分裂点。
适用场景 需要强可解释性的场景、特征有明确业务含义、混合类型数据
优点 直观可解释、无需特征缩放、可处理非线性关系、能处理缺失值
缺点 容易过拟合、对数据变化敏感、可能产生偏向性(偏向取值多的特征)
# 决策树示例(带可视化)
from sklearn.tree import DecisionTreeClassifier, export_text, plot_tree
import matplotlib.pyplot as plt

# 使用鸢尾花数据集简化版(仅2个特征便于可视化)
from sklearn.datasets import load_iris
iris = load_iris()
X, y = iris.data[:, :2], iris.target  # 只取前2个特征

# 创建决策树模型(限制深度防止过拟合)
model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X, y)

# 文本形式展示树结构
print("决策树规则:")
print(export_text(model, feature_names=['花瓣长度', '花瓣宽度']))

# 可视化(需要matplotlib)
plt.figure(figsize=(20, 10))
plot_tree(model, feature_names=['花瓣长度', '花瓣宽度'], 
          class_names=iris.target_names, filled=True, rounded=True)
plt.title('决策树可视化')
plt.savefig('decision_tree.png', dpi=150, bbox_inches='tight')
plt.show()
决策树可视化解读:每个节点显示分裂条件、基尼系数/熵、样本数和类别分布。颜色越深表示该类纯度越高。叶子节点给出最终预测结果。

4.1.4 支持向量机 (SVM)

维度 说明
原理简述 寻找最优超平面使不同类别的间隔最大化。通过核函数(Kernel)将数据映射到高维空间处理非线性问题。支持向量是距离超平面最近的样本点。
适用场景 高维数据分类、图像识别、文本分类、小样本学习
优点 泛化能力强、适合高维数据、通过核函数处理非线性、最终模型只依赖支持向量
缺点 大规模数据训练慢、对参数敏感、核函数选择困难、黑盒模型难解释
# SVM示例
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler

# 数据标准化(SVM对特征尺度敏感)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 创建SVM模型(RBF核)
model = SVC(kernel='rbf', C=1.0, gamma='scale', random_state=42)
model.fit(X_train_scaled, y_train)

# 预测
y_pred = model.predict(X_test_scaled)
print(f"准确率: {accuracy_score(y_test, y_pred):.4f}")

# 使用线性核对比
model_linear = SVC(kernel='linear', random_state=42)
model_linear.fit(X_train_scaled, y_train)
print(f"线性核准确率: {accuracy_score(y_test, model_linear.predict(X_test_scaled)):.4f}")

4.1.5 K近邻 (KNN)

维度 说明
原理简述 懒惰学习算法,没有显式的训练过程。预测时找到测试样本的K个最近邻居,分类问题采用投票法,回归问题采用平均值。
适用场景 小数据集、低维数据、推荐系统、异常检测
优点 简单直观、无需训练、对数据分布无假设、适合多分类
缺点 预测慢(需遍历所有样本)、维度灾难、对异常值敏感、需要大量内存
# KNN示例
from sklearn.neighbors import KNeighborsClassifier

# 创建KNN模型(K=5,使用欧氏距离)
model = KNeighborsClassifier(n_neighbors=5, metric='euclidean')
model.fit(X_train, y_train)

# 预测
y_pred = model.predict(X_test)
print(f"K=5 准确率: {accuracy_score(y_test, y_pred):.4f}")

# 寻找最优K值
from sklearn.model_selection import cross_val_score

k_range = range(1, 31)
cv_scores = []
for k in k_range:
    knn = KNeighborsClassifier(n_neighbors=k)
    scores = cross_val_score(knn, X_train, y_train, cv=5, scoring='accuracy')
    cv_scores.append(scores.mean())

optimal_k = k_range[np.argmax(cv_scores)]
print(f"最优K值: {optimal_k}, 交叉验证准确率: {max(cv_scores):.4f}")

4.1.6 朴素贝叶斯 (Naive Bayes)

维度 说明
原理简述 基于贝叶斯定理,假设特征之间相互独立("朴素"的来源)。计算后验概率 P(y|x) 选择最大概率的类别。核心公式:P(y|x) ∝ P(y) × Π P(xᵢ|y)
适用场景 文本分类(垃圾邮件、情感分析)、文档分类、实时预测系统
优点 训练速度极快、对缺失值不敏感、适合高维数据、对小样本效果好
缺点 特征独立性假设往往不成立、概率估计可能不准确、对输入数据分布敏感
# 朴素贝叶斯 - 文本分类示例
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline

# 示例数据
reviews = [
    "这部电影太精彩了,强烈推荐",
    "完全浪费时间,剧情老套",
    "演员演技出色,值得一看",
    "特效很差,故事无聊",
    "这是我今年看过最好的电影",
    "太失望了,根本不值得票价"
]
labels = [1, 0, 1, 0, 1, 0]  # 1=正面, 0=负面

# 构建管道
pipeline = Pipeline([
    ('tfidf', TfidfVectorizer()),
    ('nb', MultinomialNB())
])

pipeline.fit(reviews, labels)

# 预测新评论
new_reviews = ["故事很棒,演员表现出色", "完全看不懂,太无聊了"]
predictions = pipeline.predict(new_reviews)
for review, pred in zip(new_reviews, predictions):
    sentiment = "正面" if pred == 1 else "负面"
    print(f"评论: {review} -> {sentiment}")

4.2 集成学习

集成学习(Ensemble Learning)的核心思想是"三个臭皮匠,顶个诸葛亮"——通过组合多个基学习器的预测结果,获得比单一模型更好的性能。

4.2.1 集成学习算法对比

算法 核心原理 基学习器 集成方式 特点 适用场景
随机森林 Bagging思想,多棵决策树并行训练,随机选择特征和样本 决策树 投票/平均 并行训练、抗过拟合、特征重要性 通用场景、特征选择
AdaBoost Boosting思想,串行训练,重点学习前序模型分错的样本 弱学习器 加权投票 关注难样本、容易过拟合 二分类、基线模型
XGBoost 梯度提升+正则化,使用二阶泰勒展开优化目标函数 决策树 加法模型 速度快、精度高、支持并行、功能丰富 竞赛首选、表格数据
LightGBM 基于直方图的决策树算法,叶子优先分裂策略 决策树 加法模型 训练极快、内存高效、大数据首选 大规模数据、实时预测

4.2.2 随机森林 (Random Forest)

# 随机森林示例
from sklearn.ensemble import RandomForestClassifier

# 创建随机森林模型
model = RandomForestClassifier(
    n_estimators=100,    # 树的数量
    max_depth=10,        # 最大深度
    min_samples_split=5, # 节点分裂最小样本数
    random_state=42,
    n_jobs=-1            # 使用所有CPU核心
)
model.fit(X_train, y_train)

# 预测与评估
y_pred = model.predict(X_test)
print(f"准确率: {accuracy_score(y_test, y_pred):.4f}")

# 特征重要性
importances = model.feature_importances_
for i, imp in enumerate(importances):
    print(f"特征 {i}: 重要性 {imp:.4f}")

4.2.3 XGBoost

# XGBoost示例(需安装: pip install xgboost)
import xgboost as xgb
from sklearn.datasets import load_breast_cancer

# 加载数据
data = load_breast_cancer()
X, y = data.data, data.target
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 转换为DMatrix(XGBoost专用数据结构)
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)

# 设置参数
params = {
    'objective': 'binary:logistic',
    'max_depth': 6,
    'learning_rate': 0.1,
    'n_estimators': 100,
    'subsample': 0.8,
    'colsample_bytree': 0.8,
    'eval_metric': 'auc'
}

# 训练模型
model = xgb.XGBClassifier(**params, random_state=42)
model.fit(X_train, y_train)

# 预测与评估
y_pred = model.predict(X_test)
print(f"准确率: {accuracy_score(y_test, y_pred):.4f}")

# 特征重要性可视化
xgb.plot_importance(model, max_num_features=10)
plt.show()

4.2.4 LightGBM

# LightGBM示例(需安装: pip install lightgbm)
import lightgbm as lgb

# 创建数据集
train_data = lgb.Dataset(X_train, label=y_train)
valid_data = lgb.Dataset(X_test, label=y_test, reference=train_data)

# 设置参数
params = {
    'objective': 'binary',
    'metric': 'auc',
    'boosting_type': 'gbdt',
    'num_leaves': 31,
    'learning_rate': 0.05,
    'feature_fraction': 0.9,
    'bagging_fraction': 0.8,
    'bagging_freq': 5,
    'verbose': -1
}

# 训练模型
model = lgb.train(
    params,
    train_data,
    num_boost_round=100,
    valid_sets=[valid_data],
    callbacks=[lgb.early_stopping(stopping_rounds=10), lgb.log_evaluation(0)]
)

# 预测
y_pred = (model.predict(X_test) > 0.5).astype(int)
print(f"准确率: {accuracy_score(y_test, y_pred):.4f}")
集成学习选择建议:
  • 快速原型:随机森林,参数少、效果稳定
  • 竞赛/高精度:XGBoost或LightGBM
  • 大规模数据:LightGBM速度最快
  • 特征分析:随机森林的特征重要性功能

4.3 无监督学习算法

4.3.1 聚类算法对比

算法 核心原理 优点 缺点
K-Means 迭代优化,将样本分配到最近的质心,然后更新质心位置,直到收敛 简单高效、可扩展性好、时间复杂度O(n) 需预设K值、对初始值敏感、假设球形簇
层次聚类 自底向上(凝聚)或自顶向下(分裂),逐步合并/分裂簇 无需预设K值、输出树状图、可解释性强 计算复杂度高O(n²)、对噪声敏感
DBSCAN 基于密度,将高密度区域划分为簇,可识别噪声点 自动识别簇数量、发现任意形状簇、抗噪声 对参数敏感、密度不均时效果差

4.3.2 K-Means

# K-Means聚类示例
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt

# 生成模拟数据
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.6, random_state=42)

# 肘部法则确定K值
inertias = []
K_range = range(1, 10)
for k in K_range:
    kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
    kmeans.fit(X)
    inertias.append(kmeans.inertia_)

# 绘制肘部图
plt.figure(figsize=(8, 4))
plt.plot(K_range, inertias, 'bo-')
plt.xlabel('K值')
plt.ylabel('惯性(簇内平方和)')
plt.title('肘部法则')
plt.show()

# 使用最优K值聚类
optimal_k = 4
kmeans = KMeans(n_clusters=optimal_k, random_state=42, n_init=10)
labels = kmeans.fit_predict(X)

# 可视化结果
plt.figure(figsize=(8, 6))
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', alpha=0.6)
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], 
            marker='X', s=200, c='red', label='质心')
plt.legend()
plt.title(f'K-Means聚类结果 (K={optimal_k})')
plt.show()

4.3.3 层次聚类

# 层次聚类示例
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import dendrogram, linkage

# 凝聚聚类
model = AgglomerativeClustering(n_clusters=3, linkage='ward')
labels = model.fit_predict(X)

# 绘制树状图(需scipy)
linked = linkage(X[:50], 'ward')  # 取子集便于展示
plt.figure(figsize=(10, 5))
dendrogram(linked, orientation='top', distance_sort='descending')
plt.title('层次聚类树状图')
plt.show()

4.3.4 DBSCAN

# DBSCAN示例
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_moons

# 生成月牙形数据(K-Means难以处理)
X, _ = make_moons(n_samples=300, noise=0.05, random_state=42)

# K-Means效果
kmeans = KMeans(n_clusters=2, random_state=42, n_init=10)
kmeans_labels = kmeans.fit_predict(X)

# DBSCAN效果
dbscan = DBSCAN(eps=0.3, min_samples=5)
dbscan_labels = dbscan.fit_predict(X)

# 可视化对比
fig, axes = plt.subplots(1, 2, figsize=(12, 5))

axes[0].scatter(X[:, 0], X[:, 1], c=kmeans_labels, cmap='viridis')
axes[0].set_title('K-Means(效果不佳)')

axes[1].scatter(X[:, 0], X[:, 1], c=dbscan_labels, cmap='viridis')
axes[1].set_title('DBSCAN(正确识别)')

plt.tight_layout()
plt.show()

print(f"DBSCAN发现簇数: {len(set(dbscan_labels)) - (1 if -1 in dbscan_labels else 0)}")
print(f"噪声点数量: {list(dbscan_labels).count(-1)}")

4.3.5 降维方法对比

方法 核心原理 优点 缺点
PCA 线性变换,寻找方差最大的正交方向(主成分),保留最大信息量 计算高效、无参数、去相关、降噪 仅捕捉线性关系、对异常值敏感
t-SNE 非线性降维,保持局部邻域结构,高维相似点映射到低维也相似 可视化效果极佳、保留局部结构 计算慢、结果随机、不保持全局结构

4.3.6 PCA

# PCA示例
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris

# 加载数据
iris = load_iris()
X, y = iris.data, iris.target

# 应用PCA
pca = PCA(n_components=2)  # 降至2维
X_pca = pca.fit_transform(X)

# 可视化
plt.figure(figsize=(8, 6))
for i, target_name in enumerate(iris.target_names):
    plt.scatter(X_pca[y == i, 0], X_pca[y == i, 1], label=target_name, alpha=0.7)
plt.xlabel(f'第一主成分 ({pca.explained_variance_ratio_[0]:.2%})')
plt.ylabel(f'第二主成分 ({pca.explained_variance_ratio_[1]:.2%})')
plt.legend()
plt.title('PCA降维可视化')
plt.show()

print(f"总方差解释率: {sum(pca.explained_variance_ratio_):.2%}")
print(f"主成分数量(全部): {PCA().fit(X).n_components_}")

4.3.7 t-SNE

# t-SNE示例
from sklearn.manifold import TSNE
from sklearn.datasets import load_digits

# 加载手写数字数据集(64维)
digits = load_digits()
X, y = digits.data[:500], digits.target[:500]  # 取子集加速

# 应用t-SNE
tsne = TSNE(n_components=2, random_state=42, perplexity=30)
X_tsne = tsne.fit_transform(X)

# 可视化
plt.figure(figsize=(10, 8))
scatter = plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y, cmap='tab10', alpha=0.6)
plt.colorbar(scatter, label='数字')
plt.title('t-SNE: 手写数字可视化 (0-9)')
plt.show()
降维方法选择建议:
  • 特征压缩/预处理:使用PCA,可逆变换且保留全局结构
  • 数据可视化:使用t-SNE或UMAP,视觉效果更好
  • 大数据集:先用PCA降维,再用t-SNE可视化
算法速查表:
任务类型推荐算法
回归问题线性回归、随机森林回归、XGBoost
二分类逻辑回归、SVM、XGBoost
多分类随机森林、Softmax回归、XGBoost
文本分类朴素贝叶斯、逻辑回归
聚类分析K-Means、DBSCAN、层次聚类
降维可视化PCA、t-SNE
竞赛/高精度XGBoost、LightGBM

本章详细介绍了机器学习的经典算法,从基础的线性回归到强大的集成学习方法,再到无监督学习的聚类和降维技术。掌握这些算法后,你将能够应对大多数机器学习任务。下一章我们将进入深度学习的世界。