资讯动态

Pandas面试90题精讲:从DataFrame操作到性能优化全覆盖

发布时间:2026/10/15 9:55:07 来源:尧图企业网站定制
简介一份聚焦Pandas核心知识点的面试题库PDF面向数据分析岗位求职者、数据开发及准备Python/Pandas面试的读者覆盖从基础数据结构、DataFrame操作到高级性能优化、时间序列、MultiIndex等60个高频问题每题均配有答案与代码示例。文件为单个PDF文档共1个文件大小约263KB轻量便携适合离线刷题与考前冲刺。内容按基础、中级、高级及额外探讨分层组织既涉及常用方法与条件筛选、缺失值处理也包含cut/qcut、pivot_table与crosstab、窗口函数、内存优化、大型数据集分块处理等进阶技巧能帮助读者系统串联知识并提升实战分析能力。目前已有1288人浏览学习可作为面试冲刺题库也可作为日常Pandas使用的速查手册。1. 为什么这份 Pandas 面试题值得刷90 题覆盖了技能树上的哪些点做数据分析岗面试准备的人多半经历过这种尴尬Pandas 的 API 背了一堆真被问到 apply 和 transform 的区别、merge 时键重复会怎样、Category 类型省了多少内存还是会卡壳。这份 Pandas 面试题 PDF 整理了 90 道题按基础、中级、高级和额外探讨四层划分正好覆盖了从 DataFrame 增删改查到内存优化、窗口函数、分块读大文件这些一线高频场景。适合两类人准备面试时用它做自查清单的求职者以及带新人时需要现成题库的团队老手。我按自己的使用习惯把题目重新过了一遍下面把每层的重点、参数边界和坑位拆开讲你刷的时候能少走弯路。2. 基础题Series/DataFrame 的选型逻辑与高频操作边界这层 20 道题看着简单但恰恰是面试里最容易暴露基本功不扎实的地方。很多候选人会用 df.head()、df[列名]但被问到 loc 和 iloc 的区别、布尔索引的优先级、缺失值填充的 method 参数时就开始含糊了。2.1 先想清楚你手里的数据是一维还是二维第 1 题问 Pandas 的基本数据结构标准答案是 Series 和 DataFrame但如果只答这两个名字是不够的。实际工作中选型逻辑更重要一维的、带标签的序列用 Series比如某只股票连续 30 天的收盘价二维的、各列类型可以异构的表用 DataFrame比如订单表里订单号是字符串、金额是浮点数、下单时间是日期。import pandas as pd # 一维数据Seriesindex 就是标签 s pd.Series([10, 20, 30], index[a, b, c], namescore) # 二维异构数据DataFrame每列可以不同类型 df pd.DataFrame({ city: [北京, 上海, 广州], score: [88, 92, 79], date: [2024-01-01, 2024-01-02, 2024-01-03] }) # 读 CSV 时直接把日期列解析成 datetime省一步转换 df_from_csv pd.read_csv(sales.csv, parse_dates[date])逻辑说明Series 的 name 属性很多人忽略它在后面 reset_index() 或 join 时会影响列名。DataFrame 传 dict 创建时key 就是列名value 是列数据。read_csv 里 parse_dates 可以传列名列表也可以传列名和格式的字典比如parse_dates{date: [1, 2]}表示把第 1、2 列合并解析成日期。参数说明parse_dates 在文件很大时会拖慢读取速度但换来的是后续直接可以按时间排序、resample值不值看你场景。如果只是偶尔用日期列做筛选读完再 to_datetime 也不迟。2.2 筛选、排序与缺失值别再用链式赋值了第 4、5、6 题分别考选择列、条件筛选、排序。条件筛选最常用的是布尔索引但面试官想听的是 loc 和布尔索引配合的写法以及为什么不要用链式赋值。第 9 题缺失值处理dropna 和 fillna 都有隐藏参数。# 条件筛选三种写法效果接近但适用场景不同 mask df[score] 85 result1 df[mask] # 直接布尔索引简单直接 result2 df.loc[df[score] 85, [city, score]] # loc 同时控制行列 # query 写法适合条件表达式较长、列名带特殊字符的场景 result3 df.query(score 85 and city 北京) # 排序ascending 控制升降序na_position 决定缺失值放在哪头 df_sorted df.sort_values(byscore, ascendingFalse, na_positionlast)逻辑说明df[mask]只返回满足条件的行但如果后面接赋值操作就容易触发视图拷贝问题具体在第 5 章展开。df.loc[行条件, 列条件]是一个原子操作既能筛选行又能选列是推荐写法。query 内部的字符串表达式会被解析条件长的时候可读性比布尔变量拼接好但注意字符串里的引号规则。参数说明sort_values 的 by 参数支持传列名列表比如by[city, score]会先按城市排序再按分数排序。na_position 默认是 last即缺失值排最后这在 TopN 场景下很有用比如看销售榜单时 NaN 不应该出现在最前面。缺失值处理这块fillna 的 method 参数值得单独说# 前向填充缺失值用上一个有效值补上适合时间序列 df[price].fillna(methodffill, inplaceTrue) # 后向填充用下一个有效值补适合中间有个别缺失的情况 df[price].fillna(methodbfill, inplaceTrue)逻辑说明ffill 是 forward fill常用于股票价格、传感器数据这种按时间排序的场景缺失值默认沿用最近一个观测值。bfill 恰好反过来。注意新版 Pandas 里 method 参数有调整建议用df[price].ffill()这种独立方法兼容性更好。实际项目里先看缺失值占比超过一定阈值就别填充了直接考虑删列或换数据源。2.3 merge 和 groupbySQL 思维迁移时的关键差异第 7 题 merge、第 16 题 groupby、第 19 题透视表是基础层里最值钱的三道题。merge 的 how 参数要能脱口而出四种取值groupby 之后能干什么也要心里有数。orders pd.DataFrame({user_id: [1, 2, 3], amount: [100, 200, 300]}) users pd.DataFrame({user_id: [1, 2, 4], city: [北京, 上海, 深圳]}) # inner只保留两边都有的 user_idleft保留 orders 全部users 没有的填空 merged_inner pd.merge(orders, users, onuser_id, howinner) merged_left pd.merge(orders, users, onuser_id, howleft) # groupby 之后可以接 agg多个聚合一次算完 stats orders.groupby(user_id)[amount].agg([sum, mean, count]) print(stats)逻辑说明merge 的 on 参数指定连接键如果两边列名不同要用 left_on 和 right_on。how 的四种取值对应 SQL 的 inner、left outer、right outer、full outer这个类比面试官很认可。groupby 之后列的选择要用方括号接在 groupby 后面上面例子按 user_id 分组后只对 amount 列做聚合所以结果是分组键加 amount 的三个统计量。参数说明agg 可以同时传多个函数名结果列名默认是函数名想自定义列名可以传字典agg({amount: [sum, mean]})或agg(合计(amount, sum))。groupby 默认会把分组键变成索引加as_indexFalse可以让分组键保持为普通列这个细节在后续拼接多个结果时经常用到忘了的话容易踩坑。3. 中级题apply、时间序列与 MultiIndex 的完整链路第 21 到 40 题开始上强度。这一层考的不再是单函数用法而是组合能力apply 怎么处理行级运算、时间序列怎么走完 读取-转换-索引-聚合 的完整链路、MultiIndex 什么时候用得上。3.1 apply 家族map、apply、applymap 的边界再别搞混第 21、22、27 题都跟函数应用有关。map 只作用在 Series 上是一个元素到一个元素的映射apply 既可以作用在 Series 上默认对每个元素也可以作用在 DataFrame 上按行或按列跑函数applymap 作用于 DataFrame 的每一个元素。三者的返回值类型也不一样map 返回 Seriesapply 根据函数返回内容可能返回 Series 或 DataFrame。df pd.DataFrame({name: [alice, bob], score: [85, 92]}) # mapSeries 上做值到值的映射 df[grade] df[score].map(lambda x: A if x 90 else B) # apply对 Series 逐元素或对 DataFrame 按 axis 方向应用函数 df[score_plus] df[score].apply(lambda x: x 5) # applymap对整个 DataFrame 每个单元格生效新版中可被 apply 替代 df[[name]] df[[name]].applymap(lambda s: s.upper()) print(df)逻辑说明map 和 apply 在 Series 上很多时候可以互换但 map 更适合做字典映射比如把状态码映射成状态名。apply 的优势是函数可以写得复杂甚至返回多个值。applymap 在 Pandas 2.x 上调整为df.apply(lambda x: x.upper())也能实现但老版本兼容性还是 applymap 稳。面试时能说出 apply 配合 axis1 可以实现行级运算就已经赢过一半候选人了。参数说明apply 的 axis 参数默认 axis0表示对每列应用函数传入函数的参数是该列 Seriesaxis1 表示对每行应用函数传入的是该行 Series。按行跑函数通常比按列慢因为 Pandas 的行存储不连续数据量大时建议先 vectorize不行再考虑 apply。3.2 时间序列从字符串到 resample 的完整链路第 17、23、51 题围绕时间序列。第一步永远是 to_datetime 把字符串转成 datetime 类型第二步是 set_index 把日期列变成索引第三步才是 resample、rolling 这些时间操作。很多人上来就 resample 结果报错就是因为索引还不是 DatetimeIndex。df pd.DataFrame({ date: [2024-01-01, 2024-01-02, 2024-01-03], sales: [100, 120, 90] }) # 第一步字符串转 datetime df[date] pd.to_datetime(df[date]) # 第二步设为索引 df df.set_index(date) # 第三步按周聚合求和W 代表按周 weekly df[sales].resample(W).sum() print(weekly)逻辑说明resample 的规则字符串 W 是按周D 是按天M 是按月Q 是按季度。注意 resample 之后返回的是一个 Resampler 对象必须接 sum()、mean() 等聚合函数才出结果。如果数据里有缺失日期比如某天没记录resample 默认会补出缺失的天数但值是 NaN这时需要接 ffill() 或 bfill() 填充。参数说明to_datetime 的 errors 参数默认是 raise遇到无法解析的字符串直接报错改成 errorscoerce 会把非法日期变成 NaT不中断流程。这在清洗脏数据时非常实用但要注意 NaT 后面需要处理否则 groupby、pivot 时会出现一整组 NaN。3.3 数据重塑melt、pivot、stack/unstack 怎么选第 34、66、75 题都和数据重塑有关。宽表转长表用 melt长表转宽表用 pivot 或 pivot_tableMultiIndex 行列互换用 stack/unstack。选型逻辑很简单看目标表里哪部分是维度、哪部分是指标。wide pd.DataFrame({ city: [北京, 上海], 2023: [100, 90], 2024: [110, 95], }) # 宽转长year 列是年份value 列是销售额 long wide.melt(id_vars[city], var_nameyear, value_namesales) # 长转宽行是城市列是年份值是对应销售额 pivot long.pivot(indexcity, columnsyear, valuessales) print(pivot)逻辑说明melt 的 id_vars 指定保留不变的列var_name 是列名转换成新列后的名字value_name 是指标列的名字。pivot 的三个参数 index、columns、values 对应目标表的行维度、列维度、值。pivot 要求索引和列的组合没有重复一旦有重复会报错这时改用 pivot_table它内部做了 groupby 聚合不会报错。MultiIndex 在第 24、47、81 题里反复出现。它的本质是把多个列组合成一个层级化索引set_index 传列表就生成了 MultiIndex。stack/unstack 是在行索引和列索引之间移动层级unstack 把行索引里的层级转成列索引stack 是逆操作。实战中 MultiIndex 更适合做面板数据但日常用 pivot_table 就够了别为了炫技过度设计。4. 高级题内存、大文件与窗口函数的工程解法第 41 到 60 题是区分度最高的部分也是这份 PDF 最有价值的地方。这些题在真实项目里直接对应生产环境的性能问题面试官问这些就是想看候选人有没有处理过真实数据量。4.1 内存优化dtype 与 Categorical 的实际收益第 41、43、86 题考内存优化。核心思想只有一个Pandas 的 dtype 决定了每个元素占多少字节默认的 int64/float64 往往是大材小用。一个订单表几百万行把 int64 降到 int32 甚至 int8内存能省 50% 以上。df pd.read_csv(sales.csv) # 先看每列的类型和总内存占用 print(df.info(memory_usagedeep)) # 数值列按取值范围缩小 dtype df[age] df[age].astype(int8) # 低基数的字符串列转 category省内存还加速分组 df[region] df[region].astype(category) # 确认优化效果 print(df.info(memory_usagedeep))逻辑说明age 如果取值在 0-127 之间int8 够用比默认 int64 省 8 倍内存。region 如果只有几个城市名category 类型内部用整数编码存映射关系同样省内存而且在 groupby 时因为比较的是整数不是字符串速度也更快。info 里 memory_usagedeep 会统计对象内部嵌套的元素类型显示会更完整。参数说明Categorical 类型要留意两点。一是它是有序的或者无序的 category 概念如果城市名本身没有大小关系默认无序二是如果后续要加新类别必须通过df[region].cat.add_categories()添加直接赋值新城市名会报错。这个坑面试时经常被拿出来考为什么 category 列赋了新值会报错答案就是类别集合固定了。4.2 大文件与 SQL分块读取的工程姿势第 42、59、88 题都指向同一个场景文件太大内存装不下。标准答案是分块读取和逐块处理而不是一次性 load 进来。第 44 题考的是 read_sql和第 88 题的分块问题本质上是同一类工程思维。# chunk 方式每 10000 行一个块逐块过滤后合并 chunk_list [] for chunk in pd.read_csv(big.csv, chunksize10000, parse_dates[date]): # 每块先做过滤只保留有效数据减少后续合并压力 chunk chunk[chunk[amount] 0] chunk_list.append(chunk) # 合并所有块注意 ignore_index 避免索引重复 result pd.concat(chunk_list, ignore_indexTrue) print(result.shape)逻辑说明chunksize 指的是每个块的行数不是大小块太大内存还是会爆块太小 IO 次数增加。每块内部先做行过滤和列裁剪只保留后面需要的字段这样合并时的内存压力远小于先全量读入再处理。注意 pd.concat 里的 ignore_indexTrue否则每块的索引从 0 开始合并后索引全是重复的后续操作容易踩坑。参数说明read_csv 还有一个低内存模式参数 low_memory默认 True它在读大文件时用更省内存的方式解析但有时会导致类型推断不稳定。如果发现某列被推断成 object 而不是数字尝试设 low_memoryFalse代价是读取更慢、内存占用更高属于拿时间换准确性的取舍。4.3 窗口函数与自定义聚合复杂业务的两把刀第 46、49、57 题围绕聚合和窗口。窗口函数的核心是 rolling它和 groupby 的区别是groupby 是按分组整体聚合rolling 是滑动窗口聚合。股票计算 5 日均线就是典型的 rolling(5).mean()分组后的滚动需要先 groupby 再 rolling。s pd.Series([1, 2, 3, 4], indexpd.date_range(2024-01-01, periods4)) # 窗口为 2 的均值前两个值算一次往后滑动 print(s.rolling(2).mean()) # 自定义聚合函数去最大最小值后求均值类似 trimmed mean def trimmed_mean(x): return x[(x x.min()) and (x x.max())].mean() # 在 groupby 里用 agg 传自定义函数 stats df.groupby(city)[amount].agg([sum, trimmed_mean])逻辑说明rolling(2) 的窗口包含当前行和前一行的值第一行因为窗口不满 2 个值输出 NaN。自定义聚合函数接收的是一个 Series函数里只能做向量化操作不能对列名做引用因为传入的是数据本身。agg 传自定义函数名时结果列名就是函数名和内置 sum、mean 是同样的用法。参数说明rolling 的 min_periods 参数可以用来控制窗口内部最少需要多少个非空值才输出结果默认是窗口宽度。时间序列数据经常有缺失min_periods1 时只要窗口里有一个值就给结果虽然会偏低但至少不出现大片 NaN。这个参数面试时很少被直接问到但实际做 Slaes 预测的人都懂它的价值。5. 常见问题排查Pandas 刷题里最容易翻车的几个细节这一章把刷这 90 道题时最常遇到的运行时问题集中列一遍都是我在实际项目里踩过的。每一条按现象、原因、解决思路来写你刷题时遇到同样的报错可以直接对照。5.1 链式赋值触发 SettingWithCopyWarning现象执行df[df[score] 60][status] pass之后Pandas 弹出 SettingWithCopyWarning而且赋值的结果偶尔生效偶尔不生效。原因方括号筛选后返回的是一个对象可能是视图也可能是副本Pandas 为了性能默认按视图处理但进一步的链式赋值会让修改丢失或产生不可预期的行为。解决所有筛选后赋值的操作统一用.loc一步到位。# 错误写法 df[df[score] 60][status] pass # 正确写法loc 的左侧写行条件右侧写列名 df.loc[df[score] 60, status] pass从那以后我写筛选赋值只认这一种格式。这个警告不报错比报错更坑因为问题被隐藏了等到下游用数据发现值没变时排查成本已经很高。5.2 时区问题导致时间比较直接报错现象两个日期列分别来自不同数据源比较时抛出TypeError: Timestamp subtraction must have the same timezones或者结果全为 False。原因一个列是带时区的 tz-aware 类型另一个是不带时区的 tz-naive 类型Pandas 不允许直接比较。解决对齐时区要么全去掉时区要么全保留。# 统一去掉时区 ts_naive ts.tz_localize(None) # 或者统一设置到某个时区后保留 ts_aware ts.tz_localize(UTC).tz_convert(Asia/Shanghai)代码逻辑tz_localize(None) 是把带时区的时间转换为不带时区的本地时间注意这是直接移除时区信息不做时间换算。tz_localize(UTC) 是给没有时区的时间打上 UTC 标记tz_convert(Asia/Shanghai) 再做 8 小时偏移。两种方式都能让两列时间在相同时区体系下比较才可靠。5.3 merge 后行数暴增出现重复数据现象两个 DataFrame 按 id 合并后行数比两边都多得多而没有报错。这是merge 最容易忽略的行为。原因连接键在某一侧数据里不是唯一的重复值和另一侧匹配时产生笛卡尔积。比如订单表里一个用户有多条订单用户表里该用户只应该出现一次但如果用户表里也重复了合并后行数就会翻倍。解决合并前先检查键的唯一性必要时去重。用users[user_id].is_unique快速判断或者先看一下分组计数# 1. 判断键是否唯一 assert users[user_id].is_unique, user_id 在 users 表中存在重复 # 2. 有重复时先聚合再去合并而不是直接 merge users_dedup users.groupby(user_id).first().reset_index() merged pd.merge(orders, users_dedup, onuser_id, howleft)原因里多说一句merge 的 howleft 不会自动删重它忠实执行 SQL 语义。很多从 Excel 转过来的人在这里栽过跟头以为 left join 会保留左边全部行但如果右边键重复左边单行会被复制成多行。5.4 读 CSV 时前导零被自动吃掉现象读入订单号或手机号列发现 00123 变成了 123文本 ID 变成了数字。原因read_csv 的类型推断机制自动把这列识别成了 int64前导零在数值上无意义自然被丢弃。解决读入时直接指定 dtype把所有不参与运算的代码类列强制设成字符串。df pd.read_csv(orders.csv, dtype{order_id: string, phone: string})代码里 string 是 Pandas 的可空字符串类型比旧版的 str 更适配缺失值。凡是看起来像数字但实际不参与加减乘除的列比如 ID、邮编、证件号都应该在读取时显式声明为字符串。这个习惯能避免一大半数据清洗的返工。6. 额外 10 题能补什么两小时刷完后的自查方法这份 PDF 的额外探讨部分也就是第 81 到 90 题虽然只有 10 题却是性价比最高的一块。第 81 题是 MultiIndex 的数据筛选第 82 题是 loc 和 iloc 的区别第 84 题是快速找空值列第 85 题是大数据集分块处理第 87 题是时区处理第 88 题是分块读文件第 89 题是 eval 高效计算。这些题单独拎出来都不难但它们组合起来就是一个完整的数据预处理工作流。我建议拿到这份资源后按下面的路径自查两小时能走完一遍先花 40 分钟把基础题从头到尾口述一遍答案能说清楚为什么要这么写而不是只给结论。比如第 5 题条件筛选除了回答用布尔索引还要说为什么推荐 loc 配合布尔索引这个原因在第 5 章讲过了。再花 40 分钟对着中级题敲代码特别是时间序列的 resample 和 melt/pivot 的互转这两个方向最容易考代码题。剩下的时间主攻高级题的第 41、42、59 题把 dtype 优化和分块读取的脚本跑通。第 89 题 eval 值得单独拿出来讲一句。它的作用是让 Pandas 在内部做向量化运算减少 Python 层临时变量的创建在大 DataFrame 上做多列乘除时速度有肉眼可见的提升# 用 eval 一次算三列减少中间临时数组 df[total] df.eval(price * quantity * (1 - discount)) # query 里用 引用外部变量避免拼接字符串条件 threshold 100 subset df.query(total threshold)eval 的表达式里可以直接写列名做四则运算不用带 df. 前缀这是它和普通 DataFrame 运算最大的区别。query 里的 threshold 表示引用 Python 外部变量而不是列名。这两个配合起来筛选和计算都能在一行内完成代码可读性和性能同时在线。刷题这件事最怕的就是背答案背下来的东西换个场景就失效。这份 PDF 最好的用法是当自查清单每道题都能讲出为什么和什么时候用比能写出正确答案值钱得多。我自己的习惯是面试前把第 5 章那几个坑重新过一遍再把第 41、42 题的代码敲一遍这两个地方翻车率最高也是面试官最爱深挖的点。从那以后我每次接触新数据集第一件事永远是跑一遍df.info(memory_usagedeep)和df.isna().sum()这两个动作帮我避开了后面绝大多数的坑。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑