📖 本篇简介:本篇是大厂数据岗面试的"业务重头戏":用 pandas 实现面试官最爱考的六类业务题——指标口径与计算(DAU/GMV/ARPU)、留存与漏斗、同比环比、AB 实验解读、异动归因、指标异动排查。每道题按"业务背景 → 题目 → 参考答案(带注释)→ 面试官追问"组织,并附指标口径速查表。前置知识:已掌握第 30 章的 API 与第 40 章的流程框架。学完后你能在面试中熟练拆解业务指标并用 pandas 快速落地。
大厂数据岗二面最常出现的模式:面试官抛一张业务表 + 一个业务问题("算一下这个活动的 DAU 变化"、"用户留存为什么掉了")。本篇把这六类题型一次讲透——口径先行、代码跟上、追问接得住。
目录
1. 业务题答题框架:口径 → 拆解 → 代码 → 验证
2. 题 1:DAU / GMV / ARPU 指标口径
3. 题 2:留存与回访计算
4. 题 3:转化漏斗与环节定位
5. 题 4:同比 / 环比 / 周环比
6. 题 5:AB 实验结果的业务解读
7. 题 6:指标异动归因(下钻)
8. 指标口径速查表
9. 本章小结与自测清单
1. 业务题答题框架:口径 → 拆解 → 代码 → 验证
业务题最怕"上来就写代码"。大厂面试官想听到的是:
def business_framework():
steps = [
"① 先确认口径:指标怎么定义?(DAU 按设备还是账号去重?GMV 含不含退款?)",
"② 再拆公式:目标 = 分子/分母,或 人数 × 人均 × 转化率;",
"③ 写代码:用 pandas 逐步实现,变量名即口径;",
"④ 验证:结果是否在合理范围?换个口径结果变多少?",
"⑤ 延伸:数据量大怎么办?指标下降如何归因?",
]
return steps
print("面试金句:'我先确认一下口径,DAU 的定义是……'")
print("这句话比任何一行代码都值钱。")
2. 题 1:DAU / GMV / ARPU 指标口径
业务背景
电商 App,给三张表:uv(每日活跃用户明细)、order(订单)、user_info(用户信息)。
题目
请用 pandas 计算 7 月的:DAU 日均、GMV 总量、ARPU(人均付费),并说明口径。
参考答案
import pandas as pd
import numpy as np
np.random.seed(2025)
# ---------- 模拟三张表 ----------
# uv 表:每次打开 App 记一行
uv = pd.DataFrame({
"date": np.random.choice(pd.date_range("2026-07-01", "2026-07-31", freq="D"), 200000),
"user_id": np.random.randint(1, 50000, 200000),
"device_id": np.random.randint(100000, 200000, 200000),
})
# order 表:每笔订单一行
order = pd.DataFrame({
"date": np.random.choice(pd.date_range("2026-07-01", "2026-07-31", freq="D"), 30000),
"user_id": np.random.randint(1, 50000, 30000),
"amount": np.round(np.random.uniform(10, 500, 30000), 2),
"status": np.random.choice(["paid", "refunded", "pending"], 30000,
p=[0.85, 0.05, 0.1]),
})
# ---------- ① DAU:每日去重用户数,再取平均 ----------
# 口径:同一用户一天内多次打开只算 1 个 DAU(按 user_id 去重)
daily_uv = uv.groupby("date")["user_id"].nunique()
dau_avg = daily_uv.mean()
print(f"7 月日均 DAU = {dau_avg:.0f}")
# ---------- ② GMV:成交订单金额合计 ----------
# 口径:GMV = 已支付订单金额合计(不含退款、不含未支付)
paid = order[order["status"] == "paid"]
gmv = paid["amount"].sum()
print(f"7 月 GMV = {gmv:,.0f} 元")
# ---------- ③ ARPU:总营收 / 活跃用户数 ----------
# 口径:ARPU = 期内总营收 ÷ 期内活跃用户数(含未付费用户)
active_users = uv["user_id"].nunique()
arpu = gmv / active_users
print(f"7 月 ARPU = {arpu:.2f} 元/人")
面试官追问
1. "ARPPU 和 ARPU 什么区别?" → ARPPU 只算付费用户(paid_users),ARPU 算全部活跃用户。指标口径混用是大厂大忌,一定要先问清。
2. "GMV 为什么不直接用订单表 sum?" → 订单含退款、未支付、刷单,要按 status 过滤,否则高估。
3. "DAU 按设备还是账号?" → 一账号多设备会高估、一设备多账号会低估,面试里给出选择并说明影响即可。
3. 题 2:留存与回访计算
题目
给 login 表(user_id, date),计算次日留存率:7 月 1 日新增用户里,有多少在 7 月 2 日又登录了?参考答案
import pandas as pd
import numpy as np
np.random.seed(3)
n = 100000
# ---------- 模拟登录流水 ----------
login = pd.DataFrame({
"date": np.random.choice(pd.date_range("2026-07-01", "2026-07-07", freq="D"), n),
"user_id": np.random.randint(1, 20000, n),
})
login["date"] = pd.to_datetime(login["date"])
# ---------- 口径:首次登录日 = 新增日 ----------
# 每个用户最早的登录日期作为"新增日"
first_login = login.groupby("user_id")["date"].min().rename("first_date")
df = login.merge(first_login, on="user_id")
# ---------- 计算次日留存 ----------
# 新增用户里,是否在 first_date + 1 天再次出现
df["is_day1"] = (df["date"] == df["first_date"] + pd.Timedelta(days=1)).astype(int)
# 按新增日分组:次日留存率 = 次日回来的人数 / 当日新增人数
retention = df.groupby("first_date").agg(
新增用户=("user_id", "nunique"),
次日回来=("is_day1", "sum"),
)
retention["次日留存率"] = retention["次日回来"] / retention["新增用户"]
print(retention.round(3))
面试官追问
1. "怎么算 7 日留存?" → is_day7 = (date == first_date + 7days),同理;留存曲线 = 对 D1/D3/D7/D30 分别算。
2. "新增用户里混着老用户怎么处理?" → 用首次登录日界定新增,保证每个用户只属于一个 Cohort(同期群)。
3. "留存下降可能是什么原因?" → 内容供给、推送触达、新用户 onboarding、版本回归、渠道质量变化——按这几个方向拆。
4. 题 3:转化漏斗与环节定位
题目
埋点表event(user_id, date, event_name)。事件链:view_home → view_detail → add_cart → pay。请计算每一步转化率并指出流失最重的环节。
参考答案
import pandas as pd
import numpy as np
np.random.seed(9)
events = ["view_home", "view_detail", "add_cart", "pay"]
ev = pd.DataFrame({
"date": np.random.choice(pd.date_range("2026-07-01", "2026-07-07", freq="D"), 80000),
"user_id": np.random.randint(1, 15000, 80000),
"event_name": np.random.choice(events, 80000, p=[0.5, 0.3, 0.13, 0.07]),
})
# ---------- 漏斗:每一步到达过的人数(去重) ----------
step_users = {}
for step in events:
step_users[step] = ev[ev["event_name"] == step]["user_id"].nunique()
funnel = pd.DataFrame({
"环节": list(step_users.keys()),
"人数": list(step_users.values()),
})
funnel["转化率"] = funnel["人数"] / funnel["人数"].shift(1)
funnel["总体转化率"] = funnel["人数"] / funnel["人数"].iloc[0]
print(funnel.round(3))
# 环节 人数 转化率 总体转化率
# 0 view_home 14939 NaN 1.000
# 1 view_detail 10682 0.715 0.715
# 2 add_cart 4860 0.455 0.325 <- 流失最重:详情→加购
# 3 pay 2649 0.545 0.177
# 结论:加购环节转化率 45.5%,是全链路最短的板
# 建议:看详情页跳失原因(价格/库存/竞品比价),加购按钮与信任要素优化
面试官追问
1. "漏斗能不能按渠道拆分看?" → groupby(渠道) 重复上述过程,对比渠道质量。
2. "怎么看多天窗口而不是单日?" → 拉长观察窗口,用户可能跨天转化,用"最后一次曝光后 N 天"归因。
3. "埋点漏采怎么兜底?" → 以支付流水为准反推上游,或用抽样校准。
5. 题 4:同比 / 环比 / 周环比
题目
给每日 GMV,请计算:环比(vs 昨日)、同比(vs 去年同日)、周同比(vs 上周同日),并识别增长异常日。
参考答案
import pandas as pd
import numpy as np
np.random.seed(5)
dates = pd.date_range("2025-07-01", "2026-07-31", freq="D")
gmv = pd.Series(np.round(np.random.uniform(80, 120, len(dates)), 1),
index=dates, name="gmv")
# 转 DataFrame 方便操作
df = gmv.rename("gmv").to_frame()
# ---------- 环比:vs 前一天 ----------
df["环比"] = df["gmv"].pct_change()
# ---------- 同比:vs 去年同日(365 天前) ----------
df["去年同日"] = df["gmv"].shift(365)
df["同比"] = df["gmv"] / df["去年同日"] - 1
# ---------- 周同比:vs 上周同日(7 天前) ----------
df["上周同日"] = df["gmv"].shift(7)
df["周同比"] = df["gmv"] / df["上周同日"] - 1
# ---------- 只看最近 10 天 ----------
recent = df.tail(10)[["gmv", "环比", "同比", "周同比"]]
print(recent.round(3))
面试官追问
1. "环比和同比什么时候用哪个?" → 环比看短期波动(适合日常监控);同比消除季节性(节假日/大促要看同比);两者结合才完整。
2. "为什么我环比大涨但同比大跌?" → 去年同期的基数效应:先看绝对值再看比率。
3. "周期性业务(周末高、周一低)怎么办?" → 用周同比、7 日滚动均值,避免被日内/周内节奏干扰。
6. 题 5:AB 实验结果的业务解读
题目
实验数据:对照组/实验组各 1 万用户,转化率 8.2% vs 9.1%。请判断:这个提升是否可信?要不要全量?
参考答案
import pandas as pd
import numpy as np
from scipy import stats
# ---------- 数据 ----------
n_c, n_t = 10000, 10000
conv_c, conv_t = 0.082, 0.091
# ---------- 卡方检验 ----------
table = np.array([
[int(n_c * conv_c), n_c - int(n_c * conv_c)], # 对照组:转化/未转化
[int(n_t * conv_t), n_t - int(n_t * conv_t)], # 实验组
])
chi2, p_val, _, _ = stats.chi2_contingency(table)
print(f"卡方={chi2:.3f}, p={p_val:.4f}")
# ---------- 差异的置信区间 ----------
diff = conv_t - conv_c
se = np.sqrt(conv_c * (1 - conv_c) / n_c + conv_t * (1 - conv_t) / n_t)
ci = (diff - 1.96 * se, diff + 1.96 * se)
print(f"差异={diff:.3%}, 95%CI=[{ci[0]:.3%}, {ci[1]:.3%}]")
# ---------- 业务解读三连 ----------
print("① 统计显著性:p 值是否 < 0.05?", "显著" if p_val < 0.05 else "不显著")
print("② 业务显著性:+0.9pp 相对 +11%,对业务意味着多少营收增量?")
print("③ 稳健性:样本量够不够(功效)、有没有 AA 校准、指标有没有多重比较?")
面试官追问
1. "p 值 0.04 就一定能上线吗?" → 不一定:要看效应量、置信区间下界、长期指标(留存/复购)、新奇效应。
2. "两组用户没随机好怎么办?" → 先做 AA 测试/协变量平衡检验;随机化失败则分层随机或匹配。
3. "实验开了一周,转化率升了但客单价降了?" → 可能抢了高价用户,看整体 GMV,别单看一个指标。
7. 题 6:指标异动归因(下钻)
题目
7 月 20 日 DAU 突然下降 15%,请给出一套归因分析流程并用 pandas 实现第一步下钻。
参考答案
import pandas as pd
import numpy as np
np.random.seed(11)
n = 150000
# ---------- 模拟 7/15 ~ 7/22 的活跃数据 ----------
uv = pd.DataFrame({
"date": np.random.choice(pd.date_range("2026-07-15", "2026-07-22", freq="D"), n),
"user_id": np.random.randint(1, 40000, n),
"channel": np.random.choice(["自然", "广告", "推送", "外链"], n,
p=[0.4, 0.3, 0.2, 0.1]),
"app_version": np.random.choice(["v5.2", "v5.3", "v5.4"], n),
})
# ---------- 第一步:时间维度确认异常范围 ----------
daily = uv.groupby("date")["user_id"].nunique()
base = daily.loc["2026-07-15":"2026-07-19"].mean() # 基准:前 5 天均值
drop_day = daily["2026-07-20"]
print(f"基准 DAU={base:.0f}, 7/20={drop_day}, 降幅={(1 - drop_day/base):.1%}")
# ---------- 第二步:渠道下钻(哪个渠道在跌) ----------
# 对比 7/20 与基准期各渠道 DAU
base_ch = uv[uv["date"] < "2026-07-20"].groupby("channel")["user_id"].nunique()
d20_ch = uv[uv["date"] == "2026-07-20"].groupby("channel")["user_id"].nunique()
print("\n渠道降幅:")
print((1 - d20_ch / base_ch).round(2).sort_values(ascending=False))
# 广告渠道跌幅最大 -> 大概率是投放预算/素材问题
# ---------- 第三步:版本下钻(是否版本回归) ----------
base_ver = uv[uv["date"] < "2026-07-20"].groupby("app_version")["user_id"].nunique()
d20_ver = uv[uv["date"] == "2026-07-20"].groupby("app_version")["user_id"].nunique()
print("\n版本降幅:")
print((1 - d20_ver / base_ver).round(2).sort_values(ascending=False))
归因流程(背下来):确认异常 → 拆时间/渠道/版本/地区 → 看外部事件(竞品、政策、故障)→ 定位根因 → 验证(拉长窗口)→ 出结论与建议。
面试官追问
1. "渠道下钻发现广告暴跌,怎么进一步定位?" → 广告位/素材/出价/定向再下钻;查投放后台数据。
2. "如果所有渠道都在跌?" → 大概率是产品侧或大盘问题:查崩溃率、版本灰度、竞品动态。
3. "归因结论怎么验证?" → 拉长对比窗口、排除同期干扰事件、必要时做对照实验。
8. 指标口径速查表
| 指标 | 公式 | 常见口径坑 |
|------|------|-----------|
| DAU | 当日去重活跃用户数 | 按账号还是设备? |
| MAU | 当月去重活跃用户数 | 与 DAU 的月度去重不是简单相加 |
| GMV | Σ 已支付订单金额 | 含不含退款/取消/未支付? |
| ARPU | 总营收 ÷ 活跃用户 | 分母用 DAU 还是 MAU? |
| ARPPU | 总营收 ÷ 付费用户 | 与 ARPU 差一个"付费率" |
| 留存率 | D1/D7/D30 回来人数 ÷ 新增人数 | 新增如何定义?窗口如何对齐? |
| 转化率 | 达成目标人数 ÷ 进入环节人数 | 漏斗每层口径要一致 |
| 环比 | 本期 ÷ 上期 - 1 | 上期是否是异常期? |
| 同比 | 本期 ÷ 去年同期 - 1 | 闰年、节假日错位 |
| 复购率 | 购买 ≥2 次用户 ÷ 购买用户 | 周期内 vs 累计 |
9. 本章小结与自测清单
=== 本章核心 ===
1. 业务题先定口径再写代码,一句话"我先确认口径"价值千金;
2. 六类高频题:指标口径 / 留存 / 漏斗 / 同比环比 / AB解读 / 异动归因;
3. 漏斗找"最短的板",异动归因按"时间→渠道→版本→外部事件"下钻;
4. AB 实验要看显著性 + 效应量 + 长期指标,不唯 p 值论。
面试前自测清单:
- [ ] 能不能 1 分钟说清 DAU/GMV/ARPU/ARPPU 的口径差异?
- [ ] 能否现场写出次日留存率的 pandas 代码?
- [ ] 能否指出漏斗中"转化率最低环节"并给出两个优化方向?
- [ ] 环比、同比、周同比分别什么时候用?
- [ ] AB 实验拿到 p=0.03,你能说出三个"还不能全量"的理由?
- [ ] 指标暴跌,你能按顺序给出归因流程?
下一篇预告:第 42 章 大厂面试:SQL 与 pandas 双引擎与规模化 —— SQL ↔ pandas 对照、大数据量方案、生产环境工程素养。
文章回复
0 条公开回复