开发思路
- 配置 (
# --- 配置 ---):
REPORT_PREFIX: 生成的报告和图表文件名的前缀。
NUM_USERS, START_DATE, END_DATE: 用于生成模拟数据的参数。
- 数据生成 (
generate_sample_data):
- 模拟了5000名用户的数据,包括
user_id, signup_date, segment (分群), first_purchase_date, last_purchase_date, total_orders, total_spent, is_churned (是否流失)。
- 用户被分为三类:
普通用户, 高价值用户, 流失风险用户,并根据类别分配不同的行为特征(如购买频率、消费金额)。
- 流失判定:在分析周期结束时(2024年1月1日),如果用户距离上次购买已超过90天,则标记为流失。
- 生成的数据保存为CSV文件,方便查看和后续使用。
- 分析函数:
analyze_user_cohorts:
- 进行 Cohort 留存分析。将用户按注册周(Cohort Date)分组。
- 追踪每个组的用户在后续每周的活跃情况(即留存)。
- 计算并输出一个留存率矩阵,显示每个Cohort在不同周期后的留存百分比。
- 使用
matplotlib 绘制最近几个Cohort的留存率曲线图,直观展示用户流失趋势。
analyze_segments:
- 按用户分群 (
segment) 计算关键指标:用户数、平均订单数、平均消费、总消费、流失用户数、流失率。
- 分析各分群在用户总量和消费总额中的占比。
- 使用
matplotlib 绘制两个饼图,分别展示各分群的用户数量占比和消费金额占比。
analyze_ltv:
- 计算每个用户分群的 平均生命周期价值 (LTV),即该分群用户的平均总消费。
- 使用
matplotlib 绘制柱状图展示各分群的平均LTV。
- 报告生成 (
generate_retention_strategies_report):
- 汇总所有分析结果。
- 计算整体核心指标(总用户数、总流失数、整体流失率)。
- 打印各部分的分析摘要和数据表格。
- 核心部分: 基于数据分析,提出具体的、可执行的用户留存策略建议。例如:
- 针对LTV最高的分群,建议提供VIP服务。
- 针对流失率最高的分群,建议进行挽留活动。
- 针对新用户,建议优化引导和首单体验。
- 提出通用的精细化运营建议。
- 将所有内容写入一个
.txt 文件。
- 主函数 (
main):
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
import os
# --- 配置 ---
# 报告文件名前缀
REPORT_PREFIX = '用户生命周期与留存策略报告'
# 模拟数据参数
NUM_USERS = 5000
START_DATE = datetime(2023, 1, 1)
END_DATE = datetime(2024, 1, 1)
# --- 数据生成函数 ---
def generate_sample_data(n_users, start_date, end_date):
"""生成模拟用户生命周期数据"""
print("--- 正在生成模拟用户数据 ---")
np.random.seed(42) # 保证结果可复现
data = []
user_ids = range(1, n_users + 1)
for user_id in user_ids:
# 1. 注册日期: 在指定时间范围内随机
signup_date = start_date + timedelta(days=np.random.randint(0, (end_date - start_date).days))
# 2. 用户分群 (简化模拟)
# 假设60%是普通用户,30%是高价值用户,10%是流失风险用户
segments = ['普通用户', '高价值用户', '流失风险用户']
segment_probs = [0.6, 0.3, 0.1]
segment = np.random.choice(segments, p=segment_probs)
# 3. 首次购买日期: 注册后0-30天内
days_to_first_purchase = np.random.randint(0, 31)
first_purchase_date = signup_date + timedelta(days=days_to_first_purchase)
if first_purchase_date > end_date:
first_purchase_date = None # 部分用户注册后未购买
# 4. 总购买次数和总消费 (与分群相关)
if segment == '高价值用户':
total_orders = np.random.poisson(15) + 1 # 泊松分布,确保至少1次
total_spent = np.random.lognormal(10, 0.5) # 对数正态分布模拟高消费
elif segment == '普通用户':
total_orders = np.random.poisson(3) + 1
total_spent = np.random.lognormal(8, 0.8)
else: # 流失风险用户
total_orders = np.random.poisson(1)
total_spent = np.random.lognormal(7, 1.0)
# 5. 最后购买日期 (决定是否已流失)
# 假设用户平均每月购买一次,流失前平均活跃6个月
avg_days_between_purchases = 30
std_days = 10
days_active = np.random.normal(6 * avg_days_between_purchases, 2 * std_days)
days_active = max(days_active, avg_days_between_purchases) # 至少活跃一次购买周期
last_purchase_date = first_purchase_date + timedelta(days=days_active) if first_purchase_date else None
if last_purchase_date and last_purchase_date > end_date:
last_purchase_date = end_date
# 6. 判定是否流失 (在分析周期结束时,距离上次购买超过90天)
is_churned = False
if last_purchase_date:
days_since_last_purchase = (end_date - last_purchase_date).days
is_churned = days_since_last_purchase > 90
data.append({
'user_id': user_id,
'signup_date': signup_date,
'segment': segment,
'first_purchase_date': first_purchase_date,
'last_purchase_date': last_purchase_date,
'total_orders': total_orders,
'total_spent': round(total_spent, 2),
'is_churned': is_churned
})
df = pd.DataFrame(data)
# 修正未购买用户的字段
df.loc[df['first_purchase_date'].isnull(), ['last_purchase_date', 'total_orders', 'total_spent']] = [None, 0, 0]
csv_filename = f'{REPORT_PREFIX}_模拟数据.csv'
df.to_csv(csv_filename, index=False, encoding='utf-8-sig') # utf-8-sig for Excel compatibility
print(f"模拟数据已生成并保存至: {csv_filename}")
return df
# --- 分析函数 ---
def analyze_user_cohorts(df, analysis_end_date):
"""分析用户留存率 (按注册周 cohorts)"""
print("\n--- 正在分析用户留存率 (Cohort Analysis) ---")
# 确保日期列是datetime类型
df['signup_date'] = pd.to_datetime(df['signup_date'])
df['last_purchase_date'] = pd.to_datetime(df['last_purchase_date'])
# 1. 定义 Cohort (以用户注册周的第一天为 Cohort Date)
df['cohort_date'] = df['signup_date'].dt.to_period('W').dt.start_time
# 2. 计算每个用户最后一次活跃的时期
# 如果已流失,则活跃截止到流失前;如果未流失,则截止到分析期末
df['active_end_date'] = np.where(df['is_churned'], df['last_purchase_date'], analysis_end_date)
df['active_end_period'] = df['active_end_date'].dt.to_period('W').dt.start_time
# 3. 计算用户所属的cohort和活跃的cohort
cohort_groups = df.groupby(df['cohort_date'])
# 4. 构建留存率矩阵
cohort_sizes = cohort_groups['user_id'].count() # 每个cohort的初始用户数
# 为每个用户生成其活跃期内的所有周
user_cohort_periods = []
for _, user in df.iterrows():
if pd.notnull(user['cohort_date']) and pd.notnull(user['active_end_period']):
periods_active = pd.date_range(user['cohort_date'], user['active_end_period'], freq='W-MON')
for period in periods_active:
user_cohort_periods.append({'cohort_date': user['cohort_date'], 'active_period': period})
df_active_periods = pd.DataFrame(user_cohort_periods)
# 计算每个cohort在不同周期的活跃用户数
retention_counts = df_active_periods.groupby(['cohort_date', 'active_period']).size().reset_index(name='active_users')
# 将周期转换为相对于cohort的月份索引 (简化为周)
retention_counts['period_number'] = ((retention_counts['active_period'] - retention_counts['cohort_date']).dt.days / 7).astype(int)
# 透视表:行是cohort,列是周期,值是活跃用户数
retention_pivot = retention_counts.pivot_table(index='cohort_date', columns='period_number', values='active_users', fill_value=0)
# 计算留存率 (%)
cohort_sizes_aligned = cohort_sizes.reindex(retention_pivot.index, fill_value=0)
retention_matrix = retention_pivot.divide(cohort_sizes_aligned, axis=0) * 100
print("用户周留存率矩阵 (部分数据):")
print(retention_matrix.head(10).round(1)) # 显示前10个cohort
# 绘制留存率曲线 (选取几个最近的cohort)
plt.figure(figsize=(12, 6))
recent_cohorts = retention_matrix.tail(5).index # 最近5个cohort
for cohort_date in recent_cohorts:
cohort_data = retention_matrix.loc[cohort_date].dropna()
periods = cohort_data.index
rates = cohort_data.values
plt.plot(periods, rates, marker='o', label=f'Cohort: {cohort_date.strftime("%Y-%m-%d")}')
plt.xlabel('周数 (相对于注册周)')
plt.ylabel('留存率 (%)')
plt.title('用户按周 Cohort 留存率趋势')
plt.legend()
plt.grid(True)
cohort_chart_path = f'{REPORT_PREFIX}_留存率曲线.png'
plt.savefig(cohort_chart_path)
plt.close()
print(f"Cohort留存率图表已保存至: {cohort_chart_path}")
return retention_matrix, cohort_chart_path
def analyze_segments(df):
"""分析不同用户分群的特征"""
print("\n--- 正在分析用户分群特征 ---")
# 按分群计算关键指标
segment_analysis = df.groupby('segment').agg(
user_count=('user_id', 'count'),
avg_orders=('total_orders', 'mean'),
avg_spent=('total_spent', 'mean'),
total_spent=('total_spent', 'sum'),
churned_count=('is_churned', 'sum')
).reset_index()
segment_analysis['churn_rate'] = (segment_analysis['churned_count'] / segment_analysis['user_count']) * 100
segment_analysis['avg_spent'] = segment_analysis['avg_spent'].round(2)
segment_analysis['avg_orders'] = segment_analysis['avg_orders'].round(2)
segment_analysis['churn_rate'] = segment_analysis['churn_rate'].round(2)
segment_analysis['pct_total_spent'] = (segment_analysis['total_spent'] / segment_analysis['total_spent'].sum()) * 100
segment_analysis['pct_total_spent'] = segment_analysis['pct_total_spent'].round(2)
# 重新排序列
segment_analysis = segment_analysis[[
'segment', 'user_count', 'avg_orders', 'avg_spent',
'total_spent', 'pct_total_spent', 'churned_count', 'churn_rate'
]]
print("各用户分群核心指标:")
print(segment_analysis.to_string(index=False))
# 绘制分群用户数和贡献额饼图
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 7))
# 用户数分布
ax1.pie(segment_analysis['user_count'], labels=segment_analysis['segment'], autopct='%1.1f%%', startangle=140)
ax1.set_title('各分群用户数量占比')
# 消费贡献分布
ax2.pie(segment_analysis['total_spent'], labels=segment_analysis['segment'], autopct='%1.1f%%', startangle=140)
ax2.set_title('各分群消费金额占比')
plt.tight_layout()
segments_chart_path = f'{REPORT_PREFIX}_用户分群分析.png'
plt.savefig(segments_chart_path)
plt.close()
print(f"用户分群分析图表已保存至: {segments_chart_path}")
return segment_analysis, segments_chart_path
def analyze_ltv(df):
"""分析用户生命周期价值 (简化计算)"""
print("\n--- 正在分析用户生命周期价值 (LTV) ---")
# 简化LTV计算:总消费 / 总用户数 (平均LTV)
# 或按分群计算平均LTV
ltv_analysis = df.groupby('segment').agg(
user_count=('user_id', 'count'),
total_spent=('total_spent', 'sum')
).reset_index()
ltv_analysis['avg_ltv'] = (ltv_analysis['total_spent'] / ltv_analysis['user_count']).round(2)
print("各分群平均生命周期价值 (LTV):")
print(ltv_analysis[['segment', 'avg_ltv']].to_string(index=False))
# 绘制LTV柱状图
plt.figure(figsize=(10, 6))
bars = plt.bar(ltv_analysis['segment'], ltv_analysis['avg_ltv'], color=['skyblue', 'gold', 'lightcoral'])
plt.xlabel('用户分群')
plt.ylabel('平均生命周期价值 (元)')
plt.title('各分群平均生命周期价值 (LTV)')
# 在柱状图上添加数值标签
for bar in bars:
yval = bar.get_height()
plt.text(bar.get_x() + bar.get_width()/2.0, yval, round(yval, 2), ha='center', va='bottom')
plt.tight_layout()
ltv_chart_path = f'{REPORT_PREFIX}_LTV分析.png'
plt.savefig(ltv_chart_path)
plt.close()
print(f"LTV分析图表已保存至: {ltv_chart_path}")
return ltv_analysis, ltv_chart_path
# --- 报告生成函数 ---
def generate_retention_strategies_report(df, retention_matrix, cohort_chart, segment_df, segments_chart, ltv_df, ltv_chart):
"""生成留存策略报告"""
print("\n--- 正在生成留存策略报告 ---")
from datetime import datetime
report_filename = f"{REPORT_PREFIX}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
total_users = len(df)
total_churned = df['is_churned'].sum()
overall_churn_rate = (total_churned / total_users) * 100 if total_users > 0 else 0
with open(report_filename, 'w', encoding='utf-8') as f:
f.write("=" * 50 + "\n")
f.write(" 电商平台用户生命周期与留存策略报告\n")
f.write(f" 生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write("=" * 50 + "\n\n")
f.write("--- 1. 核心指标概览 ---\n")
f.write(f"总用户数: {total_users}\n")
f.write(f"总流失用户数: {total_churned}\n")
f.write(f"整体流失率: {overall_churn_rate:.2f}%\n\n")
f.write("--- 2. 用户留存率分析 (Cohort Analysis) ---\n")
f.write("说明:追踪同一时间注册的用户群随时间的留存情况。\n")
f.write("解读:图表显示了最近几个用户群的按周留存率。理想情况下,曲线应缓慢下降。\n")
f.write(" 快速下降可能表明新用户体验或早期价值传递存在问题。\n")
f.write(f"图表: {cohort_chart}\n")
f.write("(请查看CSV文件获取完整的留存率矩阵数据)\n\n")
f.write("--- 3. 用户分群特征分析 ---\n")
f.write("说明:将用户分为不同群体,分析其行为差异。\n")
f.write(segment_df.to_string(index=False))
f.write(f"\n图表: {segments_chart}\n\n")
f.write("--- 4. 生命周期价值 (LTV) 分析 ---\n")
f.write("说明:衡量用户在生命周期内为企业创造的平均收入。\n")
f.write(ltv_df[['segment', 'avg_ltv']].to_string(index=False))
f.write(f"\n图表: {ltv_chart}\n\n")
f.write("--- 5. 留存策略建议 ---\n")
f.write("基于以上分析,提出以下针对性的用户留存策略:\n\n")
high_value_seg = ltv_df.loc[ltv_df['avg_ltv'].idxmax(), 'segment']
high_churn_seg_row = segment_df.loc[segment_df['churn_rate'].idxmax()]
high_churn_seg = high_churn_seg_row['segment']
high_churn_rate = high_churn_seg_row['churn_rate']
f.write(f"1. 重点维护高价值用户 ({high_value_seg}):\n")
f.write(f" - 特征: 平均LTV最高。\n")
f.write(f" - 策略: 提供VIP服务、专属优惠、优先客服、新品体验权等,提升其忠诚度和满意度。\n\n")
f.write(f"2. 挽救流失风险用户 ({high_churn_seg}):\n")
f.write(f" - 特征: 流失率最高 ({high_churn_rate:.2f}%)。\n")
f.write(f" - 策略: 分析其流失原因,通过邮件/SMS推送个性化优惠券、召回活动,或进行用户回访了解需求。\n\n")
f.write("3. 提升新用户价值:\n")
f.write(" - 特征: 新用户(如Cohort分析所示)早期流失率是关键。\n")
f.write(" - 策略: 优化新用户引导流程,提供首单优惠,设置新手任务奖励,确保首次购买体验顺畅。\n\n")
f.write("4. 通用精细化运营:\n")
f.write(" - 策略: 利用用户行为数据进行个性化推荐,实施生命周期自动化营销(如注册后、首购后、沉默期自动触发邮件/SMS)。\n")
f.write(" 建立积分体系、会员等级制度,增加用户粘性。\n\n")
f.write("=" * 50 + "\n")
f.write(" 报告结束\n")
f.write("=" * 50 + "\n")
print(f"留存策略报告已生成: {report_filename}")
# --- 主函数 ---
def main():
"""主函数"""
# 1. 生成或加载数据
# 在实际应用中,这里会是加载真实数据库数据的逻辑
df_users = generate_sample_data(NUM_USERS, START_DATE, END_DATE)
# 2. 执行分析
retention_matrix, cohort_chart = analyze_user_cohorts(df_users, END_DATE)
segment_df, segments_chart = analyze_segments(df_users)
ltv_df, ltv_chart = analyze_ltv(df_users)
# 3. 生成报告
generate_retention_strategies_report(
df_users, retention_matrix, cohort_chart,
segment_df, segments_chart,
ltv_df, ltv_chart
)
print("\n分析完成。")
if __name__ == "__main__":
main()