
Ltv Predictor
- 27 installs
- 264 repo stars
- Updated May 10, 2026
- liangdabiao/claude-data-analysis-ultra-main
Helps with ai & agent building tasks.
About
ltv-predictor is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- ltv-predictor
- AI & Agent Building
- AI-coding skill
Ltv Predictor by the numbers
- 27 all-time installs (skills.sh)
- Ranked #9,560 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/liangdabiao/claude-data-analysis-ultra-main --skill ltv-predictorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 27 |
|---|---|
| repo stars | ★ 264 |
| Last updated | May 10, 2026 |
| Repository | liangdabiao/claude-data-analysis-ultra-main ↗ |
What it does
Helps with ai & agent building tasks.
Files
客户生命周期价值预测技能
一个基于《数据分析咖哥十话》第3课理论的自动化LTV预测分析工具,提供从RFM特征工程到回归建模的完整解决方案。
✨ 核心功能
🔍 RFM特征工程
- R值计算: 最近一次消费时间间隔分析
- F值计算: 消费频率统计与分析
- M值计算: 消费金额汇总与分层
- 时间窗口: 基于短期数据预测长期价值
- 客户分群: 自动化客户价值分层
🤖 回归算法建模
- 线性回归: 基础回归分析模型
- 随机森林: 高性能集成学习算法
- 模型对比: 多算法性能评估比较
- 交叉验证: 可靠的模型性能评估
- 超参数优化: 自动化模型调参
📊 LTV预测引擎
- 时间序列预测: 基于历史数据预测未来LTV
- 批量预测: 支持大规模客户批量处理
- 置信区间: 提供预测结果的不确定性评估
- 特征重要性: 解释影响LTV的关键因素
📈 可视化分析
- RFM分布图: 客户价值分布可视化
- 预测效果对比: 实际值vs预测值散点图
- 特征重要性: 关键特征贡献度分析
- 模型性能对比: 多算法效果对比图
📋 专业报告
- HTML报告: 交互式分析报告
- Markdown文档: 轻量级分析总结
- Excel导出: 便于业务部门使用
- API接口: 支持系统集成调用
🚀 快速开始
1. 环境安装
# 安装基础依赖
pip install pandas numpy scikit-learn matplotlib seaborn
# 安装可选依赖(用于高级功能)
pip install xgboost lightgbm joblib openpyxl2. 基础使用
from scripts.ltv_predictor import LTVPredictor
from scripts.data_processor import DataProcessor
# 1. 初始化处理器
processor = DataProcessor()
predictor = LTVPredictor()
# 2. 加载和预处理数据
data = processor.load_order_data('your_orders.csv')
rfm_data = processor.calculate_rfm_features(data,
feature_period='3M',
prediction_period='12M')
# 3. 训练LTV预测模型
model_results = predictor.train_models(rfm_data)
# 4. 进行LTV预测
predictions = predictor.predict_ltv(new_customer_data)
# 5. 生成分析报告
report_path = predictor.generate_report(predictions, 'ltv_analysis_report.html')3. 快速示例
from scripts.quick_analysis import quick_ltv_analysis
# 一键完成完整LTV分析流程
results = quick_ltv_analysis(
order_data_path='ecommerce_orders.csv',
feature_period_months=3,
prediction_period_months=12,
output_dir='ltv_analysis_results'
)
print(f"最佳模型R²分数: {results['best_model_r2']:.4f}")
print(f"预测客户数: {len(results['predictions'])}")
print(f"分析报告: {results['report_path']}")📁 技能结构
ltv-predictor/
├── scripts/ # 核心功能模块
│ ├── data_processor.py # 数据预处理和RFM计算
│ ├── ltv_predictor.py # LTV预测核心引擎
│ ├── regression_models.py # 回归算法实现
│ ├── visualizer.py # 可视化生成器
│ └── report_generator.py # 报告生成器
├── examples/ # 示例脚本
│ ├── ecommerce_ltv_analysis.py # 电商完整分析示例
│ ├── quick_ltv_prediction.py # 快速预测示例
│ └── model_comparison.py # 模型对比示例
├── data/ # 示例数据
│ └── sample_orders.csv # 示例订单数据
├── tests/ # 测试脚本
│ ├── test_rfm_analysis.py # RFM分析测试
│ └── test_prediction.py # 预测功能测试
├── SKILL.md # 技能说明文档
└── README.md # 使用说明🎯 应用场景
🛒 电商零售
- 客户价值分层: 基于LTV对客户进行金/银/铜牌分层
- 营销预算分配: 根据LTV预测结果优化营销投入
- 库存预测: 基于客户价值预测进行商品库存规划
- 个性化推荐: 为高价值客户提供精准推荐
💰 金融服务
- 信贷评估: 结合LTV进行客户信用评级
- 产品设计: 为不同价值客户设计差异化产品
- 客户维护: 识别高价值客户进行重点维护
- 风险控制: 基于客户价值进行风险评估
🎯 营销策略
- 获客成本分析: 计算不同渠道的LTV/CAC比率
- 客户生命周期管理: 制定全生命周期营销策略
- 复购率提升: 识别低频客户制定提升策略
- 客户挽回: 预测流失风险制定挽回方案
⚙️ 配置选项
RFM分析配置
config = {
'feature_period_months': 3, # 特征计算时间窗口(月)
'prediction_period_months': 12, # 预测时间窗口(月)
'r_weight': 0.2, # R值权重
'f_weight': 0.3, # F值权重
'm_weight': 0.5, # M值权重
'customer_segments': 5 # 客户分层数量
}模型训练配置
config = {
'test_size': 0.2, # 测试集比例
'cv_folds': 5, # 交叉验证折数
'random_state': 42, # 随机种子
'enable_hyperparameter_tuning': True, # 是否调参
'n_iter_search': 50, # 超参数搜索次数
'scoring_metric': 'r2' # 评估指标
}预测配置
config = {
'confidence_interval': 0.95, # 置信区间
'batch_size': 1000, # 批处理大小
'feature_importance_threshold': 0.01, # 特征重要性阈值
'prediction_uncertainty': True # 是否计算预测不确定性
}📊 数据格式要求
订单数据格式
订单号,产品码,消费日期,产品说明,数量,单价,用户码,城市
536374,21258,2022-06-01 09:09,绿联usb分线器,32,10.95,15100,北京
536376,22114,2022-06-01 09:32,加大男装T恤,48,50.45,15291,上海必需字段:
用户码: 客户唯一标识消费日期: 购买时间(支持多种日期格式)数量: 购买数量单价: 商品单价
可选字段:
订单号: 订单唯一标识产品码: 商品标识产品说明: 商品描述城市: 客户城市信息
🧪 模型性能基准
基于第3课实测数据:
- 数据规模: 37,060条订单记录,370个独立客户
- 时间窗口: 3个月数据预测12个月LTV
- 线性回归: R² = 0.4778 (测试集)
- 随机森林: R² = 0.5899 (测试集)
- 性能提升: 23.4% (相对线性回归)
- 特征重要性: M值(金额)贡献78.53%,F值(频率)贡献16.32%
🔧 高级功能
自动特征工程
- 时间序列特征生成
- 滑动窗口计算
- 季节性模式识别
- 异常值检测和处理
模型可解释性
- SHAP值分析
- 部分依赖图
- 特征交互作用
- 预测路径追踪
业务洞察
- 客户价值趋势分析
- 产品关联度分析
- 地域价值分布
- 时间价值模式
📋 最佳实践
数据质量
- 确保订单数据时间连续性
- 处理缺失值和异常值
- 验证客户标识唯一性
- 检查数据时间覆盖度
模型选择
- 小数据集优先使用线性回归
- 大数据集推荐随机森林或XGBoost
- 注重模型可解释性时选择线性模型
- 追求预测精度时使用集成学习
业务应用
- 定期重新训练模型(建议每月)
- 结合业务规则调整预测结果
- 建立模型监控和预警机制
- 持续跟踪预测准确性
🔄 更新日志
v1.0.0 (2025-01-19)
- 初始版本发布
- 完整的RFM分析功能
- 线性回归和随机森林算法
- 基础可视化和报告功能
- 电商订单数据支持
未来计划
- 支持更多回归算法(XGBoost、LightGBM)
- 增加深度学习模型
- 实时预测API
- 更多行业数据模板
- 自动化模型部署
🤝 贡献指南
欢迎贡献代码、报告问题或提出改进建议:
1. Fork 项目 2. 创建功能分支 3. 提交更改 4. 发起 Pull Request
📄 许可证
本项目采用 MIT 许可证。
🙏 致谢
- 《数据分析咖哥十话》提供的理论基础
- Scikit-learn提供的机器学习算法
- Pandas和NumPy提供的数据处理能力
- 数据科学社区的支持和反馈
---
通过这个技能,您可以: ✅ 快速进行客户RFM分析 ✅ 构建准确的LTV预测模型 ✅ 获得可解释的业务洞察 ✅ 生成专业的分析报告 ✅ 支持数据驱动的业务决策
更新日志
[1.0.0] - 2024-12-20
新增功能
- 🎉 客户生命周期价值(LTV)预测技能首次发布
- 📊 完整的RFM特征工程模块
- 🤖 多种回归算法支持(线性回归、随机森林)
- 📈 专业的数据可视化功能
- 📋 多格式分析报告生成(HTML、Markdown、Excel)
- ⚡ 高性能批量预测功能
- 🎯 高级客户行为分析
- 🚀 完整的部署管理系统
核心模块
- data_processor.py: 数据预处理和RFM特征计算
- regression_models.py: 回归算法实现和模型评估
- ltv_predictor.py: 核心LTV预测引擎
- visualizer.py: 数据可视化模块
- report_generator.py: 分析报告生成
- quick_analysis.py: 快速分析工具
- model_optimizer.py: 模型优化器
- advanced_analytics.py: 高级分析功能
- deployment_manager.py: 部署管理器
示例和文档
- 📖 完整的README文档
- 🚀 快速入门指南
- 💡 电商LTV分析示例
- ⚡ 快速预测示例
- 🧪 功能测试验证脚本
技术特性
- ✅ 完整的中文支持
- ✅ 模块化架构设计
- ✅ 命令行工具接口
- ✅ API服务器支持
- ✅ 自动化部署包生成
- ✅ 全面的错误处理
- ✅ 性能优化和扩展
业务价值
- 🎯 精准的客户价值预测
- 📊 深度的客户行为洞察
- 🎨 智能的客户分层管理
- 💰 优化的营销策略制定
- 🔍 流失风险预警机制
性能基准
- 📈 随机森林模型R²: 0.5899
- ⚡ 处理50条订单数据 < 30秒
- 🎯 支持大规模客户数据分析
- 💾 内存优化,适合生产环境
---
计划功能 (未来版本)
[1.1.0] - 计划中
- 🔄 支持更多回归算法(XGBoost、LightGBM)
- 🌐 Web界面管理控制台
- 📱 移动端API优化
- 🤖 自动化模型重训练机制
[1.2.0] - 计划中
- 🔗 更多数据源集成
- 📊 实时数据流处理
- 🎨 可定制的可视化主题
- 🌍 多语言国际化支持
---
本项目基于"数据分析咖哥十话"第3课内容开发,专注于实际业务应用场景。
LTV预测技能快速入门指南
本指南将帮助您在10分钟内快速上手LTV预测技能,完成第一个客户生命周期价值分析。
🚀 第一步:环境准备
1. 检查Python环境
确保您的系统已安装Python 3.7或更高版本:
python --version2. 安装依赖包
# 进入技能目录
cd .claude/skills/ltv-predictor
# 安装必需的Python包
pip install pandas numpy scikit-learn matplotlib seaborn openpyxl3. 验证安装
# 运行快速验证
python -c "import pandas, sklearn, matplotlib, seaborn; print('✅ 所有依赖包安装成功')"📊 第二步:准备数据
1. 使用示例数据(推荐新手)
技能已提供示例数据,位于:
data/sample_orders.csv2. 使用自己的数据
如果您有自己的订单数据,请确保CSV文件包含以下列:
| 列名 | 说明 | 示例 |
|---|---|---|
| 订单号 | 唯一订单编号 | 1001 |
| 产品码 | 产品标识 | PROD001 |
| 消费日期 | 购买时间 | 2022-06-01 09:15 |
| 产品说明 | 产品描述 | 绿联usb分线器 |
| 数量 | 购买数量 | 2 |
| 单价 | 产品单价 | 25.50 |
| 用户码 | 客户唯一标识 | CUST001 |
| 城市 | 客户所在城市 | 北京 |
🎯 第三步:运行第一个分析
方法1:使用Python脚本(推荐)
创建一个新文件 my_first_analysis.py:
from scripts.quick_analysis import quick_ltv_analysis
# 使用示例数据进行分析
results = quick_ltv_analysis(
file_path='data/sample_orders.csv',
feature_period_months=3, # 使用前3个月数据
prediction_period_months=12, # 预测后12个月LTV
output_dir='./my_results', # 结果保存目录
generate_charts=True, # 生成图表
generate_reports=True # 生成报告
)
# 查看结果
print("🎉 分析完成!")
print(f"最佳模型: {results['summary']['model_summary']['best_model']}")
print(f"模型R²分数: {results['summary']['model_summary']['best_r2_score']:.4f}")
print(f"分析客户数: {results['summary']['data_summary']['total_customers']}")
print(f"平均LTV: {results['summary']['data_summary']['avg_ltv']:,.0f}")运行脚本:
python my_first_analysis.py方法2:使用命令行工具
# 基础分析
python scripts/quick_analysis.py analyze data/sample_orders.csv --output-dir ./cli_results
# 查看帮助
python scripts/quick_analysis.py --help📈 第四步:查看结果
分析完成后,您将在输出目录中看到以下文件:
1. 数据文件
rfm_features.csv- RFM特征和LTV数据models/- 训练好的模型文件
2. 可视化图表
charts/01_rfm_distribution.png- RFM特征分布charts/02_customer_segments.png- 客户分层分布charts/03_model_performance.png- 模型性能比较charts/04_feature_importance.png- 特征重要性charts/06_prediction_analysis.png- 预测结果分析
3. 分析报告
reports/ltv_analysis_report.html- 完整HTML报告reports/ltv_analysis_report.md- Markdown报告reports/ltv_analysis_report.xlsx- Excel报告
4. 分析摘要
analysis_summary.json- JSON格式结果摘要
🔍 第五步:理解结果
RFM特征说明
- R值:客户最近购买距离现在的天数(越小越好)
- F值:客户在特征期内的购买次数(越大越好)
- M值:客户在特征期内的总消费金额(越大越好)
客户价值分层
- 钻石客户:R、F、M值都很高
- 白金客户:F、M值较高
- 黄金客户:中等水平的客户
- 白银客户:F、M值较低
- 青铜客户:低价值客户
模型性能指标
- R²分数:模型解释能力(0-1,越接近1越好)
- MAE:平均绝对误差
- RMSE:均方根误差
- MAPE:平均绝对百分比误差
🎯 下一步建议
1. 深入学习
- 运行完整示例:
python examples/ecommerce_ltv_analysis.py - 查看技术文档:
SKILL.md
2. 实际应用
- 使用自己的订单数据进行分析
- 调整时间窗口参数
- 尝试不同的模型配置
3. 高级功能
- 预测新客户LTV:
python examples/quick_ltv_prediction.py - 批量预测功能
- 自定义特征工程
❓ 常见问题
Q1: 分析报错怎么办?
A: 首先检查: 1. 数据文件路径是否正确 2. 数据格式是否符合要求 3. 所有依赖包是否安装成功
查看详细错误信息,常见问题:
- 中文编码问题:确保文件使用UTF-8编码
- 日期格式问题:检查消费日期列格式
- 内存不足:减少数据量或调整参数
Q2: 模型准确性不高?
A: 尝试以下优化: 1. 增加历史数据量 2. 调整特征计算期和预测期 3. 启用超参数调优 4. 检查数据质量
Q3: 如何处理新客户?
A: 使用 predict_new_customers 功能:
from scripts.quick_analysis import predict_new_customers
predict_new_customers('./models', 'new_customers.csv')Q4: 大数据集处理?
A: 对于大数据集: 1. 分批处理数据 2. 关闭可视化生成 3. 使用更简单的模型 4. 增加系统内存
🎉 恭喜!
您已成功完成LTV预测技能的入门学习。现在可以:
- 使用示例数据进行各种实验
- 应用到自己的业务数据
- 探索高级功能和配置
更多资源:
- 📖 完整文档
- 🛠️ API参考
- 💡 示例代码
开始您的客户价值分析之旅吧!
#!/usr/bin/env python3
"""
高级分析模块
提供客户行为分析、流失预测、聚类分析等高级功能
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
from sklearn.ensemble import IsolationForest
from sklearn.decomposition import PCA
import warnings
warnings.filterwarnings('ignore')
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
class AdvancedAnalytics:
"""高级分析类"""
def __init__(self):
self.scaler = StandardScaler()
self.cluster_model = None
self.anomaly_detector = None
def customer_behavior_analysis(self, rfm_data, output_dir='./analysis_results'):
"""
客户行为深度分析
Args:
rfm_data: RFM特征数据
output_dir: 输出目录
Returns:
分析结果字典
"""
print("🔍 开始客户行为分析...")
results = {}
# 1. 购买模式分析
results['purchase_patterns'] = self._analyze_purchase_patterns(rfm_data)
# 2. 客户生命周期阶段分析
results['lifecycle_stages'] = self._analyze_lifecycle_stages(rfm_data)
# 3. 价值分布分析
results['value_distribution'] = self._analyze_value_distribution(rfm_data)
# 4. 活跃度分析
results['activity_analysis'] = self._analyze_activity_patterns(rfm_data)
# 生成可视化
self._plot_behavior_analysis(rfm_data, results, output_dir)
print("✅ 客户行为分析完成")
return results
def _analyze_purchase_patterns(self, rfm_data):
"""分析购买模式"""
print(" 分析购买模式...")
patterns = {}
# 频率分布
freq_dist = rfm_data['F值'].value_counts().sort_index()
patterns['frequency_distribution'] = freq_dist.to_dict()
# 金额分布
amount_stats = {
'mean': rfm_data['M值'].mean(),
'median': rfm_data['M值'].median(),
'std': rfm_data['M值'].std(),
'min': rfm_data['M值'].min(),
'max': rfm_data['M值'].max()
}
patterns['amount_statistics'] = amount_stats
# 最近购买时间分布
recency_stats = {
'mean_days': rfm_data['R值'].mean(),
'median_days': rfm_data['R值'].median(),
'recent_customers': (rfm_data['R值'] <= 30).sum(),
'inactive_customers': (rfm_data['R值'] > 90).sum()
}
patterns['recency_analysis'] = recency_stats
return patterns
def _analyze_lifecycle_stages(self, rfm_data):
"""分析客户生命周期阶段"""
print(" 分析生命周期阶段...")
# 定义生命周期阶段
def classify_lifecycle_stage(row):
r, f, m = row['R值'], row['F值'], row['M值']
if r <= 30 and f >= 3 and m >= m * 0.8: # 高R值、高F值、高M值
return "成熟期"
elif r <= 60 and f >= 2:
return "成长期"
elif r <= 30 and f == 1:
return "新客户期"
elif r > 90 and f <= 2:
return "衰退期"
elif r > 180:
return "流失期"
else:
return "稳定期"
rfm_data['生命周期阶段'] = rfm_data.apply(classify_lifecycle_stage, axis=1)
stage_counts = rfm_data['生命周期阶段'].value_counts()
stage_percentages = (stage_counts / len(rfm_data) * 100).round(2)
return {
'stage_counts': stage_counts.to_dict(),
'stage_percentages': stage_percentages.to_dict(),
'stage_distribution': rfm_data.groupby('生命周期阶段')['年度LTV'].mean().to_dict()
}
def _analyze_value_distribution(self, rfm_data):
"""分析价值分布"""
print(" 分析价值分布...")
ltv_stats = {
'mean': rfm_data['年度LTV'].mean(),
'median': rfm_data['年度LTV'].median(),
'std': rfm_data['年度LTV'].std(),
'percentiles': {
'25%': rfm_data['年度LTV'].quantile(0.25),
'50%': rfm_data['年度LTV'].quantile(0.50),
'75%': rfm_data['年度LTV'].quantile(0.75),
'90%': rfm_data['年度LTV'].quantile(0.90),
'95%': rfm_data['年度LTV'].quantile(0.95)
}
}
# 帕累托分析(80/20法则)
sorted_ltv = rfm_data['年度LTV'].sort_values(ascending=False)
total_ltv = sorted_ltv.sum()
cumulative_ltv = sorted_ltv.cumsum() / total_ltv
# 找到贡献80%价值的客户比例
eighty_percent_idx = (cumulative_ltv >= 0.8).idxmax()
top_customer_percentage = (eighty_percent_idx + 1) / len(rfm_data) * 100
ltv_stats['pareto_analysis'] = {
'top_20_percent_customers_contribute': cumulative_ltv.iloc[int(len(rfm_data) * 0.2) - 1] * 100,
'customers_for_80_percent_value': top_customer_percentage
}
return ltv_stats
def _analyze_activity_patterns(self, rfm_data):
"""分析活跃度模式"""
print(" 分析活跃度模式...")
# 活跃度分类
def classify_activity(row):
r, f = row['R值'], row['F值']
if r <= 30 and f >= 3:
return "高活跃"
elif r <= 60 and f >= 2:
return "中等活跃"
elif r <= 90 and f >= 1:
return "低活跃"
else:
return "非活跃"
rfm_data['活跃度'] = rfm_data.apply(classify_activity, axis=1)
activity_counts = rfm_data['活跃度'].value_counts()
activity_stats = rfm_data.groupby('活跃度')['年度LTV'].agg(['mean', 'count'])
return {
'activity_distribution': activity_counts.to_dict(),
'activity_value_stats': activity_stats.to_dict()
}
def _plot_behavior_analysis(self, rfm_data, results, output_dir):
"""绘制行为分析图表"""
import os
os.makedirs(output_dir, exist_ok=True)
print(" 生成行为分析图表...")
# 1. RFM分布图
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
# R值分布
axes[0, 0].hist(rfm_data['R值'], bins=20, alpha=0.7, color='skyblue')
axes[0, 0].set_title('最近购买时间分布 (R值)')
axes[0, 0].set_xlabel('距离上次购买天数')
axes[0, 0].set_ylabel('客户数')
# F值分布
axes[0, 1].hist(rfm_data['F值'], bins=10, alpha=0.7, color='lightgreen')
axes[0, 1].set_title('购买频率分布 (F值)')
axes[0, 1].set_xlabel('购买次数')
axes[0, 1].set_ylabel('客户数')
# M值分布
axes[1, 0].hist(rfm_data['M值'], bins=15, alpha=0.7, color='salmon')
axes[1, 0].set_title('消费金额分布 (M值)')
axes[1, 0].set_xlabel('总消费金额')
axes[1, 0].set_ylabel('客户数')
# LTV分布
axes[1, 1].hist(rfm_data['年度LTV'], bins=15, alpha=0.7, color='gold')
axes[1, 1].set_title('年度LTV分布')
axes[1, 1].set_xlabel('年度LTV')
axes[1, 1].set_ylabel('客户数')
plt.tight_layout()
plt.savefig(f'{output_dir}/behavior_distributions.png', dpi=300, bbox_inches='tight')
plt.close()
# 2. 生命周期阶段分布
if '生命周期阶段' in rfm_data.columns:
plt.figure(figsize=(10, 6))
stage_counts = rfm_data['生命周期阶段'].value_counts()
plt.pie(stage_counts.values, labels=stage_counts.index, autopct='%1.1f%%')
plt.title('客户生命周期阶段分布')
plt.savefig(f'{output_dir}/lifecycle_stages.png', dpi=300, bbox_inches='tight')
plt.close()
# 3. 活跃度 vs LTV
if '活跃度' in rfm_data.columns:
plt.figure(figsize=(10, 6))
sns.boxplot(data=rfm_data, x='活跃度', y='年度LTV')
plt.title('不同活跃度客户的LTV分布')
plt.ylabel('年度LTV')
plt.savefig(f'{output_dir}/activity_vs_ltv.png', dpi=300, bbox_inches='tight')
plt.close()
def advanced_customer_segmentation(self, rfm_data, n_clusters=5, output_dir='./analysis_results'):
"""
高级客户细分(基于聚类算法)
Args:
rfm_data: RFM特征数据
n_clusters: 聚类数量
output_dir: 输出目录
Returns:
聚类结果
"""
print("🎯 开始高级客户细分...")
# 准备特征数据
features = ['R值', 'F值', 'M值']
X = rfm_data[features].copy()
# 数据标准化
X_scaled = self.scaler.fit_transform(X)
# 寻找最佳聚类数量
best_k = self._find_optimal_clusters(X_scaled, max_k=10)
print(f" 最佳聚类数量: {best_k}")
# 执行K-means聚类
self.cluster_model = KMeans(n_clusters=best_k, random_state=42)
cluster_labels = self.cluster_model.fit_predict(X_scaled)
# 添加聚类标签到数据
rfm_data_copy = rfm_data.copy()
rfm_data_copy['聚类标签'] = cluster_labels
# 分析聚类结果
cluster_analysis = self._analyze_clusters(rfm_data_copy, features)
# 生成可视化
self._plot_clustering_results(rfm_data_copy, features, output_dir)
print(f"✅ 客户细分完成,共识别{best_k}个客户群体")
return {
'cluster_labels': cluster_labels,
'cluster_analysis': cluster_analysis,
'optimal_clusters': best_k,
'data_with_clusters': rfm_data_copy
}
def _find_optimal_clusters(self, X_scaled, max_k=10):
"""使用肘部法则和轮廓系数找最佳聚类数量"""
print(" 寻找最佳聚类数量...")
inertias = []
silhouette_scores = []
for k in range(2, max_k + 1):
kmeans = KMeans(n_clusters=k, random_state=42)
labels = kmeans.fit_predict(X_scaled)
inertias.append(kmeans.inertia_)
silhouette_scores.append(silhouette_score(X_scaled, labels))
# 综合考虑肘部法则和轮廓系数
# 选择轮廓系数最高的k值
best_k = np.argmax(silhouette_scores) + 2
return best_k
def _analyze_clusters(self, data, features):
"""分析聚类特征"""
print(" 分析聚类特征...")
cluster_analysis = {}
for cluster_id in sorted(data['聚类标签'].unique()):
cluster_data = data[data['聚类标签'] == cluster_id]
analysis = {
'size': len(cluster_data),
'percentage': len(cluster_data) / len(data) * 100,
'feature_means': {},
'ltv_stats': {
'mean': cluster_data['年度LTV'].mean(),
'median': cluster_data['年度LTV'].median(),
'std': cluster_data['年度LTV'].std()
}
}
for feature in features:
analysis['feature_means'][feature] = cluster_data[feature].mean()
# 为聚类命名
r_mean = analysis['feature_means']['R值']
f_mean = analysis['feature_means']['F值']
m_mean = analysis['feature_means']['M值']
if r_mean <= 30 and f_mean >= 3 and m_mean >= 500:
cluster_name = "高价值活跃客户"
elif r_mean <= 60 and f_mean >= 2:
cluster_name = "中价值潜力客户"
elif r_mean > 90 and f_mean <= 2:
cluster_name = "低价值流失风险客户"
elif r_mean <= 30 and f_mean == 1:
cluster_name = "新客户"
else:
cluster_name = f"客户群体{cluster_id + 1}"
analysis['cluster_name'] = cluster_name
cluster_analysis[cluster_id] = analysis
return cluster_analysis
def _plot_clustering_results(self, data, features, output_dir):
"""绘制聚类结果"""
import os
os.makedirs(output_dir, exist_ok=True)
print(" 生成聚类可视化...")
# 1. 聚类散点图 (使用PCA降维)
X = data[features]
X_scaled = self.scaler.transform(X)
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
plt.figure(figsize=(12, 8))
scatter = plt.scatter(X_pca[:, 0], X_pca[:, 1], c=data['聚类标签'],
cmap='viridis', alpha=0.6, s=100)
plt.colorbar(scatter)
plt.xlabel(f'主成分1 (解释方差: {pca.explained_variance_ratio_[0]:.2%})')
plt.ylabel(f'主成分2 (解释方差: {pca.explained_variance_ratio_[1]:.2%})')
plt.title('客户聚类结果 (PCA降维)')
plt.savefig(f'{output_dir}/customer_clusters_pca.png', dpi=300, bbox_inches='tight')
plt.close()
# 2. 聚类特征雷达图
self._plot_cluster_radar_chart(data, features, output_dir)
# 3. 聚类大小分布
plt.figure(figsize=(10, 6))
cluster_counts = data['聚类标签'].value_counts().sort_index()
plt.bar(range(len(cluster_counts)), cluster_counts.values)
plt.xlabel('聚类标签')
plt.ylabel('客户数')
plt.title('各聚类客户数量分布')
plt.xticks(range(len(cluster_counts)), [f'聚类{i}' for i in cluster_counts.index])
plt.savefig(f'{output_dir}/cluster_sizes.png', dpi=300, bbox_inches='tight')
plt.close()
def _plot_cluster_radar_chart(self, data, features, output_dir):
"""绘制聚类特征雷达图"""
from math import pi
# 计算各聚类的平均特征值
cluster_means = data.groupby('聚类标签')[features].mean()
# 归一化到0-1范围
normalized_means = (cluster_means - cluster_means.min()) / (cluster_means.max() - cluster_means.min())
# 雷达图设置
angles = [n / float(len(features)) * 2 * pi for n in range(len(features))]
angles += angles[:1] # 闭合图形
plt.figure(figsize=(10, 10))
ax = plt.subplot(111, polar=True)
# 为每个聚类绘制雷达图
colors = plt.cm.Set3(np.linspace(0, 1, len(cluster_means)))
for i, (cluster_id, row) in enumerate(normalized_means.iterrows()):
values = row.values.tolist()
values += values[:1] # 闭合图形
ax.plot(angles, values, 'o-', linewidth=2, label=f'聚类{cluster_id}', color=colors[i])
ax.fill(angles, values, alpha=0.25, color=colors[i])
# 设置标签
plt.xticks(angles[:-1], features)
plt.yticks([0.2, 0.4, 0.6, 0.8, 1.0], ['0.2', '0.4', '0.6', '0.8', '1.0'])
plt.title('客户聚类特征雷达图', size=16, y=1.08)
plt.legend(loc='upper right', bbox_to_anchor=(1.3, 1.0))
plt.savefig(f'{output_dir}/cluster_radar_chart.png', dpi=300, bbox_inches='tight')
plt.close()
def churn_prediction(self, rfm_data, output_dir='./analysis_results'):
"""
客户流失预测分析
Args:
rfm_data: RFM特征数据
output_dir: 输出目录
Returns:
流失预测结果
"""
print("⚠️ 开始流失预测分析...")
# 定义流失标签
def define_churn(row):
# 基于R值定义流失:90天未购买为流失
return 1 if row['R值'] > 90 else 0
rfm_data_copy = rfm_data.copy()
rfm_data_copy['流失标签'] = rfm_data_copy.apply(define_churn, axis=1)
# 流失统计分析
churn_rate = rfm_data_copy['流失标签'].mean()
print(f" 当前流失率: {churn_rate:.2%}")
# 流失特征分析
churn_features = self._analyze_churn_features(rfm_data_copy)
# 高风险流失客户识别
high_risk_customers = self._identify_high_risk_customers(rfm_data_copy)
# 生成可视化
self._plot_churn_analysis(rfm_data_copy, output_dir)
print("✅ 流失预测分析完成")
return {
'churn_rate': churn_rate,
'churn_features': churn_features,
'high_risk_customers': high_risk_customers,
'data_with_churn_labels': rfm_data_copy
}
def _analyze_churn_features(self, data):
"""分析流失相关特征"""
churn_group = data.groupby('流失标签')[['R值', 'F值', 'M值']].mean()
return churn_group.to_dict()
def _identify_high_risk_customers(self, data, risk_threshold=0.7):
"""识别高风险流失客户"""
# 基于R值和F值识别高风险客户
high_risk = data[
(data['R值'] > 60) | # 60天未购买
(data['F值'] <= 1) # 只购买过一次
].sort_values('R值', ascending=False)
return high_risk.head(20) # 返回前20个高风险客户
def _plot_churn_analysis(self, data, output_dir):
"""绘制流失分析图表"""
import os
os.makedirs(output_dir, exist_ok=True)
# 1. 流失vs非流失客户特征对比
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
features = ['R值', 'F值', 'M值']
feature_names = ['最近购买', '购买频率', '消费金额']
for i, (feature, name) in enumerate(zip(features, feature_names)):
churn_0 = data[data['流失标签'] == 0][feature]
churn_1 = data[data['流失标签'] == 1][feature]
axes[i].hist([churn_0, churn_1], bins=20, alpha=0.7,
label=['非流失', '流失'], color=['green', 'red'])
axes[i].set_title(f'{name}分布')
axes[i].set_xlabel(name)
axes[i].set_ylabel('客户数')
axes[i].legend()
plt.tight_layout()
plt.savefig(f'{output_dir}/churn_feature_comparison.png', dpi=300, bbox_inches='tight')
plt.close()
# 2. 流失风险散点图
plt.figure(figsize=(10, 6))
scatter = plt.scatter(data['R值'], data['F值'], c=data['流失标签'],
cmap='RdYlGn', alpha=0.6, s=100)
plt.colorbar(scatter)
plt.xlabel('最近购买天数 (R值)')
plt.ylabel('购买频率 (F值)')
plt.title('客户流失风险分布')
plt.savefig(f'{output_dir}/churn_risk_scatter.png', dpi=300, bbox_inches='tight')
plt.close()
def generate_comprehensive_insights(self, rfm_data, behavior_results,
segmentation_results, churn_results,
output_path='comprehensive_insights.md'):
"""生成综合洞察报告"""
print("📋 生成综合洞察报告...")
report = "# 客户生命周期价值综合洞察报告\n\n"
report += f"生成时间: {pd.Timestamp.now()}\n\n"
# 客户概览
report += "## 客户概览\n\n"
report += f"- 总客户数: {len(rfm_data):,}\n"
report += f"- 平均年度LTV: {rfm_data['年度LTV'].mean():,.0f}\n"
report += f"- LTV中位数: {rfm_data['年度LTV'].median():,.0f}\n"
report += f"- 平均购买频率: {rfm_data['F值'].mean():.1f}次\n"
report += f"- 平均最近购买: {rfm_data['R值'].mean():.0f}天前\n\n"
# 行为分析洞察
if behavior_results:
report += "## 客户行为洞察\n\n"
# 生命周期阶段
if 'lifecycle_stages' in behavior_results:
stages = behavior_results['lifecycle_stages']
report += "### 生命周期阶段分布\n\n"
for stage, percentage in stages['stage_percentages'].items():
report += f"- {stage}: {percentage}%\n"
report += "\n"
# 细分分析洞察
if segmentation_results:
report += "## 客户细分洞察\n\n"
clusters = segmentation_results['cluster_analysis']
for cluster_id, analysis in clusters.items():
report += f"### {analysis['cluster_name']}\n\n"
report += f"- 客户数量: {analysis['size']} ({analysis['percentage']:.1f}%)\n"
report += f"- 平均LTV: {analysis['ltv_stats']['mean']:,.0f}\n"
report += f"- 特征特征: R值{analysis['feature_means']['R值']:.1f}, "
report += f"F值{analysis['feature_means']['F值']:.1f}, "
report += f"M值{analysis['feature_means']['M值']:.0f}\n\n"
# 流失分析洞察
if churn_results:
report += "## 流失风险洞察\n\n"
report += f"当前流失率: {churn_results['churn_rate']:.1%}\n\n"
high_risk = churn_results['high_risk_customers']
if not high_risk.empty:
report += f"高风险客户数: {len(high_risk)}\n"
report += "主要风险因素:\n"
report += "- 长时间未购买 (R值 > 60天)\n"
report += "- 购买频率低 (F值 ≤ 1)\n\n"
# 策略建议
report += "## 营销策略建议\n\n"
report += "基于上述分析,建议采取以下策略:\n\n"
if segmentation_results:
# 基于聚类结果的建议
clusters = segmentation_results['cluster_analysis']
for cluster_id, analysis in clusters.items():
cluster_name = analysis['cluster_name']
if '高价值' in cluster_name:
report += f"### {cluster_name}\n"
report += "- 提供VIP专属服务\n"
report += "- 安排客户经理专人对接\n"
report += "- 定制个性化营销方案\n\n"
elif '潜力' in cluster_name:
report += f"### {cluster_name}\n"
report += "- 推荐升级产品和套餐\n"
report += "- 提供会员激励计划\n"
report += "- 增加互动频率\n\n"
elif '流失风险' in cluster_name:
report += f"### {cluster_name}\n"
report += "- 发放召回优惠券\n"
report += "- 推荐性价比高的产品\n"
report += "- 主动关怀和沟通\n\n"
if churn_results and churn_results['churn_rate'] > 0.2:
report += "### 流失预防策略\n"
report += "- 建立流失预警机制\n"
report += "- 实施客户关怀计划\n"
report += "- 优化产品和服务体验\n\n"
# 保存报告
with open(output_path, 'w', encoding='utf-8') as f:
f.write(report)
print(f"✅ 综合洞察报告已保存: {output_path}")
return output_path#!/usr/bin/env python3
"""
数据预处理器和RFM特征工程模块
基于第3课核心算法实现RFM分析和数据预处理功能
"""
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
from typing import Dict, Tuple, Optional, Union
import warnings
warnings.filterwarnings('ignore')
class DataProcessor:
"""
数据预处理器
专门处理电商订单数据,进行RFM特征工程和数据预处理
支持多种数据格式和时间窗口配置
"""
def __init__(self, config: Optional[Dict] = None):
"""
初始化数据处理器
Args:
config: 配置参数字典
"""
# 默认配置
self.config = {
'date_column': '消费日期',
'customer_column': '用户码',
'quantity_column': '数量',
'price_column': '单价',
'order_id_column': '订单号',
'product_column': '产品码',
'city_column': '城市',
'feature_period_months': 3,
'prediction_period_months': 12,
'min_orders_per_customer': 1,
'remove_outliers': True,
'outlier_threshold': 3.0
}
# 更新配置
if config:
self.config.update(config)
# 数据存储
self.raw_data = None
self.processed_data = None
self.rfm_data = None
self.data_quality_report = {}
def load_order_data(self, file_path: str, **kwargs) -> pd.DataFrame:
"""
加载订单数据
Args:
file_path: 文件路径
**kwargs: pandas.read_csv的额外参数
Returns:
加载的订单数据
"""
try:
# 尝试不同的编码格式
encodings = ['utf-8', 'utf-8-sig', 'gbk', 'gb2312']
for encoding in encodings:
try:
self.raw_data = pd.read_csv(file_path, encoding=encoding, **kwargs)
print(f"✓ 数据加载成功: {self.raw_data.shape}")
print(f" - 使用编码: {encoding}")
break
except UnicodeDecodeError:
continue
else:
raise ValueError("无法解码文件,请检查文件编码")
# 数据质量检查
self._validate_data()
self._generate_data_quality_report()
return self.raw_data
except Exception as e:
raise ValueError(f"数据加载失败: {str(e)}")
def _validate_data(self):
"""验证数据格式和必需字段"""
required_columns = [
self.config['date_column'],
self.config['customer_column'],
self.config['quantity_column'],
self.config['price_column']
]
missing_columns = [col for col in required_columns if col not in self.raw_data.columns]
if missing_columns:
raise ValueError(f"缺少必需字段: {missing_columns}")
print(f"✓ 数据验证通过,包含必需字段: {required_columns}")
def _generate_data_quality_report(self):
"""生成数据质量报告"""
df = self.raw_data
report = {
'total_rows': len(df),
'total_columns': len(df.columns),
'total_orders': df[self.config['order_id_column']].nunique() if self.config['order_id_column'] in df.columns else 'Unknown',
'total_customers': df[self.config['customer_column']].nunique(),
'total_products': df[self.config['product_column']].nunique() if self.config['product_column'] in df.columns else 'Unknown',
'date_range': self._get_date_range(),
'missing_values': df.isnull().sum().to_dict(),
'duplicate_orders': df.duplicated(subset=[self.config['order_id_column']]).sum() if self.config['order_id_column'] in df.columns else 'Unknown'
}
self.data_quality_report = report
# 打印质量报告
print(f"📊 数据质量报告:")
print(f" - 总记录数: {report['total_rows']:,}")
print(f" - 总客户数: {report['total_customers']:,}")
print(f" - 时间范围: {report['date_range'][0]} ~ {report['date_range'][1]}")
print(f" - 缺失值: {sum(val for val in report['missing_values'].values())}")
def _get_date_range(self) -> Tuple[str, str]:
"""获取数据时间范围"""
try:
dates = pd.to_datetime(self.raw_data[self.config['date_column']])
return (dates.min().strftime('%Y-%m-%d'),
dates.max().strftime('%Y-%m-%d'))
except:
return ('Unknown', 'Unknown')
def preprocess_data(self, data: Optional[pd.DataFrame] = None) -> pd.DataFrame:
"""
预处理订单数据
Args:
data: 输入数据,如果为None则使用self.raw_data
Returns:
预处理后的数据
"""
if data is None:
data = self.raw_data.copy()
print("🧹 开始数据预处理...")
# 1. 创建总价字段
if '总价' not in data.columns:
data['总价'] = data[self.config['quantity_column']] * data[self.config['price_column']]
print(" ✓ 计算总价")
# 2. 转换日期格式
data[self.config['date_column']] = pd.to_datetime(data[self.config['date_column']])
print(" ✓ 转换日期格式")
# 3. 过滤异常数据
if self.config['remove_outliers']:
data = self._remove_outliers(data)
print(" ✓ 移除异常值")
# 4. 筛选活跃客户
min_orders = self.config['min_orders_per_customer']
customer_order_counts = data[self.config['customer_column']].value_counts()
active_customers = customer_order_counts[customer_order_counts >= min_orders].index
data = data[data[self.config['customer_column']].isin(active_customers)]
print(f" ✓ 筛选活跃客户 (≥{min_orders}订单): {len(active_customers)}个客户")
# 5. 数据排序
data = data.sort_values([self.config['customer_column'], self.config['date_column']])
self.processed_data = data
print(f"✓ 数据预处理完成: {data.shape}")
return data
def _remove_outliers(self, data: pd.DataFrame) -> pd.DataFrame:
"""移除异常值"""
threshold = self.config['outlier_threshold']
# 移除价格异常值
price_mean = data[self.config['price_column']].mean()
price_std = data[self.config['price_column']].std()
price_outliers = np.abs(data[self.config['price_column']] - price_mean) > threshold * price_std
# 移除数量异常值
qty_mean = data[self.config['quantity_column']].mean()
qty_std = data[self.config['quantity_column']].std()
qty_outliers = np.abs(data[self.config['quantity_column']] - qty_mean) > threshold * qty_std
# 移除总价异常值
total_mean = data['总价'].mean()
total_std = data['总价'].std()
total_outliers = np.abs(data['总价'] - total_mean) > threshold * total_std
# 组合异常值条件
outlier_mask = price_outliers | qty_outliers | total_outliers
clean_data = data[~outlier_mask]
removed_count = len(data) - len(clean_data)
if removed_count > 0:
print(f" 移除异常值: {removed_count} 条记录")
return clean_data
def calculate_rfm_features(self,
data: Optional[pd.DataFrame] = None,
feature_period_months: Optional[int] = None,
prediction_period_months: Optional[int] = None) -> pd.DataFrame:
"""
计算RFM特征
Args:
data: 输入数据
feature_period_months: 特征计算时间窗口(月)
prediction_period_months: 预测时间窗口(月)
Returns:
包含RFM特征和LTV标签的数据
"""
if data is None:
data = self.processed_data
else:
# 如果传入的是原始数据,需要先预处理
if self.processed_data is None or not data.equals(self.processed_data):
data = self.preprocess_data(data)
if feature_period_months is None:
feature_period_months = self.config['feature_period_months']
if prediction_period_months is None:
prediction_period_months = self.config['prediction_period_months']
print(f"🔍 开始RFM特征计算...")
print(f" - 特征计算期: {feature_period_months}个月")
print(f" - 预测期: {prediction_period_months}个月")
# 确定数据时间范围
data_sorted = data.sort_values(self.config['date_column'])
start_date = data_sorted[self.config['date_column']].min()
# 确保start_date是Timestamp类型
if not isinstance(start_date, pd.Timestamp):
start_date = pd.to_datetime(start_date)
feature_end_date = start_date + pd.DateOffset(months=feature_period_months)
prediction_end_date = start_date + pd.DateOffset(months=prediction_period_months)
print(f" - 特征计算期: {start_date.strftime('%Y-%m-%d')} ~ {feature_end_date.strftime('%Y-%m-%d')}")
print(f" - 完整预测期: {start_date.strftime('%Y-%m-%d')} ~ {prediction_end_date.strftime('%Y-%m-%d')}")
# 特征计算期数据
feature_data = data[
(data[self.config['date_column']] > start_date) &
(data[self.config['date_column']] <= feature_end_date)
].copy()
# 完整数据用于计算LTV
full_data = data[
(data[self.config['date_column']] > start_date) &
(data[self.config['date_column']] <= prediction_end_date)
].copy()
# 获取独立客户列表
unique_customers = feature_data[self.config['customer_column']].unique()
print(f" - 活跃客户数: {len(unique_customers)}")
# 初始化RFM数据框
rfm_data = pd.DataFrame({
self.config['customer_column']: unique_customers
})
# 计算R值 (Recency - 最近一次消费距期末天数)
print(" 计算R值 (最近消费时间间隔)...")
r_data = feature_data.groupby(self.config['customer_column'])[self.config['date_column']].max().reset_index()
r_data.columns = [self.config['customer_column'], '最近购买日期']
r_data['R值'] = (feature_end_date - r_data['最近购买日期']).dt.days
rfm_data = rfm_data.merge(r_data[[self.config['customer_column'], 'R值']],
on=self.config['customer_column'], how='left')
# 计算F值 (Frequency - 消费频率)
print(" 计算F值 (消费频率)...")
f_data = feature_data.groupby(self.config['customer_column'])[self.config['date_column']].count().reset_index()
f_data.columns = [self.config['customer_column'], 'F值']
rfm_data = rfm_data.merge(f_data, on=self.config['customer_column'], how='left')
# 计算M值 (Monetary - 消费金额)
print(" 计算M值 (消费金额)...")
m_data = feature_data.groupby(self.config['customer_column'])['总价'].sum().reset_index()
m_data.columns = [self.config['customer_column'], 'M值']
rfm_data = rfm_data.merge(m_data, on=self.config['customer_column'], how='left')
# 计算年度LTV (目标变量)
print(" 计算年度LTV (目标变量)...")
ltv_data = full_data.groupby(self.config['customer_column'])['总价'].sum().reset_index()
ltv_data.columns = [self.config['customer_column'], '年度LTV']
rfm_data = rfm_data.merge(ltv_data, on=self.config['customer_column'], how='left')
# 处理缺失值
rfm_data['年度LTV'] = rfm_data['年度LTV'].fillna(0)
# 添加RFM分析信息
self._add_rfm_insights(rfm_data)
self.rfm_data = rfm_data
print(f"✓ RFM特征计算完成: {rfm_data.shape}")
return rfm_data
def _add_rfm_insights(self, rfm_data: pd.DataFrame):
"""添加RFM分析洞察"""
# RFM分位数分析 - 处理边界情况
try:
rfm_data['R_分位数'] = pd.qcut(rfm_data['R值'], q=4, labels=['D', 'C', 'B', 'A'], duplicates='drop')
except ValueError:
# 如果qcut失败,使用cut作为备选方案
rfm_data['R_分位数'] = pd.cut(rfm_data['R值'], bins=4, labels=['D', 'C', 'B', 'A'], include_lowest=True)
try:
rfm_data['F_分位数'] = pd.qcut(rfm_data['F值'], q=4, labels=['A', 'B', 'C', 'D'], duplicates='drop')
except ValueError:
rfm_data['F_分位数'] = pd.cut(rfm_data['F值'], bins=4, labels=['A', 'B', 'C', 'D'], include_lowest=True)
try:
rfm_data['M_分位数'] = pd.qcut(rfm_data['M值'], q=4, labels=['A', 'B', 'C', 'D'], duplicates='drop')
except ValueError:
rfm_data['M_分位数'] = pd.cut(rfm_data['M值'], bins=4, labels=['A', 'B', 'C', 'D'], include_lowest=True)
# RFM组合分群
rfm_data['RFM_分群'] = rfm_data['R_分位数'].astype(str) + rfm_data['F_分位数'].astype(str) + rfm_data['M_分位数'].astype(str)
# 计算RFM得分
rfm_data['RFM_得分'] = (
rfm_data['R值'].rank(ascending=False) * 0.2 +
rfm_data['F值'].rank() * 0.3 +
rfm_data['M值'].rank() * 0.5
)
def segment_customers(self, rfm_data: Optional[pd.DataFrame] = None, n_segments: int = 5) -> pd.DataFrame:
"""
客户分群
Args:
rfm_data: RFM数据
n_segments: 分群数量
Returns:
包含客户分群的数据
"""
if rfm_data is None:
rfm_data = self.rfm_data
# 基于RFM得分进行分群
rfm_data['客户价值分层'] = pd.qcut(
rfm_data['RFM_得分'],
q=n_segments,
labels=['铜牌客户', '银牌客户', '金牌客户', '白金客户', '钻石客户']
)
# 计算各层级统计信息
segment_stats = rfm_data.groupby('客户价值分层').agg({
self.config['customer_column']: 'count',
'年度LTV': ['mean', 'sum'],
'R值': 'mean',
'F值': 'mean',
'M值': 'mean'
}).round(2)
print("📊 客户价值分层统计:")
print(segment_stats)
return rfm_data
def get_rfm_summary(self, rfm_data: Optional[pd.DataFrame] = None) -> Dict:
"""
获取RFM分析摘要
Args:
rfm_data: RFM数据
Returns:
RFM分析摘要字典
"""
if rfm_data is None:
rfm_data = self.rfm_data
if rfm_data is None:
return {"error": "RFM数据未计算,请先运行calculate_rfm_features"}
summary = {
'total_customers': len(rfm_data),
'date_range': self._get_date_range(),
'rfm_statistics': {
'R值': {
'mean': rfm_data['R值'].mean(),
'median': rfm_data['R值'].median(),
'std': rfm_data['R值'].std(),
'min': rfm_data['R值'].min(),
'max': rfm_data['R值'].max()
},
'F值': {
'mean': rfm_data['F值'].mean(),
'median': rfm_data['F值'].median(),
'std': rfm_data['F值'].std(),
'min': rfm_data['F值'].min(),
'max': rfm_data['F值'].max()
},
'M值': {
'mean': rfm_data['M值'].mean(),
'median': rfm_data['M值'].median(),
'std': rfm_data['M值'].std(),
'min': rfm_data['M值'].min(),
'max': rfm_data['M值'].max()
},
'年度LTV': {
'mean': rfm_data['年度LTV'].mean(),
'median': rfm_data['年度LTV'].median(),
'std': rfm_data['年度LTV'].std(),
'min': rfm_data['年度LTV'].min(),
'max': rfm_data['年度LTV'].max()
}
},
'high_value_customers': {
'top_10_percent_threshold': rfm_data['年度LTV'].quantile(0.9),
'count': len(rfm_data[rfm_data['年度LTV'] >= rfm_data['年度LTV'].quantile(0.9)])
}
}
return summary
def export_rfm_data(self, rfm_data: pd.DataFrame, output_path: str, format: str = 'csv'):
"""
导出RFM数据
Args:
rfm_data: RFM数据
output_path: 输出路径
format: 输出格式 ('csv', 'excel')
"""
try:
if format.lower() == 'csv':
rfm_data.to_csv(output_path, index=False, encoding='utf-8-sig')
elif format.lower() == 'excel':
rfm_data.to_excel(output_path, index=False)
else:
raise ValueError("不支持的格式,请使用 'csv' 或 'excel'")
print(f"✓ RFM数据已导出: {output_path}")
except Exception as e:
print(f"❌ 导出失败: {str(e)}")
# 便利函数
def quick_rfm_analysis(file_path: str,
feature_period_months: int = 3,
prediction_period_months: int = 12,
output_dir: str = './rfm_results') -> Dict:
"""
快速RFM分析
Args:
file_path: 订单数据文件路径
feature_period_months: 特征计算期(月)
prediction_period_months: 预测期(月)
output_dir: 输出目录
Returns:
分析结果字典
"""
import os
from pathlib import Path
# 创建输出目录
Path(output_dir).mkdir(parents=True, exist_ok=True)
# 初始化处理器
processor = DataProcessor({
'feature_period_months': feature_period_months,
'prediction_period_months': prediction_period_months
})
# 加载和预处理数据
data = processor.load_order_data(file_path)
processed_data = processor.preprocess_data(data)
# 计算RFM特征
rfm_data = processor.calculate_rfm_features(processed_data)
# 客户分群
segmented_data = processor.segment_customers(rfm_data)
# 获取摘要
summary = processor.get_rfm_summary(segmented_data)
# 导出结果
rfm_output_path = os.path.join(output_dir, 'rfm_features.csv')
processor.export_rfm_data(segmented_data, rfm_output_path)
return {
'rfm_data': segmented_data,
'summary': summary,
'processor': processor,
'output_paths': {
'rfm_features': rfm_output_path
}
}
if __name__ == "__main__":
# 示例使用
print("🔧 数据处理器测试")
# 如果有示例数据文件,可以进行测试
sample_file = '../data/sample_orders.csv'
if os.path.exists(sample_file):
results = quick_rfm_analysis(sample_file)
print("✓ 快速RFM分析完成")
else:
print("⚠️ 示例数据文件不存在,跳过测试")#!/usr/bin/env python3
"""
部署管理器
提供LTV预测技能的部署、集成和管理功能
"""
import os
import json
import pickle
import joblib
import pandas as pd
from pathlib import Path
from typing import Dict, Any, List, Optional
import shutil
import zipfile
from datetime import datetime
class DeploymentManager:
"""部署管理器类"""
def __init__(self, skill_dir: str = None):
"""
初始化部署管理器
Args:
skill_dir: 技能根目录
"""
if skill_dir is None:
# 默认为当前脚本所在目录的上级目录
self.skill_dir = Path(__file__).parent.parent
else:
self.skill_dir = Path(skill_dir)
self.config_dir = self.skill_dir / 'config'
self.models_dir = self.skill_dir / 'models'
self.data_dir = self.skill_dir / 'data'
self.docs_dir = self.skill_dir / 'docs'
# 确保目录存在
for dir_path in [self.config_dir, self.models_dir, self.data_dir, self.docs_dir]:
dir_path.mkdir(parents=True, exist_ok=True)
def create_deployment_package(self, output_path: str = None,
include_models: bool = True,
include_data: bool = False,
include_docs: bool = True) -> str:
"""
创建部署包
Args:
output_path: 输出路径
include_models: 是否包含模型文件
include_data: 是否包含数据文件
include_docs: 是否包含文档
Returns:
部署包路径
"""
print("📦 创建部署包...")
if output_path is None:
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
output_path = f"ltv_predictor_deployment_{timestamp}.zip"
output_path = Path(output_path)
# 创建临时目录
temp_dir = self.skill_dir / 'temp_deployment'
if temp_dir.exists():
shutil.rmtree(temp_dir)
temp_dir.mkdir()
try:
# 复制核心文件
self._copy_core_files(temp_dir)
# 复制模型文件(如果需要)
if include_models:
self._copy_models(temp_dir)
# 复制数据文件(如果需要)
if include_data:
self._copy_data(temp_dir)
# 复制文档(如果需要)
if include_docs:
self._copy_docs(temp_dir)
# 创建部署配置
self._create_deployment_config(temp_dir)
# 创建启动脚本
self._create_startup_scripts(temp_dir)
# 创建ZIP包
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
for file_path in temp_dir.rglob('*'):
if file_path.is_file():
arcname = file_path.relative_to(temp_dir)
zipf.write(file_path, arcname)
print(f"✅ 部署包已创建: {output_path}")
print(f" 包大小: {output_path.stat().st_size / 1024 / 1024:.1f} MB")
finally:
# 清理临时目录
if temp_dir.exists():
shutil.rmtree(temp_dir)
return str(output_path)
def _copy_core_files(self, temp_dir: Path):
"""复制核心文件"""
print(" 复制核心文件...")
core_files = [
'scripts/data_processor.py',
'scripts/regression_models.py',
'scripts/ltv_predictor.py',
'scripts/visualizer.py',
'scripts/report_generator.py',
'scripts/quick_analysis.py',
'scripts/model_optimizer.py',
'scripts/advanced_analytics.py',
'scripts/deployment_manager.py',
'SKILL.md',
'README.md'
]
for file_path in core_files:
src = self.skill_dir / file_path
if src.exists():
dst = temp_dir / file_path
dst.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(src, dst)
print(f" ✓ {file_path}")
def _copy_models(self, temp_dir: Path):
"""复制模型文件"""
print(" 复制模型文件...")
models_src = self.skill_dir / 'models'
if models_src.exists():
models_dst = temp_dir / 'models'
shutil.copytree(models_src, models_dst, dirs_exist_ok=True)
print(f" ✓ 模型文件已复制")
def _copy_data(self, temp_dir: Path):
"""复制数据文件"""
print(" 复制数据文件...")
data_src = self.skill_dir / 'data'
if data_src.exists():
data_dst = temp_dir / 'data'
shutil.copytree(data_src, data_dst, dirs_exist_ok=True)
print(f" ✓ 数据文件已复制")
def _copy_docs(self, temp_dir: Path):
"""复制文档文件"""
print(" 复制文档文件...")
docs_src = self.skill_dir / 'docs'
if docs_src.exists():
docs_dst = temp_dir / 'docs'
shutil.copytree(docs_src, docs_dst, dirs_exist_ok=True)
print(f" ✓ 文档文件已复制")
examples_src = self.skill_dir / 'examples'
if examples_src.exists():
examples_dst = temp_dir / 'examples'
shutil.copytree(examples_src, examples_dst, dirs_exist_ok=True)
print(f" ✓ 示例文件已复制")
def _create_deployment_config(self, temp_dir: Path):
"""创建部署配置"""
config = {
'skill_info': {
'name': 'ltv-predictor',
'version': '1.0.0',
'description': '客户生命周期价值预测技能',
'author': 'Claude Code',
'created_at': datetime.now().isoformat()
},
'dependencies': [
'pandas>=1.3.0',
'numpy>=1.21.0',
'scikit-learn>=1.0.0',
'matplotlib>=3.5.0',
'seaborn>=0.11.0',
'openpyxl>=3.0.0'
],
'default_config': {
'feature_period_months': 3,
'prediction_period_months': 12,
'models_to_train': ['linear_regression', 'random_forest'],
'enable_visualization': True,
'enable_reports': True
},
'api_endpoints': {
'analyze': '/api/v1/analyze',
'predict': '/api/v1/predict',
'batch_predict': '/api/v1/batch_predict',
'model_info': '/api/v1/model_info'
}
}
config_path = temp_dir / 'deployment_config.json'
with open(config_path, 'w', encoding='utf-8') as f:
json.dump(config, f, indent=2, ensure_ascii=False)
print(f" ✓ 部署配置已创建")
def _create_startup_scripts(self, temp_dir: Path):
"""创建启动脚本"""
# 创建Windows批处理文件
windows_script = '''@echo off
echo 启动LTV预测技能服务...
python scripts/deployment_manager.py start_server
pause
'''
with open(temp_dir / 'start.bat', 'w', encoding='utf-8') as f:
f.write(windows_script)
# 创建Linux/Mac shell脚本
linux_script = '''#!/bin/bash
echo "启动LTV预测技能服务..."
python scripts/deployment_manager.py start_server
'''
with open(temp_dir / 'start.sh', 'w', encoding='utf-8') as f:
f.write(linux_script)
# 使shell脚本可执行
os.chmod(temp_dir / 'start.sh', 0o755)
print(f" ✓ 启动脚本已创建")
def validate_deployment(self, deployment_path: str) -> Dict[str, Any]:
"""
验证部署包
Args:
deployment_path: 部署包路径
Returns:
验证结果
"""
print("🔍 验证部署包...")
deployment_path = Path(deployment_path)
validation_result = {
'is_valid': True,
'errors': [],
'warnings': [],
'file_count': 0,
'total_size': 0
}
try:
# 检查文件是否存在
if not deployment_path.exists():
validation_result['is_valid'] = False
validation_result['errors'].append("部署包文件不存在")
return validation_result
# 检查文件大小
size_mb = deployment_path.stat().st_size / 1024 / 1024
validation_result['total_size'] = size_mb
if size_mb > 100:
validation_result['warnings'].append("部署包较大,建议优化大小")
# 检查ZIP文件完整性
with zipfile.ZipFile(deployment_path, 'r') as zipf:
validation_result['file_count'] = len(zipf.namelist())
# 检查必要文件
required_files = [
'scripts/ltv_predictor.py',
'scripts/quick_analysis.py',
'deployment_config.json'
]
for required_file in required_files:
if required_file not in zipf.namelist():
validation_result['is_valid'] = False
validation_result['errors'].append(f"缺少必要文件: {required_file}")
print(f"✅ 部署包验证完成")
print(f" 文件数量: {validation_result['file_count']}")
print(f" 包大小: {size_mb:.1f} MB")
print(f" 验证状态: {'通过' if validation_result['is_valid'] else '失败'}")
if validation_result['warnings']:
print(f" 警告: {len(validation_result['warnings'])}个")
except Exception as e:
validation_result['is_valid'] = False
validation_result['errors'].append(f"验证过程中出现错误: {str(e)}")
return validation_result
def install_dependencies(self) -> bool:
"""
安装依赖包
Returns:
是否安装成功
"""
print("📦 安装依赖包...")
dependencies = [
'pandas>=1.3.0',
'numpy>=1.21.0',
'scikit-learn>=1.0.0',
'matplotlib>=3.5.0',
'seaborn>=0.11.0',
'openpyxl>=3.0.0'
]
try:
import subprocess
for dep in dependencies:
print(f" 安装 {dep}...")
result = subprocess.run(['pip', 'install', dep],
capture_output=True, text=True)
if result.returncode != 0:
print(f" ❌ 安装失败: {result.stderr}")
return False
print(f" ✓ {dep}")
print("✅ 所有依赖包安装成功")
return True
except Exception as e:
print(f"❌ 依赖包安装失败: {str(e)}")
return False
def setup_environment(self) -> bool:
"""
设置运行环境
Returns:
是否设置成功
"""
print("🔧 设置运行环境...")
try:
# 创建必要的目录
directories = [
'logs',
'temp',
'output',
'models/trained',
'data/upload',
'reports'
]
for directory in directories:
dir_path = self.skill_dir / directory
dir_path.mkdir(parents=True, exist_ok=True)
print(f" ✓ 创建目录: {directory}")
# 创建环境配置文件
env_config = {
'LOG_LEVEL': 'INFO',
'MAX_UPLOAD_SIZE': '100MB',
'DEFAULT_MODEL': 'random_forest',
'CACHE_TIMEOUT': 3600,
'ENABLE_MONITORING': True
}
env_path = self.skill_dir / '.env'
with open(env_path, 'w', encoding='utf-8') as f:
for key, value in env_config.items():
f.write(f"{key}={value}\n")
print(" ✓ 环境配置已创建")
print("✅ 运行环境设置完成")
return True
except Exception as e:
print(f"❌ 环境设置失败: {str(e)}")
return False
def create_api_server(self) -> str:
"""
创建API服务器脚本
Returns:
API服务器脚本路径
"""
print("🌐 创建API服务器...")
api_script = '''#!/usr/bin/env python3
"""
LTV预测技能API服务器
提供RESTful API接口
"""
import json
import os
import sys
from pathlib import Path
from datetime import datetime
# 添加技能模块路径
current_dir = Path(__file__).parent
sys.path.append(str(current_dir / 'scripts'))
try:
from flask import Flask, request, jsonify
from quick_analysis import quick_ltv_analysis, predict_new_customers
from ltv_predictor import LTVPredictor
except ImportError as e:
print(f"缺少依赖包: {e}")
print("请运行: pip install flask")
sys.exit(1)
app = Flask(__name__)
# 全局变量
predictor = None
@app.route('/api/v1/health', methods=['GET'])
def health_check():
"""健康检查"""
return jsonify({
'status': 'healthy',
'timestamp': datetime.now().isoformat(),
'version': '1.0.0'
})
@app.route('/api/v1/analyze', methods=['POST'])
def analyze_data():
"""分析数据并训练模型"""
try:
data = request.get_json()
# 验证输入参数
if 'data_file' not in data:
return jsonify({'error': '缺少data_file参数'}), 400
# 执行分析
results = quick_ltv_analysis(
file_path=data['data_file'],
feature_period_months=data.get('feature_period_months', 3),
prediction_period_months=data.get('prediction_period_months', 12),
output_dir=data.get('output_dir', './api_results'),
generate_charts=data.get('generate_charts', True),
generate_reports=data.get('generate_reports', True)
)
return jsonify({
'status': 'success',
'results': {
'best_model': results['summary']['model_summary']['best_model'],
'r2_score': results['summary']['model_summary']['best_r2_score'],
'total_customers': results['summary']['data_summary']['total_customers'],
'avg_ltv': results['summary']['data_summary']['avg_ltv']
}
})
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/v1/predict', methods=['POST'])
def predict_ltv():
"""预测新客户LTV"""
try:
data = request.get_json()
if 'model_dir' not in data or 'new_orders_file' not in data:
return jsonify({'error': '缺少必要参数'}), 400
# 执行预测
predictions = predict_new_customers(
data['model_dir'],
data['new_orders_file'],
data.get('output_path', 'api_predictions.csv')
)
return jsonify({
'status': 'success',
'predictions_count': len(predictions),
'avg_predicted_ltv': predictions['预测LTV'].mean(),
'max_predicted_ltv': predictions['预测LTV'].max(),
'min_predicted_ltv': predictions['预测LTV'].min()
})
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/v1/model_info', methods=['GET'])
def get_model_info():
"""获取模型信息"""
return jsonify({
'available_models': ['linear_regression', 'random_forest'],
'default_features': ['R值', 'F值', 'M值'],
'supported_formats': ['csv', 'xlsx'],
'version': '1.0.0'
})
if __name__ == '__main__':
print("🚀 启动LTV预测API服务器...")
print("📡 服务地址: http://localhost:5000")
print("📖 API文档: http://localhost:5000/api/v1/model_info")
app.run(host='0.0.0.0', port=5000, debug=True)
'''
api_path = self.skill_dir / 'api_server.py'
with open(api_path, 'w', encoding='utf-8') as f:
f.write(api_script)
print(f"✅ API服务器脚本已创建: {api_path}")
return str(api_path)
def start_server(self, host='localhost', port=5000):
"""
启动API服务器
Args:
host: 主机地址
port: 端口号
"""
print(f"🚀 启动服务器 {host}:{port}...")
try:
# 检查Flask是否安装
import flask
except ImportError:
print("❌ 缺少Flask依赖包")
print("请运行: pip install flask")
return
# 创建并启动API服务器
api_path = self.create_api_server()
os.system(f"python {api_path}")
def generate_deployment_guide(self, output_path: str = None) -> str:
"""
生成部署指南
Args:
output_path: 输出路径
Returns:
部署指南路径
"""
print("📖 生成部署指南...")
if output_path is None:
output_path = self.skill_dir / 'DEPLOYMENT_GUIDE.md'
guide = '''# LTV预测技能部署指南
## 系统要求
- Python 3.7+
- 内存: 最少2GB,推荐4GB+
- 存储: 最少1GB可用空间
## 快速部署
### 1. 环境准备
```bash
# 安装Python依赖
pip install pandas numpy scikit-learn matplotlib seaborn openpyxl flask
# 或使用requirements.txt
pip install -r requirements.txt
```
### 2. 部署包部署
```bash
# 解压部署包
unzip ltv_predictor_deployment_*.zip
cd ltv_predictor
# 安装依赖
python scripts/deployment_manager.py install_dependencies
# 设置环境
python scripts/deployment_manager.py setup_environment
```
### 3. 启动服务
#### 方式1: 命令行工具
```bash
# Windows
start.bat
# Linux/Mac
./start.sh
```
#### 方式2: Python脚本
```bash
python scripts/deployment_manager.py start_server
```
#### 方式3: 直接启动API
```bash
python api_server.py
```
## API接口
### 健康检查
```http
GET /api/v1/health
```
### 数据分析
```http
POST /api/v1/analyze
Content-Type: application/json
{
"data_file": "path/to/your/data.csv",
"feature_period_months": 3,
"prediction_period_months": 12,
"output_dir": "./results"
}
```
### LTV预测
```http
POST /api/v1/predict
Content-Type: application/json
{
"model_dir": "./models",
"new_orders_file": "new_customers.csv",
"output_path": "predictions.csv"
}
```
## 使用示例
### Python客户端
```python
import requests
# 分析数据
response = requests.post('http://localhost:5000/api/v1/analyze', json={
'data_file': 'data/orders.csv'
})
result = response.json()
# 预测LTV
response = requests.post('http://localhost:5000/api/v1/predict', json={
'model_dir': './models',
'new_orders_file': 'new_customers.csv'
})
predictions = response.json()
```
### 命令行工具
```bash
# 基础分析
python scripts/quick_analysis.py analyze data/orders.csv
# 预测新客户
python scripts/quick_analysis.py predict ./models new_customers.csv
# 批量预测
python scripts/quick_analysis.py batch ./models rfm_features.csv
```
## 配置说明
### 环境变量
- `LOG_LEVEL`: 日志级别 (DEBUG/INFO/WARNING/ERROR)
- `MAX_UPLOAD_SIZE`: 最大上传文件大小
- `DEFAULT_MODEL`: 默认模型 (linear_regression/random_forest)
- `ENABLE_MONITORING`: 是否启用监控
### 配置文件
编辑 `deployment_config.json` 文件来自定义配置。
## 故障排除
### 常见问题
1. **依赖包安装失败**
```bash
# 使用国内镜像
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ 包名
```
2. **内存不足**
- 减少数据集大小
- 调整模型参数
- 增加系统内存
3. **模型训练慢**
- 启用并行处理: `n_jobs=-1`
- 减少交叉验证折数
- 使用更简单的模型
4. **API服务无法启动**
- 检查端口是否被占用
- 确认Flask依赖已安装
- 查看错误日志
### 日志查看
```bash
# 查看应用日志
tail -f logs/application.log
# 查看错误日志
tail -f logs/error.log
```
## 性能优化
### 数据优化
- 使用CSV格式而不是Excel
- 预处理数据去除异常值
- 合理设置时间窗口
### 模型优化
- 启用超参数调优
- 使用特征选择
- 考虑模型集成
### 系统优化
- 增加内存配置
- 使用SSD存储
- 启用缓存机制
## 监控和维护
### 性能监控
- API响应时间
- 模型预测准确性
- 系统资源使用率
### 定期维护
- 更新依赖包版本
- 重新训练模型
- 清理临时文件
## 技术支持
如遇到问题,请:
1. 查看本文档的故障排除部分
2. 检查日志文件获取详细错误信息
3. 提交Issue或联系技术支持
---
**版本**: 1.0.0
**更新时间**: {datetime.now().strftime('%Y-%m-%d')}
'''
with open(output_path, 'w', encoding='utf-8') as f:
f.write(guide)
print(f"✅ 部署指南已创建: {output_path}")
return str(output_path)
def main():
"""主函数 - 命令行接口"""
import argparse
parser = argparse.ArgumentParser(description='LTV预测技能部署管理器')
subparsers = parser.add_subparsers(dest='command', help='可用命令')
# 创建部署包命令
package_parser = subparsers.add_parser('package', help='创建部署包')
package_parser.add_argument('--output', '-o', help='输出文件路径')
package_parser.add_argument('--no-models', action='store_true', help='不包含模型文件')
package_parser.add_argument('--include-data', action='store_true', help='包含数据文件')
package_parser.add_argument('--no-docs', action='store_true', help='不包含文档')
# 验证部署包命令
validate_parser = subparsers.add_parser('validate', help='验证部署包')
validate_parser.add_argument('package_path', help='部署包路径')
# 安装依赖命令
subparsers.add_parser('install', help='安装依赖包')
# 设置环境命令
subparsers.add_parser('setup', help='设置运行环境')
# 启动服务器命令
server_parser = subparsers.add_parser('start_server', help='启动API服务器')
server_parser.add_argument('--host', default='localhost', help='主机地址')
server_parser.add_argument('--port', type=int, default=5000, help='端口号')
# 生成指南命令
guide_parser = subparsers.add_parser('guide', help='生成部署指南')
guide_parser.add_argument('--output', '-o', help='输出文件路径')
args = parser.parse_args()
if args.command == 'package':
# 创建部署包
manager = DeploymentManager()
manager.create_deployment_package(
output_path=args.output,
include_models=not args.no_models,
include_data=args.include_data,
include_docs=not args.no_docs
)
elif args.command == 'validate':
# 验证部署包
manager = DeploymentManager()
result = manager.validate_deployment(args.package_path)
print(f"验证结果: {'通过' if result['is_valid'] else '失败'}")
if result['errors']:
print("错误:")
for error in result['errors']:
print(f" - {error}")
if result['warnings']:
print("警告:")
for warning in result['warnings']:
print(f" - {warning}")
elif args.command == 'install':
# 安装依赖
manager = DeploymentManager()
success = manager.install_dependencies()
if success:
print("依赖安装成功")
else:
print("依赖安装失败")
elif args.command == 'setup':
# 设置环境
manager = DeploymentManager()
success = manager.setup_environment()
if success:
print("环境设置成功")
else:
print("环境设置失败")
elif args.command == 'start_server':
# 启动服务器
manager = DeploymentManager()
manager.start_server(args.host, args.port)
elif args.command == 'guide':
# 生成指南
manager = DeploymentManager()
guide_path = manager.generate_deployment_guide(args.output)
print(f"部署指南已生成: {guide_path}")
else:
parser.print_help()
if __name__ == '__main__':
main()#!/usr/bin/env python3
"""
电商LTV分析完整示例
演示如何使用LTV预测技能进行完整的电商客户生命周期价值分析
"""
import sys
import os
from pathlib import Path
import pandas as pd
import numpy as np
# 添加技能模块路径
current_dir = Path(__file__).parent
sys.path.append(str(current_dir.parent / 'scripts'))
from quick_analysis import quick_ltv_analysis
def main():
"""电商LTV分析示例"""
print("🛒 电商客户生命周期价值分析示例")
print("=" * 60)
# 示例数据文件路径
sample_data_path = current_dir.parent / 'data' / 'sample_orders.csv'
output_dir = current_dir.parent / 'examples' / 'ecommerce_analysis_results'
print(f"📁 示例数据: {sample_data_path}")
print(f"📁 输出目录: {output_dir}")
print()
# 检查数据文件是否存在
if not sample_data_path.exists():
print(f"❌ 示例数据文件不存在: {sample_data_path}")
print("请先运行数据准备脚本或检查文件路径。")
return
try:
# 1. 基础LTV分析
print("1️⃣ 执行基础LTV分析...")
print("-" * 30)
basic_config = {
'data_processor_config': {
'feature_period_months': 3, # 使用前3个月数据
'prediction_period_months': 12, # 预测后12个月
'remove_outliers': True,
'min_orders_per_customer': 1
},
'regression_config': {
'test_size': 0.2,
'cv_folds': 5,
'scoring_metric': 'r2',
'enable_hyperparameter_tuning': False
},
'models_to_train': ['linear_regression', 'random_forest']
}
results = quick_ltv_analysis(
file_path=str(sample_data_path),
feature_period_months=3,
prediction_period_months=12,
output_dir=str(output_dir / 'basic_analysis'),
config=basic_config,
generate_charts=True,
generate_reports=True
)
print("✅ 基础LTV分析完成")
# 2. 高级LTV分析(包含调优)
print("\n2️⃣ 执行高级LTV分析...")
print("-" * 30)
advanced_config = {
'data_processor_config': {
'feature_period_months': 6, # 使用前6个月数据
'prediction_period_months': 12, # 预测后12个月
'remove_outliers': True,
'min_orders_per_customer': 2 # 至少2个订单
},
'regression_config': {
'test_size': 0.2,
'cv_folds': 10, # 更多折交叉验证
'scoring_metric': 'r2',
'enable_hyperparameter_tuning': True # 启用超参数调优
},
'models_to_train': ['linear_regression', 'random_forest']
}
advanced_results = quick_ltv_analysis(
file_path=str(sample_data_path),
feature_period_months=6,
prediction_period_months=12,
output_dir=str(output_dir / 'advanced_analysis'),
config=advanced_config,
generate_charts=True,
generate_reports=True
)
print("✅ 高级LTV分析完成")
# 3. 结果比较
print("\n3️⃣ 分析结果比较...")
print("-" * 30)
basic_summary = results.get('summary', {})
advanced_summary = advanced_results.get('summary', {})
print("基础分析结果:")
print(f" - 最佳模型: {basic_summary.get('model_summary', {}).get('best_model', 'Unknown')}")
print(f" - R²分数: {basic_summary.get('model_summary', {}).get('best_r2_score', 0):.4f}")
print(f" - 分析客户数: {basic_summary.get('data_summary', {}).get('total_customers', 0)}")
print(f" - 平均LTV: {basic_summary.get('data_summary', {}).get('avg_ltv', 0):.0f}")
print("\n高级分析结果:")
print(f" - 最佳模型: {advanced_summary.get('model_summary', {}).get('best_model', 'Unknown')}")
print(f" - R²分数: {advanced_summary.get('model_summary', {}).get('best_r2_score', 0):.4f}")
print(f" - 分析客户数: {advanced_summary.get('data_summary', {}).get('total_customers', 0)}")
print(f" - 平均LTV: {advanced_summary.get('data_summary', {}).get('avg_ltv', 0):.0f}")
# 4. 业务洞察
print("\n4️⃣ 业务洞察...")
print("-" * 30)
# 获取RFM数据进行分析
basic_rfm_path = results['output_paths']['rfm_features']
if os.path.exists(basic_rfm_path):
rfm_data = pd.read_csv(basic_rfm_path)
# 客户价值分层统计
if '客户价值分层' in rfm_data.columns:
segment_counts = rfm_data['客户价值分层'].value_counts()
print("客户价值分层分布:")
for segment, count in segment_counts.items():
percentage = (count / len(rfm_data)) * 100
print(f" - {segment}: {count}人 ({percentage:.1f}%)")
# 城市分析
if '城市' in rfm_data.columns:
city_ltv = rfm_data.groupby('城市')['年度LTV'].agg(['count', 'mean']).sort_values('mean', ascending=False)
print("\n城市LTV排名:")
for city, stats in city_ltv.head(5).iterrows():
print(f" - {city}: {stats['count']}人, 平均LTV {stats['mean']:,.0f}")
# 5. 推荐策略
print("\n5️⃣ 推荐营销策略...")
print("-" * 30)
recommendations = basic_summary.get('recommendations_summary', [])
if recommendations:
for i, rec in enumerate(recommendations[:5], 1): # 显示前5条建议
print(f" {i}. {rec}")
else:
print(" 基于分析结果,建议:")
print(" 1. 针对高价值客户设计VIP维护计划")
print(" 2. 对中价值客户进行交叉销售和向上销售")
print(" 3. 对低价值客户制定激活和留存策略")
print(" 4. 重点关注一线城市客户的个性化服务")
print(" 5. 建立客户生命周期管理流程")
# 6. 文件生成总结
print("\n6️⃣ 生成文件总结...")
print("-" * 30)
print("基础分析生成文件:")
print(f" 📊 RFM特征数据: {results['output_paths']['rfm_features']}")
print(f" 🤖 训练模型: {results['output_paths']['models']}")
print(f" 📋 分析摘要: {results['summary_path']}")
chart_count = len(results.get('chart_paths', {}))
report_count = len(results.get('report_paths', {}))
print(f" 📈 可视化图表: {chart_count}个")
print(f" 📄 分析报告: {report_count}个")
print("\n高级分析生成文件:")
print(f" 📊 RFM特征数据: {advanced_results['output_paths']['rfm_features']}")
print(f" 🤖 训练模型: {advanced_results['output_paths']['models']}")
print(f" 📋 分析摘要: {advanced_results['summary_path']}")
chart_count = len(advanced_results.get('chart_paths', {}))
report_count = len(advanced_results.get('report_paths', {}))
print(f" 📈 可视化图表: {chart_count}个")
print(f" 📄 分析报告: {report_count}个")
print("\n" + "=" * 60)
print("🎉 电商LTV分析示例完成!")
print("=" * 60)
print(f"📁 所有结果已保存至: {output_dir}")
print("\n📖 后续步骤:")
print("1. 查看生成的HTML报告了解详细分析结果")
print("2. 使用可视化图表洞察客户行为模式")
print("3. 基于推荐策略制定营销计划")
print("4. 定期更新数据重新分析以跟踪变化")
except Exception as e:
print(f"\n❌ 分析过程中出现错误: {str(e)}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()#!/usr/bin/env python3
"""
LTV预测引擎
整合数据预处理、RFM分析和回归建模的完整LTV预测流程
"""
import pandas as pd
import numpy as np
from typing import Dict, List, Tuple, Optional, Union, Any
import os
import json
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')
from data_processor import DataProcessor
from regression_models import RegressionModels
class LTVPredictor:
"""
LTV预测引擎
整合数据预处理、RFM分析和回归建模的完整流程
基于第3课理论实现的客户生命周期价值预测系统
"""
def __init__(self, config: Optional[Dict] = None):
"""
初始化LTV预测器
Args:
config: 配置参数字典
"""
# 默认配置
self.config = {
'data_processor_config': {
'feature_period_months': 3,
'prediction_period_months': 12,
'remove_outliers': True,
'min_orders_per_customer': 1
},
'regression_config': {
'test_size': 0.2,
'cv_folds': 5,
'scoring_metric': 'r2',
'enable_hyperparameter_tuning': False
},
'feature_columns': ['R值', 'F值', 'M值'],
'target_column': '年度LTV',
'models_to_train': ['linear_regression', 'random_forest'],
'customer_column': '用户码'
}
# 更新配置
if config:
self.config.update(config)
if 'data_processor_config' in config:
self.config['data_processor_config'].update(config['data_processor_config'])
if 'regression_config' in config:
self.config['regression_config'].update(config['regression_config'])
# 初始化组件
self.data_processor = DataProcessor(self.config['data_processor_config'])
self.regression_models = RegressionModels(self.config['regression_config'])
# 结果存储
self.training_results = None
self.model_results = None
self.predictions = None
self.feature_importance = None
self.summary_report = None
print("🚀 LTV预测引擎初始化完成")
def load_and_preprocess_data(self, file_path: str, **kwargs) -> pd.DataFrame:
"""
加载和预处理数据
Args:
file_path: 数据文件路径
**kwargs: 加载参数
Returns:
预处理后的数据
"""
print("📁 开始数据加载和预处理...")
# 加载数据
raw_data = self.data_processor.load_order_data(file_path, **kwargs)
# 预处理数据
processed_data = self.data_processor.preprocess_data(raw_data)
return processed_data
def calculate_rfm_and_prepare_training_data(self, processed_data: pd.DataFrame) -> pd.DataFrame:
"""
计算RFM特征并准备训练数据
Args:
processed_data: 预处理后的订单数据
Returns:
包含RFM特征和LTV标签的训练数据
"""
print("🔍 开始RFM特征计算和训练数据准备...")
# 计算RFM特征
rfm_data = self.data_processor.calculate_rfm_features(processed_data)
# 客户分群
segmented_data = self.data_processor.segment_customers(rfm_data)
# 获取RFM摘要
rfm_summary = self.data_processor.get_rfm_summary(segmented_data)
self.rfm_summary = rfm_summary
print(f"✓ RFM分析完成:")
print(f" - 总客户数: {rfm_summary['total_customers']}")
print(f" - R值均值: {rfm_summary['rfm_statistics']['R值']['mean']:.2f}")
print(f" - F值均值: {rfm_summary['rfm_statistics']['F值']['mean']:.2f}")
print(f" - M值均值: {rfm_summary['rfm_statistics']['M值']['mean']:.2f}")
print(f" - 年度LTV均值: {rfm_summary['rfm_statistics']['年度LTV']['mean']:.2f}")
return segmented_data
def train_models(self, rfm_data: pd.DataFrame, model_names: Optional[List[str]] = None) -> Dict[str, Any]:
"""
训练LTV预测模型
Args:
rfm_data: RFM特征数据
model_names: 要训练的模型列表
Returns:
训练结果字典
"""
print("🤖 开始模型训练...")
if model_names is None:
model_names = self.config['models_to_train']
# 准备训练数据
feature_columns = self.config['feature_columns']
target_column = self.config['target_column']
X, y = self.regression_models.prepare_data(rfm_data, feature_columns, target_column)
X_train, X_test, y_train, y_test = self.regression_models.split_data(X, y)
# 训练多个模型
model_results = self.regression_models.train_multiple_models(
model_names, X_train, y_train, X_test, y_test
)
self.model_results = model_results
self.training_data = {
'X_train': X_train, 'X_test': X_test,
'y_train': y_train, 'y_test': y_test
}
# 提取特征重要性
self.feature_importance = self.regression_models.feature_importance
return {
'model_results': model_results,
'training_data': self.training_data,
'feature_importance': self.feature_importance,
'best_model_name': self.regression_models.best_model_name,
'rfm_summary': self.rfm_summary
}
def predict_ltv(self, data: Union[pd.DataFrame, Dict[str, float]],
model_name: Optional[str] = None) -> Union[np.ndarray, float]:
"""
预测客户LTV
Args:
data: 客户数据(DataFrame或单个客户字典)
model_name: 使用的模型名称
Returns:
LTV预测结果
"""
if self.model_results is None:
raise ValueError("模型未训练,请先调用train_models")
if isinstance(data, dict):
# 单个客户预测
return self._predict_single_customer(data, model_name)
else:
# 批量预测
return self._predict_batch(data, model_name)
def _predict_single_customer(self, customer_data: Dict[str, float], model_name: Optional[str] = None) -> float:
"""
预测单个客户的LTV
Args:
customer_data: 客户RFM特征字典
model_name: 模型名称
Returns:
LTV预测值
"""
# 准备特征数据
feature_columns = self.config['feature_columns']
features = [customer_data.get(col, 0) for col in feature_columns]
# 转换为DataFrame
X = pd.DataFrame([features], columns=feature_columns)
# 预测
prediction = self.regression_models.predict(model_name, X)
return float(prediction[0])
def _predict_batch(self, customer_data: pd.DataFrame, model_name: Optional[str] = None) -> np.ndarray:
"""
批量预测客户LTV
Args:
customer_data: 客户RFM特征DataFrame
model_name: 模型名称
Returns:
LTV预测数组
"""
# 确保包含所需特征列
feature_columns = self.config['feature_columns']
missing_cols = [col for col in feature_columns if col not in customer_data.columns]
if missing_cols:
raise ValueError(f"数据缺少特征列: {missing_cols}")
X = customer_data[feature_columns]
# 预测
predictions = self.regression_models.predict(model_name, X)
return predictions
def predict_new_customers(self, customer_orders: pd.DataFrame,
model_name: Optional[str] = None) -> pd.DataFrame:
"""
为新客户预测LTV
Args:
customer_orders: 新客户的订单数据
model_name: 使用的模型名称
Returns:
包含LTV预测的客户数据
"""
print("🔮 为新客户预测LTV...")
# 使用相同的配置计算RFM特征
temp_processor = DataProcessor(self.config['data_processor_config'])
# 预处理新客户数据
processed_new_data = temp_processor.preprocess_data(customer_orders)
# 计算RFM特征(仅特征期)
feature_config = {
'feature_period_months': self.config['data_processor_config']['feature_period_months'],
'prediction_period_months': 0 # 不需要LTV标签
}
# 临时修改配置
original_config = temp_processor.config.copy()
temp_processor.config.update(feature_config)
try:
# 计算RFM特征
new_rfm = temp_processor.calculate_rfm_features(processed_new_data)
except:
# 如果失败,使用简化的RFM计算
print(" 使用简化RFM计算...")
new_rfm = self._simple_rfm_calculation(processed_new_data)
finally:
# 恢复配置
temp_processor.config = original_config
# 预测LTV
feature_columns = self.config['feature_columns']
X_new = new_rfm[feature_columns]
predictions = self.regression_models.predict(model_name, X_new)
# 添加预测结果
new_rfm['预测LTV'] = predictions
new_rfm['预测时间'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"✓ 完成对{len(new_rfm)}个新客户的LTV预测")
print(f" - 平均预测LTV: {predictions.mean():.2f}")
print(f" - 预测范围: {predictions.min():.2f} ~ {predictions.max():.2f}")
return new_rfm
def _simple_rfm_calculation(self, data: pd.DataFrame) -> pd.DataFrame:
"""
简化的RFM计算(用于新客户)
Args:
data: 订单数据
Returns:
RFM特征数据
"""
customer_col = self.config['customer_column']
date_col = self.data_processor.config['date_column']
# 获取唯一客户
unique_customers = data[customer_col].unique()
rfm_data = pd.DataFrame({customer_col: unique_customers})
# 计算R值(距今天数)
latest_date = data[date_col].max()
r_data = data.groupby(customer_col)[date_col].max().reset_index()
r_data['R值'] = (latest_date - r_data[date_col]).dt.days
rfm_data = rfm_data.merge(r_data[[customer_col, 'R值']], on=customer_col, how='left')
# 计算F值
f_data = data.groupby(customer_col)[date_col].count().reset_index()
f_data.columns = [customer_col, 'F值']
rfm_data = rfm_data.merge(f_data, on=customer_col, how='left')
# 计算M值
if '总价' not in data.columns:
data['总价'] = data[self.data_processor.config['quantity_column']] * data[self.data_processor.config['price_column']]
m_data = data.groupby(customer_col)['总价'].sum().reset_index()
m_data.columns = [customer_col, 'M值']
rfm_data = rfm_data.merge(m_data, on=customer_col, how='left')
return rfm_data
def evaluate_prediction_accuracy(self, test_data: pd.DataFrame,
actual_ltv_column: str = '年度LTV') -> Dict[str, float]:
"""
评估预测准确性
Args:
test_data: 测试数据
actual_ltv_column: 实际LTV列名
Returns:
评估指标字典
"""
if self.model_results is None:
raise ValueError("模型未训练,请先调用train_models")
# 预测测试集LTV
feature_columns = self.config['feature_columns']
X_test = test_data[feature_columns]
y_true = test_data[actual_ltv_column]
# 使用最佳模型预测
y_pred = self.regression_models.predict(self.regression_models.best_model_name, X_test)
# 计算评估指标
from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error
r2 = r2_score(y_true, y_pred)
mae = mean_absolute_error(y_true, y_pred)
rmse = np.sqrt(mean_squared_error(y_true, y_pred))
mape = np.mean(np.abs((y_true - y_pred) / y_true)) * 100
evaluation_metrics = {
'r2_score': r2,
'mae': mae,
'rmse': rmse,
'mape': mape,
'mean_actual_ltv': y_true.mean(),
'mean_predicted_ltv': y_pred.mean(),
'total_customers': len(test_data)
}
print(f"📊 预测准确性评估:")
print(f" - R² 分数: {r2:.4f}")
print(f" - 平均绝对误差: {mae:.2f}")
print(f" - 均方根误差: {rmse:.2f}")
print(f" - 平均绝对百分比误差: {mape:.2f}%")
print(f" - 实际平均LTV: {y_true.mean():.2f}")
print(f" - 预测平均LTV: {y_pred.mean():.2f}")
return evaluation_metrics
def get_feature_analysis(self) -> Dict[str, Any]:
"""
获取特征分析报告
Returns:
特征分析字典
"""
if self.feature_importance is None:
return {"error": "特征重要性未计算,请先训练模型"}
analysis = {
'feature_importance': self.feature_importance,
'best_model_features': {},
'feature_insights': {}
}
# 分析最佳模型的特征重要性
if self.regression_models.best_model_name in self.feature_importance:
best_features = self.feature_importance[self.regression_models.best_model_name]
analysis['best_model_features'] = best_features
# 生成特征洞察
if best_features:
top_feature = max(best_features.keys(), key=lambda x: best_features[x])
analysis['feature_insights'] = {
'most_important_feature': top_feature,
'most_important_score': best_features[top_feature],
'feature_ranking': dict(sorted(best_features.items(), key=lambda x: x[1], reverse=True)),
'feature_contribution_analysis': self._analyze_feature_contributions(best_features)
}
return analysis
def _analyze_feature_contributions(self, feature_importance: Dict[str, float]) -> Dict[str, str]:
"""
分析特征贡献
Args:
feature_importance: 特征重要性字典
Returns:
特征贡献分析字典
"""
total_importance = sum(feature_importance.values())
contributions = {}
for feature, importance in feature_importance.items():
contribution_pct = (importance / total_importance) * 100
if feature == 'R值':
contributions[feature] = f"最近消费时间贡献了{contribution_pct:.1f}%的预测信息,客户活跃度对LTV影响显著"
elif feature == 'F值':
contributions[feature] = f"消费频率贡献了{contribution_pct:.1f}%的预测信息,频繁购买客户更有价值"
elif feature == 'M值':
contributions[feature] = f"消费金额贡献了{contribution_pct:.1f}%的预测信息,历史消费金额是LTV的关键指标"
else:
contributions[feature] = f"该特征贡献了{contribution_pct:.1f}%的预测信息"
return contributions
def generate_summary_report(self) -> Dict[str, Any]:
"""
生成综合摘要报告
Returns:
摘要报告字典
"""
if self.model_results is None:
return {"error": "模型未训练,请先运行完整流程"}
report = {
'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'config': self.config,
'data_summary': self.rfm_summary,
'model_summary': self.regression_models.get_model_summary(),
'best_model_performance': {},
'feature_analysis': self.get_feature_analysis(),
'recommendations': []
}
# 最佳模型性能
if self.regression_models.best_model_name and self.regression_models.best_model_name in self.model_results:
best_result = self.model_results[self.regression_models.best_model_name]
if 'r2_score' in best_result:
report['best_model_performance'] = {
'model_name': self.regression_models.best_model_name,
'r2_score': best_result['r2_score'],
'mae': best_result.get('mae'),
'rmse': best_result.get('rmse'),
'mape': best_result.get('mape')
}
# 生成业务建议
report['recommendations'] = self._generate_business_recommendations(report)
self.summary_report = report
return report
def _generate_business_recommendations(self, report: Dict[str, Any]) -> List[str]:
"""
生成业务建议
Args:
report: 分析报告
Returns:
建议列表
"""
recommendations = []
try:
# 基于模型性能的建议
best_performance = report.get('best_model_performance', {})
r2_score = best_performance.get('r2_score', 0)
if r2_score > 0.7:
recommendations.append("模型预测性能优秀(R² > 0.7),可用于精准营销和客户价值管理")
elif r2_score > 0.5:
recommendations.append("模型预测性能良好(R² > 0.5),建议结合业务规则进行客户分层")
else:
recommendations.append("模型预测性能一般,建议增加更多特征数据或尝试其他算法")
# 基于特征重要性的建议
feature_analysis = report.get('feature_analysis', {})
if 'most_important_feature' in feature_analysis:
top_feature = feature_analysis['most_important_feature']
if top_feature == 'M值':
recommendations.append("消费金额是影响LTV的最重要因素,建议重点提升客单价")
elif top_feature == 'F值':
recommendations.append("消费频率是影响LTV的最重要因素,建议重点提高复购率")
elif top_feature == 'R值':
recommendations.append("客户活跃度是影响LTV的最重要因素,建议加强客户互动和唤醒")
# 基于数据的建议
data_summary = report.get('data_summary', {})
if data_summary and 'total_customers' in data_summary:
customer_count = data_summary['total_customers']
if customer_count < 100:
recommendations.append("样本量较少,建议积累更多数据以提高模型稳定性")
elif customer_count > 10000:
recommendations.append("样本量充足,可考虑更复杂的机器学习算法")
except Exception as e:
print(f"生成建议时出错: {str(e)}")
if not recommendations:
recommendations.append("模型训练完成,建议结合具体业务场景进行应用")
return recommendations
def save_results(self, directory: str):
"""
保存分析结果
Args:
directory: 保存目录
"""
import os
from pathlib import Path
Path(directory).mkdir(parents=True, exist_ok=True)
# 保存模型
if self.model_results:
model_dir = os.path.join(directory, "models")
self.regression_models.save_models(model_dir)
# 保存摘要报告
if self.summary_report:
report_path = os.path.join(directory, "summary_report.json")
with open(report_path, 'w', encoding='utf-8') as f:
json.dump(self.summary_report, f, ensure_ascii=False, indent=2, default=str)
print(f"✓ 分析结果已保存到: {directory}")
def load_results(self, directory: str):
"""
加载分析结果
Args:
directory: 结果目录
"""
import os
# 加载模型
model_dir = os.path.join(directory, "models")
if os.path.exists(model_dir):
self.regression_models.load_models(model_dir)
# 加载摘要报告
report_path = os.path.join(directory, "summary_report.json")
if os.path.exists(report_path):
with open(report_path, 'r', encoding='utf-8') as f:
self.summary_report = json.load(f)
print(f"✓ 分析结果已从{directory}加载")
# 便利函数
def complete_ltv_analysis(file_path: str,
output_dir: str = './ltv_results',
config: Optional[Dict] = None) -> Dict[str, Any]:
"""
完整的LTV分析流程
Args:
file_path: 订单数据文件路径
output_dir: 输出目录
config: 配置参数
Returns:
完整分析结果
"""
from pathlib import Path
# 创建输出目录
Path(output_dir).mkdir(parents=True, exist_ok=True)
# 初始化预测器
predictor = LTVPredictor(config)
print("🚀 开始完整LTV分析流程...")
print(f" - 输入数据: {file_path}")
print(f" - 输出目录: {output_dir}")
try:
# 1. 加载和预处理数据
processed_data = predictor.load_and_preprocess_data(file_path)
# 2. 计算RFM特征
rfm_data = predictor.calculate_rfm_and_prepare_training_data(processed_data)
# 3. 训练模型
training_results = predictor.train_models(rfm_data)
# 4. 生成摘要报告
summary_report = predictor.generate_summary_report()
# 5. 保存结果
predictor.save_results(output_dir)
# 6. 导出RFM数据
rfm_output_path = os.path.join(output_dir, 'rfm_features.csv')
predictor.data_processor.export_rfm_data(rfm_data, rfm_output_path)
results = {
'predictor': predictor,
'rfm_data': rfm_data,
'training_results': training_results,
'summary_report': summary_report,
'output_paths': {
'rfm_features': rfm_output_path,
'models': os.path.join(output_dir, 'models'),
'summary_report': os.path.join(output_dir, 'summary_report.json')
}
}
print("🎉 完整LTV分析流程完成!")
# 打印关键结果
if summary_report and 'best_model_performance' in summary_report:
best_perf = summary_report['best_model_performance']
print(f"\n📊 关键结果:")
print(f" - 最佳模型: {best_perf.get('model_name', 'Unknown')}")
print(f" - 模型R²: {best_perf.get('r2_score', 0):.4f}")
print(f" - 分析客户数: {training_results.get('rfm_summary', {}).get('total_customers', 0)}")
return results
except Exception as e:
print(f"❌ LTV分析流程失败: {str(e)}")
raise
if __name__ == "__main__":
# 示例使用
print("🎯 LTV预测引擎测试")
# 如果有示例数据文件,可以进行测试
sample_file = '../data/sample_orders.csv'
if os.path.exists(sample_file):
results = complete_ltv_analysis(sample_file, output_dir='./ltv_test_results')
print("✓ 完整测试完成")
else:
print("⚠️ 示例数据文件不存在,跳过测试")#!/usr/bin/env python3
"""
模型优化器
提供模型性能优化和超参数调优功能
"""
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV, cross_val_score
from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error
import warnings
warnings.filterwarnings('ignore')
class ModelOptimizer:
"""模型优化器类"""
def __init__(self):
self.best_params = {}
self.optimization_history = {}
def optimize_random_forest(self, X_train, y_train, X_test=None, y_test=None,
optimization_method='grid', cv_folds=5, n_iter=50):
"""
优化随机森林模型
Args:
X_train, y_train: 训练数据
X_test, y_test: 测试数据(可选)
optimization_method: 优化方法 ('grid', 'random', 'bayesian')
cv_folds: 交叉验证折数
n_iter: 随机搜索迭代次数
Returns:
优化后的模型和参数
"""
print("🔧 开始随机森林模型优化...")
# 基础模型
rf = RandomForestRegressor(random_state=42, n_jobs=-1)
# 参数搜索空间
param_grid = {
'n_estimators': [50, 100, 200, 300],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4],
'max_features': ['sqrt', 'log2', None]
}
# 选择优化方法
if optimization_method == 'grid':
print(" 使用网格搜索...")
search = GridSearchCV(
rf, param_grid, cv=cv_folds,
scoring='r2', n_jobs=-1, verbose=1
)
elif optimization_method == 'random':
print(" 使用随机搜索...")
search = RandomizedSearchCV(
rf, param_grid, n_iter=n_iter, cv=cv_folds,
scoring='r2', n_jobs=-1, verbose=1, random_state=42
)
else:
raise ValueError(f"不支持的优化方法: {optimization_method}")
# 执行搜索
search.fit(X_train, y_train)
# 获取最佳模型
best_model = search.best_estimator_
best_params = search.best_params_
best_score = search.best_score_
print(f"✅ 优化完成!")
print(f" 最佳参数: {best_params}")
print(f" 交叉验证R²: {best_score:.4f}")
# 在测试集上评估
if X_test is not None and y_test is not None:
test_score = best_model.score(X_test, y_test)
print(f" 测试集R²: {test_score:.4f}")
# 保存结果
self.best_params['random_forest'] = best_params
self.optimization_history['random_forest'] = {
'best_params': best_params,
'best_cv_score': best_score,
'test_score': test_score if X_test is not None else None
}
return best_model, best_params, best_score
def optimize_linear_regression(self, X_train, y_train, X_test=None, y_test=None):
"""
优化线性回归模型(特征选择和正则化)
Args:
X_train, y_train: 训练数据
X_test, y_test: 测试数据(可选)
Returns:
优化后的模型和特征信息
"""
print("🔧 开始线性回归模型优化...")
# 基础模型
lr = LinearRegression()
# 交叉验证评估
cv_scores = cross_val_score(lr, X_train, y_train, cv=5, scoring='r2')
print(f" 交叉验证R²: {cv_scores.mean():.4f} (±{cv_scores.std():.4f})")
# 训练模型
lr.fit(X_train, y_train)
# 特征重要性分析(系数绝对值)
feature_importance = np.abs(lr.coef_)
feature_ranking = np.argsort(feature_importance)[::-1]
print(" 特征重要性排名:")
for i, idx in enumerate(feature_ranking):
if i < len(feature_importance):
print(f" {i+1}. 特征{idx}: {feature_importance[idx]:.4f}")
# 在测试集上评估
test_score = None
if X_test is not None and y_test is not None:
test_score = lr.score(X_test, y_test)
print(f" 测试集R²: {test_score:.4f}")
# 保存结果
self.optimization_history['linear_regression'] = {
'feature_importance': feature_importance.tolist(),
'feature_ranking': feature_ranking.tolist(),
'cv_scores': cv_scores.tolist(),
'test_score': test_score
}
return lr, feature_importance, cv_scores.mean()
def ensemble_models(self, models, X_test, y_test, weights=None):
"""
模型集成
Args:
models: 模型列表
X_test, y_test: 测试数据
weights: 模型权重(可选)
Returns:
集成预测结果和性能
"""
print("🔗 开始模型集成...")
if weights is None:
# 简单平均
weights = [1.0 / len(models)] * len(models)
# 获取各模型预测
predictions = []
model_scores = []
for i, model in enumerate(models):
pred = model.predict(X_test)
predictions.append(pred)
score = model.score(X_test, y_test)
model_scores.append(score)
print(f" 模型{i+1} R²: {score:.4f} (权重: {weights[i]:.3f})")
# 加权平均预测
ensemble_pred = np.zeros_like(predictions[0])
for pred, weight in zip(predictions, weights):
ensemble_pred += pred * weight
# 计算集成性能
ensemble_r2 = r2_score(y_test, ensemble_pred)
ensemble_mae = mean_absolute_error(y_test, ensemble_pred)
ensemble_rmse = np.sqrt(mean_squared_error(y_test, ensemble_pred))
print(f"✅ 集成模型性能:")
print(f" R² 分数: {ensemble_r2:.4f}")
print(f" MAE: {ensemble_mae:.4f}")
print(f" RMSE: {ensemble_rmse:.4f}")
return ensemble_pred, {
'r2_score': ensemble_r2,
'mae': ensemble_mae,
'rmse': ensemble_rmse,
'individual_scores': model_scores,
'weights': weights
}
def feature_selection(self, X_train, y_train, X_test=None, y_test=None,
method='correlation', threshold=0.1):
"""
特征选择
Args:
X_train, y_train: 训练数据
X_test, y_test: 测试数据(可选)
method: 选择方法 ('correlation', 'mutual_info', 'rfe')
threshold: 选择阈值
Returns:
选择的特征索引和重要性
"""
print(f"🎯 开始特征选择 (方法: {method})...")
if method == 'correlation':
# 相关性分析
correlations = []
for i in range(X_train.shape[1]):
corr = np.corrcoef(X_train[:, i], y_train)[0, 1]
correlations.append(abs(corr))
selected_features = [i for i, corr in enumerate(correlations) if corr > threshold]
feature_importance = correlations
elif method == 'mutual_info':
from sklearn.feature_selection import mutual_info_regression
mi_scores = mutual_info_regression(X_train, y_train)
selected_features = [i for i, score in enumerate(mi_scores) if score > threshold]
feature_importance = mi_scores
elif method == 'rfe':
from sklearn.feature_selection import RFE
from sklearn.linear_model import LinearRegression
estimator = LinearRegression()
selector = RFE(estimator, n_features_to_select=max(1, int(threshold * X_train.shape[1])))
selector.fit(X_train, y_train)
selected_features = [i for i, selected in enumerate(selector.support_) if selected]
feature_importance = selector.ranking_
else:
raise ValueError(f"不支持的特征选择方法: {method}")
print(f" 原始特征数: {X_train.shape[1]}")
print(f" 选择特征数: {len(selected_features)}")
print(f" 选择特征索引: {selected_features}")
# 在测试集上评估特征选择效果
if X_test is not None and y_test is not None and len(selected_features) > 0:
X_train_selected = X_train[:, selected_features]
X_test_selected = X_test[:, selected_features]
lr = LinearRegression()
lr.fit(X_train_selected, y_train)
test_score = lr.score(X_test_selected, y_test)
# 与原始特征对比
lr_full = LinearRegression()
lr_full.fit(X_train, y_train)
full_score = lr_full.score(X_test, y_test)
print(f" 选择后模型R²: {test_score:.4f}")
print(f" 原始模型R²: {full_score:.4f}")
print(f" 性能变化: {((test_score - full_score) / full_score * 100):+.2f}%")
return selected_features, feature_importance
def automated_hyperparameter_tuning(self, X_train, y_train, X_test, y_test,
model_types=['random_forest'], time_limit=300):
"""
自动化超参数调优
Args:
X_train, y_train: 训练数据
X_test, y_test: 测试数据
model_types: 要调优的模型类型
time_limit: 时间限制(秒)
Returns:
调优结果摘要
"""
print("🤖 开始自动化超参数调优...")
print(f" 时间限制: {time_limit}秒")
print(f" 调优模型: {model_types}")
import time
start_time = time.time()
results = {}
for model_type in model_types:
if time.time() - start_time > time_limit:
print(f"⏰ 时间限制达到,停止调优")
break
print(f"\n 调优 {model_type}...")
try:
if model_type == 'random_forest':
# 快速随机搜索
model, params, score = self.optimize_random_forest(
X_train, y_train, X_test, y_test,
optimization_method='random', n_iter=20, cv_folds=3
)
results[model_type] = {
'model': model,
'best_params': params,
'best_score': score
}
elif model_type == 'linear_regression':
model, importance, score = self.optimize_linear_regression(
X_train, y_train, X_test, y_test
)
results[model_type] = {
'model': model,
'feature_importance': importance,
'score': score
}
except Exception as e:
print(f" ❌ 调优失败: {str(e)}")
continue
# 选择最佳模型
best_model_type = None
best_score = -np.inf
for model_type, result in results.items():
score = result.get('best_score', result.get('score', 0))
if score > best_score:
best_score = score
best_model_type = model_type
elapsed_time = time.time() - start_time
print(f"\n✅ 自动调优完成 (耗时: {elapsed_time:.1f}秒)")
if best_model_type:
print(f"🏆 最佳模型: {best_model_type} (R²: {best_score:.4f})")
return results, best_model_type, elapsed_time
def generate_optimization_report(self, output_path='optimization_report.md'):
"""生成优化报告"""
print("📋 生成优化报告...")
report = "# 模型优化报告\n\n"
report += f"生成时间: {pd.Timestamp.now()}\n\n"
# 随机森林优化结果
if 'random_forest' in self.optimization_history:
rf_result = self.optimization_history['random_forest']
report += "## 随机森林优化\n\n"
report += f"最佳参数: {rf_result['best_params']}\n\n"
report += f"交叉验证R²: {rf_result['best_cv_score']:.4f}\n\n"
if rf_result.get('test_score'):
report += f"测试集R²: {rf_result['test_score']:.4f}\n\n"
# 线性回归优化结果
if 'linear_regression' in self.optimization_history:
lr_result = self.optimization_history['linear_regression']
report += "## 线性回归优化\n\n"
cv_scores = lr_result['cv_scores']
report += f"交叉验证R²: {np.mean(cv_scores):.4f} (±{np.std(cv_scores):.4f})\n\n"
if lr_result.get('test_score'):
report += f"测试集R²: {lr_result['test_score']:.4f}\n\n"
# 保存报告
with open(output_path, 'w', encoding='utf-8') as f:
f.write(report)
print(f"✅ 优化报告已保存: {output_path}")
return output_path用户码,R值,F值,M值,年度LTV,R_分位数,F_分位数,M_分位数,RFM_分群,RFM_得分,预测LTV,预测时间
CUST010,22,1,127.43,0.0,B,A,A,BAA,1.9,185.80339484126984,2025-12-20 00:25:14
CUST011,6,3,1354.62,0.0,D,D,D,DDD,9.3,462.28403968253974,2025-12-20 00:25:14
CUST012,18,1,228.92,0.0,B,A,A,BAA,3.1,215.76969246031746,2025-12-20 00:25:14
CUST013,35,1,135.32999999999998,0.0,A,A,A,AAA,2.0,185.80339484126984,2025-12-20 00:25:14
CUST014,32,3,1052.52,0.0,A,D,D,ADD,7.8,462.28403968253974,2025-12-20 00:25:14
CUST015,5,2,560.72,0.0,D,B,C,DBC,7.05,460.65070634920636,2025-12-20 00:25:14
CUST016,16,2,503.09999999999997,0.0,C,B,C,CBC,5.95,460.65070634920636,2025-12-20 00:25:14
CUST017,40,2,376.78999999999996,0.0,A,B,B,ABB,3.8499999999999996,404.9150873015874,2025-12-20 00:25:14
CUST018,16,2,431.21,0.0,C,B,B,CBB,5.45,460.65070634920636,2025-12-20 00:25:14
CUST019,5,3,840.53,0.0,D,D,D,DDD,8.6,462.28403968253974,2025-12-20 00:25:14
pandas>=1.3.0
numpy>=1.21.0
scikit-learn>=1.0.0
matplotlib>=3.5.0
seaborn>=0.11.0
openpyxl>=3.0.0
flask>=2.0.0