Pandas 作为 Python 数据科学生态中的核心库,提供了高效的数据结构和数据分析工具,广泛应用于数据清洗、转换、分析等场景。本文将基于实际代码案例,从基础操作到高级技巧,全面解析 Pandas 的常用功能,帮助读者快速掌握数据处理的核心技能。
一、Pandas 基础操作与数据结构
1.1 数据读取与基本信息查看
Pandas 最常用的数据结构是 DataFrame(二维表格)和 Series(一维数组)。以下代码展示了如何读取 CSV 数据并查看基本信息:
import pandas as pd
# 读取 CSV 数据
df = pd.read_csv("./data/titanic.csv")
# 查看前 10 行数据
print(df.head(10))
# 查看数据基本信息(行数、列数、数据类型、缺失值等)
df.info()
# 查看索引、列名、数据类型和值
print("索引:", df.index)
print("列名:", df.columns)
print("数据类型:", df.dtypes)
print("值:", df.values)
分析:
- read_csv 是读取 CSV 文件的核心函数,支持本地文件和 URL 路径。
- head(n) 用于快速预览数据,默认显示前 5 行,适合初步了解数据结构。
- df.info() 是数据探查的关键工具,可直观看到每列的非空值数量和数据类型(如 int64、float64、object),帮助识别缺失值和异常类型。
- index、columns、dtypes、values 分别返回数据的索引、列名、列类型和底层数值数组,便于深入理解数据结构。
1.2 手动创建 DataFrame
除了读取外部数据,还可以手动构造 DataFrame:
# 手动创建 DataFrame
data = {
"country": ["aaa", "bbb", "ccc"],
"population": [10, 12, 14]
}
df_data = pd.DataFrame(data)
print(df_data)
df_data.info()
分析:
- 通过字典创建 DataFrame 时,字典的键为列名,值为列数据(列表或数组)。
- 这种方式适合小批量数据的快速构造,常用于测试和示例。
1.3 Series 与数据查询
Series 是 DataFrame 的单列,具有索引和值:
# 提取 Series 并操作
age = df["Age"] # 提取"Age"列(Series类型)
print(age[:5]) # 查看前5个值
# 以姓名为索引查询年龄
age = df.set_index("Name")["Age"] # 将"Name"设为索引
print(age["Braund, Mr. Owen Harris"]) # 通过姓名查询年龄
# 数值运算与统计
age += 10 # 所有年龄加10
print("平均年龄:", age.mean())
print("最小年龄:", age.min())
print("最大年龄:", age.max())
# 数据统计摘要
print(df.describe()) # 显示数值列的计数、均值、标准差、分位数等
分析:
- Series 可通过 df["列名"] 提取,支持切片([:5])和索引查询。
- set_index 可将指定列设为索引,便于按标签快速查询(如按姓名查年龄)。
- 内置统计函数(mean、min、max)会自动忽略缺失值(NaN),describe() 则提供数值列的整体统计概览。
二、索引操作
一、索引操作
Pandas 的索引操作是数据查询和筛选的核心,涵盖多种方式以适应不同场景,相关操作主要集中在2.Pandas索引.py和13.Pandas索引2.py中:
1. 基础索引(标签与位置)
-
loc(标签索引):通过行 / 列的标签(名称)定位数据,支持单值、切片(包含端点)和条件筛选。示例:# 定位指定行标签的整行数据 name.loc["Braund, Mr. Owen Harris"] # 定位指定行标签和列标签的具体值 name.loc["Braund, Mr. Owen Harris", "Fare"] # 切片获取连续标签的行 name.loc["Braund, Mr. Owen Harris":"Heikkinen, Miss. Laina"] -
iloc(位置索引):通过整数位置(从 0 开始)定位数据,类似列表索引,切片不包含端点。示例:# 获取前5行、第1-3列(位置索引) df.iloc[0:5, 1:3]
2. 布尔索引
通过条件判断生成布尔值序列,筛选满足条件的行 / 列。示例:
# 筛选票价大于40的行
name[name["Fare"] > 40][:5]
# 筛选女性乘客
name[name["Sex"] == "female"][:5]
# 统计年龄大于70的人数
(df["Age"] > 70).sum()
3. 特殊索引方法
-
isin:判断元素是否包含在指定列表中,返回布尔序列,支持多级索引。示例:# 筛选Series中值为1、3、4的元素 s[s.isin([1, 3, 4])] # 筛选多级索引中标签为(1, 'a')或(0, 'b')的行 s2.iloc[s2.index.isin([(1, 'a'), (0, 'b')])] -
where:保留满足条件的元素,不满足的替换为指定值(默认 NaN)。示例:# 将小于0的值保留,大于等于0的替换为999 df.where(df < 0, 999) -
query:通过字符串表达式筛选数据,语法更简洁。示例:# 筛选a < b且b < c的行 df.query('(a < b) & (b < c)')
4. 多级索引(MultiIndex)
通过多个维度的标签组合索引数据,可通过from_product生成(笛卡尔积)。示例:
# 生成两级索引的Series
arrays = [['bar', 'bar', 'baz'], ['one', 'two', 'one']]
index = pd.MultiIndex.from_arrays(arrays, names=['first', 'second'])
s = pd.Series(np.random.randn(3), index=index)
# 按第0层索引分组求和
s.groupby(level=0).sum()
二、loc 和 iloc 是两种核心索引方式的区别
索引是 Pandas 高效查询数据的基础,loc 和 iloc 是两种核心索引方式:
import pandas as pd
df = pd.read_csv("./data/titanic.csv")
# 提取两列的前5行
values = df[["Age", "Fare"]][:5]
print(values)
# iloc:按位置索引(整数位置,从0开始)
print(values.iloc[0:5]) # 取前5行(0-4)
print(df.iloc[0:5, 1:3]) # 取前5行,第2-3列(位置1到2)
# loc:按标签索引(行/列的名称)
name = df.set_index("Name") # 将"Name"设为行索引
print(name.loc["Braund, Mr. Owen Harris"]) # 按姓名取整行
print(name.loc["Braund, Mr. Owen Harris", "Fare"]) # 按姓名和列名取具体值
print(name.loc["Braund, Mr. Owen Harris":"Heikkinen, Miss. Laina"]) # 按标签切片(包含终点)
# 布尔索引:筛选满足条件的数据
print(name[name["Fare"] > 40][:5]) # 筛选票价>40的前5行
print(name[name["Sex"] == "female"][:5]) # 筛选女性乘客
分析:
- iloc 基于整数位置索引,语法为 iloc[行位置, 列位置],切片时遵循「左闭右开」规则(如 0:5 包含 0-4)。
- loc 基于标签索引,语法为 loc[行标签, 列标签],切片包含终点(如 a:b 包含 a 和 b)。
- 布尔索引通过条件表达式(如 name["Fare"] > 40)生成布尔值数组,快速筛选符合条件的行,是数据过滤的常用方式。
三、分组操作:groupby 的核心逻辑
groupby 是数据分析中分组聚合的核心工具,遵循「拆分 - 应用 - 合并」(Split-Apply-Combine)逻辑:
import pandas as pd
# 简单示例:按key分组求和
df = pd.DataFrame({
"key": ["A", "B", "C", "A", "B", "C", "A", "B", "C"],
"data": [0, 5, 10, 5, 10, 15, 10, 15, 20]
})
print(df.groupby("key").sum()) # 按key分组并求和
print(df.groupby("key").aggregate("mean")) # 按key分组并求均值
# 泰坦尼克号数据:按性别分组分析
titanic = pd.read_csv("./data/titanic.csv")
print("男女生平均年龄:", titanic.groupby("Sex")["Age"].mean())
print("男女获救率:", titanic.groupby("Sex")["Survived"].mean())
分析:
- groupby("key") 将数据按 key 列的值拆分为多个子数据集(如 A、B、C 三组)。
- 聚合函数(sum、mean、aggregate)用于对每个子数据集应用计算,最终合并为结果。
- 实际场景中,可通过 groupby(列名)[目标列].聚合函数() 实现复杂分析,如按性别统计平均年龄和获救率,快速挖掘数据规律。
四、数据合并:merge 操作详解
merge 用于合并多个 DataFrame,类似 SQL 中的表连接,支持多种连接方式:
import pandas as pd
# 基础合并(单键)
left = pd.DataFrame({
"Key": ["K0", "K1", "K2", "K3"],
"A": ["A0", "A1", "A2", "A3"],
"B": ["B0", "B1", "B2", "B3"]
})
right = pd.DataFrame({
"Key": ["K0", "K1", "K2", "K3"],
"C": ["C0", "C1", "C2", "C3"],
"D": ["D0", "D1", "D2", "D3"]
})
print(pd.merge(left, right, on="Key")) # 按Key合并
# 多键合并
left = pd.DataFrame({
"Key1": ["K0", "K1", "K2", "K3"],
"Key2": ["K0", "K1", "K2", "K3"],
"A": ["A0", "A1", "A2", "A3"]
})
right = pd.DataFrame({
"Key1": ["K0", "K1", "K2", "K3"],
"Key2": ["K0", "K1", "K2", "K4"],
"C": ["C0", "C1", "C2", "C3"]
})
# 按Key1和Key2合并,外连接(保留所有键),并显示合并来源
print(pd.merge(left, right, on=["Key1", "Key2"], how="outer", indicator=True))
分析:
- on 参数指定合并的键(可单个或多个),多键合并时需确保键值对完全匹配。
- how 参数控制连接方式:inner(默认,交集)、outer(并集)、left(左表为准)、right(右表为准)。
- indicator=True 会添加 _merge 列,标记每行数据来自左表、右表还是两者共有,便于排查合并问题。
五、数值运算与统计分析
Pandas 提供了丰富的数值运算和统计函数,支持按行或列操作:
import pandas as pd
# 基础数值运算
df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], index=["a", "b"], columns=["A", "B", "C"])
print("按列求和:", df.sum()) # 默认按列
print("按行求和:", df.sum(axis=1)) # axis=1表示按行
print("均值:", df.mean())
print("中位数:", df.median())
# 泰坦尼克号数据:协方差与相关系数
titanic = pd.read_csv("./data/titanic.csv")
# 筛选数值列计算协方差(反映变量间相关性方向和强度)
print("协方差矩阵:\n", titanic.select_dtypes(["int64", "float64"]).cov())
# 计算相关系数(-1到1之间,绝对值越大相关性越强)
print("相关系数矩阵:\n", titanic.select_dtypes(["int64", "float64"]).corr())
# 值计数与分布
print("年龄分布计数:", titanic["Age"].value_counts(ascending=True)) # 按年龄值计数
# 按区间分组计数(归一化后为频率)
print("年龄区间分布:", titanic["Age"].value_counts(normalize=True, bins=5))
分析:
- 轴参数 axis 是关键:axis=0(默认)按列操作,axis=1 按行操作。
- 协方差(cov)和相关系数(corr)用于分析变量间关系,相关系数更易解释(消除量纲影响)。
- value_counts 用于统计离散值的出现次数,bins 参数可将连续值分段统计,适合分析数据分布。
六、高级操作:apply、透视表与时间序列
6.1 apply 函数:灵活处理行 / 列数据
apply 允许对 DataFrame/Series 应用自定义函数,实现复杂逻辑:
import pandas as pd
titanic = pd.read_csv('./data/titanic_train.csv')
# 计算每列缺失值数量
def not_null_count(columns):
columns_null = pd.isnull(columns) # 标记缺失值
return len(columns[columns_null]) # 返回缺失值数量
columns_null_count = titanic.apply(not_null_count)
print("每列缺失值数量:\n", columns_null_count)
# 转换乘客等级为文字描述(按行操作,axis=1)
def which_class(row):
pclass = row['Pclass']
if pd.isnull(pclass):
return 'Unknown'
elif pclass == 1:
return 'First class'
elif pclass == 2:
return 'Second class'
else:
return 'Third class'
classes = titanic.apply(which_class, axis=1)
print("乘客等级文字描述:\n", classes)
分析:
- apply 可作用于列(默认,axis=0)或行(axis=1),传入的参数为每列 / 每行的数据。
- 适合实现无法用内置函数直接完成的逻辑(如条件判断、复杂转换),但性能略低于向量化操作,大数据量时需谨慎。
6.2 透视表:数据汇总与多维分析
pivot_table 用于快速生成透视表,实现多维度数据汇总:
import pandas as pd
titanic = pd.read_csv("./data/titanic.csv")
# 不同性别在不同船舱的平均费用
print(titanic.pivot_table(index="Sex", columns="Pclass", values="Fare"))
# 不同客舱和性别的生存率(指定聚合函数为均值)
print(titanic.pivot_table(
index="Pclass",
columns="Sex",
values="Survived",
aggfunc="mean"
))
# 新增"是否未成年"列,分析未成年与性别对生存率的影响
titanic["Underaged"] = titanic["Age"] <= 18
print(titanic.pivot_table(
index="Underaged",
columns="Sex",
values="Survived",
aggfunc="mean"
))
分析:
- 透视表的核心参数:index(行分组)、columns(列分组)、values(聚合数据)、aggfunc(聚合函数,默认均值)。
- 适合多维度分析,如同时按性别和船舱等级分析生存率,快速发现数据中的模式(如女性和高等级船舱乘客生存率更高)。
6.3 时间序列:日期处理与重采样
Pandas 对时间序列支持强大,可轻松处理日期转换、筛选和重采样:
import pandas as pd
# 时间数据转换
data = pd.read_csv("./data/flowdata.csv")
data["Time"] = pd.to_datetime(data["Time"]) # 将字符串转为datetime类型
data = data.set_index("Time") # 设为索引
# 时间筛选
print("2012-01-01 09:00至19:00的数据:\n",
data[pd.Timestamp("2012-01-01 09:00"):pd.Timestamp("2012-01-01 19:00")])
print("2013年数据:\n", data.loc['2013']) # 按年份筛选
# 重采样(时间粒度转换)
print("按天均值重采样:\n", data.resample("D").mean().head()) # 每日均值
print("按月均值重采样:\n", data.resample("ME").mean().head()) # 每月均值(ME=月末)
分析:
- pd.to_datetime 可将字符串转换为 datetime 类型,便于时间操作。
- 时间索引支持按年份('2013')、区间('2012':'2013')筛选,比普通索引更灵活。
- resample 用于时间粒度转换(如日转月),结合聚合函数(mean、sum)可实现时序数据的汇总分析。
七、大数据处理:内存优化技巧
处理大型数据集时,内存占用是关键问题,以下是常用优化方法:
import pandas as pd
import numpy as np
# 读取大数据时优化类型推断
gl = pd.read_csv('./data/game_logs.csv', low_memory=False) # 禁用低内存模式,更准确推断类型
# 优化数值类型(缩小整数/浮点数占用空间)
gl_int = gl.select_dtypes(include=['int64'])
# 向下转换为最小可行无符号整数类型
converted_int = gl_int.apply(pd.to_numeric, downcast='unsigned')
print("优化前int内存:", mem_usage(gl_int))
print("优化后int内存:", mem_usage(converted_int))
# 优化字符串类型(转为category类型)
gl_obj = gl.select_dtypes(include=["object"]).copy()
converted_obj = pd.DataFrame()
for col in gl_obj.columns:
# 唯一值占比低的列转为category(节省内存)
if len(gl_obj[col].unique()) / len(gl_obj[col]) < 0.5:
converted_obj[col] = gl_obj[col].astype('category')
else:
converted_obj[col] = gl_obj[col]
print("优化前object内存:", mem_usage(gl_obj))
print("优化后object内存:", mem_usage(converted_obj))
分析:
- low_memory=False 确保读取大文件时类型推断更准确,避免因分块读取导致的类型错误。
- 数值类型优化:downcast='unsigned' 将 int64 转为最小可行无符号类型(如 uint8),减少内存占用。
- 字符串类型优化:category 类型通过整数编码存储重复字符串,适合唯一值少的列(如性别、类别),可大幅降低内存使用。
八、绘图操作
Pandas 基于 Matplotlib 封装了绘图功能,支持多种图表类型,相关操作在14.Pandas绘图.py中:
1. 基础线图
Series.plot()或DataFrame.plot()默认绘制线图,适合展示数据趋势。示例:# 绘制Series线图 s = pd.Series(np.random.randn(10), index=np.arange(0, 100, 10)) s.plot() # 绘制DataFrame多列线图 df = pd.DataFrame(np.random.randn(10, 4).cumsum(0), columns=['A', 'B', 'C', 'D']) df.plot()
2. 柱状图
- 垂直柱状图(
kind='bar')和水平柱状图(kind='barh'),适合比较分类数据。示例:# 子图中分别绘制垂直和水平柱状图 fig, axes = plt.subplots(2, 1) data.plot(ax=axes[0], kind='bar') # 垂直 data.plot(ax=axes[1], kind='barh') # 水平
3. 直方图(kind='hist')
展示单变量的分布特征,通过bins指定分箱数量。示例:
# 绘制总账单金额的直方图(50个分箱)
tips.total_bill.plot(kind='hist', bins=50)
4. 散点图与散点矩阵图
- 散点图(
kind='scatter'):展示两个变量的相关性。 - 散点矩阵图(
scatter_matrix):展示多变量间的两两关系,对角线为单变量分布。示例:# 散点图:季度与实际GDP的关系 data.plot.scatter('quarter', 'realgdp') # 散点矩阵图:多变量关系(绿色,透明度0.3) scatter_matrix(data, color='g', alpha=0.3)
九、groupby 延伸操作
groupby 是数据分组聚合的核心,除基础分组外,还有更多灵活用法,见11.groupby操作延申.py:
1. 多键分组
通过多个列(或索引)组合分组,适合复杂维度分析。示例:
# 按A和B两列分组,统计数量
grouped = df.groupby(['A', 'B'])
print(grouped.count())
2. 按函数分组
通过自定义函数对索引或列进行分组,灵活度高。示例:
# 按索引首字母是否为元音分组(元音返回'a',否则返回'b')
def get_letter_type(letter):
if letter.lower() in "aeiou":
return "a"
else:
return "b"
grouped = df.T.groupby(get_letter_type) # 转置后按列索引分组
print(grouped.count())
3. 多层索引分组
对多级索引的某一层进行分组,通过level指定层级(或名称)。示例:
# 对多级索引的第0层(名称为'first')分组求和
grouped = s.groupby(level='first')
print(grouped.sum())
4. 聚合操作(aggregate/agg)
- 支持多函数聚合,可指定列名。
as_index参数控制分组键是否作为索引(False时保留为列)。示例:# 对C列应用sum、mean、std,并指定结果列名 grouped['C'].agg([('res_sum', 'sum'), ('res_mean', 'mean'), ('res_std', 'std')]) # 分组键作为普通列(非索引) grouped = df.groupby(['A', 'B'], as_index=False) print(grouped.aggregate("sum"))
5. 其他实用方法
size():返回每个分组的元素数量。describe():返回每个分组的统计摘要(均值、标准差等)。
十、显示操作
Pandas 默认会截断输出,可通过set_option调整显示参数,相关操作在7.显示设置.py中:
1. 控制行数 / 列数
display.max_rows/display.max_columns:设置最大显示行数 / 列数(None表示不限制)。示例:# 设置最大显示100行 pd.set_option("display.max_rows", 100) # 查看当前设置 print(pd.get_option("display.max_rows"))
2. 控制列宽
display.max_colwidth:设置列中字符串的最大显示长度。示例:# 设置列宽为100(默认较短,长字符串会截断) pd.set_option("display.max_colwidth", 100)
3. 控制精度
display.precision:设置浮点数的显示精度(小数位数)。示例:# 设置浮点数显示5位小数 pd.set_option("display.precision", 5)
十一、总结
本文通过实际代码案例,系统讲解了 Pandas 的核心操作,包括基础数据处理、索引查询、分组聚合、数据合并、数值统计、高级函数(apply、透视表)、时间序列和内存优化。可高效处理从小型表格到大型数据集的各种场景,为数据分析和建模奠定坚实基础。
1529

被折叠的 条评论
为什么被折叠?



