机器学习核心算法全解:从小白到实战,一文掌握十大经典算法

本文系统梳理了机器学习的核心知识体系,涵盖监督学习、无监督学习、集成学习等十大经典算法,并配有完整可运行的Python代码示例。无论你是刚入门的大一新生,还是正在系统复习的AI从业者,这篇文章都能帮你构建完整的机器学习知识框架。


文章目录


一、机器学习概述

1.1 人工智能、机器学习与深度学习的关系

在进入具体算法之前,先理清三个核心概念:

  • 人工智能(AI, Artificial Intelligence):让机器像人一样思考和行动,是最终目标。
  • 机器学习(ML, Machine Learning):实现AI的一种途径,让机器从数据中自动学习规律,而不依赖特定规则编程。
  • 深度学习(DL, Deep Learning):机器学习的一种方法,通过多层神经网络模拟人脑工作方式。

三者的关系是逐层包含的:AI ⊃ ML ⊃ DL。

1.2 两种学习范式

对比维度 基于规则的学习 基于模型的学习(机器学习)
实现方式 手工编写if-else规则 从数据中自动学习规律
适用场景 规则明确的简单问题 图像识别、NLP等复杂问题
灵活性 差,规则变了需要重写 强,重新训练即可

1.3 机器学习的分类

有监督学习(Supervised Learning):训练数据有标签,目标是学习特征到标签的映射。

  • 分类(Classification):标签是离散值。如:垃圾邮件识别(二分类)、手写数字识别(多分类)。
  • 回归(Regression):标签是连续值。如:房价预测、股票预测。

无监督学习(Unsupervised Learning):训练数据无标签,目标是发现数据内在结构。

  • 聚类(Clustering):将相似样本归为一组。如:用户分群、异常检测。

半监督学习:少量标注数据 + 大量未标注数据,先用少量标注数据训练模型,再在大量未标注数据上测试和调整,降低标注成本。

强化学习:通过Agent与环境交互,获得奖励信号来学习策略(模型会趋向于奖励最大化)。如:AlphaGo、无人驾驶。

1.4 核心术语

  • 样本(Sample):一行数据即为一个样本,多个样本构成数据集。
  • 特征(Feature):一列数据即为一个特征,也称为属性。如房价预测中的面积、楼层、地段。
  • 标签(Label/Target):模型要预测的那一列。如房价。
  • 训练集:用于训练模型的数据,通常占70%-80%。
  • 测试集:用于评估模型性能的数据,通常占20%-30%。

1.5 机器学习开发流程

加载数据 → 数据预处理 → 特征工程 → 模型训练 → 模型预测 → 模型评估

二、特征工程与模型拟合

数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已,所以特征工程和数据预处理非常重要。

2.1 特征工程四大方向

  • 特征提取:将原始数据(文本、图片)转换为结构化行列数据。
  • 特征预处理:通过归一化/标准化消除量纲影响,使不同特征对模型产生较为一致的影响。
  • 特征降维:在保留主要信息的前提下减少特征维度。
  • 特征选择:从原始特征中选取对任务最有用的特征子集。

2.2 归一化与标准化

归一化(Min-Max Scaling):将数据映射到 [0, 1] 区间。适合精确小数据场景,但对异常值敏感。

from sklearn.preprocessing import MinMaxScaler

# 数据归一化
scaler = MinMaxScaler(feature_range=(0, 1))
data_normalized = scaler.fit_transform(data)

标准化(Standardization):将数据转换为均值为0、标准差为1的标准正态分布。对异常值鲁棒性更强,是更常用的方法。

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
data_standardized = scaler.fit_transform(data)

2.3 欠拟合与过拟合

问题 表现 原因 解决方案
欠拟合 训练集和测试集表现都差 模型过于简单 增加特征、增加模型复杂度
过拟合 训练集表现好,测试集差 模型过于复杂、数据量少 正则化、增加数据、减少特征

泛化能力:模型在新数据集上的表现能力。奥卡姆剃刀原则告诉我们——在泛化误差相当的模型中,越简单的模型越好。

2.4 L1和L2正则化

正则化通过在损失函数中加入惩罚项来限制模型复杂度:

L1正则化(Lasso回归)
L = L ( W ) + λ ∑ i = 1 n ∣ w i ∣ L = L(W) + \lambda \sum_{i=1}^{n} |w_i| L=L(W)+λi=1nwi

  • 可以产生稀疏解(部分权重变为0),实现特征选择
  • API:sklearn.linear_model.Lasso

L2正则化(Ridge回归)
L = L ( W ) + λ ∑ i = 1 n w i 2 L = L(W) + \lambda \sum_{i=1}^{n} w_i^2 L=L(W)+λi=1nwi2

  • 让权重趋近于0但不等于0,防止过拟合
  • API:sklearn.linear_model.Ridge
import numpy as np
from sklearn.linear_model import Lasso, Ridge

# 模拟数据
np.random.seed(666)
x = np.random.uniform(-3, 3, size=100)
y = 0.5 * x ** 2 + x + 2 + np.random.normal(0, 1, size=100)

X = x.reshape(-1, 1)
X_poly = np.hstack([X, X**2, X**3, X**4, X**5, X**6, X**7, X**8, X**9, X**10])

# L1正则化
lasso = Lasso(alpha=0.1)
lasso.fit(X_poly, y)
print(f'L1权重: {lasso.coef_}')   # 部分权重为0

# L2正则化
ridge = Ridge(alpha=10)
ridge.fit(X_poly, y)
print(f'L2权重: {ridge.coef_}')   # 所有权重趋近0但不为0

三、K近邻算法(KNN)

3.1 算法思想

KNN的核心思想非常朴素:近朱者赤,近墨者黑——一个样本的类别由其 K 个最近邻居的类别决定。

3.2 距离度量

距离 公式 特点
欧氏距离 d = ∑ i = 1 n ( x i − y i ) 2 d = \sqrt{\sum_{i=1}^{n}(x_i - y_i)^2} d=i=1n(xiyi)2 最常用,直线距离
曼哈顿距离 $d = \sum_{i=1}^{n} x_i - y_i
切比雪夫距离 $d = \max( x_i - y_i
闵氏距离 $d = (\sum x_i - y_i

3.3 分类与回归流程

分类问题

  1. 计算待测样本到所有训练样本的距离
  2. 按距离升序排列
  3. 取最近 K 个样本
  4. 多数表决——出现次数最多的类别即为预测结果

回归问题

  1. 同上步骤1-3
  2. 取 K 个样本目标值的平均值作为预测结果

3.4 K值的选择

  • K 太小:容易受噪声影响,过拟合
  • K 太大:容易受其他类别样本影响,欠拟合
  • 通常使用交叉验证 + 网格搜索来确定最优 K 值

3.5 实战:鸢尾花分类

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier

# 1. 加载数据
iris = load_iris()

# 2. 数据集划分
x_train, x_test, y_train, y_test = train_test_split(
    iris.data, iris.target, test_size=0.2, random_state=22
)

# 3. 数据标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

# 4. 交叉验证 + 网格搜索 寻找最优K值
estimator = KNeighborsClassifier()
param_grid = {"n_neighbors": range(1, 10)}
estimator = GridSearchCV(estimator, param_grid, cv=5)
estimator.fit(x_train, y_train)

print(f'最优参数: {estimator.best_params_}')  # 输出最优K值
print(f'最优交叉验证得分: {estimator.best_score_:.4f}')

# 5. 模型评估
y_predict = estimator.predict(x_test)
print(f'测试集准确率: {estimator.score(x_test, y_test):.4f}')

3.6 交叉验证与网格搜索

交叉验证:将训练集划分为 n 份,轮流用其中 n-1 份训练、1 份验证,取平均得分作为评估结果。

网格搜索:遍历预设的超参数组合,结合交叉验证,找到使模型表现最优的超参数。

from sklearn.model_selection import GridSearchCV

# 网格搜索本质:自动遍历参数组合,找到最优
estimator = GridSearchCV(
    estimator=KNeighborsClassifier(),
    param_grid={"n_neighbors": range(1, 10)},
    cv=5  # 5折交叉验证
)

四、线性回归

4.1 什么是线性回归

线性回归利用回归方程对一个或多个自变量(特征)与因变量(目标值)之间的关系进行建模。

  • 一元线性回归 y = w x + b y = wx + b y=wx+b
  • 多元线性回归 y = w 1 x 1 + w 2 x 2 + . . . + w n x n + b = w T x + b y = w_1x_1 + w_2x_2 + ... + w_nx_n + b = w^Tx + b y=w1x1+w2x2+...+wnxn+b=wTx+b

其中,w 称为权重(Weight),b 称为偏置(Bias)。机器学习的目标就是学习最优的 w 和 b。

4.2 损失函数

损失函数衡量预测值与真实值之间的差距:

损失函数 公式 说明
MSE(均方误差) M S E = 1 m ∑ i = 1 m ( y i − y ^ i ) 2 MSE = \frac{1}{m}\sum_{i=1}^{m}(y_i - \hat{y}_i)^2 MSE=m1i=1m(yiy^i)2 最常用
RMSE(均方根误差) R M S E = M S E RMSE = \sqrt{MSE} RMSE=MSE 量纲与原始数据一致
MAE(平均绝对误差) $MAE = \frac{1}{m}\sum_{i=1}^{m} y_i - \hat{y}_i

RMSE 会放大大误差样本的影响,MAE 只给出平均误差。数据有异常值时 MAE 可能更合适。

4.3 参数求解方法

正规方程法

利用矩阵运算一次性求解最优参数:
w = ( X T X ) − 1 X T y w = (X^TX)^{-1}X^Ty w=(XTX)1XTy

  • 优点:不需要选择学习率,不需要迭代
  • 缺点:特征数量多时计算量大(矩阵求逆复杂度 O ( n 3 ) O(n^3) O(n3)
梯度下降法

沿着损失函数梯度下降的方向,逐步迭代更新参数,最终找到最小值。

比喻:就像蒙着眼睛下山,每一步都沿着最陡的方向走,最终走到山谷。

梯度下降分类

  • 全梯度下降(FGD):每次使用全部样本
  • 随机梯度下降(SGD):每次使用1个样本
  • 小批量梯度下降(Mini-Batch):折中方案,最常用
方法 正规方程 梯度下降
一次性求解 否,需要迭代
学习率 不需要 需要设置
大特征数量 O ( n 3 ) O(n^3) O(n3)
适用性 仅线性回归 各种模型通用

4.4 实战:波士顿房价预测

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression, SGDRegressor
from sklearn.metrics import mean_squared_error, mean_absolute_error
import pandas as pd
import numpy as np

# 1. 加载数据
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep="\\s+", skiprows=22, header=None)
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]

# 2. 数据划分与标准化
x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.2, random_state=22)

transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

# 3. 正规方程法
model_norm = LinearRegression(fit_intercept=True)
model_norm.fit(x_train, y_train)
y_pred_norm = model_norm.predict(x_test)
print(f'正规方程-MSE: {mean_squared_error(y_test, y_pred_norm):.2f}')

# 4. 梯度下降法
model_sgd = SGDRegressor(learning_rate='constant', eta0=0.01, fit_intercept=True)
model_sgd.fit(x_train, y_train)
y_pred_sgd = model_sgd.predict(x_test)
print(f'梯度下降-MSE: {mean_squared_error(y_test, y_pred_sgd):.2f}')

五、逻辑回归

注意:虽然名字里有"回归",但逻辑回归是解决二分类问题的利器。

5.1 核心原理

逻辑回归的基本思想:

  1. 用线性模型 f ( x ) = w x + b f(x) = wx + b f(x)=wx+b 对特征进行加权求和
  2. 通过 Sigmoid 函数将结果映射到 (0, 1) 之间,输出概率值
  3. 设定阈值(如 0.5),概率大于阈值判为正类,否则判为负类

Sigmoid 函数
s i g m o i d ( z ) = 1 1 + e − z sigmoid(z) = \frac{1}{1 + e^{-z}} sigmoid(z)=1+ez1

Sigmoid 函数将任意实数映射到 (0, 1),正好可以表示概率。

5.2 分类评估指标体系

混淆矩阵是评估分类模型的基础:

预测为正 预测为负
真实为正 TP(真正例) FN(伪反例)
真实为负 FP(伪正例) TN(真反例)

基于混淆矩阵,可以计算:

  • 精确率(Precision) P = T P T P + F P P = \frac{TP}{TP + FP} P=TP+FPTP —— 查准率,预测为正的有多少是真的
  • 召回率(Recall) R = T P T P + F N R = \frac{TP}{TP + FN} R=TP+FNTP —— 查全率,真正的正例有多少被找到
  • F1-Score F 1 = 2 P R P + R F1 = \frac{2PR}{P + R} F1=P+R2PR —— 精确率和召回率的调和平均
  • AUC:ROC曲线下的面积,值越大模型区分正负样本能力越强
from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score, roc_auc_score

# 真实值和预测值
y_true = ['恶性', '恶性', '恶性', '恶性', '恶性', '恶性', '良性', '良性', '良性', '良性']
y_pred_A = ['恶性', '恶性', '恶性', '良性', '良性', '良性', '良性', '良性', '良性', '良性']

print(f'精确率: {precision_score(y_true, y_pred_A, pos_label="恶性"):.2%}')
print(f'召回率: {recall_score(y_true, y_pred_A, pos_label="恶性"):.2%}')
print(f'F1值: {f1_score(y_true, y_pred_A, pos_label="恶性"):.2%}')

5.3 实战:癌症分类

import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score

# 1. 获取数据
data = pd.read_csv('breast-cancer-wisconsin.csv')

# 2. 处理缺失值
data = data.replace('?', np.NaN)
data = data.dropna()

# 3. 确定特征和目标值
x = data.iloc[:, 1:-1]    # 医学特征
y = data.iloc[:, -1]      # 2=良性, 4=恶性

# 4. 划分数据集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=21)

# 5. 特征标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

# 6. 模型训练与评估
estimator = LogisticRegression()
estimator.fit(x_train, y_train)

print(f'准确率: {estimator.score(x_test, y_test):.4f}')

六、决策树

6.1 算法思想

决策树模拟人类的if-else决策过程,是一种树形结构的分类/回归模型。每个内部节点代表一个特征的判断,每个分支代表判断结果的输出,每个叶节点代表最终的分类结果。

6.2 三种决策树算法

算法 划分依据 特点
ID3 信息增益 倾向于选择取值多的特征
C4.5 信息增益率 缓解了ID3的偏好问题,可处理连续值
CART 基尼指数(分类)/ 平方损失(回归) 一定是二叉树,计算量小

6.3 核心概念

信息熵:衡量数据不确定性。熵越大,不确定性越高。
H = − ∑ i = 1 k p i log ⁡ ( p i ) H = -\sum_{i=1}^{k} p_i \log(p_i) H=i=1kpilog(pi)

信息增益:划分前后熵的减少量。增益越大,说明特征对分类越有贡献。
g ( D , A ) = H ( D ) − H ( D ∣ A ) g(D, A) = H(D) - H(D|A) g(D,A)=H(D)H(DA)

基尼指数:CART使用,值越小表示数据纯度越高。
G i n i = 1 − ∑ p k 2 Gini = 1 - \sum p_k^2 Gini=1pk2

6.4 决策树剪枝

决策树容易过拟合,剪枝是主要的应对手段:

策略 做法 优点 缺点
预剪枝 构建过程中提前停止分裂 降低过拟合风险,减少训练时间 可能欠拟合
后剪枝 先构建完整树再自底向上修剪 泛化性能更好 训练时间更长

6.5 回归决策树

CART回归树与分类树的区别:

  • 使用平方损失作为划分依据
  • 叶节点输出为该节点样本的均值
  • 输出的是连续值

6.6 API总结

from sklearn.tree import DecisionTreeClassifier  # 分类树
from sklearn.tree import DecisionTreeRegressor   # 回归树

# 关键参数:
# criterion: 'gini'(默认) 或 'entropy'
# max_depth: 树的最大深度,控制过拟合
# min_samples_split: 节点再划分的最小样本数
# min_samples_leaf: 叶节点的最小样本数

clf = DecisionTreeClassifier(
    criterion='gini',
    max_depth=5,
    min_samples_leaf=4,
    random_state=22
)

七、集成学习

三个臭皮匠,赛过诸葛亮。集成学习就是通过组合多个弱学习器,形成一个预测效果更好的强学习器。

7.1 两大范式

Bagging:有放回抽样产生不同训练集,并行训练多个弱学习器,平权投票得出结果。

Boosting:串行训练,每个后续学习器重点关注前一个学习器犯错的样本,加权投票。

区别 Bagging Boosting
数据采样 有放回随机采样 使用全部数据,关注错分样本
学习顺序 并行 串行
投票方式 平权投票 加权投票
代表算法 随机森林 AdaBoost, GBDT, XGBoost

7.2 随机森林

随机森林 = Bagging + 决策树,通过样本随机特征随机双重随机性来保证树的多样性:

from sklearn.ensemble import RandomForestClassifier

# 1. 数据准备(以泰坦尼克号生存预测为例)
titanic = pd.read_csv('titanic.csv')
X = titanic[['Pclass', 'Age', 'Sex']]
y = titanic['Survived']

# 特征处理
X['Age'].fillna(X['Age'].mean(), inplace=True)
X = pd.get_dummies(X)

# 2. 训练与评估
rfc = RandomForestClassifier(
    n_estimators=100,     # 树的数量
    max_depth=6,          # 最大深度
    random_state=9
)
rfc.fit(X_train, y_train)
print(f'随机森林准确率: {rfc.score(X_test, y_test):.4f}')

# 3. 网格搜索调参
from sklearn.model_selection import GridSearchCV

param = {
    "n_estimators": [80, 100, 200],
    "max_depth": [2, 4, 6, 8, 10, 12],
    "random_state": [9]
}
gc = GridSearchCV(RandomForestClassifier(), param_grid=param, cv=2)
gc.fit(X_train, y_train)
print(f'调参后准确率: {gc.score(X_test, y_test):.4f}')

7.3 AdaBoost

AdaBoost的核心是自适应提升——动态调整样本权重和弱学习器权重:

  • 错分样本权重增大,让后续学习器重点关注
  • 正确分类样本权重减小
  • 误差率小的学习器权重更大
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier

# 使用决策树桩(深度为1的决策树)作为基学习器
base = DecisionTreeClassifier(criterion='entropy', max_depth=1)
ada = AdaBoostClassifier(
    base_estimator=base,
    n_estimators=500,      # 弱学习器数量
    learning_rate=0.1,     # 学习率
    random_state=0
)
ada.fit(X_train, y_train)
print(f'AdaBoost准确率: {ada.score(X_test, y_test):.4f}')

7.4 GBDT(梯度提升树)

GBDT的核心思想:每一轮拟合的是上一轮残差的负梯度

通俗理解:假如某人30岁,先用20岁去拟合 → 残差10岁 → 再用6岁拟合 → 残差4岁 → 再用3岁拟合 → 残差1岁…最终把所有预测加起来就是模型输出。

from sklearn.ensemble import GradientBoostingClassifier

gbc = GradientBoostingClassifier()
gbc.fit(X_train, y_train)
print(f'GBDT准确率: {gbc.score(X_test, y_test):.4f}')

7.5 XGBoost

XGBoost(Extreme Gradient Boosting)是Kaggle比赛中的"王牌算法",对GBDT做了以下改进:

  1. 使用泰勒二阶展开近似损失函数
  2. 在损失函数中加入正则化项,防止过拟合
  3. 自定义树节点分裂指标,从损失函数直接推导
import xgboost as xgb

# 红酒品质分类示例
estimator = xgb.XGBClassifier(
    n_estimators=100,
    max_depth=6,
    learning_rate=0.1,
    objective='multi:softmax',   # 多分类
    eval_metric='merror',
    use_label_encoder=False,
    random_state=22
)
estimator.fit(x_train, y_train)

# 样本不均衡处理
from sklearn.utils import class_weight
weights = class_weight.compute_sample_weight(class_weight='balanced', y=y_train)
estimator.fit(x_train, y_train, sample_weight=weights)

八、KMeans聚类

8.1 算法思想

KMeans是一种典型的无监督学习算法,目标是将相似样本自动归到同一类别。

8.2 算法流程

  1. 随机设置 K 个初始聚类中心(质心)
  2. 计算每个样本到 K 个中心的距离,分配到最近的中心
  3. 重新计算每个簇的中心(取均值)
  4. 如果新中心与旧中心一致(收敛),则结束;否则回到步骤2

8.3 聚类评估

指标 说明 判断
SSE(误差平方和) 样本到质心距离的平方和 越小越好
SC系数(轮廓系数) 结合凝聚度和分离度 [-1, 1],越大越好
CH系数 簇内紧密度 vs 簇间分离度 越大越好

肘部法:通过绘制不同K值对应的SSE,找到拐点来确定最佳K值。

8.4 实战:客户分群

from sklearn.cluster import KMeans
import pandas as pd
import matplotlib.pyplot as plt

# 1. 加载数据
data = pd.read_csv('customers.csv')
# 特征:Gender, Age, Annual Income, Spending Score

# 2. 特征编码与标准化
data = pd.get_dummies(data, columns=['Gender'])
from sklearn.preprocessing import StandardScaler
data_scaled = StandardScaler().fit_transform(data[:, 1:])

# 3. 肘部法确定K值
sse = []
for k in range(1, 20):
    km = KMeans(n_clusters=k, random_state=0)
    km.fit(data_scaled)
    sse.append(km.inertia_)

plt.plot(range(1, 20), sse, marker='o')
plt.xlabel('K值')
plt.ylabel('SSE')
plt.title('肘部法确定最佳K值')
plt.show()

# 4. 使用最优K值进行聚类
best_k = 5
estimator = KMeans(n_clusters=best_k, random_state=0)
y_pred = estimator.fit_predict(data_scaled)

# 5. 聚类评估
from sklearn.metrics import silhouette_score, calinski_harabasz_score
print(f'SSE: {estimator.inertia_:.2f}')
print(f'SC系数: {silhouette_score(data_scaled, y_pred):.4f}')
print(f'CH系数: {calinski_harabasz_score(data_scaled, y_pred):.2f}')

九、朴素贝叶斯

9.1 贝叶斯公式

P ( C ∣ W ) = P ( W ∣ C ) ⋅ P ( C ) P ( W ) P(C|W) = \frac{P(W|C) \cdot P(C)}{P(W)} P(CW)=P(W)P(WC)P(C)

  • P ( C ∣ W ) P(C|W) P(CW):后验概率——观察到W后,C发生的概率
  • P ( W ∣ C ) P(W|C) P(WC):似然——C条件下W出现的概率
  • P ( C ) P(C) P(C):先验概率——C发生的概率
  • P ( W ) P(W) P(W):证据因子

9.2 朴素贝叶斯的核心假设

"朴素"在于引入了特征条件独立假设——假设各个特征之间相互独立。这简化了计算:

P ( x 1 , x 2 ∣ C ) = P ( x 1 ∣ C ) ⋅ P ( x 2 ∣ C ) P(x_1, x_2 | C) = P(x_1|C) \cdot P(x_2|C) P(x1,x2C)=P(x1C)P(x2C)

虽然这个假设在现实中很少成立,但朴素贝叶斯在很多场景下仍然表现很好,而且训练速度快。

9.3 拉普拉斯平滑

当某个特征在训练集中未出现时,会导致概率为0。拉普拉斯平滑通过给分子分母加上常数来避免这个问题:

P ( x i ∣ C ) = N i + α N + α ⋅ m P(x_i|C) = \frac{N_i + \alpha}{N + \alpha \cdot m} P(xiC)=N+αmNi+α

其中 α=1 时即为拉普拉斯平滑。

9.4 实战:商品评论情感分析

import pandas as pd
import jieba
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB

# 1. 加载数据
data = pd.read_csv('书籍评价.csv', encoding='gbk')

# 2. 标注:好评=1,差评=0
data.loc[data['评价'] == '好评', '标签'] = 1
data.loc[data['评价'] == '差评', '标签'] = 0

# 3. 分词处理
comment_list = []
for text in data['内容']:
    seg_list = jieba.cut(text, cut_all=False)
    comment_list.append(','.join(seg_list))

# 4. 加载停用词
with open('stopwords.txt', 'r', encoding='utf-8') as f:
    stopwords = [line.strip() for line in f.readlines()]
stopwords = list(set(stopwords))

# 5. 文本向量化
con = CountVectorizer(stop_words=stopwords)
X = con.fit_transform(comment_list)

# 6. 划分训练集和测试集
x_train = X[:10, :].toarray()
y_train = data['标签'][:10]
x_test = X[10:, :].toarray()
y_test = data['标签'][10:]

# 7. 朴素贝叶斯分类
nb = MultinomialNB(alpha=1)  # alpha为拉普拉斯平滑系数
nb.fit(x_train, y_train)
y_predict = nb.predict(x_test)

print(f'预测值: {y_predict}')
print(f'真实值: {y_test.values}')
print(f'准确率: {nb.score(x_test, y_test):.4f}')

十、实战案例:电力负荷预测

10.1 项目背景

电力工业是国民经济的基石。准确预测电力负荷有助于实现电力供需平衡,有效整合可再生能源,降低碳排放,确保电网稳定运行。

需求:基于历史电力负荷数据,预测未来某个时间步的负荷值。

技术栈:pandas + matplotlib + sklearn + xgboost

10.2 项目架构

project/
├── data/          # 数据源与图表
│   └── fig/       # 分析图表
├── log/           # 日志
├── model/         # 保存的模型文件
├── src/           # 业务逻辑
│   ├── train.py   # 模型训练
│   └── predict.py # 模型预测
└── utils/         # 工具类
    ├── log.py     # 日志工具
    └── common.py  # 通用函数

10.3 特征工程(核心难点)

将时序数据转换为结构化表格是机器学习处理时序问题的关键:

def feature_engineering(data, logger):
    """
    关键特征:
    1. 时间特征:月份、小时 → one-hot编码
    2. 时间窗口特征:前1/2/3小时的负荷
    3. 昨日同时刻负荷特征
    """
    result = data.copy(deep=True)

    # 1. 提取时间特征并one-hot编码
    result['hour'] = result['time'].str[11:13]
    result['month'] = result['time'].str[5:7]
    hour_encoding = pd.get_dummies(result['hour'])
    month_encoding = pd.get_dummies(result['month'])
    result = pd.concat([result, hour_encoding, month_encoding], axis=1)

    # 2. 时间窗口特征(前1/2/3小时负荷)
    window_size = 3
    shift_list = [result['power_load'].shift(i) for i in range(1, window_size + 1)]
    shift_data = pd.concat(shift_list, axis=1)
    shift_data.columns = ['前1小时', '前2小时', '前3小时']
    result = pd.concat([result, shift_data], axis=1)

    # 3. 昨日同时刻负荷
    result['yesterday_load'] = ...  # 通过时间字典映射获取

    result.dropna(inplace=True)
    return result, feature_names

10.4 模型训练(XGBoost + 网格搜索)

import xgboost as xgb
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import mean_squared_error, mean_absolute_error
import joblib

# 1. 数据集切分
x_train, x_test, y_train, y_test = train_test_split(
    x_data, y_data, test_size=0.3, random_state=22
)

# 2. 网格搜索寻找最优超参数
param_dict = {
    'n_estimators': [50, 100, 150, 200],
    'max_depth': [3, 6, 9],
    'learning_rate': [0.1, 0.01]
}
grid_cv = GridSearchCV(estimator=xgb.XGBRegressor(), param_grid=param_dict, cv=5)
grid_cv.fit(x_train, y_train)
print(f'最优参数: {grid_cv.best_params_}')

# 3. 使用最优参数训练
xgb_model = xgb.XGBRegressor(
    n_estimators=150, max_depth=6, learning_rate=0.1
)
xgb_model.fit(x_train, y_train)

# 4. 模型评估
y_pred = xgb_model.predict(x_test)
print(f'MSE: {mean_squared_error(y_test, y_pred):.2f}')
print(f'MAE: {mean_absolute_error(y_test, y_pred):.2f}')

# 5. 模型保存
joblib.dump(xgb_model, 'model/xgb.pkl')

10.5 模型预测与评估

预测时需要注意:模拟真实场景——只能使用预测时刻之前的历史数据,不能"穿越"使用未来数据。

# 1. 加载模型
model = joblib.load('model/xgb.pkl')

# 2. 只使用预测时刻之前的历史数据
data_his_dict = {k: v for k, v in full_data_dict.items() if k < pred_time}

# 3. 解析特征(小时、月份、前N小时负荷、昨日同时刻负荷)
features_df = pred_feature_extract(data_his_dict, pred_time)

# 4. 预测
pred_value = model.predict(features_df)

# 5. 计算MAE评估预测效果
mae = mean_absolute_error(true_values, pred_values)

10.6 改进方向

  • 特征角度:引入温度、湿度、风速等外部特征;优化时间窗口大小
  • 算法角度:尝试LightGBM、LSTM、iTransformer等算法;按地区分群建模
  • 工程角度:预测模块封装REST API;模型容器化部署

十一、总结与学习路线

11.1 算法全景图

类别 算法 核心思想 适用场景
分类 KNN 近邻多数表决 小规模分类任务
分类 逻辑回归 Sigmoid输出概率 二分类(流失预测、疾病诊断)
分类+回归 决策树 树形if-else决策 可解释性要求高的场景
回归 线性回归 拟合线性关系 趋势预测(房价、销售)
集成 随机森林 Bagging+决策树 通用分类/回归
集成 AdaBoost 关注错分样本 二分类
集成 XGBoost Gradient Boosting + 正则化 比赛、工业界首选
聚类 KMeans 迭代寻找质心 用户分群、异常检测
分类 朴素贝叶斯 贝叶斯公式+特征独立 文本分类、情感分析

11.2 通用开发流程

# 1. 导入依赖
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 2. 加载数据 → 3. 数据预处理 → 4. 数据集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# 5. 特征工程(标准化、编码等)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)  # 注意:测试集用transform,不要fit

# 6. 模型训练
model = YourModel()
model.fit(X_train, y_train)

# 7. 模型预测与评估
y_pred = model.predict(X_test)
score = model.score(X_test, y_test)

11.3 学习建议

  1. 先理解思想,再动手编码:搞清楚每个算法在解决什么问题、为什么这样设计。
  2. 从经典数据集入手:鸢尾花、波士顿房价、泰坦尼克号、手写数字识别是入门必做案例。
  3. 掌握评估方法:分类看混淆矩阵和AUC,回归看MSE和MAE,聚类看轮廓系数。
  4. 学会调参:交叉验证 + 网格搜索是调参的标准范式。
  5. 理论联系实际:学完一个算法就找一个真实案例练习,代码是最好的老师。

本文所有代码和案例均基于 scikit-learn 和 XGBoost 实现。机器学习的学习之路没有捷径,但好的总结和梳理能帮你少走很多弯路。希望这篇博客能成为你机器学习学习路上的一个实用参考!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐