Skip to content

第五章 Pandas :序列与数据框 ​

本章定位:Pandas 是 Python 数据分析领域的核心基础库,基于 NumPy 构建,专门用于处理结构化表格数据,提供了高效的数据清洗、筛选、转换、汇总与分析工具,是数据挖掘、数据分析、自动化办公的必备工具。

前置准备:使用前需安装 Pandas 库:pip install pandas 行业惯例导入方式:

python
import pandas as pd
import numpy as np  # Pandas 常与 NumPy 搭配使用

学习目标:掌握 Series 序列与 DataFrame 数据框的创建、外部数据读写、数据清洗、子集筛选、合并连接与分组汇总,能独立完成基础的表格数据处理任务。


1 序列与数据框基础概念 ​

Pandas 有两大核心数据结构:序列(Series) 和 数据框(DataFrame),分别对应表格的“列”与“整张表”。

1.1 序列 Series ​

Series 是一维带标签的数组结构,要求内部元素数据类型一致,可理解为表格中的“一列数据”。

  • 每个元素都对应一个索引标签(默认从0开始的整数索引,可自定义)
  • 支持向量化运算,特性与 NumPy 数组类似
  • 同时具备数组的运算能力和字典的索引访问能力

1.2 数据框 DataFrame ​

DataFrame 是二维表格型结构,由多个 Series 按列组合而成;每一列可以是不同的数据类型(数值、字符串、日期等),对应表格的“整张数据表”。

  • 既有行索引(index),也有列索引(columns)
  • 每一列都是一个 Series 对象
  • 支持丰富的表格操作,是数据分析的核心载体

1.3 核心结构对比 ​

结构维度数据类型要求对应表格概念核心作用
Series一维元素类型必须一致表格的一列单列数据处理与运算
DataFrame二维每列类型可不同整张表格多列结构化数据处理

2 序列与数据框的构造 ​

2.1 序列 Series 的构造 ​

语法:pd.Series(data, index=None, dtype=None)

数据来源代码示例说明
从列表/元组创建```python
s = pd.Series([10, 20, 30, 40])
print(s)
|
| 自定义索引 | ```python
s = pd.Series([10, 20, 30], index=['a', 'b', 'c'])
print(s)
``` | index 参数指定行标签 |
| 从字典创建 | ```python
s = pd.Series({"苹果": 5, "香蕉": 3, "橙子": 4})
print(s)
``` | 字典键作为索引,值作为元素 |
| 从 NumPy 数组创建 | ```python
s = pd.Series(np.arange(5))
print(s)
``` | 数组元素转为序列元素 |

### 2.2 数据框 DataFrame 的构造
语法:`pd.DataFrame(data, index=None, columns=None)`

#### 方式1:从“列名-列表”字典创建(最常用)
字典的键为列名,值为对应列的数据列表。
```python
data = {
    "姓名": ["张三", "李四", "王五"],
    "年龄": [20, 21, 19],
    "成绩": [85.5, 92.0, 78.5]
}
df = pd.DataFrame(data)
print(df)

方式2:从二维数组创建 + 指定列名 ​

python
arr = np.array([[1, 2, 3], [4, 5, 6]])
df = pd.DataFrame(arr, columns=["A列", "B列", "C列"], index=["行1", "行2"])
print(df)

方式3:从字典列表创建 ​

每个字典代表一行数据。

python
data = [
    {"姓名": "张三", "年龄": 20},
    {"姓名": "李四", "年龄": 21}
]
df = pd.DataFrame(data)
print(df)

提示

创建 DataFrame 时,若各列数据长度不一致会触发报错;缺失位置会自动填充为 NaN。


3 外部数据读取 ​

Pandas 支持读取多种格式的外部数据,直接加载为 DataFrame,是数据导入的核心方式。

3.1 文本/表格文件读取 ​

函数适用格式核心说明
pd.read_csv()CSV 逗号分隔文件最常用,专门读取 CSV 格式表格
pd.read_table()TXT/CSV 等文本表格通用文本表格读取,可指定分隔符
pd.read_excel()Excel 文件(.xlsx/.xls)读取 Excel 电子表格,需额外安装 openpyxl 依赖库

基础示例 ​

python
# 读取 CSV 文件
df = pd.read_csv("data.csv", encoding="utf-8")

# 读取带分隔符的 TXT 文件,sep 指定分隔符
df = pd.read_table("data.txt", sep="\t", encoding="utf-8")

# 读取 Excel 文件,指定工作表
df = pd.read_excel("data.xlsx", sheet_name="Sheet1")

常用参数

  • sep:指定分隔符,read_csv 默认 ,
  • encoding:指定文件编码,中文文件常用 utf-8/gbk
  • header:指定第几行作为表头,默认第 0 行
  • index_col:指定某列作为行索引
  • nrows:只读取前 N 行数据

3.2 数据库数据读取 ​

可直接从关系型数据库(如 MySQL)中读取 SQL 查询结果为 DataFrame。

前置依赖:需安装数据库驱动库,MySQL 场景需安装 pymysql:pip install pymysql

python
import pymysql

# 1. 创建数据库连接
con = pymysql.connect(
    host="localhost",
    user="root",
    password="数据库密码",
    database="数据库名",
    port=3306,
    charset="utf8"
)

# 2. 执行 SQL 并读取为 DataFrame
sql = "SELECT * FROM 表名"
df = pd.read_sql(sql, con)

# 3. 关闭连接
con.close()

4 数据清洗 ​

数据清洗是数据分析的核心前置步骤,包括类型转换、重复值处理、缺失值处理、异常值处理等,直接决定后续分析结果的准确性。

4.1 数据类型转换 ​

(1)通用类型转换:astype() ​

用于数值、字符串、布尔型等类型的转换。

python
# 将年龄列转换为浮点型
df["年龄"] = df["年龄"].astype("float64")

# 转为字符串类型
df["姓名"] = df["姓名"].astype("str")

(2)日期时间转换:pd.to_datetime() ​

专门用于日期格式转换,支持识别多种日期字符串格式。

python
# 将日期字符串列转换为日期类型,format 指定原数据的格式
df["日期"] = pd.to_datetime(df["日期"], format="%Y-%m-%d")

4.2 描述性统计 ​

describe() 可以快速生成数据的统计概览,默认只统计数值型列。

python
# 默认统计数值型列:计数、均值、标准差、最小值、四分位数、最大值
print(df.describe())

# 包含离散型(object)列的统计:计数、唯一值数、众数、最高频
print(df.describe(include="object"))

4.3 重复值处理 ​

函数/方法功能
df.duplicated()识别重复行,返回布尔 Series,重复行为 True
df.drop_duplicates()删除重复行,默认保留第一条
python
# 查看所有重复行
print(df[df.duplicated()])

# 删除重复行,keep='last' 保留最后一条
df = df.drop_duplicates(keep="first")

4.4 缺失值处理 ​

(1)缺失值识别 ​

方法功能
df.isnull()识别缺失值,缺失处为 True
df.notnull()识别非缺失值,非缺失处为 True,是 isnull() 的反函数
python
# 统计每列缺失值数量
print(df.isnull().sum())

(2)缺失值删除 ​

方法功能
df.dropna()删除包含缺失值的行/列
df.drop(labels, axis)删除指定的行或列
del df["列名"]直接删除指定列

drop() 核心参数:

  • labels:待删除的行名或列名
  • axis:删除轴,0 删除行,1 删除列
python
# 删除所有包含缺失值的行
df1 = df.dropna(axis=0)

# 删除指定多列
df2 = df.drop(["无用列1", "无用列2"], axis=1)

# 直接删除列(无返回值,直接修改原数据)
del df["废弃列"]

(3)缺失值填充:fillna() ​

支持多种填充策略,满足不同业务场景需求。

python
# 1. 常数填充
df["列名"] = df["列名"].fillna(0)

# 2. 前向填充(用上一行的值填充)
df["列名"] = df["列名"].fillna(method="ffill")

# 3. 后向填充(用下一行的值填充)
df["列名"] = df["列名"].fillna(method="bfill")

# 4. 统计值填充
# 数值型:均值填充
df["年龄"] = df["年龄"].fillna(df["年龄"].mean())
# 数值型:中位数填充(受异常值影响小)
df["收入"] = df["收入"].fillna(df["收入"].median())
# 离散型:众数填充
df["城市"] = df["城市"].fillna(df["城市"].mode()[0])

4.5 异常值处理 ​

异常值指偏离整体数据分布的极端值,常用两种识别方法:

方法1:3σ 法(标准差法) ​

数据落在均值 ± 3倍标准差范围内视为正常,超出则判定为异常值。

python
col = df["目标列"]
mean_val = col.mean()
std_val = col.std()

# 计算正常范围上下界
upper = mean_val + 3 * std_val
lower = mean_val - 3 * std_val

# 筛选出异常值
outliers = df[(col > upper) | (col < lower)]
print("识别出的异常值:\n", outliers)

# 保留正常数据
df_normal = df[(col <= upper) & (col >= lower)]

方法2:箱线图判别法 ​

基于四分位数计算:上限 = Q3 + 1.5×IQR,下限 = Q1 - 1.5×IQR,超出范围为异常值。

python
col = df["目标列"]
Q1 = col.quantile(0.25)  # 下四分位数
Q3 = col.quantile(0.75)  # 上四分位数
IQR = Q3 - Q1  # 四分位距

upper = Q3 + 1.5 * IQR
lower = Q1 - 1.5 * IQR

# 筛选正常数据
df_normal = df[(col <= upper) & (col >= lower)]

5 数据子集筛选 ​

Pandas 提供了多种索引方式来筛选数据,可根据索引类型选择对应方法。

5.1 iloc:位置索引(整数索引) ​

通过整数位置筛选数据,和 Python 列表切片规则一致,前闭后开。 语法:df.iloc[行索引, 列索引]

python
# 取第 0 行整行
print(df.iloc[0])

# 取第 0 到 2 行(不包含 2),第 1 到 3 列(不包含 3)
print(df.iloc[0:2, 1:3])

# 用整数列表指定离散位置
print(df.iloc[[0, 2], [0, 2]])

5.2 loc:标签索引 ​

通过行标签/列标签名筛选数据,包含起止两端,即前闭后闭;也支持条件表达式筛选。 语法:df.loc[行条件/行标签, 列标签]

(1)标签筛选 ​

python
# 行标签为 'row1' 的行,列名为 '姓名'、'成绩' 的列
print(df.loc["row1", ["姓名", "成绩"]])

# 行标签从 'a' 到 'c',所有列
print(df.loc["a":"c", :])

(2)条件筛选(最常用) ​

python
# 筛选年龄大于20的行
print(df.loc[df["年龄"] > 20, :])

# 多条件筛选:年龄>20 且 成绩>80
print(df.loc[(df["年龄"] > 20) & (df["成绩"] > 80), :])

注意

多条件筛选时,每个条件必须用括号包裹,逻辑运算符用 &(且)、|(或),不能使用 and/or。

5.3 ix:混合索引 ​

ix 是 iloc 与 loc 的混合模式,既支持位置索引也支持标签索引。

⚠️ 注意:目前官方已不推荐使用 ix,建议根据场景明确使用 iloc 或 loc,避免索引歧义。

5.4 索引设置与重置 ​

方法功能
df.set_index("列名")将指定列设为行索引
df.reset_index(drop=False, inplace=False)重置为默认整数索引

参数说明:

  • drop=True:丢弃原索引;False:原索引转为普通列
  • inplace=True:直接修改原数据框;False:返回新对象
python
# 将姓名列设为行索引
df = df.set_index("姓名")

# 重置索引,丢弃原索引
df = df.reset_index(drop=True)

补充

NumPy 的通用函数(如 np.abs()、np.mean()、np.sum()等),大多可直接作用于 Pandas 的 Series 和 DataFrame 对象。

5.5 apply:函数应用 ​

apply() 可以将自定义函数应用到每一行或每一列,实现批量自定义处理。

  • axis=0(默认):函数作用于每一列
  • axis=1 / axis="columns":函数作用于每一行
python
# 对每一列应用求和函数
print(df.apply(np.sum, axis=0))

# 对每一行应用自定义函数,计算总分
def get_total(row):
    return row["语文"] + row["数学"] + row["英语"]

df["总分"] = df.apply(get_total, axis=1)

6 数据的合并与连接 ​

6.1 数据拼接:pd.concat() ​

将多个 DataFrame 按行或按列直接拼接,类似“堆叠”,不做关联匹配。

python
# 纵向拼接(行堆叠),要求各表列数、列名一致
df_all = pd.concat([df1, df2, df3], axis=0)

# 横向拼接(列合并),要求各表行数一致
df_all = pd.concat([df1, df2], axis=1)

6.2 数据连接:pd.merge() ​

类似 SQL 的表连接,根据共同的键列将两个表关联起来,支持多种连接模式。 语法:pd.merge(left, right, on="关联列", how="inner")

how 连接方式参数:

  • inner:内连接,只保留两边都匹配的行(默认)
  • left:左连接,保留左表所有行,右表匹配填充
  • right:右连接,保留右表所有行
  • outer:外连接,保留两边所有行
python
# 内连接,根据 id 列关联
df_merge = pd.merge(df1, df2, on="id", how="inner")

# 左连接,左右表关联列名不同时分别指定
df_merge = pd.merge(df1, df2, left_on="用户id", right_on="id", how="left")

7 数据汇总与透视表 ​

7.1 分组统计 groupby ​

按指定列分组,然后对各组进行统计汇总。

python
# 按城市分组,计算各组年龄、成绩的均值
df_group = df.groupby("城市")[["年龄", "成绩"]].mean()

# 多维度分组 + 多指标聚合
df_group = df.groupby(["城市", "性别"]).agg(
    人数=("姓名", "count"),
    平均年龄=("年龄", "mean"),
    最高成绩=("成绩", "max")
)

7.2 透视表 pivot_table ​

快速生成交叉汇总透视表,类似 Excel 的数据透视表功能。 语法:pd.pivot_table(data, index=行分组, columns=列分组, values=值列, aggfunc='mean')

python
# 行:城市;列:性别;值:成绩;聚合方式:均值
pivot = pd.pivot_table(
    df,
    index="城市",
    columns="性别",
    values="成绩",
    aggfunc="mean"
)
print(pivot)

本章练习 ​

基础题 ​

  1. 创建一个包含姓名、年龄、城市、成绩 4 列的学生 DataFrame,包含 5 条测试数据。
  2. 将上述数据保存为 CSV 文件,再重新读取出来,查看各列的数据类型。
  3. 为上述数据新增 2 条重复数据,识别并删除重复值。
  4. 将成绩列的缺失值用均值填充,然后筛选出成绩大于 80 分的学生。
  5. 按城市分组,统计每个城市的平均成绩和学生人数。

进阶题 ​

  1. 读取一个 Excel 销售表格,完成完整数据清洗:去除空列、转换日期格式、填充缺失值、识别并处理异常值。
  2. 有订单表和用户表,根据用户 ID 将两表左连接,计算每个用户的订单总金额。
  3. 生成销售数据透视表:行维度为月份,列维度为产品类别,值为销售额,聚合方式为求和。

本章常见易错点 ​

  1. iloc 与 loc 混淆:iloc 是整数位置、前闭后开;loc 是标签、前闭后闭,注意区分使用场景。
  2. 多条件筛选括号缺失:多条件筛选时每个条件必须加括号,否则运算符优先级会导致结果错误。
  3. drop 的 axis 搞反:axis=0 删除行,axis=1 删除列,记忆口诀:0行1列。
  4. fillna 不生效:fillna 默认返回新对象,需要赋值接收,或使用 inplace=True 参数。
  5. 分组后索引变化:groupby 后分组列会变成索引,需要保留列可使用 reset_index() 或 as_index=False。
  6. merge 列名不匹配:左右表关联列名不同时,需用 left_on 和 right_on 分别指定。

基于 Vite 强力驱动 | 纯静态轻量托管