基于RandomForest与TF-IDF的文本情感分类混淆矩阵异常排查
为啥RandomForest+TF-IDF把所有Bad样本都判成Good?
咱先从你的结果倒推问题:看混淆矩阵里的样本数,Bad类总共才2631个,Good类却有10166个——Good样本是Bad的近4倍,这是严重的类别不平衡!
RandomForest这类树模型有个特点:它会优先追求整体准确率。你算下,哪怕把所有样本都判成Good,准确率也能达到 10166/(10166+2631)≈79.5%,正好和你得到的准确率完全一致!模型觉得“反正判成Good准没错,不用费劲找Bad的特征”,直接躺平偏向多数类了。
那为啥MultinomialNB+CountVectorizer就正常?这得说两个点:
- NB模型本身的特性:MultinomialNB是基于概率统计的,它会考虑每个类别的先验概率,不会单纯被多数类的数量优势带偏;
- 特征类型的适配性:CountVectorizer保留了词的原始计数,NB这类依赖词频统计的模型对这种特征天生适配,能抓得住Bad类的特征词信号;而TF-IDF会压低高频通用词的权重,万一Bad类的特征词刚好是相对高频的(比如“差”“烂”这类吐槽词),TF-IDF反而削弱了它们的区分度,让RandomForest更难学到Bad类的特征。
给你几个解决RandomForest+TF-IDF问题的办法
1. 先搞定类别不平衡
这是核心问题,有两种思路:
- 给模型加
class_weight='balanced'参数,让模型自动给少数类(Bad)更高的权重,强迫它重视少数类:rf = RandomForestClassifier(n_estimators=50, max_depth=20, n_jobs=-1, class_weight='balanced') - 对数据做采样:要么给Bad类做过采样(比如用SMOTE算法生成更多Bad样本),要么给Good类做欠采样(随机删掉一部分Good样本),让两类样本量尽量均衡。
2. 调整TF-IDF的参数
试试过滤掉无意义的噪声特征,比如设置min_df=5(去掉在少于5个样本里出现的词),或者max_df=0.8(去掉在80%以上样本里出现的通用词),让TF-IDF保留更有区分度的特征:
tfidf_vect = TfidfVectorizer(analyzer=clean_text, min_df=5, max_df=0.8)
3. 调优RandomForest的参数
你当前设的max_depth=20可能太浅了,模型欠拟合,根本学不到Bad类的特征。试试把max_depth设大一点(比如改成None,让树完全生长),或者增加n_estimators的数量(比如调到100),给模型更多学习的空间。
4. 用分层交叉验证划分数据集
你之前用的train_test_split是随机划分的,万一测试集里Bad样本占比极低,也会影响结果。改用StratifiedKFold做分层交叉验证,保证训练集和测试集的类别分布和原数据一致:
from sklearn.model_selection import StratifiedKFold skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) for train_idx, test_idx in skf.split(X_tfidf, df['Label']): X_train, X_test = X_tfidf[train_idx], X_tfidf[test_idx] y_train, y_test = df['Label'][train_idx], df['Label'][test_idx] # 后续模型训练代码
先确认你的数据分布
可以先跑一行代码看看标签的具体分布,验证咱的判断:
print(df['Label'].value_counts())
要是Good的占比确实远高于Bad,那类别不平衡就是罪魁祸首啦。
内容的提问来源于stack exchange,提问作者Riya Negi
相关产品推荐
相关产品推荐

