机器学习小白入门这一篇就够了!——算法原理、评估指标、实战案例全覆盖
机器学习核心算法全解:从小白到实战,一文掌握十大经典算法
本文系统梳理了机器学习的核心知识体系,涵盖监督学习、无监督学习、集成学习等十大经典算法,并配有完整可运行的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=1∑n∣wi∣
- 可以产生稀疏解(部分权重变为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=1∑nwi2
- 让权重趋近于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(xi−yi)2 | 最常用,直线距离 |
| 曼哈顿距离 | $d = \sum_{i=1}^{n} | x_i - y_i |
| 切比雪夫距离 | $d = \max( | x_i - y_i |
| 闵氏距离 | $d = (\sum | x_i - y_i |
3.3 分类与回归流程
分类问题:
- 计算待测样本到所有训练样本的距离
- 按距离升序排列
- 取最近 K 个样本
- 多数表决——出现次数最多的类别即为预测结果
回归问题:
- 同上步骤1-3
- 取 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=m1∑i=1m(yi−y^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 核心原理
逻辑回归的基本思想:
- 用线性模型 f ( x ) = w x + b f(x) = wx + b f(x)=wx+b 对特征进行加权求和
- 通过 Sigmoid 函数将结果映射到 (0, 1) 之间,输出概率值
- 设定阈值(如 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+e−z1
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=1∑kpilog(pi)
信息增益:划分前后熵的减少量。增益越大,说明特征对分类越有贡献。
g ( D , A ) = H ( D ) − H ( D ∣ A ) g(D, A) = H(D) - H(D|A) g(D,A)=H(D)−H(D∣A)
基尼指数:CART使用,值越小表示数据纯度越高。
G i n i = 1 − ∑ p k 2 Gini = 1 - \sum p_k^2 Gini=1−∑pk2
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做了以下改进:
- 使用泰勒二阶展开近似损失函数
- 在损失函数中加入正则化项,防止过拟合
- 自定义树节点分裂指标,从损失函数直接推导
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 算法流程
- 随机设置 K 个初始聚类中心(质心)
- 计算每个样本到 K 个中心的距离,分配到最近的中心
- 重新计算每个簇的中心(取均值)
- 如果新中心与旧中心一致(收敛),则结束;否则回到步骤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(C∣W)=P(W)P(W∣C)⋅P(C)
- P ( C ∣ W ) P(C|W) P(C∣W):后验概率——观察到W后,C发生的概率
- P ( W ∣ C ) P(W|C) P(W∣C):似然——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,x2∣C)=P(x1∣C)⋅P(x2∣C)
虽然这个假设在现实中很少成立,但朴素贝叶斯在很多场景下仍然表现很好,而且训练速度快。
9.3 拉普拉斯平滑
当某个特征在训练集中未出现时,会导致概率为0。拉普拉斯平滑通过给分子分母加上常数来避免这个问题:
P ( x i ∣ C ) = N i + α N + α ⋅ m P(x_i|C) = \frac{N_i + \alpha}{N + \alpha \cdot m} P(xi∣C)=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 学习建议
- 先理解思想,再动手编码:搞清楚每个算法在解决什么问题、为什么这样设计。
- 从经典数据集入手:鸢尾花、波士顿房价、泰坦尼克号、手写数字识别是入门必做案例。
- 掌握评估方法:分类看混淆矩阵和AUC,回归看MSE和MAE,聚类看轮廓系数。
- 学会调参:交叉验证 + 网格搜索是调参的标准范式。
- 理论联系实际:学完一个算法就找一个真实案例练习,代码是最好的老师。
本文所有代码和案例均基于 scikit-learn 和 XGBoost 实现。机器学习的学习之路没有捷径,但好的总结和梳理能帮你少走很多弯路。希望这篇博客能成为你机器学习学习路上的一个实用参考!
更多推荐




所有评论(0)