Sklearn随机森林针对不平衡数据集优化AUC/F1分数的方法咨询
不平衡数据集下优化模型AUC/F1指标的技巧及模型支持
Sklearn随机森林能否针对AUC/F1优化?
Sklearn的随机森林默认以基尼系数或熵作为分裂准则,训练时直接优化的是分类准确率,无法将AUC、F1这类考虑样本不平衡的指标作为训练目标。但可以通过间接手段引导模型向优化这类指标的方向靠拢。
除类别权重外的优化技巧
1. 数据集重采样
- 过采样:对占比少的正类样本进行扩充,推荐用SMOTE生成合成样本(避免简单重复导致过拟合),可通过
imblearn.over_sampling.SMOTE实现。 - 欠采样:对占比多的负类样本进行筛选,比如用NearMiss保留与正类样本关联性更强的负类样本,减少冗余数据。
- 混合采样:结合欠采样和过采样,比如先对负类欠采样,再对正类做SMOTE过采样,平衡数据集的同时降低过拟合风险。
2. 用目标指标指导调参
在使用GridSearchCV或RandomizedSearchCV调参时,将scoring参数指定为'roc_auc'或'f1',调参过程会自动选择在目标指标上表现最优的模型参数,间接让模型适配不平衡场景。示例代码:
from sklearn.model_selection import GridSearchCV from sklearn.ensemble import RandomForestClassifier param_grid = {'n_estimators': [100, 200], 'max_depth': [5, 10]} rf = RandomForestClassifier(class_weight='balanced') grid_search = GridSearchCV(rf, param_grid, scoring='roc_auc', cv=5) grid_search.fit(X_train, y_train)
3. 自定义样本权重
除了class_weight参数按类别设置权重,还可以手动给每个样本分配权重(比如正类样本权重设为4,负类设为1,对应类别占比的反比),通过fit方法的sample_weight参数传入,更灵活地控制样本对模型训练的影响。
4. 调整分类阈值
随机森林输出的是样本属于正类的概率,默认0.5的分类阈值在不平衡数据集上往往不是最优的。可以通过PR曲线或ROC曲线找到能最大化F1或AUC的阈值,再用该阈值生成预测结果。示例:
import numpy as np from sklearn.metrics import precision_recall_curve # 得到正类概率 y_proba = rf.predict_proba(X_test)[:, 1] # 计算不同阈值下的精确率、召回率 precision, recall, thresholds = precision_recall_curve(y_test, y_proba) # 找到F1最高的阈值 f1_scores = 2 * (precision * recall) / (precision + recall) best_threshold = thresholds[np.argmax(f1_scores)] # 用最优阈值生成预测结果 y_pred = (y_proba >= best_threshold).astype(int)
其他模型的自定义指标支持(以XGBoost为例)
XGBoost、LightGBM、CatBoost这类梯度提升树模型,相比随机森林更灵活,支持自定义评估指标甚至目标函数:
- XGBoost处理不平衡+优化AUC:可以设置
scale_pos_weight为负类与正类的比例(这里是4)来平衡类别,同时将eval_metric设为'auc',训练过程中监控AUC指标。 - XGBoost自定义F1评估:可以编写自定义评估函数,在训练时监控F1分数,调参时选择F1最优的模型。示例代码:
import xgboost as xgb # 转换为XGBoost专用数据格式 dtrain = xgb.DMatrix(X_train, label=y_train) dtest = xgb.DMatrix(X_test, label=y_test) params = { 'objective': 'binary:logistic', 'scale_pos_weight': 4, # 平衡类别权重 'eval_metric': 'auc' } # 自定义F1评估函数 def f1_score_eval(preds, dtrain): labels = dtrain.get_label() preds = (preds >= 0.5).astype(int) tp = (labels * preds).sum() fp = ((1 - labels) * preds).sum() fn = (labels * (1 - preds)).sum() precision = tp / (tp + fp) if (tp + fp) != 0 else 0 recall = tp / (tp + fn) if (tp + fn) != 0 else 0 f1 = 2 * precision * recall / (precision + recall) if (precision + recall) != 0 else 0 return 'f1', f1 # 训练并监控自定义指标 watchlist = [(dtrain, 'train'), (dtest, 'test')] model = xgb.train(params, dtrain, num_boost_round=100, evals=watchlist, feval=f1_score_eval, maximize=True)
LightGBM可通过is_unbalance参数自动处理不平衡,CatBoost支持auto_class_weights='Balanced',两者也都支持自定义评估指标。
内容的提问来源于stack exchange,提问作者Baron Yugovich
相关产品推荐
相关产品推荐

