简介:这份数据分析笔试题资源包面向准备数据分析岗位笔试的求职者与在校学生,覆盖从统计基础到机器学习、大数据处理的完整知识链路,帮助读者在真实题目中检验数据清洗、建模与业务解读能力。包内共41个文件,以png图表、xlsx与xls数据表、docx文档为主,辅以gif动图、pptx演示、mp4录屏及htm说明,压缩包约54.78MB,涵盖SQL查询、分析报告、岗前测试与多套笔试真题等模块。资源中既有前海数据等企业的岗位笔试题,也有分年度、分行业的制造与批发数据图表,可对照练习缺失值处理、异常值识别、假设检验、可视化选型及线性回归、决策树等算法应用。目前已有818人学习下载,适合需要系统刷题、复盘解题思路并积累业务分析经验的中级学习者。
1. 数据分析笔试题:为什么 SQL 写对了,业务结论还是错的
很多人第一次做数据分析笔试题,都会掉进同一个坑:SQL 跑通了、Python 脚本没报错、图表也画出来了,但面试官看完只回一句“结论呢”。问题不在工具,在于笔试题考的不是语法,而是你能不能把一句模糊的业务问题翻译成可验证的分析路径。比如“最近三个月复购率下降的原因”,它背后藏着指标定义、口径对齐、维度拆解、异常归因四层动作,缺一层结论就站不住。这类题在数据运营、商业分析、增长策略岗的笔试里出现频率极高,适合已经会写基础查询、但一遇到开放题就不知道从哪下手的从业者。下面按我实际做题和带人的顺序,把整套流程拆开讲。
2. 拆解笔试题干:从一句话需求到可执行分析框架
2.1 先分清题目要的是描述、诊断还是预测
数据分析笔试题干通常分三类。描述型问“是什么”,比如“统计各渠道月度 GMV”;诊断型问“为什么”,比如“找出转化率下滑的主要环节”;预测型问“会怎样”,比如“预估下季度留存”。三类题的答题结构完全不同:描述型重口径和完整性,诊断型重假设和验证,预测型重特征和误差说明。拿到题先花三十秒判断类型,再决定后面写不写模型。我见过不少人一上来就上回归,结果题目只想要一个分组对比,反而显得不会抓重点。
判断方法很简单:题干里出现“下降/上升/异常/原因”就是诊断型,出现“预计/预估/趋势”就是预测型,出现“统计/汇总/分布”就是描述型。混合型题目按主问题定类型,次要问题用附注处理。
2.2 把业务词翻译成字段和口径
题干里的“活跃用户”“有效订单”“高价值客户”都不是天然存在的字段,需要你给出可执行定义。这一步是笔试拉开差距的地方。常见做法是先列一张口径对照表,把每个业务词映射到表、字段、过滤条件和时间窗口。
| 业务词 | 可执行定义 | 涉及字段 | 注意点 |
|---|---|---|---|
| 活跃用户 | 统计周期内至少一次登录 | user_id, login_time | 去重,排除内部账号 |
| 有效订单 | 支付成功且未全额退款 | order_id, pay_status, refund_amount | 部分退款是否剔除要写明 |
| 高价值客户 | 近90天消费额前20% | user_id, pay_amount | 分位数按全量还是分渠道 |
这张表不用写进最终答案,但一定要在草稿里过一遍。口径不清,后面所有数字都是空中楼阁。
2.3 用假设树把诊断型题目拆到可验证
诊断型题目最怕东查一下西查一下。我的习惯是先画假设树:根节点是现象,第一层按“量、价、频、人”拆,第二层按渠道、地区、品类、新老客拆,叶子节点必须是能直接用 SQL 验证的粒度。
-- 假设:复购率下降主要由新客首购后30天未复购导致 -- 按注册月份和新老客拆分复购率 SELECT DATE_TRUNC('month', u.register_time) AS register_month, CASE WHEN o.order_seq = 1 THEN '首购' ELSE '复购' END AS order_type, COUNT(DISTINCT o.user_id) AS buyer_cnt, COUNT(DISTINCT o.order_id) AS order_cnt FROM orders o JOIN users u ON o.user_id = u.user_id WHERE o.pay_status = 'success' AND o.pay_time >= '2024-01-01' GROUP BY 1, 2 ORDER BY 1, 2;这段查询的作用是把复购率按注册月份和订单序号拆开,看下降是集中在某一批新客还是全体用户。order_seq是订单序号,需要在子查询里用窗口函数生成;DATE_TRUNC的粒度按题目要求换成周或日。跑完先看绝对值,再看环比,最后看结构占比,三步下来基本能定位到具体人群。
3. SQL 与 Python 双线作答:笔试现场怎么分配时间
3.1 SQL 部分:先保证口径正确,再追求写法优雅
笔试里的 SQL 题通常限时,我的策略是先用最直白的写法把结果跑出来,再考虑优化。窗口函数、CTE、子查询都能解题,但现场优先选自己不容易写错的。比如算留存,用自连接比用窗口函数更稳,虽然代码长一点,但逻辑一眼能看懂。
-- 计算次日留存:先取每日新增,再关联次日活跃 WITH new_users AS ( SELECT user_id, MIN(DATE(login_time)) AS first_day FROM login_log GROUP BY user_id ), next_day_active AS ( SELECT DISTINCT user_id, DATE(login_time) AS active_day FROM login_log ) SELECT n.first_day, COUNT(DISTINCT n.user_id) AS new_cnt, COUNT(DISTINCT a.user_id) AS retained_cnt, ROUND(COUNT(DISTINCT a.user_id) * 1.0 / COUNT(DISTINCT n.user_id), 4) AS retention_rate FROM new_users n LEFT JOIN next_day_active a ON n.user_id = a.user_id AND a.active_day = DATE_ADD(n.first_day, INTERVAL 1 DAY) GROUP BY n.first_day ORDER BY n.first_day;MIN(DATE(login_time))取每个用户首次登录日,LEFT JOIN保证没有次日活跃的用户也计入分母。DATE_ADD的间隔按题目要求改成 1、3、7、30。注意COUNT(DISTINCT)在关联后可能重复计数,所以分子分母都要去重。
3.2 Python 部分:pandas 处理脏数据的三板斧
笔试给的数据集往往有缺失、重复、格式混乱。pandas 里我固定用三步:先看形状和类型,再处理缺失和重复,最后做分组聚合。不要一上来就dropna(),先统计缺失比例,超过 30% 的列要考虑是否保留。
import pandas as pd df = pd.read_csv('orders.csv') # 第一步:体检 print(df.shape) print(df.dtypes) print(df.isnull().mean().sort_values(ascending=False).head(10)) # 第二步:清洗 df = df.drop_duplicates(subset=['order_id']) df['pay_amount'] = pd.to_numeric(df['pay_amount'], errors='coerce') df = df[df['pay_amount'].notna() & (df['pay_amount'] > 0)] # 第三步:聚合 result = (df.groupby(['channel', pd.Grouper(key='pay_time', freq='M')]) .agg(order_cnt=('order_id', 'nunique'), gmv=('pay_amount', 'sum'), buyer_cnt=('user_id', 'nunique')) .reset_index()) result['arpu'] = result['gmv'] / result['buyer_cnt'] print(result.head())errors='coerce'把无法转换的值变成 NaN,避免整列报错。pd.Grouper按月聚合时要求pay_time是 datetime 类型,读入后要先用pd.to_datetime转换。nunique去重计数,sum求和,最后算 ARPU 时注意分母是买家数不是订单数。
3.3 图表只画能支撑结论的那一张
笔试如果要求出图,不要堆图表。诊断型题目画一张趋势图加一张结构拆解图就够了。趋势图看整体走向,结构图看哪个维度贡献了变化。用 matplotlib 时把标题、轴标签、单位写全,面试官不用猜。
import matplotlib.pyplot as plt fig, axes = plt.subplots(1, 2, figsize=(12, 4)) result.groupby('pay_time')['gmv'].sum().plot(ax=axes[0], title='月度GMV趋势') result.groupby('channel')['gmv'].sum().plot(kind='bar', ax=axes[1], title='渠道GMV分布') axes[0].set_ylabel('GMV') axes[1].set_ylabel('GMV') plt.tight_layout() plt.show()左图看趋势是否下降,右图看是哪个渠道拖累。如果右图某一根柱子明显变短,结论就落到那个渠道上,再回去查该渠道的转化漏斗。
4. 避坑:数据分析笔试题里最容易翻车的五个地方
现象:SQL 跑出来行数对不上。原因:多表关联时一对多导致膨胀,或者WHERE里对右表字段过滤把LEFT JOIN变成了INNER JOIN。解决:关联前先确认粒度,右表过滤条件写到ON里而不是WHERE里,聚合前用COUNT(DISTINCT)验证。
现象:留存率算出来大于 1。原因:分子分母口径不一致,分子用了全量活跃用户,分母只用了新增用户。解决:分子必须从分母同一批用户里取,用LEFT JOIN或IN子查询限定用户范围。
现象:Python 分组结果和 SQL 对不上。原因:时间字段时区不一致,或者 pandas 读入时把日期解析成了字符串。解决:统一用 UTC 或业务时区,读入时显式指定parse_dates,分组前打印dtypes确认。
现象:结论写了“建议加强运营”这种空话。原因:没有落到具体维度和动作。解决:结论必须包含“哪个群体、哪个环节、预期影响多少”,比如“新客首购后 7 天内未复购占比上升 12%,建议对这批人做首购后第 3 天触达”。
现象:时间不够,最后一题没写完。原因:在前面的清洗和探索上花太久。解决:笔试先扫一遍所有题,按分值分配时间,SQL 题控制在 40% 以内,Python 和结论各占 30%,留 10% 检查口径。
5. 从笔试到实战:把一次作答变成可复用的分析模板
笔试和实际工作的差别在于,笔试有标准答案,工作没有。但两者共用同一套底层能力:定义问题、拆解假设、验证结论、给出动作。我后来把笔试里反复用到的结构固化成一个模板,遇到新问题直接往里填。
模板分四块:第一块是问题定义,写清楚现象、时间范围、涉及指标;第二块是口径表,把每个业务词映射到字段和过滤条件;第三块是验证路径,按假设树列出要跑的查询和预期结果;第四块是结论与建议,每条结论必须附上数据支撑和下一步动作。
# 可复用的分析模板骨架 analysis = { 'problem': '复购率下降', 'period': '2024-01 至 2024-03', 'metrics': { 'repurchase_rate': '近90天复购用户数 / 近90天购买用户数', 'new_buyer_retention': '首购后30天内再次购买用户数 / 首购用户数' }, 'hypotheses': [ '新客首购后触达不足', '某渠道用户质量下降', '促销活动导致一次性购买增加' ], 'validation': [], 'conclusion': [] }这个骨架的好处是,每填一个字段都在逼自己把模糊想法变具体。hypotheses列表里的每一条都要能对应到一个 SQL 或 pandas 查询,跑完把结果填进validation,最后从验证结果里提炼conclusion。我现在的习惯是,任何分析任务先花十分钟把这个字典写出来,再动手写代码。写不出来说明问题还没想清楚,这时候敲键盘只是浪费时间。
还有一个技巧是反向验证:结论出来后,假设这个结论是错的,去找一个能推翻它的查询。如果找不到,结论才站得住。比如你说是渠道问题,那就把该渠道剔除后重算整体指标,看下降是否消失。这个动作在笔试里能加分,在实际工作里能救命。
最后说一个我自己的教训。早期做笔试题总想展示技术,窗口函数、复杂 CTE、机器学习模型全往上堆,结果面试官只关心“所以呢”。后来我改成先写一句结论,再用数据证明,反而通过率高了。分析的价值不在代码多漂亮,在于能不能让看的人做决定。希望帮到你。
本文还有配套的精品资源,点击获取