资讯详情

酒店中文评论情感分析实战:从TF-IDF到预训练模型的Python实现

📅 2026/9/28 15:10:15 | 华诺云谱 👁 阅读
酒店中文评论情感分析实战:从TF-IDF到预训练模型的Python实现
简介这是一套面向毕业设计场景的Python情感分析实战资源聚焦酒店中文评论的正负极性分类适合具备基础Python知识的本科生或自然语言处理入门者。资源包共2000个文件压缩后约7.47MB主要包含5个Python脚本、1份设计报告Word文档、csv汇总表及大量原始与处理后的txt数据。脚本依次实现语料预处理、分句分词、停用词过滤、词向量生成以及PCASVM建模预测txt数据覆盖2000条正向和2000条负向酒店评论的原始文本与切分结果。目前已有949人学习浏览。通过这套资源读者可以对照代码和数据复现完整实验流程理解从文本清洗、特征表示到分类器训练的每个环节设计报告可用于毕业设计文档参考中间产物与原始数据一一对应便于调试、修改和扩展后续实验。1. 酒店中文评论的情感分析这个毕设到底在做什么酒店中文评论的情感分析是自然语言处理里少有的“数据集好找、任务定义清楚、Python 生态全覆盖”的题目因此成了毕业设计里的常青树。它要解决的事情一句话能说清给定一条用户评论判断用户整体情绪是正向还是负向。但真动手你才会发现中文点评里的否定、反讽、口语新词会把一个“简单分类”搅得鸡飞狗跳。以下按我自己的落地顺序写先定数据和指标再跑通最小流水线然后讲我翻过车的坑最后补上预训练模型和验证技巧。想用它做毕设或练手项目的同学照这条路走能少熬两周夜。2. 先定任务再写代码数据口径和评价指标怎么立住很多同学一上来就装库、跑预训练模型结果答辩时被问“你的标签怎么来的”“为什么用准确率”就卡壳。情感分析的任务定义决定了后面所有环节这一章把数据来源、标签口径和评价指标讲清楚这些才是毕设论文里真正撑场面的部分。2.1 任务定位你要做的是“极性判断”不是情绪识别情感分析Sentiment Analysis在工程上通常落到文本分类输入一条评论文本输出情感极性。酒店场景最常见的形态是评分映射用户打了 1-5 星评论写了文字我们把星级当成弱标签。这里有个前提要先说明白星级和文字情绪并不完全一致。有人给四星但吐槽“电梯坏了”有人给三星但夸“前台态度好”。毕设阶段我们不做细粒度情感先把任务定成二分类好评/差评。映射规则我一般这样定4 星及以上为正向2 星及以下为负向3 星直接丢弃或单独做中性类。为什么丢 3 星而不是把它并进负向因为 3 星评论的语气往往模棱两可强行二分类会引入大量标注噪声模型学了也学不干净。如果你论文里想多写一个实验可以把 3 星保留做三分类作为对比实验的一部分但主线别放在三分类上。答辩时老师大概率会追问这个决策论文里把“丢弃 3 星”的理由写清楚反而是加分项。注意丢弃 3 星不是“数据不行就删”而是明确的实验设计报告里要写明删除量和理由。2.2 数据从哪来采集和公开数据集怎么取舍常见做法有两种。第一种是自己写 Python 爬虫去采集公开平台的评论美团、携程、去哪儿都有酒店点评页这类数据真实、时效性好但要注意对方的服务条款和反爬策略毕设场景下控制采集量、只做学术研究问题不大。第二种是直接用公开的酒店评论数据集网上流传的携程酒店评论语料之类的资源并不难找优点是已经按 1-5 星标好省去自己标注的功夫。我的建议是如果答辩要求里有“数据是自己采集的”那走爬虫路线规模控制在 6000-12000 条够用如果对数据来源没硬要求用公开数据能省两周时间把精力留给模型。无论哪种拿到的原始评论都要做三件事去重同一条文本被多次粘贴、去掉无意义占位文本比如“此用户未填写评价内容”、按用户 ID 和时间过滤明显重复刷评的数据。另外记得把采集结果结构化存成 CSV字段至少包含 id、评分、评论文本、评论时间。这里多说一句网上那些号称“免费 Python 源码大全”的二手 NLP 包一半以上依赖过期、路径写死拿来跑还不如从干净环境自己搭。数据同理二手数据集的标签口径往往不透明用之前先抽样看 20 条评论核对一下评分和文本是否匹配。2.3 数据量、类别平衡和样本划分酒店评论天然地不平衡好评通常占 70% 以上。如果直接拿原始分布训练模型很容易学成“无脑好评”准确率虚高差评几乎全错。处理办法有两个一是对好评做随机下采样让训练集正负比接近 1:1二是保留原始分布但在模型里加class_weightbalanced逻辑回归、SVM 都支持。我习惯先下采样再做训练因为后面上预训练模型的时候class_weight不是所有框架都方便传不如在数据层面就平衡掉。样本量方面二分类任务 4000 条以上就能跑出一个像样的基线模型8000 条以上再做深度模型会比较稳。不要盲目追求大数据量酒店评论的表达模式其实很集中“干净、位置好、服务态度好、性价比高”来回出现几千条足够覆盖 80% 的常见句式。如果采集到的数据差异很大比如不同城市、不同价位酒店混在一起建议先按属性分组统计一下避免模型只学到“高档酒店好评多”这种无关规律。2.4 评价指标准确率是最没信息量的一个数字二分类且类别不平衡的任务里准确率accuracy会骗人全预测好评都有 70% 的准确率。所以主指标要用宏平均 F1macro-F1再加上混淆矩阵。差评的召回率尤其重要答辩时老师一定问“你的模型对差评的识别能力怎么样”。精确率、召回率、F1 用classification_report一键输出后面第三章的代码里有。另一个额外指标可以选 ROC-AUC但对类别不平衡且样本量中等的情况它不如 F1 直观论文里写清楚你用什么做主指标、为什么比堆指标更有说服力。3. 用 Python 跑通最小可复现流水线清洗、分词、特征、训练第三章是能直接抄作业的部分。我的原则是先跑通一个最小闭环再用多长的时间去换更好的模型。下面 5 个小节对应 5 个步骤每一步都给出代码、逻辑说明和参数含义。3.1 环境准备依赖和项目结构先交代环境Python 3.9 以上就行IDE 用你顺手的即可vscode 或 pycharm 都行关键是虚拟环境要干净。新建一个项目目录至少分data/、src/、output/三个文件夹。依赖我列一个最小集合其余用到再装pip install pandas numpy jieba scikit-learn matplotlib说明jieba 做中文分词scikit-learn 提供 TF-IDF 和分类器pandas 做数据读取和清洗matplotlib 最后画图用。如果后面要用预训练模型再单独加 transformers 和 torch不要一开始就把重依赖装进来省得环境出问题排查半天。3.2 读取数据与文本清洗假设你已经有一份 CSV字段至少包含 label0/1和 text原始评论。清洗这一步经常被低估但它的影响比换模型还大。import re import pandas as pd df pd.read_csv(data/hotel_reviews.csv) def clean_review(text: str) - str: if not isinstance(text, str): return # 去掉 HTML 标签点评页爬下来的文本常有残留 text re.sub(r[^], , text) # 去掉 URL text re.sub(rhttp\S|www\.\S, , text) # 压缩多余空白 text re.sub(r\s, , text).strip() return text df[clean_text] df[text].apply(clean_review) df df[df[clean_text].str.len() 4] # 太短的文本没有判别意义逻辑说明三个正则分别处理三样东西——HTML 标签爬虫常见残留、链接、以及多余空白。最后一行过滤掉长度不足 4 个字符的评论这类文本大多是“不错”“太差”这种极短评价保留反而会放大噪声。清洗之后记得打印几条看看确认没有把有效内容误删。3.3 分词与停用词中文 NLP 的第一道坎分词用 jieba它对点评类短文本的默认效果已经不错。停用词表我不用网上那种几百词的大表而是自己维护一份小的里面只放标点、语气助词、无意义的量词。import jieba import re stopwords set([的, 了, 是, 在, 就, 都, 也, 还, 有, 非常, 比较, 很, 毕竟, 反正, 然后]) def seg_review(text: str) - str: words jieba.lcut(text) # 过滤停用词、纯标点符号 words [w for w in words if w.strip() and w not in stopwords and not re.fullmatch(r[\W_], w)] return .join(words) df[seg_text] df[clean_text].apply(seg_review)逻辑说明jieba.lcut返回词列表 .join把分词结果拼成以空格分隔的字符串这样可以直接喂给 TF-IDF 的默认 tokenizer。特别注意停用词表里我没有删“不、没、别、太、这么”这些词的删与不删会直接影响情感极性的判断第四章第一坑就是栽在这上面。这里删掉的“非常、比较”属于程度副词不是极性词留着只会给特征空间加噪声。提示第一次跑通后强烈建议随机打印 20 条分词结果检查一遍再往下走。分词和清洗阶段的错误后面模型再强也救不回来。3.4 特征化与基线模型TF-IDF 逻辑回归情感分类的基线模型我强烈推荐 TF-IDF 逻辑回归LogisticRegression。它训练快几千条数据几秒钟、系数可解释直接看哪些词推正向、哪些词推负向、而且效果不差作为答辩时的对比基线无可挑剔。from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.linear_model import LogisticRegression from sklearn.pipeline import make_pipeline from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( df[seg_text], df[label], test_size0.2, random_state42, stratifydf[label] ) pipe make_pipeline( TfidfVectorizer( tokenizerlambda x: x.split( ), ngram_range(1, 2), max_features20000 ), LogisticRegression(C1.0, max_iter1000, class_weightbalanced) ) pipe.fit(X_train, y_train)参数说明ngram_range(1, 2)会把相邻两个词拼成二元特征能部分缓解否定词被切碎的问题max_features20000限制词表规模防止出现频率过低的噪声词进入模型class_weightbalanced自动放大少数类权重。C1.0是正则强度的默认值如果过拟合训练集 F1 远高于测试集就调小比如 0.5 或 0.1。tokenizerlambda x: x.split( )直接按空格切分因为我们前面已经分词并用空格连接好了。3.5 评估别只看准确率from sklearn.metrics import classification_report, confusion_matrix y_pred pipe.predict(X_test) print(classification_report(y_test, y_pred, target_names[negative, positive])) print(confusion_matrix(y_test, y_pred))逻辑说明classification_report会输出正向和负向各自的精确率、召回率、F1。重点看 negative 行的 recall它衡量的是差评能找回多少这才是情感分析在不平衡场景下的核心指标。如果 negative recall 低于 0.7建议先回到数据层面做平衡而不是急着换模型。混淆矩阵的四格一看就懂左上角是负向预测对的数量右下角是正向预测对的数量右上角和左下角分别是两类错误。4. 排查中文评论情感分析的 5 个典型翻车现场现象、原因、解决办法这一章写我实际踩过的坑一条条按“现象 → 原因 → 修复”来。每条都能对应你跑实验时可能遇到的崩溃瞬间也是论文“实验分析”部分最好写的素材。4.1 否定词被停用词表删掉差评全变好评现象训练完后模型对“服务不怎么样”“卫生不太好”这类评论全部判成正向negative 召回率惨不忍睹。原因我把网上抄来的通用停用词表直接用了那张表里赫然列着“不、没、别、太、很”。这些是否定词和程度词是判断极性最关键的信息删掉之后特征空间里只剩“服务、卫生、好、满意”这些正面词。修复停用词表一定要自己维护只删标点和语气词。更稳的做法是分词后让二元特征把“不”和后面的词拼起来ngram_range(1, 2)已经能覆盖“不/满意”这类组合。如果你的分词把“不怎么样”切成“不/怎么样”二元特征就是“不_怎么样”同样能表达否定。4.2 训练集和测试集来源不同模型当场崩掉现象用公开数据集训练的表现挺好macro-F1 0.9换到我自己采集的 2000 条评论上测试macro-F1 直接掉到 0.6。原因两个来源的评论风格、平台话术、时间跨度都不一样。公开数据集大多是几年前的文本句式和用词跟新采集的有明显差异更隐蔽的是评分口径不同有的平台 3 星算中评有的平台 3 星算差评标签对齐本身就出错了。修复要么全部用自己的数据要么至少保证测试集和训练集来自同一平台、同一时间段。交叉验证时用 KFold 按时间或按用户分组切分而不是完全随机切分这样评估结果更接近真实使用场景。4.3 过长评论被截断关键信息在尾巴上现象预训练模型的输入长度超过max_length时被直接截断训练集 F1 高但测试集不稳定badcase 里很多长评论的判断是错的。原因酒店点评虽然平均只有几十个字但冷门长评论能到 300 字以上。常见配置max_length128截断时默认从头保留、从尾丢弃而很多吐槽的重点恰恰在最后一句比如“总之不会再来了”。修复先统计语料长度分布df[clean_text].str.len().describe()看 95 分位占比超过 95% 的文本长度就是合理值一般是 128 或 256。如果必须截断可以改成保留头部加尾部各一半或者用 TextRank 先抽出关键句再喂模型但这属于加分项不是必做。4.4 类别不平衡导致“无脑好评”差评召回率 0现象训练完打印分类报告negative 的 recall 是 0.00positive 是 1.00但 accuracy 高达 85%答辩老师一看混淆矩阵就皱眉头。原因原始数据好评占 80% 以上模型学到的先验就是“全都预测好评”损失函数里正确率已经很高优化器没动力去改。修复两个手段叠加。数据层面做下采样让训练集正负比接近 1:1模型层面加class_weightbalanced。测试集不要动保持真实的自然分布这样评估出来的 F1 才有参考意义。两组实验都要在报告里写一组是原始分布一组是平衡后分布对比着讲“类别不平衡带来的影响”。4.5 jieba 词典不认识新词口语化表达被切得稀碎现象“房间巨吵”被切成“房间/巨/吵”“价格小贵”被切成“价格/小/贵”“yyds”直接变单字模型对这些文本的预测基本靠猜。原因jieba 的默认词典是通用语料统计出来的对点评里的口语化新词、网络热词覆盖很差。修复维护一份自定义词典hotel_words.txt每行一个词格式是“词 词频 词性”词频给 1 就够让 jieba 尽量保留整词巨吵 1 小贵 1 yyds 1 隔音差 1 性价比高 1然后在分词前执行jieba.load_userdict(data/hotel_words.txt)。加载后先打印两条评论看分词结果确认词典生效。自定义词典别贪多30-50 个高频的领域词就够加太多会把正常词组切开反而产生新噪声。5. 从基线到加分项对比实验、预训练模型和可视化第四章把坑填平之后你的基线模型应该已经能用了。这一章讲怎么把它升级成一个“能拿出去答辩”的方案对比实验怎么设计预训练模型怎么最小接入可视化怎么做最后怎么把模型包装成交付物。5.1 为什么必须做对比实验基线怎么搭毕设答辩的经典问题是“你的模型为什么比 baseline 好”。没有对比实验这个问题的答案只能是“我不知道”。实验设计至少要三档规则/词典基线用常见中文情感词典对评论句子打分正分判好评、负分判差评机器学习基线第三章的 TF-IDF 逻辑回归再加一个朴素贝叶斯或 SVM 都可以深度模型TextCNN 或 BiLSTM加分项可以上 BERT。下面是我在类似任务上见过的经验范围不是严格基准用来帮你判断自己的结果是不是正常区间模型训练时间量级macro-F1 常见区间是否可解释情感词典规则秒级0.62-0.70是TF-IDF 逻辑回归秒级0.82-0.88是TextCNN分钟级0.83-0.89部分BERT-base小时级0.88-0.93部分注意这个表的含义传统机器学习不一定被深度学习碾压尤其在几千条数据的小任务上TF-IDF LR 往往和 TextCNN 打成平手。答辩时把这个表做出来能讲清楚“深度模型在这个任务上并没有绝对优势成本反而更高”这是一个有价值的独立结论。5.2 预训练模型的最小接入方案如果想让毕设有一个技术亮点我建议用 Hugging Face transformers 的 AutoModelForSequenceClassification以 bert-base-chinese 为例代码骨架from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer AutoTokenizer.from_pretrained(bert-base-chinese) model AutoModelForSequenceClassification.from_pretrained( bert-base-chinese, num_labels2 ) def tokenize_fn(texts): return tokenizer(texts, truncationTrue, paddingmax_length, max_length128) train_encodings tokenize_fn(X_train.tolist())参数说明max_length128按第四章第 3 条的长度统计来定truncationTrue截断超长文本paddingmax_length把样本补齐到同样长度显存小就用 128 而不是 256。tokenizer 的输出是 input_ids 和 attention_mask两者都要喂给模型。训练参数的核心手感learning_rate 用 2e-5 到 5e-5我习惯 2e-5 起步batch_size 显存不够就 8能上 16 就 16epoch 设 2 到 3 个几千条数据 2 个 epoch 就够多了必过拟合。没钱没卡的同学不用慌小数据集上 CPU 也能硬跑 BERT就是慢几倍提前把数据预处理和结果评估准备好训练环节剩下的就是等。5.3 数据可视化词云、分布图和属性维度Python 数据分析与可视化这一环是毕设报告里最出效果的。常见三项情感分布饼图统计预测结果里正负向占比词云分开生成好评词云和差评词云看高频词差异属性维度对比把评论按关键词分组卫生、位置、服务、设施、价格分别算情感得分出一条横向柱状图。WordCloud 的坑在字体。中文字体需要指定font_pathWindows 一般用 simhei.ttfLinux 可以用系统自带的文泉驿字体。代码骨架from wordcloud import WordCloud import matplotlib.pyplot as plt wc WordCloud( font_pathC:/Windows/Fonts/simhei.ttf, # Linux/mac 换成自己环境里的中文字体 width800, height600, background_colorwhite ) wc.generate( .join(positive_words)) plt.imshow(wc) plt.axis(off) plt.savefig(output/positive_wordcloud.png, dpi150)说明positive_words是从所有被预测为好评的评论里收集的词语列表。词云只能做“高频词分布”的直观展示不能当分析结论报告里一定要配统计数字一起写否则答辩老师的下一个问题就是“这词云能说明什么”。5.4 把模型包装成能演示的东西毕设交付一般有两种形式一是论文加实验记录二是可演示的小系统。如果你选第二种别上大框架FastAPI 或 Flask 起一个单接口就够了这里给 FastAPI 的最小例子from fastapi import FastAPI app FastAPI() def predict_one(text: str): seg .join(seg_review(text)) label int(pipe.predict([seg])[0]) prob pipe.predict_proba([seg])[0].tolist() return {label: label, prob: prob} app.post(/sentiment) def sentiment(text: str): return predict_one(text)说明predict_proba返回两个类别的概率调试和演示都比只看 label 有用。FastAPI 起服务后在本地浏览器访问 /docs 就能直接测试接口答辩现场演示很方便。如果你不想写服务也可以用 streamlit 写一个上传 CSV 批量打分的页面工作量不大效果更直观。6. 验证模型是不是“真的有用”混淆矩阵、badcase 复议和一个小习惯6.1 先看 badcase再谈调参我每次训练完第一步不是看 F1而是把预测错的样本前 50 条拉出来打印import pandas as pd result pd.DataFrame({text: X_test, true: y_test, pred: y_pred}) bad result[result[true] ! result[pred]] print(bad.head(50)[text].to_string())你马上会发现两类问题一类是标签错了用户三星说“还行”你标成负向这类不用改模型回去修正标注一类是文本里出现了训练集没见过的表达比如“拉胯”“踩雷”这类才需要补词典或加数据。数据修复的性价比永远高于模型调参。6.2 用最简单的方式验证稳定性好的验证不是测试集上跑一次而是多次切分取均值。我习惯用 5 折交叉验证from sklearn.model_selection import cross_val_score scores cross_val_score(pipe, df[seg_text], df[label], cv5, scoringf1_macro) print(macro-F1: %.4f ± %.4f % (scores.mean(), scores.std()))标准差小于 0.02 说明模型稳定如果波动很大多半是数据量不足或类别分布不稳先回去加数据而不是继续调参。多年做文本任务的教训是把 badcase 样本攒成一个固定文件每次模型迭代后都对着同一个 badcase 集合看“哪些被修好了哪些还在错”。分数是会骗人的坏样本不会。多模态情感分析确实很火但毕设做到文本单模态的“可解释、可复现、坑都讲得清”已经比堆一堆说不清的黑匣子模型强得多。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑