RSS
菜单
全部文章快讯开发科技深度热点

第 51 章 LeetCode pandas 题库精讲(一)

内容摘要

本篇从 LeetCode 官方 "Introduction to Pandas" 板块选 14 道入门题,覆盖 DataFrame 创建、形状探查、head/loc 筛选、新增列、去重、缺失值删除与填充、列重命名、类型转换、concat 拼接、pivot 透视、melt 反透视等最核心的日常操作。每道题按"题目概括 → 思路 → 带中文注释的参考答案 → 复杂度与考点"四步走,所有答案在本机 pandas 3.0.6 下实跑通过。前置知识是本系列第 02、03、05、06、07、08、11、12 章。学完后你可以直接在 LeetCode 上把 Introduction 板块刷到 100% 通过率。

📖 本篇简介:本篇从 LeetCode 官方 "Introduction to Pandas" 板块选 14 道入门题,覆盖 DataFrame 创建、形状探查、head/loc 筛选、新增列、去重、缺失值删除与填充、列重命名、类型转换、concat 拼接、pivot 透视、melt 反透视等最核心的日常操作。每道题按"题目概括 → 思路 → 带中文注释的参考答案 → 复杂度与考点"四步走,所有答案在本机 pandas 3.0.6 下实跑通过。前置知识是本系列第 02、03、05、06、07、08、11、12 章。学完后你可以直接在 LeetCode 上把 Introduction 板块刷到 100% 通过率。
这是系列第一次"用题目倒逼语法"。前面讲的是"pandas 能做什么",从本篇开始讲"判题系统到底怎么考你"。

目录

1. 写在前面

2. 题目总览表

3. 环境与作答约定

4. 2877 从二维列表创建 DataFrame

5. 2878 返回 DataFrame 的行列数

6. 2879 取出前 3 行

7. 2880 按条件筛选行并选列

8. 2881 新增一列 bonus

9. 2882 按邮箱去重

10. 2883 删除 name 缺失的行

11. 2884 将 salary 列翻倍

12. 2885 批量重命名列

13. 2886 将 grade 由 float 转 int

14. 2887 用 0 填充 quantity 缺失值

15. 2888 纵向拼接两张表

16. 2889 pivot 透视

17. 2890 melt 反透视

18. pandas 3.0 常见坑提示

19. 本章小结

20. 练习题


1. 写在前面

LeetCode 的 "Introduction to Pandas" 学习计划一共 15 道超简单题:给你一个 pd.DataFrame,让你写函数返回新的 pd.DataFrame。它的价值在于:① 强制函数式风格;② 覆盖日常 80% 的 pandas 操作;③ 判题严格,列名、行序、dtype 错一个都挂。本篇选 14 道(最后一道 Method Chaining 留作练习)。


2. 题目总览表

| 题号 | 题目(自己概括) | 核心考点 | 对应本系列章节 |

|------|------------------|----------|----------------|

| 2877 | 从二维列表构造 DataFrame | pd.DataFrame(...) 与 columns | 第 03 章 |

| 2878 | 返回 DataFrame 的形状 | .shape | 第 05 章 |

| 2879 | 取前 3 行 | .head(n) | 第 05 章 |

| 2880 | 按 id 筛选并取指定列 | loc[mask, cols] | 第 06 章 |

| 2881 | 派生新列 bonus = salary*2 | 列赋值 / 向量化 | 第 08、10 章 |

| 2882 | 按邮箱去重 | drop_duplicates(subset=...) | 第 07 章 |

| 2883 | 删除 name 为缺失值的行 | dropna(subset=...) | 第 07 章 |

| 2884 | 把 salary 列翻倍 | 列级向量化运算 | 第 08 章 |

| 2885 | 批量改列名 | df.rename(columns={...}) | 第 03 章 |

| 2886 | grade 列 float→int | .astype(int) | 第 08 章 |

| 2887 | quantity 缺失填 0 | .fillna(0) | 第 07 章 |

| 2888 | 两张表纵向拼接 | pd.concat([...]) | 第 11 章 |

| 2889 | 月 × 城市透视温度 | df.pivot(...) | 第 12 章 |

| 2890 | 季度列 melt 成长表 | df.melt(...) | 第 12 章 |


3. 环境与作答约定

本机实跑环境:Windows / Python 3.14.7 / pandas 3.0.6 / numpy 2.5.3。函数签名保留 LeetCode 风格(入参/出参都是 DataFrame),不要 print、不要写文件。pandas 3.0 默认开启 Copy-on-Write,下面这些写法在 3.0 下都安全;如果你在旧版上看到 SettingWithCopyWarning,那是旧行为,3.0 起默认不再触发。

import pandas as pd, numpy as np
from typing import List
print("pandas", pd.__version__)
pandas 3.0.6

4. 2877 从二维列表创建 DataFrame

题目概括:给你二维列表 student_data,每行是 [student_id, age]。返回两列 DataFrame,列名固定为 student_id 和 age。

思路:把二维列表塞进 pd.DataFrame,用 columns= 指定列名。

from typing import List
import pandas as pd

def create_dataframe(student_data: List[List[int]]) -> pd.DataFrame:
    # columns 指定列名;行索引由 pandas 自动生成
    return pd.DataFrame(student_data, columns=["student_id", "age"])

print(create_dataframe([[1,15],[2,11],[3,11],[4,20]]))
   student_id  age
0           1   15
1           2   11
2           3   11
3           4   20

复杂度与考点:O(n)。从原生 Python 构造 DataFrame,对应第 03 章。漏写 columns= 会让列名变成 0、1,判题直接挂。


5. 2878 返回 DataFrame 的行列数

题目概括:给你一个 DataFrame,返回它的形状(行数、列数),要求是一个 Python list。

思路:.shape 直接给出 (行数, 列数) 元组,转 list 即可。

from typing import List
import pandas as pd

def getDataframeSize(players: pd.DataFrame) -> List[int]:
    # .shape 返回 (n_rows, n_cols) 元组;list(...) 转成 LeetCode 要的列表
    return list(players.shape)

print(getDataframeSize(pd.DataFrame({"a":[1,2,3,4], "b":[10,20,30,40]})))
[4, 2]

复杂度与考点:O(1),.shape 是预计算属性,对应第 05 章。不要用 len(df),那只给行数。


6. 2879 取出前 3 行

题目概括:给你一个员工表,返回它的前 3 行(按原始顺序)。

思路:.head(3) 就是干这个的,比 iloc[:3] 更语义化。

import pandas as pd

def selectFirstRows(employees: pd.DataFrame) -> pd.DataFrame:
    # head(n) 取前 n 行;不传参默认 5 行
    return employees.head(3)

emp = pd.DataFrame({"employee_id":[1,2,3,4,5],
                    "name":["Ann","Bob","Cat","Dan","Eve"],
                    "age":[20,21,22,23,24]})
print(selectFirstRows(emp))
   employee_id name  age
0            1  Ann   20
1            2  Bob   21
2            3  Cat   22

复杂度与考点:O(1)(视图),对应第 05 章。pandas 3.0 CoW 下后续修改不会污染原表。


7. 2880 按条件筛选行并选列

题目概括:学生表有 student_id / name / age。选出 student_id == 101 的那一行,只保留 name 和 age 两列。

思路:布尔掩码选行,列名列表选列,一行 loc 搞定。

import pandas as pd

def selectData(students: pd.DataFrame) -> pd.DataFrame:
    # loc[行掩码, 列名列表]:同时完成"选行 + 选列"
    return students.loc[students["student_id"] == 101, ["name", "age"]]

students = pd.DataFrame({"student_id":[101,53,128,3],
                         "name":["Ulysses","William","Henry","Henry"],
                         "age":[13,10,6,11]})
print(selectData(students))
      name  age
0  Ulysses   13

复杂度与考点:O(n)。考点是布尔索引 + loc 二维选择,对应第 06 章。常见错误是 df[mask]["name","age"]——外层方括号会把 ["name","age"] 当成元组 key,直接 KeyError。永远用 loc。


8. 2881 新增一列 bonus

题目概括:员工表有 name、salary。新增一列 bonus,值为 salary * 2。

思路:直接列赋值,pandas 自动向量化,不要写 for 循环。

import pandas as pd

def bonusColumn(employees: pd.DataFrame) -> pd.DataFrame:
    # 整列向量化乘法;pandas 3.0 CoW 下无 SettingWithCopyWarning
    employees["bonus"] = employees["salary"] * 2
    return employees

print(bonusColumn(pd.DataFrame({"name":["Piper","Grace"], "salary":[4548,3456]})))
    name  salary  bonus
0  Piper    4548   9096
1  Grace    3456   6912

复杂度与考点:O(n)。考点是"派生列",对应第 08、10 章。更函数式的写法是 employees.assign(bonus=employees["salary"]*2)。


9. 2882 按邮箱去重

题目概括:客户表里同一个 email 可能出现多次,保留每个邮箱第一次出现的行。

思路:drop_duplicates(subset=["email"]) 默认 keep="first",正好是题目要的。

import pandas as pd

def dropDuplicateEmails(customers: pd.DataFrame) -> pd.DataFrame:
    # subset 指定按哪些列判重;keep="first" 是默认值
    return customers.drop_duplicates(subset=["email"])

cust = pd.DataFrame({"customer_id":[1,2,3,4,5,6],
                     "name":["Ella","David","Zachary","Alice","Finn","Violet"],
                     "email":["emily@x.com","michael@x.com","sarah@x.com",
                              "john@x.com","john@x.com","alice@x.com"]})
print(dropDuplicateEmails(cust))
   customer_id     name                email
0            1     Ella    emily@example.com
1            2    David  michael@example.com
2            3  Zachary    sarah@example.com
3            4    Alice           john@example.com
5            6   Violet      alice@example.com

复杂度与考点:O(n)。考点是 drop_duplicates 与 subset,对应第 07 章。subset 不填就按整行判重,语义不同。


10. 2883 删除 name 缺失的行

题目概括:学生表 name 列可能有 NaN,把 name 缺失的行整行删掉。

思路:dropna(subset=["name"]) 只看 name 这一列。

import pandas as pd, numpy as np

def dropMissingData(students: pd.DataFrame) -> pd.DataFrame:
    # subset 限定只检查 name 列
    return students.dropna(subset=["name"])

s = pd.DataFrame({"student_id":[321,21,321,52,123,222],
                  "name":["Anna","Bob",np.nan,"Alex",np.nan,"Jean"],
                  "age":[17,np.nan,np.nan,18,17,17]})
print(dropMissingData(s))
   student_id  name   age
0         321  Anna  17.0
1          21   Bob   NaN
3          52  Alex  18.0
5         222  Jean  17.0

复杂度与考点:O(n)。考点是 dropna 与 subset,对应第 07 章。注意 age 列因为混进 NaN 自动升成了 float64。


11. 2884 将 salary 列翻倍

题目概括:把员工表 salary 列全部乘以 2。

思路:和第 8 题类似,但这次是改原列而不是加新列。

import pandas as pd

def modifySalaryColumn(employees: pd.DataFrame) -> pd.DataFrame:
    # pandas 3.0 下无 inplace 版本,直接赋值即可
    employees["salary"] = employees["salary"] * 2
    return employees

e = pd.DataFrame({"name":["Jack","Piper","Mia","Ulysses"],
                  "salary":[12966,74954,85060,77395]})
print(modifySalaryColumn(e))
      name  salary
0     Jack   25932
1    Piper  149908
2      Mia  170120
3  Ulysses  154790

复杂度与考点:O(n)。考点是列级向量化赋值,对应第 08 章。pandas 3.0 已弃用 df["salary"].mul(2, inplace=True),统一写成 df["salary"] *= 2。


12. 2885 批量重命名列

题目概括:列名 id / first / last / age 改成 student_id / first_name / last_name / age_in_years。

思路:df.rename(columns={旧名: 新名, ...}) 一次搞定,比手动改 df.columns=[...] 安全。

import pandas as pd

def renameColumns(students: pd.DataFrame) -> pd.DataFrame:
    # columns 传 {旧列名: 新列名} 字典;未提到的列保持不变
    return students.rename(columns={
        "id": "student_id", "first": "first_name",
        "last": "last_name", "age": "age_in_years",
    })

s = pd.DataFrame({"id":[1,2,3,4,5],
                  "first":["Mason","Ava","Taylor","Georgia","Thomas"],
                  "last":["King","Wright","Hall","Thompson","Moore"],
                  "age":[6,6,6,10,8]})
print(renameColumns(s))
   student_id first_name last_name  age_in_years
0           1      Mason      King             6
1           2        Ava    Wright             6
2           3     Taylor      Hall             6
3           4    Georgia  Thompson            10
4           5      Thomas      Moore             8

复杂度与考点:O(列数)。考点是 rename 字典映射,对应第 03 章。


13. 2886 将 grade 由 float 转 int

题目概括:grade 列是 4.0 / 9.0 这种浮点值,转成真正的整数类型。

思路:.astype(int)。如果列里有 NaN,先 dropna 或 fillna 再转。

import pandas as pd

def changeDatatype(students: pd.DataFrame) -> pd.DataFrame:
    # astype(int) 把 4.0 变成 4;有 NaN 会抛 IntCastingNaNError
    students["grade"] = students["grade"].astype(int)
    return students

out = changeDatatype(pd.DataFrame({"student_id":[1,2], "name":["A","B"],
                                  "age":[11,12], "grade":[4.0,9.0]}))
print(out, "\ngrade dtype =", out["grade"].dtype)
   student_id name  age  grade
0           1    A   11      4
1           2    B   12      9
grade dtype = int64

复杂度与考点:O(n)。考点是 astype 类型转换,对应第 08 章。


14. 2887 用 0 填充 quantity 缺失值

题目概括:商品表 quantity 列有缺失值,把所有缺失位置填 0,其它列不动。

思路:.fillna(0) 只作用于被选中的那一列。

import pandas as pd

def fillMissingValues(products: pd.DataFrame) -> pd.DataFrame:
    # 只对 quantity 列 fillna;整表 fillna(0) 会误伤 price 等列
    products["quantity"] = products["quantity"].fillna(0)
    return products

p = pd.DataFrame({"name":["Apple","Banana","Orange","Pineapple"],
                  "quantity":[150,None,34,None],
                  "price":[25.0,4.5,10.8,12.0]})
print(fillMissingValues(p))
        name  quantity  price
0      Apple     150.0   25.0
1     Banana       0.0    4.5
2     Orange      34.0   10.8
3  Pineapple       0.0   12.0

复杂度与考点:O(n)。考点是 fillna,对应第 07 章。填充后 quantity 仍是 float64,想变 int 要再 .astype(int)。


15. 2888 纵向拼接两张表

题目概括:两张结构相同的学生表 df1、df2,纵向堆成一张表,行索引从 0 重新开始。

思路:pd.concat([df1, df2], ignore_index=True),ignore_index=True 是关键。

import pandas as pd

def concatenateTables(df1: pd.DataFrame, df2: pd.DataFrame) -> pd.DataFrame:
    # axis=0 是默认值(纵向拼);ignore_index=True 重新生成 0..n-1 索引
    return pd.concat([df1, df2], ignore_index=True)

t1 = pd.DataFrame({"student_id":[1,2,3,4],
                   "name":["Mason","Ava","Taylor","Georgia"], "age":[6,6,6,10]})
t2 = pd.DataFrame({"student_id":[5,6], "name":["Leo","Alex"], "age":[7,7]})
print(concatenateTables(t1, t2))
   student_id     name  age
0           1    Mason    6
1           2      Ava    6
2           3   Taylor    6
3           4  Georgia   10
4           5      Leo    7
5           6     Alex    7

复杂度与考点:O(n+m)。考点是 pd.concat 纵向拼接,对应第 11 章。concat 按列名对齐,列名不一致会产生 NaN。


16. 2889 pivot 透视

题目概括:天气长表每行 (city, month, temperature)。透视为宽表:行索引是 month,列是 city,单元格是 temperature。

思路:df.pivot(index="month", columns="city", values="temperature")。

import pandas as pd

def pivotTable(weather: pd.DataFrame) -> pd.DataFrame:
    # index 当行,columns 当列,values 填值;要求每个 (index, columns) 唯一
    return weather.pivot(index="month", columns="city", values="temperature")

w = pd.DataFrame({"city":["Jacksonville"]*5 + ["ElPaso"]*5,
                  "month":[1,2,3,4,5]*2,
                  "temperature":[13,23,34,43,50,20,22,32,43,38]})
print(pivotTable(w))
city    ElPaso  Jacksonville
month
1           20            13
2           22            23
3           32            34
4           43            43
5           38            50

复杂度与考点:O(n)。考点是 pivot 长转宽,对应第 12 章。若 (month, city) 重复出现,pivot 会报 ValueError,改用 pivot_table(..., aggfunc="mean")。


17. 2890 melt 反透视

题目概括:销售宽表列为 product / Q1 / Q2 / Q3 / Q4。反透视为长表 (product, quarter, sales)。

思路:df.melt(id_vars=["product"], var_name="quarter", value_name="sales")。

import pandas as pd

def meltTable(report: pd.DataFrame) -> pd.DataFrame:
    # id_vars 保留不动;其它列被"堆"成长表
    return report.melt(id_vars=["product"], var_name="quarter", value_name="sales")

r = pd.DataFrame({"product":["Umbrella","SleepingBag","PhoneCase","RoadBike"],
                  "Q1":[417,800,700,600], "Q2":[224,900,700,750],
                  "Q3":[379,0,300,850], "Q4":[611,500,900,550]})
print(meltTable(r).head(8))
      product quarter  sales
0   Umbrella      Q1    417
1  SleepingBag      Q1    800
2    PhoneCase      Q1    700
3    RoadBike      Q1    600
4   Umbrella      Q2    224
5  SleepingBag      Q2    900
6    PhoneCase      Q2    700
7    RoadBike      Q2    750

复杂度与考点:O(行列乘积)。考点是 melt 宽转长,对应第 12 章。pivot 与 melt 互为逆操作:宽表给人看,长表给 groupby。


18. pandas 3.0 常见坑提示

⚠️ 坑 1:字符串列 dtype。pandas 3.0 起字符串列默认 dtype 是 "str" 而非 object。打印 df.dtypes 看到 str 不是环境坏了。
⚠️ 坑 2:`inplace=True` 几乎被移除。df.dropna(inplace=True)、df.rename(..., inplace=True) 在 3.0 下弃用或报错,统一写成 df = df.dropna(subset=["name"])。
⚠️ 坑 3:链式赋值警告默认关闭。pandas < 3.0 时 df[df.x>0]["y"] = 1 会触发 SettingWithCopyWarning;3.0 默认 CoW 下警告关闭。但不要因此写链式赋值——可读性差、语义模糊。
⚠️ 坑 4:`df.append`、`pd.Series.append`、`df.lookup`、`df.iteritems` 都已删除。老 StackOverflow 答案里看到这些 API,直接换 pd.concat 等新写法。

19. 本章小结

| 操作类别 | 一句口诀 | 核心 API |

|----------|----------|----------|

| 创建 | 给二维列表加 columns 就是 DataFrame | pd.DataFrame(..., columns=...) |

| 形状 | .shape 是元组 | list(df.shape) |

| 看前几行 | head | df.head(3) |

| 选行选列 | 永远用 loc[mask, cols] | df.loc[...] |

| 派生列 | 向量化赋值 | df["new"] = df["a"] * 2 |

| 去重 | 按列去重 | drop_duplicates(subset=...) |

| 缺失值 | 删 / 填 | dropna(subset=...) / fillna(0) |

| 重命名 | 字典映射 | rename(columns={...}) |

| 类型转换 | astype | astype(int) |

| 拼接 | 纵向 concat | pd.concat([...], ignore_index=True) |

| 长转宽 | pivot | df.pivot(...) |

| 宽转长 | melt | df.melt(id_vars=...) |

这 14 道题覆盖了 LeetCode Introduction 板块的几乎所有考点。刷完它们,你就完成了从"会写 pandas"到"能在判题系统上 AC pandas 题"的第一步。


20. 练习题

1. (对应 2877)给定二维列表 [[1, "A"], [2, "B"]],构造列名为 id / letter 的 DataFrame,并打印它的形状。

2. (对应 2882 + 2887 综合)订单表 orders(order_id, customer_id, amount),amount 可能为 NaN。请:① 按 order_id 去重;② 把 amount 的 NaN 填 0;③ 返回结果。

3. (对应 2889)把天气表 (city, month, temperature) 透视为"行是 city、列是 month"的宽表,与 2889 有什么不同?

4. (对应 2890)手上有宽表 (user, Jan, Feb, Mar),请 melt 成长表 (user, month, login_days),并按 user 排序。

5. (对应 2886 + 2884)salary 列是 float,里面可能有 NaN。请把 NaN 填 0 后转成 int,再整体乘以 1.1 作为"涨薪后薪资"。

6. (Method Chaining,即 2891)把第 9、10、11 题的操作串成一行链式调用:先按 email 去重 → 删 name 缺失 → salary 翻倍 → 返回。


下一篇预告:第 52 章 LeetCode pandas 题库精讲(二) —— 14 道 SQL↔pandas 经典题,从 Big Countries 到 Employees With Missing Information,把 groupby、merge、反连接、透视全部串起来。
— 全文完 —回到顶部 ↑
下载推广海报

文章推广海报

《第 51 章 LeetCode pandas 题库精讲(一)》完整推广海报
DISCUSSION

文章回复

0 条公开回复
未登录回复需要审核后公开
还没有回复,欢迎参与讨论。