2026.09.15 09:56
学习路线
Python -> Python数据分析 -> LangChain -> LangGraph -> FastAPI + SQLAIchemy -> 机器学习 -> 神经网络 -> NLP -> Coze -> Dify -> 大模型应用基础 -> 大模型微调 -> 多模态 -> vibeCoding -> Hermes -> Docker
复习巩固总结
1. 回归模型_评估方法
| 公式要点 | 单位 | 特点 | |
|---|---|---|---|
| MAE | 绝对误差的平均 | 与 相同 | 不容易被个别离谱点拉爆 |
| MSE | 平方误差的平均 | 的平方 | 惩罚大误差,训练常用 |
| RMSE | 与 相同 | 评估时比 MSE 好看懂,但对异常点更敏感 |
MAE 和 RMSE 都能反映真实误差,但不能说 RMSE 更好,也不该只盯着 RMSE 把误差压下去:
- 若训练时只把 RMSE 压得很低,说明模型把异常点(噪声)也拟合得很紧
- 这样很容易过拟合
- 所以评估要几个指标一起看,不要只信一个数
代码示例如 2.2
2. 梯度下降法
2.1 算法分类
2.1.1 随机梯度下降 SGD(Stochastic Gradient Descent)
每次迭代随机抽 1 个样本,只用这一条的梯度更新:
是这一步抽到的那个人。简单、高效,但不稳定:每步只看一条,碰上噪声样本容易被带偏
2.1.2 对比
| 算法 | 每步用几个样本 | 优点 | 缺点 |
|---|---|---|---|
| FGD | 全部 个 | 方向准。§43 手算的就是这个 | 数据大就慢 |
| SGD | 随机 个 | 简单、快。SGDRegressor | 不稳定,噪声样本会带偏 |
| mini-batch | 随机 个() | 快和稳折中,目前用得最多 | 要选 |
| SAG | 抽 个重算,用历史梯度均值更新 | 后期接近 FGD 的稳、又省扫描 | 初期慢(梯度先当 ,还掺旧值) |
2.2 多元线性回归 - 使用梯度下降SGDRegressor
"""
案例:
演示:随机梯度下降法 线性回归对象 完成 波士顿房价预测案例
回顾:
线性回归算法 属于 有监督学习之 有特征,有标签,且标签是连续的
线性回归分类:
一元线性回归:1个特征列,1个标签列
多元线性回归:多个特征列,1个标签列
线性回归大白话解释:
它是用线性公式来描述 特征 和 标签 之间的关系的,方便做预测,公式如下:
一元线性回归:y = w * x + b
多元线性回归:y = w1 * x1 + w2 * x2 + ... + wn * xn + b = w的转置 * x + b
如何衡量线性回归模型的好坏?
思路:
预测值和真实值之间的误差,误差越小,模型越好 => 损失函数
具体的方案:
1. 最小二乘法: 每个(样本)误差平方和
2. 均方误差(MSE) 每个(样本)误差平方和 / 样本总数
3. 均方根误差(RMSE) 每个(样本)误差平方和 / 样本总数 的 平方根
4. 平均绝对误差(MAE) 每个(样本)误差绝对值和 / 样本总数
如何让损失函数最小?
思路1:梯度下降法
全梯度下降(Full Gradient Descent,FGD)
随机梯度下降(Stochastic Gradient Descent,SGD)
小批量梯度下降(推荐,Mini-batch Gradient Descent,MBGD)
随机平均梯度下降(Stochastic Average Gradient Descent,SAG)
思路2:正规方程法
机器学习开发流程:
1. 加载数据
2. 数据的预处理
3. 特征工程(特征提取,特征预处理...)
4. 模型训练
5. 模型预测
6. 模型评估
"""
# 导包
from sklearn.preprocessing import StandardScaler # 特征处理
from sklearn.model_selection import train_test_split # 数据集划分
from sklearn.linear_model import LinearRegression # 正规方程的回归模型
from sklearn.linear_model import SGDRegressor # 梯度下降的回归模型
from sklearn.metrics import mean_absolute_error, mean_squared_error, root_mean_squared_error # 均方误差评估
from sklearn.linear_model import Ridge, RidgeCV # 岭回归
import pandas as pd # 数据处理
import numpy as np # 数组处理
# 1. 加载波士顿房价数据
data_url = "https://raw.githubusercontent.com/Csengupta1101/Datasets/main/BostonHousing.csv"
raw_df = pd.read_csv(data_url, storage_options={"User-Agent": "Mozilla/5.0"})
data = raw_df.drop(columns=["medv"]).values # 前 13 列是特征
target = raw_df["medv"].values # 最后一列房价是标签
# 2. 数据的预处理,按照 8:2 切分 训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.2, random_state=23)
# 3. 特征工程(特征提取,特征预处理...)
# 3.1 创建标准化对象
transfer = StandardScaler()
# 3.2 对训练集进行标准化
x_train = transfer.fit_transform(x_train)
# 3.3 对测试集进行标准化
x_test = transfer.transform(x_test)
# 4. 模型训练
# estimator = LinearRegression(fit_intercept=True) # 正规方程法 线性回归对象
# 4.1 创建 线性回归 随机梯度下降 模型对象
# 参1:fit_intercept:是否计算截距(Bias,偏置),默认是True
# 参2:learning_rate:学习率模式 -> 常量,即:不会发生改变
# 参3:eta0:学习率
estimator = SGDRegressor(fit_intercept=True, learning_rate="constant", eta0=0.01)
# 4.2 模型训练
estimator.fit(x_train, y_train)
# 4.3 打印模型计算出的 w(权重,weight)和 b(偏置,bias)
print(f'权重:{estimator.coef_}')
print(f'偏置:{estimator.intercept_}')
# 5. 模型预测
y_pre = estimator.predict(x_test)
# 6. 模型评估
# MSE: 均方误差,每个样本的误差平方和 / 样本总数
print(f'均方误差:{mean_squared_error(y_test, y_pre)}') # 参1:测试集的真实标签,参2:测试集的预测标签
# RMSE: 均方根误差,均方误差的平方根
print(f'均方根误差:{root_mean_squared_error(y_test, y_pre)}') # 参1:测试集的真实标签,参2:测试集的预测标签
# MAE: 平均绝对误差,每个样本的误差绝对值和 / 样本总数
print(f'平均绝对误差:{mean_absolute_error(y_test, y_pre)}') # 参1:测试集的真实标签,参2:测试集的预测标签
2.3 一元线性回归 - 使用正规方程LinearRegression
# 导包
from sklearn.linear_model import LinearRegression
# 案例:演示线性回归API入门
# 1. 准备数据
x_train = [[160], [166], [172], [174], [180]] # 训练集的特征
y_train = [56.3, 60.6, 65.1, 68.5, 75] # 训练集的标签
x_test = [[176]] # 测试集的特征
# 2. 数据的预处理,这里不需要
# 3. 特征工程(特征提取,特征预处理),这里不需要
# 4. 模型训练
# 4.1 创建模型对象
estimator = LinearRegression()
# 4.2 具体的训练动作
estimator.fit(x_train, y_train)
# 4.3 因为是线性回归模型,我们可以查看下:斜率(w,权重),截距(b,偏置)
print(f'斜率(w,权重):{estimator.coef_},截距(b,偏置):{estimator.intercept_}')
# 0.92942177 -93.27346938775517
# 5. 模型评估
y_pre = estimator.predict(x_test)
print(f'模型预测:{y_pre}') # 70.3047619
# 6. 模型评估
2.4 正规方程 vs 梯度下降
| 梯度下降 | 正规方程 | |
|---|---|---|
| 学习率 | 要选 | 不需要 |
| 怎么求 | 迭代多步 | 一次算完 |
| 特征很多 / 数据很大 | 能用,深度学习主要靠它 | 求逆太慢或没逆 |
| 噪声、特征相关 | 仍能走(SGD 还会抖) | 容易被带偏,相关时可能没逆 |
| 适用损失 | 各种可微损失 | 基本是线性最小二乘 |
| 典型场景 | 嘈杂、大数据、深度模型 | 小数据、要精确的线性回归 |
3. 拟合
| 情况 | 训练集 | 测试集 | 曲线长什么样 |
|---|---|---|---|
| 欠拟合 under-fitting | 很差 | 很差 | 直线硬切弯数据,趋势都没学到 |
| 正好拟合 Just right | 好 | 好 | 平滑曲线跟着大趋势走,不追每个点 |
| 过拟合 over-fitting | 很好 | 很差 | 折线穿过几乎每个点,把噪声也记住了 |
3.1 欠拟合
3.1.1 代码模拟
# 1. 定义函数,模拟:欠拟合
def dm01_under_fitting():
# pass
# 1. 准备数据
# 1.1 指定随机种子,则每次生成(噪声)的数据都是固定的
np.random.seed(23)
# 1.2. 随机生成x轴 100 个数据,模拟:特征
# 参1:x轴最小值 参2:x轴最大值 参3:生成个数
x = np.random.uniform(-3, 3, size=100)
# 1.3. 基于x轴值,通过线性公式,生成y轴 100 个数据,模拟:标签
# 线性公式:y = kx + b = 0.5 * x ** 2 + x + 2 + 噪声
# 参1:平均值 参2:标准差 参3:生成个数
y = 0.5 * x ** 2 + x + 2 + np.random.normal(0, 1, size=100)
# 1.4 查看生成的 x轴(特征)和 y轴(标签)的数据
# print(f'x轴(特征):{x}')
# print(f'y轴(标签):{y}')
# 2. 数据预处理,把x轴(特征)转成 多行1列的形式
X = x.reshape(-1, 1)
# print(f'处理后的特征:{X}')
# 3. 特征工程,这里不做了,直接用100条数据,先训练,后预测
# 4. 训练模型
# 4.1 创建模型对象
estimator = LinearRegression() # 正规方程 线性回归模型
# 4.2 模型训练
estimator.fit(X, y) # 参1:处理后的特征数据 参2:标签数据
# 5. 模型预测
y_pre = estimator.predict(X) # 处理后的特征数据
# 6. 模型评估
print(f'均方误差:{mean_squared_error(y, y_pre)}') # 参1:真实值,参2:预测值
# 7. 绘图
plt.scatter(x, y) # 以散点图的形式绘制 真实值
plt.plot(x, y_pre, color='red') # 以线图的形式绘制 预测值
plt.show()
3.1.2 解决办法
- 组合:把已有特征拼在一起
- 泛化:把具体值做成更宽的表征
- 相关性:把和目标相关、但还没进模型的特征加进来
# 2. 定义函数,模拟:恰好拟合
# def dm01_under_fitting():
def dm02_just_fitting():
# ...
# 2. 数据预处理,把x轴(特征)转成 多行1列的形式
# 2.1 把上述的x轴(特征)转成 多行1列的形式,即:[[1], [2], [3], ..., [100]]
X = x.reshape(-1, 1)
# print(f'处理后的特征:{X}')
# 2.2 因为目前特征列只有1列,模型过于简单,会出现欠拟合的问题,我们增加1列 特征列,从而增加模型的复杂度
# 即:把数据从 [[1], [2], [3], ..., [100]] => [[1, 1], [2, 4], [3, 9], ..., [100, 10000]]
X2 = np.hstack([X, X ** 2]) # 该函数作用:横向拼接,即:拼接2个数组,拼接后数组的行数不变,拼接后数组的列数等于拼接前的列数之和
# ...
# 7. 绘图
plt.scatter(x, y) # 以散点图的形式绘制 真实值
# np.sort(x):对x轴(特征)进行排序,默认是:升序
# np.argsort(x):对x轴(特征)进行排序,返回的是排序后的索引
# 例如:排序前x轴是 [11, 33, 22] -> 对应索引:[0, 1, 2]
# 排序后:x轴是 [11, 22, 33] -> 对应索引:[0, 2, 1]
# plt.plot(x, y_pre, color='red') # 以线图的形式绘制 预测值
plt.plot(np.sort(x), y_pre[np.argsort(x)], color='red')
plt.show()
3.2 过拟合
3.2.1 代码模拟
# 3. 定义函数,模拟:过拟合
def dm03_over_fitting():
# ...
# 2.2 因为目前特征列只有1列,模型过于简单,为了模拟过拟合,我们增加9列 特征列,从而增加模型的复杂度
# 即:把数据从 [[1], [2], [3], ..., [100]] => [[1, 1², 1³, ..., 1⁹], [2, 4, 8, ..., 512], [3, 9, 27, ..., 729], ..., [100, 10000, 1000000, ..., 1000000000]]
# 该函数作用:横向拼接,即:拼接多个数组,拼接后数组的行数不变,拼接后数组的列数等于拼接前的列数之和
# X2 = np.hstack([X, X ** 2])
X3 = np.hstack([X, X ** 2, X ** 3, X ** 4, X ** 5, X ** 6, X ** 7, X ** 8, X ** 9])
# ...
3.2.2 解决办法
- 重新清洗数据:异常点过多、数据不纯的地方再处理一遍(异常值检测、去噪声),少让模型去记脏特征。
- 增大训练量:原来那点数据被训练得太过了;样本变多,同样复杂度的模型更难把噪声当成规律,过拟合会缓解。
- 正则化:专门用来压过拟合,机器学习和深度学习里都大量用。
- 减少特征维度,防止维灾难:特征太多、样本太少时,空间被撑得很空,学不充分,泛化差。降维(少特征)等于把模型从「太复杂」往回拉。
正则化分为L1正则化和L2正则化:
- L1 会让权重趋向 0,甚至等于 0。等于 0 的那些特征等于失效,所以 L1 能做特征筛选。
- L2 会让权重趋向 0,一般不等于 0(减弱影响,不删特征)。
3.2.2.1 L1正则化
:惩罚系数(sklearn 里叫 alpha)。越大,对特征权重罚得越狠,权重被往 0 拉的幅度越大。
使用 L1 的线性回归叫 Lasso:
from sklearn.linear_model import Lasso
# 4. 定义函数,模拟:L1正则化
def dm04_l1_regularization():
# ...
# 4. 训练模型
# 4.1 创建模型对象
# estimator = LinearRegression() # 正规方程 线性回归模型
# 改为创建 L1正则化对象
estimator = Lasso(alpha=0.1) # alpha:正则化系数(惩罚系数),默认是1
# ...
3.2.2.2 L2正则化
:同样是惩罚系数。越大,对特征权重罚得越狠。
使用 L2 的线性回归叫岭回归:
from sklearn.linear_model import Ridge
# 5. 定义函数,模拟:L2正则化
def dm05_l2_regularization():
# ...
# 4. 训练模型
# 4.1 创建模型对象
# estimator = Lasso(alpha=0.1) # alpha:正则化系数(惩罚系数),默认是1
# 改为创建 L2正则化对象
# estimator = Ridge(alpha=0.1)
estimator = Ridge(alpha=10)
# ...
4. 逻辑回归
4.1 简介
逻辑回归 = 有监督学习,有特征、有标签,且标签是离散的(分类)= 适用于二分类。
线性回归的标签是连续的(房价、授信额度);逻辑回归的标签是离散的(是/否、A/B)。它仍是有监督学习:有特征、有标签,但干的是分类,而且课件这一章主要讲二分类。
Sigmoid 也叫 S 型函数,在神经网络里常当激活函数。线性回归吐出来的是任意实数,分类要的是 之间的概率,中间就靠它压。
- 先按线性回归算出一个实数(可正可负、可很大很小)
- 丢进 Sigmoid,压成 之间的概率
- 拿你写的阈值去切:课件例子是 判 A(正样本),否则判 B(负样本)
逻辑回归是解决二分类问题的利器:输出只有两边,是或不是
4.2 相关概念
4.2.1 精确率/召回率
4.2.2 混淆矩阵
| 预测值(正例) | 预测值(反例) | |
|---|---|---|
| 真实值(正例) | 真正例 TP(True Positive) | 伪反例 FN(False Negative) |
| 真实值(假,反例) | 伪正例 FP(False Positive) | 真反例 TN(True Negative) |
- TP:真是正的,也预测成正的
- FN:真是正的,却预测成负的(漏检)
- FP:真是负的,却预测成正的(误报)
- TN:真是负的,也预测成负的
4.3 数学基础 - Sigmoid 函数
这里是线性回归的预测值(,可正可负、可到 )。作用:把 映射到 。
几个常用点:
- 单调递增:线性预测越大,概率越大,不会扭回来
- 拐点在 :曲线在这儿从下凸换成上凸,也是默认阈值常取 的原因
- 两端饱和:离 0 很远时曲线几乎贴着 0 或 1,梯度很小
导数:
机器学习
55. 概率相关知识回顾
课件这块是给后面 打底:先分清「单独发生」「一起发生」「已知一件再发生另一件」。
55.1 概率
概率:事件发生的可能性,取值 。联合概率、条件概率都是概率论里描述随机变量之间关系的基本概念。
课件例子:北京堵车
| 事件 | 含义 | 概率 |
|---|---|---|
| 早上堵车 | ||
| 中午堵车 | ||
| 晚上堵车 |
55.1.1 联合概率
两个或多个事件同时发生的概率,记 或 。
只有在相互独立时才能拆成相乘:
课件:周一早上、周二早上都堵。若两天相互独立、每天早上堵车都是 :
不独立就不能直接乘。比如「早上堵」和「中午堵」往往相关(早高峰堵了,中午更可能还堵), 不一定等于 。
55.1.2 条件概率
条件概率:在事件 已经发生的前提下,事件 再发生的概率:
分母是「已知那件」的概率,分子是「两件一起发生」。乘法公式反过来说就是 。
对照:
| 公式 | 课件那组数(先假设独立) | 含义 | |
|---|---|---|---|
| 联合 | 早上且中午都堵 | ||
| 条件 | 已知早上堵了,中午还堵 |
记法统一用 :竖线右边是已经知道的。
55.2 极大似然估计
核心思想:根据已经观测到的结果,反推模型里那个未知参数最像是多少。
未知参数 先「产生」出数据(人、样本、对话),再用这些数据去估计 。正向是「参数 → 数据」,极大似然是倒过来「数据 → 参数」。
55.2.1 硬币例子
一枚不均匀的硬币,正面概率记 ,反面就是 。抛 6 次,现象
4 正 2 反。每次投掷相互独立,所以整段序列的联合概率可以拆成相乘(55.1.1):
是「参数取 时,碰巧看到这份数据的概率」。 未知,这份 已经发生了,于是把上式看成 的函数,叫似然函数:
问题变成:哪个 让 最大?——最能「解释」这 6 次结果的那个正面概率。
55.2.2 求导找极大值
对 求导,令导数为 0:
给出三个根:
或 时,(数据里正、反都出现过,说「永远正面」或「永远反面」完全解释不了 )。真正的极大值在
和直觉一致:6 次里 4 次正面,频率就是 。伯努利试验的极大似然估计,就是样本里「成功」的比例。
55.3 对数函数
55.3.1 定义
若 ( 且 ),则 叫做以 为底 的对数:
例子:(因为 ),(因为 )。
55.3.2 三条运算性质
定义域:,。(课件写成「」,底数排除的是 不是 。)
第一条就是课件那句话:几个概率连乘,可以改成 log 相加。
55.3.3 用回硬币的似然
上一节似然 是连乘。样本一多, 这类数会下溢成 。对数能把乘法变加法,极大值的位置不变( 单调递增),所以实际都改成最大化 。
连乘变成两项相加,求导不再用乘法法则硬拆:
和 55.2.2 直接对 求导的结果一样,步骤短一截。逻辑回归里每条样本一个 或 ,似然是 项连乘,训练时优化的就是这个对数似然(再取负变成损失去最小化)。
55.4 练习:正态均值的极大似然
总体 的密度是
这是 (方差钉死为 ,只估均值 )。抽到独立样本 ,求 的极大似然估计。
55.4.1 写似然,再取
各样本独立,联合密度是连乘(55.1.1):
连乘不好下手,两边取 (55.3)。,:
第一项不含 ,最大化 等价于最小化 ——点离均值越近,似然越大。
55.4.2 对 求导
所以
令导数为 :
的极大似然估计就是样本均值。课件写「当 时概率最大」,应为 时似然最大( 是已观测的一串数,不能再当未知量)。
和硬币那题同一套路:硬币的 是正面出现的频率;正态的 是样本的平均。都是「用数据里最像那个参数的统计量去估」。
56. 逻辑回归_原理介绍
56.1 概念
逻辑回归(Logistic Regression)是一种分类模型:把线性回归的输出,当作逻辑回归的输入。模型吐出来的是 之间的值(正类概率),不是房价那种连续标签。
整条链就一句话:
线性回归预测值 → Sigmoid 映射到 → 结合阈值,划分正样本 / 负样本。
56.1.1 基本思想
- 用线性模型按特征重要性打一个分:
大的特征话语权大。这个 可正可负、可到 ,还不是概率。
- 用 Sigmoid 把 压成概率 。再设阈值(课件常用 或 ):
- 概率 大于 阈值 → 判 1 类(正类 / A)
- 否则 → 判 0 类(负类 / B)
56.1.2 假设函数
括号里仍是线性回归那一项;外面套上 Sigmoid,才变成逻辑回归。所以:线性回归的输出 = 逻辑回归的输入。
56.1.3 预测过程(阈值 )
约定:Sigmoid 给出的是属于 A 的概率。 判 A,否则判 B。
样本先和权重做回归计算得到 ,再过 Sigmoid 得到 ,最后按 切开:
| 特征 | 回归预测值 | 逻辑回归 | 预测(阈值 ) | 真实 |
|---|---|---|---|---|
| B | A | |||
| A | B | |||
| B | A | |||
| B | B | |||
| A | A |
、 判 A;、、 都不到 ,判 B。五条里对了后两条,前三条预测和真实反着——权重还没训好,或阈值和数据对不齐,后面用极大似然去调 。
表里 动辄 、,真代入 Sigmoid 会几乎贴死 ,不会出现 。课件这组数是在演示流程,不是按公式手算出来的;真实计算仍是 。
56.2 损失函数
线性回归用 MSE 看「差了多少」;逻辑回归输出的是概率,损失改成对数损失(二分类交叉熵)。它就是 55.2 里似然取 再加负号:最大化「看到这些标签」的概率,等价于把这个损失压下去。
编码:(正样本),(负样本)。 是真实标签,预估的是 。
56.2.1 在干什么
每个样本模型都给出两个数:(是 A 的概率)和 (是 B 的概率)。损失只盯真实那一类对应的那个概率:越大越好。外面的负号把「越大越好」翻成「越小越好」,才能当损失。
只能是 或 ,两项里永远只活一项:
| 真实 | 活下来的那项 | 含义 |
|---|---|---|
| (正样本) | 真实是 A,希望 靠近 | |
| (负样本) | 真实是 B,希望 靠近 |
真实类时, 靠近 ,损失靠近 ;预测反了(真实是 A 却 ),,损失爆炸。
56.2.2 手工计算
沿用 56.1.3 那五条, 仍用课件表上的数, 按真实 A/B 编成 :
| 代入 | 这一项 | |||
|---|---|---|---|---|
| 1 | ||||
| 2 | ||||
| 3 | ||||
| 4 | ||||
| 5 |
总损失是这些数求和再取负:
第 1 条真实是 A 却只给了 的把握, 比较大,在罚;第 5 条 更贴近真实正类, 更小。把 调到让这份 Loss 下降,就是在用极大似然估逻辑回归的参数。
56.2.3 损失函数从哪来
推导拆成「1 个样本 → n 个样本 → 让联合概率最大」。公式不是拍出来的,就是硬币那道极大似然(55.2),把共用的 换成每条样本自己的 。
1. 一个样本的概率
两类: 和 。模型认为这条样本是 类的概率为 ,是 类就是 。真实标签对应的那一项,就是这条样本对似然的贡献(课件写成 ,容易和后面的 Loss 撞名,这里用 ):
当开关: 时 ; 时 。
真实标签在模型看来有多大概率发生。真实是 ,希望 越大越好;真实是 ,希望 越大越好。
2. 个样本的概率
训练集 。各样本独立,联合概率连乘:
- :第 条被判成 类的概率,
- :第 条的真实类别, 或
3. 极大似然 → 对数似然 → 损失
连乘会下溢, 单调,改成最大化对数似然 (记 ,就是 ):
仍是 Sigmoid:
在 时是 ,会除零;Sigmoid 在 必须是 ,只有 才对。
梯度下降默认下山,把最大化 翻成最小化 :
逻辑回归损失函数 极大似然(对数似然)函数。 这就是 56.2 的式子。
4. 用梯度下降更新 、
对 求 、 的梯度,按下式迭代(和线性回归同一套路,只是损失换成了交叉熵):
是学习率。损失下降 对数似然上升 越来越能解释这批真实标签。
56.2.4 练习
以下关于逻辑回归的说法正确的是?(多选)
- A)逻辑回归应用在分类场景中
- B)逻辑回归使用了回归将特征数据进行拟合
- C)逻辑回归使用了 sigmoid 激活函数将回归的结果映射到了 值域中
- D)逻辑回归的损失函数使用了极大似然估计,因为其输出值是一个概率
答案:ABCD。
- A:名字带「回归」,干的是二分类(疾病阴阳性、放贷与否)。
- B:先有线性式 按特征打分,这块就是回归拟合。
- C:Sigmoid 把 压到 ,当正类概率。
- D:输出是概率,似然按伯努利来写,损失就是 对数似然。
57. 逻辑回归案例_癌症预测
57.1 API 介绍
sklearn 封装好了逻辑回归,损失、Sigmoid、梯度更新都在 fit 里面:
from sklearn.linear_model import LogisticRegression
estimator = LogisticRegression(solver='liblinear', penalty='l2', C=1.0)
57.1.1 solver:优化方法
solver 是怎么把交叉熵压下去(优化器),不是换模型。
| solver | 适合 | 正则 |
|---|---|---|
| liblinear | 小数据更快(坐标下降那一类) | L1、L2 |
| sag | 大数据更快(随机平均梯度,DAY9 的 SAG) | L2,或不要正则 |
| saga | 大数据,sag 的改进版 | L1、L2,或不要正则 |
课件口诀:小数据用 liblinear;数据大改 sag / saga。要 L1(稀疏、特征筛选)只能 liblinear 或 saga,纯 sag 没有 L1。
现在 sklearn 默认 solver 多半是 'lbfgs'(二分类 L2 够用)。solver 和 penalty 必须配对,否则会报错。
57.1.2 penalty 和 C
penalty:'l1'或'l2',和岭回归 / Lasso 同一套:L2 把权重往 0 缩,L1 能缩到正好 0。C:正则强弱的倒数。损失里是 正则项。C越大,罚得越轻,越接近不正则(容易过拟合)C越小,罚得越狠,权重越扁
Ridge 里是 alpha 越大罚越狠;这里不要把 C 当成 alpha。默认 C=1.0。
57.1.3 谁当正例
正类要自己对上业务,一般将类别数量少的当做正例,但不要默认少数类就是正例。
57.2 数据描述
UCI 威斯康星乳腺癌原表(Original Breast Cancer),二分类:良性 / 恶性。
| 项目 | 内容 |
|---|---|
| 样本量 | 699 条 |
| 列数 | 11 列:1 个 id + 9 个医学特征 + 1 个标签 |
| 缺失 | 16 个,用 ? 标出(主要在 Bare Nuclei) |
| 标签 | 2 = 良性,4 = 恶性 |
第一列 Sample code number 只是检索用的编号,不能当特征(否则模型会记病人编号,没有泛化)。中间 9 列才是肿瘤相关特征,最后一列 Class 是要预测的肿瘤类型。
57.2.1 九列特征
课件表头(B~J)就是这九列,取值一般都在 :
| 列 | 英文 | 含义(大意) |
|---|---|---|
| B | Clump Thickness | 肿块厚度 |
| C | Uniformity of Cell Size | 细胞大小一致性 |
| D | Uniformity of Cell Shape | 细胞形状一致性 |
| E | Marginal Adhesion | 边缘粘附 |
| F | Single Epithelial Cell Size | 单上皮细胞大小 |
| G | Bare Nuclei | 裸核(这列有 ?) |
| H | Bland Chromatin | 染色质 |
| I | Normal Nucleoli | 核仁 |
| J | Mitoses | 有丝分裂 |
K 列 Class 是标签。表上 2 居多是良性,出现 4 是恶性。
57.2.2 读表时要注意
- 标签已经是离散的 ,不是连续房价——所以用逻辑回归做分类,不是线性回归。
- 和 只是编码,进模型前常映射成 (良性 、恶性 )。不映射也可以:sklearn 会按数值排序,
classes_ = [2, 4],predict_proba第二列就是恶性概率——和业务上「恶性当正例」碰巧一致。 - 16 个
?必须先处理(删行或填补),否则fit进不去。 - 699 条算小数据,
solver='liblinear'和课件示范匹配。
57.2.3 代码实现
"""
案例:
演示逻辑回归模型实现 癌症预测
逻辑回归模型介绍:
概述:
属于有监督学习,即:有特征,有标签,且表示离散的
主要适用于:二分类
原理:
把线性回归处理后的预测值 -> 通过 Sigmoid 激活函数,映射到 (0, 1) 概率 -> 基于自定义的阈值,结合概率来分类
损失函数:
极大似然估计函数的 负数形式
回顾:机器学习项目流程
1. 加载数据
2. 数据预处理
3. 特征工程(预处理...)
4. 模型训练
5. 模型预测
6. 模型评估
"""
# 导包
from pathlib import Path
import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression # 逻辑回归模型
from sklearn.preprocessing import StandardScaler # 标准化
from sklearn.model_selection import train_test_split # 训练集和测试集分割
from sklearn.metrics import accuracy_score # 模型评估
# 1. 加载数据
data_path = Path(__file__).resolve().parent / 'data' / 'breast-cancer-wisconsin.csv'
data = pd.read_csv(data_path)
data.info() # 查看数据信息
# 2. 数据预处理
# 2.1 把 ? 替换成 np.nan
# 参1:要被替换的值 参2:用来替换的值 参3:是否替换源数据,默认为False
data.replace('?', np.nan, inplace=True)
# 2.2 缺失值处理 -> 删除
# 参1:axis=0,表示删除包含缺失值的行 参2:inplace=True,表示替换源数据
data.dropna(axis=0, inplace=True)
# 2.3 打印处理后的信息
data.info()
# 3. 特征工程(提取,预处理...)
# 3.1 提取特征之提取特征和标签
# 按照行号,列索引获取数据
# : 表示所有行
# 1:-1 表示从第1列到最后一列,包左不包右
x = data.iloc[:, 1:-1]
# y = data.iloc[:, -1] # 获取最后一列
# y = data.iloc['Class'] # 获取最后一列,效果同上
y = data.Class # 获取最后一列,效果同上
# 3.2 查看下特征 和 标签
print(x.head())
print(y.head())
print(x.shape, y.shape)
# 3.3 切割训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=23)
# 3.4 特征工程:标准化
# 3.4.1 创建标准化对象
transfer = StandardScaler()
# 3.4.2 对训练集进行标准化,训练 + 标准化
x_train = transfer.fit_transform(x_train)
# 3.4.3 对测试集进行标准化,标准化
x_test = transfer.transform(x_test)
# 4. 模型训练
# 4.1 创建模型对象 -> 逻辑回归模型
estimator = LogisticRegression()
# 4.2 训练模型
estimator.fit(x_train, y_train)
# 5. 模型预测
y_pre = estimator.predict(x_test)
print(f'预测值:{y_pre}')
# 6. 模型评估
# 正确率(准确率),公式为:预测对的 / 样本总数
print(f'预测前评估,正确率:{estimator.score(x_test, y_test)}') # 训练集的特征,标签
print(f'预测后评估,正确率:{accuracy_score(y_test, y_pre)}') # 测试集的标签,预测值
# 思考:逻辑回归模型能用准确率来评测吗?
# 答:可以,但是结果不精确,因为逻辑回归模型主要用于二分类,即:A类还是B类,不能说 97%的A类,3%的B类
# 所以要通过混淆矩阵来评估,即:精确率,召回率,F1值(F1-score),ROC曲线,AUC值
57.2.4 练习
下列关于逻辑回归 API 的使用正确的是?(多选)
- A)需要在 sklearn 的线性模型
linear_model中导出使用 - B)可以通过
solver参数指定损失的优化方法 - C)可以通过
penalty参数指定使用哪种正则化方式 - D)它默认将样本中类别数较多的一类当做正例
答案:ABC。
- A:
from sklearn.linear_model import LogisticRegression - B:
solver是优化器(liblinear / sag / saga / lbfgs) - C:
penalty='l1'或'l2' - D 错:数量少的当正例,不是数量多的。sklearn 实际也不按多少来,而是
classes_排序后较大的那个标签当predict_proba的第二列。
58. 混淆矩阵及精确率,召回率,F1值介绍
癌症案例里准确率「能算、但不精确」:恶性很少时,全猜良性准确率也很高。分类要拆开看四种对错,这就是混淆矩阵。精确率、召回率、F1 都从这四个格子来。
58.1 混淆矩阵
四个英文拆开记:
| 词 | 意思 |
|---|---|
| True | 真(预测对了) |
| False | 假 / 伪(预测错了) |
| Positive | 正例(模型说是正类) |
| Negative | 反例(模型说是负类) |
| 预测正例 | 预测假例(反例) | |
|---|---|---|
| 真实正例 | 真正例 TP(True Positive) | 伪反例 FN(False Negative) |
| 真实假例(反例) | 伪正例 FP(False Positive) | 真反例 TN(True Negative) |
58.1.1 四个格子
- TP:真实是正例,也分成了正例(找对了)
- FN:真实是正例,却分成了假例(漏检,漏掉的病人)
- FP:真实是假例,却分成了正例(误报,没病说成有病)
- TN:真实是假例,也分成了假例(正确地排除)
癌症里若恶性当正例:TP 是恶性且查出恶性,FN 是恶性却当成良性,FP 是良性却当成恶性,TN 是良性且判断良性。
一行是「真实为正」的全部(TP+FN),一列是「预测为正」的全部(TP+FP)。后面精确率走列,召回率走行。
58.1.2 举个栗子
10 个样本:6 个恶性、4 个良性,恶性当正例。恒等式:。真实正例一行必须加起来是 6,真实反例一行必须是 4。
模型 A:恶性对了 3 个,良性对了 4 个。
6 个恶性里只找对 3 个 → ,剩下 3 个漏掉 → 。4 个良性全对 → ,没有把良性说成恶性 → 。
| 预测正例 | 预测假例 | |
|---|---|---|
| 真实正例(6 恶) | TP | FN |
| 真实假例(4 良) | FP | TN |
查出来的全是真恶性(精确率 1),但一半恶性漏了(召回率 0.5)。
模型 B:恶性对了 6 个,良性对了 1 个。(留作自测)
6 个恶性全找对 → , 。4 个良性只对了 1 个 → ,另外 3 个良性被说成恶性 → 。
| 预测正例 | 预测假例 | |
|---|---|---|
| 真实正例(6 恶) | TP | FN |
| 真实假例(4 良) | FP | TN |
恶性一个没漏(召回率 1),但查出来的 9 个「恶性」里掺了 3 个良性(精确率 )。
两个模型准确率都是 ,混淆矩阵却完全不同:A 宁漏勿错,B 宁错勿漏。所以分类不能只看准确率。
58.2 精确率 Precision
也叫查准率:在模型喊出来的正例里,有多少真是正例。癌症里恶性当正例,问的就是——报成恶性的那些人里,到底几个真是恶性。
看混淆矩阵预测正例那一列(TP 和 FP),和 FN、TN 无关:
分母是「模型认为是正例」的全部;分子是其中真的那部分。 表示报恶性的没有一个是误报; 低说明误报多(良性被说成恶性)。
沿用 58.1.2 那 10 条(6 恶 4 良):
| 模型 | TP | FP | 精确率 | 读法 |
|---|---|---|---|---|
| A(恶对 3,良对 4) | 报了 3 个恶性,全对,零误报 | |||
| B(恶对 6,良对 1) | 报了 9 个恶性,3 个是误报 |
A 的精确率更高:嘴严,不乱报。B 把恶性全抓到了,但掺进 3 个良性,精确率被拉下来。精确率高不等于召回率高,下一节召回率看的是另一条边(真实正例那一行)。
58.3 召回率 Recall
也叫查全率:所有真实正例里,被找出来的占多少。恶性当正例时问的是——病人里有没有漏掉的,能不能把恶性都报出来。
看混淆矩阵真实正例那一行(TP 和 FN),和 FP、TN 无关:
分母是「真实就是正例」的全部;分子是其中被模型抓住的。 表示恶性一个没漏; 低说明漏检多。
还是那 10 条(6 恶 4 良):
| 模型 | TP | FN | 召回率 | 读法 |
|---|---|---|---|---|
| A | 6 个恶性只抓住 3 个,漏一半 | |||
| B | 6 个恶性全抓住,零漏检 |
和精确率对照:A 精确率 100%、召回率 50%(宁漏勿错);B 精确率约 67%、召回率 100%(宁错勿漏)。癌症筛查通常更怕漏,召回率往往优先;误报代价极高时才把精确率压上去。两个指标常对着干,下一节用 F1 捏到一起。
58.4 F1-score
精确率和召回率都要看、又经常对着干时,用一个数反映综合能力:F1。它是两者的调和平均(不是算术平均 ):
调和平均的脾气:有一个很低,F1 就被拖下去;两个都高,F1 才高。一边 100%、一边 0%,F1 是 0——不会出现「平均 50% 还不错」的错觉。
还是 A、B 那组数:
| 模型 | 精确率 | 召回率 | F1 | 百分数 |
|---|---|---|---|---|
| A | (100%) | (50%) | ||
| B | () | (100%) |
B 的 F1 更高:召回拉满的同时精确率也还过得去。A 精确率满分但漏了一半,综合分被召回率拖住。业务上若更怕漏或更怕误报,仍应单看 或 ;两边都要交代时,才拿 F1 比模型。
58.5 练习
题目1:关于精确率、召回率和 F1 值的定义,下列说法正确的是:
- A. 精确率是指预测为正例中实际为正例的比例,召回率是指实际为正例中被预测为正例的比例,F1 值是精确率和召回率的调和平均数。
- B. 精确率是指实际为正例中被预测为正例的比例,召回率是指预测为正例中实际为正例的比例,F1 值是精确率和召回率的调和平均数。
- C. 精确率是指实际为正例中被预测为正例的比例,召回率是指预测为正例中实际为正例的比例,F1 值是精确率和召回率的算术平均数。
答案:A。
- 精确率 :预测为正里有多少真是正(查准,走列)
- 召回率 :实际为正里有多少被找出(查全,走行)
- F1 是调和平均 ,不是
B 把精确率和召回率对调了。C 既对调,又把调和平均说成算术平均。
题目2:如果一个二分类模型的精确率为 ,召回率为 ,那么该模型的 F1 值为:
- A.
- B.
- C.
- D.
答案:C。
A 是直接相乘 ;B 抄了召回率;D 是算术平均 。F1 一定是调和平均,不会等于 。
59. 混淆矩阵_精确率_召回率_F1值代码演示
"""
案例:
演示混淆矩阵,精确率,召回率,F1值
回顾:逻辑回归
概述:
属于有监督学习,即:有特征,有标签,且标签是离散的
适用于二分类
评估:
精确率,召回率,F1值
混淆矩阵:
概述:
用来描述 真实值 和 预测值 之间关系的
图解:
预测标签(正例) 预测标签(反例)
真实标签(正例) 真正例(TP) 伪反例(FN)
真实标签(反例) 伪正例(FP) 真反例(TN)
单词:
True:真
False:假
Positive:正例
Negative:反例
结论:
1. 模型使用 分类少的 充当正例
2. 精确率 = 真正例 在 预测正例中的占比,即:TP / (TP + FP)
3. 召回率 = 真正例 在 真实正例中的占比,即:TP / (TP + FN)
4. F1值 = 2 * (精确率 * 召回率) / (精确率 + 召回率)
"""
# 导包
import pandas as pd
from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score # 混淆矩阵, 精确率, 召回率, F1值
# 需求:已知有10个样本,6个恶性肿瘤(正例),4个良性肿瘤(反例)
# 模型A预测结果为:预测对了3个恶性肿瘤,预测对了4个良性肿瘤
# 模型B预测结果为:预测对了6个恶性肿瘤,预测对了1个良性肿瘤
# 请针对于上述的数据集,搭建混淆矩阵,分别计算模型A,模型B的 精确率,召回率,F1值
# 1. 定义变量,记录:样本数据
y_train = ['恶性', '恶性', '恶性', '恶性', '恶性', '恶性', '良性', '良性', '良性', '良性']
# 2. 定义变量,记录:模型A的预测结果
y_pre_A = ['恶性', '恶性', '恶性', '良性', '良性', '良性', '良性', '良性', '良性', '良性']
# 3. 定义变量,记录:模型B的预测结果
y_pre_B = ['恶性', '恶性', '恶性', '恶性', '恶性', '恶性', '恶性', '恶性', '恶性', '良性']
# 4. 用标签标记 正例,反例
label = ['恶性', '良性']
df_label = ['恶性(正例)', '良性(反例)']
# 5. 针对于 真实值(y_train)和 模型A的预测结果(y_pre_A),搭建混淆矩阵
cm_A = confusion_matrix(y_train, y_pre_A, labels=label)
print(f'模型A的混淆矩阵:\n{cm_A}')
# 6. 为了测试结果更好看,把上述的混淆矩阵转换成 DataFrame
df_A = pd.DataFrame(cm_A, index=df_label, columns=df_label)
print(f'模型A的混淆矩阵的 DataFrame 形式:\n{df_A}')
# 7. 针对于 真实值(y_train)和 模型B的预测结果(y_pre_B),搭建混淆矩阵
cm_B = confusion_matrix(y_train, y_pre_B, labels=label)
print(f'模型B的混淆矩阵:\n{cm_B}')
# 8. 为了测试结果更好看,把上述的混淆矩阵转换成 DataFrame
df_B = pd.DataFrame(cm_B, index=df_label, columns=df_label)
print(f'模型B的混淆矩阵的 DataFrame 形式:\n{df_B}')
# 9. 计算A模型的 精确率,召回率,F1值
# 参1:真实值 参2:预测值 参3:正例的标签
print(f'模型A的精确率:{precision_score(y_train, y_pre_A, pos_label='恶性')}')
# 参1:真实值 参2:预测值 参3:正例的标签
print(f'模型A的召回率:{recall_score(y_train, y_pre_A, pos_label='恶性')}')
# 参1:真实值 参2:预测值 参3:正例的标签
print(f'模型A的F1值:{f1_score(y_train, y_pre_A, pos_label='恶性')}')
# 10. 计算B模型的 精确率,召回率,F1值
print(f'模型B的精确率:{precision_score(y_train, y_pre_B, pos_label='恶性')}')
print(f'模型B的召回率:{recall_score(y_train, y_pre_B, pos_label='恶性')}')
print(f'模型B的F1值:{f1_score(y_train, y_pre_B, pos_label='恶性')}')
60. ROC曲线和AUC指标介绍(了解)
精确率、召回率、F1 都绑在某一个阈值上( 或 )。阈值一改,四个格子全变。ROC / AUC 把阈值从高扫到低,看模型整体把正负分得开不开。本章了解即可。
60.1 真正率 TPR 与假正率 FPR
- TPR(True Positive Rate,真正率 / 灵敏度):正样本里被报成正的比例。公式和召回率是同一个,走真实正例那一行。
- FPR(False Positive Rate,假正率):负样本里被错报成正的比例。走真实反例那一行: 是全部负类。
两个一起看:TPR 高、FPR 低,说明正的抓得全、负的又没乱报,分得开。
60.2 ROC 曲线
ROC(Receiver Operating Characteristic curve):评估分类模型的可视化工具。
- 横轴:FPR(特异度)
- 纵轴:TPR(灵敏度)
- 曲线上每一点 = 某一个阈值下的
逻辑回归输出概率后,阈值从 降到 :门槛很高时几乎谁也不报正 → 靠近左下;门槛很低时几乎人人报正 → 靠近右上。把这些点连起来就是 ROC。虚线对角线是随机瞎猜(TPR = FPR)。
60.3 四个角上的点
坐标一律 。
| 点 | 含义 | 效果 |
|---|---|---|
| 负类全对(没人被报成正),正类全错(一个正的都没抓到) | 阈值极高,全判负 | |
| 负类全错,正类也全错 | 最差:该报的不报,不该报的全报 | |
| 负类全错(全被报成正),正类全对 | 阈值极低,全判正 | |
| 负类全对,正类也全对 | 最好:完美分类 |
曲线上每个点仍是「某个阈值下的表现」。从图像上看:曲线越靠近左上角 ,模型越好(TPR 高、FPR 低)。往右下是 Worse。
正常扫阈值时,曲线大致从 走到 ,不会故意停在 ; 是「比随机还差、预测和真相反着」的角落。
60.4 AUC
AUC(Area Under the ROC Curve)= ROC 曲线下的面积,取值 。面积越大,分类器越好。
| AUC | 含义 |
|---|---|
| 完美分类器,正负全对。几乎不存在 | |
| 等于随机猜测(对角线) | |
| 正负分不清,甚至比瞎猜还差(把标签反一下会好过 0.5) | |
| 越接近 | 越能把正负样本分开 |
一句话:精确率 / 召回率问「这个阈值好不好」;AUC 问「阈值怎么切,模型本身分得开不开」。
61. ROC曲线_案例(了解)
广告位展示 6 次,点了 2 次。正样本 (点了),负样本 (没点)。按不同阈值算 ,再连成 ROC。
约定:预测概率 阈值 → 判点击(正类 1),否则判 0。分母:正类 2 个,负类 4 个。
61.1 数据:先按概率从高到低排
| 样本 | 是否点击 | 预测概率 |
|---|---|---|
| 1 | 1 | |
| 3 | 1 | |
| 2 | 0 | |
| 4 | 0 | |
| 5 | 0 | |
| 6 | 0 |
两个正样本的分都高于全部负样本,排完序正类全在最上面——后面会看到曲线很快贴到左上,AUC 接近 1。
61.2 逐个阈值手算
| 阈值 | 谁被判正( 阈值) | TPR | FPR | 点 |
|---|---|---|---|---|
| 没有() | ||||
| 仅 1 号 | ||||
| 1、3 号 | ||||
| 1、3、2 号 | ||||
| 再加 4 号 | ||||
| 再加 5 号 | ||||
| 6 个全判正 |
,再加上阈值 的 。连起来:先沿纵轴爬到 ,再水平走到 。
61.3 AUC 的计算 API
from sklearn.metrics import roc_auc_score
roc_auc_score(y_true, y_score)
算的就是 ROC 曲线下面积。
| 参数 | 含义 |
|---|---|
y_true | 真实类别,必须是 (反例)、(正例) |
y_score | 预测得分:正类概率、置信度,或 decision_function 的返回值 |
本例 y_true = [1,0,1,0,0,0],y_score = [0.9,0.7,0.8,0.6,0.5,0.4],两个正类分全高于负类,roc_auc_score 会得到 。
61.4 分类评估报告 API
from sklearn.metrics import classification_report
print(classification_report(y_true, y_pred, labels=None, target_names=None))
按类输出精确率、召回率、F1(还带 support)。这是某一个阈值切开之后的报表,和 AUC 不是同一个东西。
| 参数 | 含义 |
|---|---|
y_true | 真实标签 |
y_pred | 模型预测的类别(已经切过阈值的 0/1,不是概率) |
labels | 要报告的类别取值,顺序会反映到表上 |
target_names | 类别显示名,比如 ['良性','恶性'] |
61.5 练习
题目1:下列关于逻辑回归模型的评估说法正确的是?(多选)
- A)我们在评估逻辑回归模型时只需要选择一种评估方法即可
- B)混淆矩阵能够帮助我们快速计算出其它分类模型指标
- C)召回率和精确率表达的是同样的概念
- D)ROC 曲线下与坐标轴形成的闭合区域的面积即为 AUC 指标的值
答案:BD。
- A 错:准确率、精确率、召回率、F1、AUC 看的不是同一件事,只盯一个会偏(癌症案例里准确率高也可能漏诊)。
- B 对:四个格子齐了,精确率、召回率、F1、TPR、FPR 都能直接算。
- C 错:精确率走预测正例那一列(查准),召回率走真实正例那一行(查全)。
- D 对:AUC 就是 ROC 曲线下、和坐标轴围成的面积。
题目2:以下哪个描述最准确地解释了 AUC 指标的含义?
- A. AUC 是 ROC 曲线下方的面积,用于比较分类器的性能。
- B. AUC 是 ROC 曲线上某一点的斜率,表示分类器的灵敏度。
- C. AUC 是 ROC 曲线上的最大误分类率,用于评估分类器的错误率。
- D. AUC 是 ROC 曲线上的阈值,用于选择最佳分类器。
答案:A。 B 把 AUC 说成斜率(灵敏度是纵轴 TPR,不是 AUC);C 说成误分类率;D 把 AUC 说成阈值。阈值是扫出来画 ROC 的,AUC 是整条曲线下的面积。
题目3:下面哪个选项最能说明 ROC 曲线的作用?
- A. ROC 曲线用于描述模型的参数。
- B. ROC 曲线用于可视化模型的损失函数。
- C. ROC 曲线用于评估二元分类模型的性能。
- D. ROC 曲线用于选择最佳的回归模型。
答案:C。 它是二分类的可视化评估(TPR–FPR,不同阈值)。不是参数、不是损失曲线,也不用来挑回归模型。
62. 逻辑回归_电信用户流失预测_数据预处理
已知用户的个人、通话、上网等信息,要做两件事:找出可能造成流失的因素,再训练模型判断会不会流失,好做预警。这是二分类(流失 Yes / 留下 No),用逻辑回归。
数据在 churn.csv:7043 行、16 列,没有空值。
62.1 字段
| 列 | 含义 |
|---|---|
| Churn | 标签:是否流失(Yes / No) |
| gender | 性别 Male / Female |
| Partner_att | 配偶是否也是该运营商用户 |
| Dependents_att | 家人是否也是 |
| landline | 是否用固话 |
| internet_att / internet_other | 是否用该运营商 / 别家的宽带 |
| StreamingTV / StreamingMovies | 是否用在线电视、电影 |
| Contract_Month / Contract_1YR | 月付合约 / 一年合约 |
| PaymentBank / PaymentCreditcard / PaymentElectronic | 付款方式(银行、信用卡、电子) |
| MonthlyCharges | 每月话费 |
| TotalCharges | 累计话费 |
除 Churn、gender 外,其余已经是 或连续数。info() 里这两列是 object,进模型前要变成数。
标签分布:No 5174,Yes 1869,留下的远多于流失,后面训练要处理不平衡(正例一般取流失 Yes)。
62.2 整案四步(本节省第一步)
- 数据基本处理(本节):看行列、类别 one-hot、看标签分布
- 特征筛选:按流失/留下分组看均值,留下对标签影响大的列,拆成 、
- 模型训练:样本均衡 / 不均衡各训一版,再网格搜索 + 交叉验证
- 模型评估:精确率、ROC-AUC(流失更怕漏,召回和 AUC 都要看)
62.3 数据基本处理在干什么
- 确认 7043×16、无缺失。
- One-hot / 映射类别列:
gender→gender_Female、gender_Male(或只留一列,避免共线)Churn:Yes→1、No→0(当 ,不必 one-hot 成两列)
- 看
value_counts():确认 Yes 是少数类。准确率会虚高(全猜 No 也有 ),所以不能只看准确率。
62.4 代码实现
"""
案例:
通过逻辑回归算法,针对于电信用户数据建模,进行流失预测分析
"""
# 导包
import numpy as np
import pandas as pd
from pathlib import Path
# 1. 定义函数,演示:数据的预处理
def dm01_data_preprocess():
# pass
# 1. 读取csv文件,获取到df对象
data_path = Path(__file__).resolve().parent / 'data' / 'churn.csv'
churn_df = pd.read_csv(data_path)
# 2. 查看(处理前)数据集
# churn_df.info()
# print(churn_df.head())
# 3. 因为 Churn 和 gender 列是字符串,所以需要进行one-hot编码(热编码处理)
# churn_df = churn_df.get_dummies(['Churn', 'gender'])
churn_df = pd.get_dummies(churn_df, columns=['Churn', 'gender'])
# 4. 查看(处理后)的数据集
# churn_df.info()
# print(churn_df.head())
# 5. 删除one-hot编码后,冗余的列
# 参1:要删除的列,参2:axis=1,表示删除列,参3:inplace=True,表示直接修改原数据
churn_df.drop(['Churn_No', 'gender_Male'], axis=1, inplace=True)
# churn_df.info()
# print(churn_df.head())
# 6. 修改列名,将Churn_Yes -> flag,充当标签列
churn_df.rename(columns={'Churn_Yes': 'flag'}, inplace=True)
churn_df.info()
print(churn_df.head()) # False -> 不流失,True -> 流失
# 7. 查案数据值的分布
print(churn_df['flag'].value_counts()) # False: 5174, True: 1869
# 2. 定义函数,演示:数据的可视化
# 3. 定义函数,演示:逻辑回归算法的模型训练,预测,评估
# 4. 测试
if __name__ == '__main__':
dm01_data_preprocess()