上传文件至 /
This commit is contained in:
commit
2926e89cb6
2
.env.example
Normal file
2
.env.example
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# DeepSeek API Key
|
||||||
|
DEEPSEEK_API_KEY=sk-xxxx
|
||||||
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# ===== 环境变量(绝对不能提交!)=====
|
||||||
|
.env
|
||||||
|
|
||||||
|
# ===== Python 虚拟环境 =====
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# ===== IDE 配置 =====
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# ===== macOS 系统文件 =====
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# ===== Jupyter =====
|
||||||
|
.ipynb_checkpoints/
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.12
|
||||||
212
README.md
Normal file
212
README.md
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
# 电信客户流失预测系统
|
||||||
|
|
||||||
|
> **机器学习 (Python) 课程设计**
|
||||||
|
|
||||||
|
## 👥 团队成员
|
||||||
|
|
||||||
|
| 姓名 | 学号 | 贡献 |
|
||||||
|
|------|------|------|
|
||||||
|
| 陈思坤 | 2311020204 | 数据处理、模型训练 |
|
||||||
|
| (请填写) | (请填写) | Agent 开发、Streamlit |
|
||||||
|
| (请填写) | (请填写) | 测试、文档撰写 |
|
||||||
|
|
||||||
|
## 📝 项目简介
|
||||||
|
|
||||||
|
本项目基于 Telco Customer Churn 数据集,构建了一个完整的客户流失预测与挽留建议系统。系统包含三个核心能力:
|
||||||
|
|
||||||
|
1. **传统机器学习**:使用 LightGBM 模型预测客户流失概率
|
||||||
|
2. **LLM 集成**:使用 DeepSeek 生成个性化挽留建议
|
||||||
|
3. **Agent 工具调用**:通过 pydantic-ai 实现 ML 预测 + 风险分析的工具链
|
||||||
|
|
||||||
|
## 🚀 快速开始
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 克隆仓库
|
||||||
|
git clone http://hblu.top:3000/MachineLearning2025/GXX-TelcoChurn.git
|
||||||
|
cd GXX-TelcoChurn
|
||||||
|
|
||||||
|
# 安装依赖
|
||||||
|
uv sync
|
||||||
|
|
||||||
|
# 配置环境变量
|
||||||
|
cp .env.example .env
|
||||||
|
# 编辑 .env 填入 API Key
|
||||||
|
|
||||||
|
# 训练模型
|
||||||
|
uv run python src/train.py
|
||||||
|
|
||||||
|
# 运行 Demo
|
||||||
|
uv run streamlit run src/streamlit_app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1️⃣ 问题定义与数据
|
||||||
|
|
||||||
|
### 1.1 任务描述
|
||||||
|
|
||||||
|
- **任务类型**:二分类
|
||||||
|
- **业务目标**:预测电信客户是否会流失,并给出针对性的挽留建议
|
||||||
|
- **输入**:客户基本信息、服务订阅情况、账户信息
|
||||||
|
- **输出**:流失概率、风险等级、挽留行动计划
|
||||||
|
|
||||||
|
### 1.2 数据来源
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 数据集名称 | Telco Customer Churn |
|
||||||
|
| 数据链接 | [Kaggle](https://www.kaggle.com/datasets/blastchar/telco-customer-churn) |
|
||||||
|
| 样本量 | 7,043 条 |
|
||||||
|
| 特征数 | 20 个 |
|
||||||
|
| 流失率 | ~26.5% |
|
||||||
|
|
||||||
|
### 1.3 数据切分与防泄漏
|
||||||
|
|
||||||
|
- **切分策略**:80% 训练集,20% 测试集
|
||||||
|
- **分层采样**:使用 `stratify=y` 确保训练集和测试集的流失率一致
|
||||||
|
- **随机种子**:固定 `random_state=42` 确保可复现
|
||||||
|
- **防泄漏措施**:
|
||||||
|
- 不使用 customerID 作为特征
|
||||||
|
- TotalCharges 与 tenure 存在相关性,但保留两者因为业务含义不同
|
||||||
|
- 所有特征工程在训练集上拟合,在测试集上转换
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2️⃣ 机器学习流水线
|
||||||
|
|
||||||
|
### 2.1 数据预处理
|
||||||
|
|
||||||
|
使用 Polars 进行高性能数据处理:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 使用 Polars Lazy API
|
||||||
|
df = pl.read_csv("data/WA_Fn-UseC_-Telco-Customer-Churn.csv")
|
||||||
|
df_clean = preprocess_data(df) # 删除缺失值、转换类型
|
||||||
|
```
|
||||||
|
|
||||||
|
使用 Pandera 进行 Schema 校验:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class CleanTelcoSchema(pa.DataFrameModel):
|
||||||
|
tenure: int = pa.Field(ge=0, nullable=False)
|
||||||
|
MonthlyCharges: float = pa.Field(ge=0, nullable=False)
|
||||||
|
Churn: int = pa.Field(isin=[0, 1], nullable=False)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 基线模型
|
||||||
|
|
||||||
|
| 模型 | F1 Score | ROC-AUC |
|
||||||
|
|------|----------|---------|
|
||||||
|
| Logistic Regression | ~0.58 | ~0.84 |
|
||||||
|
|
||||||
|
### 2.3 进阶模型
|
||||||
|
|
||||||
|
| 模型 | F1 Score | ROC-AUC |
|
||||||
|
|------|----------|---------|
|
||||||
|
| LightGBM | ~0.60 | ~0.85 |
|
||||||
|
|
||||||
|
### 2.4 误差分析
|
||||||
|
|
||||||
|
模型在以下样本上表现不佳:
|
||||||
|
|
||||||
|
1. **边界客户**:流失概率在 0.4-0.6 之间的客户,模型难以准确判断
|
||||||
|
2. **长期客户突然流失**:任期较长但突然流失的客户,可能受到外部因素影响
|
||||||
|
3. **低费用客户**:月费较低的客户,特征区分度不够
|
||||||
|
|
||||||
|
**改进方向**:
|
||||||
|
- 引入更多行为特征(如投诉记录、服务使用频率)
|
||||||
|
- 考虑时序特征(如近期费用变化趋势)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3️⃣ Agent 实现
|
||||||
|
|
||||||
|
### 3.1 工具定义
|
||||||
|
|
||||||
|
| 工具名 | 功能 | 输入 | 输出 |
|
||||||
|
|--------|------|------|------|
|
||||||
|
| `predict_churn_probability` | 调用 ML 模型预测流失概率 | CustomerFeatures | float |
|
||||||
|
| `get_model_explanation` | 获取模型特征重要性 | - | str |
|
||||||
|
| `analyze_risk_factors` | 分析客户具体风险因素 | CustomerFeatures | list[str] |
|
||||||
|
|
||||||
|
### 3.2 决策流程
|
||||||
|
|
||||||
|
```
|
||||||
|
用户输入客户信息
|
||||||
|
↓
|
||||||
|
Agent 调用 predict_churn_probability → 获取流失概率
|
||||||
|
↓
|
||||||
|
Agent 调用 get_model_explanation → 获取特征重要性
|
||||||
|
↓
|
||||||
|
Agent 调用 analyze_risk_factors → 获取具体风险因素
|
||||||
|
↓
|
||||||
|
Agent 生成结构化输出 (ChurnPrediction)
|
||||||
|
↓
|
||||||
|
返回:流失概率 + 风险等级 + 关键因素 + 行动计划 + 依据说明
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 案例展示
|
||||||
|
|
||||||
|
**输入**:
|
||||||
|
```
|
||||||
|
客户信息:任期 2 个月,月费 $89.99,月付合同,光纤服务,电子支票支付
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"churn_probability": 0.82,
|
||||||
|
"risk_level": "高风险",
|
||||||
|
"key_factors": [
|
||||||
|
"新客户(任期仅2个月),流失风险较高",
|
||||||
|
"月付合同,无长期绑定,容易流失",
|
||||||
|
"使用电子支票支付,该支付方式用户流失率最高"
|
||||||
|
],
|
||||||
|
"action_plan": [
|
||||||
|
{"action": "提供首年合同升级优惠(8折)", "priority": "高"},
|
||||||
|
{"action": "赠送 3 个月在线安全服务", "priority": "高"},
|
||||||
|
{"action": "引导切换为自动银行转账支付", "priority": "中"}
|
||||||
|
],
|
||||||
|
"rationale": "该客户为新客户且使用月付合同,根据模型分析,合同类型和客户任期是最重要的流失预测因素..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4️⃣ 开发心得
|
||||||
|
|
||||||
|
### 4.1 主要困难与解决方案
|
||||||
|
|
||||||
|
1. **数据类型处理**:TotalCharges 字段在原始数据中是字符串,包含空值
|
||||||
|
- 解决:使用 Polars 的条件表达式处理空字符串
|
||||||
|
|
||||||
|
2. **类别不平衡**:流失客户仅占 26.5%
|
||||||
|
- 解决:使用 `class_weight="balanced"` 参数
|
||||||
|
|
||||||
|
3. **Agent 输出稳定性**:LLM 有时不按要求调用工具
|
||||||
|
- 解决:在 instructions 中明确规定必须调用的工具顺序
|
||||||
|
|
||||||
|
### 4.2 对 AI 辅助编程的感受
|
||||||
|
|
||||||
|
- **有帮助的场景**:代码框架搭建、API 文档查询、错误调试
|
||||||
|
- **需要注意的地方**:AI 生成的代码需要仔细审查,特别是边界条件处理
|
||||||
|
|
||||||
|
### 4.3 局限与未来改进
|
||||||
|
|
||||||
|
1. 可以引入更多特征(如客户投诉记录、服务使用频率)
|
||||||
|
2. 可以实现阈值策略,针对不同风险等级采取不同挽留措施
|
||||||
|
3. 可以添加相似案例检索功能,提供历史成功挽留案例参考
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Checklist(提交前自检)
|
||||||
|
|
||||||
|
- [x] 使用 `uv sync` 安装依赖,无需手动创建虚拟环境
|
||||||
|
- [x] `.gitignore` 包含 `.env`、`__pycache__`、大文件
|
||||||
|
- [x] 在干净环境下可以复现(`git clone && uv sync && uv run`)
|
||||||
|
- [x] 没有提交 API Key 或敏感信息
|
||||||
|
- [x] 使用 Polars 进行数据处理
|
||||||
|
- [x] 使用 Pydantic 定义特征和输出模型
|
||||||
|
- [x] Agent 至少有 2 个 tool(含 1 个 ML 工具)
|
||||||
|
- [x] README.md 说明了数据切分策略
|
||||||
|
- [x] Demo 可以正常运行
|
||||||
46
pyproject.toml
Normal file
46
pyproject.toml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
[project]
|
||||||
|
name = "telco-churn-predictor"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "电信客户流失预测系统 - 机器学习 × LLM × Agent 课程设计"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = [
|
||||||
|
"pydantic>=2.10",
|
||||||
|
"pandera>=0.21",
|
||||||
|
"pydantic-ai>=0.7",
|
||||||
|
"polars>=1.0",
|
||||||
|
"pandas>=2.2",
|
||||||
|
"scikit-learn>=1.5",
|
||||||
|
"lightgbm>=4.5",
|
||||||
|
"seaborn>=0.13",
|
||||||
|
"joblib>=1.4",
|
||||||
|
"python-dotenv>=1.0",
|
||||||
|
"streamlit>=1.40",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[tool.uv.index]]
|
||||||
|
url = "https://mirrors.aliyun.com/pypi/simple/"
|
||||||
|
default = true
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"pytest>=8.0",
|
||||||
|
"pytest-asyncio>=1.3",
|
||||||
|
"ruff>=0.8",
|
||||||
|
]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[tool.hatch.build.targets.wheel]
|
||||||
|
packages = ["src"]
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 100
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = ["E", "F", "I"]
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
testpaths = ["tests"]
|
||||||
Loading…
Reference in New Issue
Block a user