原文:
www.kdnuggets.com/2023/01/7-smote-variations-oversampling.html
作者提供的图片
不平衡数据集是数据科学中的一个问题。这个问题发生是因为不平衡通常会导致建模性能问题。为了缓解不平衡问题,我们可以使用过采样方法。过采样是对少数类数据进行重采样以平衡数据。
1. 谷歌网络安全证书 - 快速进入网络安全职业生涯。
2. 谷歌数据分析专业证书 - 提升你的数据分析技能
3. 谷歌 IT 支持专业证书 - 支持你的组织在 IT 方面
过采样有许多方法,其中之一是使用 SMOTE1。让我们深入了解多种 SMOTE 实现,以进一步了解过采样技术。
在继续之前,我们将使用来自 Kaggle2 的流失数据集来表示不平衡数据集。数据集的目标是“exited”变量,我们将观察 SMOTE 如何根据少数类目标进行过采样。
import pandas as pd
df = pd.read_csv('churn.csv')
df['Exited'].value_counts().plot(kind = 'bar', color = ['blue', 'red'])
我们可以看到流失数据集面临不平衡问题。让我们尝试使用 SMOTE 对数据进行过采样。
SMOTE 通常用于通过生成人工或合成数据来过采样连续数据以解决机器学习问题。我们使用连续数据是因为开发样本的模型只接受连续数据 1。
在我们的示例中,我们将使用数据集中的两个连续变量:“EstimatedSalary”和“Age”。让我们看看这两个变量与数据目标的分布情况。
import seaborn as sns
sns.scatterplot(data =df, x ='EstimatedSalary', y = 'Age', hue = 'Exited')
我们可以看到少数类大多分布在图的中间部分。让我们尝试用 SMOTE 进行过采样,看看差异如何形成。为了便于 SMOTE 过采样,我们将使用 imblearn Python 包。
pip install imblearn
使用 imblearn,我们将对流失数据进行过采样。
from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state = 42)
X, y = smote.fit_resample(df[['EstimatedSalary', 'Age']], df['Exited'])
df_smote = pd.DataFrame(X, columns = ['EstimatedSalary', 'Age'])
df_smote['Exited'] = y
Imblearn 包基于 scikit-learn API,使用起来很方便。在上述示例中,我们已经使用 SMOTE 对数据集进行了过采样。让我们看看“Exited”变量的分布。
df_smote['Exited'].value_counts().plot(kind = 'bar', color = ['blue', 'red'])
从上述输出中可以看出,目标变量现在具有类似的比例。让我们看看连续变量在新的 SMOTE 过采样数据中的分布情况。
import matplotlib.pyplot as plt
sns.scatterplot(data = df_smote, x ='EstimatedSalary', y = 'Age', hue = 'Exited')
plt.title('SMOTE')
上面的图显示了少数类数据现在比我们过采样前的分布更广泛了。如果我们更详细地查看输出,可以看到少数类数据的分布仍然接近核心,并且比之前扩展得更广。这是因为样本是基于邻居模型的,该模型根据最近邻估算样本。
SMOTE-NC 是针对分类数据的 SMOTE。如上所述,SMOTE 只适用于连续数据。
为什么我们不直接将分类变量编码为连续变量呢?
问题在于 SMOTE 基于最近邻创建样本。如果你对分类数据进行编码,比如‘HasCrCard’变量,它包含类 0 和 1,样本结果可能是 0.8 或 0.34 等。
从数据的角度来看,这没有意义。这就是为什么我们可以使用 SMOTE-NC 来确保分类数据的过采样是合理的。
让我们用示例数据试试。对于这个特定的样本,我们会使用变量‘HasCrCard’和‘Age’。首先,我想展示初始的‘HasCrCard’变量分布。
pd.crosstab(df['HasCrCard'], df['Exited'])
然后让我们看看使用 SMOTE-NC 进行过采样后的差异。
from imblearn.over_sampling import SMOTENC
smotenc = SMOTENC([1],random_state = 42)
X_os_nc, y_os_nc = smotenc.fit_resample(df[['Age', 'HasCrCard']], df['Exited'])
注意上面的代码中,分类变量的位置是基于 DataFrame 中变量的位置。
让我们看看‘HasCrCard’在过采样后的分布。
pd.crosstab(X_os_nc['HasCrCard'], y_os_nc)
可以看到,数据的过采样几乎保持了相同的比例。你可以尝试用其他分类变量看看 SMOTE-NC 的效果。
Borderline-SMOTE 是一种基于分类器边界的 SMOTE。Borderline-SMOTE 会对接近分类器边界的数据进行过采样。这是因为接近边界的样本更容易被误分类,因此更重要需要进行过采样。
Borderline-SMOTE 有两种类型:Borderline-SMOTE1 和 Borderline-SMOTE2。它们的区别在于,Borderline-SMOTE1 会对接近边界的两个类都进行过采样,而 Borderline-SMOTE2 只会对少数类进行过采样。
我们来尝试一下使用 Borderline-SMOTE 与一个数据集示例。
from imblearn.over_sampling import BorderlineSMOTE
bsmote = BorderlineSMOTE(random_state = 42, kind = 'borderline-1')
X_bd, y_bd = bsmote.fit_resample(df[['EstimatedSalary', 'Age']], df['Exited'])
df_bd = pd.DataFrame(X_bd, columns = ['EstimatedSalary', 'Age'])
df_bd['Exited'] = y_bd
让我们看看在启动 Borderline-SMOTE 后,数据的分布情况。
sns.scatterplot(data = df_bd, x ='EstimatedSalary', y = 'Age', hue = 'Exited')
plt.title('Borderline-SMOTE')
如果我们查看上述结果,输出与 SMOTE 输出类似,但 Borderline-SMOTE 的过采样结果稍微接近于边界。
SMOTE-Tomek 使用了 SMOTE 和欠采样 Tomek 链接的组合。Tomek 链接是一种清理数据的方法,用于去除与少数类重叠的多数类。
让我们尝试对样本数据集应用 SMOTE-TOMEK。
from imblearn.combine import SMOTETomek
s_tomek = SMOTETomek(random_state = 42)
X_st, y_st = s_tomek.fit_resample(df[['EstimatedSalary', 'Age']], df['Exited'])
df_st = pd.DataFrame(X_st, columns = ['EstimatedSalary', 'Age'])
df_st['Exited'] = y_st
让我们看看使用 SMOTE-Tomek 后的目标变量结果。
df_st['Exited'].value_counts().plot(kind = 'bar', color = ['blue', 'red'])
'Exited' 类别 0 的数量现在约为 6000,相比之下,原始数据集接近 8000。这是因为 SMOTE-Tomek 在进行过采样少数类的同时,对类别 0 进行了欠采样。
让我们看看在使用 SMOTE-Tomek 进行过采样后的数据分布。
sns.scatterplot(data = df_st, x ='EstimatedSalary', y = 'Age', hue = 'Exited')
plt.title('SMOTE-Tomek')
结果分布仍然类似于之前。但如果我们深入了解,距离数据越远,过采样的少数类样本越少。
类似于 SMOTE-Tomek,SMOTE-ENN(编辑最近邻)结合了过采样和欠采样。SMOTE 进行了过采样,而 ENN 进行了欠采样。
编辑最近邻是一种在原始和样本结果数据集中移除多数类样本的方法,当最近邻少数类样本将其错误分类时。它会移除接近边界的多数类样本,这些样本被错误分类了。
让我们尝试使用 SMOTE-ENN 与示例数据集。
from imblearn.combine import SMOTEENN
s_enn = SMOTEENN(random_state=42)
X_se, y_se = s_enn.fit_resample(df[['EstimatedSalary', 'Age']], df['Exited'])
df_se = pd.DataFrame(X_se, columns = ['EstimatedSalary', 'Age'])
df_se['Exited'] = y_se
让我们看看 SMOTE-ENN 的结果。首先,我们会查看目标变量。
df_se['Exited'].value_counts().plot(kind = 'bar', color = ['blue', 'red'])
与 SMOTE-Tomek 相比,SMOTE-ENN 的欠采样过程严格得多。从上面的结果来看,超过一半的原始'Exited' 类别 0 被欠采样,仅少数类有所略微增加。
让我们看看应用 SMOTE-ENN 后的数据分布。
sns.scatterplot(data = df_se, x ='EstimatedSalary', y = 'Age', hue = 'Exited')
plt.title('SMOTE-ENN')
类别之间的数据分布比之前大得多。然而,我们需要记住,结果数据的数量较少。
SMOTE-CUT 或 SMOTE-聚类欠采样技术结合了过采样、聚类和欠采样。
SMOTE-CUT 实现了使用 SMOTE 进行过采样,聚类原始数据和结果,并从簇中移除多数类样本。
SMOTE-CUT 聚类基于 EM(期望最大化)算法,该算法为每个数据分配属于各个簇的概率。聚类结果会引导算法进行过采样或欠采样,从而使数据集分布变得平衡。
让我们尝试使用数据集示例。对于这个例子,我们将使用 crucio Python 包。
pip install crucio
使用 crucio 包,我们通过以下代码对数据集进行过采样。
from crucio import SCUT
df_sample = df[['EstimatedSalary', 'Age', 'Exited']].copy()
scut = SCUT()
df_scut= scut.balance(df_sample, 'Exited')
让我们看看目标数据分布。
df_scut['Exited'].value_counts().plot(kind = 'bar', color = ['blue', 'red'])
尽管欠采样过程相当严格,'Exited' 类别的分布仍然相等。许多'Exited' 类别 0 的样本由于欠采样而被移除。
让我们看看实施 SMOTE-CUT 后的数据分布。
sns.scatterplot(data = df_scut, x ='EstimatedSalary', y = 'Age', hue = 'Exited')
plt.title('SMOTE-CUT')
数据分布更分散,但仍然少于 SMOTE-ENN。
ADASYN 或自适应合成采样是一种 SMOTE,它试图根据数据密度对少数数据进行过采样。ADASYN 会为每个少数样本分配一个加权分布,并优先对更难学习的少数样本进行过采样 7。
让我们尝试用示例数据集进行 ADASYN。
from crucio import ADASYN
df_sample = df[['EstimatedSalary', 'Age', 'Exited']].copy()
ada = ADASYN()
df_ada= ada.balance(df_sample, 'Exited')
让我们看看目标分布结果。
df_ada['Exited'].value_counts().plot(kind = 'bar', color = ['blue', 'red'])
由于 ADASYN 会关注那些更难学习或密度较低的数据,因此其过采样结果低于其他方法。
让我们看看数据的分布情况。
sns.scatterplot(data = df_ada, x ='EstimatedSalary', y = 'Age', hue = 'Exited')
plt.title('ADASYN')
从上面的图像中可以看出,数据的分布更接近核心,但也接近低密度的少数数据。
数据不平衡是数据领域中的一个问题。缓解不平衡问题的一种方法是通过 SMOTE 对数据集进行过采样。随着研究的发展,已经创建了许多我们可以使用的 SMOTE 方法。
在这篇文章中,我们将探讨 7 种不同的 SMOTE 技术,包括
-
SMOTE
-
SMOTE-NC
-
边界线-SMOTE
-
SMOTE-TOMEK
-
SMOTE-ENN
-
SMOTE-CUT
-
ADASYN
-
SMOTE: 合成少数类过采样技术 - Arxiv.org
-
客户流失建模数据集来自 Kaggle,许可证为 CC0: 公开领域。
-
边界线-SMOTE: 不平衡数据集学习中的一种新过采样方法 - Semanticscholar.org
-
平衡自动标注关键词的训练数据:一个案例研究 - inf.ufrgs.br
-
改进慢性心力衰竭不良结果的风险识别:使用 SMOTE+ENN 和机器学习 - dovepress.com
-
使用 Crucio SMOTE 和聚类欠采样技术处理不平衡数据集 - sigmoid.ai
-
ADASYN: 自适应合成采样方法用于不平衡学习 - ResearchGate
**Cornellius Yudha Wijaya**是一名数据科学助理经理和数据撰稿人。在全职工作于印尼安联保险期间,他喜欢通过社交媒体和写作媒体分享 Python 和数据技巧。