5.1 用户画像构建基础

【理论讲解】

用户画像,就像给每个用户画一张“数字肖像”,上面记录着他们的各种信息和行为特征。通过用户画像,我们可以更好地理解用户是谁、他们喜欢什么、有什么习惯,从而进行更精准的运营和营销。

核心要素:

  1. 用户基本信息: 性别、年龄、地域、职业等。
  2. 购买行为: 购买商品品类、品牌偏好、价格敏感度、购买频率、消费金额等。
  3. 浏览行为: 浏览时长、浏览商品类型、搜索关键词、点击路径等。
  4. 互动行为: 评论、点赞、分享、收藏、参与活动等。

构建流程:

  • 数据收集: 从订单、浏览日志、用户注册信息等来源获取原始数据。
  • 数据清洗与整合: 将不同来源的数据统一到用户ID,处理缺失值、异常值。
  • 特征工程: 从原始数据中提取有价值的特征(如“首次购买日期”、“平均客单价”、“最常浏览品类”)。
  • 标签化: 将特征转化为易于理解和使用的标签(如“高消费用户”、“时尚达人”、“电子产品爱好者”)。

【自动生成数据集与代码实例】

我们将生成一个包含用户注册信息、浏览行为和购买行为的模拟数据集。

python

import pandas as pd
import numpy as np
from datetime import datetime, timedelta

# --- 数据集生成 ---
np.random.seed(42) # 保证每次生成数据一致

def generate_user_profile_data(num_users=1000, start_date='2022-01-01', end_date='2023-12-31'):
    """
    生成模拟的用户画像相关数据
    包括用户基本信息、浏览行为、购买行为
    """
    users = []
    for i in range(num_users):
        user_id = f'U{i:04d}'
        gender = np.random.choice(['Male', 'Female', 'Unknown'], p=[0.45, 0.45, 0.1])
        age = np.random.randint(18, 60) if gender != 'Unknown' else np.random.randint(18, 80)
        city = np.random.choice(['Beijing', 'Shanghai', 'Guangzhou', 'Shenzhen', 'Chengdu', 'Hangzhou', 'Other'])
        reg_date = pd.to_datetime(start_date) + timedelta(days=np.random.randint(0, (pd.to_datetime(end_date) - pd.to_datetime(start_date)).days))
        users.append([user_id, gender, age, city, reg_date])
    df_users = pd.DataFrame(users, columns=['user_id', 'gender', 'age', 'city', 'registration_date'])

    # 模拟商品数据
    products = {
        'P101': {'category': 'Electronics', 'brand': 'TechCo', 'price_range': (100, 1000)},
        'P102': {'category': 'Apparel', 'brand': 'FashionX', 'price_range': (50, 500)},
        'P103': {'category': 'Home', 'brand': 'LifeStyle', 'price_range': (20, 300)},
        'P104': {'category': 'Books', 'brand': 'ReadNow', 'price_range': (10, 150)},
        'P105': {'category': 'Sports', 'brand': 'ActiveFit', 'price_range': (80, 800)},
    }
    product_ids = list(products.keys())

    # 模拟浏览行为
    browsing_data = []
    for _ in range(num_users * 5): # 平均每个用户5次浏览
        user_id = np.random.choice(df_users['user_id'])
        product_id = np.random.choice(product_ids)
        browse_time = pd.to_datetime(start_date) + timedelta(seconds=np.random.randint(0, (pd.to_datetime(end_date) - pd.to_datetime(start_date)).total_seconds()))
        browsing_data.append([user_id, product_id, browse_time])
    df_browsing = pd.DataFrame(browsing_data, columns=['user_id', 'product_id', 'browse_time'])
    df_browsing['category'] = df_browsing['product_id'].map(lambda x: products[x]['category'])

    # 模拟购买行为
    order_data = []
    for _ in range(num_users * 2): # 平均每个用户2次购买
        user_id = np.random.choice(df_users['user_id'], p=df_users['user_id'].map(lambda x: 0.8 if int(x[1:]) < num_users * 0.2 else 0.2).values / sum(df_users['user_id'].map(lambda x: 0.8 if int(x[1:]) < num_users * 0.2 else 0.2).values)) # 模拟部分用户购买更多
        product_id = np.random.choice(product_ids)
        quantity = np.random.randint(1, 4)
        price_range = products[product_id]['price_range']
        price = round(np.random.uniform(price_range[0], price_range[1]), 2)
        order_time = pd.to_datetime(start_date) + timedelta(seconds=np.random.randint(0, (pd.to_datetime(end_date) - pd.to_datetime(start_date)).total_seconds()))
        order_data.append([f'ORD{_ + 1:05d}', user_id, product_id, quantity, price, order_time])
    df_orders = pd.DataFrame(order_data, columns=['order_id', 'user_id', 'product_id', 'quantity', 'price', 'order_time'])
    df_orders['total_amount'] = df_orders['quantity'] * df_orders['price']
    df_orders['category'] = df_orders['product_id'].map(lambda x: products[x]['category'])
    df_orders['brand'] = df_orders['product_id'].map(lambda x: products[x]['brand'])

    return df_users, df_browsing, df_orders

df_users, df_browsing, df_orders = generate_user_profile_data(num_users=1000)

print("--- 用户基本信息 (df_users) ---")
print(df_users.head())
print("\n--- 用户浏览行为 (df_browsing) ---")
print(df_browsing.head())
print("\n--- 用户购买行为 (df_orders) ---")
print(df_orders.head())

# --- 用户画像构建 (特征工程与标签化) ---
print("\n--- 用户画像构建 ---")

# 1. 合并用户基本信息和购买行为
user_purchase_summary = df_orders.groupby('user_id').agg(
    total_orders=('order_id', 'nunique'),
    total_spent=('total_amount', 'sum'),
    avg_order_value=('total_amount', 'mean'),
    first_purchase_date=('order_time', 'min'),
    last_purchase_date=('order_time', 'max')
).reset_index()

df_user_profile = pd.merge(df_users, user_purchase_summary, on='user_id', how='left')

# 2. 从浏览行为中提取特征
# 最常浏览的商品类别
most_viewed_category = df_browsing.groupby('user_id')['category'].agg(lambda x: x.mode()[0] if not x.empty else None).reset_index(name='most_viewed_category')
df_user_profile = pd.merge(df_user_profile, most_viewed_category, on='user_id', how='left')

# 3. 从购买行为中提取特征
# 最常购买的商品类别
most_bought_category = df_orders.groupby('user_id')['category'].agg(lambda x: x.mode()[0] if not x.empty else None).reset_index(name='most_bought_category')
df_user_profile = pd.merge(df_user_profile, most_bought_category, on='user_id', how='left')

# 4. 衍生标签 (例如:消费等级、活跃度)
# 填充未购买用户的消费数据为0,方便后续打标签
df_user_profile['total_spent'] = df_user_profile['total_spent'].fillna(0)
df_user_profile['total_orders'] = df_user_profile['total_orders'].fillna(0)

# 消费等级标签
df_user_profile['spending_level'] = pd.qcut(
    df_user_profile[df_user_profile['total_spent'] > 0]['total_spent'],
    q=3,
    labels=['低消费', '中消费', '高消费']
).astype(object) # 转换为object类型,否则未购买用户会是NaN
df_user_profile['spending_level'] = df_user_profile['spending_level'].fillna('未消费')


# 活跃度标签 (简单示例:根据订单数)
df_user_profile['activity_level'] = df_user_profile['total_orders'].apply(
    lambda x: '高活跃' if x >= 5 else ('中活跃' if x >= 2 else ('低活跃' if x > 0 else '不活跃'))
)

print("\n--- 最终用户画像 (部分特征) ---")
print(df_user_profile[['user_id', 'gender', 'age', 'city', 'total_spent', 'total_orders', 'most_bought_category', 'spending_level', 'activity_level']].head(10))

print("\n--- 用户画像统计概览 ---")
print("性别分布:\n", df_user_profile['gender'].value_counts(normalize=True))
print("\n城市分布 (Top 5):\n", df_user_profile['city'].value_counts().head())
print("\n消费等级分布:\n", df_user_profile['spending_level'].value_counts())
print("\n活跃度分布:\n", df_user_profile['activity_level'].value_counts())

# 可视化用户画像特征
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

fig, axes = plt.subplots(1, 3, figsize=(18, 5))

sns.countplot(x='gender', data=df_user_profile, ax=axes[0])
axes[0].set_title('用户性别分布')

sns.histplot(df_user_profile['age'], bins=10, kde=True, ax=axes[1])
axes[1].set_title('用户年龄分布')

sns.countplot(x='spending_level', data=df_user_profile, order=['未消费', '低消费', '中消费', '高消费'], ax=axes[2])
axes[2].set_title('用户消费等级分布')

plt.tight_layout()
plt.show()

# 交叉分析示例:不同性别用户的消费等级
gender_spending = pd.crosstab(df_user_profile['gender'], df_user_profile['spending_level'], normalize='index')
print("\n不同性别用户的消费等级分布:\n", gender_spending)
gender_spending.plot(kind='bar', stacked=True, figsize=(8, 5))
plt.title('不同性别用户的消费等级')
plt.ylabel('比例')
plt.show()

【互动问答】

  • 用户画像的“标签化”有什么好处?在实际运营中如何使用这些标签?
  • 除了我们生成的这些特征,你还能想到哪些可以用来构建用户画像的特征?
  • pd.qcut() 和 pd.cut() 在数据分箱时有什么区别?
  • 如何从用户浏览行为中提取“用户偏好品类”标签?
  • 如果用户数据量非常大,如何高效地进行特征工程?

5.2 RFM模型(重点)

【理论讲解】

RFM模型(Recency, Frequency, Monetary)是电商领域最经典、最实用的用户价值分析模型之一。它通过用户的“最近一次消费时间”、“消费频率”和“消费金额”三个指标来衡量用户价值。

  • R (Recency – 最近一次消费): 用户最近一次购买距离现在的时间。R值越小(越近),用户价值越高。
  • F (Frequency – 消费频率): 用户在一定时间内的购买次数。F值越大,用户价值越高。
  • M (Monetary – 消费金额): 用户在一定时间内的消费总金额。M值越大,用户价值越高。

RFM评分与用户分群:

通常我们会将R、F、M三个指标分别打分(如1-5分),然后组合分数对用户进行分群,例如:

  • 高价值用户 (重要价值客户): R高F高M高
  • 重要保持客户: R高F高M中
  • 重要发展客户: R低F高M高(最近不活跃但消费高,需要唤醒)
  • 流失客户: R低F低M低

【自动生成数据集与代码实例】

我们将基于之前生成的 df_orders 数据,来计算RFM指标并进行用户分群。

python

import pandas as pd
import numpy as np
from datetime import datetime, timedelta

# --- 数据集生成 (复用之前的订单数据) ---
np.random.seed(42)
def generate_rfm_orders_data(num_users=1000, start_date='2022-01-01', end_date='2023-12-31'):
    products = {
        'P101': {'category': 'Electronics', 'brand': 'TechCo', 'price_range': (100, 1000)},
        'P102': {'category': 'Apparel', 'brand': 'FashionX', 'price_range': (50, 500)},
        'P103': {'category': 'Home', 'brand': 'LifeStyle', 'price_range': (20, 300)},
        'P104': {'category': 'Books', 'brand': 'ReadNow', 'price_range': (10, 150)},
        'P105': {'category': 'Sports', 'brand': 'ActiveFit', 'price_range': (80, 800)},
    }
    product_ids = list(products.keys())

    order_data = []
    for _ in range(num_users * 3): # 模拟更多购买行为,让RFM更明显
        user_id = f'U{np.random.randint(0, num_users):04d}'
        product_id = np.random.choice(product_ids)
        quantity = np.random.randint(1, 4)
        price_range = products[product_id]['price_range']
        price = round(np.random.uniform(price_range[0], price_range[1]), 2)
        order_time = pd.to_datetime(start_date) + timedelta(seconds=np.random.randint(0, (pd.to_datetime(end_date) - pd.to_datetime(start_date)).total_seconds()))
        order_data.append([f'ORD{_ + 1:05d}', user_id, product_id, quantity, price, order_time])
    df_orders_rfm = pd.DataFrame(order_data, columns=['order_id', 'user_id', 'product_id', 'quantity', 'price', 'order_time'])
    df_orders_rfm['total_amount'] = df_orders_rfm['quantity'] * df_orders_rfm['price']
    return df_orders_rfm

df_orders_rfm = generate_rfm_orders_data(num_users=500, start_date='2022-01-01', end_date='2023-12-31')
print("--- RFM订单数据预览 ---")
print(df_orders_rfm.head())
print("数据时间范围:", df_orders_rfm['order_time'].min(), "到", df_orders_rfm['order_time'].max())

# --- RFM模型计算 ---
print("\n--- RFM模型计算 ---")

# 定义分析的截止日期 (通常是数据集中最新订单的日期,或今天的日期)
snapshot_date = df_orders_rfm['order_time'].max() + timedelta(days=1)
print(f"分析截止日期: {snapshot_date}")

# 计算R, F, M
rfm = df_orders_rfm.groupby('user_id').agg(
    recency=('order_time', lambda date: (snapshot_date - date.max()).days), # 最近一次消费距离截止日期的天数
    frequency=('order_id', 'nunique'),                                  # 购买次数 (不重复订单ID)
    monetary=('total_amount', 'sum')                                    # 消费总金额
).reset_index()

print("\nRFM原始数据预览:\n", rfm.head())

# --- RFM评分 (通常采用等频分箱或业务经验分箱) ---
print("\n--- RFM评分 ---")

# 等频分箱 (将数据分成N等份,每份的用户数量大致相等)
# R: 越小越好,所以评分高的R值反而小
rfm['R_score'] = pd.qcut(rfm['recency'], q=5, labels=[5, 4, 3, 2, 1], duplicates='drop')
# F: 越大越好
rfm['F_score'] = pd.qcut(rfm['frequency'], q=5, labels=[1, 2, 3, 4, 5], duplicates='drop')
# M: 越大越好
rfm['M_score'] = pd.qcut(rfm['monetary'], q=5, labels=[1, 2, 3, 4, 5], duplicates='drop')

# 组合RFM分数
rfm['RFM_score'] = rfm['R_score'].astype(str) + rfm['F_score'].astype(str) + rfm['M_score'].astype(str)
print("\nRFM评分后的数据预览:\n", rfm.head())

# --- 用户分群 ---
print("\n--- 用户分群 ---")

# 定义用户分群规则 (可以根据业务经验调整)
def rfm_segment(row):
    r, f, m = row['R_score'], row['F_score'], row['M_score']
    if r >= 4 and f >= 4 and m >= 4:
        return '重要价值客户' # 高R高F高M
    elif r >= 4 and f >= 3 and m >= 3:
        return '重要保持客户' # 高R中F中M
    elif r >= 3 and f >= 4 and m >= 4:
        return '重要发展客户' # 中R高F高M
    elif r >= 3 and f >= 2 and m >= 2:
        return '一般客户'
    elif r <= 2 and f >= 3 and m >= 3:
        return '重要挽留客户' # 低R高F高M (过去是好客户,现在不活跃了)
    elif r <= 2 and f <= 2 and m <= 2:
        return '流失客户' # 低R低F低M
    else:
        return '潜在客户' # 其他情况,待观察

rfm['customer_segment'] = rfm.apply(rfm_segment, axis=1)

print("\nRFM分群结果预览:\n", rfm.head(10))

# 统计各群组的用户数量
segment_counts = rfm['customer_segment'].value_counts().sort_values(ascending=False)
print("\n各客户群组用户数量:\n", segment_counts)

# 可视化分群结果
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

plt.figure(figsize=(10, 6))
sns.barplot(x=segment_counts.index, y=segment_counts.values, palette='viridis')
plt.title('RFM客户分群数量分布')
plt.xlabel('客户群组')
plt.ylabel('用户数量')
plt.xticks(rotation=45, ha='right')
plt.tight_layout()
plt.show()

# 进一步分析各群组的RFM均值
segment_rfm_means = rfm.groupby('customer_segment')[['recency', 'frequency', 'monetary']].mean().sort_values(by='monetary', ascending=False)
print("\n各客户群组的RFM均值:\n", segment_rfm_means)

# 【运营策略建议】
print("\n--- 基于RFM分群的运营策略建议 ---")
print("1. **重要价值客户 (高R高F高M):** 给予VIP待遇,优先体验新品,个性化专属服务,维持高忠诚度。")
print("2. **重要保持客户 (高R中F中M):** 鼓励提升消费频次和金额,可推荐关联商品,积分奖励。")
print("3. **重要发展客户 (中R高F高M):** 最近不活跃但历史消费高,需要唤醒,通过个性化推荐、限时优惠刺激复购。")
print("4. **重要挽留客户 (低R高F高M):** 紧急挽留,发送挽留邮件/短信,提供高折扣优惠券,了解流失原因。")
print("5. **流失客户 (低R低F低M):** 成本较高,可尝试少量优惠券唤醒,或放弃。")

【互动问答】

  • 为什么RFM中的R值是越小越好,而F和M值是越大越好?
  • RFM评分时,等频分箱和等距分箱各有什么优缺点?在什么情况下选择哪种?
  • 除了我们定义的这些客户群组,你还能想到哪些有意义的RFM组合群组?
  • 如何使用RFM模型来评估一次营销活动的效果?
  • RFM模型有哪些局限性?在实际应用中需要注意什么?

5.3 用户生命周期分析

【理论讲解】

用户生命周期(User Lifecycle)描述了用户从首次接触产品到最终流失的整个过程。理解用户在不同生命周期阶段的特征和需求,有助于我们制定针对性的运营策略,提高用户留存和LTV(生命周期价值)。

主要阶段:

  1. 新用户 (New User): 首次注册或首次购买的用户。
  2. 活跃用户 (Active User): 在一定时间内有持续行为(如登录、浏览、购买)的用户。
  3. 留存用户 (Retained User): 在首次行为后,再次进行关键行为的用户。
  4. 沉默用户 (Dormant User): 一段时间内没有活跃行为,但尚未完全流失的用户。
  5. 流失用户 (Churned User): 长期没有活跃行为,被认为已离开平台的用户。

核心分析指标:

  • 用户留存率: 衡量用户在一段时间后仍保持活跃的比例。
  • 用户转化漏斗: 追踪用户从某个起始点(如访问)到最终目标(如购买)的每一步转化率。

【自动生成数据集与代码实例】

我们将生成一个包含用户注册、浏览、加购和购买行为的模拟数据集,用于用户生命周期分析。

python

import pandas as pd
import numpy as np
from datetime import datetime, timedelta

# --- 数据集生成 ---
np.random.seed(42)

def generate_user_lifecycle_data(num_users=1000, start_date='2023-01-01', end_date='2023-03-31'):
    users = [f'U{i:04d}' for i in range(num_users)]
    products = {f'P{i:03d}': {'category': np.random.choice(['Electronics', 'Apparel', 'Home', 'Books', 'Sports']), 'price': round(np.random.uniform(20, 1000), 2)} for i in range(50)}
    product_ids = list(products.keys())

    data = []
    current_date = pd.to_datetime(start_date)
    while current_date <= pd.to_datetime(end_date):
        for user_id in np.random.choice(users, size=np.random.randint(50, 200), replace=False): # 每天活跃用户
            # 模拟浏览行为
            for _ in range(np.random.randint(1, 5)):
                product_id = np.random.choice(product_ids)
                data.append([user_id, product_id, current_date + timedelta(minutes=np.random.randint(0, 1440)), 'browse'])
            
            # 模拟加购行为 (部分浏览用户会加购)
            if np.random.rand() < 0.3: # 30%的浏览用户会加购
                product_id = np.random.choice(product_ids)
                data.append([user_id, product_id, current_date + timedelta(minutes=np.random.randint(0, 1440)), 'add_to_cart'])

            # 模拟购买行为 (部分加购用户会购买)
            if np.random.rand() < 0.15: # 15%的加购用户会购买
                product_id = np.random.choice(product_ids)
                quantity = np.random.randint(1, 3)
                price = products[product_id]['price']
                total_amount = round(price * quantity, 2)
                data.append([user_id, product_id, current_date + timedelta(minutes=np.random.randint(0, 1440)), 'purchase', quantity, price, total_amount])
        current_date += timedelta(days=1)

    df_lifecycle = pd.DataFrame(data, columns=['user_id', 'product_id', 'event_time', 'event_type', 'quantity', 'price', 'total_amount'])
    df_lifecycle['event_time'] = pd.to_datetime(df_lifecycle['event_time'])
    
    # 填充NaN值,因为只有purchase事件才有quantity, price, total_amount
    df_lifecycle[['quantity', 'price', 'total_amount']] = df_lifecycle[['quantity', 'price', 'total_amount']].fillna(0)
    
    return df_lifecycle

df_lifecycle = generate_user_lifecycle_data(num_users=1000, start_date='2023-01-01', end_date='2023-03-31')
print("--- 用户生命周期数据预览 ---")
print(df_lifecycle.head())
print("\n事件类型分布:\n", df_lifecycle['event_type'].value_counts())

# --- 用户生命周期阶段识别 ---
print("\n--- 用户生命周期阶段识别 ---")

# 1. 识别新用户(首次购买用户)
first_purchase_time = df_lifecycle[df_lifecycle['event_type'] == 'purchase'].groupby('user_id')['event_time'].min().reset_index(name='first_purchase_time')
df_lifecycle = pd.merge(df_lifecycle, first_purchase_time, on='user_id', how='left')
df_lifecycle['is_new_user'] = (df_lifecycle['event_type'] == 'purchase') & (df_lifecycle['event_time'] == df_lifecycle['first_purchase_time'])

# 2. 活跃用户、沉默用户、流失用户
# 定义活跃周期和沉默周期
active_threshold_days = 7   # 7天内有行为算活跃
dormant_threshold_days = 30 # 30天内无行为算沉默,超过30天算流失

current_date_for_analysis = df_lifecycle['event_time'].max() # 以数据集中最新日期作为当前日期

user_last_activity = df_lifecycle.groupby('user_id')['event_time'].max().reset_index(name='last_activity_time')
user_last_activity['days_since_last_activity'] = (current_date_for_analysis - user_last_activity['last_activity_time']).dt.days

def get_user_status(days_since_last_activity):
    if days_since_last_activity <= active_threshold_days:
        return '活跃用户'
    elif days_since_last_activity <= dormant_threshold_days:
        return '沉默用户'
    else:
        return '流失用户'

user_last_activity['user_status'] = user_last_activity['days_since_last_activity'].apply(get_user_status)

print("\n用户活跃状态统计:\n", user_last_activity['user_status'].value_counts())

# --- 用户留存率分析 (按首次购买月份) ---
print("\n--- 用户留存率分析 ---")

# 1. 确定每个用户的首次购买月份
df_purchases = df_lifecycle[df_lifecycle['event_type'] == 'purchase'].copy()
df_purchases['cohort_month'] = df_purchases.groupby('user_id')['event_time'].transform('min').dt.to_period('M')
df_purchases['purchase_month'] = df_purchases['event_time'].dt.to_period('M')

# 2. 计算用户生命周期月份
df_purchases['cohort_period'] = (df_purchases['purchase_month'] - df_purchases['cohort_month']).apply(lambda x: x.n)

# 3. 统计每个同期群(cohort)在不同月份的留存用户数
cohort_counts = df_purchases.groupby(['cohort_month', 'cohort_period'])['user_id'].nunique().reset_index()
cohort_pivot = cohort_counts.pivot_table(index='cohort_month', columns='cohort_period', values='user_id')

# 4. 计算留存率
cohort_sizes = cohort_pivot.iloc[:, 0] # 每个同期群的初始用户数
retention_matrix = cohort_pivot.divide(cohort_sizes, axis=0)

print("\n同期群留存率矩阵:\n", retention_matrix)

# 可视化留存率热力图
plt.figure(figsize=(10, 7))
sns.heatmap(retention_matrix, annot=True, fmt=".1%", cmap='Blues', linewidths=.5)
plt.title('用户留存率 (按首次购买月份)')
plt.xlabel('生命周期月份')
plt.ylabel('首次购买月份')
plt.show()

# --- 用户转化漏斗分析 ---
print("\n--- 用户转化漏斗分析 ---")

# 定义漏斗步骤 (例如:浏览 -> 加购 -> 购买)
funnel_steps = ['browse', 'add_to_cart', 'purchase']

# 统计每个步骤的用户数
funnel_data = {}
for step in funnel_steps:
    if step == 'purchase':
        # 购买事件中,一个用户可能有多笔订单,这里统计独立用户数
        funnel_data[step] = df_lifecycle[df_lifecycle['event_type'] == step]['user_id'].nunique()
    else:
        # 浏览和加购事件,统计独立用户数
        funnel_data[step] = df_lifecycle[df_lifecycle['event_type'] == step]['user_id'].nunique()

df_funnel = pd.DataFrame.from_dict(funnel_data, orient='index', columns=['users'])
df_funnel['conversion_rate'] = df_funnel['users'].pct_change().fillna(1) * 100 # 与上一步的转化率
df_funnel['total_conversion_rate'] = df_funnel['users'] / df_funnel['users'].iloc[0] * 100 # 相对于第一步的总转化率

print("\n用户转化漏斗:\n", df_funnel)

# 漏斗可视化
fig, ax = plt.subplots(figsize=(8, 6))
bars = ax.bar(df_funnel.index, df_funnel['users'], color='lightgreen')
ax.set_title('用户转化漏斗')
ax.set_xlabel('事件类型')
ax.set_ylabel('用户数量')
ax.ticklabel_format(style='plain', axis='y') # 取消科学计数法

# 添加转化率标签
for i, bar in enumerate(bars):
    if i > 0:
        total_rate = df_funnel['total_conversion_rate'].iloc[i]
        step_rate = df_funnel['conversion_rate'].iloc[i]
        ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height(),
                f'{bar.get_height()}\n({step_rate:.1f}%)\n({total_rate:.1f}% total)',
                ha='center', va='bottom', fontsize=10)
    else:
        ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height(),
                f'{bar.get_height()}', ha='center', va='bottom', fontsize=10)
plt.tight_layout()
plt.show()

# 【运营策略建议】
print("\n--- 基于用户生命周期分析的运营策略建议 ---")
print("1. **新用户引入:** 关注新用户注册/首购转化率,优化新手引导、首单优惠。")
print("2. **提升活跃度:** 对沉默用户进行精准营销,如发送个性化推荐、优惠券唤醒。")
print("3. **挽留流失用户:** 对流失用户进行调查,了解流失原因,尝试高价值召回活动。")
print("4. **优化转化漏斗:** 针对转化率低的环节进行分析,如“加购到购买”转化低,可能是结算流程复杂、运费高、支付方式少等问题。")

【互动问答】

  • 用户生命周期分析对电商运营有什么实际意义?
  • 在计算留存率时,为什么选择“同期群(Cohort)”的概念?
  • 如何根据漏斗分析的结果,判断哪个环节最需要优化?
  • 除了我们定义的这些事件类型,你还能想到哪些可以放入漏斗分析的电商行为?
  • 如何识别“假性流失”用户(例如,某个用户只是季节性购买)?

5.4 用户价值与流失预测(入门)

【理论讲解】

在用户生命周期分析的基础上,我们可以进一步尝试预测用户的未来行为,例如预测用户未来的消费金额(用户价值)或预测哪些用户即将流失(流失预测)。这需要引入一些简单的机器学习概念。

  • 用户价值预测: 预测用户在未来一段时间内可能产生的消费金额。
  • 用户流失预测: 识别哪些用户有高风险在未来一段时间内流失。

常用方法:

  • 线性回归: 预测连续数值型目标(如未来消费金额)。
  • 逻辑回归: 预测二分类目标(如是否流失)。

【自动生成数据集与代码实例】

我们将基于之前的RFM数据和用户活跃状态,生成一些额外的特征,并进行简单的预测模型构建。

python

import pandas as pd
import numpy as np
from datetime import datetime, timedelta
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression, LogisticRegression
from sklearn.metrics import mean_squared_error, accuracy_score, classification_report
import matplotlib.pyplot as plt
import seaborn as sns

# --- 数据集生成 (复用RFM数据和用户活跃状态) ---
np.random.seed(42)

def generate_prediction_data(num_users=1000, start_date='2022-01-01', end_date='2023-12-31'):
    # 模拟RFM数据
    df_orders_rfm = generate_rfm_orders_data(num_users, start_date, end_date)
    snapshot_date = df_orders_rfm['order_time'].max() + timedelta(days=1)
    rfm = df_orders_rfm.groupby('user_id').agg(
        recency=('order_time', lambda date: (snapshot_date - date.max()).days),
        frequency=('order_id', 'nunique'),
        monetary=('total_amount', 'sum')
    ).reset_index()

    # 模拟用户活跃状态 (基于RFM的recency)
    active_threshold_days = 30
    rfm['is_churned'] = (rfm['recency'] > active_threshold_days).astype(int) # 超过30天未购买视为流失

    # 模拟额外特征,用于预测
    rfm['avg_item_price'] = df_orders_rfm.groupby('user_id')['price'].mean().fillna(0).values
    rfm['total_quantity'] = df_orders_rfm.groupby('user_id')['quantity'].sum().fillna(0).values
    rfm['days_since_first_purchase'] = (snapshot_date - df_orders_rfm.groupby('user_id')['order_time'].min()).dt.days.fillna(0).values

    # 模拟未来消费 (作为价值预测的目标变量)
    rfm['future_monetary'] = rfm['monetary'] * np.random.uniform(0.5, 1.5, size=len(rfm)) # 简单模拟,与当前消费相关
    rfm.loc[rfm['is_churned'] == 1, 'future_monetary'] = rfm.loc[rfm['is_churned'] == 1, 'future_monetary'] * np.random.uniform(0, 0.2, size=rfm['is_churned'].sum()) # 流失用户未来消费低

    return rfm

df_rfm_prediction = generate_prediction_data(num_users=1000)
print("--- 用于预测的数据预览 ---")
print(df_rfm_prediction.head())
print("\n流失用户比例:", df_rfm_prediction['is_churned'].mean())

# --- 用户价值预测 (简单线性回归) ---
print("\n--- 用户价值预测 (未来消费金额) ---")

# 选择特征 (X) 和目标变量 (y)
features_value = ['recency', 'frequency', 'monetary', 'avg_item_price', 'total_quantity', 'days_since_first_purchase']
target_value = 'future_monetary'

X_value = df_rfm_prediction[features_value]
y_value = df_rfm_prediction[target_value]

# 划分训练集和测试集
X_train_value, X_test_value, y_train_value, y_test_value = train_test_split(X_value, y_value, test_size=0.2, random_state=42)

# 训练线性回归模型
lr_model = LinearRegression()
lr_model.fit(X_train_value, y_train_value)

# 进行预测
y_pred_value = lr_model.predict(X_test_value)

# 评估模型
rmse = np.sqrt(mean_squared_error(y_test_value, y_pred_value))
print(f"\n用户价值预测 - RMSE (均方根误差): {rmse:.2f}")

# 可视化预测结果 (部分数据)
plt.figure(figsize=(10, 6))
plt.scatter(y_test_value, y_pred_value, alpha=0.6)
plt.plot([y_test_value.min(), y_test_value.max()], [y_test_value.min(), y_test_value.max()], 'r--') # 绘制y=x线
plt.title('用户未来消费金额预测结果')
plt.xlabel('真实未来消费金额')
plt.ylabel('预测未来消费金额')
plt.show()

# 【运营建议】
print("\n--- 基于用户价值预测的运营策略建议 ---")
print("1. **精准营销:** 对预测未来价值高的用户,提供专属优惠和个性化推荐,进一步提升LTV。")
print("2. **资源分配:** 将营销预算更多地投入到高价值潜力的用户上。")


# --- 用户流失预测 (简单逻辑回归) ---
print("\n--- 用户流失预测 ---")

# 选择特征 (X) 和目标变量 (y)
features_churn = ['recency', 'frequency', 'monetary', 'avg_item_price', 'total_quantity', 'days_since_first_purchase']
target_churn = 'is_churned' # 0表示未流失,1表示流失

X_churn = df_rfm_prediction[features_churn]
y_churn = df_rfm_prediction[target_churn]

# 划分训练集和测试集
X_train_churn, X_test_churn, y_train_churn, y_test_churn = train_test_split(X_churn, y_churn, test_size=0.2, random_state=42, stratify=y_churn) # stratify保持目标变量比例

# 训练逻辑回归模型
lr_churn_model = LogisticRegression(solver='liblinear') # 使用liblinear避免警告
lr_churn_model.fit(X_train_churn, y_train_churn)

# 进行预测
y_pred_churn = lr_churn_model.predict(X_test_churn)
y_pred_proba_churn = lr_churn_model.predict_proba(X_test_churn)[:, 1] # 预测流失概率

# 评估模型
accuracy = accuracy_score(y_test_churn, y_pred_churn)
print(f"\n用户流失预测 - 准确率: {accuracy:.2f}")
print("\n分类报告:\n", classification_report(y_test_churn, y_pred_churn))

# 查看流失概率最高的客户
df_test_churn = X_test_churn.copy()
df_test_churn['actual_churn'] = y_test_churn
df_test_churn['predicted_churn_proba'] = y_pred_proba_churn
print("\n预测流失概率最高的Top 10用户:\n", df_test_churn.sort_values(by='predicted_churn_proba', ascending=False).head(10))

# 【运营建议】
print("\n--- 基于用户流失预测的运营策略建议 ---")
print("1. **提前预警:** 识别出高流失风险的用户,在他们真正流失前采取干预措施。")
print("2. **精准挽留:** 对高风险用户提供个性化的挽留优惠、专属服务或问卷调查,了解并解决痛点。")
print("3. **资源优化:** 将挽留资源集中在最有价值且有流失风险的用户上。")

【互动问答】

  • 线性回归和逻辑回归分别适用于什么类型的预测问题?它们有什么区别?
  • RMSE、准确率、精确率、召回率、F1-score这些模型评估指标分别代表什么含义?在流失预测中,哪个指标可能更重要?
  • train_test_split 的 stratify 参数有什么作用?在什么情况下使用它?
  • 除了我们使用的这些特征,你还能想到哪些可以用来预测用户价值或流失的特征?
  • 在实际应用中,如何将预测结果转化为具体的运营行动?