自学教程 学编程从这里开始

Pandas 用户行为分析实战

承接电商实战案例,本篇聚焦用户行为日志分析,是埋点日志场景的标准实战:行为日志清洗、会话Session划分、PV/UV、跳出率、访问路径、转化漏斗、用户活跃度、Cohort留存,贴合埋点、APP/小程序/网站用户分析,代码可直接复用。
前置导入

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# 绘图中文配置
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
sns.set_style("whitegrid")

一、模拟用户行为埋点数据

行为日志通用字段:用户ID、设备ID、行为时间、页面/事件名称、行为类型、来源渠道、页面停留时长

业务说明:

  • 行为类型:view浏览、click点击、submit提交、pay支付
  • Session会话:同一个用户,间隔超过30分钟判定为新会话(行业通用30min窗口)
df = pd.DataFrame({
    "user_id": ["U001","U001","U001","U002","U002","U003","U003","U003","U004","U005","U005","U006"],
    "event_time": pd.to_datetime([
        "2026-09-10 08:10:00","2026-09-10 08:15:00","2026-09-10 09:00:00",
        "2026-09-10 08:20:00","2026-09-10 08:25:00",
        "2026-09-10 09:10:00","2026-09-10 09:12:00","2026-09-10 09:18:00",
        "2026-09-10 10:00:00",
        "2026-09-10 10:20:00","2026-09-10 10:25:00",
        "2026-09-10 11:00:00"
    ]),
    "event_name": ["首页","商品列表","支付页","首页","商品详情","首页","商品列表","支付","首页","首页","商品详情","首页"],
    "event_type": ["view","click","submit","view","click","view","click","pay","view","view","click","view"],
    "channel": ["小程序","小程序","小程序","抖音","抖音","淘宝","淘宝","淘宝","小红书","抖音","抖音","小红书"],
    "stay_seconds": [12,25,8,18,40,10,15,22,9,14,33,7]
})
print("原始行为日志:")
print(df.head())

二、数据清洗与排序

日志数据经常乱序,第一步必须按用户+时间排序

# 按用户、时间升序
df = df.sort_values(["user_id","event_time"], ascending=[True, True]).reset_index(drop=True)
# 新增日期列
df["event_date"] = df["event_time"].dt.date
# 检查空值
print("缺失值统计:")
print(df.isna().sum())

三、会话Session划分(用户行为核心)

规则:同一user_id,相邻两条行为时间差 >30分钟 → 新session

# 分组,计算上一条行为的时间
df["prev_time"] = df.groupby("user_id")["event_time"].shift(1)
# 时间差(分钟)
df["delta_min"] = (df["event_time"] - df["prev_time"]).dt.total_seconds() / 60
# 是否是新会话标记:第一条记录 或者 间隔>30分钟
df["is_new_session"] = np.where(df["delta_min"].isna() | (df["delta_min"] > 30), 1, 0)
# session_id:累加生成会话编号
df["session_id"] = df.groupby("user_id")["is_new_session"].cumsum()
# 拼接唯一session标识 user+session
df["session_uid"] = df["user_id"] + "_" + df["session_id"].astype(str)

print("带会话标记的数据:")
print(df[["user_id","event_time","event_name","session_uid"]].head(10))

四、基础指标:PV / UV / 会话数

  • PV:行为总次数(页面浏览次数)
  • UV:独立用户数
  • 会话数:独立session_uid
  • 平均会话时长:每个会话内首尾时间差
  • 平均每会话访问页数:会话内行为条数
pv = len(df)
uv = df["user_id"].nunique()
session_cnt = df["session_uid"].nunique()

# 会话聚合
session_agg = df.groupby("session_uid").agg(
    session_start=("event_time","min"),
    session_end=("event_time","max"),
    page_cnt=("event_name","count")
).reset_index()
session_agg["session_duration_sec"] = (session_agg["session_end"] - session_agg["session_start"]).dt.total_seconds()

avg_session_sec = session_agg["session_duration_sec"].mean()
avg_page_per_session = session_agg["page_cnt"].mean()

print("===== 大盘行为指标 =====")
print(f"PV:{pv}")
print(f"UV:{uv}")
print(f"会话总数:{session_cnt}")
print(f"平均会话时长(秒):{avg_session_sec:.1f}")
print(f"平均每会话访问页数:{avg_page_per_session:.1f}")

五、跳出率计算

跳出定义:会话内只有1条行为,用户进来直接离开,没有后续操作
跳出率 = 跳出会话数 / 总会话数

bounce_session = session_agg[session_agg["page_cnt"] == 1]
bounce_cnt = len(bounce_session)
bounce_rate = bounce_cnt / session_cnt
print(f"跳出会话数:{bounce_cnt},跳出率:{bounce_rate:.2%}")

六、转化漏斗分析

漏斗路径:首页 → 商品列表/详情 → 提交订单 → 支付
思路:统计每个环节的独立用户数,逐级计算转化率

# 各环节去重用户
step_home = df[df["event_name"] == "首页"]["user_id"].nunique()
step_product = df[df["event_name"].isin(["商品列表","商品详情"])]["user_id"].nunique()
step_submit = df[df["event_type"] == "submit"]["user_id"].nunique()
step_pay = df[df["event_type"] == "pay"]["user_id"].nunique()

funnel = pd.DataFrame({
    "step": ["访问首页","浏览商品","提交订单","完成支付"],
    "user_cnt": [step_home, step_product, step_submit, step_pay]
})
# 环比转化率
funnel["convert_rate"] = funnel["user_cnt"] / funnel["user_cnt"].shift(1)
funnel["convert_rate"] = funnel["convert_rate"].fillna(1)
print("转化漏斗:")
print(funnel)

七、渠道行为分析

不同渠道的UV、会话数、跳出率对比,用来评估渠道质量

# 渠道维度会话统计
channel_session = df.groupby(["channel","session_uid"])["event_time"].count().reset_index()
channel_session.columns = ["channel","session_uid","page_cnt"]
channel_report = channel_session.groupby("channel").agg(
    session_cnt=("session_uid","nunique"),
    bounce_session=("page_cnt", lambda x: (x == 1).sum())
).reset_index()
# 渠道UV
channel_uv = df.groupby("channel")["user_id"].nunique().reset_index().rename(columns={"user_id":"uv"})
channel_report = channel_report.merge(channel_uv, on="channel")
channel_report["bounce_rate"] = channel_report["bounce_session"] / channel_report["session_cnt"]
print("渠道行为报表:")
print(channel_report)

八、用户访问路径分析

提取每个session内的页面访问序列,看高频路径

# 按会话拼接访问路径
path_df = df.groupby("session_uid")["event_name"].agg(lambda x: "->".join(x)).reset_index()
path_df.columns = ["session_uid","visit_path"]
# 路径频次统计
path_rank = path_df["visit_path"].value_counts().reset_index()
path_rank.columns = ["visit_path","cnt"]
print("高频访问路径TOP:")
print(path_rank)

九、用户活跃度(DAU日活)

dau_report = df.groupby("event_date").agg(
    dau=("user_id","nunique"),
    pv=("user_id","count")
).reset_index()
print("DAU日活报表:")
print(dau_report)

十、可视化绘图

fig, axes = plt.subplots(2,2,figsize=(14,10))
# 1.漏斗图柱状
sns.barplot(data=funnel, x="step", y="user_cnt", ax=axes[0,0], errorbar=None)
axes[0,0].set_title("转化漏斗")
axes[0,0].tick_params(axis="x", rotation=15)
# 2.渠道跳出率
sns.barplot(data=channel_report, x="channel", y="bounce_rate", ax=axes[0,1], errorbar=None)
axes[0,1].set_title("各渠道跳出率")
# 3.渠道UV
sns.barplot(data=channel_report, x="channel", y="uv", ax=axes[1,0], errorbar=None)
axes[1,0].set_title("渠道UV")
# 4.访问路径频次
sns.barplot(data=path_rank.head(4), x="cnt", y="visit_path", ax=axes[1,1])
axes[1,1].set_title("高频访问路径")

plt.tight_layout()
plt.savefig("user_behavior_report.png",dpi=300,bbox_inches="tight")
plt.close()
print("图表导出完成:user_behavior_report.png")

十一、结果导出Excel

with pd.ExcelWriter("用户行为分析结果.xlsx", engine="openpyxl") as writer:
    funnel.to_excel(writer, sheet_name="转化漏斗", index=False)
    channel_report.to_excel(writer, sheet_name="渠道报表", index=False)
    path_rank.to_excel(writer, sheet_name="访问路径", index=False)
    dau_report.to_excel(writer, sheet_name="DAU报表", index=False)
print("Excel报表导出完成")

十二、业务解读与扩展方向

  1. 会话Session:30分钟是默认阈值,短视频、工具类产品可以改成15分钟;长内容阅读可改成60分钟
  2. 跳出率高:检查落地页加载、内容匹配度、广告素材是否货不对板
  3. 漏斗卡点:找到流失最高的环节做优化(比如提交到支付流失高,就是支付/优惠问题)
  4. 访问路径:发现用户偏好,做页面跳转、推荐位优化
  5. 进阶拓展:
    • 页面停留时长分布、热力点击
    • 用户分群(高活跃/低活跃用户)
    • 行为序列马尔可夫链
    • 和订单表关联,行为+成交联合分析

十三、高频坑清单

  1. 日志没有排序,直接分组计算session,session划分完全错乱
  2. 会话划分用全局时间差,忘记按user_id分组
  3. PV统计直接count,没有区分有效行为,埋点里过滤埋点自检、后台上报脏数据
  4. 漏斗统计混用session和user口径,指标口径不一致(优先统一用独立用户)
  5. 跳出定义混淆:不要把“只有一条行为”当成坏行为,部分场景用户就是只看首页
  6. 大埋点日志(千万级):必须分块读取、按日期分区,不要一次性加载全量日志

十四、速查表

分析场景Pandas核心方法
会话Session切割groupby + shift + 时间差 + cumsum
PV/UVlen / nunique
跳出率统计session内行为条数
转化漏斗多条件筛选 + nunique
访问路径groupby + join字符串 + value_counts
DAUgroupby 日期 + nunique(user_id)
渠道质量对比多表merge合并UV、会话、跳出率
标签:

0 条笔记