P03 银行营销预测 (Bank Marketing Classification)¶
项目概述¶
本项目基于葡萄牙银行的真实营销数据集,使用机器学习分类模型预测客户是否会订购定期存款产品。这是一个经典的二分类问题,适合学习逻辑回归和决策树等基础分类算法。
学习目标: - 理解二分类问题的建模流程 - 掌握逻辑回归(Logistic Regression)和决策树(Decision Tree)算法 - 学习特征工程:数值特征标准化、类别特征编码 - 掌握模型评估指标:准确率、精确率、召回率、F1、AUC-ROC - 理解类别不平衡问题及处理方法
数据来源: UCI Machine Learning Repository - Bank Marketing Dataset 数据规模: 45,211条记录, 17个特征, 1个目标变量 业务场景: 银行电话营销,预测客户是否会订购定期存款
项目结构¶
p03-bank-marketing/
├── README.md # 项目说明文档
├── pyproject.toml # 依赖配置
├── src/
│ ├── __init__.py
│ └── analyze.py # 分类分析主脚本
├── notebooks/
│ └── analysis.ipynb # 交互式教程
├── configs/
│ └── default.yaml # 配置文件
└── outputs/ # 自动生成
├── analysis.log # 运行日志
├── models/ # 模型文件
│ ├── logistic_model.pkl
│ └── tree_model.pkl
├── figures/ # 可视化图表
│ ├── confusion_matrix.png
│ ├── roc_curve.png
│ ├── feature_importance.png
│ └── correlation_heatmap.png
└── reports/
└── classification_report.md
数据说明¶
数据字段 (17个特征 + 1个目标)¶
客户信息 (Demographic)¶
age: 年龄 (数值型)job: 职业 (类别型: admin., blue-collar, entrepreneur, housemaid, management, retired, self-employed, services, student, technician, unemployed, unknown)marital: 婚姻状况 (类别型: divorced, married, single)education: 教育程度 (类别型: primary, secondary, tertiary, unknown)
账户信息 (Account)¶
default: 是否有信用违约 (类别型: yes, no)balance: 账户余额 (数值型, 欧元)housing: 是否有住房贷款 (类别型: yes, no)loan: 是否有个人贷款 (类别型: yes, no)
营销活动信息 (Campaign)¶
contact: 联系方式 (类别型: cellular, telephone, unknown)day: 最后联系日期 (数值型, 1-31)month: 最后联系月份 (类别型: jan, feb, mar, ..., dec)duration: 最后通话时长 (数值型, 秒) ⚠️ 注意:这个特征在实际预测时不可用(只有通话后才知道时长)campaign: 本次营销活动联系次数 (数值型)pdays: 距离上次联系天数 (数值型, -1表示未联系过)previous: 上次营销活动联系次数 (数值型)poutcome: 上次营销结果 (类别型: failure, other, success, unknown)
目标变量 (Target)¶
y: 是否订购定期存款 (类别型: yes=1, no=0)
类别分布¶
- 正样本 (yes): ~11.7% (约5,289条)
- 负样本 (no): ~88.3% (约39,922条)
- 类别不平衡比: 约 1:8 ⚠️ 需要特殊处理
快速开始¶
1. 环境准备¶
# 使用 uv 运行(推荐)
uv run --no-project --with pandas --with numpy --with scikit-learn --with matplotlib --with seaborn --with pyyaml \
python src/analyze.py --config configs/default.yaml
# 或安装依赖后运行
uv pip install pandas numpy scikit-learn matplotlib seaborn pyyaml
python src/analyze.py --config configs/default.yaml
2. 运行分析¶
# 使用默认配置
python src/analyze.py --config configs/default.yaml
# 交互式教程
jupyter notebook notebooks/analysis.ipynb
3. 查看结果¶
分析完成后查看:
- outputs/reports/classification_report.md - 详细评估报告
- outputs/figures/ - 可视化图表
- outputs/models/ - 训练好的模型文件
- outputs/analysis.log - 运行日志
核心算法¶
1. 逻辑回归 (Logistic Regression)¶
原理: 线性模型 + Sigmoid激活函数,输出概率值
数学公式:
优点: - 模型简单,训练速度快 - 输出概率值,便于解释 - 对线性可分数据效果好 - 不容易过拟合
缺点: - 假设线性关系,对非线性数据效果差 - 对特征缩放敏感 - 不能处理特征交互
适用场景: - 特征与目标呈线性关系 - 需要快速训练和预测 - 需要解释模型权重
2. 决策树 (Decision Tree)¶
原理: 递归划分特征空间,构建树形结构
划分标准:
- 基尼指数(Gini): Gini = 1 - Σ(pᵢ²) (CART算法)
- 信息增益(Entropy): Entropy = -Σ(pᵢ·log₂pᵢ) (ID3/C4.5算法)
优点: - 可以捕捉非线性关系 - 自动进行特征选择 - 不需要特征缩放 - 输出可视化,易于理解 - 可以处理类别特征
缺点: - 容易过拟合(需要剪枝) - 对噪声敏感 - 不稳定(数据小变化可能导致树结构大变化)
适用场景: - 特征与目标呈非线性关系 - 需要模型可解释性 - 数据包含复杂交互关系
特征工程¶
1. 数值特征处理¶
标准化 (Standardization):
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_numeric)
# 转换为: mean=0, std=1
为什么需要标准化? - 逻辑回归使用梯度下降优化,不同尺度的特征会导致收敛慢 - 某些特征(如balance, duration)数值范围大,会主导模型 - 标准化后所有特征在同一尺度,权重可比较
2. 类别特征处理¶
独热编码 (One-Hot Encoding):
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
# job: [admin, blue-collar, ...] -> [1,0,0,...], [0,1,0,...], ...
标签编码 (Label Encoding):
3. 特征选择¶
移除duration特征: 虽然duration是最强特征,但实际预测时不可用(通话后才知道时长),移除以避免数据泄漏。
相关性分析: 计算特征与目标的相关系数,保留相关性高的特征。
模型评估¶
1. 混淆矩阵 (Confusion Matrix)¶
- TN (True Negative): 正确预测为负
- FP (False Positive): 错误预测为正 (Type I Error)
- FN (False Negative): 错误预测为负 (Type II Error)
- TP (True Positive): 正确预测为正
2. 评估指标¶
准确率 (Accuracy):
精确率 (Precision):
召回率 (Recall/Sensitivity):
F1分数 (F1-Score):
AUC-ROC: - ROC曲线: Recall(TPR) vs FPR曲线 - AUC: ROC曲线下面积 (0.5-1.0, 越大越好) - 适用于类别不平衡数据,衡量模型排序能力
3. 类别不平衡处理¶
方法1: 调整类别权重
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(class_weight='balanced')
# 自动计算权重: n_samples / (n_classes * np.bincount(y))
方法2: 重采样
from imblearn.over_sampling import SMOTE
smote = SMOTE(sampling_strategy=0.5)
X_resampled, y_resampled = smote.fit_resample(X, y)
方法3: 调整决策阈值
业务应用¶
1. 营销策略优化¶
场景: 银行有10,000个潜在客户,如何分配有限的营销资源?
解决方案: 1. 使用模型预测每个客户的订购概率 2. 按概率从高到低排序 3. 只联系Top 20%高概率客户 4. 预期转化率提升3-5倍
2. 客户细分¶
基于预测概率将客户分为4组: - 高潜力客户 (p > 0.7): 重点跟进,提供优惠 - 中等潜力 (0.3 < p < 0.7): 标准营销话术 - 低潜力客户 (0.1 < p < 0.3): 低频次接触 - 无潜力客户 (p < 0.1): 不联系,避免骚扰
3. A/B测试¶
- 对照组: 随机选择客户进行营销
- 实验组: 基于模型预测选择客户
- 评估指标: 转化率、ROI、客户满意度
扩展思考¶
1. 特征工程优化¶
- 创建交互特征: age×job, balance×housing
- 时间特征: 季节性(month)、周期性
- 聚合特征: 历史营销总次数、平均通话时长
2. 模型优化¶
- 超参数调优: Grid Search, Random Search
- 集成学习: Random Forest, XGBoost
- 神经网络: 多层感知机(MLP)
3. 业务优化¶
- 多目标优化: 平衡转化率与营销成本
- 动态阈值: 根据营销预算动态调整决策阈值
- 实时预测: 部署在线服务API
4. 进阶分析¶
- SHAP值解释: 理解每个特征对预测的贡献
- Uplift模型: 预测营销活动的增量效果
- 因果推断: 评估营销活动的真实因果效应
常见问题¶
Q1: 为什么不能使用duration特征?¶
A: duration是最后通话时长,只有通话结束后才知道。在实际预测时(通话前),这个特征不可用。使用它会导致**数据泄漏**(Data Leakage),模型在训练集上表现很好,但实际应用时失效。
Q2: 如何处理类别不平衡?¶
A:
1. 使用F1、AUC-ROC等适合不平衡数据的指标
2. 调整模型的class_weight='balanced'
3. 使用SMOTE等重采样技术
4. 调整决策阈值(如从0.5降到0.3)
Q3: 逻辑回归 vs 决策树如何选择?¶
A: - 数据呈线性关系 -> 逻辑回归 - 数据呈非线性关系 -> 决策树 - 需要概率输出 -> 逻辑回归 - 需要可视化解释 -> 决策树 - 特征很多且有交互 -> 决策树或集成方法
Q4: 如何评估模型是否过拟合?¶
A: 比较训练集和测试集的性能: - 训练集准确率95%, 测试集准确率70% -> 过拟合 - 解决方法: 正则化(L1/L2)、剪枝、减少特征、增加数据
Q5: 模型部署后如何监控?¶
A: - 监控预测分布: 检测数据漂移 - 监控业务指标: 转化率、ROI - 定期重新训练: 每月或每季度 - A/B测试: 对比新旧模型效果
参考资料¶
数据集¶
- UCI Repository: https://archive.ics.uci.edu/ml/datasets/Bank+Marketing
- 论文: [Moro et al., 2014] A Data-Driven Approach to Predict the Success of Bank Telemarketing
算法原理¶
- 《统计学习方法》李航 - 第6章 逻辑回归, 第5章 决策树
- Scikit-learn文档: https://scikit-learn.org/stable/supervised_learning.html
类别不平衡¶
- imbalanced-learn库: https://imbalanced-learn.org/
- 论文: SMOTE - Synthetic Minority Over-sampling Technique
模型评估¶
- 混淆矩阵可视化: https://scikit-learn.org/stable/modules/model_evaluation.html
- ROC-AUC解读: https://developers.google.com/machine-learning/crash-course/classification/roc-and-auc
更新日志¶
- 2025-11-13: 初始版本,包含逻辑回归和决策树分类模型
- 数据集: 45,211条记录, 17个特征
- 实现: 完整的数据预处理、特征工程、模型训练、评估、可视化流程