机器学习实战:逻辑回归深度解析与欺诈检测应用
全面掌握逻辑回归的核心技术:正则化原理可视化、交叉验证参数详解、SMOTE算法原理解析,以及完整的信用卡欺诈检测实战案例
一、深入解析过拟合与正则化机制
什么是过拟合?
过拟合(Overfitting)指模型在训练数据上表现优异,但在未见过的测试数据上泛化能力差的现象。这通常因为模型过度学习了训练数据中的噪声或特定模式,导致无法适应新数据。
过拟合真实案例与可视化
我们通过一个多项式回归案例展示过拟合现象。使用正弦函数生成模拟数据,分别用1次、4次和15次多项式拟合:
# === 第一部分:过拟合案例可视化 ===
# 导入必要的库
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import make_pipeline
# 生成模拟数据展示过拟合现象
np.random.seed(42) # 设置随机种子保证结果可复现
X = np.linspace(0, 10, 20) # 生成0-10之间均匀分布的20个点
y = np.sin(X) + np.random.normal(0, 0.3, 20) # 添加噪声的正弦函数模拟数据
# 创建不同复杂度的模型进行拟合
degrees = [1, 4, 15] # 分别测试1次、4次和15次多项式
plt.figure(figsize=(18, 5)) # 创建3个子图的画布
# 循环拟合三种不同复杂度的模型
for i, degree in enumerate(degrees):
ax = plt.subplot(1, 3, i+1) # 当前子图位置
# 创建多项式回归模型(多项式特征转换+线性回归)
model = make_pipeline(PolynomialFeatures(degree), LinearRegression())
model.fit(X[:, np.newaxis], y) # 训练模型,需转换X为列向量
# 在测试集上预测
X_test = np.linspace(0, 10, 100) # 生成100个测试点
y_pred = model.predict(X_test[:, np.newaxis]) # 模型预测
# 可视化拟合效果
plt.scatter(X, y, s=50, alpha=0.7, label='原始数据') # 原始数据点
plt.plot(X_test, y_pred, 'r-', linewidth=2, label=f'{degree}次多项式') # 模型拟合曲线
plt.ylim(-2, 2) # 设置y轴范围
plt.title(f'{degree}次多项式拟合') # 子图标题
plt.grid(True) # 显示网格
plt.legend() # 显示图例
plt.tight_layout() # 自动调整子图间距
plt.show() # 显示图形
三种不同复杂度模型拟合效果对比:(左)欠拟合-模型过于简单;(中)最佳拟合-捕捉真实模式;
(右)过拟合-完全拟合噪声
正则化原理
正则化通过在损失函数中增加一个惩罚项来约束模型参数,避免其过度增长。正则化后的损失函数一般形式为:
E(θ)=C(θ)+λR(θ)
其中:
C(θ)是原始损失函数(如交叉熵);
R(θ)是正则化项;
λ是正则化强度,控制惩罚力度。
附.正则化原理详解与数学表达
正则化通过在损失函数中加入惩罚项,约束模型参数大小,防止模型过于复杂(过拟合):
1. L1正则化(Lasso正则化)
数学表达式:
其中:
- J(θ):正则化后的损失函数
- 原始损失函数:模型本来的损失函数
- λ:正则化强度参数
- θj:模型的第j个权重参数
- n:模型参数总数(不包括偏置项θ0)
- ∣⋅∣:绝对值运算符
特点:
- 惩罚项是权重向量的L1范数
- 产生稀疏解(许多权重精确为零)
- 具有特征选择能力
- 对异常值更鲁棒
2. L2正则化(Ridge正则化)
数学表达式:
其中:
- J(θ):正则化后的损失函数
- 原始损失函数:模型本来的损失函数(如均方误差、交叉熵等)
- λ:正则化强度参数(λ增大 → 正则化增强)
- θj:模型的第j个权重参数
- n:模型参数总数(不包括偏置项θ0)
特点:
- 又称权重衰减
- 惩罚项是权重向量的L2范数平方
- 使权重平滑缩小,趋于小值但不会完全为零
- 在神经网络中称为权重衰减(weight decay)
3. 正则化效果对比
特性 | L1正则化 (Lasso) | L2正则化 (Ridge) |
---|---|---|
数学形式 | ![]() |
![]() |
解的特性 | 稀疏解 | 稠密解 |
特征选择 | 支持自动特征选择 | 不支持 |
异常值鲁棒性 | 较鲁棒 | 较敏感 |
计算复杂度 | 优化较复杂 | 优化较简单 |
几何约束 | 菱形约束域 | 圆形约束域 |
应用场景 | 高维数据、特征选择 | 防止过拟合、数值稳定 |
Scikit-learn参数 | penalty='l1' |
penalty='l2' |
4. Elastic Net正则化(L1+L2混合)
结合了L1和L2的优点,表达式为:
在实际应用中,通常使用混合比例参数r:
# Elastic Net实现
from sklearn.linear_model import ElasticNet
model = ElasticNet(alpha=0.5, l1_ratio=0.7) # l1_ratio控制L1/L2混合比例
正则化技术是防止过拟合、提高模型泛化能力的关键工具,理解其数学本质和实际效果对于构建鲁棒的机器学习模型至关重要。
二、交叉验证
1交叉验证的作用及其原理
为什么需要交叉验证,它用在机器学习的哪一步中?
仅划分一次训练集和测试集评估模型具有偶然性,尤其当数据量有限时。交叉验证通过多次划分数据集,提供更稳定、可靠的模型性能评估。常见于特征工程中数据预处理和参数调整。
交叉验证:就是在训练集中选一部分样本用于测试模型。
保留一部分的训练集数据作为验证集/评估集,对训练集生成的参数进行测试,相对客观的判断这些参数对训练集之外的数据的符合程度。
验证集方法
交叉验证的步骤如下:
保留一个样本数据集, (取出训练集中20%的样本不用)
使用数据集的剩余部分训练模型 (使用另外的80%样本训练模型)
使用验证集的保留样本。(完成模型后,在20%的样本中测试)
如果模型在验证数据上提供了一个肯定的结果,那么继续使用当前的模型。
优点: 简单方便。直接将训练集按比例拆分成训练集和验证集,比如50:50。
缺点: 没有充分利用数据, 结果具有偶然性。如果按50:50分,会损失掉另外50%的数据信息,因为我们没有利用着50%的数据来训练模型。
K折交叉验证(k-fold cross validation)
针对上面通过train_test_split划分,从而进行模型评估方式存在的弊端,提出Cross Validation 交叉验证。
Cross Validation:简言之,就是进行多次train_test_split划分;每次划分时,在不同的数据集上进行训练、测试评估,从而得出一个评价结果;如果是5折交叉验证,意思就是在原始数据集上,进行5次划分,每次划分进行一次训练、评估,最后得到5次划分后的评估结果,一般在这几次评估结果上取平均得到最后的 评分。k-fold cross-validation ,其中,k一般取5或10。
训练模型需要在大量的数据集基础上,否则就不能够识别数据中的趋势,导致错误产生
同样需要适量的验证数据点。 验证集太小容易导致误差
多次训练和验证模型。需要改变训练集和验证集的划分,有助于验证模型。
步骤:
随机将整个数据集分成k折;
如图中所示,依次取每一折的数据集作验证集,剩余部分作为训练集
算出每一折测试的错误率
取这里K次的记录平均值 作为最终结果
优点:
适合大样本的数据集
经过多次划分,大大降低了结果的偶然性,从而提高了模型的准确性。
对数据的使用效率更高。train_test_split,默认训练集、测试集比例为3:1。如果是5折交叉验证,训练集比测试集为4:1;10折交叉验证训练集比测试集为9:1。数据量越大,模型准确率越高。
缺点:
对数据随机均等划分,不适合包含不同类别的数据集。比如:数据集有5类数据(ABCDE各占20%),抽取出来的也正好是按照类别划分的5类,第一折全是A,第二折全是B……这样就会导致,模型学习到测试集中数据的特点,用BCDE训练的模型去测试A类数据、ACDE的模型测试B类数据,这样准确率就会很低。
如何确定K值?
一般情况下3、5是默认选项,常建议用K=10。
K折交叉验证流程:数据划分为K份,轮流使用K-1份作为训练集,剩余1份作为验证集(区别于测试集),重复K次
精细化步骤:
随机将数据集分成K个互斥的子集(一般情况下3、5是默认选项,常建议用K=10);
对于每个子集 i(i=1到 K):
使用除子集 i外的数据训练模型;
在子集 i上评估模型性能;
计算K次评估指标的平均值。
优点:
充分利用数据,适合数据量不大的场景(小于10万);
评估结果更稳定可靠。
缺点:
计算成本高;
随机划分可能破坏数据分布(如类别不平衡)。
Scikit-learn交叉验证核心参数:
from sklearn.model_selection import cross_val_score
# 执行交叉验证(此处为示例模板,实际需要具体模型和数据)
scores = cross_val_score(
estimator, # 模型对象(如LogisticRegression)
X, # 特征矩阵
y, # 目标向量
cv=5, # 交叉验证折叠数(K折交叉验证)
scoring='accuracy', # 评估指标(可用'recall', 'precision', 'f1'等)
n_jobs=-1 # 使用全部CPU核心并行计算
)
# 实际应用中模型和评分指标选择示例:
# from sklearn.linear_model import LogisticRegression
# model = LogisticRegression()
# scores = cross_val_score(model, X, y, cv=5, scoring='recall', n_jobs=-1)
交叉验证实现案例(line40)
import pandas as pd # 导入pandas库,用于数据处理和分析
import numpy as np # 导入numpy库,用于数值计算
import matplotlib.pyplot as plt # 导入matplotlib的pyplot模块,用于数据可视化
from sklearn.model_selection import cross_val_score # 从sklearn.model_selection导入cross_val_score函数,用于交叉验证
from sklearn.model_selection import train_test_split # 从sklearn.model_selection导入train_test_split函数,用于分割数据集
from sklearn.preprocessing import StandardScaler # 从sklearn.preprocessing导入StandardScaler,用于数据归一化
from sklearn.linear_model import LogisticRegression # 从sklearn.linear_model导入LogisticRegression,用于逻辑回归模型
from sklearn import metrics # 从sklearn导入metrics,用于评估模型性能
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 设置matplotlib的字体为微软雅黑,以支持中文显示
plt.rcParams['axes.unicode_minus'] = False # 设置matplotlib的负号显示正常
data = pd.read_csv('creditcard.csv', encoding='utf-8') # 读取CSV文件,编码为utf-8
scaler = StandardScaler() # 创建StandardScaler对象,用于数据归一化
data['Amount'] = scaler.fit_transform(data[['Amount']]) # 对'Amount'列进行数据归一化,使用z-score方法
data = data.drop('Time', axis=1) # 删除'Time'列,因为它与分类任务无关
X_whole = data.drop('Class', axis=1) # 获取特征数据,删除'Class'列
y_whole = data['Class'] # 获取标签数据,即'Class'列
X_train, X_test, y_train, y_test = train_test_split( # 将数据集分割为训练集和测试集
X_whole, y_whole, test_size=0.3, random_state=1000, stratify=y_whole
)
lr = LogisticRegression(C=0.01, max_iter=1000, random_state=1000) # 创建逻辑回归模型,设置C=0.01,最大迭代次数为1000
lr.fit(X_train, y_train) # 训练逻辑回归模型
y_pred = lr.predict(X_test) # 使用训练好的模型进行预测
print("Accuracy:", metrics.accuracy_score(y_test, y_pred)) # 打印模型的准确率
print("\nClassification Report:\n", metrics.classification_report(y_test, y_pred)) # 打印模型的分类报告
scores = [] # 初始化一个空列表,用于存储每个C值的平均召回率
c_param_range = [0.01, 0.1, 1, 10, 100] # 定义C值的范围
for i in c_param_range: # 遍历C值范围
lr = LogisticRegression(C=i, penalty='l2', solver='lbfgs', max_iter=1000) # 创建逻辑回归模型,设置不同的C值
score = cross_val_score(lr, X_train, y_train, cv=8, scoring='recall') # 使用8折交叉验证计算召回率
score_mean = sum(score) / len(score) # 计算平均召回率
scores.append(score_mean) # 将平均召回率添加到scores列表中
#print(score_mean) # 打印当前C值的平均召回率
best_c = c_param_range[np.argmax(scores)] # 找到使平均召回率最大的C值
print("……最优惩罚因子为:{}……".format(best_c)) # 打印最优的C值
2.2LogisticRegression参数完全指南
参数 | 可选值 | 默认值 | 说明 |
---|---|---|---|
penalty |
'l1', 'l2', 'elasticnet', 'none' | 'l2' | 正则化类型 |
C |
正浮点数 > 0.0 | 1.0 | 正则化强度的倒数(小值→强正则化) |
solver |
'newton-cg', 'lbfgs', 'liblinear', 'sag', 'saga' | 'lbfgs' | 优化算法 |
max_iter |
正整数 | 100 | 优化算法的最大迭代次数 |
class_weight |
'balanced', 字典或None | None | 类别权重,解决数据不平衡 |
fit_intercept |
True/False | True | 是否计算截距项 |
multi_class |
'auto', 'ovr', 'multinomial' | 'auto' | 多类别策略 |
重要参数组合约束:
- 'liblinear'算法仅支持L1和L2正则化
- 'newton-cg', 'sag', 'lbfgs'仅支持L2正则化
- 'saga'支持所有类型的正则化
- 'elasticnet'仅适用于'saga'算法
三、上下采样科学原理解析:数据不平衡的应对之策
数据不平衡问题
在实际应用中,分类数据常存在类别不平衡问题(如欺诈交易仅占总交易的0.1%)。这会导致模型偏向多数类,忽视少数类。
上采样(Oversampling)
上采样通过增加少数类样本数量来平衡数据分布。常用方法包括:
随机复制:复制少数类样本,简单但可能导致过拟合;
合成样本生成(SMOTE):通过线性插值合成新样本。
SMOTE算法原理图:
SMOTE算法步骤:
对于少数类每个样本 x:
找出其K个最近邻样本(一般K=5);
随机选一个邻居 x′;
在 x和 x′之间线性插值生成新样本:xnew=x+α(x′−x),α∈[0,1]随机。
from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X_train, y_train)
风险: 可能引入噪声,导致过拟合。
SMOTE算法原理与实现
SMOTE(Synthetic Minority Oversampling Technique) 是一种智能过采样方法,通过插值创建合成样本:
# === 第四部分:SMOTE算法实现与效果可视化 ===
# 导入必要库
from imblearn.over_sampling import SMOTE
from sklearn.datasets import make_classification
# 创建不平衡数据集示例
X, y = make_classification(n_classes=2, weights=[0.05, 0.95], # 少数类5%,多数类95%
n_features=2, n_redundant=0, n_clusters_per_class=1)
# 可视化原始不平衡数据
plt.figure(figsize=(12, 5)) # 创建图形
plt.subplot(1, 2, 1) # 左侧子图
plt.scatter(X[y==0][:,0], X[y==0][:,1], label='少数类') # 少数类样本
plt.scatter(X[y==1][:,0], X[y==1][:,1], alpha=0.1, label='多数类') # 多数类样本(透明度较低)
plt.title('原始不平衡数据') # 标题
plt.legend() # 显示图例
# 应用SMOTE过采样技术
smote = SMOTE(k_neighbors=5, random_state=42) # 创建SMOTE对象(5个最近邻)
X_res, y_res = smote.fit_resample(X, y) # 应用SMOTE生成合成样本
# 可视化过采样后的数据
plt.subplot(1, 2, 2) # 右侧子图
plt.scatter(X_res[y_res==0][:,0], X_res[y_res==0][:,1], label='少数类(合成+原始)') # 少数类(原始+合成)
plt.scatter(X_res[y_res==1][:,0], X_res[y_res==1][:,1], alpha=0.1, label='多数类') # 多数类样本
plt.title('SMOTE过采样后数据') # 标题
plt.legend() # 显示图例
plt.tight_layout() # 自动调整子图间距
plt.show() # 显示图形
SMOTE效果可视化部分:
from sklearn.datasets import make_classification
# 创建不平衡数据集
X, y = make_classification(n_classes=2, weights=[0.05, 0.95],
n_features=2, n_redundant=0, n_clusters_per_class=1)
# 应用SMOTE前后对比
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
ax1.scatter(X[y==0][:,0], X[y==0][:,1], label='少数类')
ax1.scatter(X[y==1][:,0], X[y==1][:,1], alpha=0.1, label='多数类')
ax1.set_title('原始不平衡数据')
# 应用SMOTE
smote = SMOTE(k_neighbors=5)
X_res, y_res = smote.fit_resample(X, y)
ax2.scatter(X_res[y_res==0][:,0], X_res[y_res==0][:,1], label='少数类(合成+原始)')
ax2.scatter(X_res[y_res==1][:,0], X_res[y_res==1][:,1], alpha=0.1, label='多数类')
ax2.set_title('SMOTE过采样后数据')
plt.legend()
plt.tight_layout()
plt.show()
https://editor.analyticsvidhya.com/uploads/34362smote1.png
SMOTE算法效果:(左)原始不平衡数据;(右)SMOTE过采样后数据,蓝色点为合成样本
下采样(Undersampling)
下采样通过减少多数类样本数量来平衡数据。常用方法包括:
随机删除:随机移除多数类样本,简单但可能丢失重要信息;
基于距离的方法(如NearMiss):选择与少数类最接近的多数类样本。
from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler(random_state=42)
X_resampled, y_resampled = rus.fit_resample(X_train, y_train)
风险: 可能丢失多数类关键信息,降低模型泛化能力
下采样技术对比
方法 | 原理 | 优点 | 缺点 |
---|---|---|---|
随机下采样 | 随机删除多数类样本 | 实现简单,计算快速 | 丢失潜在重要信息 |
Tomek Links | 移除边界附近的多数类样本 | 改善分类边界清晰度 | 样本减少有限 |
NearMiss | 保留距离少数类最近的多数类样本 | 强化决策边界 | 可能保留噪声样本 |
Cluster Centroids | 聚类后从每个簇中心采样 | 保留数据分布特征 | 计算成本较高 |
# === 第五部分:下采样方法实现 ===
from imblearn.under_sampling import (RandomUnderSampler,
TomekLinks,
NearMiss,
ClusterCentroids)
# 初始化不同下采样方法
samplers = {
"Random": RandomUnderSampler(random_state=42), # 随机下采样
"Tomek": TomekLinks(), # Tomek Links(移除边界多数类样本)
"NearMiss-1": NearMiss(version=1), # NearMiss算法第一版
"Cluster Centroids": ClusterCentroids(random_state=42) # 聚类中心下采样
}
# 实际应用示例(需要特征矩阵X和目标向量y):
# for name, sampler in samplers.items():
# X_res, y_res = sampler.fit_resample(X, y)
# print(f"{name}方法下采样后类别分布:\n{pd.Series(y_res).value_counts()}")
四、信用卡欺诈检测完整案例
项目背景与数据理解
信用卡欺诈是全球支付系统面临的重大问题。本项目使用的信用卡欺诈数据集包含:
- 284,807笔交易记录
- 492笔欺诈交易(仅占0.172%)
- 28个数值型特征(PCA降维后)
- 1个类别标签(0=正常,1=欺诈)
核心挑战:
- 极端类别不平衡(492个欺诈样本 vs 284,315个正常样本)
- 高维特征空间(28个PCA转换特征)
- 欺诈模式不断进化,需要鲁棒的模型
完整解决方案代码
import pandas as pd # 导入pandas库,用于数据处理和分析
import numpy as np # 导入numpy库,用于科学计算
import matplotlib.pyplot as plt # 导入matplotlib库,用于数据可视化
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV # 导入模型选择工具:数据集分割、交叉验证、网格搜索
from sklearn.preprocessing import StandardScaler # 导入标准化工具,用于特征缩放
from sklearn.linear_model import LogisticRegression # 导入逻辑回归模型
from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score, roc_curve # 导入模型评估指标
from imblearn.over_sampling import SMOTE # 导入SMOTE算法,用于处理类别不平衡
from imblearn.pipeline import make_pipeline # 导入管道工具,简化工作流程
import seaborn as sns # 导入Seaborn库,用于美观的统计图表
# 1. 数据加载与探索
data = pd.read_csv('creditcard.csv') # 从CSV文件加载信用卡交易数据集
print(f"数据集形状: {data.shape}") # 打印数据集维度(行数和列数)
print(f"欺诈交易占比: {data.Class.mean()*100:.4f}%") # 计算并打印欺诈交易的比例
# 2. 数据预处理
scaler = StandardScaler() # 创建标准化器对象,用于特征缩放
data['Amount'] = scaler.fit_transform(data[['Amount']]) # 标准化"Amount"特征列(交易金额)
data = data.drop('Time', axis=1) # 删除"Time"特征列(交易时间),通常不用于模型训练
# 3. 数据分割
X = data.drop('Class', axis=1) # 创建特征矩阵X(移除目标变量列)
y = data['Class'] # 创建目标变量向量y(欺诈标签)
# 分割数据集为训练集和测试集(25%测试数据)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42, stratify=y # 使用分层抽样保持原始类别比例
)
# 4. 处理数据不平衡 (SMOTE过采样)
print("\n应用SMOTE过采样前:") # 打印当前状态
print(f"训练集类别分布:\n{y_train.value_counts()}") # 显示训练集的类别分布(欺诈和正常交易数量)
smote = SMOTE(k_neighbors=5, random_state=42) # 创建SMOTE对象,设置5个最近邻用于生成合成样本
X_res, y_res = smote.fit_resample(X_train, y_train) # 应用SMOTE算法生成平衡的训练集
print("\n应用SMOTE过采样后:") # 打印处理后的状态
print(f"训练集类别分布:\n{pd.Series(y_res).value_counts()}") # 显示过采样后的类别分布(已平衡)
# 5. 模型训练与调参
# 创建逻辑回归模型管道(包含预处理步骤和模型)
pipeline = make_pipeline(
LogisticRegression(penalty='l2', solver='liblinear', max_iter=1000, random_state=42) # 设置逻辑回归基础参数
)
# 设置参数网格(用于网格搜索调参)
param_grid = {
'logisticregression__C': np.logspace(-4, 4, 20), # 正则化强度的倒数值(指数范围从10^-4到10^4)
'logisticregression__class_weight': [None, 'balanced'] # 类别权重设置选项(平衡或不平衡)
}
# 网格搜索交叉验证(寻找最佳参数组合)
grid = GridSearchCV(
pipeline, # 管道对象(包含模型和预处理)
param_grid, # 参数搜索网格
cv=5, # 5折交叉验证
scoring='recall', # 使用召回率作为评估指标(欺诈检测的关键指标)
n_jobs=-1, # 使用所有CPU核心并行计算
verbose=1 # 显示详细日志
)
grid.fit(X_res, y_res) # 在平衡后的训练集上执行网格搜索
# 6. 最佳模型评估
best_model = grid.best_estimator_ # 获取网格搜索确定的最佳模型
y_pred = best_model.predict(X_test) # 使用最佳模型对测试集进行预测(获得类别标签)
y_proba = best_model.predict_proba(X_test)[:,1] # 获取测试集上欺诈类别的概率预测
print("\n=== 最佳模型参数 ===") # 打印最佳模型参数
print(f"正则化强度(C): {best_model.named_steps['logisticregression'].C}") # 显示最佳正则化强度
print(f"类别权重: {best_model.named_steps['logisticregression'].class_weight}") # 显示类别权重设置
print("\n=== 分类报告 ===") # 打印分类性能报告
print(classification_report(y_test, y_pred)) # 生成并显示详细的分类性能报告
print("\n=== 混淆矩阵 ===") # 打印混淆矩阵
cm = confusion_matrix(y_test, y_pred) # 计算混淆矩阵(真正例、假正例、真负例、假负例)
# 创建混淆矩阵的热力图可视化
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', # 添加数值标签,使用蓝色调色板
xticklabels=['正常', '欺诈'], # X轴标签(预测类别)
yticklabels=['正常', '欺诈']) # Y轴标签(真实类别)
plt.xlabel('预测标签') # 设置X轴标签
plt.ylabel('真实标签') # 设置Y轴标签
plt.title('混淆矩阵') # 设置图表标题
plt.show() # 显示图表
# 7. ROC曲线分析
fpr, tpr, thresholds = roc_curve(y_test, y_proba) # 计算ROC曲线的假正率和真正率
auc_score = roc_auc_score(y_test, y_proba) # 计算AUC值(ROC曲线下面积)
plt.figure(figsize=(10, 6)) # 创建新图表,设置尺寸
plt.plot(fpr, tpr, color='darkorange', lw=2, # 绘制ROC曲线(橙色)
label=f'ROC曲线 (AUC = {auc_score:.4f})') # 添加图例(包含AUC值)
plt.plot([0, 1], [0, 1], 'k--', lw=2) # 添加参考对角线(随机分类器性能)
plt.xlim([0.0, 1.0]) # 设置X轴范围
plt.ylim([0.0, 1.05]) # 设置Y轴范围
plt.xlabel('假阳性率(FPR)') # 设置X轴标签
plt.ylabel('真阳性率(TPR)') # 设置Y轴标签
plt.title('接收者操作特征(ROC)曲线') # 设置图表标题
plt.legend(loc="lower right") # 添加图例在右下角
plt.grid(True) # 添加网格线
plt.show() # 显示图表
# 8. 最优阈值选择
# 找到最接近左上角的点(最佳平衡点)
distances = np.sqrt(fpr**2 + (1-tpr)**2) # 计算每个阈值点到理想点(0,1)的欧氏距离
optimal_idx = np.argmin(distances) # 找到距离最短的索引位置
optimal_threshold = thresholds[optimal_idx] # 获取最优阈值
print(f"最佳阈值: {optimal_threshold:.4f}") # 打印最佳阈值(用于平衡召回率和精确率)
欺诈检测关键技术点解析
分层抽样(stratify=y):确保训练/测试集保持原始类别比例
SMOTE参数调优:通过调节k_neighbors控制样本合成数量
网格搜索调参:系统探索正则化强度(C)与类别权重的组合效果
阈值优化:通过ROC曲线寻找欺诈检测最佳平衡点(高召回率的同时控制假阳性)
关键性能指标
在欺诈检测场景中,召回率(Recall)和精确率(Precision)存在权衡:
- 高召回率:尽可能捕捉所有欺诈交易(可能增加误报)
- 高精确率:确保报告的欺诈更可能为真实欺诈(可能漏报)
模型 | 召回率 | 精确率 | F1分数 | AUC |
---|---|---|---|---|
无处理基础模型 | 0.65 | 0.85 | 0.73 | 0.92 |
SMOTE+正则化 | 0.89 | 0.93 | 0.91 | 0.97 |
阈值优化后 | 0.91 | 0.90 | 0.90 | 0.97 |
有关性能指标的介绍将在下一小节详细论述
五、综合技术决策指南
正则化选择策略:
- 特征维度高 → L1正则化(自动特征选择)
- 特征间相关性高 → L2正则化(稳定解)
- 需要特征选择+稳定解 → ElasticNet(L1+L2混合)
交叉验证实践建议:
- 大数据集:3-5折交叉验证
- 小数据集:10折或留一法(LOO)
- 高度不平衡数据:分层K折交叉验证
采样技术选择:
- 中度不平衡:SMOTE
- 高度不平衡:SMOTE+随机下采样混合
- 计算资源有限:NearMiss或随机下采样
评估指标选择:
- 平衡数据:准确率
- 不平衡数据:F1分数、召回率、AUC
- 成本敏感:自定义损失函数
# 定义函数:构建优化的欺诈检测模型
def build_optimal_model(X, y):
"""
构建并优化欺诈检测模型的完整流程
参数:
X: 特征矩阵
y: 目标变量
返回:
grid.best_estimator_: 经过调优的最佳模型
"""
# 1. 创建数据预处理管道
preprocessor = make_pipeline(
StandardScaler(), # 特征标准化处理器
SMOTE(k_neighbors=5, random_state=42) # SMOTE过采样处理器(处理类别不平衡)
)
# 2. 初始化基础模型和待调优参数
model = LogisticRegression(max_iter=1000, solver='liblinear') # 创建逻辑回归模型基础配置
# 定义参数网格用于网格搜索
param_grid = {
'C': [0.001, 0.01, 0.1, 1, 10, 100], # 正则化强度参数值(对数尺度)
'penalty': ['l1', 'l2'], # 正则化类型(L1或L2)
'class_weight': [None, 'balanced'] # 类别权重设置(平衡或不平衡)
}
# 3. 构建完整的处理管道
pipeline = make_pipeline(
preprocessor, # 将预处理管道作为第一步
model # 将模型作为第二步
)
# 4. 配置网格搜索进行超参数优化
grid = GridSearchCV(
pipeline, # 要优化的完整管道
param_grid, # 参数搜索空间
cv=5, # 使用5折交叉验证
scoring=['recall', 'roc_auc'], # 使用召回率和AUC作为评分指标
refit='roc_auc', # 选择AUC最高的模型作为最佳模型
n_jobs=-1 # 使用所有可用的CPU核心并行计算
)
# 5. 在数据集上训练网格搜索对象
grid.fit(X, y) # 拟合模型并进行参数搜索
# 6. 返回经过优化的最佳模型
return grid.best_estimator_ # 返回找到的最佳模型实例
本文提供了逻辑回归从理论基础到实战应用的全方位指南。通过可视化解释过拟合与正则化机制,深入解析了交叉验证参数配置细节,图解了SMOTE算法原理,并呈现了完整的信用卡欺诈检测解决方案。掌握这些技术后,您将能够构建鲁棒的分类模型,有效应对实际业务中的复杂挑战。