温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片!
1. 项目背景与意义
随着互联网和移动互联网的快速发展,越来越多的游客在出行前会通过携程、美团、马蜂窝等在线旅游平台浏览景区评论,以此作为决策参考。景区评论中蕴含着大量游客对景点、服务、交通、餐饮等方面的主观感受,这些非结构化的文本数据规模庞大、更新迅速,仅靠人工阅读难以高效提取有价值的信息。
情感分析(Sentiment Analysis)是自然语言处理领域的重要研究方向,其目标是从文本中自动识别和提取主观信息,判断文本所表达的情感倾向(正面、负面或中性)。将情感分析技术应用于景区评论,可以帮助景区管理者快速掌握游客满意度、发现服务短板、优化运营策略,也可以为潜在游客提供直观的参考依据。
传统的情感分析方法多依赖情感词典和人工设计特征,存在覆盖不全、泛化能力弱等问题。近年来,基于深度学习的文本分类方法在情感分析任务上取得了显著效果。其中,长短期记忆网络(LSTM)因其能够有效捕捉文本序列中的长距离依赖关系,被广泛应用于情感分析任务。本项目基于LSTM算法构建景区评论情感分析模型,并在此基础上开发一个可视化应用系统,实现从数据采集、模型训练到结果展示的完整流程。
2. 系统技术栈
本系统采用前后端分离架构,整体技术栈如下:
| 层次 | 技术选型 | 说明 |
|---|---|---|
| 前端 | Vue.js + Element UI + ECharts | 负责页面展示、交互和可视化图表渲染 |
| 后端 | Python + Flask | 提供RESTful API接口,承载模型推理和业务逻辑 |
| 深度学习框架 | TensorFlow / Keras | 用于LSTM模型的构建、训练和预测 |
| 数据处理 | Pandas + NumPy + Jieba | 负责数据清洗、分词、向量化等预处理工作 |
| 数据库 | MySQL | 存储景区评论原始数据、分析结果和用户信息 |
| 开发环境 | Python 3.8 + Anaconda | 统一依赖管理和运行环境 |
前端通过Axios向后端发送请求,后端调用训练好的LSTM模型对评论进行情感预测,并将结果返回前端进行可视化展示。系统整体流程包括数据采集、数据预处理、模型训练、情感预测和结果可视化五个模块。
3. 系统总体设计
系统整体架构分为数据层、模型层和应用层三个部分。数据层负责评论数据的采集与存储;模型层完成文本预处理、LSTM模型训练与评估;应用层面向用户提供评论情感分析、统计报表和可视化图表等功能。
系统核心业务流程如下:
flowchart TD A[景区评论数据采集] --> B[数据清洗与去重] B --> C[Jieba分词] C --> D[Word2Vec词向量化] D --> E[构建LSTM模型] E --> F[模型训练与评估] F --> G[模型保存] G --> H[Flask后端服务] H --> I[前端可视化展示] I --> J[情感分析结果统计]4. 核心代码实现
4.1 数据预处理
数据预处理是情感分析的基础环节,主要包括评论去重、去除噪声字符、分词和停用词过滤等操作。以下代码展示了基于Pandas和Jieba的预处理流程:
import pandas as pd import jieba import re 加载停用词表 def load_stopwords(path="stopwords.txt"): with open(path, "r", encoding="utf-8") as f: stopwords = [line.strip() for line in f.readlines()] return set(stopwords) stopwords = load_stopwords() def clean_text(text): # 去除HTML标签和特殊字符 text = re.sub(r"<[^>]+>", "", text) text = re.sub(r"[^\u4e00-\u9fa5a-zA-Z0-9]", " ", text) return text def seg_sentence(text): text = clean_text(text) words = jieba.lcut(text) # 过滤停用词和单字 words = [w for w in words if w.strip() and w not in stopwords and len(w) > 1] return " ".join(words) 读取原始评论数据 df = pd.read_csv("scenic_comments.csv", encoding="utf-8") df["cleaned"] = df["comment"].apply(seg_sentence) print(df.head())4.2 词向量化与序列填充
LSTM模型无法直接处理文本,需要将分词后的评论转换为词向量序列。本项目使用Word2Vec预训练词向量,并对序列进行定长填充:
from gensim.models import Word2Vec import numpy as np from tensorflow.keras.preprocessing.sequence import pad_sequences 训练Word2Vec词向量模型 sentences = [line.split() for line in df["cleaned"].tolist()] w2v_model = Word2Vec(sentences, vector_size=128, window=5, min_count=1, workers=4) 构建词索引映射 word_index = {word: idx + 1 for idx, word in enumerate(w2v_model.wv.index_to_key)} vocab_size = len(word_index) + 1 embedding_dim = 128 将评论转换为索引序列 def text_to_sequence(text): words = text.split() return [word_index.get(w, 0) for w in words] df["seq"] = df["cleaned"].apply(text_to_sequence) 定长填充 max_len = 100 X = pad_sequences(df["seq"].tolist(), maxlen=max_len, padding="post") y = df["label"].values # 标签:1表示正面,0表示负面 构建嵌入矩阵 embedding_matrix = np.zeros((vocab_size, embedding_dim)) for word, idx in word_index.items(): if word in w2v_model.wv: embedding_matrix[idx] = w2v_model.wv[word] print("训练数据形状:", X.shape, "标签形状:", y.shape)4.3 LSTM模型构建与训练
模型采用Embedding层加双向LSTM层加全连接层的结构,使用Dropout防止过拟合,损失函数选用二分类交叉熵:
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout, Bidirectional from tensorflow.keras.optimizers import Adam from sklearn.model_selection import train_test_split 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) 构建LSTM模型 model = Sequential() model.add(Embedding( input_dim=vocab_size, output_dim=embedding_dim, weights=[embedding_matrix], input_length=max_len, trainable=False )) model.add(Bidirectional(LSTM(128, return_sequences=False, dropout=0.3))) model.add(Dense(64, activation="relu")) model.add(Dropout(0.3)) model.add(Dense(1, activation="sigmoid")) model.compile( optimizer=Adam(learning_rate=0.001), loss="binary_crossentropy", metrics=["accuracy"] ) 模型训练 history = model.fit( X_train, y_train, batch_size=64, epochs=20, validation_data=(X_test, y_test), verbose=1 ) 保存模型 model.save("lstm_sentiment_model.h5") print("模型训练完成并已保存")4.4 模型评估
训练完成后,在测试集上评估模型的准确率、精确率、召回率和F1值:
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix 预测 y_pred_prob = model.predict(X_test) y_pred = (y_pred_prob > 0.5).astype(int) 计算评估指标 accuracy = accuracy_score(y_test, y_pred) precision = precision_score(y_test, y_pred) recall = recall_score(y_test, y_pred) f1 = f1_score(y_test, y_pred) print(f"准确率: {accuracy:.4f}") print(f"精确率: {precision:.4f}") print(f"召回率: {recall:.4f}") print(f"F1值: {f1:.4f}") 混淆矩阵 cm = confusion_matrix(y_test, y_pred) print("混淆矩阵:") print(cm)4.5 Flask后端接口
后端使用Flask提供评论情感分析接口,加载训练好的模型和词向量,接收前端传入的评论文本并返回情感预测结果:
from flask import Flask, request, jsonify from tensorflow.keras.models import load_model from tensorflow.keras.preprocessing.sequence import pad_sequences import jieba import re app = Flask(name) 加载模型和词向量 model = load_model("lstm_sentiment_model.h5") w2v_model = Word2Vec.load("w2v_model.model") word_index = {word: idx + 1 for idx, word in enumerate(w2v_model.wv.index_to_key)} max_len = 100 def preprocess_comment(text): # 清洗和分词 text = re.sub(r"[^\u4e00-\u9fa5a-zA-Z0-9]", " ", text) words = [w for w in jieba.lcut(text) if w.strip() and len(w) > 1] seq = [word_index.get(w, 0) for w in words] return pad_sequences([seq], maxlen=max_len, padding="post") @app.route("/api/predict", methods=["POST"]) def predict(): data = request.get_json() comment = data.get("comment", "") if not comment: return jsonify({"error": "评论内容不能为空"}), 400 X_input = preprocess_comment(comment) prob = model.predict(X_input)[0][0] sentiment = "正面" if prob > 0.5 else "负面" confidence = float(prob) if prob > 0.5 else float(1 - prob) return jsonify({ "comment": comment, "sentiment": sentiment, "confidence": round(confidence, 4) }) if name == "main": app.run(host="0.0.0.0", port=5000, debug=True)4.6 前端可视化展示
前端使用Vue.js和ECharts实现情感分析结果的可视化展示,包括情感分布饼图、评论数量趋势图和Top景区满意度排行等。以下为核心组件代码:
<template> <div class="dashboard"> <el-card class="chart-card"> <div slot="header">情感分布统计</div> <div ref="pieChart" style="height: 320px"></div> </el-card> <el-card class="chart-card"> <div slot="header">景区满意度排行</div> <div ref="barChart" style="height: 320px"></div> </el-card> </div> </template> <script> import * as echarts from "echarts"; import axios from "axios"; export default { name: "Dashboard", data() { return { stats: { positive: 0, negative: 0, neutral: 0 }, ranking: [] }; }, mounted() { this.fetchStats(); this.initCharts(); }, methods: { async fetchStats() { const res = await axios.get("/api/stats"); this.stats = res.data.stats; this.ranking = res.data.ranking; this.renderCharts(); }, initCharts() { this.pieChart = echarts.init(this.$refs.pieChart); this.barChart = echarts.init(this.$refs.barChart); }, renderCharts() { this.pieChart.setOption({ tooltip: { trigger: "item" }, series: [{ type: "pie", radius: "65%", data: [ { value: this.stats.positive, name: "正面评价" }, { value: this.stats.negative, name: "负面评价" }, { value: this.stats.neutral, name: "中性评价" } ] }] }); this.barChart.setOption({ tooltip: { trigger: "axis" }, xAxis: { type: "category", data: this.ranking.map(item => item.name) }, yAxis: { type: "value", name: "满意度得分" }, series: [{ type: "bar", data: this.ranking.map(item => item.score), itemStyle: { color: "#409EFF" } }] }); } } }; </script>5. 系统功能与应用价值
本系统主要提供以下功能:
- 评论情感分析:输入任意景区评论文本,实时返回情感倾向(正面或负面)及置信度。
- 批量评论处理:支持上传CSV文件批量分析景区评论,并导出分析结果。
- 可视化统计报表:以饼图、柱状图、折线图等形式展示情感分布、评论趋势和景区满意度排行。
- 景区对比分析:支持多景区横向对比,帮助管理者定位服务短板。
该系统可应用于景区管理部门、旅游平台运营方和文旅研究机构。通过持续监测游客评论情感变化,景区可以及时发现问题并改进服务,提升游客满意度和景区口碑,具有较高的实用价值和推广意义。
6. 总结与展望
本项目基于LSTM算法实现了景区评论情感分析系统,完整覆盖了数据采集、预处理、模型训练、接口开发和可视化展示等环节。实验结果表明,LSTM模型能够有效捕捉评论文本中的语义信息,在情感分类任务上取得了较好的准确率。
后续可以从以下方向进行优化:一是引入BERT等预训练语言模型进一步提升分类效果;二是增加情感细粒度分析,识别评论中关于不同维度(如交通、餐饮、卫生)的情感倾向;三是结合时间序列分析,挖掘景区口碑的长期变化趋势,为管理决策提供更全面的数据支撑。