ChewYiSiang/sentiment-analysis-lazada

GitHub: ChewYiSiang/sentiment-analysis-lazada

这是一个基于Lazada用户评论训练的多类别情感分析项目,用于自动分类评论情感以支持产品反馈优化。

Stars: 0 | Forks: 0

# Lazada 应用评论 — 情感分析 一个基于 **775,000+ 条真实用户评论** 训练的多类别 NLP 情感分类器,数据来源于 Lazada 的 Google Play 商店页面。本项目涵盖了完整的机器学习流程:原始文本获取 → 探索性数据分析 → 预处理 → 特征工程 → 模型对比 → 最终模型选择 → 业务建议。 ## 目录 - [概述](#overview) - [数据集](#dataset) - [技术栈](#tech-stack) - [项目流程](#project-pipeline) - [模型与结果](#models--results) - [结果分析](#analysis-of-results) - [业务发现与建议](#business-findings--recommendations) - [关键挑战与解决方案](#key-challenges--solutions) - [项目结构](#project-structure) - [快速开始](#getting-started) ## 概述 **目标变量:** `sentiment` (由 `review_rating` 派生) - ⭐⭐⭐⭐–⭐⭐⭐⭐⭐ → 积极 - ⭐⭐⭐ → 中性 - ⭐–⭐⭐ → 消极 ## 数据集 | 属性 | 值 | |---|---| | 来源 | [Kaggle — Lazada App Reviews (Google Store)](https://www.kaggle.com/datasets/bwandowando/lazada-app-reviews-from-google-store/data) | | 行数 | 775,323 | | 使用的特征 | `review_text`, `review_rating` | | 日期范围 | 2013 – 2023 | | 类别分布 | 严重不平衡(积极占优:~81.6% 积极,~14.6% 消极,~3.9% 中性) | ## 技术栈 | 类别 | 库 | |---|---| | 数据处理 | `pandas`, `numpy` | | 可视化 | `matplotlib`, `seaborn`, `wordcloud` | | NLP 与文本 | `nltk`, `emoji`, `re` | | 特征工程 | `TF-IDF` (scikit-learn) | | 机器学习模型 | `scikit-learn`, `imbalanced-learn` | | 模型持久化 | `joblib` | ## 项目流程 ### 1. 探索性数据分析 (EDA) - 检查类别分布 — 发现 **严重的类别不平衡**:积极评论 (~81.6%) 在数据集中占压倒性优势,而中性评论极其稀少 (~3.9%)。 ![情感类别分布条形图 — 显示积极类别占主导地位](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/d25d53218b115920.png) - 分析评论文本长度分布(平均:7 词,最大:379 词);发现长篇幅、包含多种情感的评论可能会混淆分类器。 ![评论文本长度分布 — 右偏分布,平均约 7 词,尾部延伸至 379](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/11e7b0a21b115921.png) - 验证评论者偏差:确认没有单一作者发布超过 2 条评论,排除了个人层面的数据偏斜。 - 处理 `review_text` 中的缺失值(删除了 305 行空值)。 ### 2. 文本预处理 一个可复用的 `clean_text()` 函数按顺序执行以下步骤: | 步骤 | 技术 | 原理 | |---|---|---| | 小写转换 | `str.lower()` | 规范化词汇 | | 移除 URL / HTML / 提及 | `re.sub()` | 剥离非语义噪声 | | 移除数字 | `re.sub(r'\d+', '', ...)` | 移除订单号、日期 | | 移除标点符号 | `str.translate()` | 减少噪声 | | 表情符号转换 | `emoji.demojize()` | 将表情符号情感保留为文本 | | 重复字符规范化 | 正则表达式 `(.)\1{2,}` | "goooood" → "good" | | 分词 | `nltk.word_tokenize()` | 将文本拆分为词元 | | 移除停用词 | `nltk.corpus.stopwords` | 移除低信号功能词 | | 词形还原 | `WordNetLemmatizer` | 将屈折形式还原为词根 ("running" → "run") | ### 3. 特征工程 — TF-IDF 向量化 - 使用 **TF-IDF** (词频-逆文档频率) 将清洗后的文本转换为数值特征向量。 - 设置 `max_features=5000` 以限制词汇表大小,防止因罕见词过拟合。 - 设置 `ngram_range=(1, 2)` 以捕获单字词和双字词(例如,"not good" 被视为一个特征)。 ### 4. 类别不平衡处理 - 在逻辑回归和线性 SVM 中使用 `class_weight='balanced'` 来按比例惩罚少数类的误分类。 - 使用宏平均 F1 分数(平等对待所有类别)和准确率进行评估,以避免类别不平衡带来的误导性结果。 ### 5. 模型训练与超参数调优 - 使用 `stratify=y` 进行分层 70/30 训练-测试划分,以保持类别比例。 - 全程使用 Scikit-learn `Pipeline` 以防止数据泄漏(向量化器仅在训练数据上拟合)。 - **分层 K 折交叉验证** (5 折) 用于获得稳健、无偏的性能估计。 - 使用 **GridSearchCV** 对朴素贝叶斯和 SVM 进行超参数调优。 ## 模型与结果 在相同的预处理数据集上对三种分类器进行了基准测试: | 模型 | 准确率 | F1 宏平均 | F1 加权平均 | 备注 | |---|---|---|---|---| | 逻辑回归 | 0.7754 | 0.5898 | 0.8263 | 基线;`class_weight='balanced'` | | 多项式朴素贝叶斯 | 0.8996 | 0.5800 | 0.8840 | 通过 GridSearchCV 调优 (alpha, fit_prior) | | **线性 SVM (SGD) ✅** | **0.8943** | **0.6127** | **0.8864** | 最佳 F1 宏平均;通过 `SGDClassifier` 实现可扩展 SVM | **胜出者:线性 SVM 配合 TF-IDF (最佳 F1 宏平均:0.6127)** 线性 SVM 在宏平均 F1 上优于另外两种模型 — 这是在类别不平衡下最有意义的指标,因为它平等地对待三个类别。虽然朴素贝叶斯取得了最高的原始准确率 (0.8996),但由于中性类别的召回率较差,其 F1 宏平均较低 (0.5800)。线性 SVM 在三个类别之间取得了最佳平衡。 ![模型对比条形图 — 每个模型的 F1 宏平均、F1 积极、F1 消极、F1 中性](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/10c3707c93115922.png) 最佳流程被序列化保存为 `best_pipeline.pkl`,所有模型保存为 `all_models.pkl`,用于后续推理而无需重新训练。 ### 混淆矩阵 ![逻辑回归混淆矩阵](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/b04618129b115922.png) ![朴素贝叶斯混淆矩阵](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/abc68cfffa115923.png) ![线性 SVM 混淆矩阵](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/180ba2af23115924.png) ## 结析分析 ### 词云 — 用户在说什么? 下面的词云展示了文本预处理后积极和消极评论中最常出现的词语。 ![并排词云 — 积极评论(绿色,左)和消极评论(红色,右)](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/fe0e9a04f2115925.png) ### 最具区分性的词(逻辑回归系数) 逻辑回归系数揭示了哪些词最强烈地推动模型倾向于每个情感类别。与原始词频不同,这显示了*相对*的预测重要性。 ![每个类别(积极、中性、消极)的前 15 个最具区分性的词(逻辑回归系数)](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/e963817c74115926.png) ## 业务发现与建议 ### 整体情感分布 | 情感 | 占比 | |---|---| | 积极 | 81.6% | | 消极 | 14.6% | | 中性 | 3.9% | ### 主要发现 1. **整体满意度较高 (~81.6% 积极):** 大多数 Lazada 用户对应用评价良好,表明品牌认知基础稳固。 2. **消极评论集中在应用性能:** 消极情感的最具区分性词汇始终包括与崩溃、卡顿、错误和更新失败相关的术语。应用稳定性是主要痛点。 3. **中性类别最难建模 (F1 ~0.14–0.16):** 3 星评分并不能可靠地映射到中性语言。对于生产部署,二分类(积极 vs. 消极)将提供更可靠和可操作的结果。 4. **情感趋势可作为产品信号:** 消极评论量的激增与应用发布窗口相关。产品工程团队可以将其用作早期预警系统,以捕捉发布后的回退问题。 5. **线性 SVM 是最佳的轻量级模型**(在 F1 宏平均上)。训练好的流程可以在毫秒内对任何新评论进行评分,使用 `pipeline.predict([review_text])`。 ### 给 Lazada 的建议 | 优先级 | 措施 | 证据 | |---|---|---| | 高 | 调查应用更新中的崩溃/性能问题 | 消极情感的最具区分性词汇 | | 高 | 每次应用发布后监控每周消极评论占比 | 情感分布 | | 中 | 部署此流程用于实时评论标签 | 保存的 `best_pipeline.pkl` | | 中 | 对消极评论运行主题建模 (BERTopic/LDA) | 识别具体的特性投诉 | | 低 | 尝试二分类(积极 vs. 消极) | 中性类别不可靠 (F1 ~0.14) | ## 关键挑战与解决方案 | 挑战 | 解决方案 | |---|---| | **严重的类别不平衡** (积极 >> 中性) | 在逻辑回归和 SVM 中使用 `class_weight='balanced'` + 使用宏平均 F1 作为主要评估指标 | | TF-IDF 带来的**数据泄漏风险** | 将向量化器和分类器包装在 `sklearn.Pipeline` 中 | | **大型数据集** (775K 行) — SVC 太慢 | 用 `SGDClassifier(loss='hinge')` 替换 `SVC` — 等同于线性 SVM,线性扩展 | | **包含多种情感的长评论** | 词形还原 + TF-IDF 双字词以捕获短语级上下文 | | **嘈杂的非正式文本** (表情符号、俚语) | `emoji.demojize()` 保留表情符号情感;基于正则表达式的重复字符规范化 | ## 项目结构 ``` ├── Sentimental Analysis (Lazada).ipynb # Main notebook ├── LAZADA_REVIEWS.csv # Raw dataset (from Kaggle) ├── all_models.pkl # All trained model pipelines (joblib) ├── best_pipeline.pkl # Best model pipeline — Linear SVM (joblib) └── README.md ``` ## 快速开始 ``` # 安装依赖 pip install pandas numpy matplotlib seaborn scikit-learn nltk emoji wordcloud langdetect pip install transformers torch pip install sentencepiece pip install imbalanced-learn # 下载 NLTK 资源(首次运行) python -c "import nltk; nltk.download('stopwords'); nltk.download('punkt'); nltk.download('wordnet')" ``` 然后在 Jupyter 中打开 `Sentimental Analysis (Lazada).ipynb` 并运行所有单元格。 要直接加载并使用保存的最佳模型: ``` import joblib # 最佳模型管线(Linear SVM + TF-IDF) pipeline = joblib.load("best_pipeline.pkl") pipeline.predict(["This app keeps crashing, very frustrating"]) # ['negative'] pipeline.predict(["Great deals and fast shipping!"]) # ['positive'] ``` 要加载所有模型: ``` import joblib models = joblib.load("all_models.pkl") lr_pipeline = models["logistic"] nb_pipeline = models["naives_baye"] svm_pipeline = models["LinearSVC"] ``` ## 致谢 数据集来源于 [Kaggle — Lazada App Reviews (Google Store)](https://www.kaggle.com/datasets/bwandowando/lazada-app-reviews-from-google-store/data),由 bwandowando 提供。
标签:Apex, Google Play, imbalanced-learn, Lazada, matplotlib, nltk, numpy, pandas, Python, scikit-learn, seaborn, TF-IDF, 多类分类, 客户反馈分析, 情感分析, 探索性数据分析, 数据科学, 数据预处理, 文本分类, 文本挖掘, 无后门, 机器学习, 模型比较, 特征工程, 电商应用, 类别不平衡处理, 评论分析, 资源验证, 逆向工具