ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python新闻文本分类源码实战:SVM、LSTM与词向量对比

Python新闻文本分类源码实战:SVM、LSTM与词向量对比 简介这份源码资源面向希望入门中文短文本分类的Python学习者与算法实践者提供了一套可运行的新闻文本分类系统用于对比传统机器学习与深度学习方法在短文本场景下的表现差异。项目以搜狗实验室新闻数据集为训练与测试基础采用keras搭建深度学习模型、sklearn实现传统机器学习并引入word2vec预训练词向量覆盖SVM、SVMword2vec、LSTM、LSTMword2vec、MLP、KNN和朴素贝叶斯等多种算法便于读者横向比较各方法的效果。资源包共9个文件以txt数据与说明文件、py源码脚本和md文档为主压缩包约1.99MB结构清晰包含主程序、工具模块及训练测试数据可直接运行调试。目前已有58人学习下载适合作为课程设计、毕业设计或算法入门的参考案例帮助读者快速理解文本分类流程并动手复现实验。1. 从一份新闻分类源码说起它到底能跑出什么结果搜「Python 新闻文本分类 源码」的人多半不是想从零学 NLP而是手里已经有一批中文短文本想找个能直接跑通、又能横向对比几种算法的架子。这份基于 Python 的新闻文本分类系统就是干这个的数据集用搜狗实验室的新闻语料深度学习走 Keras传统机器学习走 sklearn预训练词向量用 word2vec把 SVM、SVMword2vec、LSTM、LSTMword2vec、MLP、KNN、朴素贝叶斯放在同一套流程里比。它解决的不是「上线一个分类服务」而是「在同一份数据上把传统方法和深度方法的差距、词向量到底加不加分一次性看清楚」。适合正在做课程设计、想复现 baseline、或者要给自己的分类任务选型的人。下面按「资源是什么 → 怎么跑起来 → 坑在哪 → 怎么调」的顺序拆。2. 目录结构与数据格式先看清这份源码的骨架拿到压缩包解压后先别急着pip install把目录扫一遍能省掉后面一半的报错。这份源码的结构不复杂但数据文件和代码是分离的路径写错是最常见的翻车点。2.1 文件清单与各自职责解压后大致是这些内容路径作用main.py主入口串起数据加载、模型训练、评估utils.py工具函数通常是分词、词向量加载、数据预处理src/源码目录可能放模型定义或额外的处理脚本data/数据目录存放训练测试语料train_contents.txt训练集文本一行一条新闻train_labels.txt训练集标签与文本行一一对应test_contents.txt测试集文本test_labels.txt测试集标签requirements.txt依赖清单README.md说明文档这种「文本一个文件、标签一个文件、按行对齐」的格式在中文分类里很常见好处是改数据方便坏处是一旦某一行多了个空行或者编码不对文本和标签就整体错位模型准确率会莫名其妙掉到随机水平。2.2 数据格式与对齐规则先确认三个细节编码、分隔、行数。用下面这段脚本快速体检比直接开训靠谱得多。# check_data.py # 快速检查文本与标签是否按行对齐、编码是否正常 def load_lines(path, encodingutf-8): with open(path, r, encodingencoding) as f: # strip 掉行尾换行但保留行内空格 return [line.rstrip(\n) for line in f] contents load_lines(data/train_contents.txt) labels load_lines(data/train_labels.txt) print(文本行数:, len(contents)) print(标签行数:, len(labels)) print(前两条文本:, contents[:2]) print(前两条标签:, labels[:2]) # 行数不一致直接报错别让它带病训练 assert len(contents) len(labels), 文本与标签行数不一致检查空行逻辑说明rstrip(\n)只去行尾换行避免把文本里的空格也吃掉assert是给自己留的后悔药行数不对时立刻停下而不是等训练完才发现标签错位。参数上如果文件是 GBK 编码搜狗老语料有时是把encoding改成gbk再跑一遍报UnicodeDecodeError基本就是编码问题。2.3 依赖安装与环境确认requirements.txt里通常包含keras、tensorflow、scikit-learn、gensim、jieba、numpy这几类。安装前先确认 Python 版本Keras 和 TensorFlow 的版本匹配是玄学重灾区。# 建议用虚拟环境别污染全局 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 先升级 pip再装依赖 pip install --upgrade pip pip install -r requirements.txt # 验证关键库能否导入 python -c import keras, sklearn, gensim, jieba; print(ok)逻辑说明虚拟环境是为了隔离版本避免和系统里已有的 TensorFlow 打架。requirements.txt如果没锁版本装出来的可能是最新版而老代码常和新版 Keras 不兼容这时按报错回退到tensorflow2.x对应版本即可。最后那句导入验证很关键gensim加载 word2vec 模型时对版本敏感先确认能导入再往下走。3. 把传统机器学习和深度学习跑在同一套流程里这份源码的价值不在单个模型而在「同一份数据、同一套预处理、多个模型对比」。理解它的组织方式才能改得动、扩得开。3.1 中文分词与词向量加载中文短文本分类绕不开分词。常见做法是用 jieba 把每条新闻切成词序列再决定是走 TF-IDF给传统模型还是走词向量给深度模型。import jieba from gensim.models import KeyedVectors def tokenize(text): # 精确模式分词过滤掉单字和空白 return [w for w in jieba.lcut(text) if len(w) 1 and w.strip()] # 加载预训练 word2vec 词向量二进制格式 # 注意模型文件需自行准备源码不附带大体积词向量 w2v KeyedVectors.load_word2vec_format(word2vec.bin, binaryTrue) def text_to_vec(tokens, dim200): vecs [w2v[w] for w in tokens if w in w2v] if not vecs: return [0.0] * dim # 对词向量取平均得到句向量 return [sum(col) / len(vecs) for col in zip(*vecs)]逻辑说明jieba.lcut用精确模式过滤单字能减少噪声text_to_vec用词向量平均是最朴素的句表示优点是快、可解释缺点是丢语序——这也是为什么后面要拿 LSTM 做对比。参数上dim必须和词向量文件的实际维度一致200 或 300 是常见值写错会在拼接矩阵时报维度不匹配。词向量文件体积大源码通常不附带需要自己准备或用小规模语料训练一个。3.2 传统模型SVM、KNN、朴素贝叶斯的接入方式传统模型吃的是固定长度特征向量所以流程是「分词 → TF-IDF 向量化 → 喂给 sklearn 分类器」。from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.svm import SVC from sklearn.neighbors import KNeighborsClassifier from sklearn.naive_bayes import MultinomialNB from sklearn.pipeline import Pipeline # 用空格拼接分词结果作为 TF-IDF 的输入 train_texts [ .join(tokenize(t)) for t in train_contents] # SVM 用线性核短文本高维稀疏特征下表现稳 svm_clf Pipeline([ (tfidf, TfidfVectorizer(max_features5000)), (clf, SVC(kernellinear)) ]) svm_clf.fit(train_texts, train_labels) # KNN 和朴素贝叶斯同理换掉 clf 即可 knn_clf Pipeline([(tfidf, TfidfVectorizer(max_features5000)), (clf, KNeighborsClassifier(n_neighbors5))]) nb_clf Pipeline([(tfidf, TfidfVectorizer(max_features5000)), (clf, MultinomialNB())])逻辑说明Pipeline把向量化和分类器绑在一起避免测试集单独 transform 时用错词表。max_features5000是控制维度的常用值太大容易过拟合、太小学不到特征。SVM 用线性核是因为文本特征维度高、样本相对稀疏线性核又快又稳KNN 的n_neighbors默认 5短文本上可以试 3 到 10朴素贝叶斯适合做快速 baseline但它的独立性假设在新闻文本上偏强准确率通常低于 SVM。3.3 深度模型LSTM 与 MLP 的 Keras 实现深度模型这边输入是词序列或句向量输出是类别。LSTM 吃序列MLP 吃句向量。from keras.models import Sequential from keras.layers import Embedding, LSTM, Dense, Dropout from keras.preprocessing.sequence import pad_sequences MAX_LEN 100 # 每条新闻截断/补齐到 100 个词 VOCAB_SIZE 20000 # 把词转成 id 序列 def tokens_to_ids(tokens, word_index): return [word_index.get(w, 0) for w in tokens] X pad_sequences([tokens_to_ids(tokenize(t), word_index) for t in train_contents], maxlenMAX_LEN) model Sequential([ Embedding(VOCAB_SIZE, 128, input_lengthMAX_LEN), LSTM(64, dropout0.2, recurrent_dropout0.2), Dense(len(set(train_labels)), activationsoftmax) ]) model.compile(losscategorical_crossentropy, optimizeradam, metrics[accuracy]) model.fit(X, y_onehot, batch_size64, epochs5, validation_split0.1)逻辑说明pad_sequences把不等长序列统一到MAX_LEN短补长截这是 LSTM 能批量训练的前提。Embedding层维度 128 是折中值有预训练词向量时可以初始化权重再微调。dropout和recurrent_dropout都设 0.2 是为了压过拟合短文本数据量不大时尤其明显。epochs5是起步值看验证集 loss 是否还在降再决定加不加。MLP 则把EmbeddingLSTM换成对句向量的Dense堆叠输入是 3.1 里算出的平均词向量。4. 避坑与排查跑不通时先看这几处这份源码本身不复杂但中文文本 多模型 词向量的组合坑集中在数据、版本、维度三处。下面几条都是实际会撞上的。4.1 文本与标签错位准确率像随机猜现象训练 loss 正常下降但验证准确率一直在类别数倒数附近晃比如 10 分类稳定在 10% 左右。原因train_contents.txt和train_labels.txt行数不一致中间有空行或某行被截断导致标签整体偏移。解决用 2.2 的脚本先assert行数再逐行打印前几条人工核对发现空行就统一清理别用readlines()直接读。4.2 词向量维度对不上拼接矩阵报错现象加载 word2vec 后构造 Embedding 权重矩阵时抛ValueError: shapes not aligned。原因词向量文件实际维度是 300代码里按 200 写或者词表大小和VOCAB_SIZE不一致。解决加载后先打印w2v.vector_size把代码里的维度参数改成一致VOCAB_SIZE取len(word_index) 1别硬编码。4.3 Keras 与 TensorFlow 版本不匹配现象import keras成功但from keras.layers import LSTM报ImportError或AttributeError。原因Keras 2.6 之后已并入 TensorFlow独立安装的 keras 和 tf 版本错位。解决统一用tensorflow.keras或者按requirements.txt锁定的版本装实在不行就pip install tensorflow2.x让它自带 keras别单独装。4.4 分词后特征太稀疏传统模型效果差现象SVM 准确率明显低于预期混淆矩阵里多数样本挤在一个类。原因新闻短文本分词后有效词少TF-IDF 维度高但每行非零元素极少KNN 的距离度量在这种稀疏空间里几乎失效。解决SVM 保持线性核并适当降max_featuresKNN 换余弦距离或直接放弃朴素贝叶斯加alpha平滑。别指望 KNN 在短文本上出彩。4.5 内存被词向量和序列撑爆现象训练到一半进程被 kill或pad_sequences时内存飙升。原因一次性把所有文本转成 id 序列并 padding加上词向量矩阵内存占用是文本体积的几十倍。解决用生成器分批喂数据或者先把分词结果缓存成文件避免每次训练都重新分词。MAX_LEN也别设太大100 到 200 对新闻标题级文本够用。5. 把对比实验做扎实评估、调参与一个可复用的习惯跑通只是起点这份源码真正的用法是拿它做选型对比。要让结论可信评估和调参得按规矩来。5.1 统一评估口径所有模型必须用同一份测试集、同一个评估指标。分类任务别只看准确率类别不均衡时看宏平均 F1。from sklearn.metrics import classification_report, confusion_matrix def evaluate(name, y_true, y_pred): print(f {name} ) print(classification_report(y_true, y_pred, digits4)) print(confusion_matrix(y_true, y_pred)) # 每个模型预测完都走一遍输出格式统一才好横向比 evaluate(SVM, test_labels, svm_clf.predict(test_texts)) evaluate(LSTM, test_labels, lstm_pred_labels)逻辑说明classification_report同时给出精确率、召回率、F1digits4方便看小差距混淆矩阵能暴露「某两类总混」的问题比单一准确率信息量大。把每个模型的输出都过这个函数最后拉一张表对比谁强谁弱一目了然。5.2 对比实验的参数记录调参最怕「改了啥忘了」。建议每跑一组就记一行下面是我常用的记录格式模型关键参数验证集 F1测试集 F1备注SVMlinear, max_features50000.860.85baseline 稳SVMword2vec平均词向量, dim2000.830.82词向量平均丢语序LSTMemb128, hidden64, epoch50.890.88训练慢但上限高LSTMword2vec预训练初始化0.910.90提升明显MLP句向量输入, 2 隐层0.840.83快适合快速验证KNNk5, 余弦距离0.720.71短文本上偏弱朴素贝叶斯alpha1.00.780.77快但假设偏强这张表不是让你照抄数字而是说明「同一份数据下词向量对深度模型加分、对传统模型未必」这个结论怎么来的。你自己跑出来的数才是选型依据。5.3 一个我踩过坑后养成的习惯早期我图快直接拿测试集当验证集调参结果上线后指标掉一大截——测试集被「看过」太多次已经不客观了。从那以后我每次做对比实验都强制从训练集里切 10% 出来当验证集测试集只在最后评估时碰一次而且所有模型共用同一份切分。这个习惯看着笨但能保证你最后那张对比表是真的不是调出来的。另外分词结果我会缓存成文件换模型时直接读省掉重复分词的时间也避免每次分词结果有细微差异影响对比。希望这些能帮你把这份源码用出该有的价值而不是跑通就扔。本文还有配套的精品资源点击获取
返回列表