如何集成使用TF-IDF、fastText不同输入的KNN模型提升假新闻检测准确率
先修正你现有代码的致命问题
你当前TF-IDF向量化的代码存在逻辑错误:测试集不应该调用fit_transform,否则会基于测试集重新生成词汇表,和训练集特征空间不一致,会严重降低模型效果。修正后代码如下:
from sklearn.feature_extraction.text import TfidfVectorizer vector = TfidfVectorizer(max_features =5000, ngram_range=(1,3)) X_train_tfidf = vector.fit_transform(X_train['tweet']).toarray() X_test_tfidf = vector.transform(X_test['tweet']).toarray() # 测试集仅调用transform,复用训练集词汇表
可行集成方案
方案1:手动实现多数投票(最简便灵活)
不需要适配sklearn的API,直接分别得到三个模型的预测结果后做投票即可,步骤如下:
- 分别训练好3个独立的KNN模型,保留每个模型对应的预处理工具:
- 前两个KNN对应各自的TF-IDF向量化器(如果两个TF-IDF参数不同的话,参数相同可以共用)
- 第三个KNN对应fastText的向量化函数
avg_feature_vector、以及标准化器scaler
- 分别得到三个模型在测试集/推理数据上的预测结果
- 对每个样本的三个预测结果取众数,作为最终输出
示例代码:
import numpy as np from scipy.stats import mode # 假设你已经训练好了三个模型:knn_tfidf1、knn_tfidf2、knn_fasttext # 1. 分别得到三个模型的预测结果 y_pred1 = knn_tfidf1.predict(X_test_tfidf) y_pred2 = knn_tfidf2.predict(X_test_tfidf) # 处理fastText的输入 X_test_fasttext = [avg_feature_vector(text) for text in X_test['tweet']] X_test_fasttext_scaled = scaler.transform(X_test_fasttext) y_pred3 = knn_fasttext.predict(X_test_fasttext_scaled) # 2. 多数投票得到最终结果,axis=1表示按样本维度取众数 y_pred_ensemble = mode(np.c_[y_pred1, y_pred2, y_pred3], axis=1, keepdims=False)[0]
如果要实现软投票,只需要把三个模型predict_proba输出的正类概率取平均,再按阈值(默认0.5)判断即可,效果通常比硬投票更稳定。
方案2:适配sklearn原生VotingClassifier
如果你想使用sklearn官方的VotingClassifierAPI,可以将每个模型的全流程(文本输入→特征提取→预测)封装为独立的Pipeline,所有Pipeline的输入统一为原始tweet文本即可,需要自定义一个fastText向量化的Transformer类适配sklearn接口:
from sklearn.base import BaseEstimator, TransformerMixin from sklearn.pipeline import Pipeline from sklearn.neighbors import KNeighborsClassifier from sklearn.preprocessing import StandardScaler from sklearn.ensemble import VotingClassifier # 自定义fastText向量化类 class FastTextVectorizer(BaseEstimator, TransformerMixin): def fit(self, X, y=None): return self def transform(self, X): # X是输入的tweet文本序列 return np.array([avg_feature_vector(text) for text in X]) # 封装三个模型的Pipeline # 第一个TF-IDF KNN pipe1 = Pipeline([ ('tfidf', TfidfVectorizer(max_features=5000, ngram_range=(1,3))), ('knn', KNeighborsClassifier()) # 替换为你自己的KNN参数 ]) # 第二个TF-IDF KNN(如果参数和第一个不同,单独配置,相同可以复用pipe1的结构) pipe2 = Pipeline([ ('tfidf', TfidfVectorizer(max_features=3000, ngram_range=(1,2))), # 示例不同参数 ('knn', KNeighborsClassifier(n_neighbors=7)) ]) # 第三个fastText KNN pipe3 = Pipeline([ ('fasttext_vec', FastTextVectorizer()), ('scaler', StandardScaler()), ('knn', KNeighborsClassifier()) ]) # 定义投票集成器 voting_clf = VotingClassifier( estimators=[('tfidf1', pipe1), ('tfidf2', pipe2), ('fasttext', pipe3)], voting='hard' # 改成'soft'就是软投票 ) # 直接输入原始tweet列训练即可 voting_clf.fit(X_train['tweet'], y_train) # 推理也直接输入原始文本 y_pred = voting_clf.predict(X_test['tweet'])
额外优化建议
如果想要进一步提升效果,可以尝试堆叠集成(Stacking):将三个基模型的预测结果/预测概率作为新特征,训练一个元分类器(比如逻辑回归、朴素贝叶斯),通常比简单投票的效果提升更明显。
内容的提问来源于stack exchange,提问作者Narges Se
相关产品推荐
相关产品推荐

