逻辑回归算法

总说

过程参考:黑马 用于自学

https://www.bilibili.com/video/BV1Fzszz4Ek7/?spm_id_from=333.788.videopod.episodes&vd_source=24c1e92bdfe1c6a0f1b228cda0583ac9&p=55

目录

总说

一、逻辑回归简介

[1.1 应用场景](#1.1 应用场景)

[1.2 数学知识补充](#1.2 数学知识补充)

二、逻辑回归原理

[2.1 损失函数](#2.1 损失函数)

[2.2 损失函数的推导](#2.2 损失函数的推导)

[2.2.1 单个样本的概率表达式](#2.2.1 单个样本的概率表达式)

[2.2.2 似然函数](#2.2.2 似然函数)

[2.3 损失函数的直观理解](#2.3 损失函数的直观理解)

三、逻辑回归API和案例

[3.1 逻辑回归API](#3.1 逻辑回归API)

[3.2 案例:癌症分类预测](#3.2 案例:癌症分类预测)

[3.2.1 数据描述](#3.2.1 数据描述)

[3.2.2 代码实现](#3.2.2 代码实现)

四、分类问题的评估

[4.1 混淆矩阵](#4.1 混淆矩阵)

[4.2 精确率、召回率、F1-score](#4.2 精确率、召回率、F1-score)

[4.3 分类评估报告](#4.3 分类评估报告)

[4.4 ROC曲线(了解)](#4.4 ROC曲线(了解))

[4.4.1 ROC曲线的绘制](#4.4.1 ROC曲线的绘制)

[4.5 AUC指标(了解)](#4.5 AUC指标(了解))

[4.5.1 AUC 的数值含义](#4.5.1 AUC 的数值含义)

五、one-hot编码处理

六、电信客户流失预测案例

[6.1 数据描述](#6.1 数据描述)

[6.2 代码实现](#6.2 代码实现)


一、逻辑回归简介

逻辑回归(Logistic Regression)是一种二分类算法,属于有监督学习,有特征、有标签,标签离散。

它的输出不是直接的类别标签(0 或 1),而是样本属于某个类别的概率

1.1 应用场景

预测疾病(阴性/阳性)、银行信任贷款(放贷/不放贷)、感情分析(正面/负面)、预测广告点击率(点击/不点击)

1.2 数学知识补充

sigmoid函数,也可以叫激活函数,数学公式如下:


是单增函数,拐点在x = 0,y = 0.5位置

作用:把值域的(-∞,+∞)映射到(0, 1)区间

条件概率:在事件A发生的条件下,事件B发生的概率为 P(B|A) = A的概率 * B的概率

极大似然估计:在已知结果 的情况下,反推 估算最有可能导致这个结果发生的参数

二、逻辑回归原理

把线性回归处理后的值,通过Sigmoid激活函数映射到0, 1区间,结合阈值位置划分正负样本

对输入特征 x₁, x₂, ..., xₙ 做加权求和: y = w₁x₁ + w₂x₂ + ... + wₙxₙ + b = wᵀx + b

y 的范围是 (-∞, +∞),但我们希望输出一个概率,范围必须在 [0, 1] 之间。

2.1 损失函数

引入 Sigmoid 函数 将 y 压缩到 [0, 1] 区间:

Sigmoid 函数性质:

  • y → +∞ 时,p → 1

  • y → -∞ 时,p → 0

  • y = 0 时,p = 0.5

设定一个阈值(通常为 0.5):

  • 如果 p ≥ 0.5,预测为类别 1

  • 如果 p < 0.5,预测为类别 0

2.2 损失函数的推导

2.2.1 单个样本的概率表达式

对于第 i 个样本,真实标签为 yᵢ ∈ {0, 1},模型预测的正类概率为 pᵢ = σ(yᵢ)

模型认为该样本属于真实类别的概率可以统一写成:

  • yᵢ = 1,概率为 pᵢ

  • yᵢ = 0,概率为 1 - pᵢ

2.2.2 似然函数

假设所有样本独立同分布,整个数据集的联合概率(似然函数)为:

将连乘转化成连加:

为什么可以取对数?

|-----------|--------------------------------------------------------------------------------------------------------------|
| 单调性不变 | 对数函数 log(x) 是严格单调递增的。这意味着:如果 A > B,那么 log(A) > log(B)。所以最大化似然函数最大化对数似然函数 是等价的,最优解 w 完全一样。 |

我们想要最大化 对数似然,等价于最小化它的相反数:

这就是交叉熵 损失函数(Cross-Entropy Loss) ,也称对数损失(Log Loss)

然后求梯度寻找极值点。

2.3 损失函数的直观理解

正类负类不代表对错,而是两种分类。

根据预测概率 p 和阈值得到预测结果。

真实标签 y 预测概率 p 预测结果 损失值 直观含义
1 0.99 1(正类) 0.01 ✅ 预测正确且非常自信,几乎无损失
1 0.90 1(正类) 0.11 ✅ 预测正确且较自信,损失很小
1 0.70 1(正类) 0.36 🤔 预测正确但信心不足,损失中等
1 0.50 1(正类) 0.69 😰 恰好卡在阈值上,相当于随机猜测,损失较大
1 0.30 0(负类) 1.20 😱 预测错误,且倾向错误方向,损失很大
1 0.01 0(负类) 4.61 💀 预测完全错误且极其自信,损失巨大
0 0.01 0(负类) 0.01 ✅ 预测正确且非常自信,几乎无损失
0 0.10 0(负类) 0.11 ✅ 预测正确且较自信,损失很小
0 0.30 0(负类) 0.36 🤔 预测正确但信心不足,损失中等
0 0.50 1(正类) 0.69 😰 恰好卡在阈值上,相当于随机猜测,损失较大
0 0.70 1(正类) 1.20 😱 预测错误,且倾向错误方向,损失很大
0 0.99 1(正类) 4.61 💀 预测完全错误且极其自信,损失巨大

在模型训练时,损失值的绝对大小不重要,变化的趋势才重要

如果损失值在不断下降,就说明模型正在"学习",参数在朝着正确的方向更新。

当损失值经过很多轮训练后,下降变得非常平缓,几乎不再变化时,就说明模型已经"收敛",可以停止训练了。

三、逻辑回归API和案例

3.1 逻辑回归API

python 复制代码
sklearn.linear_model.LogisticRegression(solver = 'liblinear', penalty = 'l2', C = 1.0)

solver:liblinear对小数据集训练速度更快,sag和saga对大数据集更快

liblinear和saga支持L1正则化,sag和saga支持L2正则化

penalty:正则化种类

C:正则化力度

默认把类别数量少 的当作正类

3.2 案例:癌症分类预测

3.2.1 数据描述

csv文件来自黑马

3.2.2 代码实现

代码如下:

python 复制代码
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 # 模型评估

#VS Code 终端默认编码不是 UTF-8 不是VS Code 可以不用写
import sys
sys.stdout.reconfigure(encoding='utf-8') # 强制让控制台使用 UTF-8 编码输出文字

# 1.读取数据
data = pd.read_csv('./LogisticRegression/data/breast-cancer-wisconsin.csv')
# data.info() # 打印数据集信息


# 2.数据预处理
# 2.1 由于存在缺失值,需要替换缺失值? 为np.nan      np.nan是代表缺失值
data.replace('?', np.nan, inplace=True) # 参数1:要替换的值 参数2:替换后的值 参数3:是否在原数据上修改
# 2.2 删除缺失值
data.dropna(axis=0, inplace=True) #axis = 0表示行  inplace=True 表示在原数据上修改

#data.info() # 打印数据集信息

# 3.特征工程
# 3.1 特征提取
x = data.iloc[:, 1:-1] #标号从0开始 提取特征值
y = data.iloc[:, -1] # 提取标签值 只有最后一列

print(x[:5])
print(y[:5])

# 3.2 切割训练集和测试集
# train_test_split() 参1:特征数据 参2:标签数据 参3:测试集所占比例 参4:随机种子
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=23)

# 3.3 特征标准化
# 3.3.1 创建标准化对象
transfer = StandardScaler()
# 先用训练集 fit(计算均值和标准差)
transfer.fit(x_train)
# 3.3.2 对训练集和测试集进行标准化
x_train = transfer.transform(x_train)
x_test = transfer.transform(x_test)

# 4.模型训练
# 4.1 创建逻辑回归模型,在 LogisticRegression() 的内部,默认就是交叉熵损失
estimator = LogisticRegression() #默认使用L2正则化 C=1.0 solver='lbfgs' 
# 4.2 训练模型
estimator.fit(x_train, y_train)

# 5.模型预测
# 阈值也不在代码里显式出现,它被硬编码在 predict() 方法内部了,默认是 0.5
# 想要自定义阈值,必须自己用 predict_proba() 手动判断
y_pre = estimator.predict(x_test)
print(f'预测值为{y_pre}')

# 6.模型评估
# 需要通过混淆矩阵来评测 即:精确率、召回率、F1值、ROC曲线、AUC值

只通过准确率对模型进行评估,不能满足各种场景需要,需要通过混淆矩阵来评测

四、分类问题的评估

4.1 混淆矩阵

混淆矩阵:用一个表格的形式,把模型"在哪些样本上猜对了、在哪些样本上猜错了"以及"具体怎么错的"都清清楚楚地列出来。

T:true F:false P:positive N:negative

真实 \ 预测 预测为正类(1) 预测为负类(0)
真实为正类(1) TP(真阳性) ✅ 正确 FN(假阴性) ❌ 漏报
真实为负类(0) FP(假阳性) ❌ 误报 TN(真阴性) ✅正确

四个指标

缩写 全称 含义 通俗说法 是预测正确吗?
TP True Positive 真实是正类,预测也是正类 命中了 ✅ 正确
TN True Negative 真实是负类,预测也是负类 正确放行 ✅ 正确
FP False Positive 真实是负类,预测却是正类 误报 / 把好人当坏人 ❌ 错误(第一类错误)
FN False Negative 真实是正类,预测却是负类 漏报 / 把坏人当好人 ❌ 错误(第二类错误)

4.2 精确率、召回率、F1-score

准确率(Accuracy)会骗人, 当数据不平衡时,准确率会给出虚假的乐观信号。所以不能只用准确率。

指标 公式 含义
准确率(Accuracy) (TP+TN) / (TP+TN+FP+FN) 所有样本中,猜对的比例
精确率(Precision) 预测为正类的所有样本中,预测准确率
召回率(Recall) 在真实为正类中,被成功找出来的比例
F1-score 精确率和召回率的调和平均
特异度(Specificity) TN / (TN+FP) 真实负类中,被正确排除的比例

**精确率 和 召回率 的关系:**通常提高一个,另一个就会下降。需要根据业务场景在两者之间做取舍。

样例代码实现:

python 复制代码
import pandas as pd
#                            混淆矩阵            精确率             召回率       F1值
from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score

#VS Code 终端默认编码不是 UTF-8 不是VS Code 可以不用写
import sys
sys.stdout.reconfigure(encoding='utf-8') # 强制让控制台使用 UTF-8 编码输出文字

# 1. 定义数据集, 表示: 真实样本(共计10个, 6个恶性, 4个良性) => 设置: 恶性(正类), 良性(反类)
y_train = ['恶性', '恶性', '恶性', '恶性', '恶性', '恶性',   '良性', '良性', '良性', '良性']

# 2. 定义标签名
label = ['恶性', '良性']   # 正样本(正类), 负样本(反类)
df_label = ['恶性(正类)', '良性(反类)']

# 3. 定义 预测结果, 预测对了3个恶性肿瘤, 4个良性肿瘤.
y_pre = ['恶性', '恶性', '恶性', '良性', '良性', '良性',   '良性', '良性', '良性', '良性']

# 4. 把 预测结果 转换成 混淆矩阵
# 参1: 真实样本, 参2: 预测样本, 参3: 样本标签(正类, 反类)
cm = confusion_matrix(y_train, y_pre, labels=label)
print(f'混淆矩阵A: \n {cm}')

# 5. 把混淆矩阵 转换成 DataFrame.
df = pd.DataFrame(cm, index=df_label, columns=df_label)
print(f'预测结果A对应的DataFrame对象: \n {df}')
print('-' * 22)

# 9.打印预测结果 y_pre 的精确率, 召回率, F1值.
# 参1: 真实样本, 参2: 预测样本, 参3: positive label: 正类的标签
print(f'预测结果A的精确率: {precision_score(y_train, y_pre, pos_label="恶性")}')# 精确率
print(f'预测结果A的召回率: {recall_score(y_train, y_pre, pos_label="恶性")}')# 召回率
print(f'预测结果A的F1值: {f1_score(y_train, y_pre, pos_label="恶性")}')# F1值

4.3 分类评估报告

分类评估报告(Classification Report):用一张表格同时展示每个类别的精确率(Precision)召回率(Recall)F1-score支持度(Support)

支持度(Support):该类别的真实样本数量

如:

报告底部的三项:

下面表格的概率p是模型预测出来的,在用阈值判断之前算出来的

指标 计算方式 适用场景
accuracy(准确率) (TP + TN) / (TP + TN + FP + FN) 所有样本中,预测正确的比例 类别均衡 的数据集。 ⚠️ 慎用场景:类别严重不均衡时,准确率会虚高(如 99% 负类,全猜负类也能有 99% 准确率),此时应参考其他指标。
macro avg(宏平均) 每个类别的指标独立计算后,直接取算术平均 。 公式:(P₁ + P₂ + ... + Pₙ) / n 每个类别权重相同(均为 1/n 每个类别都同等重要 的场景。 例如:罕见病检测(少数类样本少,但漏诊代价极高)、多语种分类(每种语言都重要)。 能真实反映模型在少数类上的表现,不会被多数类"淹没"。
weighted avg(加权平均) 每个类别的指标按样本数量(Support) 加权后取平均。 公式:(P₁×N₁ + P₂×N₂ + ... + Pₙ×Nₙ) / 总样本数 样本越多的类别,权重越大 关心总体表现 ,或各类别样本数量与业务重要性成正比的场景。 例如:垃圾邮件过滤(正常邮件占绝大多数,模型在正常邮件上的表现直接影响用户体验)。 ⚠️ 注意 :会掩盖少数类的问题,当宏平均和加权平均差距较大时,说明数据不均衡,需要警惕。

4.4 ROC曲线(了解)

ROC 曲线(Receiver Operating Characteristic Curve,受试者工作特征曲线): 是一条用来衡量二分类模型区分能力的曲线。

指标 公式 含义
TPR(True Positive Rate) 真正例率 也叫召回率(Recall)。正类样本中,被正确预测的比例
FPR(False Positive Rate) 假正例率 负类样本中,被错误预测为正类的比例

TPR 越高越好(希望把正类都找出来),FPR 越低越好(希望不要把负类误判为正类)

ROC曲线以模型的真正例率TPR为纵轴 y,假正利率FPR为横轴 x,将模型在不同阈值下的表现画出来

4.4.1 ROC曲线的绘制

案例:某网站广告的点击概率,在不同阈值的情况下,绘制ROC曲线

4.5 AUC指标(了解)

AUC(Area Under the Curve) :就是 ROC 曲线下方的面积

AUC 是一个数值,范围在 0 到 1 之间。AUC 越大 ,模型的区分能力越强

ROC曲线的优劣 可以通过曲线下方的面积AUC来衡量。

4.5.1 AUC 的数值含义

AUC 值 模型区分能力 说明
0.9 ~ 1.0 极好 模型区分能力非常强
0.8 ~ 0.9 良好 模型有较好的区分能力
0.7 ~ 0.8 一般 模型有一定的区分能力
0.6 ~ 0.7 较差 模型区分能力较弱
0.5 无效 等于随机猜测,模型没有区分能力
< 0.5 有问题 模型预测比随机猜测还差(可能标签反了)

五、one-hot编码处理

One-Hot 编码: 是一种将类别型数据 (如颜色、城市、性别)转换为数值型数据的方法,便于机器学习模型处理。

  • 核心思想 :每个类别创建一个独立的特征列,用 01 表示是否存在

  • 名称由来 :每一行数据中,只有一个位置是 1(热),其余都是 0(冷)

原始数据:

颜色
红色
绿色
蓝色
红色

One-Hot 编码后

颜色_红色 颜色_绿色 颜色_蓝色
1 0 0
0 1 0
0 0 1
1 0 0

为什么使用One-Hot:

问题 说明
避免大小关系误导 如果用 红=1, 绿=2, 蓝=3,模型会误认为 蓝 > 绿 > 红,产生错误推理
类别平等 One-Hot 让所有类别在数学上地位平等,互不干扰
模型兼容 大多数机器学习算法(如逻辑回归、神经网络)只接受数值输入

六、电信客户流失预测案例

6.1 数据描述

6.2 代码实现

需要对Churn和gender列进行one-hot编码处理

完整代码如下:

python 复制代码
import numpy as np
import pandas as pd
import seaborn as sns #数据可视化
import matplotlib.pyplot as plt #数据可视化
from sklearn.model_selection import train_test_split #数据集划分
from sklearn.linear_model import LogisticRegression #逻辑回归
#                               准确率          精确率          召回率          F1值          分类评估报告
from sklearn.metrics import accuracy_score,  precision_score, recall_score, f1_score, classification_report 

#VS Code 终端默认编码不是 UTF-8 不是VS Code 可以不用写
import sys
sys.stdout.reconfigure(encoding='utf-8') # 强制让控制台使用 UTF-8 编码输出文字

#1. 定义函数,实现数据预处理
def data_preprocess():
    #1.1. 读取csv文件,获取到df对象
    data = pd.read_csv('./LogisticRegression/data/churn.csv')
    # data.info() #查看数据集信息

    #1.2. 由于csv文件中的Churn列和gender列是字符串类型,需要进行one-hot编码(热编码处理)
    data = pd.get_dummies(data,columns=['Churn','gender'])
    # data.info() #查看数据集信息

    #1.3. 删除one-hot编码处理后冗余的列
    data.drop(['Churn_No', 'gender_Male'], axis=1, inplace=True) # axis=1表示删除列,inplace=True表示在原数据上进行修改

    #1.4. 修改列名,将Churn_Yes改为flag 做为标签    False表示不流失,True表示流失
    data.rename(columns={'Churn_Yes':'flag'}, inplace=True)


#2. 定义函数,实现数据的可视化
def data_visualization():
    #1.1. 读取csv文件,获取到df对象
    data = pd.read_csv('./LogisticRegression/data/churn.csv')
    # data.info() #查看数据集信息

    #1.2. 由于csv文件中的Churn列和gender列是字符串类型,需要进行one-hot编码(热编码处理)
    data = pd.get_dummies(data,columns=['Churn','gender'])
    # data.info() #查看数据集信息

    #1.3. 删除one-hot编码处理后冗余的列
    data.drop(['Churn_No', 'gender_Male'], axis=1, inplace=True) # axis=1表示删除列,inplace=True表示在原数据上进行修改

    #1.4. 修改列名,将Churn_Yes改为flag 做为标签    False表示不流失,True表示流失
    data.rename(columns={'Churn_Yes':'flag'}, inplace=True)

    # 数据可视化 绘制 计数柱状图
    # 参1:数据集 参2:x轴的列名(这里是 字段:月度会员) 参3:hue:根据什么字段进行分类 这里是是否流失
    sns.countplot(data = data, x = 'Contract_Month' , hue = 'flag')
    plt.show()

#3. 定义函数,实现逻辑回归模型训练
def logistic_regression():

    # 1. 读取csv文件,获取到df对象
    data = pd.read_csv('./LogisticRegression/data/churn.csv')
    # data.info() #查看数据集信息

    # 2.1 由于csv文件中的Churn列和gender列是字符串类型,需要进行one-hot编码(热编码处理)
    data = pd.get_dummies(data,columns=['Churn','gender'])
    # data.info() #查看数据集信息

    # 2.2 删除one-hot编码处理后冗余的列
    data.drop(['Churn_No', 'gender_Male'], axis=1, inplace=True) # axis=1表示删除列,inplace=True表示在原数据上进行修改

    # 2.3 修改列名,将Churn_Yes改为flag 做为标签    False表示不流失,True表示流失
    data.rename(columns={'Churn_Yes':'flag'}, inplace=True)

    # 2.4 提取特征列 和 标签列
    # x 的特征列:月度会员,是否有互联网服务,是否是电子支付
    x = data[['Contract_Month', 'internet_other', 'PaymentElectronic']]
    y = data['flag'] # False表示不流失,True表示流失

    # 2.5 数据集划分
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=23)

    # 3. 特征工程(特征提取、特征预处理:归一化、标准化...) 这里不做处理

    # 4. 模型训练
    # 4.1 创建逻辑回归模型
    estimator = LogisticRegression()
    # 4.2 模型训练
    estimator.fit(x_train, y_train)
    # 5 模型预测
    y_pred = estimator.predict(x_test)
    print('预测结果:', y_pred)

    # 6. 模型评估
    print('训练集准确率准确率:', estimator.score(x_test, y_test)) 
    print('测试集准确率准确率:', accuracy_score(y_test, y_pred))  

    print(f'精确率:{precision_score(y_test, y_pred)}')
    print(f'召回率:{recall_score(y_test, y_pred)}')
    print(f'F1值:{f1_score(y_test, y_pred)}')

    # macro avg: 宏平均,不考虑样本权重, 直接求平均,适用于数据均衡的情况
    # weighted avg: 加权平均,考虑样本权重, 适用于数据不均衡的情况
    print(f'分类评估报告:\n{classification_report(y_test, y_pred)}')


#4. 测试
if __name__ == '__main__':
    # data_preprocess()
    # data_visualization()
    logistic_regression()
相关推荐
weixin_377634841 小时前
【多模型预测】 如何合理融合多个预测分值
算法·机器学习·概率论·预测·agent预测
无风听海1 小时前
Claude Agent Skills 的四种设计模式;从渐进式披露到最小权限
java·算法·设计模式
37.2℃9952 小时前
专业的Claude Design解决方案
前端·算法
め.2 小时前
定点数运算库
算法·unity
dyxal2 小时前
最长公共子序列(LCS)
python·算法
知识分享小能手3 小时前
统计学学习教程,从入门到精通,参数估计 — 知识点详解与公式推导(10)
学习·机器学习·概率论
长夜多忧思4 小时前
机器学习_朴素贝叶斯公式解读_多项式分布
机器学习·朴素贝叶斯·多项式分布
林泽毅4 小时前
PyTRIO:当强化学习不再需要本地GPU
人工智能·python·深度学习·机器学习
小陈phd4 小时前
QAnything 阅读优化策略05——检索
人工智能·python·机器学习