过采样(Oversampling)是一种处理类别不平衡数据问题的方法,通过增加少数类别样本的数量来平衡数据集,使得各类别的样本数大致相同。过采样的主要目的是改善模型对少数类的预测能力,确保模型能够学习到足够的少数类特征,从而提高整体分类性能。

1. 过采样的基本概念

        在不平衡数据集中,少数类别样本常常不足以让模型有效学习其特征。过采样技术对少数类别样本进行增加,使得其数量达到与多数类别更加接近的水平。这种方法可以通过多种方式实现,以下是一些常见的过采样技术。

2. 常见的过采样方法

2.1 随机过采样(Random Oversampling)

        随机过采样是最简单的过采样技术,通过随机复制少数类别样本来增加它们的数量。这种方法的优点是实现简单,但可能导致过拟合,因为同样的样本被重复使用。

2.2 SMOTE(Synthetic Minority Over-sampling Technique)

        SMOTE 是一种更复杂的过采样方法,通过合成新的少数类样本来增加其数量。具体步骤如下:
        步骤1:对于每个少数类样本,找到其 K 个最近邻样本(通常 K=5)。
        步骤2:在样本和其邻居之间生成新的样本,新的样本通过在特征空间中插值生成,使得新的样本具有一定的变异性。

        SMOTE 生成的新样本保留了少数类的特征,减少了简单复制带来的过拟合风险。

2.3. ADASYN(Adaptive Synthetic Sampling)

        ADASYN 是 SMOTE 的一种变体,通过考虑每个少数类样本的分布情况来动态生成样本。ADASYN 会更加关注边缘样本(即那些被误分类的样本),为这些样本生成更多的合成样本,从而提高模型的鲁棒性。

3. 过采样的优缺点

优点:

        改善模型性能:通过增加少数类样本,模型能更好地学习到这部分数据的特征,通常提高模型的预测能力。
        降低偏见:使得模型在面对不平衡数据时,不会过于偏向于多数类。
        简单易用:一些过采样方法(如随机过采样)实现简单,便于快速尝试。

 缺点

        过拟合风险:随机过采样会复制现有样本,可能导致模型在训练集上过拟合。
        增加计算复杂性:合成样本(如 SMOTE)可能需要时间和计算资源,特别是在大数据集上。
        未解决的根本问题:仅通过增加少数类样本,可能并未解决数据不平衡的根本原因,后续建模时仍需谨慎。

4. 示例代码

4.1 随机过采样示例

下面是一个完整的示例,演示如何使用随机过采样技术来处理不平衡数据集:

import numpy as np  
import matplotlib.pyplot as plt  
from sklearn.datasets import make_classification  
from sklearn.model_selection import train_test_split  
from imblearn.over_sampling import RandomOverSampler  
from collections import Counter  

# 1. 创建一个不平衡的数据集  
X, y = make_classification(n_classes=2, class_sep=2,  
                           weights=[0.9, 0.1], n_informative=3,  
                           n_redundant=1, flip_y=0,  
                           n_features=20, n_clusters_per_class=1,  
                           n_samples=1000, random_state=10)  

# 2. 检查原始数据集的类别分布  
print("原始数据集类别分布:", Counter(y))  

# 3. 划分训练集和测试集  
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)  

# 4. 实现随机过采样  
ros = RandomOverSampler(random_state=42)  
X_resampled, y_resampled = ros.fit_resample(X_train, y_train)  

# 5. 检查过采样后的类别分布  
print("过采样后数据集类别分布:", Counter(y_resampled))  

# 6. 可视化过采样前后的数据分布  
plt.figure(figsize=(12, 6))  

plt.subplot(1, 2, 1)  
plt.scatter(X_train[y_train == 0][:, 0], X_train[y_train == 0][:, 1], label='Class 0', alpha=0.5)  
plt.scatter(X_train[y_train == 1][:, 0], X_train[y_train == 1][:, 1], label='Class 1', alpha=0.5)  
plt.title('原始数据集')  
plt.xlabel('Feature 1')  
plt.ylabel('Feature 2')  
plt.legend()  

plt.subplot(1, 2, 2)  
plt.scatter(X_resampled[y_resampled == 0][:, 0], X_resampled[y_resampled == 0][:, 1], label='Class 0', alpha=0.5)  
plt.scatter(X_resampled[y_resampled == 1][:, 0], X_resampled[y_resampled == 1][:, 1], label='Class 1', alpha=0.5)  
plt.title('过采样后数据集(随机过采样)')  
plt.xlabel('Feature 1')  
plt.ylabel('Feature 2')  
plt.legend()  

plt.show()

 代码说明

        创建不平衡数据集:`make_classification` 函数用于生成一个模拟的不平衡数据集,其中正类(Class 1)只占很小的比例。

        划分训练集和测试集:使用 `train_test_split` 函数将数据划分为训练集和测试集。

        实现随机过采样:创建 `RandomOverSampler` 实例并调用 `fit_resample` 方法以过采样训练集中的少数类样本。

        检查类别分布:使用 `Counter` 检查过采样前后的类别分布。

        可视化数据:通过绘制散点图来比较过采样前后的数据分布,展示如何增加了少数类样本的数量。

4.2 SMOTE示例

以下是使用 Python 中的 `imblearn` 库实现 SMOTE 过采样的示例:

import numpy as np  
import matplotlib.pyplot as plt  
from sklearn.datasets import make_classification  
from sklearn.model_selection import train_test_split  
from imblearn.over_sampling import SMOTE  
from collections import Counter  

# 创建不平衡数据集  
X, y = make_classification(n_classes=2, class_sep=2,  
                           weights=[0.9, 0.1], n_informative=3,  
                           n_redundant=1, flip_y=0,  
                           n_features=20, n_clusters_per_class=1,  
                           n_samples=1000, random_state=10)  

# 检查原始数据集的类别分布  
print("原始数据集类别分布:", Counter(y))  

# 划分训练集和测试集  
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)  

# 使用 SMOTE 进行过采样  
smote = SMOTE(random_state=42)  
X_resampled, y_resampled = smote.fit_resample(X_train, y_train)  

# 检查过采样后的类别分布  
print("过采样后数据集类别分布:", Counter(y_resampled))  

# 可视化过采样前后的数据分布  
plt.figure(figsize=(12, 6))  

plt.subplot(1, 2, 1)  
plt.scatter(X_train[y_train == 0][:, 0], X_train[y_train == 0][:, 1], label='Class 0', alpha=0.5)  
plt.scatter(X_train[y_train == 1][:, 0], X_train[y_train == 1][:, 1], label='Class 1', alpha=0.5)  
plt.title('原始数据集')  
plt.legend()  

plt.subplot(1, 2, 2)  
plt.scatter(X_resampled[y_resampled == 0][:, 0], X_resampled[y_resampled == 0][:, 1], label='Class 0', alpha=0.5)  
plt.scatter(X_resampled[y_resampled == 1][:, 0], X_resampled[y_resampled == 1][:, 1], label='Class 1', alpha=0.5)  
plt.title('过采样后数据集(SMOTE)')  
plt.legend()  

plt.show()

4.2 ADASYN 示例

以下是使用 Python 中的 `imblearn` 库实现 ADASYN 过采样的示例:

import numpy as np  
import matplotlib.pyplot as plt  
from sklearn.datasets import make_classification  
from sklearn.model_selection import train_test_split  
from imblearn.over_sampling import ADASYN  
from collections import Counter  

# 1. 创建一个不平衡的数据集  
X, y = make_classification(n_classes=2, class_sep=2,  
                           weights=[0.9, 0.1], n_informative=3,  
                           n_redundant=1, flip_y=0,  
                           n_features=20, n_clusters_per_class=1,  
                           n_samples=1000, random_state=10)  

# 2. 检查原始数据集的类别分布  
print("原始数据集类别分布:", Counter(y))  

# 3. 划分训练集和测试集  
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)  

# 4. 实现 ADASYN 过采样  
adasyn = ADASYN(random_state=42)  
X_resampled, y_resampled = adasyn.fit_resample(X_train, y_train)  

# 5. 检查过采样后的类别分布  
print("过采样后数据集类别分布:", Counter(y_resampled))  

# 6. 可视化过采样前后的数据分布  
plt.figure(figsize=(12, 6))  

plt.subplot(1, 2, 1)  
plt.scatter(X_train[y_train == 0][:, 0], X_train[y_train == 0][:, 1], label='Class 0', alpha=0.5)  
plt.scatter(X_train[y_train == 1][:, 0], X_train[y_train == 1][:, 1], label='Class 1', alpha=0.5)  
plt.title('原始数据集')  
plt.xlabel('Feature 1')  
plt.ylabel('Feature 2')  
plt.legend()  

plt.subplot(1, 2, 2)  
plt.scatter(X_resampled[y_resampled == 0][:, 0], X_resampled[y_resampled == 0][:, 1], label='Class 0', alpha=0.5)  
plt.scatter(X_resampled[y_resampled == 1][:, 0], X_resampled[y_resampled == 1][:, 1], label='Class 1', alpha=0.5)  
plt.title('过采样后数据集(ADASYN)')  
plt.xlabel('Feature 1')  
plt.ylabel('Feature 2')  
plt.legend()  

plt.show()

 5. 总结

过采样是一种有效的应对类别不平衡问题的技术,能够通过增加少数类样本的数量来改善模型的学习能力和预测性能。选择适合的数据过采样方法,并结合适当的评估指标,可以在实际应用中更好地处理不平衡数据。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐