1. 数据集准备
使用 Kaggle 公开电商数据集,这里为了方便找了一个 Olist 巴西电商数据(可能需要代理访问),下载数据后通过Python 加载数据:
1 2 3 4 5 6 7 8
| import pandas as pd import matplotlib.pyplot as plt import seaborn as sns
orders = pd.read_csv('olist_orders_dataset.csv') order_items = pd.read_csv('olist_order_items_dataset.csv') products = pd.read_csv('olist_products_dataset.csv')
|
2. 数据清洗与 RFM 计算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| merged_data = pd.merge( orders[['order_id', 'customer_id', 'order_purchase_timestamp']], order_items[['order_id', 'product_id', 'price']], on='order_id' ) merged_data = pd.merge(merged_data, products[['product_id', 'product_category_name']], on='product_id')
merged_data['order_date'] = pd.to_datetime(merged_data['order_purchase_timestamp']).dt.tz_localize(None) merged_data['month'] = merged_data['order_date'].dt.to_period('M')
snapshot_date = merged_data['order_date'].max() + pd.DateOffset(days=1)
rfm = merged_data.groupby('customer_id').agg({ 'order_date': lambda x: (snapshot_date - x.max()).days, 'order_id': 'nunique', 'price': 'sum' }).reset_index() rfm.columns = ['客户_id', 'recency', 'frequency', 'monetary']
|
为何需要 snapshot_date?
在 RFM 分析中:
- Recency(最近一次消费时间)定义为:
客户最后一次购买日期到 snapshot_date 的天数。
- 若直接使用数据中的最新订单日期作为
snapshot_date,可能导致以下问题:
- 对于在最新日期下单的客户,
Recency = 0(但业务上可能需要最小间隔为 1 天)。
- 若数据仅包含历史记录(如截止到 2024-12-31),而实际分析时间是 2025-01-01,需手动指定未来的
snapshot_date。
通过将 snapshot_date 设为 最新订单日期的次日:
- 确保所有客户的最后一次消费均在
snapshot_date 之前,避免 Recency 为 0。
3. 关键指标分析
通过分析 merged_data 中的产品销售数据,找出 销售额最高的前5个商品品类,并生成可视化图表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| print(f"总销售额:{merged_data['price'].sum():.2f}") print(f"月均增长率:{merged_data.groupby('month')['price'].sum().pct_change().mean():.2%}")
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'WenQuanYi Micro Hei'] plt.rcParams['axes.unicode_minus'] = False
top_categories = merged_data.groupby('product_category_name')['price'].sum().nlargest(5)
plt.figure(figsize=(10, 6)) sns.barplot(x=top_categories.values, y=top_categories.index, palette='viridis')
plt.title('销售额最高的前5个产品类别', fontsize=14, pad=20) plt.xlabel('销售额', fontsize=12) plt.ylabel('产品类别', fontsize=12)
plt.tight_layout() plt.savefig('top_categories.png', dpi=300, bbox_inches='tight') plt.close()
|
生成条形图如下:

4. RFM 用户分层
通过对客户的 Recency(近度)、Frequency(频度)、Monetary(金额) 指标进行评分,将客户划分为 High Value(高价值)、Mid Value(中价值)、Low Value(低价值) 三个群体。
1 2 3 4 5 6 7 8 9 10 11 12 13
| rfm['R_rank'] = pd.qcut(rfm['recency'], 5, labels=False, duplicates='drop') + 1 rfm['F_rank'] = pd.cut(rfm['frequency'], 5, labels=False, include_lowest=True) + 1 rfm['M_rank'] = pd.qcut(rfm['monetary'], 5, labels=False, duplicates='drop') + 1
rfm['RFM_Score'] = rfm[['R_rank', 'F_rank', 'M_rank']].sum(axis=1) rfm['Segment'] = 'Low Value' rfm.loc[rfm['RFM_Score'] > 9, 'Segment'] = 'High Value' rfm.loc[rfm['RFM_Score'].between(6,9), 'Segment'] = 'Mid Value'
rfm.to_csv('rfm_analysis.csv', index=False, encoding='utf-8-sig')
|
最终得到通过RFM对客户进行分析后的数据:
