- 视频链接
- 数据集下载地址:无需下载
本文学习目标:
- 知道逻辑回归的损失函数、优化方法
- 知道逻辑回归的应用场景
- 应用LogisticRegression实现逻辑回归预测
- 知道精确率、召回率等指标的区别
- 知道如何解决样本不均衡情况下的评估
- 会绘制ROC曲线图形
1. 逻辑回归介绍
学习目标:
- 了解逻辑回归的应用场景
- 知道逻辑回归的原理
- 掌握逻辑回归的损失函数和优化方案
逻辑回归(Logistic Regression)是机器学习中的一种分类模型,逻辑回归是一种分类算法,虽然名字中带有回归,但是它与回归之间有一定的联系。由于算法的简单和高效,在实际中应用非常广泛。
逻辑回归(Logistic Regression)是机器学习领域最为常见的模型方法之一,常常用于作为处理各种任务的基准模型(baseline)。简单来说,逻辑回归是一种用于解决二分类(0 或 1)问题的机器学习方法,用于估计某种事物的可能性。
Q1:在机器学习中,逻辑回归和线性回归有什么联系吗?
A1:逻辑回归和线性回归都属于广义线性回归模型的特例。逻辑回归假设因变量
y
y
y 服从伯努利分布,而线性回归假设因变量
y
y
y 服从高斯分布。因此与线性回归有很多相同之处,去除Sigmoid映射函数的话,逻辑回归算法就是一个线性回归。
Q2:什么是伯努利分布,什么是高斯分布?
A2:伯努利分布(英语:Bernoulli distribution),又名两点分布或者0-1分布,是一种离散型概率分布。若伯努利试验成功,则伯努利随机变量取值为1。若伯努利试验失败,则伯努利随机变量取值为0。记其成功概率为
p
p
p,失败概率为
1
−
p
1-p
1−p。
高斯分布(Gaussian distribution),也称正态分布(Normal distribution),是一种连续型概率分布。它的概率密度函数呈钟形,两头低,中间高,左右对称。正态分布由两个参数 μ \mu μ 和 σ 2 \sigma^2 σ2 定义,它们是数轴上的最小值和最大值,通常缩写为 N ( μ , σ 2 ) N(\mu, \sigma^2) N(μ,σ2)。
Q3:逻辑回归和线性回归的区别是什么?
A3:线性回归和逻辑回归都属于广义线性回归模型的特例。线性回归用于解决回归问题,而逻辑回归用于解决分类问题(二分类、多分类)。线性回归无link-function或不起作用,逻辑回归的link-function是对数几率函数。线性回归使用最小二乘法作为参数估计方法,逻辑回归使用极大似然法作为参数估计方法。
Q4:是不是线性回归是拟合一根连续的线,而逻辑回归拟合的是一些离散的点?
A4:线性回归和逻辑回归都是拟合一个函数,但它们的目的不同。
- 线性回归用于预测连续值变量,它拟合的是一条直线或者一个平面。
- 逻辑回归用于解决分类问题,它拟合的是一个S形曲线(Sigmoid函数),这条曲线将数据分成两类或多类。逻辑回归的输出是概率值,表示数据属于某一类的概率。
1.1 逻辑回归的应用场景
- 广告点击率
- 是否为垃圾邮件
- 是否患病
- 是否为金融诈骗
- 是否为虚假账号
看到上面的例子,我们可以发现其中的特点,那就是都属于两个类别之间的判断。逻辑回归就是解决二分类问题的利器。
逻辑解决的是:是或否。而逻辑回归是给出具体的值。
1.2 逻辑回归的原理
要想掌握逻辑回归,必须掌握两点:
- 逻辑回归中,其输入值是什么?
- 如何判断逻辑回归的输出?
1.2.1 逻辑回归的输入
h ( w ) = w 1 x 1 + w 2 x 2 + . . . + b = w T x \begin{aligned} h(w) &= w_1 x_1 + w_2 x_2 + ... + b \\ &= w^Tx \end{aligned} h(w)=w1x1+w2x2+...+b=wTx
其中, w 1 , w 2 , . . . , b w_1, w_2, ..., b w1,w2,...,b 是模型的参数, x 1 , x 2 , . . . x_1, x_2, ... x1,x2,... 是输入数据的特征, h ( w ) h(w) h(w) 表示假设函数(hypothesis function),它是一个关于模型参数 w w w 的函数,也是逻辑回归的输入。这个公式计算了输入数据的特征和模型参数的线性组合,它的输出可以看作是线性回归的输出。因此我们需要记住:逻辑回归的输入就是一个线性回归的输出。
1.2.2 激活函数
该怎样理解上面那句话:“逻辑回归的输入就是一个线性回归的输出”?
这是因为逻辑回归会通过一个Sigmoid函数将线性回归的输出映射到0和1之间。Sigmoid函数的输出可以看作是数据属于某一类的概率。sigmoid函数如下所示:
g ( w T , x ) = 1 1 + e − h ( w ) = 1 1 + e − w T x \begin{aligned} g(w^T, x) &= \frac{1}{1 + e^{-h(w)}} \\ &= \frac{1}{1 + e^{-w^Tx}} \end{aligned} g(wT,x)=1+e−h(w)1=1+e−wTx1
Sigmoid函数将线性回归的输出映射到0和1之间,它的输出可以看作是数据属于某一类的概率。其中 w T x w^Tx wTx 表示输入数据的特征和模型参数的线性组合,也就是线性回归的输出。
逻辑回归的判断标准:
- 回归的结果输入到Sigmoid函数当中
- 输出结果为 [ 0 , 1 ] [0,1] [0,1] 区间中的一个概率值,默认 0.5 0.5 0.5 为阈值
逻辑回归最终的分类是通过属于某个类别的概率值来判断是否属于某个类别,并且这个类别默认标记为1(正例),另外的一个类别会标记为0(反例)。这样做的目的是方便计算损失。
输出结果解释:假设有两个类别A和B,现在有一个样本输入到逻辑回归,其输出结果0.55。因为这个概率值超过阈值0.5,这意味着我们训练或者预测的结果就是A(1)类别。反之,如果得出结果为0.3那么,训练或者预测结果就为B(用0表示)类别。
关于逻辑回归的阈值是可以进行改变的。比如上面举例中,如果把阈值设置为0.6,那么输出的结果0.55,就属于B类。
Q1:逻辑回归的输入是线性回归的输出,再通过一个Sigmoid函数得到所属不同类别的概率。那Sigmoid函数是什么函数?
A1:Sigmoid函数在机器学习中常被用作神经网络的阈值函数,将变量映射到(0,1),可以用来做二分类。在深度学习中,由于其单增以及反函数单增等性质,Sigmoid函数常被用作神经网络的激活函数,将变量映射到 [0,1] 之间。
Q2:在机器学习和深度学习中,阈值函数有哪些?
A2:在机器学习和深度学习中,阈值函数是一种将输入信号的总和转换为输出信号的函数,也称为激活函数(activation function)。常见的激活函数有Sigmoid函数和ReLU函数。
Q3:ReLU激活函数也可以用作逻辑回归吗?将线性回归的输出作为输入,得到一个[0, 1]的概率?
A3:ReLU激活函数通常不用于逻辑回归。逻辑回归通常使用Sigmoid函数作为激活函数,将线性回归的输出映射到
[
0
,
1
]
[0,1]
[0,1] 区间,得到一个概率,用来做二分类。而ReLU函数的输出范围是
[
0
,
+
∞
)
[0, +\infty)
[0,+∞),并不适合用来表示概率。
Q4:将线性回归的输出作为逻辑回归的输入,得到一个[0, 1]的概率,是不是只有Sigmoid这一种函数?
A4:不是的。虽然Sigmoid函数是逻辑回归中最常用的激活函数,但也可以使用其他能将实数映射到
[
0
,
1
]
[0,1]
[0,1] 区间的函数。例如,Softmax函数通常用于多分类问题,它可以将一组实数映射到
[
0
,
1
]
[0,1]
[0,1] 区间,并且这组数的和为1。当Softmax函数用于二分类问题时,它与Sigmoid函数等效。
在之前,我们用最小二乘法衡量线性回归的损失。在逻辑回归中,当预测结果不对的时候,我们该怎么衡量其损失呢?
我们来看下图(下图中,设置阈值为0.6):
可以看到,一共有5个样本,其中三个样本预测错了,两个预测对了。那么如何去衡量逻辑回归的预测结果与真实结果的差异呢?
1.3 损失以及优化
1.3.1 损失函数(对数似然损失,Log-likelihood Loss Function,LLLF)
逻辑回归的损失,称之为对数似然损失(Log-likelihood Loss Function,LLLF),公式如下:
一、分开类别
L ( h θ ( x ) , y ) = { − log ( h θ ( x ) ) i f y = 1 − log ( 1 − h θ ( x ) ) i f y = 0 \mathcal{L}(h_\theta(x), y) = \begin{cases} -\log{(h_\theta(x))} && \mathrm{if} \ y = 1 \\ -\log{(1 - h_\theta(x))} && \mathrm{if} \ y = 0 \end{cases} L(hθ(x),y)={−log(hθ(x))−log(1−hθ(x))if y=1if y=0
其中:
- L \mathcal{L} L 表示损失函数
- h θ ( x ) h_\theta(x) hθ(x) 表示模型对输入 x x x 的预测概率
- y y y 表示真实标签,取值为0或1
- log \log log 默认以自认常数 e e e 为底,所以 log ↔ ln \log \leftrightarrow \ln log↔ln
该函数图像如下:
-
当 y = 1 y=1 y=1 时,损失函数为 − log ( h θ ( x ) ) -\log{(h_\theta(x))} −log(hθ(x))。当模型预测正确,即 h θ ( x ) h_\theta(x) hθ(x) 接近1时,损失接近0;当模型预测错误,即 h θ ( x ) h_\theta(x) hθ(x) 接近0时,损失变得很大。
-
当 y = 0 y=0 y=0 时,损失函数为 − log ( 1 − h θ ( x ) ) -\log{(1 - h_\theta(x))} −log(1−hθ(x))。当模型预测正确,即 h θ ( x ) h_\theta(x) hθ(x) 接近0时,损失接近0;当模型预测错误,即 h θ ( x ) h_\theta(x) hθ(x) 接近1时,损失变得很大。
总之,对数损失函数能够衡量模型预测概率与真实标签之间的差异。当模型预测正确时,损失接近0;当模型预测错误时,损失变得很大。
无论何时,我们都希望损失函数值,越小越好。分情况讨论,对应的损失函数值:
- 当 y = 1 y=1 y=1 时,我们希望 h θ ( x ) h_\theta(x) hθ(x) 值越大越好
- 当 y = 0 y=0 y=0 时,我们希望 h θ ( x ) h_\theta(x) hθ(x) 值越小越好
二、综合完整损失函数
L ( h θ ( x ) , y ) = ∑ i = 1 m − y i log ( h θ ( x ) ) − − − − − − − − − − − 当 y i = 0 时此项为 0 − ( 1 − y i ) log ( 1 − h θ ( x ) ) − − − − − − − − − − − − − − − − − − − 当 y i = 1 时此项为 0 \mathcal{L}(h_\theta(x), y) = \sum_{i = 1}^m \underset{\underset{当y_i=0时此项为0}{-----------}}{- y_i \log{(h_\theta(x))}} \ \ \underset{\underset{当y_i=1时此项为0}{-------------------}}{-(1 - y_i) \log{(1 - h_\theta(x))}} L(hθ(x),y)=i=1∑m当yi=0时此项为0−−−−−−−−−−−−yilog(hθ(x)) 当yi=1时此项为0−−−−−−−−−−−−−−−−−−−−(1−yi)log(1−hθ(x))
其中:
- L \mathcal{L} L 表示损失函数
- h θ ( x ) h_\theta(x) hθ(x) 表示模型对输入 x x x 的预测概率
- y y y 表示真实标签,取值为0或1
- m m m 表示样本数量
- log \log log 默认以自认常数 e e e 为底,所以 log ↔ ln \log \leftrightarrow \ln log↔ln
这个公式是对数损失函数的向量化形式,它计算了所有样本的损失之和。对于每个样本 i i i,损失为 − y i log ( h θ ( x ) ) − ( 1 − y i ) log ( 1 − h θ ( x ) ) - y_i \log{(h_\theta(x))} - (1 - y_i) \log{(1 - h_\theta(x))} −yilog(hθ(x))−(1−yi)log(1−hθ(x))。
- 当 y i = 1 y_i=1 yi=1 时,损失为 − log ( h θ ( x ) ) -\log{(h_\theta(x))} −log(hθ(x))
- 当 y i = 0 y_i=0 yi=0 时,损失为 − log ( 1 − h θ ( x ) ) -\log{(1 - h_\theta(x))} −log(1−hθ(x))
总之,对数损失函数能够衡量模型预测概率与真实标签之间的差异。当模型预测正确时,损失接近0;当模型预测错误时,损失变得很大。
接下来我们就带入上面那个例子来计算一遍,就能理解意义了。
计算损失:
L = − [ 1 log ( 0.4 ) + ( 1 − 0 ) log ( 1 − 0.68 ) + 1 log ( 0.41 ) + ( 1 − 0 ) log ( 1 − 0.55 ) + 1 log ( 0.71 ) ] = − [ log ( 0.4 ) + log ( 1 − 0.68 ) + log ( 0.41 ) + log ( 1 − 0.55 ) + log ( 0.71 ) ] = − [ log ( 0.4 ) + log ( 0.32 ) + log ( 0.41 ) + log ( 0.45 ) + log ( 0.71 ) ] = − [ − 0.916290731874155 + ( − 1.139434283188365 ) + ( − 0.8915981192837835 ) + ( − 0.7985076962177716 ) + ( − 0.3424903089467762 ) ] = 4.088321139511852 \begin{aligned} \mathcal{L} &= -[1\log(0.4) + (1-0)\log(1-0.68)+1\log(0.41)+(1-0)\log(1-0.55)+1\log(0.71)] \\ &= -[\log(0.4) + \log(1-0.68)+\log(0.41)+\log(1-0.55)+\log(0.71)] \\ &= -[\log(0.4) + \log(0.32)+\log(0.41)+\log(0.45)+\log(0.71)] \\ &= -[-0.916290731874155 + (-1.139434283188365) + (-0.8915981192837835) + (-0.7985076962177716) + (-0.3424903089467762)] \\ &= 4.088321139511852 \end{aligned} L=−[1log(0.4)+(1−0)log(1−0.68)+1log(0.41)+(1−0)log(1−0.55)+1log(0.71)]=−[log(0.4)+log(1−0.68)+log(0.41)+log(1−0.55)+log(0.71)]=−[log(0.4)+log(0.32)+log(0.41)+log(0.45)+log(0.71)]=−[−0.916290731874155+(−1.139434283188365)+(−0.8915981192837835)+(−0.7985076962177716)+(−0.3424903089467762)]=4.088321139511852
我们已经知道了,对于 log ( P ) \log(P) log(P), P P P 值越大,结果越小。所以我们可以对这个损失的式子去分析。
1.3.2 优化函数(优化过程、如何利用损失优化模型参数)
同样使用梯度下降优化算法,去减少损失函数的值。这样去更新逻辑回归前面对应算法的权重参数,提升原本属于1类别的概率,降低原本是0类别的概率。
Q:为什么要降低原本属于0类别的样本的预测概率?
A:看公式说话。逻辑回归损失函数如下:
L ( h θ ( x ) , y ) = ∑ i = 1 m − y i log ( h θ ( x ) ) − − − − − − − − − − − ①当 y i = 0 时此项为 0 − ( 1 − y i ) log ( 1 − h θ ( x ) ) − − − − − − − − − − − − − − − − − − − ②当 y i = 1 时此项为 0 \mathcal{L}(h_\theta(x), y) = \sum_{i = 1}^m \underset{\underset{①当y_i=0时此项为0}{-----------}}{- y_i \log{(h_\theta(x))}} \ \ \underset{\underset{②当y_i=1时此项为0}{-------------------}}{-(1 - y_i) \log{(1 - h_\theta(x))}} L(hθ(x),y)=i=1∑m①当yi=0时此项为0−−−−−−−−−−−−yilog(hθ(x)) ②当yi=1时此项为0−−−−−−−−−−−−−−−−−−−−(1−yi)log(1−hθ(x))
- 对于某一个数据而言,它的真实值是1,那么②直接为0,公式变为: L ( h θ ( x ) , y ) = ∑ i = 1 m − log ( h θ ( x ) ) \mathcal{L}(h_\theta(x), y) = \sum_{i = 1}^m - \log{(h_\theta(x))} L(hθ(x),y)=∑i=1m−log(hθ(x))。我们期望损失Loss越小越好,所以对于真实值为1的数据,且 − log P -\log{P} −logP 是一个单调递减的函数,因此 P P P 越大,Loss越小,即提升原本属于1类别的概率;
- 对于某一个数据而言,它的真实值是0,那么①直接为0,公式变为: L ( h θ ( x ) , y ) = ∑ i = 1 m − log ( 1 − h θ ( x ) ) \mathcal{L}(h_\theta(x), y) = \sum_{i = 1}^m - \log{(1 - h_\theta(x))} L(hθ(x),y)=∑i=1m−log(1−hθ(x))。我们期望损失Loss越小越好,所以对于真实值为1的数据,且 − log ( 1 − P ) -\log{(1-P)} −log(1−P) 是一个单调递增的函数,因此 P P P 越大,Loss越大,而我们希望 P P P 越小越好,即降低原本是0类别的概率;
总之:逻辑回归损失函数的目标是最小化损失,因此对于真实值为1的数据,我们希望提高其预测概率,而对于真实值为0的数据,我们希望降低其预测概率。
- 逻辑回归概念【知道】
- 解决的是一个二分类问题
- 逻辑回归的输入是线性回归的输出
- 逻辑回归的原理【掌握】
- 输入:线性回归的输出
- 激活函数:Sigmoid函数
- 把整体的值映射到 [ 0 , 1 ] [0,1] [0,1]
- 再设置一个阈值,进行分类判断
- 逻辑回归的损失和优化【掌握】
- 损失函数:对数似然损失
- 借助了 log \log log(对数) 思想,进行完成
- 真实值等于0,等于1两种情况进行划分
- 优化过程:提升原本属于1类别的概率,降低原本是0类别的概率
- 损失函数:对数似然损失
对数似然损失函数的公式如下:
L i = L i ( p i , y i ) = { − l o g ( p i ) y i = 1 − l o g ( 1 − p i ) y i = 0 = − y i l o g ( p i ) − ( 1 − y i ) l o g ( 1 − p i ) \begin{aligned} \mathcal{L_i} & = \mathcal{L_i}(p_i,y_i) = \begin{cases} -log(p_i) & y_i = 1 \\ -log(1-p_i) & y_i = 0 \end{cases} \\ &= -y_ilog(p_i) - (1-y_i)log(1-p_i) \end{aligned} Li=Li(pi,yi)={−log(pi)−log(1−pi)yi=1yi=0=−yilog(pi)−(1−yi)log(1−pi)
其中, p i p_i pi 表示样本 i i i 预测为正类的概率, y i y_i yi 表示样本 i i i 的真实标签,正类为 1 1 1,负类为 0 0 0。当预测为正类的概率越大,损失越小。
2. 逻辑回归api介绍
学习目标:
- 知道逻辑回归api的用法
sklearn.linear_model.LogisticRegression(solver='liblinear', penalty='l2', C=1.0)
- 作用:用于实现逻辑回归(Logistic Regression)分类器
- 参数:
penalty
:指定正则化项中使用的范式。可选值为'l1'
、'l2'
、'elasticnet'
和None
。默认值为'l2'
。C
:正则化强度的倒数,必须是正浮点数。值越小表示正则化强度越大。默认值为 1.0。solver
:指定优化算法。可选值有'newton-cg'
、'lbfgs'
、'liblinear'
、'sag'
和'saga'
。默认值为'lbfgs'
。'newton-cg'
:牛顿法家族的一种,利用损失函数的二阶导数矩阵(即海森矩阵)来迭代优化损失函数。'lbfgs'
:拟牛顿法的一种,利用损失函数的二阶导数矩阵(即海森矩阵)来迭代优化损失函数。'liblinear'
:使用开源的 liblinear 库实现,内部使用了坐标轴下降法来迭代优化损失函数。'sag'
:随机平均梯度下降,是梯度下降法的变种,每次迭代仅仅用一部分的样本来计算梯度,适合于样本数据多的时候。'saga'
:线性收敛的随机优化算法的变种。- 说明:
- 对于小数据集,
'liblinear'
是一个不错的选择 - 对于大数据集,
'sag'
和'saga'
由于速度更快而更加适合 - 对于多分类问题,只有
'newton-cg'
、'sag'
、'saga'
和'lbfgs'
能够处理多项损失,而'liblinear'
受限于一对剩余 (OvR)。
- 对于小数据集,
fit_intercept
:是否在决策函数中添加常数项(即截距)。默认值为 True。random_state
:随机数种子。仅在优化算法为 sag 或 liblinear 时有用。默认值为 None。
- 返回值:本身是一个类,因此它的构造函数返回的是一个逻辑回归分类器实例化对象。
C
代表着“容忍度”,即模型对于分类错误的容忍程度。当C
值较大时,模型对于分类错误的容忍度较高,因此正则化强度较小;而当C
值较小时,模型对于分类错误的容忍度较低,因此正则化强度较大。
在逻辑回归中,C
参数被用作正则化强度的倒数,与 SVM 中的C
参数有类似的作用。因此可以将C
看作是一个惯用符号,而不必过于纠结它的字面含义。
LogisticRegression
方法相当于SGDClassifier(loss="log", penalty="")
。SGDClassifier
实现了一个普通的随机梯度下降学习;而LogisticRegression
实现了随机平均梯度下降(Stochastic Average Gradient Descent,SAG)
SGDClassifier(loss="log", penalty="")
- 作用:
SGDClassifier
是 scikit-learn 库中的一个类,它实现了带有随机梯度下降(SGD)学习的正则化线性模型。SGD 每次估计损失的梯度时都会对样本进行一次采样,并且模型会在采样过程中进行更新。 - 参数:
loss
参数指定了要使用的损失函数"log"
表示逻辑回归,是一种概率分类器
penalty
参数指定了要使用的惩罚(正则化项),默认值为"l2"
,表示标准的线性 SVM 模型的正则化器- 当
penalty
设置为空字符串时,不会添加任何惩罚
- 当
注意:逻辑回归默认将类别数量少的当做正例。
Q1:在逻辑回归中,什么是正例,什么是反例?
A1:在逻辑回归中,正例通常指的是标记为1的类别,而反例则指的是标记为0的类别。逻辑回归最终的分类是通过属于某个类别的概率值来判断是否属于某个类别。例如,当概率值大于0.5时,我们可以将其判断为正例,否则判断为反例。
Q2:正例和反例是正样本和负样本吗?
A2:是的,正例和反例通常指的是正样本和负样本。在二分类问题中,正样本通常指的是标记为1的类别,而负样本则指的是标记为0的类别。
Q3:正样本和负样本的定义是什么?
A3:在二分类问题中,正样本和负样本是指数据集中属于两个不同类别的样本。通常情况下,正样本指的是标记为1的类别,而负样本则指的是标记为0的类别。这些标记可以是人为定义的,也可以是根据实际情况确定的。例如,在垃圾邮件分类问题中,垃圾邮件可以被定义为正样本,而非垃圾邮件则被定义为负样本。
Q4:那在机器学习中,正样本和负样本的定义是什么?
A4:在机器学习中,正样本和负样本的定义通常与特定任务相关。例如,在二分类问题中,正样本通常指与预测目标相关的样本,而负样本则指与预测目标无关的样本。例如,在判断一张图片是否为猫的二分类任务中,正样本是猫的图片,而负样本是非猫的图片。
Q5:在深度学习中,正样本和负样本的定义是什么?
A5:在深度学习中,正样本和负样本的定义通常与训练目标有关。例如,在二分类问题中,正样本通常指与预测目标一致的样本,而负样本则指与预测目标不一致的样本。例如,在判断一张图片是否为猫的二分类任务中,正样本指图片中有猫的样本,而负样本则指图片中没有猫的样本。
Q6:那在目标检测任务中,正样本和负样本的定义是什么?
A6:在目标检测任务中,正样本是待检测的目标。例如,在检测人脸时,人脸是正样本,非人脸则是负样本。正负样本都是针对于算法经过处理生成的框(如:计算宽高比、交并比、样本扩充等)而言,而非原始的GT数据。
Q7:那对于分类问题,正负样本是原始的GT数据吗?
A7:对于分类问题,正样本和负样本通常是指原始的GT数据。例如,在二分类问题中,正样本是我们想要正确分类出的类别所对应的样本,而负样本则是另一个类别所对应的样本。
Q8:例如,在判断一张图片是否为猫的二分类任务中,正样本是猫的图片,而负样本是非猫的图片。这里的负样本可以多个类别吗,比如负样本是狗或老鼠或老虎或狮子?
A8:是的。在判断一张图片是否为猫的二分类任务中,正样本是猫的图片,而负样本是非猫的图片。负样本可以是多个类别,比如狗、老鼠、老虎或狮子等等。只要不是猫的图片都可以作为负样本。
Q9:逻辑回归只有两个类别吗?
A9:逻辑回归不仅可以用于二分类问题,也可以用于多分类问题。在处理多分类问题时,通常采用一种称为One-vs-all(也叫做 One-vs-rest)的方法。这种方法会以参考分类作为参考,构建多个分类模型,计算每个数据属于各个分类的概率,取概率最大的分类作为最终分类。
3. 案例:癌症分类预测-良/恶性乳腺癌肿瘤预测
学习目标:
- 通过肿瘤预测案例,学会如何使用逻辑回归对模型进行训练
3.1 背景介绍
一、数据介绍
文件介绍:
breast-cancer-wisconsin.data
:数据样本breast-cancer-wisconsin.names
:数据描述
数据集介绍:
- 该数据集有699条样本,共11列数据。第一列为用于检索的id,后9列分别是与肿瘤相关的医学特征,最后一列表示肿瘤类型的数值
- 该数据集共包含16个缺失值,用
?
标出
二、原始数据集的下载地址
https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/
3.2 案例分析
步骤分析:
# 1. 获取数据
# 2. 基本数据处理
## 2.1 缺失值处理
## 2.2 确定特征值和目标值
## 2.3 分割数据
# 3. 特征工程:标准化
# 4. 机器学习:逻辑回归
# 5. 模型评估
3.3 代码实现
请使用Jupyter Notebook以方便可视化。
1. 获取数据
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
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
# 1. 获取数据
names = ["Sample code number", "Clump Thickness", "Uniformity of Cell Size",
"Uniformity of Cell Shape", "Marginal Adhesion", "Single Epithelial Cell Size",
"Bare Nuclei", "Bland Chromatin", "Normal Nucleoli", "Mitoses", "Class"]
data = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data",
names=names)
data.head()
最后的
Class
表示肿瘤的类别,其中2
表示良性;4
表示恶性。
2. 基本数据处理
# 2. 基本数据处理
## 2.1 缺失值处理
data = data.replace(to_replace='?', value=np.NAN) # 替换缺失值
data = data.dropna() # 丢弃缺失值的数据(这一行就删除了,因为缺失值不多)
## 2.2 确定特征值和目标值
x = data.iloc[:, 1:10] # 不要索引列和最后一列
x.head()
y = data["Class"] # GT
y.head()
## 2.3 分割数据
x_train, x_test, y_train, y_test = train_test_split(data, y, random_state=22)
print(x_train.shape) # (512, 11)
print(y_train.shape) # (512,)
print(x_test.shape) # (171, 11)
print(y_test.shape) # (171,)
Q:为什么要先替换缺失值再删除缺失值所在的行,不能直接删除行吗?
A:在这段代码中,首先使用 replace
函数将数据中的 '?'
替换为 np.NAN
,然后使用 dropna
函数删除包含缺失值的行。这样做的原因可能是因为原始数据中使用 '?'
来表示缺失值,而 dropna
函数默认只删除包含 NaN
或 NA
值的行。因此,需要先将 '?'
替换为 np.NAN
,然后再使用 dropna
函数删除包含缺失值的行。
当然,也可以直接删除包含
'?'
的行,但这需要编写额外的代码来实现。使用replace
和dropna
函数可以更简单地实现删除包含缺失值的行的目的。
3. 特征工程:标准化
# 3. 特征工程:标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
print(x_train.shape) # (512, 11)
print(x_test.shape) # (171, 11)
4. 机器学习:逻辑回归
# 4. 机器学习:逻辑回归
estimator = LogisticRegression(penalty="l2") # 默认就是l2惩罚
estimator.fit(x_train, y_train)
print(estimator) # LogisticRegression()
5. 模型评估
# 5. 模型评估
## 5.1 准确率
scores = estimator.score(x_test, y_test)
print(f"准确率为:{scores * 100}%")
## 5.2 预测值
y_predict = estimator.predict(x_test)
print(f"预测值为:\r\n{y_predict}")
"""
模型预测效果
准确率为:100.0%
预测值为:
[2 4 4 2 2 2 2 2 2 2 2 2 2 4 2 2 4 4 4 2 4 2 4 4 4 2 4 2 2 2 2 2 4 2 2 2 4
4 2 2 2 4 2 4 4 4 4 2 4 4 2 2 2 2 2 4 2 2 2 2 4 4 4 4 2 4 2 2 4 2 2 2 2 4
2 2 2 2 2 2 4 4 4 2 4 4 4 4 2 2 2 4 2 4 2 2 2 2 2 2 4 2 2 4 2 2 4 2 4 4 2
2 2 2 4 2 2 2 2 2 2 4 2 2 2 2 2 4 2 4 2 2 2 4 2 2 2]
在很多分类场景当中我们不一定只关注预测的准确率!比如以这个癌症举例子。我们并不关注预测的准确率,而是关注在所有的样本当中,癌症患者有没有被全部预测(检测)出来。
因此我需要引入额外的模型评估指标。
小结:
- 肿瘤预测案例实现【知道】
- 如果数据中有缺失值,一定要对其进行处理。通常需要对其进行处理。处理缺失值的方法取决于缺失值的数量和数据的特点:
- 缺失值较少:如果缺失值较少,可以直接删除包含缺失值的行。这样做可以快速简单地处理缺失值,但会导致数据量减少。(一般是先替换缺失值,再丢弃缺失值所在的行)
- 缺失值较多:直接删除包含缺失值的行可能会导致数据量减少过多,影响模型的性能。此时,可以使用一些方法来填充缺失值,例如使用均值、中位数或众数填充数值型特征的缺失值,或使用众数填充类别型特征的缺失值。也可以使用更复杂的方法,例如使用其他特征预测缺失值,或使用基于邻居的方法填充缺失值。
- 准确率并不是衡量分类正确的唯一标准
- 如果数据中有缺失值,一定要对其进行处理。通常需要对其进行处理。处理缺失值的方法取决于缺失值的数量和数据的特点:
4. 分类评估方法
学习目标:
- 了解什么是混淆矩阵
- 知道分类评估中的精确率和召回率
- 知道roc曲线和auc指标
4.1 分类评估方法
4.1.1 混淆矩阵
混淆矩阵是机器学习中总结分类模型预测结果的情形分析表,以矩阵形式将数据集中的记录按照真实的类别与分类模型预测的类别判断两个标准进行汇总。其中矩阵的行表示真实值,矩阵的列表示预测值。
混淆矩阵是一种评判模型结果指标的可视化工具,属于模型评估的一部分,多用于判断分类器(Classifier)的优劣。特别用于监督学习(有一一对应的GT),在无监督学习一般叫做匹配矩阵。
在分类任务下,预测结果(Predicted Condition)与正确标记(True Condition)之间存在四种不同的组合,可以构成混淆矩阵(适用于多分类)。混淆矩阵如下图所示。
在混淆矩阵中,正例和负例(假例)是指分类模型中的两个类别。
- 真正例(True Positive,TP)是指模型正确预测为正例的数量。
- 伪正例(False Positive,FP)是指模型错误预测为正例的数量。
- 真反例(True Negative,TN)是指模型正确预测为负例的数量。
- 伪反例(False Negative,FN)是指模型错误预测为负例的数量。
举个例子,假设我们有一个分类模型用来预测一批顾客是否会购买某种产品。顾客购买产品我们标记为正例,没购买标记为负例。则:
- TP就是模型正确预测顾客会购买产品的数量。
- FP就是模型错误预测顾客会购买产品的数量。
- TN就是模型正确预测顾客不会购买产品的数量。
- FN就是模型错误预测顾客不会购买产品的数量。
只有前面是T(True)的才是预测正确的(预测值与GT一致);前面是F(False)的表示预测错误(预测值与GT不一致)
Q1:如何正确“看”一个混淆矩阵?
A1:要正确“看”一个混淆矩阵,首先需要了解混淆矩阵中各个元素的含义。此外,可以通过计算准确率、精确率、召回率和F1分数等指标来评估模型的性能。通过观察混淆矩阵中各个元素的值以及计算相关指标,可以对模型的性能进行评估。
Q2:混淆矩阵有什么鲜明的特点?
A2:混淆矩阵的一个鲜明特点是,对角线上的元素表示模型预测正确的数量,非对角线上的元素表示模型预测错误的数量。例如,在一个二分类问题中,混淆矩阵的左上角元素表示真正例(TP),右下角元素表示真反例(TN),右上角元素表示伪正例(FP),左下角元素表示伪反例(FN)。
此外,混淆矩阵可以用来计算准确率、精确率、召回率和F1分数等指标,以评估模型的性能。它可以帮助我们快速了解模型在不同类别上的预测能力,并为我们提供改进模型性能的依据。
4.1.2 精确率(Precision)
在混淆矩阵中,精确率(Precision)是指模型预测为正例且预测正确的样本数量(TP)占模型预测为正样本(正例)的样本数量(TP+FP)的比例。它衡量了模型在预测正样本时的准确性。
精确率的计算公式为:
P r e c i s i o n = T P T P + F P \rm{Precision} = \frac{TP}{TP + FP} Precision=TP+FPTP
其中TP表示真正样本(True Positive)的数量,FP表示伪正样本(False Positive)的数量。
举个例子,假设我们有一个分类模型用来预测一批顾客是否会购买某种产品。顾客购买产品我们标记为正样本,没购买标记为负例。如果模型预测有100个顾客会购买产品(TP + FP),其中有80个顾客实际购买了产品(TP),那么精确率就是 80 80 + 20 = 80 100 = 0.8 \frac{80}{80 + 20} = \frac{80}{100} = 0.8 80+2080=10080=0.8。
“如果模型预测有100个顾客会购买产品(TP + FP),其中有80个顾客实际购买了产品(TP)”,这里的“其中”是TP+FP的其中,所以“其中有80个顾客实际购买了产品”是TP而不是TP + FN。
TP + FN是所有顾客中实际购买产品的人数
4.1.3 召回率(Recall)
在混淆矩阵中,召回率(Recall)是指模型预测为正样本且预测正确的样本数量(TP)占真实值为正样本的样本数量(TP + FN)的比例。它衡量了模型对正样本的识别能力。
召回率的计算公式为:
R e c a l l = T P T P + F N \rm Recall = \frac{TP}{TP + FN} Recall=TP+FNTP
其中TP表示真正样本(True Positive)的数量,FN表示伪负样本(反例)(False Negative)的数量。
举个例子,假设我们有一个分类模型用来预测一批顾客是否会购买某种产品。顾客购买产品我们标记为正样本,没购买标记为负例。如果有100个顾客实际购买了产品(TP + FN),模型预测其中有80个顾客会购买产品(TP),那么召回率就是 80 80 + 20 = 80 100 = 0.8 \frac{80}{80 + 20} = \frac{80}{100} = 0.8 80+2080=10080=0.8。
4.1.4 准确率(Accuracy)
在混淆矩阵中,准确率(Accuracy)是指模型预测正确的样本数量(TP + FP)占总样本数量(TP + FP + TN + FN)的比例。它衡量了模型的整体预测能力。
准确率的计算公式为:
A c c u r a c y = T P + F P T P + F P + T N + F N \rm Accuracy = \frac{TP + FP}{TP + FP + TN + FN} Accuracy=TP+FP+TN+FNTP+FP
其中TP表示真正样本(True Positive)的数量,TN表示真负样本(True Negative)的数量,FP表示伪正样本(False Positive)的数量,FN表示伪负样本(False Negative)的数量。
举个例子,假设我们有一个分类模型用来预测一批顾客是否会购买某种产品。顾客购买产品我们标记为正样本,没购买标记为负例。如果总共有1000个顾客(TP + FP + TN + FN),模型预测有900个顾客有购买意向(TP + FP),那么准确率就是 900 1000 = 0.9 \frac{900}{1000} = 0.9 1000900=0.9。
正例和负例通常指分类模型中的两个类别,也可以称为正样本和负样本。在一个二分类问题中,我们通常将其中一个类别标记为正例或正样本,另一个类别标记为负例或负样本。
4.1.5 F1-Score
在混淆矩阵中,F1-Score是精确率(Precision)和召回率(Recall)的调和平均数。它衡量了模型在预测正例时的准确性和对正例的识别能力。
调和平均数:调和平均数(Harmonic Mean)是一种平均数的计算方法。它是一组数的倒数的算术平均数的倒数。对于一组正实数 x 1 , x 2 , . . . , x n x_1, x_2, ..., x_n x1,x2,...,xn,它们的调和平均数 H H H 定义为:
H = n 1 x 1 + 1 x 2 + . . . + 1 x n H = \frac{n}{\frac{1}{x_1} + \frac{1}{x_2} + ... + \frac{1}{x_n}} H=x11+x21+...+xn1n
调和平均数通常用于计算平均速率或平均比率。它对较小的数值有较大的影响,因此当数据集中有较小的数值时,调和平均数会比算术平均数小。
例如,在混淆矩阵中,F1-Score就是精确率(Precision)和召回率(Recall)的调和平均数。如果精确率和召回率中有一个值较小,那么F1-Score也会较小。
F1-Score的计算公式为:
F 1 = 2 ∗ P r e c i s i o n ∗ R e c a l l P r e c i s i o n + R e c a l l = 2 T P 2 T P + F N + F P \rm \begin{aligned} F1 & = 2 * \frac{Precision * Recall}{Precision + Recall}\\ & = \frac{2TP}{2TP + FN + FP} \end{aligned} F1=2∗Precision+RecallPrecision∗Recall=2TP+FN+FP2TP
其中Precision表示精确率,Recall表示召回率。
注意:
- F1-Score的取值范围为: [ 0 , 1 ] [0, 1] [0,1]
- F1-Score是精确率和召回率的调和平均数,它综合考虑了模型的精确率和召回率。F1-Score越大,说明模型在精确率和召回率方面都表现得较好,因此可以认为模型更稳健。
举个例子,假设我们有一个分类模型用来预测一批顾客是否会购买某种产品。顾客购买产品我们标记为正例(P),没购买标记为负例(N)。如果模型预测有100个顾客会购买产品(TP + FP),其中有80个顾客实际购买了产品(TP),那么精确率就是 T P T P + F P = 80 100 = 0.8 \frac{TP}{TP + FP} = \frac{80}{100} = 0.8 TP+FPTP=10080=0.8。如果有100个顾客实际购买了产品(TP + FN),模型预测其中有80个顾客会购买产品(TP),那么召回率就是 T P T P + F N = 80 100 = 0.8 \frac{TP}{TP + FN} = \frac{80}{100} = 0.8 TP+FNTP=10080=0.8。根据公式,F1-Score就是 2 ∗ 0.8 ∗ 0.8 0.8 + 0.8 = 0.8 2 * \frac{0.8 * 0.8}{0.8 + 0.8} = 0.8 2∗0.8+0.80.8∗0.8=0.8。
4.2 分类评估报告api
sklearn.metrics.classification_report(y_true, y_pred, labels=[], target_names=None)
-
作用:用于构建一个文本报告,显示主要的分类指标。
-
参数:
y_true
:1维数组或类似的数据结构,表示真实的目标值。y_pred
:1维数组或类似的数据结构,表示分类器返回的估计目标值(预测值)。labels
:形状为(n_labels,)
的数组,可选参数,表示要包含在报告中的标签索引列表。target_names
:形状为(n_labels,)
的字符串列表,可选参数,表示与标签匹配的显示名称(顺序相同)。sample_weight
:形状为(n_samples,)
的数组,可选参数,表示样本权重。digits
:整数,默认值为 2,表示格式化输出浮点值时保留的位数。- 当
output_dict
为 True 时,此参数将被忽略,并且返回的值不会四舍五入。
- 当
output_dict
:布尔值,默认值为False
。如果为True
,则以字典形式返回输出。zero_division
:可以是“warn”
,0
或1
,默认值为“warn”
。设置存在零除法时返回的值。如果设置为“warn”
,则相当于0
,但也会引发警告。
-
返回值:函数返回一个字符串或字典,表示每个类别的精度、召回率、F1 分数的文本摘要。如果
output_dict
为 True,则返回字典。
还拿之前的案例举例:
from sklearn.metrics import classification_report
## 5.3 精确率、召回率、F1-Score评估指标
res = classification_report(y_true=y_test, y_pred=y_predict)
print(f"精确率、召回率、F1-Score评估指标为:\r\n{res}")
结果:
精确率、召回率、F1-Score评估指标为:
precision recall f1-score support
2 1.00 1.00 1.00 89
4 1.00 1.00 1.00 48
accuracy 1.00 137
macro avg 1.00 1.00 1.00 137
weighted avg 1.00 1.00 1.00 137
但是我们发现,索引列的2和4的可读性很差,不够直观,所以我们可以优化classification_report
函数:
from sklearn.metrics import classification_report
## 5.3 精确率、召回率、F1-Score评估指标
res = classification_report(y_true=y_test,
y_pred=y_predict,
labels=(2, 4),
target_names=["良性", "恶性"])
print(f"精确率、召回率、F1-Score评估指标为:\r\n{res}")
结果:
精确率、召回率、F1-Score评估指标为:
precision recall f1-score support
良性 1.00 1.00 1.00 89
恶性 1.00 1.00 1.00 48
accuracy 1.00 137
macro avg 1.00 1.00 1.00 137
weighted avg 1.00 1.00 1.00 137
其中:
support
表示每个类别的样本数量。例如,在结果中,support
为 89 表示“良性”类别有 89 个样本,而support
为 48 表示“恶性”类别有 48 个样本。accuracy
:准确率,表示分类器正确分类的样本数量占总样本数量的比例。它是一个整体性能指标,不区分不同的类别。macro avg
:宏平均,表示对每个类别的精度、召回率和 F1 分数分别求平均值。它没有考虑每个类别的样本数量,因此对于样本不均衡的数据集可能不太合适。weighted avg
:加权平均,表示对每个类别的精度、召回率和 F1 分数分别按照该类别的样本数量进行加权求平均。它考虑了每个类别的样本数量,因此对于样本不均衡的数据集更合适。
在这个例子中,结果显示:
- 对于“良性”类别,精度、召回率和 F1 分数均为 1.00。
- 对于“恶性”类别,精度、召回率和 F1 分数均为 1.00。
- 整体准确率为 1.00。
这意味着分类器在测试集上的表现非常好,能够完美地区分“良性”和“恶性”两个类别。
假设这样一个情况,如果99个样本为恶性,1个样本良性,不管怎样我(模型)全都预测为正样本(默认恶性为正样本),那么准确率就为99%。但是这样的效果并不好:
因为模型将所有样本都预测为“恶性”,即正样本。
因此,
对于“恶性”类别:
- 精度(精确率)(Precision)= 真正例 / (真正例 + 假正例)= 99 / (99 + 1) = 0.99
- 召回率(Recall)= 真正例 / (真正例 + 假反例)= 99 / (99 + 0) = 1.00
- F1 分数(F1-Score)= 2 * 精度 * 召回率 / (精度 + 召回率) = 2 * 0.99 * 1.00 / (0.99 + 1.00) = 0.995
对于“良性”类别:
- 由于模型没有预测出任何一个“良性”样本,因此精度、召回率和 F1 分数均为 0。
出现这样的原因是因为样本数量不均衡。
样本不均衡问题是指在分类问题中,不同类别的样本数量相差悬殊。这种情况下,分类器可能会倾向于预测数量较多的类别,从而导致对数量较少的类别的预测不准确。
关于何时出现样本不均衡问题,没有一个明确的比例界限。在实际应用中,如果不同类别的样本数量相差较大,就可能出现样本不均衡问题。
注意:当正样本和负样本的比例为 4:1 时就认为出现了样本数量不均衡问题。
正负样本比例为 4:1 的情况可能会出现样本不均衡问题,但这并不是一个确定的界限(具体问题应该具体分析)。
问题:如何衡量样本不均衡下的评估?
5. ROC曲线
5.1 TPR与FPR
TPR(True Positive Rate)和 FPR(False Positive Rate)是二分类问题中常用的评估指标。
一、TPR(True Positive Rate,真·正例率)
TPR,也称为召回率(Recall),表示真正样本(TP)占所有正样本(TP + FN)的比例。它的定义为:
T P R = 真正样本 真正样本 + 假负样本 = T P T P + F N \begin{aligned} \rm TPR & = \frac{真正样本}{真正样本 + 假负样本} \\ & = \frac{\rm TP}{\rm TP + FN} \end{aligned} TPR=真正样本+假负样本真正样本=TP+FNTP
其中真正样本(TP)表示分类器正确预测为正样本的样本数量,假负样本(FN)表示分类器错误预测为负例的样本数量(但GT为正样本)。
所有真实类别为 1 的样本中,预测类别为 1 的比例
二、FPR(False Positive Rate,假·正例率)
FPR 表示假正样本(FP)占所有负例(FP + TN)的比例。它的定义为:
F P R = 假正样本 假正样本 + 真负样本 = F P F P + T N \begin{aligned} \rm FPR & = \frac{假正样本}{假正样本 + 真负样本} \\ & = \frac{\rm FP}{\rm FP + TN} \end{aligned} FPR=假正样本+真负样本假正样本=FP+TNFP
其中假正样本(FP)表示分类器错误预测为正样本的样本数量,真负样本(FP + TN)表示分类器正确预测为负例的样本数量。
所有真实类别为 0 的样本中,预测类别为 1 的比例
5.2 ROC曲线
ROC(Receiver Operating Characteristic,受试者工作特征曲线)曲线是二分类问题中常用的评估指标。它通过绘制不同阈值下 TPR(True Positive Rate)和 FPR(False Positive Rate)的关系来评估分类器的性能。
在绘制 ROC 曲线时,横轴表示 FPR,纵轴表示 TPR。对于每个阈值,计算出对应的 TPR 和 FPR 值,并在图上绘制一个点。连接所有点,就得到了 ROC 曲线。
ROC 曲线越靠近左上角,表示分类器的性能越好。通常使用 AUC(Area Under Curve,曲线下面积)值来衡量 ROC 曲线下方的面积,AUC 值越大,表示分类器的性能越好。
- 左上角:所有样本均预测正确(TPR=1且FPR=0)
- 右下角:所有样本均预测错误(TPR=0且FPR=1)
当横纵坐标相等时,即 FPR = TPR(图中的红色虚线),表示分类器的预测结果与随机猜测相当(对于不论真实类别是 1 还是 0 的样本,分类器预测为 1 或 0 的概率是相等的)。在这种情况下,分类器无法区分正负样本,其性能不佳。
像上面那个假设“不管怎样我(模型)全都预测为正样本”,这就是在随机猜测(特殊的随机猜测),此时模型的性能并不好。
Q:AUC是什么?
A:AUC(Area Under Curve,曲线下面积)是 ROC曲线下方的面积。它是二分类问题中常用的评估指标,用于衡量分类器的性能。AUC 值的范围为 0 到 1。AUC 值越大,表示分类器的性能越好。当 AUC 值为 0.5 时,表示分类器的性能与随机猜测相当😂;当 AUC 值为 1 时,表示分类器能够完美地区分正负样本👍。
5.3 AUC指标
AUC 的概率意义是随机取一对正负样本,正样本得分大于负样本得分的概率。
-
A
U
C
\rm AUC
AUC 的范围在
[
0
,
1
]
[0,1]
[0,1] 之间,并且越接近
1
1
1 越好,越接近
0.5
0.5
0.5 属于乱猜
-
A
U
C
=
1
\rm AUC = 1
AUC=1,完美分类器。采用这个预测模型时,不管设定什么阈值都能得出完美预测。
- 绝大多数预测的场合,不存在完美分类器。
- 0.5 < A U C < 1 \rm 0.5 < AUC < 1 0.5<AUC<1,优于随机猜测。这个分类器(模型)妥善设定阈值的话,有一定的预测价值。
-
A
U
C
=
1
\rm AUC = 1
AUC=1,完美分类器。采用这个预测模型时,不管设定什么阈值都能得出完美预测。
注意:
- ROC 是一条曲线
- AUC 是一个范围在 [ 0 , 1 ] [0,1] [0,1] 之间浮点数,越接近 1 越好
Q:AUC如果小于0.5说明什么?
A:AUC(Area Under Curve)值的范围为 0 到 1。当 AUC 值小于 0.5 时,表示分类器的性能不如随机猜测。这意味着分类器无法区分正负样本,其预测结果与随机猜测相当。在这种情况下,可能需要重新训练模型或更换模型来提高分类器的性能。
5.4 AUC计算API
from sklearn.metrics import roc_auc_score
sklearn.metrics.roc_auc_score(y_true, y_score)
- 作用:用于计算 ROC(Receiver Operating Characteristic)曲线下方的面积,即 AUC(Area Under Curve)值。
- 参数:
y_true
:每个样本的真实类别,因为AUC只能用来评价二分类,因此必须使用 0(负样本)或 1(正样本)进行标记(如果不是0或1,需要进行转换)。- 形状为
(n_samples,)
或(n_samples, n_classes)
。 - 对于二分类问题,形状为
(n_samples,)
。
- 形状为
y_score
:预测得分,可以是正类的估计概率、置信值或者分类器方法的返回值。- 形状为
(n_samples,)
或(n_samples, n_classes)
。 - 对于二分类问题,它对应于一个形状为
(n_samples,)
的数组。可以提供概率估计和非阈值决策值。
- 形状为
- 返回值:函数返回一个浮点数,表示 AUC 值。
from sklearn.metrics import roc_auc_score
# 先将GT的(2, 4)转换为(0, 1)
y_test = np.where(y_test > 2, 1, 0) # 如果满足条件则设置为1否则设置为0
print(f"转换后的测试集GT为:\r\n{y_test}")
"""
array([0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0,
1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1,
1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1,
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1,
0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,
0, 1, 0, 0, 0])
"""
# 5.4 AUC指标计算
# auc应该在(0.5, 1)之间,越接近1越好(如果auc结果<0.5,模型需要重新训练或换一个模型)
auc = roc_auc_score(y_true=y_test, y_score=y_predict)
print(f"AUC值为:{auc}") # AUC值为:1.0
注意:
- AUC一般用于评价二分类问题
- AUC非常适合评价样本不平衡中的分类器性能
sklearn.metrics.roc_auc_score
函数可以处理二分类、多分类和多标签分类问题,但有一些限制。例如,对于多分类目标,average=None
仅在multi_class='ovr'
时实现,而average='micro'
仅在multi_class='ovr'
时实现。此外,对于多类别问题,AUC 当前仅处理“宏观”和“加权”平均值。
小结:
- 混淆矩阵【了解】
- 真·正样本(TP)
- 伪·负样本(FN)
- 伪·正样本(FP)
- 真·负样本(TN)
- 精确率(Precision)与召回率(Recall)【知道】
- 召回率(查的全不全): R e c a l l = T P T P + F N \rm Recall = \frac{TP}{TP + FN} Recall=TP+FNTP
- 精确率(查的准不准): P r e c i s i o n = T P T P + F P \rm{Precision} = \frac{TP}{TP + FP} Precision=TP+FPTP
- 准确率(对不对): A c c u r a c y = T P + T N T P + F P + T N + F N \rm Accuracy = \frac{TP + TN}{TP + FP + TN + FN} Accuracy=TP+FP+TN+FNTP+TN
- F1-Score(反映模型的稳健性): F 1 = 2 ∗ P r e c i s i o n ∗ R e c a l l P r e c i s i o n + R e c a l l \rm F1 = 2 * \frac{Precision * Recall}{Precision + Recall} F1=2∗Precision+RecallPrecision∗Recall
- ROC曲线和AUC指标【知道】
- ROC 曲线:通过 TPR 和 FPR 来进行图形绘制,绘制 ROC 曲线后会形成一个指标 AUC
- AUC:正常的范围为:
(
0.5
,
1
)
(0.5, 1)
(0.5,1)
- 越接近 1,效果越好
- 越接近 0,效果越差
- 越接近 0.5,效果就是胡说(随机猜测)
- 注意:
- 这个指标主要用于评价不平衡的二分类问题
- 当 A U C < 0.5 \rm AUC < 0.5 AUC<0.5 时模型是不可用的,需要重新训练或换模型后再训练
6. ROC曲线的绘制
学习目标:
- 知道如何绘制ROC曲线
关于ROC曲线的绘制过程,通过如下例子进行说明。
假设有 6 次展示记录,有两次被点击了,得到一个展示序列 (1:1, 2:0, 3:1, 4:0, 5:0, 6:0)
。前面的表示序号,后面的表示点击情况(1表示点击;0表示没有点击)。然后在这 6 次展示的时候都通过 model
算出了点击的概率序列。
下面看三种情况。
6.1 曲线绘制
6.1.1 情况1
如果模型推理的结果是(1:0.9, 2:0.7, 3:0.8, 4:0.6, 5:0.5, 6:0.4)
。
与原来的序列一起,得到序列(根据概率降序排序):
真实标签 | 1 | 1 | 0 | 0 | 0 | 0 |
---|---|---|---|---|---|---|
原来对应的点 | 1 | 3 | 2 | 4 | 5 | 6 |
点击概率 | 0.9 | 0.8 | 0.7 | 0.6 | 0.5 | 0.4 |
1表示点击了,0表示没有点击
绘制的步骤如下:
Step.1:把概率序列从高到低排序,得到顺序序列(1:0.9, 3:0.8, 2:0.7, 4:0.6, 5:0.5, 6:0.4)
Step.2:我们将概率最大的点1
作为正类。这意味着我们将点1
预测为点击,而其他点预测为未点击(尽管点 3 的真实标签是点击,但在这一步中我们仍然将其预测为未点击)。我们可以用混淆矩阵来表示预测结果和真实标签之间的关系:
点击 | 未点击 | |
---|---|---|
预测为点击 | TP=1 | FP=0 |
预测为未点击 | FN=1 | TN=4 |
其中,TP(True Positive)表示真正例,即被正确预测为点击的点;FP(False Positive)表示假正例,即实际上未被点击但被预测为点击的点;FN(False Negative)表示假反例,即实际上被点击但被预测为未点击的点(这里说的是点3
);TN(True Negative)表示真反例,即实际上未被点击且被正确预测为未点击的点。
根据混淆矩阵中的值,我们可以计算得到
T P R = T P T P + F P = 1 1 + 1 = 0.5 \rm TPR=\frac{TP}{TP + FP} = \frac{1}{1 + 1}=0.5 TPR=TP+FPTP=1+11=0.5
F P R = F P F P + T N = 0 0 + 4 = 0.0 \rm FPR=\frac{FP}{FP + TN}= \frac{0}{0+4} = 0.0 FPR=FP+TNFP=0+40=0.0
Step.3:我们将概率最大的两个点1
和 点3
都作为正类(积累的过程)。这意味着我们将点1
和 点3
预测为点击,而其他点预测为未点击。我们可以用混淆矩阵来表示预测结果和真实标签之间的关系:
点击 | 未点击 | |
---|---|---|
预测为点击 | TP=2 | FP=0 |
预测为未点击 | FN=0 | TN=4 |
此时 点3倍归为TP了,所以FN=0
根据混淆矩阵中的值,我们可以计算得到
T P R = T P T P + F P = 2 2 + 0 = 1.0 \rm TPR=\frac{TP}{TP + FP} = \frac{2}{2 + 0}=1.0 TPR=TP+FPTP=2+02=1.0
F P R = F P F P + T N = 0 0 + 4 = 0.0 \rm FPR=\frac{FP}{FP + TN}= \frac{0}{0+4} = 0.0 FPR=FP+TNFP=0+40=0.0
Step.4:我们将概率最大的三个点1、3和2
都作为正类。这意味着我们将点 1、3 和 2 预测为点击,而其他点预测为未点击。我们可以用混淆矩阵来表示预测结果和真实标签之间的关系:
点击 | 未点击 | |
---|---|---|
预测为点击 | TP=2 | FP=1 |
预测为未点击 | FN=0 | TN=3 |
根据混淆矩阵中的值,我们可以计算得到
T P R = T P T P + F P = 2 2 + 0 = 1.0 \rm TPR=\frac{TP}{TP + FP} = \frac{2}{2 + 0}=1.0 TPR=TP+FPTP=2+02=1.0
F P R = F P F P + T N = 1 1 + 3 = 0.25 \rm FPR=\frac{FP}{FP + TN}= \frac{1}{1+3} = 0.25 FPR=FP+TNFP=1+31=0.25
Q:点2的GT是未点击,也可以当作正样本吗?
A:是的,在绘制 ROC 曲线时,我们会逐个将点作为正类,并根据模型预测的概率来计算 TPR 和 FPR。在第三步中,我们将概率最大的三个点 1、3 和 2 都作为正类,尽管点 2 的真实标签是未点击。
这样做的目的是为了评估模型在不同阈值下的分类性能。当我们将点 2 作为正类时,相当于我们降低了分类阈值,使得更多的点被预测为点击。通过这种方式,我们可以得到一系列 TPR 和 FPR 值,并据此绘制 ROC 曲线。
Step.5:我们将概率最大的三个点1、3、2、4
都作为正类。这意味着我们将点1、3、2、4
预测为点击,而其他点预测为未点击。我们可以用混淆矩阵来表示预测结果和真实标签之间的关系:
点击 | 未点击 | |
---|---|---|
预测为点击 | TP=2 | FP=2 |
预测为未点击 | FN=0 | TN=2 |
根据混淆矩阵中的值,我们可以计算得到
T P R = T P T P + F P = 2 2 + 0 = 1.0 \rm TPR=\frac{TP}{TP + FP} = \frac{2}{2 + 0}=1.0 TPR=TP+FPTP=2+02=1.0
F P R = F P F P + T N = 2 2 + 2 = 0.5 \rm FPR=\frac{FP}{FP + TN}= \frac{2}{2+2} = 0.5 FPR=FP+TNFP=2+22=0.5
Step.6:我们将概率最大的三个点1、3、2、4、5
都作为正类。这意味着我们将点1、3、2、4、5
预测为点击(P),而其他点预测为未点击(N)。我们可以用混淆矩阵来表示预测结果和真实标签之间的关系:
点击 | 未点击 | |
---|---|---|
预测为点击 | TP=2 | FP=3 |
预测为未点击 | FN=0 | TN=1 |
根据混淆矩阵中的值,我们可以计算得到
T P R = T P T P + F P = 2 2 + 0 = 1.0 \rm TPR=\frac{TP}{TP + FP} = \frac{2}{2 + 0}=1.0 TPR=TP+FPTP=2+02=1.0
F P R = F P F P + T N = 3 3 + 1 = 0.75 \rm FPR=\frac{FP}{FP + TN}= \frac{3}{3+1} = 0.75 FPR=FP+TNFP=3+13=0.75
Step.7:我们将概率最大的三个点1、3、2、4、5、6
(所有点) 都作为正类。这意味着我们将 所有点 预测为点击(P),而 没有 未点击(N)的点。我们可以用混淆矩阵来表示预测结果和真实标签之间的关系:
点击 | 未点击 | |
---|---|---|
预测为点击 | TP=2 | FP=4 |
预测为未点击 | FN=0 | TN=0 |
根据混淆矩阵中的值,我们可以计算得到
T P R = T P T P + F P = 2 2 + 0 = 1.0 \rm TPR=\frac{TP}{TP + FP} = \frac{2}{2 + 0}=1.0 TPR=TP+FPTP=2+02=1.0
F P R = F P F P + T N = 4 4 + 0 = 1.0 \rm FPR=\frac{FP}{FP + TN}= \frac{4}{4+0} = 1.0 FPR=FP+TNFP=4+04=1.0
Step.8:
此时,我们可以得到 6 对 TPR 和 FPR。然后把这 6 对数据组成 6 个点 (0, 0.5), (0, 1.0), (0.25, 1), (0.5, 1), (0.75, 1), (1.0, 1.0)
。并在二维坐标系中能画出来。
import matplotlib.pyplot as plt
from pylab import mpl
# 设置中文字体
mpl.rcParams["font.sans-serif"] = ["SimHei"]
# 设置正常显示符号
mpl.rcParams["axes.unicode_minus"] = False
points = [(0, 0.5), (0, 1.0), (0.25, 1), (0.5, 1), (0.75, 1), (1.0, 1.0)]
point_names = [f"点{i}" for i in [1, 3, 2, 4, 5, 6]]
plt.figure(dpi=300)
count = 0
for x, y in points:
plt.scatter(x, y, label=point_names[count], zorder=2)
count += 1
x = [point[0] for point in points]
y = [point[1] for point in points]
plt.plot(x, y, zorder=1)
plt.grid(alpha=0.3)
plt.title("不同点的TPR和FPR值")
plt.xlabel("FPR ∈ [0, 1]")
plt.ylabel("TPR ∈ [0, 1]")
for i in range(len(points)):
if i == 0:
plt.annotate(point_names[i], xy=points[i], xytext=(5, 0), textcoords='offset points')
elif i == 1:
plt.annotate(point_names[i], xy=points[i], xytext=(5, -12), textcoords='offset points')
else:
plt.annotate(point_names[i], xy=points[i], xytext=(-5, -12), textcoords='offset points')
plt.show()
上面画出来的图就是 ROC 曲线。因为ROC 曲线是一种用来评估分类模型性能的图形工具,它通过绘制真正例率(True Positive Rate,TPR)和假正例率(False Positive Rate,FPR)来展示模型的分类能力,所以虽然它看起来不是曲线,但确实是ROC曲线(数据特殊而已)。
6.1.2 情况2
如果模型推理的结果是(1:0.9, 2:0.8, 3:0.7, 4:0.6, 5:0.5, 6:0.4)
。
与原来的序列一起,得到序列(根据概率降序排序):
真实标签 | 1 | 0 | 1 | 0 | 0 | 0 |
---|---|---|---|---|---|---|
原来对应的点 | 1 | 2 | 3 | 4 | 5 | 6 |
点击概率 | 0.9 | 0.8 | 0.7 | 0.6 | 0.5 | 0.4 |
1表示点击了,0表示没有点击
绘制的步骤如下:
- 把概率序列从高到低排序,得到顺序
(1:0.9, 2:0.8, 3:0.7, 4:0.6, 5:0.5, 6:0.4)
- 从概率最大开始取一个点作为正样本,取到
点1
,其他点都作为负样本。计算得到TPR=0.5,FPR=0.0 - 从概率大开始,再取
点1和点2
作为正样本,其他点都作为负样本。计算得到TPR = 0.5,FPR = 0.25 - 从概率大开始,再取
点1、点2和点3
作为正样本,其他点都作为负样本。计算得到TPR = 1.0,FPR = 0.25 - 以此类推,得到 6 对 TPR 和 FPR:
(0.0, 0.5), (0.25, 0.5), (0.25, 1.0), (0.5, 1.0), (0.75, 1.0), (1.0, 1.0)
- 然后把这 6 对数据组成 6 个点在二维坐标系中画出来
上面画出来的图就是 ROC 曲线。因为ROC 曲线是一种用来评估分类模型性能的图形工具,它通过绘制真正例率(True Positive Rate,TPR)和假正例率(False Positive Rate,FPR)来展示模型的分类能力,所以虽然它看起来不是曲线,但确实是ROC曲线(数据特殊而已)。
6.1.3 情况3
如果模型推理的结果是(1:0.4, 2:0.6, 3:0.5, 4:0.7, 5:0.8, 6:0.9)
。
与原来的序列一起,得到序列(根据概率降序排序):
真实标签 | 0 | 0 | 0 | 0 | 1 | 1 |
---|---|---|---|---|---|---|
原来对应的点 | 6 | 5 | 4 | 2 | 3 | 1 |
点击概率 | 0.9 | 0.8 | 0.7 | 0.6 | 0.5 | 0.4 |
1表示点击了,0表示没有点击
绘制的步骤如下:
- 把概率序列从高到低排序,得到顺序
(6:0.9, 5:0.8, 4:0.7, 2:0.6, 3:0.5, 1:0.4)
- 从概率最大开始取一个点作为正样本,取到
点6
,其他点都作为负样本。计算得到TPR = 0.0,FPR = 0.25 - 从概率大开始,再取
点6和点5
作为正样本,其他点都作为负样本。计算得到TPR = 0.0,FPR = 0.5 - 从概率大开始,再取
点6、点5和点4
作为正样本,其他点都作为负样本。计算得到TPR = 0.0,FPR = 0.75 - 以此类推,得到 6 对 TPR 和 FPR:
(0.25, 0.0), (0.5, 0.0), (0.75, 0.0), (1.0, 0.0), (1.0, 0.5), (1.0, 1.0)
- 然后把这 6 对数据组成 6 个点在二维坐标系中画出来
从上图可以发现一个极端点(1, 0)
。当模型取到(1, 0)
时说明模型整体都分错了(此时FPR=1,TPR=0)。
6.2 意义解释
如上图的例子,总共 6 个点,2 个正样本,4 个负样本,取一个正样本和一个负样本的情况总共有8种。
上面的第一种情况,从上往下取,无论怎么取,正样本的概率总在负样本之上,所以分对(正确)的概率为1,AUC = 1。再看那个 ROC 曲线,它的积分是什么?也是 1,ROC 曲线的积分与 AUC 相等,此时分类器是一个非常理想、非常完美的分类器(这种效果的分类器一般在解决真实问题时是不存在的)。
上面第二种情况,如果取到了样本 2 和 3,那就分错了,其他情况都分对了。所以分对的概率是 0.875,AUC = 0.875。再看那个 ROC 曲线,它的积分也是 0.875,ROC 曲线的积分与 AUC 相等。
上面的第三种情况,无论怎么取,都是分错的,所以分对的概率是0,AUC = 0.0。再看ROC 曲线,它的积分也是 0.0,ROC 曲线的积分与 AUC 相等。
其实 AUC 的意思是 Area Under ROC Curve,就是 ROC 曲线的积分,也是 ROC 曲线的面积。绘制 ROC 曲线的意义很明显,不断地把可能分错的情况扣除掉,从概率最高往下取点,每有一个是负样本,就会导致分错排在它下面的所有正样本,所以要把它下面的正样本数扣除掉(1-TPR,剩下的正样本的比例)。总的 ROC 曲线就绘制出来了,AUC 就定了,分对的概率也能求出来了。
ROC 曲线是通过不断改变分类阈值来绘制的,每个阈值都会产生一组 TPR 和 FPR 值。AUC 越大,说明模型的分类性能越好。
小结:
- ROC 曲线的绘制【知道】
- 构建模型,把模型的预测概率值从大到小进行排序
- 从概率最大的点开始取值,一直进行 TPR 和 FPR 的计算
- 然后构建整体模型,得到结果
- 其实就是在求解ROC的积分(也就是 AUC,即 ROC 曲线的面积)
7. 【补充内容】分类中解决类别不平衡问题
前面我们已经初步认识了,什么是类别不平衡问题。其实,在现实环境中,采集的数据(建模样本)往往是比例失衡的。比如网贷数据,逾期人数的比例是极低的(千分之几的比例)。
面对类别不均衡问题,有很多方法,这些方法大致可以分为两类:
- 基于数据层面的方法
- 基于算法层面的方法
一、基于数据层面的方法
基于数据层面的方法主要包括过采样和欠采样。过采样方法通过增加少数类样本的数量来平衡数据集,例如随机过采样和 SMOTE 算法。欠采样方法通过减少多数类样本的数量来平衡数据集,例如随机欠采样和 Tomek Link 等。
二、基于算法层面的方法
基于算法层面的方法主要包括代价敏感学习和集成学习。代价敏感学习通过调整分类器的损失函数,使其对少数类样本的错误分类具有更高的惩罚。集成学习通过结合多个分类器的预测结果来提高分类性能,例如 Bagging 和 Boosting 等。
这些方法各有优缺点,可以根据具体问题选择合适的方法来解决类别不均衡问题。
接下来我们主要面向基于数据层面的方法。
7.1 类别不平衡数据集基本介绍
在这一节中,当遇到数据类别不平衡的时候,我们该如何处理。在Python中,有Imblearn
包,它就是为处理数据比例失衡而开发的。
安装Imblearn包
pip install imbalanced-learn
第三方包链接:https://pypi.org/project/imbalanced-learn/
Imblearn的使用如下:
一、创造数据集
from sklearn.datasets import make_classification
import matplotlib.pyplot as plt
# 使用make_classification生成样本数据
X, y = make_classification(n_samples=5000, # 样本数量
n_features=2, # 特征个数 = n_informative() + n_redundant + n_repeated
n_informative=2, # 多信息的特征个数
n_redundant=0, # 冗余信息,informative特征的随机线性组合
n_repeated=0, # 重复信息,随机提取n_informative和n_redundant特征
n_classes=3, # 分类类别
n_clusters_per_class=1, # 某一个类别是由几个cluster构成的
weights=[0.01, 0.05, 0.94], # 列表类型,权重比
random_state=0)
print(X.shape) # (5000, 2)
print(y.shape) # (5000,)
注意:
- 特征个数 = 多信息特征个数 + 冗余信息 + 重复信息
weights
参数用来控制不同class的数量权重,如上设置为weights=[0.01, 0.05, 0.94]
,说明3个类别的样本个数是不均衡的!
二、查看各个标签的样本
# 查看各个标签的样本量
from collections import Counter
Counter(y) # Counter({2: 4674, 1: 262, 0: 64})
Counter
是collections
库中的一个函数,它可以用来统计一个 python 列表、字符串、元组等可迭代对象中每个元素出现的次数,并返回一个字典。例如,你可以使用
Counter
来统计列表中的词频。
三、数据集可视化
# 数据集可视化
plt.figure(dpi=300)
plt.scatter(X[:, 0], X[:, 1], c=y)
plt.show()
print(X.shape) # (5000, 2)
print(y.shape) # (5000,)
可以看出样本的三个标签中,1,2的样本量极少,样本失衡。
下面使用imblearn
进行过采样。
为了解决样本数量不均衡的问题,我们需要基于以上数据,进行相应的处理。关于类别不平衡的问题,主要有两种处理方式:
- 过采样方法(Oversampling,OS):增加数量较少那一类样本的数量,使得正负样本比例均衡。
- 欠采样方法(Undersampling,US):减少数量较多那一类样本的数量,使得正负样本比例均衡。
7.2 解决类别不平衡数据方法介绍
7.2.1 过采样方法(Oversampling)
7.2.1.1 什么是过采样方法
对训练集里的少数类进行“过采样”(Oversampling),即增加一些少数类样本使得正、反例数目接近,然后再进行学习。
7.2.1.2 随机过采样方法(Random Oversampling)
随机过采样是在少数类 S min S_{\min} Smin 中随机选择一些样本,然后通过复制所选择的样本生成样本集 E E E,将它们添加到 S min S_{\min} Smin 中来扩大原始数据集,从而得到新的少数类集合 S n e w − m i n S_{\rm new-min} Snew−min。新的数据集 S n e w − m i n = S min + E S_{\rm new-min} = S_{\min} + E Snew−min=Smin+E。
通过代码实现随机过采样方法:
from imblearn.over_sampling import RandomOverSampler
# 使用imblearn进行随机过采样
ros = RandomOverSampler(random_state=0)
X_resampled, y_resampled = ros.fit_resample(X, y)
# 查看结果
Counter(y_resampled) # Counter({2: 4674, 1: 4674, 0: 4674})
# 数据集可视化
plt.figure(dpi=300)
plt.scatter(X_resampled[:, 0], X_resampled[:, 1], c=y_resampled)
plt.show()
和之前未经过采样(原始数据)的对比:
随机过采样方法的优点:
- 简单易实现,能够快速平衡数据集
随机过采样方法的缺点:
- 由于它是通过复制少数类样本来增加少数类样本的数量,因此可能会导致过拟合问题
- 如果数据集中存在噪声或异常值,随机过采样可能会放大这些样本的影响,从而影响模型的预测性能
因此,在使用随机过采样时,需要谨慎选择参数,并结合其他方法来解决类别不均衡问题。
为了解决随机过采样中造成模型过拟合问题,又能保证实现数据集均衡的目的,出现了过采样法代表性的算法 SMOTE 算法。
7.2.1.3 过采样代表性算法:SMOTE
SMOTE 全称是 Synthetic Minority Oversampling,即合成少数类过采样技术。
Synthetic:英[sɪnˈθetɪk]美[sɪnˈθetɪk]
adj. (人工)合成的; 人造的; 综合(型)的;
n. 合成物; 合成纤维(织物); 合成剂;Minority:英[maɪˈnɒrəti]美[maɪˈnɔːrəti]
n. 少数民族(成员),少数群体; 少数(人); 少数派,少数党; 未成年,未到法定年龄,未成年身份;
adj. 少数人的,构成少数的; 少数党的,少数派的; 少数民族的;
SMOTE 算法是对随机过采样方法的一个改进算法,由于随机过采样方法是直接对少数类进行重采用,会使训练集中有很多重复的样本,容易造成产生的模型过拟合问题。而SMOTE算法的基本思想是对每个少数类样本 x i x_i xi,从它的最近邻中随机选择一个样本 x ^ i \hat{x}_i x^i( x ^ i \hat{x}_i x^i 是少数类中的一个样本),然后在 x i x_i xi 和 x ^ i \hat{x}_i x^i 之间的连线上随机选择一点作为新合成的少数类样本。
SMOTE 算法合成新少数类样本的算法描述如下:
- 对于少数类中的每一个样本 x i x_i xi,以欧氏距离为标准计算它到少数类样本集 S min S_{\min} Smin 中所有样本的距离,得到其 k k k 近邻。
- 根据样本不平衡比例,设置一个采样比例,以确定采样倍率 N N N,对于每一个少数类样本 x i x_i xi,从其 k k k 近邻中随机选择若干个样本,假设选择是 x ^ i \hat{x}_i x^i。
- 对于每一个随机选出来的近邻 x ^ i \hat{x}_i x^i,分别与按照如下公式构建新的样本。
x n e w = x i + r a n d ( 0 , 1 ) × ( x ^ i − x i ) x_{\mathrm{new}} = x_i + \mathrm{rand}(0,1) \times (\hat{x}_i - x_i) xnew=xi+rand(0,1)×(x^i−xi)
我们用图文表达的方式,再来描述一下 SMOTE 算法。
一、先随机选定一个少数类样本 x i x_i xi
二、找出这个少数类样本的 k k k 个近邻(假设 k = 5 k=5 k=5),5个近邻已经被圈出
三、随机从这 k k k 个近邻中选出一个样本 x ^ i \hat{x}_i x^i(用绿色圈出来了)
四、在少数类样本 x i x_i xi 和被选中的这个近邻样本 x ^ i \hat{x}_i x^i 之间的连线上,随机找一点。这个点就是人工合成的新的样本点(绿色正号标出)
SMOTE 算法摒弃了随机过采样复制样本的做法,可以防止随机过采样中容易过拟合的问题,实践证明此方法可以提高分类器的性能。
SMOTE 算法的优点:
- 相比于简单的随机过采样方法,SMOTE 算法能够生成更多样化的新样本点,从而避免过拟合问题。
- SMOTE 算法能够有效地平衡数据集,提高分类模型对少数类样本的预测性能。
- SMOTE 算法简单易实现,且计算效率较高。
SMOTE 算法的缺点:SMOTE 过采样方法虽然能够有效地解决类别不均衡问题,但也存在一些缺点。
- SMOTE 算法通过在少数类样本之间插值来合成新的样本点,这可能会导致过拟合
- SMOTE 算法假设少数类样本是连续分布的,但在实际应用中,这个假设并不总是成立
- SMOTE 算法只考虑了少数类样本之间的关系,而忽略了多数类样本对分类边界的影响
因此,在使用 SMOTE 算法时,需要谨慎选择参数,并结合其他方法来解决类别不均衡问题。
Q1:在第四步中,随机找一点,这个点是已经存在的点还是之前没有,SMOTE自己创造的点?
A1:在第四步中,SMOTE 算法会在少数类样本
x
i
x_i
xi 和被选中的近邻样本
x
^
i
\hat{x}_i
x^i 之间的连线上随机找一点。这个点是人工合成的新的样本点,它之前并不存在。这个新的样本点是通过在
x
i
x_i
xi 和
x
^
i
\hat{x}_i
x^i 之间插值得到的。
Q2:SMOTE 算法是通过什么样的插值方法得到人工合成的新的样本点的呢?
A2:SMOTE 算法通过线性插值来合成新的样本点。具体来说,对于每个特征,新样本点的值是在少数类样本
x
i
x_i
xi 和被选中的近邻样本
x
^
i
\hat{x}_i
x^i 之间的连线上随机选取的。例如,如果
x
i
x_i
xi 的某个特征值为
a
a
a,
x
^
i
\hat{x}_i
x^i 的相应特征值为
b
b
b,则新样本点的该特征值为
a
+
(
b
−
a
)
∗
λ
a + (b-a) * \lambda
a+(b−a)∗λ,其中
λ
\lambda
λ 是一个在
[
0
,
1
]
[0,1]
[0,1] 之间随机选取的数。
SMOTE 算法的代码实现:
from imblearn.over_sampling import SMOTE
# SMOTE算法实现过采样
X_resampled, y_resampled = SMOTE().fit_resample(X, y)
Counter(y_resampled) # Counter({2: 4674, 1: 4674, 0: 4674})
# 数据集可视化
plt.figure(dpi=300)
plt.scatter(X_resampled[:, 0], X_resampled[:, 1], c=y_resampled)
plt.show()
和原始数据的对比:
三者对比:
7.2.2 欠采样方法(Undersampling)
7.2.2.1 什么是欠采样方法
直接对训练集中多数类样本进行“欠采样”(Undersampling),即去除一些多数类中的样本使得正例、反例数目接近,然后再进行学习。
欠采样方便不常用,因为数据的收集是很难的,我们一般不会丢弃珍贵的数据
7.2.2.2 随机欠采样方法(Random Undersampling)
随机欠采样顾名思义,即从多数类 S m a j S_{\mathrm{maj}} Smaj 中随机选择一些样样本组成样本集 E E E。然后将样本集 E E E 从 S m a j S_{\mathrm{maj}} Smaj 中移除。新的数据集 S n e w − m a j = S m a j − E S_{\mathrm{new - maj}} = S_{\mathrm{maj}} - E Snew−maj=Smaj−E。
maj:majority英[məˈdʒɒrəti]美[məˈdʒɔːrəti]
n. 大部分,大多数,过半数,大半; 〈英〉(获胜的)票数,(选举中的)多数票(指超出其余各方票数总和的票数); 多数党,多数派; 成年,(成年的)法定年龄,成年身份; 〈军〉少校级别(或职位、军衔);
adj. 多数(人)的,过半数的,大多数的; 多数党的,多数派的;
随机欠采样的代码实现:
from imblearn.under_sampling import RandomUnderSampler
# 随机欠采样
rus = RandomUnderSampler(random_state=0)
X_sampled, y_sampled = rus.fit_resample(X, y)
Counter(y_sampled) # Counter({0: 64, 1: 64, 2: 64})
# 数据集可视化
plt.figure(dpi=300)
plt.scatter(X_sampled[:, 0], X_sampled[:, 1], c=y_sampled)
plt.show()
和原始数据的对比:
随机欠采样方法(Random Undersampling)通过改变多数类样本比例,以达到修改样本分布的目的,从而使样本分布较为均衡。但是这也存在一些问题:
- 对于随机欠采样,由于采样的样本集合要少于原来的样本集合,因此会造成一些信息缺失,即将多数类样本删除有可能会导致分类器(模型)丢失有关多数类的重要信息。
小结:
- 什么是类别不均衡数据?
- 类别不均衡数据是指在分类问题中,不同类别的样本数量相差很大的数据集。例如,在一个二分类问题中,正类样本的数量远远少于负类样本的数量,这就是一个类别不均衡的数据集。类别不均衡数据会导致分类模型在训练过程中对多数类样本过拟合,而忽略少数类样本,从而影响模型的预测性能。
- 解决类别不平衡数据方法
- 过采样(Oversampling)
- 随机过采样(Random Oversampling)
- 原理:随机复制点从而实现增加数据的目的
- 优点:
- 简单易实现,能够快速平衡数据集
- 缺点:
- 数据重复度高
- 容易使得模型复杂度增高,模型过拟合
- 由于它是通过复制少数类样本来增加少数类样本的数量,因此可能会导致过拟合问题
- 如果数据集中存在噪声或异常值,随机过采样可能会放大这些样本的影响,从而影响模型的预测性能
- SMOTE过采样
- 原理:利用k邻近和线性插值创造新的点从而能够有效地解决类别不均衡问题
- 优点:
- 相比于简单的随机过采样方法,SMOTE 算法能够生成更多样化的新样本点,从而避免过拟合问题。
- SMOTE 算法能够有效地平衡数据集,提高分类模型对少数类样本的预测性能。
- SMOTE 算法简单易实现,且计算效率较高。
- 缺点:
- SMOTE 算法通过在少数类样本之间插值来合成新的样本点,这可能会导致过拟合
- SMOTE 算法假设少数类样本是连续分布的,但在实际应用中,这个假设并不总是成立
- SMOTE 算法只考虑了少数类样本之间的关系,而忽略了多数类样本对分类边界的影响
- 因此,在使用 SMOTE 算法时,需要谨慎选择参数,并结合其他方法来解决类别不均衡问题。
- 随机过采样(Random Oversampling)
- 欠采样(Undersampling)
- 随机欠采样(Random Undersampling)
- 原理:随机删除不均衡的样本
- 优点:
- 简单易实现,能够快速减少数据集的大小,从而缩短模型训练时间。
- 缺点:
- 由于它是随机删除多数类样本,因此可能会丢失一些重要信息
- 如果数据集中存在噪声或异常值,随机欠采样可能会保留这些样本,从而影响模型的预测性能
- 因此,在使用随机欠采样时,需要谨慎选择参数,并结合其他方法来解决类别不均衡问题。
- 随机欠采样(Random Undersampling)
- 过采样(Oversampling)
Imblearn
库- 创造数据集:
from sklearn.datasets import make_classification
- 查看各个标签的样本:
from collections import Counter
来的样本集合,因此会造成一些信息缺失,即将多数类样本删除有可能会导致分类器(模型)丢失有关多数类的重要信息。