学习日记 7.28

在机器学习的学习之路上,线性回归逻辑回归是两块重要的基石。今天我们将通过两个实战案例,从理论到代码,全面掌握这两种算法的应用:

案例一:多元线性回归—— 根据体重和年龄预测血压收缩压;案例二:逻辑回归—— 信用卡欺诈交易检测(Kaggle 经典数据集)。


一、多元线性回归

1.1 什么是多元线性回归?

简单线性回归使用一个自变量来预测因变量,而多元线性回归则使用两个或以上的自变量。其数学表达式为:

y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + ε

其中:

y是目标变量(因变量),x₁, x₂, ..., xₙ是特征(自变量),β₀是截距,β₁, β₂, ..., βₙ是回归系数,ε是误差项。

1.2 实战:血压预测

数据集

我们使用的数据集包含三个字段:体重年龄血压收缩,共 14 条记录。

体重(kg)年龄(岁)血压收缩(mmHg)
76.050120
91.520141
85.520124
82.530126
79.030117
.........
完整代码
import pandas as pd from sklearn.linear_model import LinearRegression 1. 读取数据 data = pd.read_csv("多元线性回归.csv", encoding="gbk", engine="python") 2. 查看相关性 —— 了解各特征与目标变量之间的关系 corr = data[["体重", "年龄", "血压收缩"]].corr() print("====== 相关性矩阵 ======") print(corr) 3. 创建模型 lr_model = LinearRegression() 4. 准备特征和目标变量 x = data[['体重', '年龄']] # 特征矩阵 y = data['血压收缩'] # 目标变量 5. 训练模型 lr_model.fit(x, y) 6. 模型评估 —— R² 分数 score = lr_model.score(x, y) print(f"\n模型 R² 分数: {score}") 7. 查看模型参数 print(f"\n回归系数: {lr_model.coef_}") print(f"截距: {lr_model.intercept_:.2f}")
运行结果
====== 相关性矩阵 ====== 体重 年龄 血压收缩 体重 1.000000 -0.700283 0.906402 年龄 -0.700283 1.000000 -0.382773 血压收缩 0.906402 -0.382773 1.000000 模型 R² 分数: 0.9461441227520285
结果深度解读

1. 相关性矩阵分析

体重 年龄 血压收缩 体重 1.000000 -0.700283 0.906402 年龄 -0.700283 1.000000 -0.382773 血压收缩 0.906402 -0.382773 1.000000

从相关性矩阵中可以得出以下结论:

关系相关系数解读
体重 ↔ 血压收缩0.906强正相关—— 体重越大,收缩压越高。这是影响血压的最主要因素
年龄 ↔ 血压收缩-0.383弱负相关—— 在这组数据中,年龄与血压呈现轻微负相关
体重 ↔ 年龄-0.700中等负相关—— 数据中体重和年龄存在一定的负相关关系

关键发现:体重的相关系数高达 0.906,说明体重是影响收缩压的核心因素。而年龄在本数据集中与收缩压呈弱负相关(-0.383),这可能与样本特性有关。

2. R² 分数分析

模型 R² 分数为0.9461,这意味着:

模型能够解释94.61%的血压收缩压变化。拟合效果非常好,说明体重和年龄这两个特征对血压有很强的解释力。不过需要注意:这里 R² 是在训练集上计算的,没有做训练集/测试集划分(14 条数据太少)。在实际项目中,应该划分数据集并用测试集来评估,避免过拟合


二、逻辑回归 —— 信用卡欺诈检测

2.1 什么是逻辑回归?

尽管名字里有"回归",但逻辑回归是一种分类算法。它通过 Sigmoid 函数将线性回归的输出映射到 [0, 1] 区间,从而得到属于某个类别的概率:

P(y=1|x) = 1 / (1 + e^-(β₀ + β₁x₁ + ... + βₙxₙ))

对于二分类问题,通常设定阈值为 0.5:

概率 ≥ 0.5 → 正类(1,欺诈交易);概率 < 0.5 → 负类(0,正常交易)。

2.2 数据集介绍

本案例使用的是Kaggle 信用卡欺诈检测数据集,包含约 28.5 万条交易记录。

字段说明
Time交易时间(秒)
V1 ~ V28PCA 降维后的特征(脱敏处理)
Amount交易金额
Class标签:0 = 正常交易,1 = 欺诈交易

2.3 完整代码详解

Step 1:读取数据并查看基本信息
import pandas as pd data = pd.read_csv(r"./creditcard.csv") print(data.head())

输出结果(前 5 行):

Time V1 V2 V3 V4 V5 ... V27 V28 Amount Class 0 0.0 -1.359807 -0.072781 2.536347 1.378155 -0.338321 ... 0.133558 -0.021053 149.62 0 1 0.0 1.191857 0.266151 0.166480 0.448154 0.060018 ... -0.008983 0.014724 2.69 0 2 1.0 -1.358354 -1.340163 1.773209 0.379780 -0.503198 ... -0.055353 -0.059752 378.66 0 3 1.0 -0.966272 -0.185226 1.792993 -0.863291 -0.010309 ... 0.062723 0.061458 123.50 0 4 2.0 -1.158233 0.877737 1.548718 0.403034 -0.407193 ... 0.219422 0.215153 69.99 0 [5 rows x 31 columns]

数据共有 31 列,包含 28 个 PCA 特征(V1~V28)、Time、Amount 和 Class 标签。可以看到 Amount 列的数值(149.62, 2.69, 378.66...)差异很大,后面需要进行标准化处理。

Step 2:数据预处理 —— Z-score 标准化
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() data['Amount'] = scaler.fit_transform(data[['Amount']]) data = data.drop(['Time'], axis=1)

为什么要对 Amount 做标准化?

Amount列的数值范围(0 ~ 25691)远大于 V1~V28(经过 PCA 后基本在 [-5, 5] 范围内)。如果不进行标准化,模型会错误地认为 Amount 比其他特征重要得多,从而影响模型效果。

Z-score 标准化公式:

zᵢⱼ = (xᵢⱼ - x̄ᵢ) / sᵢ

x̄ᵢ:该特征的均值(数学期望);sᵢ:该特征的标准差;标准化后数据均值为 0,标准差为 1。

这里我们把Time列删除了 —— 交易发生的绝对时间与欺诈行为之间通常没有直接的线性关系,保留它反而可能引入噪声。

Step 3:数据可视化 —— 查看正负样本分布
import matplotlib.pyplot as plt from pylab import mpl 解决中文显示问题 mpl.rcParams['font.sans-serif'] = ['Microsoft YaHei'] mpl.rcParams['axes.unicode_minus'] = False 统计类别数量并绘图 labels_count = data['Class'].value_counts() print(labels_count) plt.title("正负样本分布") plt.xlabel("类别") plt.ylabel("频数") labels_count.plot(kind='bar') plt.show()

输出结果:

Class 0 284315 1 492 Name: count, dtype: int64

这个结果非常震撼:

类别数量占比
正常交易(0)284,31599.83%
欺诈交易(1)4920.17%

关键发现:正常交易和欺诈交易的比例约为578:1!这意味着每 579 笔交易中才可能出现 1 笔欺诈交易 —— 这是一个极度不平衡的数据集

Step 4:划分训练集和测试集
from sklearn.model_selection import train_test_split X_model = data.drop(['Class'], axis=1) # 特征矩阵(29列) y_model = data.Class # 标签列 X_train_w, X_test_w, y_train_w, y_test_w = train_test_split( X_model, y_model, test_size=0.3, # 30% 作为测试集 random_state=1000 # 随机种子,保证结果可复现 )

train_test_split 参数说明:

参数含义
test_size=0.330% 的数据划分为测试集,70% 为训练集
random_state=1000固定随机种子,确保每次运行得到相同的划分结果
Step 5:训练逻辑回归模型
from sklearn.linear_model import LogisticRegression C 是正则化强度的倒数:C 越小,正则化越强,模型越简单 lr = LogisticRegression(C=0.01) lr.fit(X_train_w, y_train_w)

关于参数 C 的深入理解:

C是正则化强度的倒数C = 0.01:正则化非常强 → 防止模型过拟合。逻辑回归默认使用L2 正则化(岭回归)。这里选较小的 C 值,是因为数据极度不平衡,需要用强正则化来约束模型。

Step 6:模型评估
test_predicted = lr.predict(X_test_w) # 对测试集进行预测 result = lr.score(X_test_w, y_test_w) # 计算准确率 print(f"模型准确率: {result}")

输出结果:

模型准确率: 0.9990168884519505
运行结果深度解读

准确率高达99.90%,这看起来非常优秀!但这里有一个重要陷阱

准确率 = 99.90% 并不意味着模型真的很好!

还记得我们之前统计的类别分布吗?欺诈交易只占 0.17%。如果我们写一个"傻瓜模型"——把所有交易都预测为正常交易

# 傻瓜策略:全部预测为 0 dummy_accuracy = (y_test_w == 0).sum() / len(y_test_w) print(f"全部预测为正常的准确率: {dummy_accuracy}") # 输出约: 0.9983 (99.83%)

这个"什么都不做"的策略也能达到99.83%的准确率!所以:

核心结论:在不平衡数据集中,准确率(Accuracy)不是一个可靠的评估指标。我们需要关注的是:

精确率(Precision):被预测为欺诈的交易中,有多少是真正的欺诈?召回率(Recall):真正的欺诈交易中,有多少被模型检测出来了?F1 分数:精确率和召回率的调和平均。AUC-ROC:模型区分正负样本的能力。


三、线性回归 vs 逻辑回归:对比总结

对比维度线性回归逻辑回归
任务类型回归(预测连续值)分类(预测离散类别)
输出范围(-∞, +∞)[0, 1](概率值)
损失函数均方误差(MSE)交叉熵损失(Log Loss)
激活函数无(线性输出)Sigmoid 函数
评估指标R², MAE, MSE, RMSE精确率、召回率、F1、AUC-ROC
典型应用房价预测、气温预测垃圾邮件检测、欺诈检测、疾病诊断

四、实战经验总结

4.1 两个案例的对比启示

维度案例一(线性回归)案例二(逻辑回归)
数据量14 条(小样本)28.5 万条(大数据)
特征数2 个29 个
核心挑战样本太少,容易过拟合样本极度不平衡
R²/准确率0.9461(优秀)0.9990(看似优秀,实则存疑)
可信度需更多数据验证不能只看准确率

4.2 关键

R² = 0.9461 说明什么?体重和年龄共同解释了 94.61% 的血压变异。但 14 条数据太少,模型可能过拟合,需要更多样本验证。准确率 = 99.90% 说明什么?单独看:模型表现极好。结合类别分布看:几乎所有样本都是负类,"全部预测为 0"也有 99.83%。真相:模型的提升仅为 0.07%,这点提升来自正确识别了极少数的欺诈交易。数据预处理的重要性:Amount 标准化消除量纲差异,避免大数值特征主导模型;Time 删除去除与目标变量无关的特征,减少噪声;相关性分析中体重与血压的相关性(0.906)远超年龄(-0.383)。


五、进阶建议

针对信用卡欺诈检测案例,可以从以下方向继续优化:

处理样本不平衡:设置class_weight='balanced'让模型自动按类别频率调整权重;或用 SMOTE 过采样(random_state=42固定随机种子,保证结果可复现)。

更全面的模型评估:不平衡数据中准确率不可靠,应关注精确率、召回率、F1 和 AUC,用classification_reportroc_auc_score全面评估。