Python:图解 Pandas
NumPy 与 Pandas 有一个共同点:它们都用于存储数据并对数据进行操作。
NumPy:
当需要进行数值计算,尤其是数组或矩阵运算时,应使用 NumPy。它非常适合数学运算、线性代数以及科学计算。
Pandas:
当处理结构化或表格型数据时,应使用 Pandas。如果需要对表格数据或 CSV 文件进行清洗、整理与分析,Pandas 往往是首选库;若需要进一步可视化,则常与 Matplotlib、Seaborn 等工具配合使用。
如果将 NumPy 理解为一个高性能的多维数组系统(ndarray),那么可以将 Pandas 理解为带标签的表格结构(DataFrame)。
Pandas 提供的两种核心数据结构:
• Series(一维结构)
• DataFrame(二维结构)
在 DataFrame 中,每一列本质上是一个 Series。
可以将 DataFrame 理解为一张数据库表,我们可以像使用 SQL 一样对其进行查询和数据操作。要注意的是,DataFrame 是内存中的数据结构,而数据库表属于持久化存储结构。
一、导入 Pandas
import pandas as pd
二、构建并认识 DataFrame
1、构建 DataFrame
(1)手动创建
最常见的方式是从字典创建:
import pandas as pd
df = pd.DataFrame({ "姓名": ["张三", "李四", "王五"], "城市": ["北京", "上海", "北京"], "年龄": [25, 30, 28]})
(2)从文件创建
常通过读取 .csv 数据并构建 DataFrame
import pandas as pd
blog = pd.read_csv("blog.csv")opensource = pd.read_csv("opensource.csv")solothought = pd.concat( [blog, opensource], keys=['blog', 'OpenSource'], names=['Type', 'idx'])# st = solothought
2、DataFrame 结构
下图展示了 DataFrame 的各个组成部分。

DataFrame 是带标签的二维数据结构:行标签由 df.index(Index)管理,列标签由 df.columns(Index)管理。
(1)列标签系统
DataFrame 的每一列由列标签进行标识,这些列标签统一存储在:
df.columns # 查看列标签
df.columns 是一个 Index 对象,负责管理所有列标签。
每一列本质上是一个 Series 对象。
(2)行索引系统
DataFrame 的每一行由行索引(Index) 进行标识。
这些索引统一存储在:
df.index # 查看行索引df.index.names # 查看索引层名称
行索引用于定位数据,例如:
solothought.loc[("blog", 2)]
(3)多级行索引
图中左侧展示的是多级行索引结构(MultiIndex):
Type idx----------------blog 0blog 1...OpenSource 0OpenSource 1
pd.concat() 在合并数据时,通过 keys 参数自动生成第一层行索引("Type")和第二层行索引("idx"),从而形成 MultiIndex(多级索引)结构。
这些层级名称存储在:
df.index.names
通过多级索引,可以实现更高维度的数据组织方式。
例如:
solothought.loc["blog"]solothought.loc["OpenSource"]
(4)Series
DataFrame 中每一列都是一个 Series 对象:
solothought["title"]solothought["views"]
Series 由索引(Index)与一维数据(底层数组/ExtensionArray)组成。
3、查看数据样本
常用方法包括:
df.head() # 查看前5条记录df.tail() # 查看后5条记录
solothought.sample(5, weights="views") # 随机抽取5条记录(按权重)
其中,权重(weights)可以是
• 列名
• 数组
• Series
三、DataFrame 常见数据操作

1、查看数据结构
df.shape # 查看数据维度 (rows, columns)len(df) # 查看行数
df.info()
输出内容包括:
• DataFrame 类型
• 行数与索引范围
• 每列的非空值数量
• 数据类型(dtype)
• 内存使用情况
2、选择数据
(1)选择行
可以通过切片方式选择行:
df[0:5] # 前 5 行df[-5:] # 最后 5 行
对于 DataFrame,df[0:5] 这类切片通常表现为按行切片,常用于取前几行或后几行;若需要明确按整数位置选择,推荐使用 iloc()。
(2)选择列
选择单列:
solothought.title# 或者solothought["title"]
选择多列:
solothought[["title", "category"]]
3、新增行/列
在 Pandas 中,可以通过构造新的 DataFrame 或 Series,然后使用相关函数将其追加到现有数据表中。
(1)添加行
可以通过拼接 DataFrame 添加行。
示例:使用 concat()
row = pd.DataFrame({ "title": "strnum", "category": "library", "tags": "numeric", "uses": 72000, "featured": False}, index=[("OpenSource", 4)])
solothought = pd.concat([solothought, row])
该操作会在 DataFrame 末尾新增一条记录,并自动对齐列结构。
(2)添加列
方法一:直接赋值添加列
l = ["1 Apr 2023", "2 Apr 2023"] + [None] * 14 # 列表元素个数要与 DataFrame 的行数一致solothought["published on"] = l
方法二:
使用 insert() 可以指定要插入的列位置。
solothought.insert(4, "published on", l)
方法三:
assign() 适用于链式操作:
solothought = solothought.assign(**{"published on": l})
4、数据清洗
Pandas 中许多方法默认返回新的 DataFrame,而不会修改原对象。
如需原地修改,请设置 inplace=True,或将返回值重新赋值给变量。
(1)删除行/列
drop() 用于删除 DataFrame 中的行或列,返回删除后的新 DataFrame(默认不会修改原对象)。
删除行:
solothought.drop(0) # 按行索引删除solothought.drop(1, inplace=True) # 原地删除solothought.drop([0, 2, 4]) # 删除多行solothought.drop(index=[0, 2, 4])solothought.drop(("blog", 1), axis=0, inplace=True) # 多级索引删除 ("blog", 1) 这一行
#条件删除# 先筛选索引,再删除:hv = solothought[solothought["views"] > 1000]solothought.drop(hv.index) #删除 views 大于 1000 的行
删除列:
solothought.drop("views", axis=1) # 按列名删除solothought.drop(["views", "tags"], axis=1) # 删除多列solothought.drop(columns=["views", "tags"])solothought.drop(columns=["views"], inplace=True) # 原地删除
(2)转换列数据
例如,某列中布尔值以 'y' 和 'n' 表示,使用 apply() 或 map() 进行列操作,将其转换为真正的布尔值:
solothought["featured"] = solothought["featured"].apply( lambda x: True if x == 'y' else False)
5、缺失值处理
在数据分析之前,通常需要先处理或填充缺失值。
Pandas 常用 NaN 或 pd.NA 表示缺失值(不同 dtype 的缺失值标记可能不同)。在读取 CSV 时,可以指定哪些值应被视为 NA。
(1)检查缺失值
solothought.isnull() # 检查整个 DataFrame 的缺失值solothought["views"].isnull() # 检查某列的缺失值
(2)统计缺失值数量
solothought.isnull().sum()
(3)删除包含缺失值的行或列
solothought.dropna() # 默认 axis=0, how="any":只要该行存在 NA 即删除
dropna() 的主要参数:
• axis:指定删除行或列
• how:指定“全部为 NA 才删除”或“存在 NA 即删除”
• thresh:指定保留所需的最少非 NA 数量
• subset:指定检查 NA 的列
(3)填充缺失值
solothought["views"].fillna(0)
6、数据聚合
Pandas 提供大量统计函数用于数据汇总。
(1)描述统计
solothought["views"].describe()
(2)常用统计函数
count 9.000000 solothought["views"].count()mean 535.333333 solothought["views"].mean()std 494.384719 solothought["views"].std()min 14.000000 solothought["views"].min()25% 85.00000050% 350.000000 solothought["views"].quantile()75% 780.000000max 1331.000000 solothought["views"].max()Name: views, dtype: float64
(3)统计分类数量
value_counts() 可用于计算各类别出现的次数:
solothought["category"].value_counts()
四、数据选择:loc 与 iloc
可以通过索引、loc() 或 iloc() 选择行、列或具体值。
1、基于标签选择
loc() 是 Pandas 中最常用的基于标签的数据选择工具。
df.loc[rows, cols]
• rows:行标签(Index label)
• cols:列标签(Column label)

(1)按行索引标签选择
solothought.loc["blog"]solothought.loc[["blog","OpenSource"]] # 按多个行索引标签选择
选择第一层行索引标签为 "blog" 的所有记录。
可以逐层访问 MultiIndex:
solothought.loc["blog"].loc[0]
先选择 "blog" 这一层,再选择第二层行索引 0。
(2)行与列同时选择
可以同时指定行与列:
solothought.loc["blog", ["title", "category"]]
表示选择行索引标签为 "blog" 的所有行,返回 title 与 category 的、两列。
solothought.loc["blog"].loc[:5,["title", "category"]]
返回前 6 行:
solothought.loc["blog", ["title", "category"]][0:6]
还可以只指定列:
solothought.loc[:, ["title", "category"]]
(3)标签切片
loc() 支持标签切片,需要注意 loc() 的切片通常包含终止标签(inclusive)。
选择指定行索引范围的指定列:
solothought.loc["blog"].loc[:5,["title", "category"]]
以选择从某列开始直到最后一列:
solothought.loc["blog", "category":]
(4)排序后的索引访问
当多级索引经过排序后,可以进行更复杂的选择:
st = solothought.sort_index(level=0)
用 MultiIndex 进行范围切片:
st.loc[("blog", 1):("blog", 2), ["title", "category"]]
# 先取第一层,再在子表上切st.loc["blog"].loc[1:2, ["title", "category"]]
多级索引结构中可按指定层级选择:
st.loc[("blog",1)]
选择指定行标签的全部列:
solothought.loc[["blog", "OpenSource"],:]
2、基于位置选择
iloc() 使用整数位置(0,1,2…) 来选择行和列,而不是使用标签。
df.iloc[rows, cols]
• rows:行位置
• cols:列位置

(1)单行访问
返回第 0 行数据(Series):
solothought.iloc[0]
(2)切片访问
选择第 0~5 行,选择第 0~1 列:
solothought.iloc[0:6, 0:2] # 方法一solothought.iloc[:,0:2][0:6] # 方法二solothought.iloc[0:6, [0,1]] # 方法三
注意:行切片包含起点,不包含终点。
3、快速访问单个元素
iat() 是 iloc() 的单值版本,用于访问一个具体元素。
df.iat[row, col]
row 和 col 均是整数位置索引。
示例:
solothought.iat[0, 1]
4、添加新行
当列结构已明确且赋值数据能够与列对齐时,可以通过 loc[] 为一个新索引标签赋值,从而添加新行。
示例:
solothought.loc[("blog", i)] = some_list
表示在指定位置插入一行,行数据来自字典或列表。
五、条件筛选
1、基于布尔值的行筛选
在 Pandas 中,可以使用布尔序列(Boolean array)来决定哪些行应被保留。
• True → 保留该行
• False → 丢弃该行

示例:
solothought.loc["blog", ["title", "category"]].loc[ [False,False,False,False,True,False,False,True,False,True], [True,True]]
执行过程可以分为两个阶段:
第一步:选择数据子集
solothought.loc["blog", ["title", "category"]]
得到 blog 行标签分类下的 2 列。
第二步:使用布尔数组筛选.loc[ [False,False,False,False,True,False,False,True,False,True], [True,True]]
其中,第一组布尔值决定保留哪些行,第二组布尔值决定保留哪些列。
使用布尔索引时需要满足两个条件:
• 布尔序列长度必须与数据行数一致
• True / False 的位置决定数据保留情况
2、条件筛选
在实际数据分析中,布尔数组通常由条件表达式自动生成。

(1)使用比较运算生成布尔序列
solothought["views"] > 500
Pandas 会自动生成一个与 DataFrame 行数相同的布尔序列。并完成筛选。
(2)利用布尔序列筛选 DataFrame 行
solothought[solothought["views"] > 500]
筛选结果仅保留 "views" 大于 500 的记录。
(3)使用逻辑运算符组合多个条件
Pandas 使用按位逻辑运算符(&、|、~)来组合多个条件。
solothought[ (solothought["views"] > 500) & (solothought["featured"] == False)]
(4)可与 loc() 结合进行更精确的数据选择
比如:
solothought.loc[solothought["category"] == "tutorial"]
或者:
solothought.loc[solothought["views"] > 500]
随后可以继续进行数据分析,例如统计分类数量:
solothought.loc[solothought["views"] > 500].value_counts("category")
六、数据处理的常见操作
Pandas 在数据分析过程中常用的四类操作:条件查询(query)、随机抽样(sample)、重复数据检测与删除(duplicate)、数据替换(replace)。这些方法常用于数据清洗与数据预处理阶段。

1、条件查询
query() 方法允许使用类似 SQL 的表达式对 DataFrame 进行条件筛选。相比直接书写布尔索引,query() 往往提供了更直观的表达方式。
基本用法:
solothought.query("views > 500")
表示筛选出 "views" 大于 500 的记录。
也可以组合多个条件:
solothought.query("views > 500 and not featured")# 或者solothought.query("views > 500 & (featured == False)")
query() 的优势是可以直接使用列名作为变量,无需写 df["column"]。
2、随机抽样
sample() 用于从数据集中随机抽取样本,常用于数据探索或机器学习实验。
示例:
solothought.sample(3, weights="views")
表示从 DataFrame 中抽取 3 条记录,抽样概率与 "views" 列的值成比例(权重抽样)。
如果不指定 weights,则默认进行均匀随机抽样。
3、重复数据检测与删除
在数据清洗中,需要检测并移除重复记录。
检测重复行:
solothought.duplicated()
返回一个 布尔序列,True 表示该行是重复数据,False 表示唯一数据。
删除重复行:
solothought.drop_duplicates()
返回一个去除重复记录后的 DataFrame。
4、数据替换
replace() 用于批量替换数据值,适用于数据清洗与分类标准化。
示例:
solothought.replace({ "category": {"library": "package"}, "views": {np.nan: 0}})
表示将 category 列中的 "library" 替换为 "package",将 views 列中的缺失值 NaN 替换为 0。
多值替换:
solothought.replace( ["tutorial", "info"], ["learn", "news"])
表示将值 "tutorial" 替换为 "learn",将值 "info" 替换为 "news"。
当参数 regex=True 时,replace() 还可以进行正则表达式替换,用于文本数据处理。
七、数据处理的三个核心能力
分组统计(GroupBy)、缺失值填充(Fill Missing Value)以及数据修改(Modify Data)。这些操作通常出现在数据清洗与数据分析阶段,是 Pandas 数据处理能力的重要组成部分。

1、分组计算
groupby() 用于按照某一列或多列对数据进行分组,并在每个分组上执行统计或聚合计算。
示例:
grp = solothought.groupby("category")
按照 category 列对数据进行分组,每个类别形成一个分组。
(1)查看分组信息
grp.groups
返回每个分组对应的行索引。
(2)获取指定分组
grp.get_group("library")
返回 category = "library" 的所有记录。
(3)分组统计
grp.size()
统计每个分组的记录数量。
grp["title"].count()
统计各分组中 title 列的非空值数量。
(4)分组聚合
常见聚合函数包括:
grp["views"].min()grp["views"].max()grp["views"].std()grp["views"].describe()
这些函数会分别计算每个分组的统计指标。
(5)分组过滤
filter() 可以根据条件筛选满足要求的分组。
示例:
grp.filter(lambda x: x["views"].max() > 1300)
仅保留最大 "views" 超过 1300 的分组。
另一示例:
grp.filter(lambda x: x["featured"].sum() > 1)
仅保留 "featured" 文章数量超过 1 的分组。
2、缺失值填充
Pandas 提供多种方法用于处理缺失值(NaN)。
(1)使用 fillna()
solothought["views"].fillna(0)
将缺失值替换为 0。
也可以使用统计值填充:
solothought["views"].fillna(solothought["views"].mean())
常见填充方式包括:
• mean(平均值)
• median(中位数)
• mode(众数)
(2)插值填充
interpolate() 用于根据数据趋势对缺失值进行插值估计:
solothought.loc["blog"]["views"].interpolate( method="polynomial", order=3)
常见插值方法包括:
• linear
• polynomial
• spline
• nearest
• time
该方法通常用于数值型数据的时间序列或连续数据填补。
3、数据修改
Pandas 提供多种方式对 DataFrame 数据进行批量修改。
(1)使用 apply()
apply() 可以对每一行或每一列应用函数:
df.apply(lambda x: "Fixed value", axis=1)
其中,axis=1 表示按行处理,axis=0 表示按列处理。
apply() 会根据函数返回结果生成新的 Series 或 DataFrame,具体形式取决于操作对象和返回值结构。
示例:
def prefix(row): if row.category == "info": row["tags"] = str(row["tags"]) + "|news" return row
solothought = solothought.apply(prefix, axis=1)
该操作为 info 分类的文章标签添加 "news"。
(2)使用 map()
map() 用于对 Series 中的每个元素应用函数:
series.map(lambda x: "Fixed value")
.map() 将返回与原 Series 相同形状的数据,常用于值映射或简单转换。
如果在分组数据上执行类似操作,则通常使用 .transform()。
八、多级索引的创建与管理
多级索引(MultiIndex)允许在行或列方向上建立多层标签,使二维数据表能够表达更高维度的数据结构。

1、创建列多级索引
Pandas 可以通过元组列表(tuple list) 创建列的多级索引。例如:
cols = [ ("mandatory", "title"), ("mandatory", "category"), ("mandatory", "tags"), ("extra", "views"), ("extra", "featured"), ("extra", "uses")]
solothought.columns = pd.MultiIndex.from_tuples(cols)
该操作将列结构分为两个层级:
• 第一层(字段分组)
• 第二层(具体字段)
这样可以将数据列按逻辑分组,使数据结构更加清晰。
2、查看索引层
Pandas 提供属性用于查看索引层结构。
(1)查看行索引层
solothought.index.levels
返回:
[Index(['blog','OpenSource']),Index([0,1,2,3,...])]
(2)查看列索引层
solothought.columns.levels
示例输出:
['extra', 'mandatory']['category','featured','tags','title','uses','views']
说明:
mandatory → title, category, tagsextra → views, featured, uses
3、由列创建行索引
如果某些字段原本是普通列,可以使用 set_index() 将它们设为新的行索引。例如,对于包含 "Type" 和 "idx" 两列的普通 DataFrame,可写为:
some_df.set_index(["Type", "idx"])
此操作会生成新的多级行索引。
4、重置索引
如果希望将索引转换回普通列,可以使用 reset_index():
solothought.reset_index()
此操作会将索引(如 "Type"、"idx")变为普通列,并创建新的整数索引。
或者,丢弃 "idx" 这一层:
solothought = solothought.reset_index(level="idx", drop=True)# 或:solothought = solothought.droplevel("idx")
5、修改索引结构
solothought = solothought.set_index(("mandatory", "category")) # 使用 category 作为新的索引# 或者solothought.index.names = ["category"] # 重命名索引层名称
6、多级索引的意义
MultiIndex 的核心作用是在二维 DataFrame 中表达更复杂的数据关系。它常用于:
• 分组统计结果
• 数据透视表(pivot table)
• 多维数据表示
• 分层数据组织
通过多级索引,Pandas 能够在保持 DataFrame 结构的同时表示 更高维度的数据模型。
📘 小结
本文通过图解方式介绍了 Pandas 的核心结构与基本操作,包括 DataFrame 与 Series 的关系、索引体系、数据选择与条件筛选、数据清洗、分组统计以及多级索引等内容。通过理解这些基础机制,可以建立对 Pandas 数据结构与常见数据处理流程的整体认识,为后续数据分析与实践应用打下基础。
特别声明:
本文的基本框架、示例及所有图片来自以下网址,感谢原作者的辛勤工作。
https://solothought.com/tutorial/python-pandas-visual/

“点赞有美意,赞赏是鼓励”
更多推荐



所有评论(0)