承接电商实战案例,本篇聚焦用户行为日志分析,是埋点日志场景的标准实战:行为日志清洗、会话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报表导出完成")
十二、业务解读与扩展方向
- 会话Session:30分钟是默认阈值,短视频、工具类产品可以改成15分钟;长内容阅读可改成60分钟
- 跳出率高:检查落地页加载、内容匹配度、广告素材是否货不对板
- 漏斗卡点:找到流失最高的环节做优化(比如提交到支付流失高,就是支付/优惠问题)
- 访问路径:发现用户偏好,做页面跳转、推荐位优化
- 进阶拓展:
- 页面停留时长分布、热力点击
- 用户分群(高活跃/低活跃用户)
- 行为序列马尔可夫链
- 和订单表关联,行为+成交联合分析
十三、高频坑清单
- 日志没有排序,直接分组计算session,session划分完全错乱
- 会话划分用全局时间差,忘记按user_id分组
- PV统计直接count,没有区分有效行为,埋点里过滤埋点自检、后台上报脏数据
- 漏斗统计混用session和user口径,指标口径不一致(优先统一用独立用户)
- 跳出定义混淆:不要把“只有一条行为”当成坏行为,部分场景用户就是只看首页
- 大埋点日志(千万级):必须分块读取、按日期分区,不要一次性加载全量日志
十四、速查表
| 分析场景 | Pandas核心方法 |
|---|---|
| 会话Session切割 | groupby + shift + 时间差 + cumsum |
| PV/UV | len / nunique |
| 跳出率 | 统计session内行为条数 |
| 转化漏斗 | 多条件筛选 + nunique |
| 访问路径 | groupby + join字符串 + value_counts |
| DAU | groupby 日期 + nunique(user_id) |
| 渠道质量对比 | 多表merge合并UV、会话、跳出率 |
0 条笔记