ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Python上市公司新闻文本分类源码解析:从数据清洗到模型选型

Python上市公司新闻文本分类源码解析:从数据清洗到模型选型 简介这份资源是一套基于Python的上市公司新闻文本分析与分类预测完整源码面向具备一定Python基础、希望入门文本挖掘与机器学习实战的开发者与金融数据分析学习者。项目围绕财经新闻的自动化抓取、文本预处理、特征提取与分类建模展开覆盖从数据采集到模型预测的完整链路适合作为课程设计、毕业设计或技能练手的参考方案。资源包共21个文件以17个Python源代码文件为核心辅以3个文本文件和1个许可证文件压缩包约180KB体量轻便。代码按爬虫、文本分析、模型训练等模块拆分结构清晰便于按需阅读与二次扩展。其中财经词典与中文停用词表可直接用于分词与特征过滤SVM、随机森林等分类器的实现也提供了可复用的建模思路。目前已有350人学习下载适合想系统理解文本分类流程、积累财经文本处理经验的读者参考借鉴。1. 从一份上市公司新闻文本分类源码说起它到底能解决什么问题手里有一批上市公司公告和财经新闻想自动判断每条消息是利好、利空还是中性这件事听起来像量化团队的活其实用 Python 加一份结构清晰的源码就能跑通。基于 Python 的上市公司新闻文本分析与分类预测设计源码核心链路是「采集或导入新闻文本 → 中文分词与清洗 → 特征向量化 → 训练分类模型 → 对新文本做预测」它解决的是人工逐条读公告效率低、情绪判断主观、无法批量处理的问题。适合谁会一点 Python 基础语法、装过 Anaconda 或 VS Code 配置过 Python 环境、想拿一个完整文本分类项目练手或直接改造成自己业务工具的人。新手能照着步骤复现熟手能看清特征工程和模型选型的边界。下面按「数据怎么来、特征怎么造、模型怎么训、坑在哪」四段推进把这份源码背后的落地路径拆开讲。2. 新闻文本从哪来采集、清洗与标注的最小闭环2.1 数据来源的三种现实选择做上市公司新闻文本分析第一步不是写模型而是确定文本从哪来。常见做法有三类一是用公开财经新闻接口或页面采集二是直接导入已有的 CSV/Excel 新闻表三是用开源财经文本数据集。我一般会先看手头有没有现成表格有的话跳过采集直接进清洗环节省掉反爬和解析的麻烦。如果必须自己采集Python 爬虫是绕不开的。用 requests 加 BeautifulSoup 抓静态页面用 lxml 解析表格遇到动态渲染再考虑 Selenium。但这里有个血泪经验财经站点结构经常改写死的 CSS 选择器两周就失效所以采集脚本要把「列表页解析」和「详情页解析」拆成两个函数方便单独修。import requests from bs4 import BeautifulSoup def fetch_news_list(url): 抓取新闻列表页返回标题和详情链接 headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)} resp requests.get(url, headersheaders, timeout10) resp.encoding resp.apparent_encoding # 防止中文乱码 soup BeautifulSoup(resp.text, lxml) items [] for node in soup.select(.news-list li): title node.get_text(stripTrue) link node.find(a)[href] items.append({title: title, link: link}) return items这段代码里timeout10是必须的财经站点响应慢不设超时脚本会卡死apparent_encoding比写死utf-8更稳很多老站点实际是 gbk。返回的 items 列表后续再逐条进详情页抓正文。2.2 中文清洗比英文多出来的四步英文文本分类清洗相对简单中文多出四步去 HTML 标签、去特殊符号、分词、去停用词。上市公司新闻里还常混着股票代码、百分比、括号注释这些要不要保留取决于你的标签定义。如果分类目标是情绪数字和代码通常保留意义不大可以统一替换成占位符。import re import jieba def clean_text(raw): 中文新闻文本清洗去标签、去符号、分词、去停用词 text re.sub(r[^], , raw) # 去 HTML 标签 text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9], , text) # 只留中英文数字 words jieba.lcut(text) stopwords set(open(stopwords.txt, encodingutf-8).read().split()) words [w for w in words if w not in stopwords and len(w) 1] return .join(words)len(w) 1这行会过滤掉单字财经文本里单字噪声大但如果你做的是细粒度分类比如「增持」和「减持」单字「增」「减」反而关键这时要把阈值改成 1。停用词表建议用哈工大或百度停用词表打底再手动加「公司」「公告」「股份」这类高频但无区分度的词。2.3 标注没有标签就没有分类源码里如果自带标注数据直接看标签体系如果没有你得自己标。上市公司新闻常见标签是「利好 / 利空 / 中性」三分类也有按事件类型分「并购 / 重组 / 业绩 / 监管」的。标注量建议每类至少 300 条起步少于这个数模型很难学到稳定边界。标注时最容易翻车的是「中性」类边界模糊一条「公司完成工商变更」到底算中性还是利好我的习惯是先定一份标注规则文档遇到争议就查规则保证同一批数据标注口径一致。3. 特征工程把新闻文本变成模型能吃的数字3.1 词袋、TF-IDF 与 N-gram 的取舍文本分类绕不开把词变成向量。最基础的是词袋模型统计每个词出现次数但高频词会淹没关键信息。TF-IDF 在此基础上加权降低常见词权重是财经新闻分类里性价比最高的方案。N-gram 能捕捉「业绩预增」这种双词组合但特征维度会爆炸一般设ngram_range(1,2)就够再高维度训练慢且容易过拟合。from sklearn.feature_extraction.text import TfidfVectorizer vectorizer TfidfVectorizer( max_features5000, # 只保留权重最高的5000个词 ngram_range(1, 2), # 兼顾单词和双词组合 min_df3, # 至少出现在3篇文档里才保留 max_df0.8 # 出现在80%以上文档的词丢弃 ) X vectorizer.fit_transform(corpus)max_features5000是经验值新闻语料几万条时够用语料更大可以提到 10000。min_df3过滤掉只出现一两次的稀有词减少噪声max_df0.8把「公司」「公告」这类几乎每篇都有的词踢掉它们对分类没贡献。3.2 词向量方案什么时候值得上TF-IDF 的短板是抓不住语义比如「亏损」和「巨亏」在它眼里是两个无关词。这时候可以上 Word2Vec 或预训练词向量把每个词映射成稠密向量再对整篇文档取平均或加权平均。但要注意财经领域用通用预训练词向量效果未必好因为「利好」「利空」这类词在通用语料里语义偏移。我的做法是先用 TF-IDF 跑基线如果准确率卡在 80% 上不去再考虑在自己的语料上训练 Word2Vec。from gensim.models import Word2Vec import numpy as np # 在自有语料上训练词向量 model Word2Vec(sentences, vector_size100, window5, min_count2, workers4) def doc_vector(words, model): 把一篇文档的所有词向量取平均 vecs [model.wv[w] for w in words if w in model.wv] return np.mean(vecs, axis0) if vecs else np.zeros(100)vector_size100是常见维度语料小于 10 万条时 100 维够用再大可以到 200。min_count2过滤低频词避免为只出现一次的词训练向量。取平均是最简单的文档向量化方式缺点是丢失词序但对新闻分类这种任务通常够用。3.3 特征拼接把数值特征也塞进去上市公司新闻往往还带结构化字段比如发布时间、股票代码、涨跌幅。这些数值特征可以和文本向量拼接一起送进模型。常见做法是用scipy.sparse.hstack把 TF-IDF 稀疏矩阵和归一化后的数值特征拼起来。注意数值特征要先做标准化否则量纲差异会让模型偏向大数值特征。4. 分类模型从朴素贝叶斯到 BERT 的选型路径4.1 基线模型朴素贝叶斯和线性 SVM别一上来就上深度学习。文本分类里朴素贝叶斯和线性 SVM 在几千条数据上经常能打到 85% 以上训练只要几秒。朴素贝叶斯假设特征独立虽然不成立但在短文本上表现意外地稳。线性 SVM 对高维稀疏特征友好是 TF-IDF 的黄金搭档。from sklearn.naive_bayes import MultinomialNB from sklearn.svm import LinearSVC from sklearn.metrics import classification_report # 朴素贝叶斯基线 nb MultinomialNB(alpha1.0) nb.fit(X_train, y_train) pred_nb nb.predict(X_test) print(classification_report(y_test, pred_nb)) # 线性SVM svm LinearSVC(C1.0, max_iter2000) svm.fit(X_train, y_train) pred_svm svm.predict(X_test) print(classification_report(y_test, pred_svm))alpha1.0是朴素贝叶斯的平滑参数数据稀疏时可以调小到 0.1。C1.0是 SVM 的正则强度C 越大越容易过拟合财经文本噪声多我一般从 0.5 开始试。max_iter2000防止不收敛报警如果还报就加到 5000。4.2 树模型与集成方法如果特征里混了数值字段树模型会更自然。随机森林和 LightGBM 能自动处理特征交互对缺失值也宽容。但纯文本 TF-IDF 高维稀疏树模型反而不如线性模型所以树模型更适合「文本向量 数值特征」拼接后的场景。import lightgbm as lgb clf lgb.LGBMClassifier( n_estimators300, learning_rate0.05, num_leaves31, objectivemulticlass, num_class3 ) clf.fit(X_train, y_train)num_leaves31控制树复杂度文本特征维度高时不要设太大否则过拟合。learning_rate0.05配合 300 棵树是稳妥组合想更快收敛可以提到 0.1 但容易震荡。4.3 什么时候该上 BERT当数据量过万、TF-IDF 加 SVM 准确率卡在 85% 以下、且业务对精度要求高时再考虑 BERT 微调。BERT 的优势是预训练阶段已经学了语义微调只需要少量标注数据。但代价是显存和训练时间一张 8G 显存的卡只能跑 batch_size 16 左右。常见做法是用bert-base-chinese做三分类微调学习率设 2e-5训练 3 到 5 个 epoch。from transformers import BertTokenizer, BertForSequenceClassification import torch tokenizer BertTokenizer.from_pretrained(bert-base-chinese) model BertForSequenceClassification.from_pretrained(bert-base-chinese, num_labels3) inputs tokenizer(texts, paddingTrue, truncationTrue, max_length128, return_tensorspt) labels torch.tensor(labels) outputs model(**inputs, labelslabels) loss outputs.lossmax_length128对新闻标题和短公告够用长公告要截断或分段。num_labels3对应三分类改成你的类别数即可。微调时学习率一定要小2e-5 是 BERT 微调的经典值设大了会灾难性遗忘。5. 避坑与排查新闻分类项目里最容易翻车的五件事5.1 标签泄漏准确率 99% 的假象现象模型在测试集上准确率 99%上线后一塌糊涂。原因训练集和测试集按时间随机划分同一篇新闻的标题和正文被分到两边或者标注时把答案词留在了文本里。解决按时间切分用较早的数据训练、较晚的数据测试检查文本里有没有直接暴露标签的词比如「利好」出现在正文里就要考虑剔除或替换。5.2 分词器加载自定义词典失败现象jieba.load_userdict报编码错误或词典不生效。原因词典文件不是 UTF-8 编码或者路径写成了相对路径但工作目录不对。解决统一用encodingutf-8保存词典路径用os.path.join拼绝对路径。加载后用jieba.lcut(测试词)验证是否切对。5.3 TF-IDF 在新数据上维度对不上现象训练时max_features5000预测时新文本向量维度变成 4800模型报错。原因每次fit_transform都会重新学词表预测时必须用训练时保存的 vectorizer。解决训练完用joblib.dump(vectorizer, tfidf.pkl)保存预测时joblib.load加载只调transform不调fit。5.4 类别不平衡导致模型只预测多数类现象中性新闻占 80%模型把所有样本都预测成中性准确率看着有 80% 但召回率为 0。原因损失函数被多数类主导。解决用class_weightbalanced让模型关注少数类或者对少数类过采样。评估时看 macro F1 而不是 accuracy。5.5 中文乱码从采集到训练一路的隐形杀手现象清洗后的文本全是问号或方块。原因采集时没设resp.encoding或者 CSV 保存时用了默认编码。解决采集后立刻resp.encoding resp.apparent_encoding保存 CSV 统一用encodingutf-8-sig这样 Excel 打开也不乱码。读文件时显式指定encodingutf-8不要依赖系统默认。6. 进阶技巧用交叉验证和错误分析把准确率再抬一截模型跑通只是起点真正拉开差距的是验证方法和错误分析。我一般不会只看一次 train_test_split 的结果而是用分层 K 折交叉验证确保每个折里类别比例一致。StratifiedKFold(n_splits5)是标配配合cross_val_score能快速看出模型稳不稳。from sklearn.model_selection import StratifiedKFold, cross_val_score skf StratifiedKFold(n_splits5, shuffleTrue, random_state42) scores cross_val_score(svm, X, y, cvskf, scoringf1_macro) print(5折F1:, scores.mean(), scores.std())scoringf1_macro比 accuracy 更适合类别不平衡场景random_state42保证每次划分一致方便对比不同模型。如果 std 超过 0.05说明模型对数据划分敏感要么加数据要么简化模型。错误分析是另一个被低估的环节。把预测错的样本导出来按真实标签和预测标签分组看经常能发现规律比如「减持」被预测成「中性」往往是因为文本里出现了「减持计划完成」这种中性表述。这时候要么补充这类样本要么在特征里加入「完成」「计划」这类关键词的权重。分析维度具体做法典型发现混淆矩阵看哪两类互相错利好和中性边界模糊错误样本词频统计错分样本高频词发现标注规则漏洞置信度分布看预测概率分布低置信样本集中某类最后说个习惯每次调完参数把配置和 F1 记到一张表里别靠脑子记。我吃过亏隔一周回来忘了哪组参数最好只能重跑。这份源码的价值不在于模型多复杂而在于把「数据清洗 → 特征 → 模型 → 验证」这条链路完整跑通你换一批新闻、改一套标签它就能变成你自己的工具。希望帮到你。本文还有配套的精品资源点击获取
返回列表