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/

图片

“点赞有美意,赞赏是鼓励”

更多推荐