You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于SMOTE的XGBoost处理不平衡FTIR光谱数据问题求助

不平衡FTIR光谱分类:SMOTE+XGBoost问题排查与优化方案

问题概述

处理FTIR光谱.mat格式数据集的不平衡分类任务时,采用SMOTE+XGBoost模型遇到以下问题:

  • SMOTE过采样后,所有交叉验证折的混淆矩阵中class 0仍未被有效识别
  • 尝试加入样本权重后,触发729次拟合失败的ValueError
  • 测试Borderline SMOTE、SVMSMOTE+EasyEnsemble等方法后,F1分数依旧偏低,怀疑核心原因是XGBoost中class 0的权重配置失衡

相关代码与报错

代码片段1:初始SMOTE+XGBoost实现

from imblearn.over_sampling import SMOTE
from xgboost import XGBClassifier
from sklearn.model_selection import cross_val_predict
import scipy.io

# 加载数据
data = scipy.io.loadmat('ftir_data.mat')
X = data['features']
y = data['labels'].ravel()

# 全局SMOTE过采样
smote = SMOTE(random_state=42)
X_res, y_res = smote.fit_resample(X, y)

# XGBoost训练与交叉验证
xgb = XGBClassifier(objective='multi:softmax', num_class=3, random_state=42)
y_pred = cross_val_predict(xgb, X_res, y_res, cv=5)

代码片段2:样本权重尝试(触发报错)

import numpy as np
from sklearn.model_selection import KFold

# 计算样本权重
sample_weights = np.where(y == 0, 10.0, 1.0)

# 交叉验证传递权重
kf = KFold(n_splits=5, shuffle=True, random_state=42)
for train_idx, test_idx in kf.split(X_res, y_res):
    X_train, X_test = X_res[train_idx], X_res[test_idx]
    y_train, y_test = y_res[train_idx], y_res[test_idx]
    w_train = sample_weights[train_idx]
    xgb.fit(X_train, y_train, sample_weight=w_train)  # 此处触发ValueError

报错信息

ValueError: Invalid parameter sample_weight for estimator XGBClassifier. Check the list of available parameters with `estimator.get_params().keys()`.

类别分布

[类别分布柱状图:class 0占比<5%,class 1/2占比均>45%]


解决方案与修改建议

1. 修复核心错误:避免数据泄露+正确传递样本权重

你之前先对整个数据集做SMOTE再交叉验证,会导致验证集信息泄露,这是class 0无法被有效识别的关键原因之一。必须在每个交叉验证折的训练集上单独执行过采样,同时修正样本权重的传递方式:

from imblearn.over_sampling import SMOTE
from xgboost import XGBClassifier
from sklearn.model_selection import KFold
from sklearn.metrics import f1_score
import numpy as np
import scipy.io

# 加载数据
data = scipy.io.loadmat('ftir_data.mat')
X = data['features']
y = data['labels'].ravel()

# 交叉验证(每个fold内单独处理过采样)
kf = KFold(n_splits=5, shuffle=True, random_state=42)
scores = []
class_weights = len(y) / (len(np.unique(y)) * np.bincount(y))  # 基于类别占比计算权重

for train_idx, test_idx in kf.split(X, y):
    X_train, X_test = X[train_idx], X[test_idx]
    y_train, y_test = y[train_idx], y[test_idx]
    
    # 仅在训练集上执行SMOTE
    smote = SMOTE(random_state=42)
    X_train_res, y_train_res = smote.fit_resample(X_train, y_train)
    
    # 生成训练集样本权重(给class 0更高权重)
    train_weights = class_weights[y_train_res]
    
    # 初始化XGBoost,配置多分类参数
    xgb = XGBClassifier(
        objective='multi:softprob',  # 输出概率,便于调整分类阈值
        num_class=len(np.unique(y)),
        scale_pos_weight=class_weights,  # 全局类别权重
        learning_rate=0.05,
        max_depth=3,  # 限制树深,避免过拟合高维光谱数据
        eval_metric='mlogloss',
        random_state=42
    )
    
    # 正确传递样本权重
    xgb.fit(X_train_res, y_train_res, sample_weight=train_weights)
    
    # 预测与评估
    y_pred = xgb.predict(X_test)
    scores.append(f1_score(y_test, y_pred, average='weighted'))

print(f"平均加权F1分数: {np.mean(scores):.4f}")

2. 优化XGBoost权重配置

  • 改用objective='multi:softprob':输出每个类别的概率,后续可通过调整分类阈值(如提高class 0的概率阈值)提升其识别率
  • scale_pos_weight参数:传入基于类别占比计算的权重数组(如[10,1,1]),直接给class 0赋予更高的训练权重
  • 调整模型复杂度:FTIR光谱维度高,需降低max_depth、提高learning_rate,配合subsample、colsample_bytree减少过拟合

3. 改进采样策略

  • 针对极度不平衡的class 0,尝试ADASYN:自适应生成难分类样本,比SMOTE更聚焦于少数类的边界样本
  • 尝试SMOTEENN:过采样后移除与多数类重叠的噪声样本,提升样本质量
  • 结合欠采样:用RandomUnderSampler对多数类进行欠采样,再配合SMOTE过采样,避免过采样导致的噪声积累

4. FTIR光谱特征工程优化

  • 降维处理:用PCA或t-SNE降低光谱维度,减少冗余特征与噪声
  • 信号预处理:对光谱做基线校正、Savitzky-Golay平滑处理,提升有效信号的辨识度,帮助模型捕捉class 0的特征差异

5. 模型融合提升效果

  • 采用EasyEnsemble:集成多个基于欠采样训练的XGBoost模型,每个模型在不同的多数类子集上训练,提升对少数类的识别稳定性
  • 投票融合:结合XGBoost、LightGBM、CatBoost的预测结果,利用不同模型的优势平衡类别识别能力

内容的提问来源于stack exchange,提问作者Rahul Suresh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 17:02:06