ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Pandas面试题核心考点:索引对齐、缺失值清洗与表连接

Pandas面试题核心考点:索引对齐、缺失值清洗与表连接

简介:面向数据分析岗位求职者和 Python 开发者,这份 Pandas 面试题 PDF 系统整理了 60 道高频面试题,按基础、中级、高级分层,覆盖 Series 与 DataFrame 的创建读取、条件筛选、排序合并、缺失值处理、分组聚合、透视表、时间序列、SQL 交互及内存优化等核心主题,并涉及 iterrows 遍历、MultiIndex 多级索引、cut/qcut 分箱、rolling 窗口计算、正则表达式、数据分块读取等进阶内容。每题均配有可运行的代码示例与简洁说明,便于按需查阅和对照练习,也能帮助读者系统回顾常见考点,作为日常工作时的快速参考。资源为单个 PDF 文件,压缩包约 263KB,轻量便携,内容组织清晰,既可从头通读建立知识框架,也可按题号快速定位薄弱环节。已有 1288 人学习使用,是备战数据分析面试、提升 Pandas 应用水平的实用资料。

1. Pandas面试题.pdf 在筛的不只是代码:一道数据题能看出你会不会处理脏数据

准备数据岗位面试的人,手上多半都存过一份“Pandas面试题.pdf”。真正到了面试现场,你会发现很多题目并不要求你写出惊艳算法,而是给你一张“看起来有点脏”的表:有空值、有重复行、有类型不一致的列,然后问你几个操作能不能一次写对。别小看这种题,它考察的是你对 Pandas 索引逻辑、缺失值语义和表连接的熟练度,这些恰恰是平时用 ChatGPT 补答案最容易漏掉的部分。

很多候选人刷题时喜欢过题面、背输出,却很少注意每一步代码背后 Pandas 到底怎么对齐索引、怎么决定保留哪些行。真到写代码环节,一执行就报错,或者结果跟预想悄悄不一样。这份 PDF 真正筛选的是:你能不能在脱离快捷键和文档的情况下,把一个包含缺失值、重复值、乱序索引的 DataFrame 处理成结构规整的可用数据。适合读这篇文章的人,是准备校招或社招数据类岗位、想快速掌握 Pandas 核心操作的从业者,也适合那些已经有 Python 基础、却总在 merge 和 fillna 上翻车的人。

下面我从面试题的常见分类讲起,再给你一组“可以直接复制到本地跑”的练习数据,最后把高频踩坑点和自测方法一次说清。

2. Pandas面试题.pdf 的三类核心考点:索引对齐、缺失值清洗、表连接

Pandas 题目看起来五花八门,但把大量真题汇总在一起看,出题人反复在三个地方做文章:索引与切片、缺失值和类型、分组聚合与表连接。这三类能力几乎覆盖了面试里 80% 的动手题。你与其逐题背答案,不如先把这三个底层逻辑吃透。

2.1 索引与切片:会读代码和真会写代码的差别

Pandas 的索引与普通列表索引完全不同,这是面试最容易暴露问题的地方。列表的索引只有一种,就是整数下标;DataFrame 的索引却可能包含数值、字符串、时间戳,甚至重复值。当你写df.loc[3]时,Pandas 找的是索引标签为 3 的行,而不是“第 4 行”;而df.iloc[3]找的才是物理位置上的第 4 行。

很多候选人在理解这一步时没有形成系统概念,导致后续的切片、条件筛选、赋值全跟着错。我建议你刷题时先建立一个判断顺序:先问自己操作对象是行还是列,再问是按标签取还是按下标取,最后再想返回的是视图还是副本。这本 PDF 中大量题目其实都在反复变着法子考这个判断顺序。

索引对齐是更深一层的问题。两个 Series 做加法时,Pandas 不关心谁在上谁在下,它按照索引标签一一配对,配对不上的位置就填 NaN。这个特性让 Pandas 在连接数据时很方便,但也让很多从 Excel 转过来的人不习惯:明明两个表行数一样,加起来却多出一堆空值。面试题经常给两个结构相似的数据表,问合并结果的行数和缺失值位置,考的就是你对索引对齐的敏感度。

import pandas as pd s1 = pd.Series([100, 200, 300], index=["a", "b", "c"]) s2 = pd.Series([10, 20, 30], index=["b", "c", "d"]) print(s1 + s2)

这段代码的输出里,a 和 d 的对应位置都是 NaN,因为两个 Series 只在 b、c 两个索引上有共同标签。理解了这个行为,你再去读 PDF 里的表对齐题目就会轻松很多。索引对齐是 Pandas 最基本也最容易被忽略的行为,建议你把它当成面试前必须自己动手验证的第一个实验。

2.2 缺失值与类型清洗:面试里最日常也最拉分的模块

真实业务数据很难做到完全没有缺失值,所以 Pandas 面试题中清洗类题目一定不会少。最常见的是isna()、dropna()、fillna()三个函数的组合使用。但很多人只知道“遇到空值就用 fillna”,却不知道 Pandas 对 NaN 的语义判断、不同填充方式对后续统计结果的影响。

要特别注意:fillna(0)会把整个列统一填成 0,但这在业务上并不总是合理的。数值列可以补中位数或均值,分类列可能更适合补“未知”或“缺失”,时间列则经常需要前向填充。面试官要听的不是你会不会调用 fillna,而是你有没有“按列类型选择缺失值处理策略”的意识。刷题时看到一个缺失值题,先别急着写代码,先说你会补什么值、为什么用这个值,然后再动手。

类型问题往往和缺失值纠缠在一起。比如某列本身是整数,但因为存在 NaN,Pandas 读取后会自动变成 float。如果你在面试中直接对这个列做字符串拼接或者等值判断,结果会不符合预期。还有astype()的滥用也很常见,有的题目要求把订单编号转成字符串,但编号列如果有缺失值,直接astype(str)会把 NaN 变成字符串"nan",这又是另一种隐患。

我在实际项目里处理这类问题时的习惯是:先跑一次df.info()和df.isna().sum(),把每一列的类型和缺失数量列成一张表,再决定清洗方案。面试现场没有这么多时间,但你至少要内心形成一个判断链:这一列做什么用、缺失值占比多少、能不能删、该填什么。把这个逻辑讲清楚,比闷头写对代码更能让面试官认可。

2.3 分组、聚合与表连接:三题里至少出一道

如果面试题只能选一个方向重点考察,那大概率是分组聚合和表连接。因为这部分最贴近真实数据分析场景:订单表按地区汇总、用户表关联消费记录、透视表做交叉统计。groupby、merge、concat 三个操作几乎是所有 Pandas 面试题的高频题眼。

groupby 常见的坑是看不懂返回对象到底是什么。df.groupby("city")返回的不是一个 DataFrame,而是一个 GroupBy 对象;你必须接着调用agg()、sum()、transform()等方法才能得到结果。不同聚合方法返回的结构也不一样,agg()通常得到以分组列为索引的 DataFrame,transform()则保留原始行数。很多题目会让你比较这两者的输出形状,这其实是考察你对“行数变化”的理解。

表连接的难点在于连接键的选择和连接方式。merge()按列的值匹配,适合有明确外键关系的表;concat()更偏向按轴拼接,行数直接堆叠或者列横向扩展。面试题里常考两个细节:一是merge()中left_on和right_on的使用场景,二是连接时索引的索引是否作为连接键参与匹配。把这两点梳理清楚,基本就能应对大多数表连接题目。

# groupby 与 merge 的典型组合场景 result = df.groupby("city", as_index=False)["amount"].sum() print(result)

这里的as_index=False可以让分组列保留为普通数据列,而不是变成索引。很多考生不知道这个参数,导致结果出来后要额外reset_index()才能继续用。面试时如果能把这一步讲明白,说明你不是单纯背代码,而是真的理解 groupby 的输出结构。

3. 把 Pandas面试题.pdf 刷成肌肉记忆:本地可复制的数据样例与核心操作组

光看知识点不够,必须亲手跑。我为你准备了一份非常接近面试真题的数据样例,你不需要联网,也不需要找额外数据文件,直接在本地新建一个 Python 文件粘贴运行就可以。这份样例包含两个表,一张是订单表,一张是客户表,结构简单但把高频考点都埋进去了。

3.1 先造一份能“踩坑”的模拟数据

数据里故意安排了缺失订单金额、缺失客户编号、重复订单记录、不同列类型等面试官最喜欢设置的障碍。你要是能把这组数据处理得干净利落,面试中遇到的类似题就都不怕了。

import pandas as pd import numpy as np # 第一张表:订单表,注意里面有重复订单和缺失值 orders = pd.DataFrame({ "order_id": ["A001", "A002", "A002", "A003", "A004", "A005"], "customer_id": ["C01", "C02", "C02", "C01", "C03", np.nan], "amount": [120, 85, 65, np.nan, 45, 90], "category": ["数码", "食品", "食品", "服装", np.nan, "图书"] }) # 第二张表:客户表,关联订单表用 customers = pd.DataFrame({ "customer_id": ["C01", "C02", "C03", "C04"], "city": ["上海", "北京", "广州", "深圳"], "level": ["老客", "新客", "老客", "新客"] }) print(orders) print(customers)

订单表里有订单号重复、金额缺失、分类缺失、客户编号缺失四类问题。客户表结构相对规整,但多了订单表里没有的 C04 客户。两张表放在一起,覆盖了缺失值判断、去重、类型转换、表连接时 on 字段不一致等常见考点。

你在练习时不要只是复制运行,建议先自己看一眼这两张表,心里回答三个问题:哪个列适合做主键、哪几行需要清洗、两表连接后哪些客户会被丢掉。带着这三个问题往下走,练习效率会高很多。

3.2 筛选、去重、缺失值清洗:高频基础操作的完整连招

基础操作在面试里通常不会单独出题,而是作为后续统计的前置步骤出现。这里我把最常用的筛选、去重、缺失值处理写在一个代码块里,每一行都标了注释,方便你对照理解。

# 第一步:查看缺失值分布,这是清洗前的标准动作 print(orders.isna().sum()) # 第二步:按订单号去重,保留第一条记录 orders_clean = orders.drop_duplicates(subset=["order_id"], keep="first") # 第三步:金额缺失的订单,用整张表金额的中位数填充 median_amount = orders_clean["amount"].median() orders_clean.loc[orders_clean["amount"].isna(), "amount"] = median_amount # 第四步:分类缺失的订单,统一填“未知” orders_clean["category"] = orders_clean["category"].fillna("未知") # 第五步:客户编号缺失且无法补全的行,直接删除 orders_clean = orders_clean.dropna(subset=["customer_id"]) # 最后确认类型 print(orders_clean.info())

第一步先用isna().sum()确认每一列缺多少个,不是为了好看,而是让你在填充前知道数据现状。第二步去重时我指定了subset,只按订单号判断,keep="first"表示保留第一条;如果不写 subset,Pandas 会要求整行所有列都重复才算重复行,这在实战中往往会漏掉同一个人多次下单的重复数据。

第三步给金额列填中位数,要注意这里的小细节:先用.median()算好值再传入,而不是在 fillna 里直接写orders_clean["amount"].median(),因为后者可读性差一些,而且金额列此时的类型可能已经因为缺失值变成了 float,填充后全部变成小数,这在某些统计场景下需要额外处理。第四步和第五步分别用了 fillna 和 dropna,一个补分类,一个删掉无法补齐的客户编号,这也对应了前面讲的“按列特征选择不同清洗策略”的思路。

3.3 分组聚合与表连接:从数据到答案的完整闭环

基础清洗做完,接下来就是把两张表关联起来,做面试里最常考的统计分析。这里给出几种最常见的操作写法,每一种都有对应的输出结构,建议自己打印出来看一眼。

# 表连接:订单表关联客户表,保留订单表全部数据 merged = orders_clean.merge(customers, on="customer_id", how="left") print(merged) # 按城市汇总订单金额 city_summary = merged.groupby("city", as_index=False)["amount"].sum() print(city_summary) # 按城市和客户等级交叉统计:分组键不只一个 level_summary = merged.groupby(["city", "level"], as_index=False)["amount"].agg(["sum", "count"]) print(level_summary)

第一次连接时,how="left"表示以订单表为主表,客户表中匹配不到城市信息的订单会显示 NaN,这一行不会因连接而减少。按城市汇总时,如果城市里有 NaN,groupby 分组后也会出现一行 NaN 分组;要不要把它过滤掉,取决于面试题的具体要求。

最后交叉统计结果是一个多级索引的 DataFrame,行索引是城市和等级的组合。如果你不希望后续继续操作这个结果时被索引干扰,可以继续调用reset_index()把索引转回普通列。这里提醒一句:分组聚合题目最怕的不是不会写 groupby,而是不知道返回结果的索引结构,因为后续任何操作都依赖这个索引状态。你练习时尽量把“写完分组后自动打印一下结果结构”变成肌肉记忆。

4. Pandas 刷题常见坑:五个高频翻车点在面试前必须自查

刷 Pandas 面试题时最难受的不是不会做,而是代码没报错、结果却不对。这类问题往往是几个特定操作导致的系统性错误,我把它们放在一起做一个避坑清单,每一条都按“现象、原因、解决”整理,方便你面试前快速自查。

4.1 链式赋值后数据没改,还弹出一长串警告

很多人在条件筛选后直接对结果赋值,比如先取出所有订单金额大于 100 的记录,再对这一堆记录加一列备注。运行时 Pandas 弹出 SettingWithCopyWarning,而且原表里根本没有出现改动。这个现象很常见,原因是筛选操作可能返回的是一个视图或副本,赋值操作作用在临时对象上,没有真正写回原 DataFrame。

解决方法是放弃“筛选后再赋值”的二段式写法,直接用loc一步到位。

# 错误示范:先筛选后赋值,可能不生效 # temp = orders[orders["amount"] > 100] # temp["flag"] = "high" # 正确做法:直接定位到目标行 orders.loc[orders["amount"] > 100, "flag"] = "high"

loc的第一个参数是行筛选条件,第二个参数是列名,这样 Pandas 能准确定位到原 DataFrame 的存储位置,而不是对临时对象操作。面试时如果把这一步讲清楚,会显得你对 Pandas 内部引用机制有真实理解。

4.2 concat 拼接后索引全乱了,重复值莫名其妙变多

concat 和 merge 经常被混用,但两者的行为差异很大。concat 默认不重置索引,它只是把数据沿某个轴拼接起来,原来的索引会原样保留。两个都有 0、1、2 索引的表拼接后,新表也会有多个 0、1、2,这会让后续loc取值时匹配到多行,结果和预期不一样。

原因是你没有指定拼接后如何处理索引。解决方式是拼接时加上ignore_index=True,让 Pandas 重新生成一套连续索引;或者在拼接后手动调用reset_index(drop=True)。如果是按列拼接两个结构不同的表,还要注意axis=1的使用,避免把两张表错误地上下堆叠。

combined = pd.concat([orders_clean, customer_data], axis=0, ignore_index=True)

实际刷题时,看到题干里写“将两个表纵向合并”,第一反应就应该是concat而不是merge;看到“按某一列关联拼接”,再用merge。把这两个操作的使用边界分清楚,能省下很多排查时间。

4.3 fillna 之后数值列偷偷变成了小数,连等值判断都失效

订单金额列里如果原本存在 NaN,即使你后来用 fillna 填掉,这一列的 dtype 仍然是 float64,不是整数。有些题目会继续用amount == 65做过滤,明明表中有一条 65 元记录,筛选结果却是空的,这很容易让人误以为自己写错了条件。

原因是缺失值迫使 Pandas 在读取或构造数据时选择 float 类型,因为整数类型无法表示 NaN。解决方法是:如果你确实需要整数列,可以先把缺失值填掉,再显式用astype转换;或者使用 Pandas 提供的可空整数类型 Int64,它能同时容纳整数和缺失值。

orders_clean["amount"] = orders_clean["amount"].astype("Int64")

这里特别提醒:astype("int")在列中还有 NaN 时会直接报错,必须先填充再转换;astype("Int64")则允许保留缺失值,是处理“有空值的整数列”更实用的选择。这个细节在面试题中很常见,值得记牢。

4.4 apply 函数拿到的是行、列还是元素,经常被搞反

apply 是让很多人头疼的操作,问题往往出在函数签名与 axis 参数的配合上。axis=0时传入函数的是一整列数据,axis=1时传入函数的是一整行 Series。有人写了个接收两个参数的函数,却把 axis 设为 0,运行时直接包类型错误;还有人写 lambda 表达式按列名取值,却把 axis 设为 0,结果拿到的是某一列的全部数据而不是一行记录。

解决方式是先写好函数,再用一小段测试数据确认函数接收对象的形状。我常用的写法是让函数内部打印参数类型,跑一遍就知道传进来的是 Series 还是 DataFrame。

def calc(row): # 这里 row 是整行 Series,可以通过列名取字段 return row["amount"] * 0.9 if pd.notna(row["amount"]) else 0 orders_clean["discounted"] = orders_clean.apply(calc, axis=1)

使用axis=1时,自定义函数接收的是每一行数据,所以函数里的row["amount"]是取当前这一行的字段。如果面试题里让你“对每一行做某种计算”,优先用这种写法;如果题目是“对每一列做统计”,再把 axis 换成 0。

4.5 groupby 之后感觉像“失踪”的列,以及找不到 reset_index 的尴尬

groupby 默认会把分组的键列变成结果表的索引,如果分组键只有一列,你在结果表里可能看不到明确列出的分组名,只能用result.index才能访问。很多人急着取数据,却不知道结果表结构,导致后续合并或导入时报错。

要解决这个问题,最简单的办法是写分组时就用as_index=False,或者主动调用reset_index()。需要留意 reset_index 对多级索引的处理:分组键若不止一个,reset_index 后会产生多个普通列,其中某些列名与原有数据列重叠,这时最好手动调整列名。

summary = orders_clean.groupby(["city", "category"], as_index=False)["amount"].sum()

用as_index=False后,分组键列直接保留为普通列,结果更直观。面试现场如果时间紧张,不用纠结哪种方式更优雅,能输出正确结构即可;但你要能说清楚as_index到底控制的是什么,这个细节经常被追问。

5. 把 Pandas面试题.pdf 刷成面试现场:一套可自我演练的三步自测法

题目刷够不等于面试能过,因为面试现场不让慢慢查文档,也不让反复试错。你需要一套自测方法,提前感受“即将答题”的状态,并且能通过结构化的方式发现自己的知识盲点。这里分享我常用的三步自测法,很适合拿任何一份 Pandas 面试题 PDF 来练习。

5.1 先扫盲还是先刷题:按时间和目标选路线

很多人拿到一份 PDF 后问“要不要先把每个知识点学一遍再做题”,我的建议取决于你离面试还有多久。如果还有半个月以上,功利性弱一点,先把索引、分组、连接三大模块理解到位,再开始刷题;如果只有两三天,直接做题,但不要追求刷完所有题,只做中等难度的动手题,每题保证能写出可运行代码和口水话解释。

刷题时一定要为自己准备一个“错题本”,不用记题目原文,只记三样东西:题目的考点、你写的报错代码、正确写法的关键步骤。这个错题本复习效果远好于反复重看整份 PDF。把时间花在真正容易错的地方,比盲目多刷十道题更有效。

5.2 一题三练:把一道基础题练出三种深度

我的习惯是:拿到一道题,不要做一遍就完,而是同一道题换三种方式练习。第一遍直接写答案跑通;第二遍故意不看参考代码,自己写一遍,同时边写边说每一步在做什么;第三遍改题目条件,比如把要求从“按城市汇总”改成“按城市和月份汇总”,看你能不能比较顺畅地调整代码。

这套方法的逻辑很简单:第一遍解决“会不会”的问题,第二遍解决“熟不熟”的问题,第三遍解决“能不能迁移”的问题。面试时面试官经常会临时加需求,比如“能不能再按客户等级细分一下”“这个金额能不能换成占比”,如果你只做过原题,加需求后容易卡壳。

# 第三遍练习示例:给之前的汇总加一个“金额占比”字段 city_summary = merged.groupby("city", as_index=False)["amount"].sum() city_summary["amount_ratio"] = city_summary["amount"] / city_summary["amount"].sum() print(city_summary)

这一步测试的是你能否在已有聚合结果之上继续做二次计算。很多人做到这里会想到用 transform 或 merge 回原表,但在这个场景下,直接在汇总表上算占比就够用了。学会判断“什么时候需要回原表、什么时候直接算结果”,是面试加分的体现。

5.3 构建“考点、真题、验证方法”对照表:自我检测的实用工具

刷题到后期,不建议再按 PDF 原顺序刷,而应该按考点自测。下面这张对照表可以帮你把做过的题目按考点归类,每一类用一段最小代码验证掌握程度。

考点如何自测验证方法
索引与切片不看文档写出 loc 和 iloc 的行列取值打印结果行数与预期一致
缺失值处理对带 NaN 的列分别用 fillna 和 dropna用 isna().sum() 对比处理前后
分组聚合用 groupby 汇总城市金额检查结果表的索引与行数
表连接用 merge 关联订单表和客户表检查连接后行数是否等于主表行数
类型转换把含 NaN 的整数列转为 Int64用 dtype 属性确认类型

这个表不要求你给每个考点挤出很高深的题目,关键是“验证方法”那一列要可执行。如果自测时发现某个考点没有明确验证手段,说明你还没完全理解这个知识点,需要回看对应章节或找同类题目再练练。

6. 面试最后十分钟:当面演示 groupby transform 的思考逻辑

面试末尾经常有一个“开放题”环节,面试官会给一个稍复杂的场景,比如:算每个分类的订单金额平均值,同时保留每一行的原始金额,然后判断每一行高于还是低于其所在分类的平均值。这类题听起来像难题,其实核心就是 groupby 加 transform 的组合使用。

很多人写这种题第一时间想的是先 groupby 出一个汇总表,再用 merge 把结果匹配回原表。这个思路没错,但代码更长,而且调试时容易因为连接后索引变化而出错。更直接的方式是用 transform,它会返回一个跟原表行数一致的 Series,不需要二次连接就能拿到每行所属分组的统计值。

# 计算每个订单金额与其所在分类平均值的差值 category_mean = orders_clean.groupby("category")["amount"].transform("mean") orders_clean["diff"] = orders_clean["amount"] - category_mean print(orders_clean[["order_id", "category", "amount", "diff"]])

transform 的关键特点是结果长度与原 DataFrame 完全相同,即使没有显式指定索引,Pandas 也会自动对齐到每一行。这与agg不同,agg返回的是以分组列为索引的压缩结果。面试时你不需要背概念,把这段代码写出来并解释 transform 为什么节省了一次 merge,面试官就能看出你对分组操作的掌握程度。

这个写法在真实项目中也非常实用。比如统计每个城市销售额、每个用户最近一次消费时间、每个商品类目的价格中位数,都需要把分组统计结果完整保留在明细表上。只要你能理解“transform 按行广播”这一点,以后遇到这类需求都可以直接上手。

我自己的习惯是:平时刷题多留意那些“代码短但思考路径长”的写法,比如 loc、merge、transform 这三类。每次做完题,刻意问自己一个问题:如果不用这个函数,还有没有其他方式能达到同样效果?能把两种完全不同的写法讲清楚,就不会再在面试现场被追问细节时慌神了。这里把我积累的这套练习思路整理出来,希望可以帮到正在准备 Pandas 面试的你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进