R中LDA模型预测异常:因子水平1被误判为0的问题排查
LDA模型全误判少数类的修复方案
从你的混淆矩阵能看到,模型完全把类别1的样本预测成0,本质是模型没学到任何区分两类的有效信息,结合你试过加减变量没用的情况,核心问题出在类别极度不平衡和特征区分度不足,下面是具体的修复步骤:
一、先解决类别不平衡问题
你的测试集里类别0占95%,训练集肯定也是极度不平衡的。LDA默认用样本比例作为先验概率,这种情况下模型会优先预测多数类来保证“好看的准确率”,完全忽略少数类。
1. 手动调整LDA先验概率
强制让模型平等看待两类,比如给两类各设50%的先验(可根据实际情况调整比例):
lda.model = lda(factor(Donation) ~ Age + Home + NumberOfChild, data = dftrain, prior = c(0.5, 0.5))
2. 平衡训练集样本
- 过采样:复制少数类(类别1)的样本,让两类数量接近
- 欠采样:随机删掉一部分多数类(类别0)样本
- SMOTE合成样本:用
DMwR包生成少数类的合成样本,避免过拟合:
library(DMwR) # 生成平衡后的训练集:少数类过采样200%,多数类欠采样150% dftrain_balanced = SMOTE(factor(Donation) ~ Age + Home + NumberOfChild, data = dftrain, perc.over = 200, perc.under = 150) # 用平衡后的数据集训练LDA lda.model = lda(factor(Donation) ~ ., data = dftrain_balanced)
二、检查特征是否真的有用
你加减变量没变化,说明当前特征在两类之间几乎没差异,根本没法帮模型区分:
1. 统计检验特征区分度
对每个特征做类间差异检验:
# 连续特征(Age、NumberOfChild)做t检验 t.test(Age ~ factor(Donation), data = dftrain) t.test(NumberOfChild ~ factor(Donation), data = dftrain) # 分类特征(Home)做卡方检验 chisq.test(table(dftrain$Home, dftrain$Donation))
如果所有检验的p值都远大于0.05,说明这些特征完全没用,必须换其他特征或者做特征工程。
2. 尝试特征变换/组合
比如创建交互项、对连续特征分箱:
# 添加Age和NumberOfChild的交互项 dftrain$Age_Child = dftrain$Age * dftrain$NumberOfChild # 重新训练模型 lda.model = lda(factor(Donation) ~ Age + Home + NumberOfChild + Age_Child, data = dftrain)
三、调整模型或评估指标
1. 换用更适合不平衡数据的模型
LDA对数据假设(同协方差高斯分布)要求高,且不擅长处理不平衡数据,试试随机森林、XGBoost这类模型,它们自带处理不平衡的参数:
library(randomForest) rf.model = randomForest(factor(Donation) ~ Age + Home + NumberOfChild, data = dftrain, classwt = c(0.1, 0.9)) # 给少数类更高权重
2. 别只看准确率!
不平衡数据集里准确率毫无意义,重点看类别1的召回率、F1值、ROC-AUC这些指标,这些才能反映模型对少数类的识别能力。
四、验证LDA的假设是否成立
LDA要求两类数据的协方差矩阵相近,如果不满足,模型效果会极差:
# 拆分两类样本的特征 train_0 = dftrain[dftrain$Donation == 0, c("Age", "Home", "NumberOfChild")] train_1 = dftrain[dftrain$Donation == 1, c("Age", "Home", "NumberOfChild")] # 打印协方差矩阵对比 print("类别0的协方差矩阵:") print(cov(train_0)) print("类别1的协方差矩阵:") print(cov(train_1))
如果协方差差异很大,改用QDA(二次判别分析),它不要求同协方差:
library(MASS) qda.model = qda(factor(Donation) ~ Age + Home + NumberOfChild, data = dftrain) predictions.qda = predict(qda.model, newdata = dftest) caret::confusionMatrix(as.factor(predictions.qda$class), as.factor(dftest$Donation))
内容的提问来源于stack exchange,提问作者Isabella Clemandot
相关产品推荐
相关产品推荐

