朴素贝叶斯多分类特征选择优化:提升多类别同时预测精度
问题回顾
你正在用Naive Bayes处理4类别文本分类任务,数据集含387条观测,核心变量是文本reviewText和4水平因子pragmatic("-1","0","1","9")。目前遇到的核心问题是:
- 多类别同时预测精度仅0.5469,混淆矩阵显示模型几乎无法识别
-1和0类别,严重偏向占比最高的9类别 - 但将每个类别单独做二分类时,精度显著提升(
9类0.772、-1类0.829、0类0.9016、1类0.7959) - 尝试类别权重调整后,精度仅小幅提升至0.5677,效果不理想
推测核心原因是全局特征选择无法捕捉类别特异性词汇,加上严重的类别不平衡(训练集9类占比78.87%,0类仅0.52%),导致多类别模型难以有效区分不同类别。
针对性解决方案
一、面向多类别的特征选择优化
针对Naive Bayes的特性,你可以尝试以下特征选择策略,筛选出类别特异性更强的词汇:
类别特异性词筛选(互信息/卡方检验)
不要只用全局高频词(findFreqTerms),而是计算每个词汇与不同类别的关联度,保留对单个类别区分度高的词。比如用卡方检验筛选每个类别的Top N特征:library(quanteda) # 构建训练集的DFM矩阵 train_corpus <- corpus(sms_raw_train, text_field = "text") train_dfm <- dfm(train_corpus, tolower = TRUE, remove_punct = TRUE, remove_numbers = TRUE, stopwords = "english") # 计算词与类别的卡方值 chi_scores <- textstat_keyness(train_dfm, target = sms_raw_train$type, measure = "chi2") # 筛选每个类别top20的特征 top_terms <- chi_scores %>% group_by(feature) %>% slice_max(n=20, order_by=chi2) # 用筛选后的特征构建新的矩阵 filtered_dtm <- dfm_select(train_dfm, pattern = top_terms$feature)这种方法能过滤掉那些在所有类别中都高频的通用词,保留真正能区分类别的词汇。
TF-IDF加权替代二元特征
你当前用的是二元特征(词存在/不存在),可以换成TF-IDF加权,它能降低高频通用词的权重,提升低频但类别特异性词的权重:# 构建TF-IDF矩阵 sms_tfidf <- DocumentTermMatrix(sms_corpus_clean, control = list(weighting = weightTfIdf)) # 后续分割训练测试集、筛选特征的步骤和之前一致对于文本分类,TF-IDF通常比二元特征更能捕捉文本的语义差异,尤其适合多类别场景。
基于模型的特征重要性筛选
训练多类别Naive Bayes后,提取每个特征对不同类别的后验概率差异,筛选出那些能显著拉开类别差距的特征。比如计算每个词在类别c中的概率与其他类别平均概率的差值,保留差值较大的词。
二、One-vs-Rest(OvR)单类别预测融合方案
从你的二分类结果来看,每个类别单独预测的精度远高于多类别模型,这种情况下OvR融合方案会是更优选择,具体步骤:
- 训练4个二分类Naive Bayes模型,每个模型对应一个类别(比如模型1:
-1vs 其他;模型2:0vs 其他,以此类推) - 对每个测试样本,获取4个模型的预测概率(而非硬分类结果)
- 选择概率最高的类别作为最终分类结果
示例代码:
# 定义训练单个二分类模型的函数 train_ovr_model <- function(target_class, train_data, train_labels) { binary_labels <- as.factor(train_labels == target_class) ctrl <- trainControl(method="cv", 10) set.seed(8) model <- train(train_data, binary_labels, method="nb", trControl=ctrl) return(model) } # 训练4个OvR模型 target_classes <- c("-1", "0", "1", "9") ovr_models <- lapply(target_classes, function(c) { train_ovr_model(c, sms_train, sms_raw_train$type) }) # 获取每个模型的预测概率 predict_probs <- lapply(ovr_models, function(m) { predict(m, sms_test, type="prob")[,2] # 取正类的概率 }) predict_probs_df <- do.call(cbind, predict_probs) colnames(predict_probs_df) <- target_classes # 选择概率最高的类别作为最终预测 final_predict <- apply(predict_probs_df, 1, function(x) { names(x)[which.max(x)] }) # 评估融合后的结果 cm_ovr <- confusionMatrix(as.factor(final_predict), sms_raw_test$type)
这种方式能避免多类别模型中少数类别被主导的问题,充分利用每个二分类模型的优势。
额外注意事项
- 极端类别不平衡处理:你的训练集中
0类仅占0.52%,属于极端不平衡,即使加权也很难有效学习。可以尝试:- 过采样:用SMOTE等方法合成少数类别的样本
- 调整二分类阈值:降低少数类别的判定阈值,让模型更容易预测到少数类别
- 预处理优化:添加词干提取(
tm_map(stemDocument))或词形还原,减少词汇冗余;也可以尝试保留部分有意义的停用词(比如情感类词汇)
内容的提问来源于stack exchange,提问作者Banjo

