目录
一、两种类别的样本不均衡【首先阅读文章:一文详解数据不平衡问题】
3.1.1、随机放回、不放回采样 RandomUnderSampler
3.1.2、K-means 原型生成 prototype generation
3.2.2、SMOTE基本算法 ------ SMOTE-Regular
3.2.3、SMOTE改进算法 ------ 强调类边界 Borderline1-Smote、Borderline2-Smote、Svm-Smote
3.2.4、SMOTE改进算法 ------ 强调类区域 Kmeans-Smote
4.2.2、Focal-loss 的两个参数 α 于 γ 的作用
5.1、acc、precision、recall、F1_score 以及对应的宏平均macro 、微平均micro
5.2、ROC曲线、PR曲线 、AUC 值 以及对应的宏平均macro 、微平均micro
0、安装 imblearn 库
安装python imblearn 库:
pip install -i https://mirrors.aliyun.com/pypi/simple/ imblearn
一、两种类别的样本不均衡【首先阅读文章:一文详解数据不平衡问题】
1.1、样本不平衡问题
1、什么是样本不平衡
样本不平衡指的是不同类别样本分布比例相差较大。
2、样本不平衡会造成什么问题
基于统计过程的机器学习、深度学习模型在每一个类别Loss代价等权重时,训练好的模型的参数往往会偏向样本数目多的类
别,样本数目多的类别评估指标性能很好,但样本数目少的类别效果很差,而工程中往往样本数目小的类别是我们重点关注
的对象,这显然是不符需求的。
1.2、两种常见的样本不均衡
1、大数据分布不均衡
整体数据规模很大,而某个类别所占的比例很小。例如:总数量有1000w个样本,2个类别,某个类别只有200w的数据。
2、小数据分布不均衡
正题数据规模较小,某个类别的数目也很少。例如:总数量有100个样本,2个类别,某个类别只有20个数据。
以经验来看:样本比例差距在10倍左右时,应当引起样本不均衡的警觉;当样本比例差距在20倍以上时,必须解决样本不均衡问题。
1.3、数据不平衡经典场景
场景一:
CTR广告预估:广告的点击率,通常只是百分之几,点击的样本占比非常的少,大量的数据是未点击的样本数据。
场景二:
异常检测:比如恶意刷单、黄牛订单、信用卡欺诈、电力窃电、设备故障等,这些数据样本所占的比例通常是整体样本中很少
的一部分。以反欺诈为例,是实体信用卡的欺诈比例一般都在0.1%以内。
二、样本不均衡的处理思想
数据不平衡的问题解决思想:
1. 数据上解决不均衡问题:
① 欠采样:当少数量样本的数量满足模型的训练时,可以对多数样本类别进行欠采样。
② 过采样:当少数量样本的数量不满足模型的训练时,可以对少数样本类型进行过采样。
2. 模型上解决不均衡问题:
③ 类别代价敏感模型:如果模型训练不做处理,那么模型对于每一类别“代价敏感”是等价的,通过带有倚重权重的模型算法,针对
少量样本着重拟合,加强模型对少量样本特征的学习。
④ focal loss 损失函数
3. 评估指标上解决不均衡问题:
3.1 G-mean ( sqrt(正召回率 * 负召回率)
3.2 ROC (横:FPR[1 - 负例的召回率] 纵:TPR[正例召回率])
3.3 PR (横:TPR[正例召回率] 纵:正例精确率)
4. NLP解决不均衡问题
4.1 EDA 简单解决不均衡的问题
4.2 半监督学习解决不均衡的问题
4.2.1 UDA 解决不均衡问题
4.2.2 mix text 解决不均衡问题
三、采样处理样本不平衡
3.1、欠采样处理样本不均衡
当少数量类型的样本满足模型训练的需求时,我们可以对多数量类型样本欠采样。
tip:我们一般不会使用欠采样,数据不均衡通常处理的都是少数量类型的样本数据
# 原始数据准备
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.over_sampling import SMOTE,ADASYN,KMeansSMOTE
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
n_redundant=0, n_repeated=0, n_classes=3,
n_clusters_per_class=1,
weights=[0.01, 0.05, 0.94], # 生成样本的比例权重
class_sep=0.8, random_state=0)
print(Counter(y))
out:
Counter({2: 4674, 1: 262, 0: 64})
print(sorted(Counter(y).items()))
out:
[(0, 64), (1, 262), (2, 4674)]
3.1.1、随机放回、不放回采样 RandomUnderSampler
注意:RandomUnderSampler 获取的样本存在于源数据集种,原型生成(prototype generation)获取的数据是新的样本,可能不存在源数据集中
随机抽样 欠采样的缺点:
随机采样的过程充满着随机性,抽样出现的新数据集不能代表原始数据集样本的分布情况
# imblearn 库
from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler(random_state=42)
X_res, y_res = rus.fit_resample(X, y)
# numpy API
import numpy as np
import random
seed_idx = np.arange(0,100,1)
sample_idx = random.sample(seed_idx,40) # 从 seed_idx 中随机抽取 40 个样本
3.1.2、K-means 原型生成 prototype generation
注意:原型生成(prototype generation)获取的数据是新的样本,可能不存在源数据集中
1、PG【原型生成的执行步骤】:
1)以少数类样本总数出发,确定多数类样本集均衡后的样本数为N 【即从该多数类样本集中生成 N个样本】
2)从一个多数类样本集出发,利用 K-means 算法随机的计算该多数类样本 k 个的中心【这里面的k == N,相当于生成N个簇】
3)使用这N个簇均值而得到N个簇中心点,那么这N个簇中心点将代表源数据集。【簇中心点可以有效代表源数据集样本的分布】
4)重复 2、3两个步骤,均衡其他的多数类样本集
2、PG 欠采样算法相对于 随机抽样 的好处:
① K-means的簇中心相比于随机抽样更能代表 这一个多数量样本集的样本分布情况
② PG算法不会捕捉离群的噪声点,因为这些离群点会被kmeans的簇内均值拉回中心处。
ClusterCentroids 算法是 imblearn 中提供的原型生成算法的一个示例。 该算法通过 KMeans 算法,使得一个多数类样本生
成 N 个簇样本,并使用 N 个簇样本的中心点的坐标替换多数样本的簇。从而达到保留 N 个多数类
样本的目的。
from sklearn.datasets import make_classification
from imblearn.under_sampling import ClusterCentroids # 使用 kmeans 进行过采样
from collections import Counter
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
def plot_scatter(X,y):
data = {}
for idx,label in enumerate(y):
if not label in data:
data[label] = []
else:
data[label].append(X[idx])
for key in data:
tmp1 = np.array(data[key])
plt.scatter(tmp1[:,0],tmp1[:,1])
plt.show()
# 生成分类的数据
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
n_redundant=0, n_repeated=0, n_classes=3,
n_clusters_per_class=1,
weights=[0.01, 0.05, 0.94], # 生成样本的比例权重
class_sep=0.8, random_state=0)
print(Counter(y))
out:
Counter({2: 4674, 1: 262, 0: 64})
plot_scatter(X,y)
cc = ClusterCentroids(random_state=0)
X_resampled, y_resampled = cc.fit_sample(X, y)
plot_scatter(X_resampled,y_resampled)
print(sorted(Counter(y_resampled).items()))
out:
[(0, 64), (1, 64), (2, 64)]
3.2、过采样处理样本不均衡
当少数量类型的样本不满足模型训练的需求时,我们可以对少数量类型样本过采样。
tip:数据不均衡通常处理的都是少数量类型的样本数据
3.2.1、复制少数量样本数据
注意:这是最简单的过采样,缺点是容易过拟合
3.2.2、SMOTE基本算法 ------ SMOTE-Regular
1、smote 算法过采样的过程:
tip:首先先说明第一点,smote会生成新的样本,这与简单复制样本是有本质的区别的
算法过程如下:
smote针对少数量样本,随机选择少数量样本集a中的一个样本Xi,使用KNN计算该样本在a样本集中最近的k个样本,随机选
择k个样本中m个样本【m < k,m由少数样本与多数样本的差异而定,k值则人为定义】,生成样本:
X_new = Xi + λ*(Xj - Xi) # 其中 λ 为 0-1 的随机数
图解如下:
2、smote 基本算法的优点:
smote 线性随机注入噪声生成的新样本来代替 简单的样本复制,可以有效减少过拟合的风险。
2、smote 基本算法的缺点:
主要有的缺点:
① 传统的smote算法对少数样本的噪声点不敏感【传统的smote算法选中少量样本时没有考虑到该样本周围多数量样本
的分布,有可能会放大噪声样本的作用】
② 在特征维度较高的时候,样本分布的空间较为稀疏,我们不能保证生成的新样本具有少数量样本的特征
③ m值可以根据少数量样本与多数量样本的差异比例来定,当时k的大小比较难定
tip:NLP词汇表的维度一般比较高,所以NLP中很少用SMOTE算法
3、SMOTE-Regular 代码:
from sklearn.datasets import make_classification
from imblearn.over_sampling import SMOTE,ADASYN,KMeansSMOTE,BorderlineSMOTE
from collections import Counter
def plot_scatter(X,y):
data = {}
for idx,label in enumerate(y):
if not label in data:
data[label] = []
else:
data[label].append(X[idx])
for key in data:
tmp1 = np.array(data[key])
plt.scatter(tmp1[:,0],tmp1[:,1])
plt.show()
# 生成分类的数据
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
n_redundant=0, n_repeated=0, n_classes=3,
n_clusters_per_class=1,
weights=[0.01, 0.05, 0.94], # 生成样本的比例权重
class_sep=0.8, random_state=0)
print('不均衡的数据量:%s' %Counter(y))
plot_scatter(X,y)
out:
不均衡的数据量:Counter({2: 4674, 1: 262, 0: 64})
sm = SMOTE(random_state=42,n_jobs=-1)
X_res,y_res = sm.fit_resample(X,y)
print('过采样后数据量:%s' %Counter(y_res))
plot_scatter(X_res,y_res)
out:
过采样后数据量:Counter({2: 4674, 1: 4674, 0: 4674})
3.2.3、SMOTE改进算法 ------ 强调类边界 Borderline1-Smote、Borderline2-Smote、Svm-Smote
一、简述Borderline1-smote 执行过程:
1、说到borderline-smote算法的执行过程,首先了解什么是 ‘噪声集’、‘危险集’、‘安全集’的概念?
borderline-smote 是针对少数量样本的smote方法,它根据少数量样本周围多数量样本的分布将样本分为3类:
1.1、安全集safe:样本 KNN 近邻样本中超过一半的样本为该少数量样本
1.2、危险集danger【边界集】:样本 KNN 近邻样本中超过一半的样本为多数量样本
1.3、噪声集noise:样本 KNN 近邻样本中全部为多数量样本
borderline-smote 仅仅对 ‘danger集【边界集】’ 的样本进行 smote。
borderline-smote 的优点:
由上述borderline-smote执行过程可知:
① 该方法不会对‘noise集’的样本进行smote,不会放大噪声数据的影响
② 该方法仅仅对‘边界集’的样本进行smote,充分加强了 [类边界] 的识别能力
Boderline-Smoote 有2种处理方式:
1、Bodeline1-Smote:使用‘danger集’ 与 KNN少数量样本 进行smote
2、Bodeline2-Smote:使用‘danger集’ 与 KNN少数量样本和多数量样本 进行smote【注意:与多数量样本smote生
成的新样本标签仍然是少数量样本的label】
SVM-smote:
SVM-smote 首先用 SVM 分类器找到 支持向量,然后在支持向量的基础上生成新的样本,与Boderline-smote一样,SVM-smote也将少量样本分为 ‘safe’、‘danger’、‘noise’
Boderline-1-smote代码:
from sklearn.datasets import make_classification
from imblearn.over_sampling import SMOTE,ADASYN,KMeansSMOTE,BorderlineSMOTE
from collections import Counter
import numpy as np
import matplotlib.pyplot as plt
def plot_scatter(X,y):
data = {}
for idx,label in enumerate(y):
if not label in data:
data[label] = []
else:
data[label].append(X[idx])
for key in data:
tmp1 = np.array(data[key])
plt.scatter(tmp1[:,0],tmp1[:,1])
plt.show()
# 生成分类的数据
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
n_redundant=0, n_repeated=0, n_classes=3,
n_clusters_per_class=1,
weights=[0.01, 0.05, 0.94], # 生成样本的比例权重
class_sep=0.8, random_state=0)
print('不均衡的数据量:%s' %Counter(y))
plot_scatter(X,y)
sm = BorderlineSMOTE(kind="borderline-1",random_state=42,n_jobs=-1)
X_res,y_res = sm.fit_resample(X,y)
plot_scatter(X_res,y_res)
print('过采样后数据量:%s' %Counter(y_res))
Boderline-2-smote代码:
from sklearn.datasets import make_classification
from imblearn.over_sampling import SMOTE,ADASYN,KMeansSMOTE,BorderlineSMOTE,SVMSMOTE
from collections import Counter
import numpy as np
import matplotlib.pyplot as plt
def plot_scatter(X,y):
data = {}
for idx,label in enumerate(y):
if not label in data:
data[label] = []
else:
data[label].append(X[idx])
for key in data:
tmp1 = np.array(data[key])
plt.scatter(tmp1[:,0],tmp1[:,1])
plt.show()
# 生成分类的数据
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
n_redundant=0, n_repeated=0, n_classes=3,
n_clusters_per_class=1,
weights=[0.01, 0.05, 0.94], # 生成样本的比例权重
class_sep=0.8, random_state=0)
print('不均衡的数据量:%s' %Counter(y))
plot_scatter(X,y)
sm = BorderlineSMOTE(kind="borderline-2",random_state=42,n_jobs=-1)
X_res,y_res = sm.fit_resample(X,y)
plot_scatter(X_res,y_res)
print('过采样后数据量:%s' %Counter(y_res))
svm-smote代码:
from sklearn.datasets import make_classification
from imblearn.over_sampling import SMOTE,ADASYN,KMeansSMOTE,BorderlineSMOTE,SVMSMOTE
from collections import Counter
import numpy as np
import matplotlib.pyplot as plt
def plot_scatter(X,y):
data = {}
for idx,label in enumerate(y):
if not label in data:
data[label] = []
else:
data[label].append(X[idx])
for key in data:
tmp1 = np.array(data[key])
plt.scatter(tmp1[:,0],tmp1[:,1])
plt.show()
# 生成分类的数据
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
n_redundant=0, n_repeated=0, n_classes=3,
n_clusters_per_class=1,
weights=[0.01, 0.05, 0.94], # 生成样本的比例权重
class_sep=0.8, random_state=0)
print('不均衡的数据量:%s' %Counter(y))
plot_scatter(X,y)
sm = SVMSMOTE(random_state=42,n_jobs=-1)
X_res,y_res = sm.fit_resample(X,y)
plot_scatter(X_res,y_res)
print('过采样后数据量:%s' %Counter(y_res))
3.2.4、SMOTE改进算法 ------ 强调类区域 Kmeans-Smote
Kmeans-Smote算法执行步骤:
总体来说分为三个步骤:kmeans --- 簇过滤 ---- smote
1、kmeans 步骤:输入所有的数据集进行Kmeans,该过程不考虑类别
2、簇过滤 步骤:获得每个簇的簇标签,过滤掉标签为多数类别label的簇【其实就是选择那些少数量样本比例较高的簇】
3、smote 步骤:对剩下的簇中的样本进行 smote
K-means smote 的特点:
簇过滤的阶段其实是选择少数量样本集密度较高的区域,对该区域进行smote 其实是强调 [类区域] 的做法,这一点
不同于borderline-smote
Kmeans-Smote代码:
from sklearn.datasets import make_classification
from imblearn.over_sampling import SMOTE,ADASYN,KMeansSMOTE,BorderlineSMOTE,SVMSMOTE
from collections import Counter
import numpy as np
import matplotlib.pyplot as plt
def plot_scatter(X,y):
data = {}
for idx,label in enumerate(y):
if not label in data:
data[label] = []
else:
data[label].append(X[idx])
for key in data:
tmp1 = np.array(data[key])
plt.scatter(tmp1[:,0],tmp1[:,1])
plt.show()
# 生成分类的数据
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
n_redundant=0, n_repeated=0, n_classes=3,
n_clusters_per_class=1,
weights=[0.01, 0.05, 0.94], # 生成样本的比例权重
class_sep=0.8, random_state=0)
print('不均衡的数据量:%s' %Counter(y))
plot_scatter(X,y)
sm = KMeansSMOTE(random_state=42,n_jobs=-1,k_neighbors=5,kmeans_estimator=50) # kmeans_estimator 簇的个数
X_res,y_res = sm.fit_resample(X,y)
plot_scatter(X_res,y_res)
print('过采样后数据量:%s' %Counter(y_res))
3.2.5、几种SMOTE过采样效果总结
1、传统的smote
1.1、优点【相对于随机复制样本】:引入了随机噪声生成了新的样本,缓解了过拟合的风险
1.2、缺点:
① 没有考虑到少数量样本周围多数量样本的分布,容易加大噪声点的影响
② 特征维度高时,特征空间稀疏,不能保证生成的新样本可以代表少数量样本的特征
③ KNN的K值难以确定
2、强调类边界的smote
优点:考虑了少数量样本周围多数量样本的分布,不增强噪声点,只增强边界‘danger集’
2.1、borderline1-smote
2.2、borderline2-smote
2.3、SVM-smote
3、强调类区域的smote
优点:考虑了少数量样本周围多数量样本的分布,不增强噪声点,增强少数类样本类区域
3.1、k-means smote
四、模型算法处理样本不均衡
1、模型算法解决数据不平衡的问题的思想:
通过在模型算法引入 权重倚重,用来调节数据不均衡的各种类别样本对模型的作用效果。
2、最常见的几种方式:
cost-sensitive:
代表:meta-cost
focal-loss:
4.1、Meta-Cost【cost sensitive】
github代码:meta-cost 代码 python
cost sensitive 代价敏感矩阵的定义:Cost Sensitive 算法;通过增加少数量样本代价损失来加强模型对少量样本特征的学习
cost sensitive论文:代价铭感 Cost Sensitive 论文
代价敏感引入模型的方法:
1、通过修改模型预测阈值的方式增加模型对少数类别样本重视。
2、利用集成学习的思想更改模型的参数权重,代表 meta cost
Meta Cost 的步骤:
(1)利用集成学习的思想,在原始数据中m次采样,训练m个模型
(2)根据m个模型,计算预测样本属于 各个类别概率 p(y= 0,1,2,... j|x) 【采用m个模型求均值的方式】
(3)根据上述类别概率分布 与 类别代价分布矩阵 使得该样本的代价损失最小,更改样本的类标签
(4)训练修改过的数据集,得到新的模型
4.2、Focal-loss
阅读文章:【二分问题focal-loss解释】【多分类问题focal-loss代码】
github代码:focal-loss for NER多分类、Focal-loss 多分类代码
4.2.1、Focal-loss 与 CE交叉熵损失的关系
以二分类为例【多分类的softmax是一样的,因为不管是二分类或多分类,- log p 只计算 真实label所对应位置的交叉熵,而其他位置值为0】
1、 CE交叉熵表示方式
2、将 p 与 1-p 用函数 p(t) 表示,p(t) 表示样本在每一个类别对应位置预测概率,多分类时是样本预测softmax的概率值
3、CE 交叉熵最终表示为
4、Focal Loss 在 CE 的基础上添加 alpha 与 γ 参数
5、最后得出 Focal Loss 与 CE 交叉熵函数的关系
focal_loss = (alpha * (1-p(t))**gamma * ce_loss).mean() # 多分类的时候,p(t)是样本softmax的概率值
4.2.2、Focal-loss 的两个参数 α 于 γ 的作用
1、数据不均衡的数据有两个主要的问题:
① 每一个类别样本数量差异性太大
② 样本中存在容易分类样本与困难分类样本【容易分类样本对模型更新往往没有作用,γ参数可以减低容易样本对loss的贡献权重】
2、focal loss 中 alpha 与 γ参数
alpha参数:可以平衡样本类别比例不均衡的问题。以二分类为例,y = 1是,使用alpha 平衡,y = 0时,使用 1- alpha 平衡;但
实际上作用不大,因此 代码中不管是二分类还是softmax多分类,alpha 统统使用一个值即可
γ参数:为了解决 容易样本与困难样本 的问题。
- 用一个例子说明 Focal-loss 中 alpha 与 γ 使用方法与意义
1、假设:alpha = 0.25,γ = 2,容易样本预测概率为 p1 = 0.95,困难样本预测概率为 p2 = 0.1
计算 CE 与 focal loss:
CE:
容易样本: -log 0.95
困难样本: -log 0.1
focal:
容易样本: (1 - alpha) * (1 - 0.95)**γ * -log 0.95 = 0.75 * 0.0025 * -log 0.95
困难样本: alpha * (1 - 0.1)**γ * -log 0.95 = 0.25 * 0.81 * -log 0.1
tip:
容易样本使用较大的 1 - alpha 可以理解为不让 容易样本loss权重过于小,而困难样本使用 alpha
4.2.3、Focal-loss 多分类代码
大致步骤如下:
def focacl_loss(output,target,reduction="none",alpha=1.0 , gamma=2.0):
"""
********** 给定模型前向传播的输出 log output:[batch,num_class]与真实值target:[batch,],计算loss误差 ************
1. 仅仅在训练的时候使用 focal_loss ,验证时不使用 focal_loss
2. 由于focal_loss乘以一个小于1的数,整体比 传统的CE要小很多,所以再加入focal_loss时可以适当增加学习率
"""
ce_loss = F.nll_loss(input = output,target = target, reduction=reduction) # ce_loss dim: [B,]
pt = torch.exp(-ce_loss) # pt dim: [B,]
# 构建 focal_loss
focalloss = (alpha * (1.0 - pt)**gamma * ce_loss).mean()
return focalloss
五、评价指标【一文详解数据不平衡问题、评估指标2】
5.1、acc、precision、recall、F1_score 以及对应的宏平均macro 、微平均micro
宏平均macro F1特点:不受样本分布不平衡的影响,但会受到 高 recall 与 高 precision 值得影响
微平均micro F1 特点:容易受到样本不平衡的印象,当预测类别均属于训练类别时,micro 的4个指标的值恒相等。
from sklearn import metrics
y_test = [1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4]
y_predict = [1, 1, 1, 3, 3, 2, 2, 3, 3, 3, 4, 3, 4, 3]
print('准确率:', metrics.accuracy_score(y_test, y_predict)) #预测准确率输出
print('宏平均精确率:',metrics.precision_score(y_test,y_predict,average='macro')) #预测宏平均精确率输出
print('微平均精确率:', metrics.precision_score(y_test, y_predict, average='micro')) #预测微平均精确率输出
print('加权平均精确率:', metrics.precision_score(y_test, y_predict, average='weighted')) #预测加权平均精确率输出
print('宏平均召回率:',metrics.recall_score(y_test,y_predict,average='macro'))#预测宏平均召回率输出
print('微平均召回率:',metrics.recall_score(y_test,y_predict,average='micro'))#预测微平均召回率输出
print('加权平均召回率:',metrics.recall_score(y_test,y_predict,average='micro'))#预测加权平均召回率输出
print('宏平均F1-score:',metrics.f1_score(y_test,y_predict,labels=[1,2,3,4],average='macro'))#预测宏平均f1-score输出
print('微平均F1-score:',metrics.f1_score(y_test,y_predict,labels=[1,2,3,4],average='micro'))#预测微平均f1-score输出
print('加权平均F1-score:',metrics.f1_score(y_test,y_predict,labels=[1,2,3,4],average='weighted'))#预测加权平均f1-score输出
print('混淆矩阵输出:\n',metrics.confusion_matrix(y_test,y_predict,labels=[1,2,3,4]))#混淆矩阵输出
print('分类报告:\n', metrics.classification_report(y_test, y_predict,labels=[1,2,3,4]))#分类报告输出
输出:
准确率: 0.571428571429
宏平均精确率: 0.696428571429
微平均精确率: 0.571428571429
加权平均精确率: 0.775510204082
宏平均召回率: 0.566666666667
微平均召回率: 0.571428571429
加权平均召回率: 0.571428571429
宏平均F1-score: 0.579166666667
微平均F1-score: 0.571428571429
加权平均F1-score: 0.615476190476
混淆矩阵输出:
[[3 0 2 0]
[0 2 2 0]
[0 0 2 1]
[0 0 1 1]]
分类报告:
precision recall f1-score support
1 1.00 0.60 0.75 5
2 1.00 0.50 0.67 4
3 0.29 0.67 0.40 3
4 0.50 0.50 0.50 2
5.2、ROC曲线、PR曲线 、AUC 值 以及对应的宏平均macro 、微平均micro
5.2.1、二分类 ROC 曲线与AUC值
5.2.2、多分类的ROC曲线与AUC值
评估指标【多分类ROC曲线与macro_roc与micro_roc曲线与AUC值】
5.2.3、ROC曲线、PR曲线的区别 以及使用场景?
1、ROC曲线与PR曲线的区别:
① ROC曲线基于 TPR 与 FPR,即共同参考了正例与负例,相对比较均衡,而PR曲线完全使用正例的precision与recall
PR曲线更加关注于正例
② 当正负例数据比较均衡时,ROC曲线与PR评估效果相差不多,若突然加入大量的负例数据时,ROC曲线的波动变化比较平稳,而
PR变化及其不稳定;
但是需要注意的是,大量负例增加会导致FPR值不会大幅度变化,从而导致ROC会给定一个过于乐观的值。
2、ROC曲线与PR曲线的使用场景:
① 不考虑不同类别样本分布,综合评估正负例分类器的整体性能可以用ROC曲线;考虑不同类别样本分布对分类器性能影响使用PR曲线
② 模型评估指标聚焦于正例时使用PR曲线
② 样本分布不均衡的情况下,ROC曲线通常会给定一个过于‘乐观’的值,所以这时大多数情况使用 PR 曲线。
最后,根据一个具体的业务场景,在曲线中选取一个合适的 recal precision F1_socre 的指标,去调整模型的阈值,可以得到该
业务场景合适的模型
- ROC曲线场景举例
- PR曲线场景举例
场景:假设对用户的UGC数据进行分类,假设现在有涉政、涉黄、违禁买卖、暴恐、广告五个标签,场景为多
标签多分类问题,使用sigmiod进行多标签多分类
场景特点:
1. 多标签多分类,使用sigmiod进行多次二分类任务
2. 数据存在不均衡问题,且少数量样本为正例样本,我们的注意力主要在正例样本上
观察上图:
涉政标签的3个算法模型的PR曲线如上图所示,那么怎么选择合适的模型呢?怎么选择合适的模型阈值呢?
模型与模型阈值的选择方法:
模型选择:涉政业务场景要求高recall,可以牺牲一定的precision,因此C模型是比较合适的模型
阈值的选择:根据涉政的业务场景,根据制定的recall与precision在PR曲线上找到合适的模型阈值
5.3、样本不均衡的评估指标 G-mean
略
六、NLP场景中数据增强
6.1、EDA简单的样本增强
1、EDA样本数据增强的操作:随机 替换、插入、交换、删除 四个操作
① 从句子中随机选取 n 个不属于停用词集的单词,并随机选择同义词替换。
② 随机的找出句子中某个不属于停用词集的词,并求出其随机的同义词,将该同义词插入句子的一个随机位置,重复 n 次。
③ 随机的选择句中两个单词并交换他们的位置,重复 n 次
④ 以 p 的概率,随机的移除句子中的单词
- EDA for english? EDA for chinese ? github 代码:
6.2、UDA半监督一致性数据增强
UDA论文:Unsupervised Data Augmentation for Consistency Training
UDA github 代码:
1、Unsupervised Data Augmentation 【github code】
2、UDA pytorch with Bert 【文章地址:Google无监督数据增强方法UDA在文本分类上的实验】
论文解析:
2、半监督学习:Unsupervised Data Augmentation
6.2.1、UDA 一致性训练的图解
6.2.2、UDA训练损失函数的定义
6.2.3、UDA训练过程中‘ 退火训练 ’ TSA
参考上面的文章
七、NLP实际项目中数据不均衡的解决步骤
第一步:寻找更多的标注数据,这是最终极的解决方案
第二步:通常情况下我们的数据都是不足的,这个时候可以先做一个baseline模型得出结果,并且可以分析数据类别的分布情况,如下图:
第三步:如果我们使用的模型是bert家族,那么我们就可以使用UDA进行半监督的数据增强,而且可以魔改loss损失函数。如果模型不是bert家族,那可能会使用EDA这种数据增强的方法,需要注意的是EDA效果并非都是正向的。NLP中一般不会使用SMOTE采样,这是因为NLP项目特征维度较高,SMOTE未必有较好的效果。
第四步:模型训练完后,如果是sigmoid多分类问题,对于数据不均衡的场景,我们通常使用PR曲线关注正例,通过业务需求的recall与precision使用PR曲线来选取合适的模型,再通过业务需求的recall与precision使用PR曲线选取合适的模型阈值。