Python pandas 从零到精通自学手册
本手册专为掌握 Python 基础语法(变量、循环、函数、列表、字典)但无 pandas 经验的学习者设计,按“基础→进阶→实战”逻辑分章节讲解,内容详尽、可落地,适合反复查阅自学。
第1章:pandas 简介与安装
1.1 核心概念
pandas 是 Python 生态中用于数据处理与分析的核心库,专为表格型数据(如 Excel 表格、CSV 文件)设计,能高效完成数据读取、清洗、变换、分析等全流程工作,是数据分析、机器学习的必备工具。
简单来说,pandas 让 Python 处理表格数据像 Excel 一样直观,但功能更强大、自动化程度更高,支持海量数据快速运算。
1.2 安装方法
1.2.1 常用安装命令
通过 pip 安装(推荐,适用于绝大多数环境):
# 安装最新稳定版
pip install pandas
# 安装指定版本(避免版本兼容问题)
pip install pandas==2.1.4若使用 Anaconda 环境(数据分析常用),自带 pandas,无需额外安装;若缺失,可通过以下命令安装:
conda install pandas1.2.2 验证安装
安装完成后,在 Python 脚本或 Jupyter Notebook 中执行以下代码,无报错则安装成功:
import pandas as pd # 惯例缩写为 pd,简化后续调用
print(pd.__version__) # 打印版本号,确认安装成功1.3 常见错误与小贴士
常见错误
- pip 命令找不到:需配置 Python 环境变量,或使用
python -m pip install pandas替代。 - 安装速度慢:可切换国内镜像源,如
pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple。
小贴士
- 始终使用
import pandas as pd导入 pandas,这是行业通用惯例,可提高代码可读性。 - 建议搭配 Jupyter Notebook 学习,能逐行运行代码、实时查看结果,更适合数据分析实操。
第2章:Series 与 DataFrame 基础
pandas 有两个核心数据结构:Series(一维数据)和 DataFrame(二维数据),所有数据分析操作都围绕这两个结构展开。
2.1 Series 核心概念与操作
2.1.1 概念
Series 是带标签的一维数组,可理解为“单列表格”,包含两个部分:
- values:数据本身(可是数值、字符串、布尔值等);
- index:标签(默认是 0、1、2... 整数索引,也可自定义)。
2.1.2 常用方法与代码示例
import pandas as pd
# 1. 创建 Series(默认整数索引)
s1 = pd.Series([10, 20, 30, 40, 50])
print("默认索引的 Series:")
print(s1)
# 输出包含 index 和 values,dtype 是数据类型(此处为 int64)
# 2. 自定义索引
s2 = pd.Series([10, 20, 30, 40, 50], index=["a", "b", "c", "d", "e"])
print("\n自定义索引的 Series:")
print(s2)
# 3. 从字典创建 Series(字典的键作为索引,值作为数据)
dict_data = {"苹果": 5.99, "香蕉": 3.59, "橙子": 4.29}
s3 = pd.Series(dict_data)
print("\n从字典创建的 Series:")
print(s3)
# 4. 访问 Series 数据
print("\n访问索引为 'b' 的值:", s2["b"]) # 按标签访问
print("访问第 2 个元素(按位置,从 0 开始):", s2.iloc[1]) # 按位置访问
print("访问前 3 个元素:")
print(s2.head(3))
# 5. Series 基本属性
print("\nSeries 的索引:", s2.index)
print("Series 的值:", s2.values)
print("Series 的数据类型:", s2.dtype)
print("Series 的长度:", len(s2))2.2 DataFrame 核心概念与操作
2.2.1 概念
DataFrame 是带标签的二维表格数据结构,可理解为“Excel 工作表”,包含:
- 行索引(index):每行的标签;
- 列索引(columns):每列的标签;
- 数据(values):表格中的具体内容。
2.2.2 常用方法与代码示例
import pandas as pd
# 1. 从字典创建 DataFrame(字典的键为列名,值为列数据)
data = {
"姓名": ["张三", "李四", "王五", "赵六"],
"年龄": [22, 25, 23, 24],
"性别": ["男", "男", "女", "男"],
"薪资": [8000, 9500, 8800, 10000]
}
df = pd.DataFrame(data)
print("默认索引的 DataFrame:")
print(df)
# 2. 自定义行索引
df2 = pd.DataFrame(data, index=["员工1", "员工2", "员工3", "员工4"])
print("\n自定义行索引的 DataFrame:")
print(df2)
# 3. 从列表嵌套列表创建 DataFrame(需指定列名)
list_data = [
["张三", 22, "男", 8000],
["李四", 25, "男", 9500],
["王五", 23, "女", 8800]
]
df3 = pd.DataFrame(list_data, columns=["姓名", "年龄", "性别", "薪资"])
print("\n从列表嵌套列表创建的 DataFrame:")
print(df3)
# 4. DataFrame 基本属性
print("\nDataFrame 的行索引:", df2.index)
print("DataFrame 的列索引:", df2.columns)
print("DataFrame 的数据:")
print(df2.values)
print("DataFrame 的形状(行数, 列数):", df2.shape) # 输出 (4,4)
print("DataFrame 的数据类型:")
print(df2.dtypes)
# 5. 访问列数据(两种方式)
print("\n访问 '薪资' 列(方式1):")
print(df2["薪资"]) # 返回 Series 类型
print("访问 '姓名' 列(方式2,仅列名无空格时可用):")
print(df2.姓名)2.3 常见错误与小贴士
常见错误
- 列名访问报错:若列名包含空格(如“月 薪”),无法使用
df.列名方式,需用df["列名"]。 - Series 与列表混淆:Series 带索引,列表无索引,直接用列表方法操作 Series 会报错(如 Series 无 append 方法,需用 pd.concat)。
小贴士
- DataFrame 是 pandas 最常用的数据结构,后续所有操作(清洗、变换、分析)均以它为核心。
- 若需创建空的 DataFrame 用于后续数据填充,可使用
df_empty = pd.DataFrame(columns=["列1", "列2"])。
第3章:数据读取与写入(CSV/Excel等)
实际数据分析中,数据常存储在外部文件(CSV、Excel 等),pandas 提供了便捷的读写方法,无需手动解析文件。
3.1 核心方法概述
常用文件格式及对应读写方法:
| 文件格式 | 读取方法 | 写入方法 |
|---|---|---|
| CSV | pd.read_csv() | df.to_csv() |
| Excel | pd.read_excel() | df.to_excel() |
| JSON | pd.read_json() | df.to_json() |
3.2 CSV 文件读写(最常用)
3.2.1 读取 CSV
import pandas as pd
# 读取本地 CSV 文件(需指定正确路径,相对路径/绝对路径均可)
# 常用参数说明:
# - sep:分隔符,默认逗号(,),若为制表符分隔用 sep="\t"
# - header:表头行,默认第 0 行(即第一行),无表头用 header=None
# - names:无表头时,指定列名列表
# - encoding:编码格式,中文文件常用 encoding="utf-8" 或 "gbk"
# 示例1:读取带表头的 CSV
df = pd.read_csv("employee_data.csv", encoding="utf-8")
print("读取的 CSV 数据:")
print(df.head())
# 示例2:读取无表头的 CSV,指定列名
df_no_header = pd.read_csv(
"no_header_data.csv",
header=None,
names=["姓名", "年龄", "性别", "薪资"],
encoding="gbk"
)
print("\n无表头 CSV 读取结果:")
print(df_no_header)3.2.2 写入 CSV
import pandas as pd
# 准备数据
data = {
"姓名": ["张三", "李四", "王五"],
"年龄": [22, 25, 23],
"薪资": [8000, 9500, 8800]
}
df = pd.DataFrame(data)
# 写入 CSV 文件
# 常用参数说明:
# - index:是否写入行索引,默认 True,通常设为 False(避免多余列)
# - encoding:编码格式,中文文件用 "utf-8" 或 "gbk"
# - sep:分隔符,默认逗号
# - na_rep:缺失值替换为指定字符串,如 na_rep="未知"
df.to_csv(
"output_employee.csv",
index=False, # 不写入行索引
encoding="utf-8",
na_rep="未知"
)
print("CSV 文件写入完成!")3.3 Excel 文件读写
读取 Excel 文件需额外安装依赖库 openpyxl(读取 .xlsx 格式)和 xlrd(读取 .xls 格式):
pip install openpyxl xlrd3.3.1 读取 Excel
import pandas as pd
# 读取 Excel 文件(默认读取第一个工作表)
df = pd.read_excel("sales_data.xlsx", encoding="utf-8")
print("默认工作表数据:")
print(df.head())
# 读取指定工作表(两种方式)
df_sheet1 = pd.read_excel("sales_data.xlsx", sheet_name="工作表1") # 按工作表名
df_sheet2 = pd.read_excel("sales_data.xlsx", sheet_name=1) # 按索引(0 开始)
print("\n指定工作表数据:")
print(df_sheet1.head())
# 读取指定列
df_cols = pd.read_excel("sales_data.xlsx", usecols=["商品名", "销售额", "日期"])
print("\n指定列数据:")
print(df_cols.head())3.3.2 写入 Excel
import pandas as pd
# 准备数据
df1 = pd.DataFrame({"商品名": ["A", "B", "C"], "销售额": [1000, 1500, 1200]})
df2 = pd.DataFrame({"商品名": ["D", "E", "F"], "销售额": [800, 2000, 1800]})
# 写入 Excel,多个 DataFrame 对应多个工作表
with pd.ExcelWriter("output_sales.xlsx", engine="openpyxl") as writer:
df1.to_excel(writer, sheet_name="第一季度", index=False)
df2.to_excel(writer, sheet_name="第二季度", index=False)
print("Excel 文件写入完成!")3.4 常见错误与小贴士
常见错误
- 文件路径错误:若文件不在当前工作目录,需写绝对路径(如
"C:/data/employee.csv"),或先通过os.chdir()切换工作目录。 - 编码错误:中文文件读取报错时,尝试切换
encoding="gbk"或encoding="utf-8-sig"(处理带 BOM 的 UTF-8 文件)。 - Excel 读取报错:未安装 openpyxl/xlrd 库,或文件格式为 .xlsb(需额外安装 pyxlsb 库)。
小贴士
- 读取大文件时,可使用
chunksize参数分块读取(如pd.read_csv("big_data.csv", chunksize=10000)),避免内存溢出。 - 写入 CSV 时,优先设置
index=False,否则会多一列无意义的行索引。
第4章:查看与探索数据(head, info, describe 等)
拿到数据后,第一步需快速探索数据的基本情况(结构、缺失值、统计特征等),pandas 提供了多个便捷方法,无需手动计算。
4.1 核心方法详解(带代码示例)
先准备一份模拟数据,用于后续演示:
import pandas as pd
import numpy as np # 用于生成缺失值
# 模拟电商订单数据
data = {
"订单ID": [1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008],
"用户ID": [1, 2, 1, 3, 2, 3, 4, 4],
"商品类别": ["家电", "服饰", "家电", "食品", "服饰", "食品", "家电", np.nan], # np.nan 表示缺失值
"订单金额": [2999, 599, 1299, 89, 799, 159, 3499, 1999],
"订单日期": ["2026-01-01", "2026-01-02", "2026-01-02", "2026-01-03",
"2026-01-03", "2026-01-04", "2026-01-04", "2026-01-05"],
"支付状态": ["已支付", "已支付", "未支付", "已支付", "已支付", "未支付", "已支付", "已支付"]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)4.1.1 查看数据前/后几行(head/tail)
# head(n):查看前 n 行,默认 n=5
print("前 3 行数据:")
print(df.head(3))
# tail(n):查看后 n 行,默认 n=5
print("\n后 2 行数据:")
print(df.tail(2))4.1.2 查看数据基本信息(info)
# info():查看行数、列数、各列数据类型、非空值数量
print("数据基本信息:")
print(df.info())
# 输出解读:共 8 行、6 列;商品类别列有 1 个缺失值(Non-Null Count 为 7);订单日期为 object 类型(字符串)4.1.3 查看数值型数据统计特征(describe)
# describe():默认统计数值型列(int/float)的计数、均值、标准差、最值、分位数
print("数值型数据统计特征:")
print(df.describe())
# 统计所有列(包括字符串列)的唯一值数量、最频繁值等
print("\n所有列的统计特征:")
print(df.describe(include="all"))4.1.4 查看缺失值与唯一值
# 1. 查看每列缺失值数量(isnull().sum())
print("每列缺失值数量:")
print(df.isnull().sum())
# 2. 查看每列唯一值数量(nunique())
print("\n每列唯一值数量:")
print(df.nunique())
# 3. 查看指定列的唯一值(unique())
print("\n商品类别唯一值:")
print(df["商品类别"].unique())
# 4. 查看指定列唯一值的计数(value_counts())
print("\n各商品类别订单数量:")
print(df["商品类别"].value_counts()) # 忽略缺失值,默认按计数降序排列4.1.5 查看数据形状与列名
# 查看数据形状(行数, 列数)
print("数据形状:", df.shape) # 输出 (8,6)
# 查看列名
print("列名列表:", df.columns.tolist()) # 转为列表格式,便于后续处理
# 查看行索引
print("行索引:", df.index.tolist())4.2 常见错误与小贴士
常见错误
- value_counts() 包含缺失值:默认忽略缺失值,若需统计缺失值,需设置
dropna=False(如df["商品类别"].value_counts(dropna=False))。 - describe() 无字符串列统计:默认仅统计数值型列,需指定
include="all"才会包含字符串列。
小贴士
- 数据探索的常规流程:
head()看结构 →info()查缺失值和数据类型 →describe()看统计特征 →value_counts()分析分类变量分布。 - 若数据量较大(万行以上),
head(100)查看前 100 行即可,避免输出过多内容影响效率。
第5章:索引与选择(loc, iloc, 条件筛选)
数据分析中常需筛选特定行/列数据,pandas 提供了三种核心选择方式:按标签(loc)、按位置(iloc)、条件筛选,需严格区分使用场景。
5.1 按标签选择(loc)
5.1.1 概念
loc 基于行索引标签和列名选择数据,语法:df.loc[行标签, 列名],支持单个标签、标签列表、切片(包含终点)。
5.1.2 代码示例
import pandas as pd
# 沿用第4章的订单数据,先自定义行索引(便于演示标签选择)
df = pd.DataFrame({
"订单ID": [1001, 1002, 1003, 1004, 1005],
"商品类别": ["家电", "服饰", "家电", "食品", "服饰"],
"订单金额": [2999, 599, 1299, 89, 799],
"支付状态": ["已支付", "已支付", "未支付", "已支付", "已支付"]
}, index=["订单1", "订单2", "订单3", "订单4", "订单5"]) # 自定义行标签
# 1. 选择单个行(按行标签)
print("选择 '订单2' 行:")
print(df.loc["订单2"])
# 2. 选择多个行(标签列表)
print("\n选择 '订单1' 和 '订单4' 行:")
print(df.loc[["订单1", "订单4"]])
# 3. 选择行切片(包含起点和终点)
print("\n选择 '订单2' 到 '订单4' 行:")
print(df.loc["订单2":"订单4"])
# 4. 选择指定行和列(行标签+列名)
print("\n选择 '订单1' 和 '订单3' 的 '商品类别' 和 '订单金额' 列:")
print(df.loc[["订单1", "订单3"], ["商品类别", "订单金额"]])
# 5. 选择所有行,指定列
print("\n选择所有行的 '订单ID' 和 '支付状态' 列:")
print(df.loc[:, ["订单ID", "支付状态"]])5.2 按位置选择(iloc)
5.2.1 概念
iloc 基于行位置和列位置选择数据(类似 Python 列表切片),语法:df.iloc[行位置, 列位置],位置从 0 开始,切片不包含终点。
5.2.2 代码示例
import pandas as pd
# 沿用上述自定义行索引的数据
df = pd.DataFrame({
"订单ID": [1001, 1002, 1003, 1004, 1005],
"商品类别": ["家电", "服饰", "家电", "食品", "服饰"],
"订单金额": [2999, 599, 1299, 89, 799],
"支付状态": ["已支付", "已支付", "未支付", "已支付", "已支付"]
}, index=["订单1", "订单2", "订单3", "订单4", "订单5"])
# 1. 选择单个行(按位置)
print("选择第 2 行(位置 1):")
print(df.iloc[1])
# 2. 选择多个行(位置列表)
print("\n选择第 1 行和第 4 行(位置 0 和 3):")
print(df.iloc[[0, 3]])
# 3. 选择行切片(不包含终点)
print("\n选择第 2 行到第 4 行(位置 1 到 3,终点 4 不包含):")
print(df.iloc[1:4])
# 4. 选择指定行和列(位置组合)
print("\n选择第 1、3 行(位置 0、2)的第 2、3 列(位置 1、2):")
print(df.iloc[[0, 2], [1, 2]])
# 5. 选择所有行,前 2 列
print("\n选择所有行的前 2 列:")
print(df.iloc[:, :2])5.3 条件筛选
5.3.1 概念
基于条件表达式筛选数据,返回满足条件的行,支持单个条件、多个条件组合,是实际分析中最常用的选择方式。
5.3.2 代码示例
import pandas as pd
# 沿用订单数据
df = pd.DataFrame({
"订单ID": [1001, 1002, 1003, 1004, 1005],
"商品类别": ["家电", "服饰", "家电", "食品", "服饰"],
"订单金额": [2999, 599, 1299, 89, 799],
"支付状态": ["已支付", "已支付", "未支付", "已支付", "已支付"]
})
# 1. 单个条件筛选
# 筛选订单金额 > 1000 的行
df_high = df[df["订单金额"] > 1000]
print("订单金额 > 1000 的数据:")
print(df_high)
# 筛选商品类别为 "家电" 的行
df_elect = df[df["商品类别"] == "家电"]
print("\n商品类别为家电的数据:")
print(df_elect)
# 2. 多个条件筛选(& 表示且,| 表示或,条件需用 () 包裹)
# 筛选家电类且金额 > 2000 的行
df_elect_high = df[(df["商品类别"] == "家电") & (df["订单金额"] > 2000)]
print("\n家电类且金额 > 2000 的数据:")
print(df_elect_high)
# 筛选服饰类或未支付的行
df_cloth_unpaid = df[(df["商品类别"] == "服饰") | (df["支付状态"] == "未支付")]
print("\n服饰类或未支付的数据:")
print(df_cloth_unpaid)
# 3. isin() 筛选(属于某个列表中的值)
# 筛选商品类别为家电或食品的行
df_filter = df[df["商品类别"].isin(["家电", "食品"])]
print("\n商品类别为家电或食品的数据:")
print(df_filter)5.4 常见错误与小贴士
常见错误
- loc 与 iloc 混淆:用 iloc 传入标签(如行索引“订单1”)或用 loc 传入位置(如 0)会报错,需严格区分“标签”和“位置”。
- 多个条件用 and/or:pandas 中多个条件组合需用 &(且)、
|(或),而非 Python 内置的 and/or,否则会报错。 - SettingWithCopyWarning:筛选后直接修改数据(如
df[df["金额"]>1000]["金额"] = 0)会触发警告,本质是 pandas 无法确定修改的是原数据还是副本,后续章节会详细讲解解决方案。
小贴士
- 何时用 loc 而非 []:当需要按标签选择、同时选择行和列,或需要保证选择逻辑明确时,优先用 loc;[] 语法简洁但功能有限,且容易混淆标签和位置。
- 条件筛选后若需修改数据,建议用
loc替代 [],如df.loc[df["金额"]>1000, "金额"] = 0,可避免警告。 - 复杂条件筛选可先定义条件变量,提高代码可读性,如
condition = (df["类别"] == "家电") & (df["金额"] > 1000),再用df[condition]筛选。
第6章:数据清洗(缺失值、重复值、类型转换)
原始数据常存在缺失值、重复值、数据类型错误等问题,需先清洗数据才能进行后续分析,数据清洗是数据分析的核心步骤(占比可达 60% 以上)。
6.1 缺失值处理
6.1.1 缺失值识别
pandas 中缺失值用 np.nan(数值型缺失)或 None(对象型缺失)表示,常用 isnull()、notnull() 识别。
import pandas as pd
import numpy as np
# 模拟含缺失值的数据
df = pd.DataFrame({
"姓名": ["张三", "李四", None, "赵六"],
"年龄": [22, np.nan, 23, 24],
"薪资": [8000, 9500, np.nan, 10000],
"部门": ["技术", "销售", "技术", None]
})
# 1. 查看每列缺失值数量
print("每列缺失值数量:")
print(df.isnull().sum())
# 2. 查看含缺失值的行
print("\n含缺失值的行:")
print(df[df.isnull().any(axis=1)]) # axis=1 表示按行判断,只要有一列缺失就保留6.1.2 缺失值处理方法
处理缺失值的核心原则:根据业务场景选择,避免盲目删除或填充。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"姓名": ["张三", "李四", None, "赵六"],
"年龄": [22, np.nan, 23, 24],
"薪资": [8000, 9500, np.nan, 10000],
"部门": ["技术", "销售", "技术", None]
})
# 方法1:删除缺失值(dropna())
# 1.1 删除含任何缺失值的行(默认 axis=0,how="any")
df_drop_any = df.dropna()
print("删除含任何缺失值的行:")
print(df_drop_any)
# 1.2 仅删除所有列都缺失的行(how="all")
df_drop_all = df.dropna(how="all")
print("\n仅删除所有列都缺失的行:")
print(df_drop_all)
# 1.3 按列删除缺失值(axis=1)
df_drop_col = df.dropna(axis=1, thresh=3) # thresh=3 表示至少有 3 个非缺失值才保留列
print("\n按列删除缺失值(至少3个非缺失值):")
print(df_drop_col)
# 方法2:填充缺失值(fillna())
# 2.1 用固定值填充
df_fill_fixed = df.fillna({"年龄": 25, "薪资": 8500, "姓名": "未知", "部门": "未知"})
print("\n用固定值填充缺失值:")
print(df_fill_fixed)
# 2.2 用均值/中位数填充数值型缺失值
df_fill_mean = df.copy()
df_fill_mean["年龄"] = df_fill_mean["年龄"].fillna(df_fill_mean["年龄"].mean()) # 均值
df_fill_mean["薪资"] = df_fill_mean["薪资"].fillna(df_fill_mean["薪资"].median()) # 中位数
print("\n用均值/中位数填充数值型缺失值:")
print(df_fill_mean)
# 2.3 用前一个值/后一个值填充(ffill/bfill)
df_fill_ffill = df.fillna(method="ffill") # ffill:forward fill,前向填充
df_fill_bfill = df.fillna(method="bfill") # bfill:backward fill,后向填充
print("\n前向填充缺失值:")
print(df_fill_ffill)6.2 重复值处理
6.2.1 重复值识别
用 duplicated() 识别重复行,返回布尔值 Series(True 表示重复行)。
6.2.2 重复值处理方法
import pandas as pd
# 模拟含重复值的数据
df = pd.DataFrame({
"姓名": ["张三", "李四", "张三", "赵六", "李四"],
"年龄": [22, 25, 22, 24, 25],
"薪资": [8000, 9500, 8000, 10000, 9500],
"部门": ["技术", "销售", "技术", "技术", "销售"]
})
# 1. 识别重复行(默认保留第一行,后续重复行为 True)
print("重复行识别(True 为重复行):")
print(df.duplicated())
# 2. 查看重复行
print("\n重复行数据:")
print(df[df.duplicated()])
# 3. 删除重复行(drop_duplicates())
# 3.1 保留第一行,删除后续重复行(默认)
df_drop_dup = df.drop_duplicates()
print("\n删除重复行(保留第一行):")
print(df_drop_dup)
# 3.2 保留最后一行,删除前面重复行
df_drop_dup_last = df.drop_duplicates(keep="last")
print("\n删除重复行(保留最后一行):")
print(df_drop_dup_last)
# 3.3 按指定列判断重复(仅这些列值相同即为重复)
df_drop_dup_col = df.drop_duplicates(subset=["姓名", "部门"], keep="first")
print("\n按姓名和部门判断重复并删除:")
print(df_drop_dup_col)6.3 数据类型转换
6.3.1 查看与转换数据类型
用 dtypes 查看数据类型,用 astype() 转换类型,特殊类型(如日期)需用 to_datetime() 转换。
import pandas as pd
# 模拟数据类型不规范的数据
df = pd.DataFrame({
"订单ID": [1001, 1002, 1003],
"订单金额": ["2999", "599", "1299"], # 字符串类型的数值
"订单日期": ["2026-01-01", "2026-01-02", "2026-01-03"], # 字符串类型的日期
"支付状态": [1, 1, 0] # 数值类型的布尔值(1=已支付,0=未支付)
})
# 1. 查看数据类型
print("原始数据类型:")
print(df.dtypes)
# 2. 转换数据类型
# 2.1 字符串转数值(astype())
df["订单金额"] = df["订单金额"].astype(float) # 转float类型
print("\n订单金额转float后:")
print(df.dtypes)
# 2.2 数值转布尔值
df["支付状态"] = df["支付状态"].astype(bool)
print("\n支付状态转布尔值后:")
print(df)
# 2.3 字符串转日期(to_datetime(),核心方法)
df["订单日期"] = pd.to_datetime(df["订单日期"])
print("\n订单日期转日期类型后:")
print(df.dtypes)
print("日期类型数据:", df["订单日期"].dt.year) # 可提取年、月、日等信息
# 3. 处理转换失败的情况(errors参数)
df_error = pd.DataFrame({"数值列": ["100", "200", "abc", "300"]})
# 直接转换会报错,用 errors="coerce" 将无法转换的值设为 np.nan
df_error["数值列"] = pd.to_numeric(df_error["数值列"], errors="coerce")
print("\n处理转换失败的数据:")
print(df_error)6.4 常见错误与小贴士
常见错误
- 数值转换失败:字符串列中包含非数值字符(如“abc”),直接用
astype(float)会报错,需先用pd.to_numeric(errors="coerce")处理。 - 日期转换失败:日期格式不统一(如同时存在“2026-01-01”和“2026/01/01”),需指定
format参数(如pd.to_datetime(df["日期"], format="%Y-%m-%d")),或用errors="coerce"处理异常值。 - 盲目删除缺失值:当缺失值占比过高(如超过 30%),直接删除会导致数据量不足,影响分析结果,建议优先填充或用其他方法处理。
小贴士
- 数据类型转换优先级:日期列优先转为
datetime64类型(便于后续时间序列分析),数值型列转为int/float(便于统计计算)。 - 重复值判断需结合业务场景:有时需按关键列(如订单ID)判断,而非全列,避免误删有效数据。
- 填充缺失值时,数值型用均值(分布均匀)或中位数(存在异常值),分类列用众数(最频繁值),确保填充逻辑合理。
第7章:数据变换(新增列、apply、map、字符串/日期处理)
数据变换是指对现有数据进行加工处理,生成新的特征或调整数据格式,为后续分析提供更有价值的数据,核心方法包括新增列、apply/map、字符串处理、日期处理等。
7.1 新增列
基于现有列计算或直接赋值,生成新列,是特征工程的基础操作。
import pandas as pd
# 模拟数据
df = pd.DataFrame({
"商品名": ["A", "B", "C", "D"],
"单价": [100, 200, 150, 300],
"销量": [50, 30, 40, 25],
"成本": [60, 120, 90, 180]
})
# 1. 基于现有列计算新增列
# 新增“销售额”列(单价 * 销量)
df["销售额"] = df["单价"] * df["销量"]
# 新增“利润”列(销售额 - 成本 * 销量)
df["利润"] = df["销售额"] - (df["成本"] * df["销量"])
# 新增“利润率”列(利润 / 销售额)
df["利润率"] = (df["利润"] / df["销售额"]).round(4) # round(4) 保留4位小数
print("新增列后的数据:")
print(df)
# 2. 条件赋值新增列
# 新增“销量等级”列:销量>40为“A级”,20-40为“B级”,<20为“C级”
df["销量等级"] = pd.cut(
df["销量"],
bins=[0, 20, 40, 100], # 区间边界
labels=["C级", "B级", "A级"], # 区间对应标签
right=False # 左闭右开区间(如 [0,20) 为 C级)
)
print("\n条件赋值新增列:")
print(df[["商品名", "销量", "销量等级"]])
# 3. 直接赋值新增列(固定值或列表)
df["品牌"] = "XX品牌" # 固定值
df["批次"] = ["202601", "202601", "202602", "202602"] # 列表(长度需与行数一致)
print("\n直接赋值新增列:")
print(df[["商品名", "品牌", "批次"]])7.2 apply 与 map 方法
apply 用于对行/列执行自定义函数,map 用于对 Series 元素执行映射(一对一转换),是灵活处理数据的核心工具。
7.2.1 map 方法(仅用于 Series)
import pandas as pd
df = pd.DataFrame({
"商品名": ["A", "B", "C", "D"],
"类别": ["家电", "服饰", "家电", "食品"],
"销量": [50, 30, 40, 25]
})
# 1. 字典映射(替换值)
# 将“类别”列映射为中文全称
category_map = {"家电": "家用电器", "服饰": "服装鞋帽", "食品": "生鲜食品"}
df["类别全称"] = df["类别"].map(category_map)
# 2. 函数映射
# 对“销量”列进行标准化((销量 - 最小值) / (最大值 - 最小值))
def normalize_sales(x):
return (x - df["销量"].min()) / (df["销量"].max() - df["销量"].min())
df["销量标准化"] = df["销量"].map(normalize_sales)
print("map 方法处理后:")
print(df[["商品名", "类别", "类别全称", "销量", "销量标准化"]])7.2.2 apply 方法(Series/DataFrame 均可)
import pandas as pd
df = pd.DataFrame({
"单价": [100, 200, 150, 300],
"销量": [50, 30, 40, 25],
"成本": [60, 120, 90, 180]
})
# 1. 对 Series 用 apply(与 map 类似,更灵活)
df["利润"] = (df["单价"] - df["成本"]) * df["销量"]
# 用 apply 判断利润等级
def profit_level(profit):
if profit > 2000:
return "高利润"
elif profit > 1000:
return "中利润"
else:
return "低利润"
df["利润等级"] = df["利润"].apply(profit_level)
# 2. 对 DataFrame 用 apply(按行/列执行函数)
# 按列执行(默认 axis=0):计算每列的最大值
col_max = df.apply(lambda x: x.max(), axis=0)
print("每列最大值:")
print(col_max)
# 按行执行(axis=1):计算每行的“单价+成本”总和
df["单价成本和"] = df.apply(lambda x: x["单价"] + x["成本"], axis=1)
print("\napply 方法处理后:")
print(df[["单价", "成本", "利润", "利润等级", "单价成本和"]])7.3 字符串处理
pandas 为字符串列提供了 str 访问器,支持大小写转换、替换、分割、提取等常用操作,无需循环遍历元素。
import pandas as pd
# 模拟含字符串数据
df = pd.DataFrame({
"商品名": ["Apple-手机", "banana-耳机", "Xiaomi-电视", "华为-平板"],
"备注": [" 新品上架 ", "促销活动!", "限时折扣~~", "库存充足"],
"规格": ["128G", "无线款", "55英寸", "11英寸"]
})
# 1. 去除空格与特殊字符
df["备注_清理"] = df["备注"].str.strip() # 去除首尾空格
df["备注_无符号"] = df["备注_清理"].str.replace(r"[!~]", "", regex=True) # 正则替换特殊字符
# 2. 字符串分割
# 按 "-" 分割商品名,提取品牌和品类
df[["品牌", "品类"]] = df["商品名"].str.split("-", expand=True) # expand=True 返回 DataFrame
# 3. 字符串匹配与提取
# 判断商品名是否包含字母
df["含字母"] = df["商品名"].str.contains(r"[a-zA-Z]", regex=True)
# 从规格中提取数字
df["规格数值"] = df["规格"].str.extract(r"(\d+)", expand=False) # 提取第一个数字
# 4. 大小写转换
df["品牌大写"] = df["品牌"].str.upper() # 转大写
df["品类小写"] = df["品类"].str.lower() # 转小写
print("字符串处理后的数据:")
print(df[["商品名", "品牌", "品类", "备注", "备注_无符号", "规格数值"]])7.4 日期时间处理
将日期列转为datetime64 类型后,可通过 dt 访问器提取时间特征、计算时间差,满足时间序列分析需求。
import pandas as pd
# 模拟日期数据
df = pd.DataFrame({
"订单ID": [1001, 1002, 1003, 1004],
"下单时间": ["2026-01-01 09:30:00", "2026-01-02 14:15:00", "2026-01-03 10:00:00", "2026-01-05 16:45:00"],
"发货时间": ["2026-01-01 18:00:00", "2026-01-03 08:30:00", "2026-01-03 16:00:00", "2026-01-06 10:10:00"]
})
# 1. 转换为日期时间类型
df["下单时间"] = pd.to_datetime(df["下单时间"])
df["发货时间"] = pd.to_datetime(df["发货时间"])
# 2. 提取时间特征
df["下单日期"] = df["下单时间"].dt.date # 提取日期(date类型)
df["下单小时"] = df["下单时间"].dt.hour # 提取小时
df["星期几"] = df["下单时间"].dt.day_name() # 提取星期名称(英文)
df["是否周末"] = df["下单时间"].dt.dayofweek.isin([5, 6]) # 判断是否为周末(0=周一,6=周日)
# 3. 计算时间差
df["发货时长(小时)"] = (df["发货时间"] - df["下单时间"]).dt.total_seconds() / 3600 # 转为小时
# 4. 日期偏移与过滤
df["预计送达时间"] = df["发货时间"] + pd.Timedelta(days=2) # 加2天
# 筛选1月2日及以后下单的订单
df_jan2 = df[df["下单时间"] >= pd.Timestamp("2026-01-02")]
print("日期时间处理后的数据:")
print(df[["订单ID", "下单时间", "下单小时", "星期几", "发货时长(小时)", "预计送达时间"]])
print("\n1月2日及以后下单的订单:")
print(df_jan2[["订单ID", "下单时间", "发货时间"]])7.5 常见错误与小贴士
常见错误
- str 访问器使用错误:仅 Series 可使用
str方法,DataFrame 需先指定列(如df["列名"].str.strip()),直接用df.str.strip()会报错。 - apply 轴方向混淆:axis=0 表示按列执行(默认),axis=1 表示按行执行,方向错误会导致数据计算异常。
- 日期提取格式错误:
dt.date返回 Python 原生 date 类型,若需字符串格式,需用dt.strftime("%Y-%m-%d")转换。
小贴士
- 字符串处理优先用 pandas
str方法,比 Python 循环效率高,尤其适合大数据量。 - 复杂逻辑处理优先选 apply,简单映射用 map 更简洁;对 DataFrame 按行处理时,确保函数返回值与行数匹配。
- 日期时间处理时,统一日期格式后再提取特征,避免因格式不一致导致的计算错误。
第8章:数据聚合与分组(groupby、pivot_table)
数据聚合与分组是数据分析的核心操作,用于按指定维度拆分数据、计算统计指标,快速挖掘分组后的规律,常用方法有 groupby(分组)和 pivot_table(透视表)。
8.1 groupby 分组聚合
8.1.1 核心概念
groupby 遵循“拆分-应用-合并”逻辑:先按指定列拆分数据为多个组,对每个组应用统计函数(如求和、均值),最后合并结果为新 DataFrame。
8.1.2 基础用法(代码示例)
import pandas as pd
# 模拟销售数据
df = pd.DataFrame({
"部门": ["技术部", "销售部", "技术部", "销售部", "技术部", "人事部", "销售部", "人事部"],
"姓名": ["张三", "李四", "王五", "赵六", "孙七", "周八", "吴九", "郑十"],
"薪资": [8000, 9500, 8800, 10000, 9200, 7500, 11000, 7800],
"绩效": [85, 92, 88, 95, 90, 82, 98, 86]
})
# 1. 按单列分组,计算单个指标
# 按“部门”分组,计算薪资均值
dept_salary_mean = df.groupby("部门")["薪资"].mean()
print("各部门薪资均值:")
print(dept_salary_mean)
# 2. 按单列分组,计算多个指标
# 按“部门”分组,计算薪资的均值、最大值、最小值
dept_salary_stats = df.groupby("部门")["薪资"].agg(["mean", "max", "min"])
dept_salary_stats.columns = ["薪资均值", "薪资最高", "薪资最低"] # 重命名列
print("\n各部门薪资统计:")
print(dept_salary_stats)
# 3. 按单列分组,对多列计算不同指标
# 按“部门”分组,薪资求均值,绩效求总和
dept_multi_stats = df.groupby("部门").agg({"薪资": "mean", "绩效": "sum"})
print("\n各部门薪资均值与绩效总和:")
print(dept_multi_stats)
# 4. 按多列分组
# 按“部门”和“性别”分组(新增性别列)
df["性别"] = ["男", "男", "女", "男", "女", "女", "男", "女"]
dept_gender_stats = df.groupby(["部门", "性别"])["薪资"].mean()
print("\n各部门各性别薪资均值:")
print(dept_gender_stats)
# 重置索引(将分组标签转为列)
dept_gender_stats_reset = dept_gender_stats.reset_index()
print("\n重置索引后:")
print(dept_gender_stats_reset)8.1.3 高级用法(自定义聚合函数)
import pandas as pd
df = pd.DataFrame({
"部门": ["技术部", "销售部", "技术部", "销售部", "技术部"],
"薪资": [8000, 9500, 8800, 10000, 9200],
"绩效": [85, 92, 88, 95, 90]
})
# 自定义聚合函数:计算薪资与绩效的乘积均值
def salary_perf_product_mean(group):
product = group["薪资"] * group["绩效"]
return product.mean()
# 按部门分组应用自定义函数
dept_custom_stats = df.groupby("部门").apply(salary_perf_product_mean)
print("各部门薪资绩效乘积均值:")
print(dept_custom_stats)
# 结合 agg 应用多个自定义函数
def range_calc(series):
return series.max() - series.min() # 计算极差
dept_multi_custom = df.groupby("部门")["薪资"].agg([range_calc, "mean"])
dept_multi_custom.columns = ["薪资极差", "薪资均值"]
print("\n各部门薪资极差与均值:")
print(dept_multi_custom)8.2 pivot_table 透视表
8.2.1 核心概念
透视表是 groupby 的高级封装,可快速按行、列维度分组计算,生成结构化的汇总表格,类似 Excel 透视表功能,更适合多维度分析。
8.2.2 代码示例
import pandas as pd
# 沿用销售数据,新增“入职年份”列
df = pd.DataFrame({
"部门": ["技术部", "销售部", "技术部", "销售部", "技术部", "人事部", "销售部", "人事部"],
"性别": ["男", "男", "女", "男", "女", "女", "男", "女"],
"入职年份": [2023, 2022, 2023, 2021, 2022, 2023, 2022, 2021],
"薪资": [8000, 9500, 8800, 10000, 9200, 7500, 11000, 7800],
"绩效": [85, 92, 88, 95, 90, 82, 98, 86]
})
# 1. 基础透视表:行=部门,列=性别,值=薪资,聚合函数=均值
pivot1 = pd.pivot_table(
df,
index="部门", # 行维度
columns="性别", # 列维度
values="薪资", # 聚合值
aggfunc="mean" # 聚合函数
)
print("各部门各性别薪资均值透视表:")
print(pivot1)
# 2. 多值聚合:同时计算薪资和绩效的均值
pivot2 = pd.pivot_table(
df,
index="部门",
columns="入职年份",
values=["薪资", "绩效"],
aggfunc="mean"
)
print("\n各部门各入职年份薪资与绩效均值:")
print(pivot2)
# 3. 多聚合函数:对薪资同时计算均值和最大值
pivot3 = pd.pivot_table(
df,
index="部门",
columns="性别",
values="薪资",
aggfunc=["mean", "max"] # 多个聚合函数
)
print("\n各部门各性别薪资均值与最大值:")
print(pivot3)
# 4. 填充缺失值:用 0 填充透视表中的 NaN
pivot4 = pd.pivot_table(
df,
index="部门",
columns="性别",
values="薪资",
aggfunc="mean",
fill_value=0 # 填充缺失值
)
print("\n填充缺失值后的透视表:")
print(pivot4)8.3 常见错误与小贴士
常见错误
- groupby 后索引问题:分组后结果的索引为分组标签,若需后续分析,可通过
reset_index()重置索引,将标签转为列。 - 透视表聚合函数错误:aggfunc 未指定时,默认对数值型值计算均值,若需其他逻辑(如计数),需明确指定(如 aggfunc="count")。
- 多列分组顺序影响:groupby 多列时,分组顺序会影响结果(先按第一列分,再按第二列分),需根据分析需求确定顺序。
小贴士
- 简单分组统计用 groupby 更灵活,多维度结构化汇总用 pivot_table 更高效,可根据需求选择。
- groupby 后可结合
filter()筛选组(如筛选薪资均值>9000的部门),拓展分析维度。 - 透视表中,若需行/列总计,可添加
margins=True参数,自动计算汇总行和汇总列。
第9章:数据合并与连接(merge、concat、join)
实际数据分析中,数据常分散在多个表格中,需通过合并/连接操作整合为一张完整表格,pandas 提供 merge(按列连接)、concat(拼接)、join(按索引连接)三种核心方法。
9.1 merge 按列连接(类似 SQL 连接)
9.1.1 核心概念
merge 基于一个或多个共同列(键)连接两个 DataFrame,支持内连接、左连接、右连接、外连接四种类型,与 SQL 连接逻辑一致。
9.1.2 代码示例
import pandas as pd
# 准备两个表格数据
# 员工基本信息表
df_emp = pd.DataFrame({
"员工ID": [101, 102, 103, 104],
"姓名": ["张三", "李四", "王五", "赵六"],
"部门ID": [1, 2, 1, 3]
})
# 部门信息表
df_dept = pd.DataFrame({
"部门ID": [1, 2, 3, 4],
"部门名称": ["技术部", "销售部", "人事部", "财务部"],
"部门经理": ["孙七", "周八", "吴九", "郑十"]
})
# 1. 内连接(默认 how="inner"):只保留两个表中键值匹配的行
merge_inner = pd.merge(df_emp, df_dept, on="部门ID")
print("内连接结果:")
print(merge_inner)
# 2. 左连接(how="left"):保留左表所有行,右表匹配不到的填充 NaN
merge_left = pd.merge(df_emp, df_dept, on="部门ID", how="left")
print("\n左连接结果:")
print(merge_left)
# 3. 右连接(how="right"):保留右表所有行,左表匹配不到的填充 NaN
merge_right = pd.merge(df_emp, df_dept, on="部门ID", how="right")
print("\n右连接结果:")
print(merge_right)
# 4. 外连接(how="outer"):保留两个表所有行,匹配不到的填充 NaN
merge_outer = pd.merge(df_emp, df_dept, on="部门ID", how="outer")
print("\n外连接结果:")
print(merge_outer)
# 5. 按多列连接(键为多个列)
df1 = pd.DataFrame({"A": [1, 2], "B": [3, 4], "C": [5, 6]})
df2 = pd.DataFrame({"A": [1, 2], "B": [3, 5], "D": [7, 8]})
merge_multi_key = pd.merge(df1, df2, on=["A", "B"], how="inner")
print("\n按多列内连接结果:")
print(merge_multi_key)9.2 concat 拼接(上下/左右)
9.2.1 核心概念
concat 用于沿指定轴拼接多个 DataFrame,无需共同键,支持上下拼接(axis=0,默认)和左右拼接(axis=1)。
9.2.2 代码示例
import pandas as pd
# 准备拼接数据
df_a = pd.DataFrame({
"员工ID": [101, 102],
"姓名": ["张三", "李四"],
"薪资": [8000, 9500]
})
df_b = pd.DataFrame({
"员工ID": [103, 104],
"姓名": ["王五", "赵六"],
"薪资": [8800, 10000]
})
df_c = pd.DataFrame({
"绩效": [85, 92, 88, 95],
"入职年份": [2023, 2022, 2023, 2021]
}, index=[0, 1, 2, 3])
# 1. 上下拼接(axis=0):合并行,列需一致或部分一致
concat_rows = pd.concat([df_a, df_b], ignore_index=True) # ignore_index=True 重置行索引
print("上下拼接结果:")
print(concat_rows)
# 2. 左右拼接(axis=1):合并列,按索引匹配行
concat_cols = pd.concat([concat_rows, df_c], axis=1)
print("\n左右拼接结果:")
print(concat_cols)
# 3. 拼接时去重(join="inner"):只保留索引/列匹配的部分
df_d = pd.DataFrame({"绩效": [85, 92]}, index=[0, 1])
concat_inner = pd.concat([df_a, df_d], axis=1, join="inner")
print("\n内连接左右拼接结果:")
print(concat_inner)
# 4. 给拼接的数据添加来源标识
df_a["来源"] = "旧员工"
df_b["来源"] = "新员工"
concat_flag = pd.concat([df_a, df_b], ignore_index=True)
print("\n带来源标识的拼接结果:")
print(concat_flag)9.3 join 按索引连接
9.3.1 核心概念
join 基于两个 DataFrame 的索引进行连接,是 merge 的简化版,适合按索引匹配的场景,支持左连接、右连接、内连接、外连接。
9.3.2 代码示例
import pandas as pd
# 准备按索引连接的数据
df1 = pd.DataFrame({
"姓名": ["张三", "李四", "王五"],
"薪资": [8000, 9500, 8800]
}, index=[101, 102, 103]) # 索引为员工ID
df2 = pd.DataFrame({
"部门": ["技术部", "销售部", "人事部"],
"绩效": [85, 92, 88]
}, index=[101, 102, 104]) # 索引为员工ID
# 1. 左连接(默认 how="left"):保留左表索引所有行
join_left = df1.join(df2)
print("左连接结果:")
print(join_left)
# 2. 内连接(how="inner"):只保留索引匹配的行
join_inner = df1.join(df2, how="inner")
print("\n内连接结果:")
print(join_inner)
# 3. 右连接(how="right"):保留右表索引所有行
join_right = df1.join(df2, how="right")
print("\n右连接结果:")
print(join_right)
# 4. 处理列名重复:添加后缀区分
df3 = pd.DataFrame({
"绩效": [86, 93, 89],
"薪资": [8200, 9600, 8900]
}, index=[101, 102, 103])
join_suffix = df1.join(df3, lsuffix="_旧", rsuffix="_新") # 左表列加_旧,右表列加_新
print("\n处理列名重复的连接结果:")
print(join_suffix)9.4 常见错误与小贴士
常见错误
- 连接键数据类型不一致:如左表键为 int 类型,右表键为 str 类型,会导致匹配失败,需先统一数据类型(如
astype(int))。 - 左右拼接索引不匹配:concat 左右拼接时按索引匹配,若索引混乱,会出现大量 NaN,需先确保索引一致或重置索引。
- 列名重复冲突:连接时两个表有同名列(非键列),会导致列名重复,需用 suffixes 参数添加后缀区分。
小贴士
- 按列匹配用 merge,按索引匹配用 join,简单拼接用 concat,根据数据结构选择合适方法。
- 合并前先检查连接键的唯一性和数据类型,避免匹配异常;可通过
nunique()检查键的唯一性。 - 大数据量合并时,优先按索引连接(join),效率高于按列连接(merge)。
第10章:pandas 实战案例(综合应用)
本节通过一个完整的数据分析实战案例,整合前文所学知识点(数据读取、清洗、变换、聚合、可视化),模拟真实业务场景,提升实战能力。
10.1 案例背景与需求
背景:某电商平台 2026 年 1 月订单数据,包含订单基础信息、用户信息、商品信息三个表格。需求:分析订单销售情况、用户消费特征、商品品类表现,生成分析报告。
10.2 数据准备
需准备三个 CSV 文件(实际场景可替换为真实数据路径):
- order.csv:订单信息(订单ID、用户ID、商品ID、下单时间、支付金额、支付状态);
- user.csv:用户信息(用户ID、性别、年龄、所在城市);
- product.csv:商品信息(商品ID、商品品类、商品单价)。
10.3 实战步骤(代码实现)
10.3.1 步骤1:导入库并读取数据
首先导入所需库,读取三个CSV文件,初步探索数据基本情况,确保数据正常加载。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 设置中文字体(解决matplotlib中文显示问题)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 读取数据
order_df = pd.read_csv("order.csv", encoding="utf-8")
user_df = pd.read_csv("user.csv", encoding="utf-8")
product_df = pd.read_csv("product.csv", encoding="utf-8")
# 初步探索数据
print("订单数据形状:", order_df.shape)
print("\n订单数据前5行:")
print(order_df.head())
print("\n订单数据基本信息:")
print(order_df.info())
print("\n用户数据形状:", user_df.shape)
print("\n商品数据形状:", product_df.shape)
# 检查缺失值
print("\n订单数据缺失值:")
print(order_df.isnull().sum())
print("\n用户数据缺失值:")
print(user_df.isnull().sum())
print("\n商品数据缺失值:")
print(product_df.isnull().sum())
10.3.2 步骤2:数据清洗与预处理
处理缺失值、重复值、数据类型转换,统一数据格式,为后续分析奠定基础。
# 1. 处理订单数据
# 转换下单时间为日期时间类型
order_df["下单时间"] = pd.to_datetime(order_df["下单时间"], errors="coerce")
# 处理支付状态:统一为“已支付”“未支付”,过滤无效状态
order_df["支付状态"] = order_df["支付状态"].map({"已支付": "已支付", "未支付": "未支付"})
order_df = order_df.dropna(subset=["支付状态"]) # 删除无效状态行
# 处理支付金额异常值(过滤负数和0,保留有效订单)
order_df = order_df[order_df["支付金额"] > 0]
# 2. 处理用户数据
# 填充年龄缺失值(用均值填充)
user_df["年龄"] = user_df["年龄"].fillna(user_df["年龄"].mean()).astype(int)
# 按年龄分组,新增年龄分段列
user_df["年龄分段"] = pd.cut(
user_df["年龄"],
bins=[0, 20, 30, 40, 50, 100],
labels=["20岁及以下", "21-30岁", "31-40岁", "41-50岁", "50岁以上"]
)
# 3. 处理商品数据:删除重复行
product_df = product_df.drop_duplicates(subset=["商品ID"])
# 4. 合并三个表格(按订单ID、用户ID、商品ID关联)
# 先合并订单和用户数据
df_merge1 = pd.merge(order_df, user_df, on="用户ID", how="left")
# 再合并商品数据
df_final = pd.merge(df_merge1, product_df, on="商品ID", how="left")
# 过滤掉无商品品类的订单
df_final = df_final.dropna(subset=["商品品类"])
print("数据清洗完成后,最终数据集形状:", df_final.shape)
print("\n最终数据集前5行:")
print(df_final.head())
10.3.3 步骤3:数据变换与特征工程
基于现有数据生成新特征,如日期特征、消费特征等,丰富分析维度。
# 1. 提取日期特征
df_final["下单日期"] = df_final["下单时间"].dt.date
df_final["下单小时"] = df_final["下单时间"].dt.hour
df_final["星期几"] = df_final["下单时间"].dt.day_name()
# 2. 新增消费特征
# 计算实际单价与支付金额的差值(判断是否有优惠)
df_final["优惠金额"] = df_final["商品单价"] - df_final["支付金额"]
df_final["是否优惠"] = df_final["优惠金额"].apply(lambda x: "是" if x > 0 else "否")
# 3. 按用户分组计算累计消费金额和订单数(用户消费能力特征)
user_consume = df_final.groupby("用户ID").agg({
"订单ID": "count",
"支付金额": "sum"
}).rename(columns={"订单ID": "累计订单数", "支付金额": "累计消费金额"})
# 将用户消费特征合并回主数据集
df_final = pd.merge(df_final, user_consume, on="用户ID", how="left")
# 新增用户消费等级
df_final["消费等级"] = pd.cut(
df_final["累计消费金额"],
bins=[0, 500, 2000, 5000, 10000, float("inf")],
labels=["普通用户", "铜牌用户", "银牌用户", "金牌用户", "钻石用户"]
)
print("特征工程完成后,数据集列名:")
print(df_final.columns.tolist())
10.3.4 步骤4:数据聚合与分析
从销售情况、用户特征、商品表现三个维度进行聚合分析,挖掘业务规律。
# 一、销售情况分析
# 1. 整体销售概览
total_orders = df_final[df_final["支付状态"]=="已支付"].shape[0] # 已支付订单数
total_sales = df_final[df_final["支付状态"]=="已支付"]["支付金额"].sum() # 总销售额
avg_order_amount = df_final[df_final["支付状态"]=="已支付"]["支付金额"].mean() # 平均订单金额
payment_rate = df_final[df_final["支付状态"]=="已支付"].shape[0] / df_final.shape[0] * 100 # 支付转化率
print("=== 整体销售概览 ===")
print(f"总订单数:{df_final.shape[0]} 单")
print(f"已支付订单数:{total_orders} 单")
print(f"总销售额:{total_sales:.2f} 元")
print(f"平均订单金额:{avg_order_amount:.2f} 元")
print(f"支付转化率:{payment_rate:.2f}%")
# 2. 按日期分析销售趋势(每日销售额)
daily_sales = df_final[df_final["支付状态"]=="已支付"].groupby("下单日期")["支付金额"].sum()
print("\n=== 每日销售额趋势(前5天) ===")
print(daily_sales.head())
# 3. 按小时分析下单高峰
hourly_orders = df_final.groupby("下单小时")["订单ID"].count()
print("\n=== 各时段下单量分布 ===")
print(hourly_orders)
# 二、用户消费特征分析
# 1. 按性别分析消费情况
gender_consume = df_final[df_final["支付状态"]=="已支付"].groupby("性别").agg({
"用户ID": "nunique", # 消费用户数
"订单ID": "count", # 订单数
"支付金额": "sum" # 消费总额
}).rename(columns={"用户ID": "消费用户数", "订单ID": "订单数", "支付金额": "消费总额"})
gender_consume["人均消费"] = gender_consume["消费总额"] / gender_consume["消费用户数"]
print("\n=== 按性别分析消费情况 ===")
print(gender_consume)
# 2. 按年龄分段分析消费情况
age_consume = df_final[df_final["支付状态"]=="已支付"].groupby("年龄分段")["支付金额"].agg(["sum", "mean"])
age_consume.columns = ["消费总额", "平均消费金额"]
print("\n=== 按年龄分段分析消费情况 ===")
print(age_consume)
# 3. 按消费等级分析用户分布
level_dist = df_final[df_final["支付状态"]=="已支付"]["消费等级"].value_counts()
print("\n=== 消费等级用户分布 ===")
print(level_dist)
# 三、商品品类表现分析
# 1. 各品类销售情况
category_sales = df_final[df_final["支付状态"]=="已支付"].groupby("商品品类").agg({
"订单ID": "count", # 订单数
"支付金额": "sum" # 销售额
}).rename(columns={"订单ID": "订单数", "支付金额": "销售额"})
category_sales["占比"] = category_sales["销售额"] / category_sales["销售额"].sum() * 100
category_sales = category_sales.sort_values(by="销售额", ascending=False)
print("\n=== 各商品品类销售表现 ===")
print(category_sales)
# 2. 各品类优惠使用情况
category_discount = df_final[df_final["支付状态"]=="已支付"].groupby("商品品类")["是否优惠"].value_counts(normalize=True).unstack()
category_discount["优惠使用率"] = category_discount["是"] * 100
print("\n=== 各品类优惠使用率 ===")
print(category_discount[["优惠使用率"]])
10.3.5 步骤5:数据可视化(结果呈现)
通过图表直观展示分析结果,包括趋势图、柱状图、饼图等,提升报告可读性。
# 创建画布,设置尺寸
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
fig.suptitle("2026年1月电商订单数据分析报告", fontsize=16, fontweight='bold')
# 1. 每日销售额趋势(子图1)
daily_sales.plot(kind="line", ax=axes[0,0], color="#1f77b4", linewidth=2)
axes[0,0].set_title("每日销售额趋势", fontsize=12, fontweight='bold')
axes[0,0].set_xlabel("日期")
axes[0,0].set_ylabel("销售额(元)")
axes[0,0].tick_params(axis="x", rotation=45)
axes[0,0].grid(alpha=0.3)
# 2. 各时段下单量分布(子图2)
hourly_orders.plot(kind="bar", ax=axes[0,1], color="#ff7f0e")
axes[0,1].set_title("各时段下单量分布", fontsize=12, fontweight='bold')
axes[0,1].set_xlabel("小时")
axes[0,1].set_ylabel("下单量(单)")
axes[0,1].tick_params(axis="x", rotation=0)
# 3. 按性别消费总额对比(子图3)
gender_consume["消费总额"].plot(kind="bar", ax=axes[0,2], color=["#2ca02c", "#d62728"])
axes[0,2].set_title("不同性别消费总额对比", fontsize=12, fontweight='bold')
axes[0,2].set_xlabel("性别")
axes[0,2].set_ylabel("消费总额(元)")
axes[0,2].tick_params(axis="x", rotation=0)
# 4. 各年龄分段平均消费金额(子图4)
age_consume["平均消费金额"].plot(kind="bar", ax=axes[1,0], color="#9467bd")
axes[1,0].set_title("各年龄分段平均消费金额", fontsize=12, fontweight='bold')
axes[1,0].set_xlabel("年龄分段")
axes[1,0].set_ylabel("平均消费金额(元)")
axes[1,0].tick_params(axis="x", rotation=45)
# 5. 各商品品类销售额占比(子图5)
category_sales["占比"].plot(kind="pie", ax=axes[1,1], autopct="%1.1f%%", startangle=90)
axes[1,1].set_title("各商品品类销售额占比", fontsize=12, fontweight='bold')
axes[1,1].set_ylabel("")
# 6. 消费等级用户分布(子图6)
level_dist.plot(kind="bar", ax=axes[1,2], color="#8c564b")
axes[1,2].set_title("消费等级用户分布", fontsize=12, fontweight='bold')
axes[1,2].set_xlabel("消费等级")
axes[1,2].set_ylabel("用户数")
axes[1,2].tick_params(axis="x", rotation=45)
# 调整子图间距
plt.tight_layout()
# 保存图片
plt.savefig("电商订单分析报告.png", dpi=300, bbox_inches='tight')
plt.close()
print("可视化图表已保存为:电商订单分析报告.png")
10.3.6 步骤6:分析总结与建议
基于分析结果,总结核心结论,提出针对性业务建议,形成完整分析报告。
# 输出分析总结
print("\n=== 分析总结与业务建议 ===")
print("\n【核心结论】")
print(f"1. 销售表现:本月总销售额 {total_sales:.2f} 元,支付转化率 {payment_rate:.2f}%,整体销售态势良好;下单高峰集中在 {hourly_orders.idxmax()}:00-{hourly_orders.idxmax()+1}:00 时段。")
print(f"2. 用户特征:{gender_consume.index[gender_consume['消费总额'].idxmax()]} 消费能力更强,人均消费 {gender_consume['人均消费'].max():.2f} 元;{age_consume.index[age_consume['消费总额'].idxmax()]} 是核心消费群体。")
print(f"3. 商品表现:{category_sales.index[0]} 品类销售额最高,占比 {category_sales['占比'].iloc[0]:.1f}%;{category_discount.index[category_discount['优惠使用率'].idxmax()]} 品类优惠使用率最高,用户对该品类优惠敏感度强。")
print("\n【业务建议】")
print("1. 运营策略:在每日下单高峰时段({}:00)加大推广力度,发放限时优惠券,进一步提升订单量。".format(hourly_orders.idxmax()))
print("2. 用户运营:针对核心消费群体({})推出专属会员权益,提升用户粘性;对低消费等级用户开展精准营销,促进转化升级。".format(age_consume.index[age_consume['消费总额'].idxmax()]))
print("3. 商品策略:重点扶持 {} 等优势品类,保障供应链充足;对优惠敏感度高的 {} 品类,定期推出优惠活动,拉动销量增长。".format(category_sales.index[0], category_discount.index[category_discount['优惠使用率'].idxmax()]))
print("4. 优化方向:持续提升支付转化率,针对未支付订单开展短信提醒、优惠券补贴等召回活动。")
# 保存分析报告到文本文件
report_content = f"2026年1月电商订单数据分析报告\n" \
f"===============================\n" \
f"一、整体销售概览\n" \
f"总订单数:{df_final.shape[0]} 单\n" \
f"已支付订单数:{total_orders} 单\n" \
f"总销售额:{total_sales:.2f} 元\n" \
f"平均订单金额:{avg_order_amount:.2f} 元\n" \
f"支付转化率:{payment_rate:.2f}%\n" \
f"\n二、核心结论\n" \
f"1. 销售表现:本月整体销售态势良好,下单高峰集中在 {hourly_orders.idxmax()}:00-{hourly_orders.idxmax()+1}:00 时段。\n" \
f"2. 用户特征:{gender_consume.index[gender_consume['消费总额'].idxmax()]} 消费能力更强,人均消费 {gender_consume['人均消费'].max():.2f} 元;{age_consume.index[age_consume['消费总额'].idxmax()]} 是核心消费群体。\n" \
f"3. 商品表现:{category_sales.index[0]} 品类销售额最高,占比 {category_sales['占比'].iloc[0]:.1f}%;{category_discount.index[category_discount['优惠使用率'].idxmax()]} 品类优惠使用率最高。\n" \
f"\n三、业务建议\n" \
f"1. 运营策略:在每日下单高峰时段({hourly_orders.idxmax()}:00)加大推广力度,发放限时优惠券。\n" \
f"2. 用户运营:针对核心消费群体推出专属会员权益,对低消费等级用户开展精准营销。\n" \
f"3. 商品策略:重点扶持优势品类,对优惠敏感度高的品类定期推出优惠活动。\n" \
f"4. 优化方向:针对未支付订单开展召回活动,提升支付转化率。"
with open("电商订单分析报告.txt", "w", encoding="utf-8") as f:
f.write(report_content)
print("\n分析报告已保存为:电商订单分析报告.txt")10.4 案例拓展与延伸
本案例整合了pandas核心知识点,实际应用中可根据业务需求拓展以下方向:
- 时间序列深化分析:按周、按小时粒度分析销售趋势,结合节假日因素挖掘消费规律。
- 用户行为分析:新增用户复购率计算(7日复购、30日复购),分析用户留存特征。
- 商品关联分析:使用关联规则算法(如Apriori)挖掘常被一起购买的商品组合,优化商品推荐。
- 异常检测:识别异常订单(如高频下单、大额订单),防范刷单、欺诈等风险。
- 自动化报告:将代码封装为函数,结合调度工具(如Airflow)实现每日/每周自动生成分析报告。
10.5 实战总结
数据分析的核心流程是“数据准备→清洗预处理→特征工程→分析聚合→结果呈现”,pandas作为核心工具,提供了高效的数据处理能力。实战中需注意:
- 数据清洗是基础,需优先处理缺失值、异常值,确保数据准确性;
- 特征工程需结合业务场景,生成有价值的新特征,提升分析深度;
- 分析结果需落地为业务建议,避免纯技术层面的分析,体现数据价值;
- 可视化是结果呈现的关键,选择合适的图表类型,让数据结论更直观易懂。
第11章:pandas 进阶技巧与性能优化
掌握基础用法后,进阶技巧与性能优化能大幅提升数据分析效率,尤其适合大数据量场景。本章将介绍常用进阶技巧、性能优化方法及常见问题解决方案。
11.1 常用进阶技巧
11.1.1 数据透视表高级用法
除基础聚合外,pivot_table可结合自定义函数、多层索引实现复杂分析,同时支持快速计算行/列总计。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"部门": ["技术部", "销售部", "技术部", "销售部", "人事部"],
"性别": ["男", "女", "男", "男", "女"],
"薪资": [8000, 9500, 8800, 10000, 7500],
"绩效": [85, 92, 88, 95, 82]
})
# 1. 多层索引透视表
pivot_multi = pd.pivot_table(
df,
index=["部门", "性别"], # 多层行索引
values=["薪资", "绩效"],
aggfunc={"薪资": "mean", "绩效": "sum"},
margins=True # 显示行/列总计
)
print("多层索引透视表(含总计):")
print(pivot_multi)
# 2. 自定义聚合函数透视表
def salary_range(series):
return series.max() - series.min() # 计算薪资极差
pivot_custom = pd.pivot_table(
df,
index="部门",
values="薪资",
aggfunc=["mean", salary_range], # 结合内置函数和自定义函数
margins=True
)
pivot_custom.columns = ["薪资均值", "薪资极差"]
print("\n自定义函数透视表:")
print(pivot_custom)
11.1.2 分组后过滤(filter)与转换(transform)
groupby除聚合外,还支持filter(按组筛选)和transform(组内转换),实现更灵活的分组操作。
import pandas as pd
df = pd.DataFrame({
"部门": ["技术部", "技术部", "销售部", "销售部", "销售部", "人事部"],
"薪资": [8000, 9200, 9500, 10000, 11000, 7500]
})
# 1. filter:筛选出薪资均值>9000的部门
dept_filtered = df.groupby("部门").filter(lambda x: x["薪资"].mean() > 9000)
print("薪资均值>9000的部门数据:")
print(dept_filtered)
# 2. transform:组内标准化薪资((薪资-组内均值)/组内标准差)
df["薪资标准化"] = df.groupby("部门")["薪资"].transform(
lambda x: (x - x.mean()) / x.std()
)
print("\n组内标准化后的数据:")
print(df)
# 3. transform填充缺失值(按组填充均值)
df_miss = pd.DataFrame({
"部门": ["技术部", "技术部", "销售部"],
"薪资": [8000, np.nan, 9500]
})
df_miss["薪资_填充"] = df_miss.groupby("部门")["薪资"].transform("mean")
print("\n按组填充缺失值后:")
print(df_miss)
11.1.3 高效处理缺失值与重复值
针对大数据量,使用更高效的缺失值、重复值处理方法,避免循环遍历。
import pandas as pd
import numpy as np
# 模拟大数据量(10万行)
df = pd.DataFrame({
"A": np.random.randint(0, 100, 100000),
"B": np.random.choice([1, 2, 3, np.nan], 100000, p=[0.3, 0.3, 0.3, 0.1]),
"C": np.random.choice(["a", "b", "c"], 100000)
})
# 1. 高效填充缺失值(按列类型填充)
# 数值列用中位数填充
num_cols = df.select_dtypes(include=[np.number]).columns
df[num_cols] = df[num_cols].fillna(df[num_cols].median())
# 分类列用众数填充
cat_cols = df.select_dtypes(include=["object"]).columns
for col in cat_cols:
df[col] = df[col].fillna(df[col].mode()[0])
# 2. 高效去重(保留最后一行,按指定列判断)
df = df.drop_duplicates(subset=["A", "C"], keep="last", inplace=False)
# 3. 快速判断缺失值(替代isnull().sum(),效率更高)
missing_count = df.isna().sum().sum() # 总缺失值数
print(f"处理后总缺失值数:{missing_count}")
print(f"处理后数据形状:{df.shape}")
11.1.4 向量化操作替代循环
pandas基于NumPy实现向量化操作,效率远高于Python循环,复杂逻辑优先用向量化方法。
import pandas as pd
import numpy as np
# 模拟数据
df = pd.DataFrame({"数值": np.random.randint(0, 1000, 100000)})
# 1. 向量化操作(判断数值范围)
df["范围标签"] = np.where(
df["数值"] < 300, "低",
np.where(df["数值"] < 700, "中", "高")
)
# 2. 替代循环的apply方法(简单逻辑用np.where,复杂逻辑用apply)
def complex_logic(x):
if x % 2 == 0 and x > 500:
return "偶数高值"
elif x % 2 != 0 and x < 500:
return "奇数低值"
else:
return "其他"
df["复杂标签"] = df["数值"].apply(complex_logic)
# 3. 对比循环与向量化效率
import time
# 循环方式(效率低)
start_time = time.time()
df["循环标签"] = ""
for i in range(len(df)):
if df.loc[i, "数值"] < 300:
df.loc[i, "循环标签"] = "低"
elif df.loc[i, "数值"] < 700:
df.loc[i, "循环标签"] = "中"
else:
df.loc[i, "循环标签"] = "高"
loop_time = time.time() - start_time
# 向量化方式(效率高)
start_time = time.time()
df["向量化标签"] = np.where(
df["数值"] < 300, "低",
np.where(df["数值"] < 700, "中", "高")
)
vec_time = time.time() - start_time
print(f"循环耗时:{loop_time:.4f} 秒")
print(f"向量化耗时:{vec_time:.4f} 秒")
print(f"向量化效率是循环的 {loop_time/vec_time:.2f} 倍")
11.2 性能优化方法
11.2.1 数据类型优化
pandas默认数据类型可能占用较多内存,优化数据类型可大幅减少内存占用,提升运算效率。
import pandas as pd
import numpy as np
# 模拟数据
df = pd.DataFrame({
"整数列": np.random.randint(0, 100, 100000),
"小整数列": np.random.randint(0, 10, 100000),
"浮点列": np.random.randn(100000),
"分类列": np.random.choice(["类型A", "类型B", "类型C"], 100000)
})
# 查看原始内存占用
print("原始内存占用:", df.memory_usage(deep=True).sum() / 1024 / 1024, "MB")
# 优化数据类型
# 1. 整数列:小范围整数转为int8/int16
df["小整数列"] = df["小整数列"].astype(np.int8)
# 2. 浮点列:转为float32(精度足够时)
df["浮点列"] = df["浮点列"].astype(np.float32)
# 3. 分类列:转为category类型(重复值多的字符串列)
df["分类列"] = df["分类列"].astype("category")
# 查看优化后内存占用
print("优化后内存占用:", df.memory_usage(deep=True).sum() / 1024 / 1024, "MB")
11.2.2 大数据量分块处理
当数据量超过内存容量时,使用chunksize分块读取和处理,避免内存溢出。
import pandas as pd
# 分块读取CSV文件(每块10000行)
chunk_iter = pd.read_csv("big_data.csv", chunksize=10000, encoding="utf-8")
# 初始化结果变量
total_sales = 0
category_count = {}
# 逐块处理数据
for chunk in chunk_iter:
# 处理当前块数据(过滤有效订单)
chunk = chunk[chunk["支付金额"] > 0]
# 累加总销售额
total_sales += chunk["支付金额"].sum()
# 统计各品类订单数
chunk_category = chunk["商品品类"].value_counts()
for cat, cnt in chunk_category.items():
if cat in category_count:
category_count[cat] += cnt
else:
category_count[cat] = cnt
# 输出结果
print(f"总销售额:{total_sales:.2f} 元")
print("各品类订单数:", category_count)
11.2.3 索引优化
为常用查询列设置索引(index),可大幅提升按该列筛选、分组、连接的效率。
import pandas as pd
import time
# 模拟数据(10万行)
df = pd.DataFrame({
"用户ID": np.random.randint(1, 10000, 100000),
"支付金额": np.random.randint(100, 1000, 100000)
})
# 无索引查询耗时
start_time = time.time()
df[df["用户ID"] == 5000]
no_index_time = time.time() - start_time
# 设置用户ID为索引
df_indexed = df.set_index("用户ID")
# 有索引查询耗时
start_time = time.time()
df_indexed.loc[5000]
index_time = time.time() - start_time
print(f"无索引查询耗时:{no_index_time:.6f} 秒")
print(f"有索引查询耗时:{index_time:.6f} 秒")
print(f"索引优化后效率提升 {no_index_time/index_time:.2f} 倍")
11.2.4 避免链式赋值警告
链式赋值(如df[df["A"]>0]["B"] = 1)会触发SettingWithCopyWarning,且可能导致修改失败,需用loc/iloc替代。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"A": np.random.randint(0, 10, 10),
"B": np.random.randint(10, 20, 10)
})
# 错误:链式赋值
try:
df[df["A"] > 5]["B"] = 0
except Warning as w:
print("链式赋值警告:", w)
# 正确:用loc赋值
df.loc[df["A"] > 5, "B"] = 0
print("用loc赋值后的数据:")
print(df)
# 正确:先复制数据再修改(避免修改原数据副本)
df_copy = df[df["A"] > 5].copy()
df_copy["B"] = 100
print("\n复制后修改的数据:")
print(df_copy)11.3 常见进阶问题解决方案
11.3.1 处理超大CSV文件
对于GB级CSV文件,除分块处理外,可使用dask库(并行计算)或转为Parquet格式(压缩率高、读取快)。
import pandas as pd
import dask.dataframe as dd
# 方法1:转为Parquet格式(推荐)
# 读取CSV并保存为Parquet
df = pd.read_csv("big_data.csv", encoding="utf-8")
df.to_parquet("big_data.parquet", engine="pyarrow", compression="snappy")
# 读取Parquet文件(速度远快于CSV)
df_parquet = pd.read_parquet("big_data.parquet", engine="pyarrow")
# 方法2:用dask并行处理
dask_df = dd.read_csv("big_data.csv", encoding="utf-8")
# 并行计算总销售额
total_sales = dask_df[dask_df["支付金额"] > 0]["支付金额"].sum().compute()
print(f"总销售额:{total_sales:.2f} 元")
11.3.2 处理多编码格式文件
遇到编码不明确的文件,自动检测编码并读取,避免编码错误。
import pandas as pd
import chardet
# 自动检测文件编码
def detect_encoding(file_path):
with open(file_path, "rb") as f:
result = chardet.detect(f.read(100000)) # 读取前100KB检测编码
return result["encoding"]
# 检测编码并读取文件
file_path = "data.csv"
encoding = detect_encoding(file_path)
print(f"检测到文件编码:{encoding}")
df = pd.read_csv(file_path, encoding=encoding)
11.3.3 合并大数据量表格
合并超大DataFrame时,避免内存溢出,可先按索引排序,再分块合并。
import pandas as pd
# 读取两个大数据表并按连接键排序
df1 = pd.read_csv("table1.csv", encoding="utf-8").sort_values(by="用户ID").reset_index(drop=True)
df2 = pd.read_csv("table2.csv", encoding="utf-8").sort_values(by="用户ID").reset_index(drop=True)
# 分块合并(每块50000行)
chunk_size = 50000
result_chunks = []
for i in range(0, len(df1), chunk_size):
df1_chunk = df1.iloc[i:i+chunk_size]
# 找到df2中对应用户ID的范围(利用排序优化)
min_uid = df1_chunk["用户ID"].min()
max_uid = df1_chunk["用户ID"].max()
df2_chunk = df2[(df2["用户ID"] >= min_uid) & (df2["用户ID"] <= max_uid)]
# 合并当前块
merged_chunk = pd.merge(df1_chunk, df2_chunk, on="用户ID", how="left")
result_chunks.append(merged_chunk)
# 合并所有块
df_merged = pd.concat(result_chunks, ignore_index=True)
print(f"合并后数据形状:{df_merged.shape}")
11.4 进阶技巧总结
pandas进阶学习的核心是“高效”与“灵活”:
- 优先使用向量化操作、索引优化、数据类型优化,提升运算效率;
- 大数据量场景下,善用分块处理、并行计算(dask)、高效文件格式(Parquet);
- 避免链式赋值、循环遍历等低效操作,规范代码写法,减少警告和错误;
- 结合业务需求,灵活运用groupby的filter/transform、透视表高级用法,实现复杂分析逻辑。
第12章:pandas 与其他工具集成(Matplotlib、NumPy、SQL等)
实际数据分析场景中,pandas极少单独使用,常需与NumPy(数值计算)、Matplotlib/Seaborn(可视化)、SQL(数据库交互)、Scikit-learn(机器学习)等工具协同工作。本章将讲解核心集成场景与实操方法,打通数据分析全流程。
12.1 与 NumPy 集成
pandas 基于 NumPy 构建,二者数据结构可无缝转换,NumPy 的数值计算能力可弥补 pandas 在复杂数学运算上的不足,同时 pandas 能为 NumPy 数组提供更便捷的标签化操作。
import pandas as pd
import numpy as np
# 1. pandas 与 NumPy 数据结构互转
# Series <-> NumPy 数组
s = pd.Series([1, 2, 3, 4], index=["a", "b", "c", "d"])
np_arr = s.values # Series 转 NumPy 数组
s_from_np = pd.Series(np_arr, index=["a", "b", "c", "d"]) # NumPy 数组转 Series
# DataFrame <-> NumPy 二维数组
df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
np_mat = df.values # DataFrame 转 NumPy 二维数组
df_from_np = pd.DataFrame(np_mat, columns=["A", "B"]) # NumPy 数组转 DataFrame
# 2. 用 NumPy 函数处理 pandas 数据
df["C"] = np.sqrt(df["A"]) # 用 NumPy 平方根函数生成新列
df["D"] = np.where(df["B"] > 5, 1, 0) # 用 NumPy where 函数实现条件逻辑
print("NumPy 处理后的 DataFrame:")
print(df)
# 3. 处理 NumPy 缺失值(np.nan 与 pandas 缺失值兼容)
np_arr_with_nan = np.array([1, np.nan, 3, 4])
s_nan = pd.Series(np_arr_with_nan)
print("\n含缺失值的 Series 处理:")
print(s_nan.fillna(s_nan.mean())) # pandas 方法处理 NumPy 生成的缺失值
12.2 与 Matplotlib/Seaborn 集成(可视化)
pandas 内置了对 Matplotlib 的封装,可直接调用 DataFrame/Series 的 plot 方法快速绘图;Seaborn 作为 Matplotlib 的高级封装,能与 pandas 数据结构完美兼容,生成更美观的统计图表。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 准备数据
df = pd.DataFrame({
"日期": pd.date_range("2026-01-01", "2026-01-10"),
"销售额": np.random.randint(5000, 15000, 10),
"客流量": np.random.randint(100, 500, 10),
"品类": np.random.choice(["家电", "服饰", "食品"], 10)
})
# 1. pandas 内置 plot 方法(基于 Matplotlib)
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
# 折线图:每日销售额趋势
df.plot(x="日期", y="销售额", ax=axes[0,0], color="blue", linewidth=2, title="每日销售额趋势")
axes[0,0].set_xlabel("日期")
axes[0,0].set_ylabel("销售额(元)")
# 柱状图:每日客流量
df.plot(x="日期", y="客流量", ax=axes[0,1], kind="bar", color="orange", title="每日客流量")
axes[0,1].tick_params(axis="x", rotation=45)
# 散点图:销售额与客流量关系
df.plot(x="客流量", y="销售额", ax=axes[1,0], kind="scatter", color="green", title="销售额与客流量关系")
# 饼图:各品类订单占比
category_count = df["品类"].value_counts()
category_count.plot(kind="pie", ax=axes[1,1], autopct="%1.1f%%", startangle=90, title="各品类订单占比")
axes[1,1].set_ylabel("")
plt.tight_layout()
plt.savefig("pandas_matplotlib_plot.png", dpi=300)
plt.close()
# 2. Seaborn 与 pandas 集成
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# 箱线图:各品类销售额分布
sns.boxplot(x="品类", y="销售额", data=df, ax=axes[0], palette="Set2")
axes[0].set_title("各品类销售额分布")
# 回归线图:销售额与客流量相关性
sns.regplot(x="客流量", y="销售额", data=df, ax=axes[1], color="red", scatter_kws={"alpha":0.6})
axes[1].set_title("销售额与客流量回归线")
plt.tight_layout()
plt.savefig("pandas_seaborn_plot.png", dpi=300)
plt.close()
print("可视化图表已保存")
12.3 与 SQL 集成(数据库交互)
实际业务中,数据常存储在 MySQL、PostgreSQL 等关系型数据库中。pandas 可通过 SQLAlchemy 库连接数据库,直接读取 SQL 查询结果为 DataFrame,也可将 DataFrame 写入数据库,实现数据读写自动化。
import pandas as pd
from sqlalchemy import create_engine
# 1. 连接 MySQL 数据库(需提前安装 pymysql 库:pip install pymysql)
# 连接格式:mysql+pymysql://用户名:密码@主机地址:端口/数据库名
engine = create_engine("mysql+pymysql://root:123456@localhost:3306/shop_db")
# 2. 从数据库读取数据(执行 SQL 查询)
# 方法1:直接执行 SQL 语句
df_from_sql = pd.read_sql(
sql="SELECT 订单ID, 用户ID, 支付金额, 下单时间 FROM orders WHERE 支付状态='已支付'",
con=engine
)
print("从数据库读取的数据:")
print(df_from_sql.head())
# 方法2:读取整个表
df_table = pd.read_sql_table(table_name="users", con=engine)
print("\n读取整个用户表:")
print(df_table.head())
# 3. 将 DataFrame 写入数据库
# 准备待写入数据
new_data = pd.DataFrame({
"用户ID": [1001, 1002, 1003],
"姓名": ["张三", "李四", "王五"],
"性别": ["男", "女", "男"],
"注册时间": pd.date_range("2026-01-01", "2026-01-03")
})
# 写入数据库(if_exists 参数:replace 覆盖、append 追加、fail 存在则报错)
new_data.to_sql(
name="new_users", # 数据库表名
con=engine,
if_exists="append",
index=False # 不写入行索引
)
print("\n数据已写入数据库")
# 4. 关闭数据库连接
engine.dispose()
12.4 与 Scikit-learn 集成(机器学习)
Scikit-learn 是 Python 机器学习核心库,pandas 可用于机器学习的数据预处理(特征工程、缺失值处理等),预处理后的 DataFrame 可直接转换为 Scikit-learn 所需的特征矩阵(X)和目标向量(y)。
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
from sklearn.preprocessing import LabelEncoder
# 1. 数据预处理(用 pandas 处理)
df = pd.DataFrame({
"房屋面积": [60, 80, 100, 120, 140, 160],
"户型": ["一居", "两居", "两居", "三居", "三居", "四居"],
"装修情况": ["简装", "精装", "简装", "精装", "豪装", "精装"],
"房价": [80, 120, 150, 180, 220, 250] # 单位:万元
})
# 分类特征编码(户型、装修情况)
le_house = LabelEncoder()
df["户型编码"] = le_house.fit_transform(df["户型"])
le_decor = LabelEncoder()
df["装修编码"] = le_decor.fit_transform(df["装修情况"])
# 2. 构建特征矩阵 X 和目标向量 y
X = df[["房屋面积", "户型编码", "装修编码"]].values # 特征矩阵(NumPy 数组)
y = df["房价"].values # 目标向量(NumPy 数组)
# 3. 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 4. 训练线性回归模型(Scikit-learn)
model = LinearRegression()
model.fit(X_train, y_train)
# 5. 预测与评估
y_pred = model.predict(X_test)
r2 = r2_score(y_test, y_pred)
print(f"模型 R² 得分:{r2:.4f}")
print(f"测试集预测结果:{y_pred}")
print(f"测试集真实结果:{y_test}")
# 6. 用新数据预测(pandas 处理新数据)
new_house = pd.DataFrame({
"房屋面积": [90, 130],
"户型": ["两居", "三居"],
"装修情况": ["简装", "豪装"]
})
new_house["户型编码"] = le_house.transform(new_house["户型"])
new_house["装修编码"] = le_decor.transform(new_house["装修情况"])
X_new = new_house[["房屋面积", "户型编码", "装修编码"]].values
y_new_pred = model.predict(X_new)
new_house["预测房价"] = y_new_pred
print("\n新房屋预测结果:")
print(new_house[["房屋面积", "户型", "装修情况", "预测房价"]])
12.5 常见错误与小贴士
常见错误
- 数据库连接失败:未安装对应数据库驱动(如 MySQL 需 pymysql,PostgreSQL 需 psycopg2),或连接参数(用户名、密码、端口)错误,需逐一排查。
- 可视化中文乱码:未设置中文字体,或字体文件不存在,需通过 plt.rcParams 配置正确的中文字体(如 SimHei、Microsoft YaHei)。
- 机器学习特征编码遗漏:分类特征未编码直接传入模型,导致 Scikit-learn 报错,需先对分类列进行 LabelEncoder 或 OneHotEncoder 处理。
小贴士
- 与数据库交互时,优先使用 SQLAlchemy 连接,兼容性更强,支持多种数据库,且能避免直接拼接 SQL 语句导致的注入风险。
- 可视化时,简单图表用 pandas 内置 plot 方法(高效快捷),复杂统计图表用 Seaborn(美观且代码简洁),按需选择。
- 机器学习预处理时,用 pandas 处理缺失值、异常值,用 Scikit-learn 处理特征编码、归一化,分工明确,效率更高。
第13章:pandas 常见问题排查与调试
使用 pandas 过程中,常会遇到数据类型错误、索引异常、内存溢出、逻辑错误等问题。本章将梳理高频问题及排查方法,帮助快速定位并解决问题,提升调试效率。
13.1 数据类型相关问题
问题1:数值计算结果异常(如求和为0、均值错误)
原因:数值列被识别为 object 类型(字符串),无法正常参与计算。排查方法:用 df.dtypes 查看数据类型,检查列中是否包含非数值字符。
import pandas as pd
import numpy as np
# 模拟问题数据
df = pd.DataFrame({
"金额": ["100", "200", "300元", "400"], # 包含非数值字符"元"
"数量": [2, 3, 4, 5]
})
# 排查:查看数据类型
print("数据类型:")
print(df.dtypes) # 金额列为 object 类型
# 解决方法:清理非数值字符,转换为数值类型
df["金额"] = df["金额"].str.replace("元", "").astype(float)
print("\n转换后数据:")
print(df)
print("求和结果:", df["金额"].sum()) # 正常计算问题2:日期列无法提取年/月/日信息
原因:日期列未转为 datetime64 类型,仍为 object 类型。排查方法:用 df.dtypes 确认类型,用 pd.to_datetime 转换并处理异常值。
import pandas as pd
df = pd.DataFrame({
"日期": ["2026-01-01", "2026/01/02", "2026年01月03日", "无效日期"],
"销售额": [1000, 2000, 3000, 4000]
})
# 排查:尝试提取年份(失败)
try:
print(df["日期"].dt.year)
except AttributeError as e:
print("错误:", e) # 提示 'Series' object has no attribute 'dt'
# 解决方法:转换为日期类型,处理异常值
df["日期"] = pd.to_datetime(df["日期"], errors="coerce", format="%Y-%m-%d")
# 补充处理其他格式
df.loc[df["日期"].isna(), "日期"] = pd.to_datetime(df.loc[df["日期"].isna(), "日期"], errors="coerce", format="%Y/%m/%d")
df.loc[df["日期"].isna(), "日期"] = pd.to_datetime(df.loc[df["日期"].isna(), "日期"].str.replace("年", "-").str.replace("月", "-").str.replace("日", ""), errors="coerce")
print("\n转换后日期列:")
print(df["日期"])
print("提取年份:", df["日期"].dt.year) # 正常提取
13.2 索引与选择相关问题
问题1:loc/iloc 索引报错(KeyError/IndexError)
原因:loc 传入位置索引,或 iloc 传入标签索引;或索引值不存在。排查方法:用 df.index 查看行索引,确认索引类型(标签/位置)。
import pandas as pd
df = pd.DataFrame({
"A": [1, 2, 3],
"B": [4, 5, 6]
}, index=["a", "b", "c"]) # 标签索引
# 排查:错误用法
try:
print(df.loc[0]) # loc 传入位置索引,报错 KeyError
except KeyError as e:
print("KeyError:", e)
try:
print(df.iloc["a"]) # iloc 传入标签索引,报错 IndexError
except TypeError as e:
print("TypeError:", e)
# 解决方法:正确区分 loc/iloc
print("\n正确用法:")
print("loc 按标签:", df.loc["a"])
print("iloc 按位置:", df.iloc[0])
问题2:条件筛选结果为空或异常
原因:条件表达式错误(如字符串包含空格、数值类型不匹配),或逻辑运算符使用错误(用 and/or 而非 &/|)。
import pandas as pd
df = pd.DataFrame({
"姓名": ["张三 ", "李四", "王五"], # 张三后有空格
"年龄": [22, 25, 23],
"薪资": [8000.0, 9500, 8800]
})
# 排查:筛选姓名为"张三"的行(结果为空)
print("错误筛选结果:")
print(df[df["姓名"] == "张三"]) # 无结果,因姓名后有空格
# 排查:多个条件用 and(报错)
try:
print(df[(df["年龄"] > 22) and (df["薪资"] > 9000)])
except ValueError as e:
print("错误:", e)
# 解决方法:清理字符串,使用正确逻辑运算符
df["姓名"] = df["姓名"].str.strip() # 清理空格
print("\n正确筛选结果:")
print(df[df["姓名"] == "张三"])
print(df[(df["年龄"] > 22) & (df["薪资"] > 9000)]) # 用 & 连接条件
13.3 内存与效率相关问题
问题1:大数据量读取时内存溢出
原因:数据量超过内存容量,或数据类型未优化导致内存占用过高。排查方法:用 df.memory_usage() 查看内存占用,优化数据类型或分块读取。
import pandas as pd
# 解决方法1:分块读取
chunk_iter = pd.read_csv("big_data.csv", chunksize=10000) # 每块10000行
total_sales = 0
for chunk in chunk_iter:
total_sales += chunk[chunk["支付状态"] == "已支付"]["支付金额"].sum()
print("总销售额(分块计算):", total_sales)
# 解决方法2:优化数据类型读取
df = pd.read_csv(
"big_data.csv",
dtype={
"用户ID": "int32", # 小范围整数用 int32
"支付金额": "float32",
"商品品类": "category" # 分类列用 category
}
)
print("\n优化后内存占用:", df.memory_usage(deep=True).sum() / 1024 / 1024, "MB")
问题2:代码运行缓慢(循环遍历导致)
原因:使用 Python 循环遍历 DataFrame/Series,效率极低。排查方法:替换为向量化操作、apply 或 groupby 方法。
import pandas as pd
import numpy as np
import time
df = pd.DataFrame({"数值": np.random.randint(0, 1000, 100000)})
# 排查:循环遍历(缓慢)
start_time = time.time()
df["循环标签"] = ""
for i in range(len(df)):
if df.loc[i, "数值"] < 300:
df.loc[i, "循环标签"] = "低"
else:
df.loc[i, "循环标签"] = "高"
loop_time = time.time() - start_time
# 解决方法:向量化操作(快速)
start_time = time.time()
df["向量化标签"] = np.where(df["数值"] < 300, "低", "高")
vec_time = time.time() - start_time
print(f"循环耗时:{loop_time:.4f} 秒")
print(f"向量化耗时:{vec_time:.4f} 秒")
print(f"效率提升:{loop_time/vec_time:.2f} 倍")
13.4 调试工具与技巧
- 基础调试:用 print 输出关键信息(数据类型、形状、前几行),用 df.info()、df.dtypes、df.shape 快速排查数据结构问题。
- 异常捕获:用 try-except 捕获异常,打印错误信息,定位问题位置,如捕获 KeyError、ValueError 等高频异常。
- 逐步执行:在 Jupyter Notebook 中逐行运行代码,观察每一步结果,定位错误发生的具体代码行。
- 工具辅助:使用 pandas_profiling 库生成数据概览报告,自动检测缺失值、异常值、数据类型问题(pip install ydata-profiling)。
第14章:pandas 学习资源与进阶方向
掌握 pandas 基础与进阶用法后,需通过优质资源深化学习,并结合实际场景拓展技能边界。本章将推荐学习资源、实战项目及进阶方向,助力从“会用”到“精通”。
14.1 优质学习资源
官方文档
- pandas 官方文档:最权威、最全面的学习资源,包含所有方法的详细说明、参数解释及示例代码,适合随时查阅。地址:https://pandas.pydata.org/docs/。
- pandas 官方教程:针对初学者设计,从基础到进阶,步骤清晰,适合系统学习。地址:https://pandas.pydata.org/docs/getting_started/index.html。
书籍推荐
- 《利用 Python 进行数据分析》(作者:Wes McKinney):pandas 创始人编写,数据分析领域经典书籍,深入讲解 pandas 核心用法及数据分析流程,适合进阶学习。
- 《Python for Data Analysis》(第3版):英文原版,同步更新 pandas 最新特性,适合想接触前沿内容的学习者。
- 《Pandas 实战》(作者:托马兹·卡拉斯):通过大量实战案例讲解 pandas 应用,注重解决实际问题,适合提升实战能力。
在线课程与平台
- DataCamp - Pandas 课程:交互式学习,边学边练,适合初学者快速入门,课程分为基础、中级、高级三个阶段。
- Coursera - 数据分析专项课程:由约翰霍普金斯大学开设,涵盖 pandas、Matplotlib、SQL 等工具,体系完整,适合系统构建数据分析能力。
- B站/YouTube:大量免费教学视频,如“黑马程序员”“尚硅谷”的 pandas 教程(适合中文学习者),“Corey Schafer”的 Python 数据分析系列(英文优质内容)。
社区与论坛
- Stack Overflow:全球最大的编程问答社区,搜索 pandas 相关问题,几乎都能找到解决方案,适合排查疑难问题。
- GitHub:pandas 开源仓库,可查看源码、提交 Issue、参与贡献,深入理解底层实现;同时有大量开源项目,可借鉴实战代码。
- 知乎/掘金:中文技术社区,有大量数据分析从业者分享的 pandas 实战技巧、踩坑经验,适合结合国内场景学习。
14.2 实战项目推荐
实战是提升 pandas 能力的核心,以下项目从易到难,覆盖不同应用场景,可结合公开数据集练习。
- 基础项目:电商订单数据分析数据集:Kaggle 电商订单数据集(包含订单信息、用户信息、商品信息)。任务:数据清洗(缺失值、异常值处理)、销售趋势分析、用户消费特征分析、商品品类表现分析,生成可视化报告。
- 中级项目:股票数据分析数据集:Tushare 或 Yahoo Finance 股票数据(包含开盘价、收盘价、成交量等)。任务:计算移动平均线、收益率、波动率等指标,分析股票走势,构建简单的交易信号策略,可视化展示结果。
- 高级项目:用户行为分析与推荐数据集:MovieLens 电影评分数据集(包含用户评分、电影信息)。任务:用户画像构建、电影评分预测、基于协同过滤的推荐系统实现,结合 Scikit-learn 构建模型。
- 综合项目:数据自动化报告生成需求:从数据库读取数据,自动完成清洗、分析、可视化,生成 PDF/Excel 格式分析报告,结合 Airflow 实现定时调度。技术栈:pandas + SQLAlchemy + Matplotlib + ReportLab(PDF生成)+ Airflow。
14.3 进阶学习方向
1. 大数据量处理与并行计算
针对 GB/TB 级数据,学习 Dask、Vaex 等库,实现并行计算和内存高效处理;掌握 Parquet、Feather 等高效文件格式的使用,提升数据读写速度。
2. 时间序列分析
深入学习 pandas 时间序列工具(resample、rolling、shift 等),结合 statsmodels 库进行时间序列建模(如 ARIMA、SARIMA),应用于销量预测、股价分析等场景。
3. 数据可视化进阶
除 Matplotlib/Seaborn 外,学习 Plotly、Bokeh 等交互式可视化库,生成可交互图表;学习 Tableau 与 pandas 结合,实现更专业的数据分析仪表盘。
4. 机器学习与深度学习集成
将 pandas 与 Scikit-learn、TensorFlow/PyTorch 深度集成,实现端到端机器学习流程(数据预处理→特征工程→模型训练→预测评估);学习特征工程高级技巧(特征交叉、特征选择等)。
5. 数据工程与自动化
学习数据管道构建(如 Airflow、Prefect),实现数据读取、处理、分析、报告的全流程自动化;学习 PySpark 与 pandas 结合,处理大规模分布式数据。
14.4 学习建议
- 循序渐进,注重基础:先掌握 Series、DataFrame 核心操作,再学习聚合、分组、合并等进阶功能,避免跳过基础直接学复杂技巧。
- 多练多总结:每学一个方法,结合实际数据练习;遇到问题先自行排查(查文档、搜社区),解决后总结经验,形成自己的知识体系。
- 结合业务场景:数据分析的核心是解决业务问题,学习时多思考“这个方法能解决什么业务场景”,避免纯技术层面的学习。
- 关注版本更新:pandas 迭代较快,定期关注官方文档更新,学习新特性(如 pandas 2.0+ 的 Arrow 引擎,大幅提升性能)。
附录:pandas 常用方法速查表
为方便快速查阅,本附录整理了 pandas 核心方法,按功能分类,涵盖基础操作、数据清洗、聚合分析、数据读写等场景。
一、基础数据结构操作
| 方法 | 功能描述 | 示例 |
|---|---|---|
| pd.Series() | 创建一维 Series | pd.Series([1,2,3], index=["a","b","c"]) |
| pd.DataFrame() | 创建二维 DataFrame | pd.DataFrame({"A":[1,2],"B":[3,4]}) |
| df.head(n) | 查看前 n 行数据(默认 5 行) | df.head(3) |
| df.tail(n) | 查看后 n 行数据 | df.tail(2) |
| df.info() | 查看数据基本信息(类型、缺失值) | df.info() |
| df.shape | 查看数据形状(行数, 列数) | print(df.shape) |
| df.dtypes | 查看各列数据类型 | print(df.dtypes) |
二、数据读取与写入
| 方法 | 功能描述 | 示例 |
|---|---|---|
| pd.read_csv() | 读取 CSV 文件 | pd.read_csv("data.csv", encoding="utf-8") |
| pd.read_excel() | 读取 Excel 文件 | pd.read_excel("data.xlsx", sheet_name="Sheet1") |
| df.to_csv() | 写入 CSV 文件 | df.to_csv("output.csv", index=False) |
| df.to_excel() | 写入 Excel 文件 | df.to_excel("output.xlsx", sheet_name="结果", index=False) |
| pd.read_sql() | 读取数据库数据 | pd.read_sql(sql="SELECT * FROM users", con=engine) |
三、数据清洗
| 方法 | 功能描述 | 示例 |
|---|---|---|
| df.isnull() | 判断缺失值(返回布尔值) | df.isnull().sum() |
| df.dropna() | 删除缺失值 | df.dropna(subset=["金额"]) |
| df.fillna() | 填充缺失值 | df["年龄"].fillna(df["年龄"].mean()) |
| df.duplicated() | 判断重复行 | df[df.duplicated()] |
| df.drop_duplicates() | 删除重复行 | df.drop_duplicates(subset=["订单ID"]) |
| pd.to_datetime() | 转换为日期类型 | df["日期"] = pd.to_datetime(df["日期"]) |
四、数据选择与索引
| 方法 | 功能描述 | 示例 |
|---|---|---|
| df.loc[] | 按标签选择 | df.loc[["a","b"], ["A","B"]] |
| df.iloc[] | 按位置选择 | df.iloc[0:2, 0:1] |
| df[条件] | 条件筛选 | df[df["金额"] > 1000] |
| df[列名] | 选择单列/多列 | df[["A","B"]] |
| df.isin() | 按列表筛选 | df[df["品类"].isin(["家电","服饰"])] |
五、数据聚合与分组
| 方法 | 功能描述 | 示例 |
|---|---|---|
| df.groupby() | 分组操作 | df.groupby("品类")["金额"].sum() |
| df.agg() | 多函数聚合 | df.groupby("品类").agg({"金额":["sum","mean"]}) |
| df.pivot_table() | 数据透视表 | pd.pivot_table(df, index="品类", values="金额", aggfunc="sum") |
| df.merge() | 合并数据 | pd.merge(df1, df2, on="用户ID", how="left") |
| pd.concat() | 拼接数据 | pd.concat([df1, df2], axis=0) |
六、数据变换
| 方法 | 功能描述 | 示例 |
|---|---|---|
| df.apply() | 应用自定义函数 | df["金额"].apply(lambda x: x*0.8) |
| df.map() | 元素级映射 | df["性别"].map({"男":1,"女":0}) |
| df.assign() | 新增列 | df.assign(折扣价=df["金额"]*0.8) |
| df.rename() | 重命名列/索引 | df.rename(columns={"金额":"销售额"}) |
| df.sort_values() | 排序 | df.sort_values(by="金额", ascending=False) |
总结
本手册从 pandas 基础入门到进阶实战,覆盖了数据分析全流程所需的核心技能。学好 pandas 的关键在于“理解原理+大量实战”,建议结合实际数据集反复练习,将方法内化为技能。随着学习的深入,可逐步探索大数据处理、机器学习集成等进阶方向,让 pandas 成为数据分析工作中的得力工具。祝您在数据分析的道路上不断进步!
(注:文档部分内容可能由 AI 生成)