为何二元语法(Bigram)模型的AUC指标出现下降?
从你的代码和数据集情况入手,我发现几个可能导致二元模型AUC下降的关键问题:
1. 测试集向量化的致命错误
看你这部分代码:
vectorizer2 = TfidfVectorizer(vocabulary=set(dic_bigram_features),ngram_range=(1,2)) tf_idf_train2=vectorizer2.fit_transform(sentence_train) tf_idf_test2=vectorizer2.fit_transform(sentence_test)
这里犯了一个典型的机器学习错误:测试集绝对不能用fit_transform!fit步骤是用来计算训练集的TF-IDF统计规则(比如词频、逆文档频率)的,测试集必须完全复用训练集的这些规则,也就是只用transform方法。你对测试集再做一次fit,相当于让测试集生成了一套全新的TF-IDF特征空间,和训练集的特征逻辑完全脱节,模型在测试集上的表现必然混乱,这是导致AUC下降的核心原因之一。
正确写法应该是:
vectorizer2 = TfidfVectorizer(vocabulary=set(dic_bigram_features),ngram_range=(1,2)) tf_idf_train2=vectorizer2.fit_transform(sentence_train) tf_idf_test2=vectorizer2.transform(sentence_test) # 这里只用transform!
这个问题不仅影响二元模型,你的一元、三元模型如果也犯了同样的错误,结果也是不可靠的,只是可能一元模型因特征少受影响较小。
2. 特征集构建的冗余与冲突
你把二元特征列表和一元特征列表合并:
lst_bigram=lst_bigram+lst_unigram
然后用这个构建的字典作为vocabulary,同时又设置了ngram_range=(1,2)。这里存在两个问题:
- 合并后的列表转成
set会去重,但ngram_range=(1,2)本身就会自动生成一元+二元特征,手动合并再转集合可能导致特征集和ngram_range生成的特征不匹配,甚至引入无效特征; - 这种手动合并的方式会引入大量冗余特征,对于你只有500条样本的小数据集来说,特征维度爆炸很容易导致模型过拟合,泛化能力下降,最终拉低AUC。
建议要么直接用ngram_range=(1,2)自动生成一元+二元特征,不要手动合并特征列表;如果一定要用自定义词汇表,确保词汇表是准确的一元+二元特征集合,且和ngram_range的设置完全匹配。
3. 不平衡数据集的适配缺失
你的数据集是135条负样本、365条正样本,属于典型的类别不平衡问题。SVM默认的损失函数对所有样本权重一致,这会导致模型偏向数量更多的正样本。二元语法模型的特征维度比一元更高,模型更容易记住正样本的特征模式,在测试集上对负样本的识别能力会大幅降低,而AUC衡量的是整体分类区分能力,负样本识别差会严重拉低这个指标。
解决办法是给SVM加上class_weight='balanced'参数,让模型自动根据样本数量调整类别权重:
clf=SVC(C=100.0,kernel='linear',probability=True, class_weight='balanced')
这个调整对不平衡数据集下的高维度特征模型表现提升非常明显。
4. 超参数的适配性问题
你给所有模型都用了C=100.0的超参数,但不同特征维度的模型需要的正则化强度完全不同。二元模型特征更多,更容易过拟合,C=100是一个正则化很弱的参数(C越大,正则化越弱),这会让模型过度拟合训练集,在测试集上表现自然下降。建议针对不同的n-gram模型单独调整C值,比如用GridSearchCV做网格搜索来找到最优参数。
总结
先修正测试集向量化的错误(这是最紧急的),再处理特征集的冗余问题,接着针对不平衡数据集调整SVM的类别权重,最后优化超参数,应该就能解决二元模型AUC下降的问题了。
内容的提问来源于stack exchange,提问作者shayan talaei

