# 航空推文情感分析系统


> **机器学习 (Python) 课程设计**


## 👥 团队成员


| 姓名 | 学号 | 贡献 |
|------|------|------|
| 张则文 | 2311020133 | 数据处理、模型训练、Agent 开发、Streamlit开发与测试、文档撰写 |
| 潘俊康 | 2311020121 | 仓库搭建、Streamlit测试、文档撰写、项目报告 |
| 陈俊均 | 2311020104 | Agent 开发、Streamlit开发与测试、文档撰写 |


## 📝 项目简介


本项目是一个基于**传统机器学习 + LLM + Agent**的航空推文情感分析系统，旨在实现可落地的智能预测与行动建议。系统使用 Twitter US Airline Sentiment 数据集，通过传统机器学习完成推文情感的量化预测，再利用 LLM 和 Agent 技术将预测结果转化为结构化、可执行的决策建议，确保输出结果可追溯、可复现。


## 🚀 快速开始


```bash
# 克隆仓库
git clone http://hblu.top:3000/MachineLearning2025/G05-Sentiment-Analysis-of-Aviation-Tweets.git
cd G05-Sentiment-Analysis-of-Aviation-Tweets

# 安装依赖
pip install uv -i https://mirrors.aliyun.com/pypi/simple/
uv config set index-url https://mirrors.aliyun.com/pypi/simple/
uv sync

# 配置环境变量
cp .env.example .env
# 编辑 .env 填入 API Key

# 运行 Demo
uv run streamlit run src/streamlit_tweet_app.py
```


## 1️⃣ 问题定义与数据


### 1.1 任务描述


本项目是一个三分类任务，目标是自动识别航空推文的情感倾向（negative/neutral/positive）。业务目标是构建一个高准确率、可解释的推文情感分析系统，帮助航空公司及时了解客户反馈，优化服务质量，提升客户满意度。


### 1.2 数据来源


| 项目 | 说明 |
|------|------|
| 数据集名称 | Twitter US Airline Sentiment |
| 数据链接 | [Kaggle](https://www.kaggle.com/datasets/crowdflower/twitter-airline-sentiment) |
| 样本量 | 14,640 条 |
| 特征数 | 15 个 |


### 1.3 数据切分与防泄漏


数据按 8:2 比例分割为训练集和测试集，确保模型在独立的测试集上进行评估。在数据预处理和特征工程阶段，所有操作仅在训练集上进行，避免信息泄漏到测试集。使用 TF-IDF 进行文本向量化时，同样严格遵循先训练后应用的原则。


### 1.4 数据转换流程


原数据集转换为处理后数据集主要经过以下步骤：

#### 1. 数据加载
从 `Tweets.csv` 读取原始数据，包含以下字段：
- `tweet_id` - 推文ID
- `airline_sentiment` - 情感标签
- `airline_sentiment_confidence` - 情感置信度
- `negativereason` - 负面原因
- `negativereason_confidence` - 负面原因置信度
- `airline` - 航空公司
- `text` - 原始推文文本
- 其他元数据字段（坐标、时间、位置等）

#### 2. 数据筛选
- **置信度过滤**：仅保留 `airline_sentiment_confidence >= 0.5` 的样本
- 确保情感标签的可靠性

#### 3. 文本清洗
遵循"克制"原则，仅进行必要的预处理：

**移除的内容：**
- 用户提及：`@username`
- URL 链接：`http://...` 或 `www...`
- 多余空格和换行符

**保留的内容：**
- 表情符号（对情感分析有价值）
- 标点符号（表达情绪强度）
- 否定词（如 "not", "don't"）
- 原始大小写（后续统一小写）

**不进行的处理：**
- 不进行词形还原（lemmatization）
- 不进行词干提取（stemming）
- 不删除停用词（否定词对情感很重要）

#### 4. 文本标准化
- 统一转换为小写
- 保留语义信息

#### 5. 数据清理
- 删除 `text_cleaned` 为空的样本
- 删除 `airline_sentiment` 为空的样本
- 基于 `tweet_id` 去重

#### 6. 字段选择
最终保留的列：
```python
["tweet_id", "airline_sentiment", "airline_sentiment_confidence", 
 "negativereason", "negativereason_confidence", "airline", 
 "text_cleaned", "text_original"]
```

#### 7. 数据验证
使用 Pandera Schema 进行严格校验：
- `airline_sentiment` 必须是 `["positive", "neutral", "negative"]`
- `airline` 必须是 `["Virgin America", "United", "Southwest", "Delta", "US Airways", "American"]`
- 所有必需字段不允许缺失值

#### 8. 数据保存
保存到 `data/Tweets_cleaned.csv`

#### 清洗示例对比

**原始文本：**
```
@United This is the worst airline ever! My flight was delayed for 5 hours...
```

**清洗后文本：**
```
this is the worst airline ever! my flight was delayed for 5 hours...
```

可以看到，用户提及 `@United` 被移除，文本转为小写，但保留了感叹号、否定词和语义信息。


## 2️⃣ 机器学习流水线


### 2.1 模型架构


本项目采用 **VotingClassifier** 集成学习方法，结合多个基础分类器的优势：

- **逻辑回归 (Logistic Regression)**：线性模型，适合处理高维稀疏特征
- **多项式朴素贝叶斯 (MultinomialNB)**：适合文本分类任务
- **随机森林 (RandomForestClassifier)**：集成树模型，抗过拟合能力强
- **LightGBM 分类器**：梯度提升树模型，高性能、高效率


### 2.2 模型性能


| 模型 | 指标 | 结果 |
|------|------|------|
| VotingClassifier | 准确率 | 0.8159 |
| VotingClassifier | F1 分数（Macro） | 0.7533 |


### 2.3 特征工程


#### 2.3.1 文本特征提取（TF-IDF 向量化）

使用 TF-IDF（Term Frequency-Inverse Document Frequency）将文本转换为数值特征向量。具体配置如下：

| 参数 | 值 | 说明 |
|------|-----|------|
| `max_features` | 15000 | 保留最重要的 15,000 个特征（词或词组），避免维度灾难和过拟合 |
| `ngram_range` | (1, 3) | 考虑 1-gram（单词）、2-gram（双词组）、3-gram（三词组），捕捉上下文关系 |
| `min_df` | 2 | 词至少在 2 个文档中出现才保留，过滤噪声词 |
| `max_df` | 0.95 | 词最多出现在 95% 的文档中，过滤停用词 |
| `lowercase` | False | 保留原始大小写，保留情感强度信息 |
| `sublinear_tf` | True | 使用次线性缩放（1 + log(TF)），平衡词频影响 |

**TF-IDF 参数详解：**

- **max_features=15000**：从所有可能的词和词组中，选择 TF-IDF 值最高的 15,000 个作为特征，其余被丢弃。限制特征数量可以提高训练速度并避免过拟合。

- **ngram_range=(1, 3)**：考虑从 1-gram 到 3-gram 的所有词组：
  - 1-gram（unigram）：单个单词，如 `"flight"`, `"delayed"`, `"service"`
  - 2-gram（bigram）：连续的两个单词，如 `"flight delayed"`, `"customer service"`
  - 3-gram（trigram）：连续的三个单词，如 `"flight was delayed"`, `"worst airline ever"`
  - 作用：捕捉词语之间的上下文关系，提高模型对短语的理解能力

- **min_df=2**：一个词或词组至少要在 2 个文档中出现才会被保留。过滤掉只出现一次的词（可能是拼写错误或罕见词），减少噪声特征。

- **max_df=0.95**：如果一个词或词组在超过 95% 的文档中出现，会被过滤掉。过滤掉停用词（如 "the", "a", "is"），这些词对分类没有帮助。

- **lowercase=False**：保留原始大小写，不将所有文本转换为小写。保留大小写信息可能对情感分析有帮助，例如 `"THANKS"` 和 `"thanks"` 可能表达不同的情感强度。

- **sublinear_tf=True**：使用次线性缩放来降低词频的影响。公式为 `TF = 1 + log(词频)`，防止高频词（如 "flight"）过度主导特征，平衡不同词的重要性。

**特征选择流程：**

1. 收集所有可能的 n-gram（1-gram, 2-gram, 3-gram）
2. 过滤低频词：`min_df=2`（至少在 2 个文档中出现）
3. 过滤高频词：`max_df=0.95`（不超过 95% 的文档）
4. 计算 TF-IDF 值：对每个保留的词/词组
5. 选择 Top 15,000：按 TF-IDF 值排序，保留最高的 15,000 个

#### 2.3.2 航空公司编码

使用 `LabelEncoder` 对航空公司名称进行编码，将 6 家航空公司转换为数值标签：

- Virgin America → 0
- United → 1
- Southwest → 2
- Delta → 3
- US Airways → 4
- American → 5

#### 2.3.3 特征合并

将文本特征（15,000 维）和航空公司特征（1 维）合并为最终特征矩阵（15,001 维），使用 `scipy.sparse.hstack` 进行稀疏矩阵合并。


### 2.4 机器学习方法概述


本项目使用集成学习方法进行推文情感分析，具体技术细节如下：

#### 集成学习（Ensemble Learning）

使用 **VotingClassifier** 进行集成学习，结合多个基学习器的预测结果，通过**软投票（Soft Voting）**机制提高模型性能。

#### 5个基学习器（Base Learners）

**① Logistic Regression（逻辑回归）**
- **特点**：稳定的基线模型，适合文本分类
- **作用**：提供可靠的线性分类边界
- **参数**：`class_weight="balanced"` 处理类别不平衡

**② Multinomial Naive Bayes（多项式朴素贝叶斯）**
- **特点**：经典的文本分类算法
- **作用**：擅长处理词频特征，计算效率高
- **参数**：`alpha=0.3` 平滑参数

**③ Random Forest（随机森林）**
- **特点**：基于决策树的集成方法
- **作用**：捕捉非线性关系，减少过拟合
- **参数**：200棵决策树，最大深度15

**④ LightGBM（梯度提升机）**
- **特点**：高效的梯度提升框架
- **作用**：强大的非线性建模能力
- **参数**：300轮迭代，学习率0.05

**⑤ XGBoost（极致梯度提升）**
- **特点**：业界领先的梯度提升算法
- **作用**：处理复杂特征交互
- **参数**：300轮迭代，子采样率0.8

#### 特征工程

**TF-IDF 向量化**
- **max_features=15000**：保留最重要的15000个特征
- **ngram_range=(1, 3)**：使用1-3元组（unigram, bigram, trigram）
- **min_df=2**：词至少出现2次
- **max_df=0.95**：词最多出现在95%的文档中（过滤高频词）
- **sublinear_tf=True**：使用对数缩放TF值

**航空公司特征**
- 使用 `LabelEncoder` 对航空公司进行编码
- 与文本特征合并作为额外特征

#### 软投票机制（Soft Voting）

- **原理**：对每个基学习器的预测概率取平均
- **优势**：比硬投票更稳健，考虑了置信度
- **公式**：`P(y|x) = (1/n) * Σ P_i(y|x)`

#### 数据划分

- **训练集**：80%
- **测试集**：20%
- **分层采样**：保持各类别比例一致

#### 性能指标

- **Accuracy（准确率）**：目标 ≥ 0.82
- **Macro-F1（宏平均F1）**：目标 ≥ 0.75
- **分类报告**：precision, recall, f1-score（按类别）

#### 机器学习流程图

```
原始文本
    ↓
[文本清洗] → 清洗后文本
    ↓
[TF-IDF向量化] → 文本特征向量 (15000维)
    ↓
[航空公司编码] → 航空公司特征 (1维)
    ↓
[特征合并] → 组合特征 (15001维)
    ↓
┌─────────────────────────────────────┐
│   5个基学习器并行训练               │
│  ┌────────┐ ┌────────┐ ┌────────┐  │
│  │   LR   │ │   NB   │ │   RF   │  │
│  └────────┘ └────────┘ └────────┘  │
│  ┌────────┐ ┌────────┐             │
│  │ LightGBM│ │ XGBoost │             │
│  └────────┘ └────────┘             │
└─────────────────────────────────────┘
    ↓
[软投票] → 概率平均
    ↓
[预测结果] → negative/neutral/positive
```

#### 为什么选择这些方法？

1. **多样性**：不同类型的算法（线性、贝叶斯、树模型、梯度提升）
2. **互补性**：各有优势，相互补充
3. **稳定性**：集成学习减少单一模型的偏差和方差
4. **性能**：软投票通常比硬投票效果更好
5. **可解释性**：可以查看各基学习器的贡献

最终模型在测试集上达到了 **Macro-F1 = 0.7533** 的性能指标。


### 2.5 误差分析


模型在以下类型的样本上表现相对较差：
1. 包含复杂情感表达的推文（如讽刺、反语）
2. 混合多种情感的推文
3. 包含大量特殊字符或缩写的推文
4. 上下文依赖较强的推文

这主要是因为文本特征提取方法（TF-IDF）对语义理解有限，无法完全捕捉复杂的语言模式和上下文信息。


## 3️⃣ Agent 实现


### 3.1 工具定义


| 工具名 | 功能 | 输入 | 输出 |
|--------|------|------|------|
| `predict_sentiment` | 使用机器学习模型预测推文情感 | 推文文本、航空公司 | 分类结果和概率 |
| `explain_sentiment` | 解释模型预测结果并生成行动建议 | 推文文本、分类结果、概率 | 结构化的解释和建议 |
| `generate_response` | 生成针对推文的回复建议 | 推文文本、情感分类 | 回复建议文本 |


### 3.2 决策流程


Agent 按照以下流程执行任务：
1. 接收用户提供的推文文本和航空公司信息
2. 使用 `predict_sentiment` 工具进行情感分类预测
3. 使用 `explain_sentiment` 工具解释分类结果并生成行动建议
4. 使用 `generate_response` 工具生成针对性的回复建议
5. 向用户提供清晰、完整的情感分析结果、解释和建议


### 3.3 案例展示


**输入**：
```
@United This is the worst airline ever! My flight was delayed for 5 hours and no one helped!
```

**输出**：
```json
{
  "classification": {
    "label": "negative",
    "probability": {
      "negative": 0.92,
      "neutral": 0.05,
      "positive": 0.03
    }
  },
  "explanation": {
    "key_factors": ["worst airline ever", "delayed for 5 hours", "no one helped"],
    "reasoning": "推文中包含强烈的负面情感词汇，描述了航班延误和缺乏帮助的负面体验",
    "confidence_level": "高",
    "suggestions": ["立即联系客户并提供补偿", "调查延误原因并改进服务流程", "加强员工培训"]
  },
  "response_suggestion": "尊敬的客户，对于您航班延误和未能获得及时帮助的糟糕体验，我们深表歉意。我们将立即调查此事并为您提供相应的补偿。感谢您的反馈，我们将努力改进服务质量。"
}
```


## 4️⃣ 系统特色


### 4.1 多模态情感分析

系统不仅提供情感分类结果，还通过 LLM 生成详细的解释和可执行的行动建议，实现从预测到决策的完整闭环。


### 4.2 实时交互体验

通过 Streamlit 构建的 Web 界面提供直观的交互体验，支持单条推文分析和批量文件处理功能。


### 4.3 结构化输出

所有输出都采用结构化格式，确保结果的可追溯性和可复现性，便于后续分析和应用。


## 5️⃣ 开发心得


### 5.1 主要困难与解决方案


1. **文本特征提取**：航空推文包含大量缩写、特殊字符和行业术语，解决方案是使用 TF-IDF 结合 ngram 特征，捕捉更丰富的语言模式。
2. **多分类平衡**：情感分类是三分类任务，需要处理类别不平衡问题，解决方案是使用 Macro-F1 作为主要评估指标。
3. **模型集成**：单个模型在复杂情感识别上存在局限，解决方案是使用 VotingClassifier 集成多个模型的优势。


### 5.2 对 AI 辅助编程的感受


AI 辅助编程工具在代码编写和问题解决方面提供了很大帮助，特别是在处理重复性任务和学习新框架时。它可以快速生成代码模板，提供解决方案建议，显著提高开发效率。但同时也需要注意，AI 生成的代码可能存在错误或不符合项目规范，需要人工仔细检查和调试。


### 5.3 局限与未来改进


1. **模型性能**：当前模型在处理复杂语言模式和上下文理解方面仍有提升空间，可以考虑使用更先进的文本表示方法（如 BERT）。
2. **多语言支持**：目前系统主要支持英文推文，未来可以扩展到多语言情感分析。
3. **实时性**：可以优化模型推理速度，实现实时情感分析功能。
4. **情感细粒度分析**：可以进一步细分情感类别，如愤怒、失望、满意等更细致的情感标签。


## 技术栈


| 组件 | 技术 | 版本要求 |
|------|------|----------|
| 项目管理 | uv | 最新版 |
| 数据处理 | polars + pandas | polars>=0.20.0, pandas>=2.2.0 |
| 数据验证 | pandera | >=0.18.0 |
| 机器学习 | scikit-learn + lightgbm | sklearn>=1.3.0, lightgbm>=4.0.0 |
| LLM 框架 | openai | >=1.0.0 |
| Agent 框架 | pydantic | pydantic>=2.0.0 |
| 可视化 | streamlit | >=1.20.0 |
| 文本处理 | nltk | >=3.8.0 |


## 许可证


MIT License


## 致谢


- 感谢 [DeepSeek](https://www.deepseek.com/) 提供的 LLM API
- 感谢 Kaggle 提供的 [Twitter US Airline Sentiment](https://www.kaggle.com/datasets/crowdflower/twitter-airline-sentiment) 数据集
- 感谢所有开源库的贡献者


## 联系方式


如有问题或建议，欢迎通过以下方式联系：

- 项目地址：[http://hblu.top:3000/MachineLearning2025/G05-Sentiment-Analysis-of-Aviation-Tweets](http://hblu.top:3000/MachineLearning2025/G05-Sentiment-Analysis-of-Aviation-Tweets)
- 邮箱：xxxxxxxxxx@gmail.com


---

**© 2026 航空推文情感分析系统 | 基于传统机器学习 + LLM + Agent**
