机器学习:类别不平衡数据优化-过采样
过采样(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. 总结
过采样是一种有效的应对类别不平衡问题的技术,能够通过增加少数类样本的数量来改善模型的学习能力和预测性能。选择适合的数据过采样方法,并结合适当的评估指标,可以在实际应用中更好地处理不平衡数据。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)