Pandas DataFrame 实战分析:分组、合并、查询、索引与缺失值处理
Pandas 是 Python 数据分析的基石,DataFrame 作为其核心数据结构,提供了强大的数据处理能力。本文将通过实战案例,详细分析 DataFrame 在分组、合并、查询、重建索引、缺失值填充和索引对象方面的应用,并提供代码示例和记忆技巧,帮助你深入掌握这些功能。
一、分组实战(GroupBy)
1. 功能简介
分组操作通过 groupby()
方法实现,用于按某列(或多列)将数据分组,然后对每组应用聚合函数(如求和、均值)或自定义操作。
2. 实战案例
假设有一个学生成绩表,分析每个班级的平均成绩。
import pandas as pd
# 创建 DataFrame
data = {
'class': ['A', 'A', 'B', 'B', 'C'],
'student': ['Alice', 'Bob', 'Cathy', 'David', 'Eve'],
'score': [90, 85, 88, 92, 95]
}
df = pd.DataFrame(data)
# 分组并计算每个班级的平均成绩
class_avg = df.groupby('class')['score'].mean()
print(class_avg)
# 输出:
# class
# A 87.5
# B 90.0
# C 95.0
# Name: score, dtype: float64
# 多列分组:按班级和学生统计
group = df.groupby('class').agg({'score': ['mean', 'max']})
print(group)
# 输出:
# score
# mean max
# class
# A 87.5 90
# B 90.0 92
# C 95.0 95
3. 关键点
- 分组依据:可以是单列(
df.groupby('class')
)或多列(df.groupby(['class', 'student'])
)。 - 聚合函数:常用
mean()
,sum()
,count()
,max()
等,也支持自定义函数通过apply()
。 - 多列聚合:使用
agg()
可对不同列应用不同函数。
4. 记忆技巧
将 groupby()
想象为“按标签打包”,每一组是一个“包裹”,然后对每个包裹执行统计操作。
二、合并实战(Merge)
1. 功能简介
merge()
用于合并两个 DataFrame,类似于 SQL 的 JOIN 操作,支持内连接、左连接、右连接和外连接。
2. 实战案例
假设有学生信息表和成绩表,合并它们以获取完整信息。
# 学生信息表
df1 = pd.DataFrame({
'student_id': [1, 2, 3, 4],
'name': ['Alice', 'Bob', 'Cathy', 'David']
})
# 成绩表
df2 = pd.DataFrame({
'student_id': [1, 2, 3, 5],
'score': [90, 85, 88, 92]
})
# 内连接:只保留匹配的记录
merged_inner = pd.merge(df1, df2, on='student_id', how='inner')
print(merged_inner)
# 输出:
# student_id name score
# 0 1 Alice 90
# 1 2 Bob 85
# 2 3 Cathy 88
# 左连接:保留 df1 的所有记录
merged_left = pd.merge(df1, df2, on='student_id', how='left')
print(merged_left)
# 输出:
# student_id name score
# 0 1 Alice 90.0
# 1 2 Bob 85.0
# 2 3 Cathy 88.0
# 3 4 David NaN
3. 关键点
-
参数:
on
:指定合并的键(列名)。how
:连接类型(inner
,left
,right
,outer
)。left_on
/right_on
:当键名不同时使用。
-
性能:对于大数据集,合并前确保键列的数据类型一致以提升效率。
4. 记忆技巧
将 merge()
想象为“两张表格拼图”,on
是拼图的连接点,how
决定如何处理不匹配的部分。
三、查询实战
1. 功能简介
查询操作通过条件筛选、布尔索引或 query()
方法提取满足条件的行。
2. 实战案例
筛选成绩高于 90 的学生,并查询特定班级的记录。
# 数据
df = pd.DataFrame({
'class': ['A', 'A', 'B', 'B', 'C'],
'student': ['Alice', 'Bob', 'Cathy', 'David', 'Eve'],
'score': [90, 85, 88, 92, 95]
})
# 布尔索引:筛选 score > 90
high_score = df[df['score'] > 90]
print(high_score)
# 输出:
# class student score
# 3 B David 92
# 4 C Eve 95
# query() 方法:筛选 class == 'A' 且 score >= 85
class_a = df.query("class == 'A' and score >= 85")
print(class_a)
# 输出:
# class student score
# 0 A Alice 90
# 1 A Bob 85
3. 关键点
- 布尔索引:使用条件表达式(如
df['score'] > 90
)生成布尔 Series。 query()
:支持 SQL 风格的字符串查询,适合复杂条件。- 性能:
query()
在大数据集上通常比布尔索引快。
4. 记忆技巧
将查询想象为“从表格中挑出符合规则的行”,布尔索引是“手工筛选”,query()
是“自动化过滤”。
四、重建索引实战(Reindex)
1. 功能简介
reindex()
用于更改 DataFrame 的行或列索引,可以重新排序、添加或删除索引。
2. 实战案例
调整 DataFrame 的行索引,并为缺失的索引填充值。
# 数据
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Cathy'],
'score': [90, 85, 88]
}, index=['x', 'y', 'z'])
# 重新设置行索引
df_reindexed = df.reindex(['w', 'x', 'y', 'z', 'a'])
print(df_reindexed)
# 输出:
# name score
# w NaN NaN
# x Alice 90.0
# y Bob 85.0
# z Cathy 88.0
# a NaN NaN
# 填充缺失值
df_filled = df.reindex(['w', 'x', 'y', 'z', 'a'], fill_value=0)
print(df_filled)
# 输出:
# name score
# w 0 0
# x Alice 90
# y Bob 85
# z Cathy 88
# a 0 0
3. 关键点
-
参数:
index
:新行索引。columns
:新列索引。fill_value
:填充缺失值。
-
用途:常用于数据对齐或统一索引格式。
4. 记忆技巧
将 reindex()
想象为“重新贴标签”,新标签可能导致空位(NaN),需要决定是否填充。
五、缺失值填充实战(Handling Missing Values)
1. 功能简介
缺失值(NaN 或 None)在数据分析中常见,Pandas 提供多种方法处理缺失值,包括删除(dropna()
)和填充(fillna()
)。
2. 实战案例
以下分析不同场景下的缺失值处理。
(1)删除缺失值
# 数据
df = pd.DataFrame({
'name': ['Alice', 'Bob', None, 'David'],
'score': [90, None, 88, 92]
})
# 删除包含缺失值的行
df_dropped = df.dropna()
print(df_dropped)
# 输出:
# name score
# 0 Alice 90.0
# 3 David 92.0
(2)填充固定值
# 填充 NaN 为 0
df_filled = df.fillna(0)
print(df_filled)
# 输出:
# name score
# 0 Alice 90.0
# 1 Bob 0.0
# 2 0 88.0
# 3 David 92.0
(3)前向填充(ffill)/后向填充(bfill)
# 前向填充:用前一个值填充
df_ffill = df.fillna(method='ffill')
print(df_ffill)
# 输出:
# name score
# 0 Alice 90.0
# 1 Bob 90.0
# 2 Bob 88.0
# 3 David 92.0
(4)按列填充不同值
# 按列指定填充值
df_col_fill = df.fillna({'name': 'Unknown', 'score': df['score'].mean()})
print(df_col_fill)
# 输出:
# name score
# 0 Alice 90.000000
# 1 Bob 90.000000
# 2 Unknown 88.000000
# 3 David 92.000000
(5)插值填充(interpolate)
# 线性插值
df_interpolate = df['score'].interpolate()
print(df_interpolate)
# 输出:
# 0 90.0
# 1 89.0
# 2 88.0
# 3 92.0
# Name: score, dtype: float64
3. 关键点
-
删除:
dropna()
适合缺失值较少的情况,避免丢失过多数据。 -
填充:
- 固定值:简单但可能引入偏差。
- 前/后向填充:适合时间序列数据。
- 均值/中位数:适合数值列,保留分布特性。
- 插值:适合连续数据,生成平滑过渡值。
-
注意:填充前需分析数据分布,避免引入不合理值。
4. 记忆技巧
将缺失值处理想象为“修补破洞的衣服”:
- 删除:直接扔掉破损部分(
dropna()
)。 - 填充:用布料补洞(
fillna()
),布料可以是固定颜色(固定值)、附近颜色(ffill/bfill)或渐变色(interpolate)。
六、索引对象实战(Index Objects)
1. 功能简介
Pandas 的索引对象(Index
或其子类)管理行和列的标签,支持高效查询和对齐。
2. 实战案例
操作索引对象,修改和查询索引。
# 数据
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Cathy'],
'score': [90, 85, 88]
}, index=['x', 'y', 'z'])
# 获取索引
print(df.index)
# 输出:Index(['x', 'y', 'z'], dtype='object')
# 修改索引
df.index = ['a', 'b', 'c']
print(df)
# 输出:
# name score
# a Alice 90
# b Bob 85
# c Cathy 88
# 检查索引是否存在
print('a' in df.index) # True
# 重置索引为默认整数索引
df_reset = df.reset_index(drop=True)
print(df_reset)
# 输出:
# name score
# 0 Alice 90
# 1 Bob 85
# 2 Cathy 88
# 设置某列为索引
df_set = df.set_index('name')
print(df_set)
# 输出:
# score
# name
# Alice 90
# Bob 85
# Cathy 88
3. 关键点
-
索引类型:常见有
Index
(通用)、RangeIndex
(整数序列)、MultiIndex
(多级索引)。 -
操作:
reset_index()
:将索引转为列或丢弃。set_index()
:将列设为索引。
-
不可变性:索引对象是不可变的,保证数据一致性。
4. 记忆技巧
将索引对象想象为“表格的门牌号”,可以更换(set_index
)、重置(reset_index
),但门牌本身不能随意修改。
七、总结与记忆技巧
1. 综合记忆
- 分组:像整理书架,按类别(
groupby
)整理后再统计。 - 合并:像拼图,找共同点(
on
)拼接表格。 - 查询:像搜索,设定条件(布尔或
query
)找到目标。 - 重建索引:像重新贴标签,调整表格的“地址”。
- 缺失值:像修补漏洞,选择合适的“材料”填充。
- 索引对象:像门牌号,管理表格的定位系统。
2. 实践建议
- 动手实践:运行每个案例代码,尝试修改参数(如
how
、method
)观察效果。 - 真实数据:找一个 CSV 文件(如 Kaggle 数据集),应用这些操作。
- 记录笔记:将常用方法(如
groupby
,merge
)整理成 cheatsheet。
通过本文的实战案例,你可以更深入理解 Pandas DataFrame 的核心功能。希望这篇博客能帮助你快速上手 Pandas 并在数据分析中游刃有余!