shivanshu1512/Quora_question_pair_project
GitHub: shivanshu1512/Quora_question_pair_project
基于 Quora 数据集构建的 NLP 重复问题检测系统,通过词袋模型与多层级手工特征工程训练机器学习分类器,并部署为 Streamlit 交互式 Web 应用。
Stars: 0 | Forks: 0
# 🔍 Quora 问题重复检测器
[](https://quora-question-pair-project.streamlit.app/)
[](https://python.org)
[](https://scikit-learn.org)
## 📌 这个项目是关于什么的?
Quora 是一个供人们提问的平台。在 Quora 上一个非常普遍的问题是,**同一个问题会被多次询问**,只是表述方式不同。例如:
- *"学习 Python 的最好方法是什么?"*
- *"我该如何开始学习 Python 编程?"*
这两个问题问的是**同一件事**——它们是**重复的**!
在这个项目中,我构建了一个 **Machine Learning 系统**,它可以自动检测给定的两个问题是否重复。这正是 Quora 发布为 [Kaggle 比赛](https://www.kaggle.com/c/quora-question-pairs) 的同一个问题。
## 🌐 在线演示
👉 **在这里亲自尝试:** [quora-question-pair-project.streamlit.app](https://quora-question-pair-project.streamlit.app/)
只需输入两个问题,点击按钮,模型就会告诉你它们是否是重复的!
## 🗂️ 项目结构
```
Quora_question_pair_project/
│
├── 📓 initial_EDA.ipynb # Step 1: Exploring the dataset
├── 📓 only-bow.ipynb # Step 2: Baseline model (Bag of Words only)
├── 📓 bow-with-basic-features.ipynb # Step 3: Adding basic NLP features
├── 📓 bow-with-preprocessing-and-advanced-features.ipynb # Step 4: Final best model
│
└── 📁 streamlit-app/ # Step 5: Live web app
├── app.py # Main Streamlit app code
├── helper.py # Feature engineering functions
├── requirements.txt # Python dependencies
├── setup.sh # Heroku setup script
└── Procfile # Heroku deployment config
```
## 🚀 我是如何构建它的 —— 逐步解析
### 第一步:探索性数据分析 (EDA) 📊
**文件:** `initial_EDA.ipynb`
在构建任何模型之前,我首先**探索并理解了数据集**。
- **数据集:** 来自 Kaggle 的 Quora Question Pairs 数据集(约 404,000 个问题对)
- 每一行包含:`question1`、`question2` 和一个标签(`1` = 重复,`0` = 不重复)
- 我分析了:
- 存在多少重复与非重复问题(约 37% 是重复的)
- 问题长度的分布
- 重复与非重复问题对中最常见的词
- 词云图,用于直观地理解数据
- 同一个问题出现的频率(问题频率分析)
这一步帮助我理解了**模型应该寻找哪些模式**。
### 第二步:基线模型 —— 仅使用词袋模型 📦
**文件:** `only-bow.ipynb`
我的第一种方法很简单——只需使用**词袋模型**将问题转换为数字,然后训练一个分类器。
**什么是词袋模型?**
词汇表中的每个单词都会获得一个数字。每个问题都变成一个向量,计算每个单词出现的次数。然后我将两个问题向量拼接在一起,并将其输入到模型中。
**我所做的:**
- 使用 `CountVectorizer` 将文本转换为 BoW 向量(前 3000 个特征)
- 训练了 **Random Forest** 和 **XGBoost** 分类器
- 使用了 30,000 个样本的子集(为了提高速度),并进行分层 80/20 训练-测试集划分
**结果:**
| 模型 | 准确率 |
|-------|----------|
| Random Forest (仅 BoW) | **74.20%** |
| XGBoost (仅 BoW) | 73.28% |
### 第三步:添加基础 NLP 特征 🛠️
**文件:** `bow-with-basic-features.ipynb`
仅有 BoW 是不够的。我添加了**手工设计的特征**,直接捕捉两个问题之间的关系。
**我创建的基础特征:**
| 特征 | 含义 |
|---------|--------------|
| `q1_len` | 问题 1 的字符数 |
| `q2_len` | 问题 2 的字符数 |
| `q1_num_words` | 问题 1 的词数 |
| `q2_num_words` | 问题 2 的词数 |
| `word_common` | 两个问题中共同包含的词数 |
| `word_total` | 两个问题中独特词汇的总数 |
| `word_share` | 共同词数与总词数的比率 |
**添加基础特征后的结果:**
| 模型 | 准确率 |
|-------|----------|
| Random Forest | **76.83%** |
| XGBoost | 76.45% |
### 第四步:高级特征工程 + 预处理(最佳模型) 🏆
**文件:** `bow-with-preprocessing-and-advanced-features.ipynb`
这是模型变得非常聪明的地方。我添加了三个类别的**高级 NLP 特征**:
#### 🔤 Token 特征(8 个特征)
这些特征不仅限于计算单词数量,还捕捉了两个问题内容的相似程度:
| 特征 | 描述 |
|---------|-------------|
| `cwc_min` | 共同的非停用词 / 较小的非停用词集合 |
| `cwc_max` | 共同的非停用词 / 较大的非停用词集合 |
| `csc_min` | 共同的停用词 / 较小的停用词集合 |
| `csc_max` | 共同的停用词 / 较大的停用词集合 |
| `ctc_min` | 共同的 token / 较小的总 token 数 |
| `ctc_max` | 共同的 token / 较大的总 token 数 |
| `last_word_eq` | 两个问题是否以同一个词结尾?(1 或 0) |
| `first_word_eq` | 两个问题是否以同一个词开头?(1 或 0) |
#### 📏 长度特征(3 个特征)
| 特征 | 描述 |
|---------|-------------|
| `mean_len` | 两个问题的平均字符长度 |
| `abs_len_diff` | 两个问题长度之间的绝对差值 |
| `longest_substr_ratio` | 最长公共子串与较短问题长度的比率 |
#### 🤝 模糊匹配特征(4 个特征)
我使用了 **FuzzyWuzzy** 库,它能像人类一样衡量字符串的相似度:
| 特征 | 描述 |
|---------|-------------|
| `fuzz_ratio` | 总体相似度评分 (0–100) |
| `fuzz_partial_ratio` | 最佳部分匹配的相似度 |
| `token_sort_ratio` | 按字母顺序排序单词后的相似度 |
| `token_set_ratio` | 取单词集合交集后的相似度 |
#### 📦 文本特征
- 来自两个问题上 `CountVectorizer` 的 **BoW 向量**(3000 个特征)
**最终结果:**
| 模型 | 准确率 |
|-------|----------|
| Random Forest | **78.47%** |
| **XGBoost** | **79.27% ✅ (最佳)** |
### 第五步:在线 Web 应用 🌐
**文件:** `streamlit-app/app.py` 和 `streamlit-app/helper.py`
我使用 **Streamlit** 将模型部署为一个交互式的 Web 应用。
**应用的工作原理:**
1. 用户输入 **Question 1** 和 **Question 2**
2. 应用提取所有的 NLP 特征(token、长度和模糊特征)
3. 经过训练的 **Random Forest 分类器** 进行预测
4. 应用显示:**"DUPLICATE"** 或 **"NOT DUPLICATE"**,并附带置信度分数
**关键文件:**
- `app.py` — 带有自定义 CSS 样式(浅色/白色主题)的 Streamlit 主 UI
- `helper.py` — 复用了 notebook 中所有的特征工程函数
## 📊 模型性能总结
| 阶段 | 添加的内容 | Random Forest | XGBoost |
|-------|-------------|--------------|---------|
| 基线 (仅 BoW) | 仅词频统计 | 74.20% | 73.28% |
| + 基础特征 | 词汇重叠统计 | 76.83% | 76.45% |
| + 高级特征 | Token + 长度 + 模糊匹配 | 78.47% | **79.27% 🏆** |
**最佳模型:包含所有特征的 XGBoost → 约 79.3% 准确率**
## 🧠 从这个项目中获得的关键心得
作为一名 BTech 学生,这个项目教会了我很多:
1. **文本无法直接输入到 ML 模型中** —— 你需要先将其转换为数字(BoW, TF-IDF 等)
2. **特征工程非常重要** —— 相比于原始 BoW,手工设计的特征使准确率提高了约 5%
3. **模糊匹配非常强大**,即使单词被重新排列,也能用于比较两个字符串的相似程度
4. **XGBoost 在处理结构化/表格特征数据时** 始终优于 Random Forest
5. **部署模型** 与构建模型一样重要 —— Streamlit 让这一切变得非常简单!
6. **EDA 优先** —— 在进入建模阶段之前,务必先探索和可视化你的数据
## 🛠️ 使用的技术
| 类别 | 工具 |
|----------|-------|
| **语言** | Python 3 |
| **数据分析** | Pandas, NumPy, Matplotlib, Seaborn |
| **NLP** | NLTK, BeautifulSoup, FuzzyWuzzy, distance |
| **ML 模型** | Scikit-learn (Random Forest), XGBoost |
| **文本向量化** | CountVectorizer (词袋模型), TF-IDF |
| **Web 应用** | Streamlit |
| **部署** | Streamlit Cloud / Heroku |
## ⚙️ 如何在本地运行
### 1. 克隆仓库
```
git clone https://github.com/shivanshu1512/Quora_question_pair_project.git
cd Quora_question_pair_project
```
### 2. 安装依赖
```
pip install -r streamlit-app/requirements.txt
```
### 3. 运行 Streamlit 应用
```
cd streamlit-app
streamlit run app.py
```
### 4. 在浏览器中打开 `http://localhost:8501`
## 📁 数据集
- **来源:** [Kaggle — Quora Question Pairs](https://www.kaggle.com/c/quora-question-pairs/data)
- **大小:** 约 404,000 个问题对
- **用于训练:** 30,000 个问题对(分层抽样)
- **标签:** `1` = 重复,`0` = 不重复
- **类别划分:** 约 37% 重复,约 63% 不重复
## 👨💻 关于我
你好!我是 **Shivanshu Shukla**,一名对 Machine Learning 和 NLP 充满热情的 BTech 学生。
这个项目是我在应用机器学习学习之旅中构建的。
- 📧 电子邮件:meshivanshu1512@gmail.com
- 🐙 GitHub:[@shivanshu1512](https://github.com/shivanshu1512)
## ⭐ 如果这个项目对你有帮助,请给它点个 Star!
这会激励我构建更多酷炫的项目。🙏
*使用 Python、Scikit-learn、XGBoost 和 Streamlit 充满 ❤️ 构建*
标签:Apex, Kubernetes, NLP, scikit-learn, Streamlit, 文本分类, 文本相似度, 机器学习, 访问控制, 逆向工具