开发思路

  1. 配置 (# --- 配置 ---):
    • REPORT_PREFIX: 生成的报告和图表文件名的前缀。
    • NUM_USERSSTART_DATEEND_DATE: 用于生成模拟数据的参数。
  2. 数据生成 (generate_sample_data):
    • 模拟了5000名用户的数据,包括 user_idsignup_datesegment (分群), first_purchase_datelast_purchase_datetotal_orderstotal_spentis_churned (是否流失)。
    • 用户被分为三类:普通用户高价值用户流失风险用户,并根据类别分配不同的行为特征(如购买频率、消费金额)。
    • 流失判定:在分析周期结束时(2024年1月1日),如果用户距离上次购买已超过90天,则标记为流失。
    • 生成的数据保存为CSV文件,方便查看和后续使用。
  3. 分析函数:
    • analyze_user_cohorts:
      • 进行 Cohort 留存分析。将用户按注册周(Cohort Date)分组。
      • 追踪每个组的用户在后续每周的活跃情况(即留存)。
      • 计算并输出一个留存率矩阵,显示每个Cohort在不同周期后的留存百分比。
      • 使用 matplotlib 绘制最近几个Cohort的留存率曲线图,直观展示用户流失趋势。
    • analyze_segments:
      • 按用户分群 (segment) 计算关键指标:用户数、平均订单数、平均消费、总消费、流失用户数、流失率。
      • 分析各分群在用户总量和消费总额中的占比。
      • 使用 matplotlib 绘制两个饼图,分别展示各分群的用户数量占比和消费金额占比。
    • analyze_ltv:
      • 计算每个用户分群的 平均生命周期价值 (LTV),即该分群用户的平均总消费。
      • 使用 matplotlib 绘制柱状图展示各分群的平均LTV。
  4. 报告生成 (generate_retention_strategies_report):
    • 汇总所有分析结果。
    • 计算整体核心指标(总用户数、总流失数、整体流失率)。
    • 打印各部分的分析摘要和数据表格。
    • 核心部分: 基于数据分析,提出具体的、可执行的用户留存策略建议。例如:
      • 针对LTV最高的分群,建议提供VIP服务。
      • 针对流失率最高的分群,建议进行挽留活动。
      • 针对新用户,建议优化引导和首单体验。
      • 提出通用的精细化运营建议。
    • 将所有内容写入一个 .txt 文件。
  5. 主函数 (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()