📖 本篇简介:本篇从 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、反连接、透视全部串起来。
文章回复
0 条公开回复