机器学习——模型的简单优化
在训练模型时我们可能会遇到模型不满足于预期需要进行改善的环节,这些情况通常包括以下几种常见问题和对应的解决方案:
数据质量不足
- 数据量过少:当训练样本不足时,模型难以学习到有效的特征表示。建议通过数据增强(如图像旋转、加噪等)或收集更多数据来解决
- 数据不平衡:某些类别样本远多于其他类别时,可以采用过采样(如SMOTE)、欠采样或类别加权等方法
- 数据质量问题:需要检查并处理缺失值、异常值和标注错误
模型欠拟合
- 表现为训练集和验证集上表现都不佳
- 可能原因:模型结构过于简单、特征工程不足或正则化过度
- 解决方案:增加模型复杂度、优化特征选择、减少正则化强度模型过拟合
模型过拟合
- 表现为训练集表现很好但验证集表现差
- 可能原因:模型过于复杂、训练数据不足或训练轮次过多
- 解决方案:增加dropout层、使用早停(early stopping)、添加L1/L2正则化、数据增强
一、数据集改善
1、数据集拆分
1. 核心功能
train_test_split
是 scikit-learn 中用于将数据集随机划分为训练集和测试集的函数,主要作用包括:
防止过拟合:通过分离训练和测试数据,评估模型在未见数据上的泛化能力。
灵活划分比例:支持自定义测试集或训练集的比例(如 80% 训练 + 20% 测试)。
分层抽样:处理类别不均衡数据时,保持训练集和测试集的类别分布一致。
2. 参数详解
参数 | 说明 | 示例值 |
---|---|---|
| 待划分的数据(如特征 |
|
| 测试集比例(0.0-1.0)或样本数。默认 0.25 。 |
|
| 训练集比例,若未设置则自动补全 |
|
| 随机种子,保证划分结果可复现 。 |
|
| 是否打乱数据(默认 |
|
| 按标签分层抽样,保持类别比例一致 。 |
|
3.示例
from sklearn.model_selection import train_test_split
import numpy as npX = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
y = np.array([0, 1, 0, 1])# 80% 训练集,20% 测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print("训练集:", X_train) # 输出示例:[[3 4], [1 2], [7 8]]
print("测试集:", X_test) # 输出示例:[[5 6]][1,5]
2.样本归一化
样本归一化是指对数据集中的每个样本(行)进行缩放,使其满足特定范数(如L1、L2或最大值范数),从而消除样本间量纲差异。与特征归一化(按列处理)不同,样本归一化适用于样本向量需整体比较的场景,如文本分类、聚类分析等。
1.核心公式
L2归一化(默认):
使每个样本的欧几里得范数为1。
L1归一化:
使样本的绝对值和为1。
最大值归一化(Max):
将样本最大值缩放到1。
2. 适用场景
文本数据处理
如TF-IDF向量或词频向量,归一化后可比性更强。基于距离的算法
KNN、SVM等需计算样本间距离的模型,归一化避免大数值特征主导结果。神经网络输入
归一化到统一范围(如[0,1])可加速梯度下降收敛。图像处理
像素值归一化后更适应卷积神经网络的输入要求。
3. 方法对比与选择
方法 | 特点 | 适用场景 |
---|---|---|
L2归一化 | 保留样本向量的方向信息,对异常值敏感度较低 | 文本分类、聚类分析 |
L1归一化 | 生成稀疏解,适合特征选择 | 高维稀疏数据(如词袋模型) |
Max归一化 | 快速缩放至[-1,1],但对极端值敏感 | 图像像素值处理 |
注意事项:
若样本中存在异常值,建议使用L2归一化或RobustScaler(基于中位数和四分位数)。
归一化会改变原始数据分布,但保留相对大小关系
代码实现(Python)
使用Scikit-learn的Normalizer
from sklearn.preprocessing import Normalizer
import numpy as np# 示例数据(每行一个样本)
X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])# L2归一化(默认)
normalizer = Normalizer(norm='l2')
X_l2 = normalizer.fit_transform(X)
print("L2归一化结果:\n", X_l2)#[0.267, 0.534, 0.801]# L1归一化
normalizer = Normalizer(norm='l1')
X_l1 = normalizer.fit_transform(X)
print("L1归一化结果:\n", X_l1)
3.样本标准化
样本标准化(也称为数据标准化或特征缩放)是将不同尺度的数据转换为统一尺度的过程,使不同特征具有可比性。
常见的标准化方法
Z-score标准化(标准差标准化)
公式:z = (x - μ) / σ
其中μ是均值,σ是标准差
处理后数据均值为0,标准差为1
Min-Max标准化
公式:x' = (x - min) / (max - min)
将数据线性变换到[0,1]区间
Max标准化
公式:x' = x / max
将数据按最大值缩放
小数缩放
公式:x' = x / 10^j
j为使最大绝对值小于1的最小整数
标准化的作用
消除不同特征间的量纲影响
提高模型收敛速度(特别是梯度下降算法)
提高模型精度
使不同特征对模型有相近的贡献度
应用场景
基于距离的算法(如KNN、K-means)
使用梯度下降的模型(如神经网络)
主成分分析(PCA)等降维方法
正则化模型(如Lasso、Ridge回归)
Z-score标准化
import numpy as np
from sklearn.preprocessing import StandardScaler# 原始数据
data = np.array([[1, 2], [3, 4], [5, 6]])# 使用sklearn
scaler = StandardScaler()
scaled_data = scaler.fit_transform(data)
print("Z-score标准化结果:\n", scaled_data)# 手动计算
mean = np.mean(data, axis=0)
std = np.std(data, axis=0)
manual_scaled = (data - mean) / std
print("手动计算结果:\n", manual_scaled)
Min-Max标准化
from sklearn.preprocessing import MinMaxScaler# 使用sklearn
minmax_scaler = MinMaxScaler()
minmax_scaled = minmax_scaler.fit_transform(data)
print("Min-Max标准化结果:\n", minmax_scaled)# 手动计算
data_min = np.min(data, axis=0)
data_max = np.max(data, axis=0)
manual_minmax = (data - data_min) / (data_max - data_min)
print("手动计算结果:\n", manual_minmax)
4.上采样和下采样
上采样和下采样是处理数据不平衡问题的两种常用技术,主要用于解决分类任务中类别分布不均的情况。
下采样(Downsampling)
基本概念
也称为欠采样(Undersampling)
减少多数类样本数量,使其与少数类样本数量接近或相同
适用于多数类样本数量远大于少数类的情况
常用方法
随机下采样
从多数类中随机删除样本
from sklearn.utils import resample# 假设df是DataFrame,'class'是目标列 majority_class = df[df['class'] == 0] minority_class = df[df['class'] == 1]# 随机下采样多数类 majority_downsampled = resample(majority_class,replace=False,n_samples=len(minority_class),random_state=42)# 合并下采样后的数据 df_downsampled = pd.concat([majority_downsampled, minority_class])
Tomek Links
移除边界附近造成分类困难的多数类样本
from imblearn.under_sampling import TomekLinkstl = TomekLinks() X_res, y_res = tl.fit_resample(X, y)
Cluster Centroids
使用聚类方法减少多数类样本
from imblearn.under_sampling import ClusterCentroidscc = ClusterCentroids(random_state=42)
X_res, y_res = cc.fit_resample(X, y)
优缺点
优点:
减少训练数据量,加快训练速度
解决类别不平衡问题
缺点:
可能丢失重要信息
可能导致模型欠拟合
上采样(Upsampling)
基本概念
也称为过采样(Oversampling)
增加少数类样本数量,使其与多数类样本数量接近或相同
适用于少数类样本数量不足的情况
常用方法
随机上采样
随机复制少数类样本
from sklearn.utils import resampleminority_upsampled = resample(minority_class,replace=True,n_samples=len(majority_class),random_state=42)df_upsampled = pd.concat([majority_class, minority_upsampled])
SMOTE(Synthetic Minority Oversampling Technique)
合成新的少数类样本
from imblearn.over_sampling import SMOTEsmote = SMOTE(random_state=42)
X_res, y_res = smote.fit_resample(X, y)
ADASYN(Adaptive Synthetic Sampling)
基于数据分布的自适应上采样
from imblearn.over_sampling import ADASYNadasyn = ADASYN(random_state=42)
X_res, y_res = adasyn.fit_resample(X, y)
优缺点
优点:
不丢失原始信息
可以改善模型对少数类的识别能力
缺点:
可能导致过拟合
增加计算负担
二、交叉验证
交叉验证是评估机器学习模型性能和选择超参数的重要技术,它通过将数据集分成多个子集来减少评估结果的方差。
常见交叉验证方法
1. K折交叉验证(K-Fold CV)
原理:将数据集随机分成K个大小相似的互斥子集(称为"折"),每次用K-1折训练,剩下1折验证,重复K次。
from sklearn.model_selection import KFold, cross_val_score
from sklearn.linear_model import LogisticRegressionkfold = KFold(n_splits=5, shuffle=True, random_state=42)
model = LogisticRegression()
scores = cross_val_score(model, X, y, cv=kfold)
print("平均准确率:", scores.mean())
2. 分层K折交叉验证(Stratified K-Fold)
特点:保持每个折中类别比例与原始数据集一致,适用于分类问题,特别是类别不平衡时。
from sklearn.model_selection import StratifiedKFoldskf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=skf)
3. 留一法交叉验证(Leave-One-Out, LOO)
原理:每次留一个样本作为验证集,其余作为训练集,重复N次(N为样本数)。
from sklearn.model_selection import LeaveOneOutloo = LeaveOneOut()
scores = cross_val_score(model, X, y, cv=loo)
print("LOO平均准确率:", scores.mean())
4. 留P法交叉验证(Leave-P-Out)
原理:每次留P个样本作为验证集。
from sklearn.model_selection import LeavePOutlpo = LeavePOut(p=2)
scores = cross_val_score(model, X, y, cv=lpo) # 注意:计算量很大
5. 时间序列交叉验证(Time Series CV)
特点:考虑数据的时间顺序,防止未来信息泄露。
from sklearn.model_selection import TimeSeriesSplittscv = TimeSeriesSplit(n_splits=5)
for train_index, test_index in tscv.split(X):X_train, X_test = X[train_index], X[test_index]y_train, y_test = y[train_index], y[test_index]
交叉验证的最佳实践
数据预处理:应在交叉验证循环内进行,防止数据泄露
from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScalerpipeline = make_pipeline(StandardScaler(), LogisticRegression()) scores = cross_val_score(pipeline, X, y, cv=5)
类别不平衡处理:使用分层抽样或自定义采样策略
from sklearn.model_selection import StratifiedKFoldskf = StratifiedKFold(n_splits=5)
随机性控制:设置
random_state
确保结果可复现折数选择:
小数据集:5-10折
大数据集:3-5折(减少计算量)
超参数调优:可使用更多折数
性能指标选择:根据问题类型选择合适的评估指标
from sklearn.metrics import make_scorer, f1_scorescorer = make_scorer(f1_score, average='macro') scores = cross_val_score(model, X, y, cv=5, scoring=scorer)
交叉验证的局限性
计算成本高,特别是大数据集或复杂模型
对数据顺序敏感的数据集(如时间序列)需要特殊处理
极端不平衡数据可能需要分层抽样或其他采样技术
交叉验证是机器学习工作流中不可或缺的部分,合理使用可以有效评估模型泛化能力并防止过拟合。
三、数据结果
混淆矩阵
混淆矩阵是评估分类模型性能的重要工具,它以矩阵形式直观展示模型的预测结果与真实标签的对比情况。
基本结构
对于二分类问题,混淆矩阵为2×2矩阵:
TP(True Positive):真正例,实际为阳性且预测为阳性
FN(False Negative):假反例,实际为阳性但预测为阴性
FP(False Positive):假正例,实际为阴性但预测为阳性
TN(True Negative):真反例,实际为阴性且预测为阴性
#Python实现
from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns# 示例数据
y_true = [1, 0, 1, 1, 0, 1, 0, 0]
y_pred = [1, 0, 0, 1, 0, 1, 1, 0]# 计算混淆矩阵
cm = confusion_matrix(y_true, y_pred)
print("混淆矩阵:\n", cm)# 可视化
plt.figure(figsize=(6, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=['预测阴性', '预测阳性'],yticklabels=['真实阴性', '真实阳性'])
plt.xlabel('预测值')
plt.ylabel('真实值')
plt.title('混淆矩阵')
plt.show()
分类指标
指标 | 公式 | 侧重 | 适用场景 | sklearn函数 |
---|---|---|---|---|
准确率 | (TP+TN)/Total | 整体正确率 | 平衡数据集 | accuracy_score |
精确率 | TP/(TP+FP) | 预测阳性准确度 | FP代价高 | precision_score |
召回率 | TP/(TP+FN) | 阳性样本识别率 | FN代价高 | recall_score |
F1分数 | 2(PR)/(P+R) | 精确率召回率平衡 | 不平衡数据 | f1_score |
AUC | ROC曲线下面积 | 整体区分能力 | 阈值无关评估 | roc_auc_score |