Appearance
Pandas 完整实战手册
导航目录
- 一、前言(用途、安装、导入惯例)
- 二、基础数据结构:Series、DataFrame
- 三、文件读写:csv、excel、txt、json
- 四、数据查看与基础信息
- 五、索引与选取:loc、iloc、[]、at、iat
- 六、数据筛选:条件过滤、多条件、isin、query、between
- 七、新增/修改/删除列:assign、drop、del、map、apply
- 八、缺失值处理:isna、fillna、dropna、interpolate
- 九、重复值:duplicated、drop_duplicates
- 十、数据类型转换:astype、to_numeric、to_datetime
- 十一、排序:sort_values、sort_index
- 十二、分组聚合:groupby、agg、transform、apply
- 十三、表连接:merge、concat、join、append
- 十四、透视表与交叉表:pivot_table、crosstab
- 十五、字符串处理:str 方法大全
- 十六、时间序列:dt 访问器、重采样 resample
- 十七、数据导出与优化:to_csv、to_excel、减少内存
- 十八、高频实战技巧(一行代码完成常用操作)
- 十九、常见坑与避坑指南
- 二十、结语
1. 前言(用途、安装、导入惯例)
1.1 Pandas 是什么
Pandas 是 Python 生态中最常用的数据处理库,适合做以下工作:
- 结构化数据清洗(缺失值、重复值、异常值)
- 表格数据分析(统计、分组、透视、时间序列)
- 多数据源读写(CSV/Excel/JSON/TXT)
- 特征工程前的数据准备
1.2 安装
bash
pip install pandas1.3 导入惯例
python
import pandas as pd关键注意点:
- 全文统一使用
import pandas as pd - 示例尽量用小数据集,便于理解和复现
2. 基础数据结构:Series、DataFrame
2.1 Series(一维带索引数组)
python
import pandas as pd
s = pd.Series([95, 88, 76], index=["张三", "李四", "王五"], name="score")
print(s)
# 输出解释:
# 张三 95
# 李四 88
# 王五 76
# Name: score, dtype: int64关键注意点:
Series= 值 + 索引- 可通过索引标签直接访问元素,如
s["张三"]
2.2 DataFrame(二维表格)
python
import pandas as pd
df = pd.DataFrame(
{
"name": ["张三", "李四", "王五"],
"age": [23, 25, 22],
"city": ["北京", "上海", "深圳"],
}
)
print(df)
# 输出解释:
# name age city
# 0 张三 23 北京
# 1 李四 25 上海
# 2 王五 22 深圳关键注意点:
DataFrame由行索引 + 列索引组成- 每一列本质上是一个
Series
3. 文件读写:csv、excel、txt、json
3.1 CSV 读写
python
import pandas as pd
df = pd.DataFrame({"name": ["A", "B"], "score": [90, 85]})
df.to_csv("students.csv", index=False)
df2 = pd.read_csv("students.csv")
print(df2)
# 输出解释:成功读取 CSV 文件内容3.2 Excel 读写
python
import pandas as pd
df = pd.DataFrame({"month": ["Jan", "Feb"], "sales": [100, 120]})
df.to_excel("sales.xlsx", index=False)
df2 = pd.read_excel("sales.xlsx")
print(df2)
# 输出解释:成功读取 Excel 内容3.3 TXT 读写(分隔符文本)
python
import pandas as pd
df = pd.DataFrame({"id": [1, 2], "value": [10, 20]})
df.to_csv("data.txt", sep="\t", index=False)
df2 = pd.read_csv("data.txt", sep="\t")
print(df2)
# 输出解释:按制表符分割读取成功3.4 JSON 读写
python
import pandas as pd
df = pd.DataFrame({"name": ["Tom", "Jerry"], "age": [20, 21]})
df.to_json("users.json", orient="records", force_ascii=False)
df2 = pd.read_json("users.json")
print(df2)
# 输出解释:读取 JSON 成功,得到 DataFrame关键注意点:
- 写文件建议
index=False,避免额外索引列 - JSON 常用
orient="records",更接近接口返回格式
4. 数据查看与基础信息:info、describe、head、tail、shape、dtypes
python
import pandas as pd
df = pd.DataFrame(
{"name": ["A", "B", "C"], "age": [20, 21, 22], "score": [88.5, 92.0, 79.5]}
)
print(df.head(2)) # 查看前 2 行
print(df.tail(2)) # 查看后 2 行
print(df.shape) # 输出解释:(3, 3) -> 3 行 3 列
print(df.dtypes) # 查看每列数据类型
print(df.info()) # 列信息 + 非空数量 + 内存
print(df.describe()) # 数值列统计摘要关键注意点:
info()是排查缺失值和类型问题的第一步describe()默认只统计数值列,可用include="all"查看全部列
5. 索引与选取:loc、iloc、[]、at、iat
python
import pandas as pd
df = pd.DataFrame(
{"name": ["A", "B", "C"], "score": [90, 85, 88]}, index=["s1", "s2", "s3"]
)
print(df["name"])
# 输出解释:取出单列,返回 Series
print(df.loc["s1"])
# 输出解释:按标签取行(s1)
print(df.iloc[0])
# 输出解释:按位置取第 0 行
print(df.at["s2", "score"])
# 输出解释:按标签快速取单个标量,返回 85
print(df.iat[2, 1])
# 输出解释:按位置快速取单个标量,返回 88关键注意点:
loc用标签,iloc用整数位置at/iat适合单值读写,速度更快
6. 数据筛选:条件过滤、多条件、isin、query、between
python
import pandas as pd
df = pd.DataFrame(
{
"name": ["A", "B", "C", "D"],
"age": [18, 25, 30, 22],
"city": ["北京", "上海", "北京", "深圳"],
"score": [70, 88, 95, 82],
}
)
print(df[df["age"] > 20])
# 输出解释:筛选年龄大于 20 的行
print(df[(df["age"] > 20) & (df["score"] >= 85)])
# 输出解释:多条件与(&)
print(df[df["city"].isin(["北京", "深圳"])])
# 输出解释:城市在给定列表中的行
print(df.query("age >= 22 and score >= 80"))
# 输出解释:query 写法更接近 SQL 条件表达式
print(df[df["score"].between(80, 90)])
# 输出解释:分数在 [80, 90] 区间内关键注意点:
- 多条件必须加括号:
(cond1) & (cond2) and/or不能直接用于 Series 条件,需用&/|
7. 新增/修改/删除列:assign、drop、del、map、apply
python
import pandas as pd
df = pd.DataFrame({"name": ["A", "B"], "score": [80, 95]})
df = df.assign(pass_flag=df["score"] >= 60)
# 输出解释:新增 pass_flag 列
df["level"] = df["score"].map(lambda x: "A" if x >= 90 else "B")
# 输出解释:map 用于逐元素映射
df["score2"] = df["score"].apply(lambda x: x + 5)
# 输出解释:apply 逐元素处理,得到新列
del df["score2"]
# 输出解释:删除列 score2
df = df.drop(columns=["pass_flag"])
# 输出解释:删除 pass_flag 列,返回新 DataFrame
print(df)关键注意点:
assign()链式调用友好map()常用于单列映射;apply()更灵活drop()默认返回新对象,若原地可用inplace=True
8. 缺失值处理:isna、fillna、dropna、interpolate
python
import pandas as pd
df = pd.DataFrame({"name": ["A", "B", "C"], "score": [90, None, 80], "age": [20, None, 22]})
print(df.isna())
# 输出解释:True 表示该位置是缺失值
print(df.fillna({"score": df["score"].mean(), "age": 0}))
# 输出解释:score 用均值填充,age 用 0 填充
print(df.dropna(subset=["score"]))
# 输出解释:删除 score 缺失的行
ts = pd.Series([1.0, None, None, 4.0])
print(ts.interpolate())
# 输出解释:线性插值 -> [1.0, 2.0, 3.0, 4.0]关键注意点:
- 先判断缺失比例,再决定“删”还是“补”
- 时间序列数据经常用
interpolate()
9. 重复值:duplicated、drop_duplicates
python
import pandas as pd
df = pd.DataFrame({"name": ["A", "A", "B"], "score": [90, 90, 80]})
print(df.duplicated())
# 输出解释:第 2 行是重复行 -> True
print(df.drop_duplicates())
# 输出解释:去重后只保留首次出现记录
print(df.drop_duplicates(subset=["name"], keep="last"))
# 输出解释:按 name 去重,保留最后一次出现关键注意点:
subset指定按哪些列判重keep=False可删除所有重复项(包括第一次)
10. 数据类型转换:astype、to_numeric、to_datetime
python
import pandas as pd
df = pd.DataFrame({"age": ["20", "21", "x"], "date": ["2026-01-01", "2026-01-02", "2026-01-03"]})
df["age_num"] = pd.to_numeric(df["age"], errors="coerce")
# 输出解释:无法转换的 "x" 变为 NaN
df["date"] = pd.to_datetime(df["date"])
# 输出解释:date 列变成 datetime64[ns]
df["age_int"] = df["age_num"].fillna(0).astype("int64")
# 输出解释:先填补 NaN,再转换整数
print(df.dtypes)关键注意点:
errors="coerce"是清洗脏数据的常见手法- 整数列含 NaN 时,不能直接转
int64
11. 排序:sort_values、sort_index
python
import pandas as pd
df = pd.DataFrame({"name": ["A", "B", "C"], "score": [88, 95, 88]}, index=[2, 0, 1])
print(df.sort_values(by="score", ascending=False))
# 输出解释:按 score 降序排序
print(df.sort_values(by=["score", "name"], ascending=[False, True]))
# 输出解释:先按 score,再按 name 排序
print(df.sort_index())
# 输出解释:按行索引升序关键注意点:
- 多列排序时,
ascending可传列表 sort_index(axis=1)可按列名排序
12. 分组聚合:groupby、agg、transform、apply
python
import pandas as pd
df = pd.DataFrame(
{
"dept": ["技术", "技术", "销售", "销售"],
"name": ["A", "B", "C", "D"],
"salary": [12000, 15000, 9000, 11000],
}
)
print(df.groupby("dept")["salary"].mean())
# 输出解释:按部门求平均工资
print(df.groupby("dept").agg(avg_salary=("salary", "mean"), max_salary=("salary", "max")))
# 输出解释:一次聚合多个指标
df["dept_avg"] = df.groupby("dept")["salary"].transform("mean")
# 输出解释:transform 返回与原表等长结果,可直接回填新列
result = df.groupby("dept").apply(lambda g: g.nlargest(1, "salary"))
print(result)
# 输出解释:每个部门取工资最高的一行关键注意点:
agg适合“汇总表”transform适合“回写原表”apply灵活但通常更慢,优先考虑向量化/内建聚合
13. 表连接:merge、concat、join、append
python
import pandas as pd
left = pd.DataFrame({"id": [1, 2, 3], "name": ["A", "B", "C"]})
right = pd.DataFrame({"id": [2, 3, 4], "score": [80, 90, 85]})
print(pd.merge(left, right, on="id", how="inner"))
# 输出解释:内连接,只保留 id=2,3
print(pd.merge(left, right, on="id", how="left"))
# 输出解释:左连接,以 left 为主
df1 = pd.DataFrame({"a": [1, 2]})
df2 = pd.DataFrame({"a": [3, 4]})
print(pd.concat([df1, df2], axis=0, ignore_index=True))
# 输出解释:纵向拼接,重置索引
left_i = left.set_index("id")
right_i = right.set_index("id")
print(left_i.join(right_i, how="left"))
# 输出解释:基于索引 join关键注意点:
append已不推荐,使用pd.concat- 连接后注意检查行数变化,防止一对多导致数据膨胀
14. 透视表与交叉表:pivot_table、crosstab
python
import pandas as pd
df = pd.DataFrame(
{
"city": ["北京", "北京", "上海", "上海"],
"gender": ["男", "女", "男", "女"],
"sales": [100, 120, 90, 130],
}
)
pt = pd.pivot_table(df, index="city", columns="gender", values="sales", aggfunc="mean")
print(pt)
# 输出解释:按城市和性别统计平均销售额
ct = pd.crosstab(df["city"], df["gender"])
print(ct)
# 输出解释:城市 * 性别 的频数统计表关键注意点:
pivot_table支持聚合,pivot不支持重复键crosstab(..., normalize="index")可计算行占比
15. 字符串处理:str 方法大全
python
import pandas as pd
s = pd.Series([" Alice_01 ", "Bob_02", "Cathy_03"])
print(s.str.strip())
# 输出解释:去除首尾空格
print(s.str.lower())
# 输出解释:转小写
print(s.str.replace("_", "-"))
# 输出解释:替换字符
print(s.str.split("_", expand=True))
# 输出解释:按 "_" 拆分为多列
print(s.str.contains("Bob"))
# 输出解释:是否包含子串 Bob
print(s.str.extract(r"([A-Za-z]+)_(\d+)"))
# 输出解释:正则提取名字和编号关键注意点:
- 字符串列存在缺失值时,许多
str方法会返回 NaN - 正则处理优先使用
extract/contains/replace
16. 时间序列:dt 访问器、重采样 resample
python
import pandas as pd
df = pd.DataFrame(
{
"date": pd.to_datetime(["2026-01-01", "2026-01-02", "2026-01-08", "2026-01-09"]),
"value": [10, 12, 15, 13],
}
)
df["year"] = df["date"].dt.year
df["weekday"] = df["date"].dt.day_name()
print(df[["date", "year", "weekday"]])
# 输出解释:dt 访问器提取日期特征
ts = df.set_index("date")
print(ts.resample("W")["value"].mean())
# 输出解释:按周重采样并计算均值关键注意点:
- 使用
resample前,索引必须是DatetimeIndex - 常见频率:
D日、W周、M月、Q季、Y年
17. 数据导出与优化:to_csv、to_excel、减少内存
17.1 导出数据
python
import pandas as pd
df = pd.DataFrame({"name": ["A", "B"], "score": [90, 85]})
df.to_csv("result.csv", index=False, encoding="utf-8-sig")
df.to_excel("result.xlsx", index=False)
# 输出解释:生成 CSV 和 Excel 文件17.2 内存优化示例
python
import pandas as pd
df = pd.DataFrame(
{
"id": [1, 2, 3],
"score": [100, 90, 80],
"city": ["北京", "上海", "北京"],
}
)
print(df.memory_usage(deep=True))
# 输出解释:查看每列内存占用
df["id"] = df["id"].astype("int32")
df["score"] = df["score"].astype("int16")
df["city"] = df["city"].astype("category")
print(df.dtypes)
# 输出解释:整数降位 + 分类类型可减少内存关键注意点:
- 大表优先优化整数/浮点类型位宽
- 低基数字符串列可转
category
18. 高频实战技巧(一行代码完成常用操作)
python
import pandas as pd
df = pd.DataFrame(
{
"name": ["A", "B", "C", "D"],
"score": [90, 75, 88, 92],
"city": ["北京", "上海", "北京", "深圳"],
}
)
top3 = df.nlargest(3, "score") # 分数 Top3
city_count = df["city"].value_counts() # 城市频次
has_null = df.isna().any().any() # 是否存在缺失值
renamed = df.rename(columns={"score": "final_score"}) # 重命名列
unique_city = df["city"].nunique() # 不重复城市数
score_rank = df["score"].rank(method="dense", ascending=False) # 密集排名
print(top3)
print(city_count)
print(has_null)
print(renamed.head(1))
print(unique_city)
print(score_rank)
# 输出解释:以上是一行即可完成的高频分析操作关键注意点:
- 掌握
nlargest/value_counts/rank/rename/nunique能显著提升效率 - 对大数据优先使用向量化方法,少写 Python 循环
19. 常见坑与避坑指南
19.1 链式赋值警告(SettingWithCopyWarning)
python
import pandas as pd
df = pd.DataFrame({"score": [60, 90, 75]})
sub = df[df["score"] >= 80]
sub.loc[:, "level"] = "A" # 推荐写法:明确 loc
print(sub)
# 输出解释:避免不明确的链式赋值关键注意点:
- 尽量使用
df.loc[行条件, 列名] = 值进行赋值
19.2 布尔条件优先级错误
python
import pandas as pd
df = pd.DataFrame({"a": [1, 2, 3], "b": [3, 2, 1]})
ok = df[(df["a"] > 1) & (df["b"] < 3)] # 每个条件都加括号
print(ok)
# 输出解释:正确筛选出满足复合条件的行关键注意点:
- 直接写
df["a"] > 1 & df["b"] < 3会出错或结果错误
19.3 datetime 未转换导致 dt 报错
python
import pandas as pd
df = pd.DataFrame({"date": ["2026-01-01", "2026-01-02"]})
df["date"] = pd.to_datetime(df["date"])
print(df["date"].dt.month)
# 输出解释:必须先转 datetime 才能使用 dt关键注意点:
- 时间处理前统一
pd.to_datetime
19.4 merge 后行数异常膨胀
python
import pandas as pd
left = pd.DataFrame({"id": [1, 1], "x": [10, 20]})
right = pd.DataFrame({"id": [1, 1], "y": [100, 200]})
merged = pd.merge(left, right, on="id", how="inner")
print(merged)
# 输出解释:一对多/多对多会产生笛卡尔扩张关键注意点:
- 连接前先检查键是否唯一:
df["key"].is_unique - 必要时先
drop_duplicates再连接
19.5 读写中文乱码
python
import pandas as pd
df = pd.DataFrame({"城市": ["北京", "上海"]})
df.to_csv("cn.csv", index=False, encoding="utf-8-sig")
df2 = pd.read_csv("cn.csv", encoding="utf-8-sig")
print(df2)
# 输出解释:使用 utf-8-sig 可减少 Excel 打开乱码问题关键注意点:
- 团队内统一编码规范,优先
utf-8/utf-8-sig
结语
掌握本手册中的核心 API 后,你已经具备了完整的 Pandas 数据处理能力。建议后续按以下路径持续提升:
- 先把“清洗 + 分组 + 连接 + 时间序列”练熟
- 再结合真实业务数据进行端到端分析
- 最后形成自己的可复用数据处理模板
持续实践,Pandas 会成为你最稳定、最高效的数据工程工具之一。