imbalanced-learn欠采样技术全解析

imbalanced-learn欠采样技术全解析

【免费下载链接】imbalanced-learn 【免费下载链接】imbalanced-learn 项目地址: https://gitcode.com/gh_mirrors/imb/imbalanced-learn

本文全面解析了imbalanced-learn库中的多种欠采样技术,包括随机欠采样(RandomUnderSampler)、基于近邻的NearMiss系列算法、Tomek Links与Condensed Nearest Neighbour方法,以及编辑最近邻(ENN)和邻域清理规则(NCR)。文章详细介绍了每种算法的核心原理、参数配置、实现机制和适用场景,为处理类别不平衡问题提供了全面的技术指南和实践建议。

随机欠采样(RandomUnderSampler)策略

随机欠采样(RandomUnderSampler)是处理类别不平衡数据最简单直观的方法之一。该方法通过从多数类中随机删除样本来平衡数据集,使得各个类别的样本数量达到相对均衡的状态。作为imbalanced-learn库中最基础的欠采样技术,RandomUnderSampler以其简单高效的特点成为处理类别不平衡问题的首选方法。

核心原理与工作机制

RandomUnderSampler的工作原理基于概率抽样理论,其核心思想是通过随机选择的方式减少多数类样本的数量。该算法的工作流程可以通过以下流程图清晰地展示:

mermaid

参数配置详解

RandomUnderSampler提供了灵活的配置选项,让用户可以根据具体需求调整采样行为:

参数名称类型默认值描述
sampling_strategystr/dict'auto'采样策略,控制各个类别的目标样本数量
random_stateint/RandomStateNone随机数生成器种子,确保结果可重现
replacementboolFalse是否使用有放回抽样

sampling_strategy参数详解

  • 'auto':自动将多数类采样到与少数类相同数量
  • 'majority':仅对多数类进行欠采样
  • 'not minority':对所有非少数类进行欠采样
  • 'all':对所有类进行重采样
  • 字典:自定义每个类别的目标样本数量

代码实现示例

下面通过一个完整的代码示例展示RandomUnderSampler的使用方法:

import numpy as np
from collections import Counter
from sklearn.datasets import make_classification
from imblearn.under_sampling import RandomUnderSampler

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

print('原始数据集分布:', Counter(y))

# 初始化RandomUnderSampler
rus = RandomUnderSampler(
    sampling_strategy='auto',  # 自动平衡到少数类数量
    random_state=42,           # 确保结果可重现
    replacement=False          # 无放回抽样
)

# 执行欠采样
X_resampled, y_resampled = rus.fit_resample(X, y)

print('重采样后数据集分布:', Counter(y_resampled))
print('选择的样本索引:', rus.sample_indices_[:10])  # 显示前10个被选中的样本索引

采样策略对比分析

不同的sampling_strategy设置会产生不同的采样效果,下表展示了各种策略的对比:

策略类型目标类别采样效果适用场景
auto多数类 → 少数类完全平衡标准的二分类问题
majority仅多数类减少多数类需要保留所有少数类样本
not minority所有非少数类部分平衡多分类问题中的主要类别
all所有类别自定义平衡需要精确控制每个类别的样本数量

算法优势与局限性

优势

  1. 简单高效:算法实现简单,计算复杂度低
  2. 内存友好:减少数据集大小,降低内存需求
  3. 训练加速:较小的数据集意味着更快的训练速度
  4. 广泛适用:支持多分类问题和各种数据类型

局限性

  1. 信息损失:随机删除可能丢失重要样本信息
  2. 过拟合风险:如果删除的样本包含重要特征,可能导致模型欠拟合
  3. 不稳定性:不同的随机种子可能产生不同的结果

实际应用场景

RandomUnderSampler在以下场景中特别有用:

  1. 大规模数据集:当原始数据集非常大时,欠采样可以显著减少计算资源需求
  2. 探索性分析:在数据探索阶段快速获得平衡的数据视图
  3. 基准测试:作为其他复杂采样方法的性能对比基准
  4. 实时系统:需要快速响应的在线学习系统

性能优化建议

为了获得最佳的采样效果,建议遵循以下最佳实践:

  1. 设置随机种子:使用random_state参数确保实验的可重现性
  2. 多次采样:进行多次随机采样并评估结果的稳定性
  3. 结合交叉验证:在交叉验证过程中应用采样,避免数据泄露
  4. 监控信息损失:通过特征重要性分析评估采样对模型的影响

与其他采样方法的对比

RandomUnderSampler作为最简单的欠采样方法,与其他方法相比具有独特的定位:

mermaid

通过合理配置参数和结合业务场景,RandomUnderSampler能够为类别不平衡问题提供一个简单而有效的解决方案。虽然它可能不是所有情况下的最优选择,但其简洁性和高效性使其成为处理不平衡数据的重要工具之一。

基于近邻的欠采样方法:NearMiss系列

在处理类别不平衡数据集时,NearMiss系列算法提供了一种基于距离度量的智能欠采样方法。与简单的随机欠采样不同,NearMiss通过分析样本间的空间关系,选择性地保留那些与少数类样本具有特定距离关系的大多数类样本,从而在减少多数类样本数量的同时保持数据分布的完整性。

NearMiss算法原理

NearMiss算法基于k近邻思想,通过计算多数类样本与少数类样本之间的距离关系来进行样本选择。该系列包含三个不同版本,每个版本采用不同的选择策略:

mermaid

NearMiss-1:最近邻平均距离最小化

NearMiss-1选择那些与少数类样本平均距离最小的多数类样本。具体来说,对于每个多数类样本,算法计算其到k个最近少数类样本的平均距离,然后选择平均距离最小的样本。

算法流程:

  1. 对每个多数类样本,找到k个最近的少数类样本
  2. 计算到这些少数类样本的平均距离
  3. 选择平均距离最小的样本进行保留
from imblearn.under_sampling import NearMiss
from collections import Counter
from sklearn.datasets import make_classification

# 创建不平衡数据集
X, y = make_classification(n_classes=2, weights=[0.1, 0.9], 
                          n_samples=1000, random_state=42)
print("原始数据集分布:", Counter(y))

# 应用NearMiss-1
nm1 = NearMiss(version=1, n_neighbors=3)
X_resampled, y_resampled = nm1.fit_resample(X, y)
print("NearMiss-1处理后分布:", Counter(y_resampled))

NearMiss-2:最远邻平均距离最小化

NearMiss-2采用相反的思路,选择那些与少数类样本最远邻平均距离最小的多数类样本。这种方法关注的是样本在特征空间中的边界区域。

算法特点:

  • 计算每个多数类样本到最远k个少数类样本的平均距离
  • 选择这些平均距离最小的样本
  • 更适合处理类别边界模糊的情况
# 应用NearMiss-2
nm2 = NearMiss(version=2, n_neighbors=3)
X_resampled2, y_resampled2 = nm2.fit_resample(X, y)
print("NearMiss-2处理后分布:", Counter(y_resampled2))

NearMiss-3:两阶段选择策略

NearMiss-3采用更加复杂的两阶段选择过程,首先预选与少数类样本相关的多数类样本,然后从中选择最具代表性的样本。

两阶段流程:

阶段描述目的
第一阶段使用k近邻找到与少数类样本相关的多数类样本缩小候选样本范围
第二阶段从预选样本中选择与少数类样本平均距离最大的样本保留边界样本
# 应用NearMiss-3
nm3 = NearMiss(version=3, n_neighbors=3, n_neighbors_ver3=3)
X_resampled3, y_resampled3 = nm3.fit_resample(X, y)
print("NearMiss-3处理后分布:", Counter(y_resampled3))

参数配置与调优

NearMiss算法提供了多个可配置参数,合理设置这些参数对算法效果至关重要:

主要参数说明:

参数类型默认值描述
versionint1NearMiss版本(1、2或3)
n_neighborsint3近邻数量,用于距离计算
n_neighbors_ver3int3NearMiss-3专用的近邻参数
sampling_strategystr/dict'auto'采样策略配置
n_jobsintNone并行计算线程数

参数调优建议:

from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import Pipeline

# 创建包含NearMiss的管道
pipeline = Pipeline([
    ('sampler', NearMiss()),
    ('classifier', RandomForestClassifier())
])

# 参数网格
param_grid = {
    'sampler__version': [1, 2, 3],
    'sampler__n_neighbors': [3, 5, 7],
    'sampler__n_neighbors_ver3': [3, 5]
}

# 网格搜索优化
grid_search = GridSearchCV(pipeline, param_grid, cv=5, scoring='f1')
grid_search.fit(X, y)
print("最佳参数:", grid_search.best_params_)

实际应用场景

NearMiss系列算法在以下场景中表现优异:

  1. 高维数据:当特征维度较高时,基于距离的方法能更好地捕捉样本间的关系
  2. 边界样本重要:当分类边界附近的样本对模型性能影响较大时
  3. 数据质量要求高:需要保持数据分布特性的场景

与其他方法的对比:

方法优点缺点适用场景
NearMiss-1保留接近少数类的样本可能过度简化边界类别分离明显的数据
NearMiss-2关注边界区域计算复杂度较高边界模糊的数据
NearMiss-3两阶段选择,更精确参数调优复杂高质量要求的应用
随机欠采样简单快速可能丢失重要信息大数据集初步处理

性能考量与最佳实践

在使用NearMiss算法时,需要注意以下性能考量:

  1. 计算复杂度:NearMiss算法需要计算距离矩阵,时间复杂度为O(n²),在大数据集上可能较慢
  2. 参数敏感性:近邻数量k对结果影响较大,需要通过交叉验证确定最优值
  3. 数据标准化:距离计算对特征尺度敏感,建议先进行特征标准化
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

# 推荐的数据处理管道
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('sampler', NearMiss(version=1, n_neighbors=5)),
    ('classifier', RandomForestClassifier())
])

# 训练和评估
pipeline.fit(X_train, y_train)
accuracy = pipeline.score(X_test, y_test)
print(f"模型准确率: {accuracy:.3f}")

NearMiss系列算法为处理类别不平衡问题提供了基于距离的智能解决方案。通过合理选择算法版本和参数配置,可以在减少多数类样本的同时保持数据集的重要特征,为后续机器学习模型训练提供高质量的数据基础。

Tomek Links与Condensed Nearest Neighbour

在解决类别不平衡问题的欠采样技术中,Tomek Links和Condensed Nearest Neighbour(CNN)是两种基于原型选择的重要方法。它们通过不同的策略来识别和移除对分类边界影响较小的样本,从而改善数据集的平衡性。

Tomek Links算法原理

Tomek Links算法基于一个简单而有效的概念:识别并移除边界上的噪声样本。具体来说,Tomek Link是指两个不同类别的样本点,它们互为最近邻。这种成对关系通常出现在类别的边界区域,其中至少有一个样本可能是噪声或对分类决策边界贡献不大的点。

算法核心机制

Tomek Links算法的核心在于is_tomek静态方法,该方法检测Tomek链接对:

@staticmethod
def is_tomek(y, nn_index, class_type):
    links = np.zeros(len(y), dtype=bool)
    class_excluded = [c for c in np.unique(y) if c not in class_type]
    
    for index_sample, target_sample in enumerate(y):
        if target_sample in class_excluded:
            continue
            
        if y[nn_index[index_sample]] != target_sample:
            if nn_index[nn_index[index_sample]] == index_sample:
                links[index_sample] = True
                
    return links

该方法的执行流程如下:

mermaid

参数配置与使用

TomekLinks类的主要参数包括:

参数类型默认值描述
sampling_strategystr/dict"auto"采样策略,控制哪些类别需要欠采样
n_jobsint/NoneNone并行计算的工作进程数

使用示例:

from imblearn.under_sampling import TomekLinks
from collections import Counter
from sklearn.datasets import make_classification

# 创建不平衡数据集
X, y = make_classification(n_classes=2, weights=[0.1, 0.9], 
                          n_samples=1000, random_state=42)
print('原始数据集分布:', Counter(y))

# 应用Tomek Links
tl = TomekLinks()
X_res, y_res = tl.fit_resample(X, y)
print('处理后数据集分布:', Counter(y_res))

Condensed Nearest Neighbour算法

Condensed Nearest Neighbour(CNN)是一种更复杂的原型选择方法,旨在找到能够保持原始数据集分类性能的最小样本子集。该算法通过迭代过程构建一个"浓缩"的训练集。

算法执行流程

CNN算法的核心在于_fit_resample方法,其执行过程如下:

mermaid

关键参数说明

CondensedNearestNeighbour类提供多个可配置参数:

参数类型默认值描述
sampling_strategystr/dict"auto"采样策略配置
random_stateint/RandomStateNone随机数生成器种子
n_neighborsint/estimatorNone最近邻数量或分类器对象
n_seeds_Sint1初始多数类样本数量
n_jobsint/NoneNone并行计算设置
实际应用示例
from imblearn.under_sampling import CondensedNearestNeighbour
from sklearn.neighbors import KNeighborsClassifier

# 使用自定义KNN分类器
cnn = CondensedNearestNeighbour(
    n_neighbors=KNeighborsClassifier(n_neighbors=3),
    random_state=42,
    n_seeds_S=2
)

X_res_cnn, y_res_cnn = cnn.fit_resample(X, y)
print('CNN处理后样本分布:', Counter(y_res_cnn))
print('使用的KNN分类器数量:', len(cnn.estimators_))

算法比较与选择指南

Tomek Links和CNN虽然都属于原型选择方法,但在适用场景和效果上存在显著差异:

特性Tomek LinksCondensed Nearest Neighbour
计算复杂度
样本减少程度温和显著
主要目标移除边界噪声构建最小充分训练集
多类别支持一对多策略一对多策略
参数敏感性中等
适用场景建议

选择Tomek Links当:

  • 数据集相对较小,计算资源有限
  • 只需要轻微调整样本分布
  • 主要目标是清理边界噪声样本
  • 希望保持尽可能多的原始数据信息

选择Condensed Nearest Neighbour当:

  • 数据集较大,需要显著减少样本数量
  • 追求最小化的训练集规模
  • 计算资源充足,可以接受较高的时间复杂度
  • 需要构建高度浓缩的代表性样本集

性能优化技巧

  1. 并行处理优化:对于大型数据集,设置n_jobs参数可以显著加速计算过程
  2. KNN配置调优:在CNN中,通过调整n_neighbors参数可以平衡浓缩效果和计算效率
  3. 随机种子设置:使用固定的random_state确保结果可重现
  4. 采样策略定制:根据具体需求定制sampling_strategy参数,精确控制各类别的采样比例

实际应用注意事项

在使用这两种算法时,需要注意以下问题:

  1. 数据预处理:确保数据已经过适当的标准化处理,因为距离计算对尺度敏感
  2. 类别标签处理:算法支持多类别问题,但采用一对多策略处理
  3. 稀疏数据支持:两种算法都支持稀疏矩阵输入
  4. 特征名称保留:从0.10版本开始支持特征名称的保留

通过合理选择和应用Tomek Links与Condensed Nearest Neighbour算法,可以有效地处理类别不平衡问题,提升机器学习模型的性能和泛化能力。

编辑最近邻与邻域清理规则

在机器学习处理类别不平衡数据集时,编辑最近邻(Edited Nearest Neighbours, ENN)和邻域清理规则(Neighbourhood Cleaning Rule, NCR)是两种基于原型选择的重要欠采样技术。这些方法通过智能地移除靠近决策边界的噪声样本,而不是简单地随机删除多数类样本,从而在保持数据集质量的同时实现类别平衡。

编辑最近邻(ENN)算法原理

编辑最近邻算法基于一个核心思想:如果一个样本的大多数最近邻样本属于不同的类别,那么这个样本很可能位于决策边界附近或者是噪声样本,应该被移除。

ENN算法的工作流程如下:

mermaid

ENN算法在imbalanced-learn中的实现提供了两种选择策略:

策略类型描述保守程度移除样本数量
kind_sel="all"所有最近邻都必须属于相同类别才保留样本较不保守较多
kind_sel="mode"多数最近邻属于相同类别即可保留样本较保守较少

ENN算法实现详解

在imbalanced-learn中,ENN算法的核心实现逻辑如下:

def _fit_resample(self, X, y):
    self._validate_estimator()
    idx_under = np.empty((0,), dtype=int)
    self.nn_.fit(X)
    
    for target_class in np.unique(y):
        if target_class in self.sampling_strategy_.keys():
            target_class_indices = np.flatnonzero(y == target_class)
            X_class = _safe_indexing(X, target_class_indices)
            y_class = _safe_indexing(y, target_class_indices)
            nnhood_idx = self.nn_.kneighbors(X_class, return_distance=False)[:, 1:]
            nnhood_label = y[nnhood_idx]
            
            if self.kind_sel == "mode":
                nnhood_label, _ = _mode(nnhood_label, axis=1)
                nnhood_bool = np.ravel(nnhood_label) == y_class
            elif self.kind_sel == "all":
                nnhood_label = nnhood_label == target_class
                nnhood_bool = np.all(nnhood_label, axis=1)
                
            index_target_class = np.flatnonzero(nnhood_bool)
        else:
            index_target_class = slice(None)
            
        idx_under = np.concatenate((idx_under, 
                                  np.flatnonzero(y == target_class)[index_target_class]), 
                                  axis=0)
    
    self.sample_indices_ = idx_under
    return _safe_indexing(X, idx_under), _safe_indexing(y, idx_under)

邻域清理规则(NCR)算法

邻域清理规则是对ENN算法的扩展,它结合了ENN和k-NN分类器来提供更全面的数据清理。NCR采用两阶段清理策略:

mermaid

NCR算法的关键参数配置:

参数默认值描述
n_neighbors3最近邻数量
threshold_cleaning0.5清理阈值,控制哪些类别参与第二阶段清理
edited_nearest_neighboursNone自定义ENN实例,默认为kind_sel="mode"

NCR算法实现机制

NCR算法的实现包含两个主要阶段:

第一阶段 - ENN预处理:

self.edited_nearest_neighbours_.fit_resample(X, y)
index_not_a1 = self.edited_nearest_neighbours_.sample_indices_
index_a1 = np.ones(y.shape, dtype=bool)
index_a1[index_not_a1] = False
index_a1 = np.flatnonzero(index_a1)

第二阶段 - 邻域清理:

# 确定需要清理的类别
self.classes_to_clean_ = [
    c for c, n_samples in target_stats.items()
    if (c in self.sampling_strategy_.keys() and 
        n_samples > target_stats[class_minority] * self.threshold_cleaning)
]

# 使用k-NN识别误分类样本的邻居
self.nn_.fit(X, y)
y_pred_minority = self.nn_.predict(X_minority)
neighbors_to_minority_indices = self.nn_.kneighbors(
    X_minority, n_neighbors=self.nn_.n_neighbors + 1, return_distance=False
)[:, 1:]

mask_misclassified_minority = y_pred_minority != y_minority
index_a2 = np.ravel(neighbors_to_minority_indices[mask_misclassified_minority])

算法性能对比

为了帮助选择合适的算法,以下是ENN和NCR的性能特征对比:

特性ENNNCR
计算复杂度中等较高
噪声处理能力良好优秀
边界样本处理保守积极
多类别支持
参数敏感性中等较高

实际应用示例

下面展示如何使用这两种算法处理不平衡数据集:

from collections import Counter
from sklearn.datasets import make_classification
from imblearn.under_sampling import EditedNearestNeighbours, NeighbourhoodCleaningRule

# 创建不平衡数据集
X, y = make_classification(n_classes=2, class_sep=2,
                          weights=[0.1, 0.9], 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))

# 使用ENN算法
enn = EditedNearestNeighbours(n_neighbors=5, kind_sel='mode')
X_enn, y_enn = enn.fit_resample(X, y)
print('ENN处理后分布:', Counter(y_enn))

# 使用NCR算法  
ncr = NeighbourhoodCleaningRule(n_neighbors=5, threshold_cleaning=0.6)
X_ncr, y_ncr = ncr.fit_resample(X, y)
print('NCR处理后分布:', Counter(y_ncr))

参数调优建议

  1. n_neighbors选择:通常选择3-11之间的奇数,较大的值会产生更平滑的决策边界但可能欠拟合。

  2. kind_sel策略

    • 对于噪声较多的数据集,使用kind_sel="all"进行更激进的清理
    • 对于相对干净的数据集,使用kind_sel="mode"保留更多样本
  3. threshold_cleaning调整

    • 较低的值(0.3-0.5)会清理更多类别
    • 较高的值(0.6-0.8)只清理明显多数的类别
  4. 交叉验证:建议使用交叉验证来评估不同参数组合对最终模型性能的影响。

算法适用场景

ENN适合场景:

  • 数据集相对干净,噪声较少
  • 需要快速初步清理
  • 计算资源有限的情况

NCR适合场景:

  • 数据集包含大量噪声和边界样本
  • 对分类精度要求较高
  • 有足够的计算资源处理两阶段清理

这两种算法都是基于最近邻的智能欠采样方法,能够有效识别和移除噪声样本,同时在保持数据集代表性的前提下实现类别平衡。在实际应用中,建议根据具体数据集特性和业务需求选择合适的算法和参数配置。

总结

imbalanced-learn库提供了丰富而强大的欠采样技术来应对类别不平衡问题。从简单的随机欠采样到基于智能距离度量的NearMiss系列,再到专注于边界清理的Tomek Links和原型选择的CNN算法,以及最后的高级清理技术ENN和NCR,每种方法都有其独特的优势和适用场景。在实际应用中,需要根据数据集特性、计算资源和业务需求选择合适的算法。随机欠采样适合大规模数据和初步处理,NearMiss系列适用于高维数据和边界样本重要的场景,Tomek Links和CNN专注于噪声清理和原型选择,而ENN和NCR则提供更精细的邻域清理能力。通过合理配置参数和结合交叉验证,这些欠采样技术能够显著提升不平衡数据集的建模效果。

【免费下载链接】imbalanced-learn 【免费下载链接】imbalanced-learn 项目地址: https://gitcode.com/gh_mirrors/imb/imbalanced-learn

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值