多标签不平衡数据集处理:imblearn SMOTE不支持,求替代方案
多标签分类不平衡问题的SMOTE替代方案
针对多标签分类的不平衡问题,以下是几种可行的SMOTE替代方法:
MLSMOTE(Multi-Label SMOTE)
这是专门为多标签场景设计的过采样方法,核心思路是基于样本的完整标签组合识别少数类,再在同类标签组合的样本中生成合成数据,避免单标签过采样破坏标签间的关联。
你可以通过自定义实现来使用,以下是一个简化的Python实现示例:
import numpy as np from sklearn.neighbors import NearestNeighbors from collections import Counter def mlsmote(X, y, k_neighbors=5, n_samples=100): # 统计所有标签组合的出现次数 label_combos = [tuple(row) for row in y] combo_counts = Counter(label_combos) # 定义少数类标签组合(这里以中位数为阈值) minority_combos = [combo for combo, cnt in combo_counts.items() if cnt < np.median(list(combo_counts.values()))] synthetic_X = [] synthetic_y = [] for combo in minority_combos: # 提取当前标签组合的所有样本 sample_idx = np.where([tuple(row) == combo for row in y])[0] X_minority = X[sample_idx] y_minority = y[sample_idx] # 拟合KNN模型找近邻 nn_model = NearestNeighbors(n_neighbors=k_neighbors) nn_model.fit(X_minority) # 生成合成样本 gen_count = n_samples // len(minority_combos) for _ in range(gen_count): # 随机选一个基准样本 base_idx = np.random.randint(0, len(X_minority)) # 获取其近邻(排除自身) neighbor_ids = nn_model.kneighbors(X_minority[base_idx].reshape(1, -1), return_distance=False)[0][1:] neighbor_idx = np.random.choice(neighbor_ids) # 插值生成新样本 diff = X_minority[neighbor_idx] - X_minority[base_idx] alpha = np.random.rand() new_sample = X_minority[base_idx] + alpha * diff synthetic_X.append(new_sample) synthetic_y.append(combo) # 合并原数据与合成数据 return np.vstack([X, np.array(synthetic_X)]), np.vstack([y, np.array(synthetic_y)])
基于标签子集的过采样
如果不需要严格保留完整标签组合,可以针对单个标签的少数类分别处理:对每个目标变量,单独识别其少数类样本,用SMOTE生成对应样本后,保留原样本的其他标签值。这种方法实现简单,但可能会引入标签冲突(比如生成的样本在多个标签上同时属于少数类,不符合原数据的标签关联),适合标签独立性较强的场景。
示例代码片段:
from imblearn.over_sampling import SMOTE def per_label_smote(X, y, sampling_strategy='auto'): X_resampled = X.copy() y_resampled = y.copy() for label_col in range(y.shape[1]): # 单独处理每个目标标签 sm = SMOTE(sampling_strategy=sampling_strategy) X_temp, y_temp = sm.fit_resample(X_resampled, y_resampled[:, label_col]) # 合并其他标签列 y_temp_full = np.zeros((len(X_temp), y.shape[1])) y_temp_full[:, label_col] = y_temp # 复制其他标签的原有值 for col in range(y.shape[1]): if col != label_col: y_temp_full[:, col] = np.concatenate([y_resampled[:, col], y_resampled[:, col][sm.sample_indices_]]) X_resampled, y_resampled = X_temp, y_temp_full return X_resampled, y_resampled
MLADASYN(Multi-Label ADASYN)
ADASYN的多标签版本,和MLSMOTE类似,但会根据样本的难分类程度调整合成样本数量——对那些被多数类样本包围的少数类样本,生成更多合成数据,提升模型对难分样本的识别能力。实现思路和MLSMOTE接近,只是在生成样本时,给难分样本分配更高的采样权重。
聚类辅助的多标签过采样
先对所有样本进行聚类(比如用K-Means),在每个簇内部识别不平衡的标签组合,再针对簇内的少数类进行过采样。这种方法能保留样本的局部特征分布,避免生成不符合数据分布的合成样本,适合特征空间具有明显聚类结构的数据集。
额外建议
- 不要单纯依赖过采样,可结合多数类欠采样(比如随机欠采样、聚类欠采样),平衡计算成本与数据分布。
- 过采样后建议用交叉验证评估模型性能,避免过拟合。
内容的提问来源于stack exchange,提问作者Miuni Nihara
相关产品推荐
相关产品推荐

