机器学习分类算法

逻辑回归介绍

逻辑回归(Logistic Regression)是一种用于分类任务的算法。虽然名字里有“回归”,但它本质上是一个分类模型,不是拿来预测连续值的;它最擅长处理二分类任务,比如“是/不是”“通过/不通过”“会/不会点击”这类问题。它先对特征做线性组合,再通过 Sigmoid 函数把结果压到 0~1,最后把这个值解释成“属于某个类别的概率”。

逻辑回归

扩展部分:几个常见概率背景/概念

概率基础

  • 逻辑回归最后输出的不是“具体分数”,而是“属于某一类的概率”,所以先把几个常见概率概念分清。
  1. 边际概率
  • 描述的是单个事件发生的可能性
  • 记作 $P(A)$。
  • 例如:明天下雨的概率、一个用户会点击广告的概率。
  1. 联合概率
  • 描述的是两个或多个事件同时发生的概率
  • 记作 $P(A \cap B)$。
  • 例如:一个用户既点击了广告,又完成了下单。
  1. 条件概率
  • 描述的是在事件 A 已经发生的前提下,事件 B 发生的概率
  • 记作 $P(B \mid A)$。
  • 例如:用户已经点进商品页后,最终下单的概率。

一句话理解

  • 边际概率:只看一件事会不会发生。
  • 联合概率:看几件事会不会一起发生。
  • 条件概率:先假设一件事已经发生,再看另一件事发生的可能性。
扩展部分:Sigmoid 函数不是归一化

它俩只是恰好都能把数值压缩到 0~1 区间,但作用对象、目的、使用阶段完全是两回事。


1. 归一化:是「输入特征的预处理操作」 我们常说的归一化(比如 Min-Max 归一化)、标准化,都属于数据预处理步骤——是在数据喂给模型之前,对「输入特征」做的处理。

  • 作用对象:原始特征列(比如房屋面积、用户收入、年龄)
  • 核心目的:消除不同特征的数值量级差异,让模型公平学习、训练收敛更快
  • 典型计算(Min-Max 归一化):(x - 最小值) / (最大值 - 最小值)
  • 特点:依赖当前这批数据的统计值(最值/均值),是对“一整列数据”做尺度统一

2. Sigmoid:是「模型内部的概率映射函数」
Sigmoid 是逻辑回归模型计算过程中的一环,它处理的不是输入特征,而是“特征线性组合后的结果 z = wx + b”。

  • 作用对象:线性计算的输出值(可以是负无穷到正无穷的任意实数)
  • 核心目的:把任意实数转换成 0~1 之间的数值,并赋予「概率」的含义,最终用来做二分类决策
  • 计算公式:$f(z) = 1 / (1 + e^(-z))$
  • 特点:是固定的数学函数,和数据分布无关;输入越大输出越接近1,输入越小输出越接近0,输入为0时刚好等于0.5

核心区别对照表

对比维度 归一化(Min-Max) Sigmoid 函数
使用阶段 数据预处理(模型外部) 模型计算内部
处理对象 输入特征 x 线性加权结果 z = wx + b
核心目的 统一特征量纲,辅助模型稳定训练 输出概率值,支撑分类判断
数值依赖 依赖数据的最值/均值等统计量 固定公式,和数据分布无关

通俗例子帮你分清
比如做“用户会不会点击广告”的分类模型:

  • 归一化:是把“用户年龄(18 ~ 60岁)”“用户月收入(3千 ~ 5万)”这些尺度差很大的特征,都缩到 0~1 之间,避免模型误以为“收入”天然比“年龄”更重要。
  • Sigmoid:是模型把年龄、收入等特征加权算完得到一个分数(比如 2.5 或者 -1.3)后,用 Sigmoid 把这个分数转成 0 ~ 1 的数,比如 0.92,解释成“这个用户有 92% 的概率会点击广告”。

一句话理清顺序
在逻辑回归的完整流程里,它俩是先后关系,互不冲突: 原始特征 → 做归一化/标准化 → 线性加权求和 → 过 Sigmoid → 输出分类概率

使用场景

逻辑回归是分类任务,线性回归就是回归任务

图片

逻辑回归原理

逻辑回归主要拿来做分类。更准确地说,它可以分成两条主线:预测流程训练流程

主线流程:

  • 预测流程:线性组合 -> Sigmoid -> 概率 -> 阈值分类
  • 训练流程:线性组合 -> Sigmoid -> 交叉熵损失 -> 梯度下降更新参数
展开看逻辑回归的预测流程和训练流程

1. 预测流程:模型怎么做分类

先做线性组合:$z = w^T x + b$

  • 这个 $z$ 可以理解成模型先算出来的一个“原始分数”,范围不固定,不能直接当概率用。

再过 Sigmoid 函数:$\sigma(z) = \frac{1}{1 + e^{-z}}$

  • Sigmoid 会把任意实数映射到 01 之间。公式:$\sigma(z) = \frac{1}{1 + e^{-z}}$
  • 所以逻辑回归真正输出的是:$P(y=1 \mid x) = \sigma(w^T x + b)$
  • 这个值就可以理解成:给定输入特征 $x$ 时,样本属于正类的概率。

最后按阈值分类

  • 如果概率大于某个阈值,就判成正类。
  • 如果概率小于某个阈值,就判成负类。
  • 最常见的阈值是 0.5,但实际业务里也可以按需求调整。

2. 训练流程:模型怎么学会这条分类线

  • 训练时,模型不会先急着按阈值分正负类,而是先看“预测概率和真实标签到底差多少”。
  • 这个“差多少”的衡量标准,常用的就是交叉熵损失
  • 再通过梯度下降不断调整参数 $w$ 和 $b$,让损失越来越小。
  • 参数调好之后,模型本质上就是学到了一条更合适的分类边界。

一句话理解
逻辑回归本质上是:预测时先算分数、再转概率、最后做分类;训练时用交叉熵衡量误差,再用梯度下降调整参数。

为什么转概率值?

  • 因为线性计算出来的原始分数没有固定范围,直接拿它做分类不直观,也不方便统一设阈值。
  • 转成 0~1 的概率后,就更容易解释成“属于某一类的可能性有多大”,也更方便做二分类判断。
扩展:底层原理 交叉熵损失与极大似然估计等

这部分属于更偏原理的扩展内容,知道它和交叉熵有关就够了

伯努利分布与似然函数

伯努利分布

  • 逻辑回归最常见的是二分类,而二分类的结果只有两种:01
  • 这种“只有两种结果”的随机变量,就很适合用伯努利分布来描述。
  • 你可以把它理解成一次抛硬币:
  • 结果要么是正面,要么是反面;在模型里,就是要么属于这一类,要么不属于这一类。

伯努利分布函数

  • 如果一个样本的标签 $y \in \{0, 1\}$,模型预测它属于正类的概率是 $p$,那么伯努利分布可以写成:
$$ P(y \mid x) = p^y (1-p)^{1-y} $$
  • 当 $y=1$ 时,公式会变成 $P(y \mid x)=p$。
  • 当 $y=0$ 时,公式会变成 $P(y \mid x)=1-p$。
  • 在逻辑回归里,这里的 $p$ 就是:
$$ p = P(y=1 \mid x) = \sigma(w^T x + b) $$
  • 也就是说,逻辑回归先用 Sigmoid 算出概率,再拿这个概率去描述二分类结果。

似然函数

  • 似然函数可以理解成:假设当前这组参数是对的,那训练数据出现的可能性有多大。
  • 如果模型参数选得好,真实标签就应该更容易被“解释出来”,也就是似然更大。
  • 对单个样本来说,似然就是:
$$ P(y \mid x) = p^y (1-p)^{1-y} $$
  • 对整个训练集来说,就是把所有样本的概率乘起来:
$$ L(w,b) = \prod_{i=1}^{m} p_i^{y_i}(1-p_i)^{1-y_i} $$
  • 逻辑回归训练时,本质上就是希望这整个似然函数尽量大。

交叉熵损失与极大似然估计

为什么又会变成交叉熵损失

  • 直接把很多概率连乘,数值会非常小,计算不方便。
  • 所以通常会先取对数,把“连乘”变成“连加”:
$$ \log L(w,b) = \sum_{i=1}^{m}\left[y_i \log p_i + (1-y_i)\log(1-p_i)\right] $$
  • 训练时我们一般习惯写成“损失越小越好”,所以再取一个负号,就得到常见的对数损失,也就是二分类交叉熵损失:
$$ J(w,b) = -\frac{1}{m}\sum_{i=1}^{m}\left[y_i \log p_i + (1-y_i)\log(1-p_i)\right] $$

怎么理解交叉熵损失

  • 如果真实标签是 1,模型给出的 $p$ 越接近 1,损失越小。
  • 如果真实标签是 0,模型给出的 $p$ 越接近 0,损失越小。
  • 如果模型明明很有把握,却判断错了,交叉熵会罚得很重。
  • 所以它特别适合分类任务,能逼着模型把“正确类别的概率”尽量拉高。

交叉熵和似然函数是什么关系

  • 这两个东西本质上是在说同一件事,只是站的角度不一样。
  • 似然函数站在“概率越大越好”的角度,希望训练数据在当前参数下出现的可能性尽量大。
  • 交叉熵损失站在“损失越小越好”的角度,希望模型犯错更少、而且别错得太自信。
  • 数学上,交叉熵损失其实就是负对数似然再取平均
$$ J(w,b) = -\frac{1}{m}\log L(w,b) $$
  • 所以:
  • 最大化似然 = 最大化对数似然
  • 最大化对数似然 = 最小化负对数似然
  • 最小化负对数似然 = 最小化交叉熵损失

极大似然估计

  • 极大似然估计(MLE,Maximum Likelihood Estimation)可以理解成:
  • 在一堆参数里,挑出那组最能解释训练数据的参数。
  • 也就是找到一组 $w$ 和 $b$,让训练集出现的概率最大。
  • 放到逻辑回归里,就是让真实标签在模型预测下“尽可能合理”。
  • 因为直接最大化连乘形式的似然不方便,所以实际训练时通常改成:
  • 最大化对数似然,或者等价地最小化交叉熵损失。

一句话理解极大似然

  • 极大似然估计就是:哪组参数最像是“生成”当前这批训练数据的,就选哪组参数。

一句话串起来

  • 逻辑回归先输出一个概率,这个概率符合二分类的伯努利分布;训练时通过最大化似然,最后就等价成最小化交叉熵损失。

逻辑回归API应用

LogisticRegression 基础用法

  • sklearn.linear_model.LogisticRegression():逻辑回归分类模型,最常见的是拿来做二分类
  • fit(X, y):用训练数据拟合模型,学出权重和偏置
  • predict_proba(X):输出每个类别的概率
  • predict(X):根据概率和阈值输出最终类别
  • coef_:查看模型学到的权重
  • intercept_:查看模型学到的偏置

代码示例

# 导包
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# 1.读取文件获取数据
data = pd.read_csv('data/breast-cancer-wisconsin.csv', sep=',')
print(data.shape, data.ndim)  # 形状:(699, 11) 维度:2
# 2.数据预处理
# 2.0 注意: 数据中有"?"无效字符,需要先转换为numpy中的nan,然后使用dropna()删除或者fillna()填充
new_data = data.replace('?', np.nan).dropna()
print(new_data.shape, new_data.ndim)  # 形状:(683, 11) 维度:2
# 2.1 分别获取特征和标签
# 拓展:  iloc格式 : 数据.iloc[行索引,列索引]
# 所有行,第1列到最后一列,不包含最后一列,不包含第0列索引
x = new_data.iloc[:, 1:-1]
# -1 最后一列
y = new_data.iloc[:, -1]
print(x.shape, x.ndim)  # 形状:(683, 9) 维度:2
print(y.shape, y.ndim)  # 形状:(683,) 维度:1
# 2.2 使用train_test_split()按比例切割成4部分
# 同一个种子,同一份随机数据
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2,random_state=666)  
# 3.特征处理(标准化)
ss = StandardScaler()  # 标准化模型对特征数据处理
new_x_train = ss.fit_transform(X_train)
new_x_test = ss.transform(X_test)
# 4.创建模型
lr_model = LogisticRegression()  # 逻辑回归模型真正预测结果
# 5.模型训练
lr_model.fit(new_x_train, y_train)
print('=======================================================')
# 6.模型预测和评估: 准确率
y_pred = lr_model.predict(new_x_test)  # 1.先预测
print(y_pred)
print(y_test.tolist())
print(f"准确率:{accuracy_score(y_test, y_pred)}")  # 2.再计算
print('---------------------------------------------------')
# 把上面两步合并一步,底层也是先预测再计算
print(f"准确率:{lr_model.score(new_x_test, y_test)}") 
print('=======================================================')

打印:

(699, 11) 2
(683, 11) 2
(683, 9) 2
(683,) 1
=======================================================
[2 2 2 2 4 2 2 2 2 2 4 4 4 4 2 2 2 4 4 2 2 2 2 2 4 2 4 2 2 4 2 4 4 2 2 2 4
 2 2 2 4 2 2 2 4 2 2 4 2 2 2 2 4 2 2 4 4 2 2 2 2 4 4 4 2 4 4 4 2 4 2 2 4 4
 2 2 2 2 2 2 2 4 4 4 4 2 2 2 4 2 4 2 2 4 4 2 2 2 2 2 2 4 4 2 2 2 2 4 4 4 4
 2 2 2 2 2 2 4 4 2 2 4 4 2 4 2 4 4 2 2 4 4 4 2 2 4 2]
[2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 4, 2, 4, 4, 2, 2, 2, 4, 4, 2, 2, 2, 2, 2, 4, 2, 4, 2, 2, 4, 2, 4, 4, 2, 2, 2, 4, 2, 2, 4, 4, 2, 2, 2, 4, 2, 2, 4, 2, 2, 2, 2, 4, 2, 2, 4, 4, 2, 2, 2, 2, 4, 4, 4, 2, 4, 4, 4, 2, 4, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 2, 2, 2, 4, 2, 4, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 2, 2, 2, 2, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 2, 2, 4, 4, 2, 4, 2, 4, 4, 2, 2, 4, 4, 4, 2, 2, 4, 2]
准确率:0.9854014598540146
---------------------------------------------------
准确率:0.9854014598540146
=======================================================
扩展:numpy中随机种子的应用
  • train_test_split(x, y, test_size=0.2, random_state=666) 里的 random_state=666,本质上就是在固定这次数据切分时的随机种子。
  • 这样做的好处是:同一份数据、同一段代码,多次运行后训练集和测试集的划分结果都一样
  • 如果不固定种子,每次切分出来的训练集、测试集都可能不同,最终准确率也可能跟着波动,不方便复现和对比实验结果。

可以先把“随机种子”理解成一个固定的起点:

  • 种子一样,随机结果就会一样。
  • 种子不一样,随机结果通常也会不一样。

所以在机器学习里,固定随机种子最常见的作用就是:保证实验可复现

这里再区分一下:

  • np.random.seed(666):更偏向直接控制 Numpy 自己生成随机数的结果。
  • random_state=666:更偏向给 sklearn 这类工具传一个固定种子,让它内部涉及随机的步骤保持可复现。

一句话理解:上面的代码已经用 random_state=666 把“随机切分数据”这件事固定住了,本质上和设置随机种子的目的相同。

随机种子示例

import numpy as np

# 设置随机种子为固定值
np.random.seed(true)

# 生成随机数组
arr1 = np.random.randint(0, 10, size=5)
print("第一次生成:", arr1)

print('============================================')

# 设置随机种子为固定值
np.random.seed(2)

# 生成随机数组
arr2 = np.random.randint(0, 10, size=5)
print("第二次生成:", arr2)

分类模型评估方法

  • 准确率(Accuracy):预测对了多少,最直观。
  • 精确率(Precision):预测成正类的样本里,有多少是真的正类。
  • 召回率(Recall):真实正类里,有多少被模型找出来了。
  • F1-score:精确率和召回率的折中指标。
展开查看更多

好嘞,这个我来!用一个"癌症筛查"的例子把这几个概念一次串清楚——

先说场景

假设医院有个测试,能判断一个人有没有癌症。我们拿 10000 个人去测,结果如下:

真的没癌(实际阴性) 真的有癌(实际阳性)
测试说没癌 9700(正确放行) 30(漏诊)
测试说有癌 70(误诊) 200(正确抓出)

横着看是测试的结果,竖着是真实情况。这张 2×2 的表,就是混淆矩阵——名字挺玄乎,其实就是把"猜对猜错"摊开给你看。

四个格子都有专门名字:

  • TP(True Positive):真有,测出有 → 200
  • FN(False Negative):真有,测出没有 → 30(漏诊,最危险)
  • FP(False Positive):真没有,测出有 → 70(误诊,吓你一跳)
  • TN(True Negative):真没有,测出没有 → 9700

然后四个指标

1. 准确率 Accuracy = 猜对的比例
$$(TP + TN) / 总数 = (200 + 9700) / 10000 = 99\%$$

问题在哪? 如果癌症发病率只有 0.1%,那我让模型对所有人说"没癌",准确率 99.9%——但它一个真病人都抓不出来。所以光看准确率会被骗。

2. 精确率 Precision = 我说有癌的人里,真的有的比例
$$TP / (TP + FP) = 200 / (200 + 70) = 74\%$$

大白话:模型不轻易报警,但一旦报警,74% 真的有事。关心的是"我喊狼来了,喊得准不准"。代价是宁可漏报也不乱报(你也不想没事被拉去化疗吧)。

3. 召回率 Recall = 真有病的人里,我抓出多少
$$TP / (TP + FN) = 200 / (200 + 30) = 87\%$$

大白话:100 个真病人我抓到 87 个。关心的是"真的狼,一只都不能漏"。代价是宁可多误报也不能漏(漏诊的代价远大于误诊)。

4. F1 = 精确率和召回率的"调和平均"
$$2 \times P \times R / (P + R) = 2 \times 0.74 \times 0.87 / (0.74 + 0.87) \approx 0.80$$

大白话:你又想准又怕漏,两个都想要又不能偏科太严重,F1 就是那个"不偏科分数"。如果一个高一个低,F1 会狠狠惩罚你。


一张表记住区别

指标 关心的问题 适用场景
准确率 总共猜对了多少 数据均衡、四类差不多重要
精确率 说我阳性的里,真的阳性占多少 误报代价大(垃圾邮件误判会丢重要邮件)
召回率 真阳性里,我抓出了多少 漏报代价大(癌症、欺诈、安全事故)
F1 精确率和召回率的综合 两个都重要又数据不均衡

一句话记忆法 🎯

  • 精确率:抓得准不准
  • 召回率:抓得全不全
  • F1:又准又全的均衡分
  • 准确率:总体答对率(数据偏的时候别太信它)

记住一个直觉:精确率和召回率是跷跷板——阈值调高,报警更保守,精确率上去、召回率下来;阈值调低,反过来。F1 就是帮你找那个最舒服的平衡点。

讲清楚了吗?还有具体的场景想套一下,或者想看代码实现(比如 sklearn 里 classification_report 怎么用),随时说~

acc = accuracy_score(y_test, y_pred)
# 这个乳腺癌数据集里通常是 2=良性、4=恶性,这里显式指定 4 为正类
pre = precision_score(y_test, y_pred, pos_label=4)
rec = recall_score(y_test, y_pred, pos_label=4)
f1 = f1_score(y_test, y_pred, pos_label=4)

混淆矩阵

混淆矩阵就是一张分类结果的“对账统计表”,清清楚楚告诉你:你的分类模型「哪些判对了、哪些判错了,以及是怎么错的」,是评估分类算法好坏的基础工具。

混淆矩阵是带错题详情的成绩单,而且可以用来计算准确率、精确率、F1 分数,分数只能告诉你考得好不好,错题本才能告诉你哪里错了、该怎么改进。

基础版本:二分类混淆矩阵

混淆矩阵图片

  • 图里一共 10 个样本,其中 6 个是恶性4 个是良性
  • 这里约定:恶性 = 正类良性 = 负类

矩阵的行代表真实情况列代表模型预测结果,最终分出 4 个核心格子:

真实\预测 预测“恶性”(阳性) 预测“良性”(阴性)
真恶性 ✅ 真阳性(TP) ❌ 假阴性(FN)
真良性 ❌ 假阳性(FP) ✅ 真阴性(TN)
四个格子一秒记牢
  • 第一个字(真/假)看判得对不对,第二个字(阳/阴)看模型给出的结论。
  • 所以:TP = 真恶性判成恶性,FN = 真恶性判成良性,FP = 真良性判成恶性,TN = 真良性判成良性。

它的核心价值:揭穿“准确率”的骗局

很多人一上来只看准确率,但在分类任务里,只看准确率很容易把模型看错

  • 因为两个模型就算准确率一样,错法也可能完全不同。
  • 混淆矩阵的价值就在这里:它不只告诉你“对了多少”,还告诉你“错在了哪里”。
  • 比如在癌症筛查里,通常更怕 FN,也就是把真的恶性漏成良性。
  • 所以这里不能只盯着准确率,还得继续看精确率、召回率、F1。

同样的准确率,可能是完全不同的模型

下面把指标公式实际代入分开看。

计算公式
  • 准确率(Accuracy):(TP + TN) / (TP + TN + FP + FN)

  • 精确率(Precision):TP / (TP + FP)

  • 召回率(Recall):TP / (TP + FN)

  • F1-score:2 * Precision * Recall / (Precision + Recall)

  • 精确率:你报成正类的那堆里,有多少是真的。

  • 召回率:所有真的正类里,你找出来多少。

  • F1:看精确率和召回率有没有明显偏科。

再看实际值 按图里的两个模型代入。

模型 TP FN FP TN
模型 A 3 3 0 4
模型 B 6 0 3 1

模型 A

  • 准确率:(3 + 4) / 10 = 70%
  • 精确率:3 / (3 + 0) = 100%
  • 召回率:3 / (3 + 3) = 50%
  • F1:2 * 1.0 * 0.5 / (1.0 + 0.5) = 0.667

模型 B

  • 准确率:(6 + 1) / 10 = 70%
  • 精确率:6 / (6 + 3) = 66.7%
  • 召回率:6 / (6 + 0) = 100%
  • F1:2 * 0.667 * 1.0 / (0.667 + 1.0) ≈ 0.8
怎么理解这两个结果
  • 两个模型准确率一样,都是 70%,所以只看准确率分不出谁更适合业务。
  • 模型 A 更“保守”:精确率高,但漏掉了 3 个恶性,召回率低。
  • 模型 B 更“激进”:召回率满分,但多错报了 3 个良性,精确率下降。
  • F1 看,模型 B 的综合表现更好。

这就是为什么只看准确率很危险:

  • 如果这是机场安检,通常会更偏向模型 B,因为宁可多复检几个人,也别把真正危险的东西漏过去。
  • 如果这是垃圾邮件过滤,你可能反而不想要一个误报特别多的模型。

混淆矩阵代码应用

# 导包
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

# 1.读取文件获取数据
data = pd.read_csv('data/breast-cancer-wisconsin.csv', sep=',')
print(data.shape, data.ndim)  # 形状:(699, 11) 维度:2
# 2.数据预处理
# 2.0 注意: 数据中有"?"无效字符,需要先转换为numpy中的nan,然后使用dropna()删除或者fillna()填充
new_data = data.replace('?', np.nan).dropna()
print(new_data.shape, new_data.ndim)  # 形状:(683, 11) 维度:2
# 2.1 分别获取特征和标签
# 拓展:  iloc格式 : 数据.iloc[行索引,列索引]
x = new_data.iloc[:, 1:-1]
y = new_data.iloc[:, -1]
print(x.shape, x.ndim)  # 形状:(683, 9) 维度:2
print(y.shape, y.ndim)  # 形状:(683,) 维度:1
print(pd.DataFrame(y).value_counts())  # 2:444 3:239
# 2.2 使用train_test_split()按比例切割成4部分
# 同一个种子,同一份随机数据
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=666)  
# 3.特征处理(标准化)
ss = StandardScaler()  # 标准化模型对特征数据处理
new_x_train = ss.fit_transform(X_train)
new_x_test = ss.transform(X_test)
# 4.创建模型
lr_model = LogisticRegression()  # 逻辑回归模型真正预测结果
# 5.模型训练
lr_model.fit(new_x_train, y_train)
print('=======================================================')
# TODO 导包: 依次导入混淆矩阵,准确率,精确率,召回率,f1分数,分类报告/报表
from sklearn.metrics import confusion_matrix, accuracy_score, precision_score, recall_score, f1_score, \
    classification_report

# TODO 模型预测和评估: 准确率,精确率,召回率,f1分数
y_pred = lr_model.predict(new_x_test)
print(f"准确率:{accuracy_score(y_test, y_pred)}")
print(f"精确率:{precision_score(y_test, y_pred, pos_label=4)}")
print(f"召回率:{recall_score(y_test, y_pred, pos_label=4)}")
print(f"F1分数:{f1_score(y_test, y_pred, pos_label=4)}")

# 混淆矩阵
print(f"混淆矩阵:\n{confusion_matrix(y_test, y_pred)}")
# 分类报告
print(f"分类报告:\n{classification_report(y_test, y_pred)}")