Pandas 数据处理进阶:缺失值、合并、分组聚合与透视表

Pandas 数据处理进阶:缺失值、合并、分组聚合与透视表

在完成 pandas 的基础操作(索引、筛选、赋值、函数应用)之后,下一步便是处理真实数据中常见的问题:缺失值、多表合并、分组统计以及数据透视。本文带你系统掌握这些核心技能,并提供可直接运行的代码示例。

目录

  1. 数据清洗:缺失值处理
    • 1.1 检测缺失值
    • 1.2 删除缺失值
    • 1.3 填充缺失值
    • 1.4 自定义替换为 NaN
  2. [数据合并:concat 与 merge](#数据合并:concat 与 merge)
    • 2.1 concat:轴向拼接
    • 2.2 merge:键值关联
    • 2.3 join:基于索引的合并
  3. [分组与聚合:groupby 的威力](#分组与聚合:groupby 的威力)
    • 3.1 基础分组
    • 3.2 多列分组
    • 3.3 聚合函数 agg
    • 3.4 过滤与变换
  4. 透视表与交叉表
    • 4.1 交叉表 crosstab:频数统计
    • 4.2 透视表 pivot_table:灵活聚合
    • 4.3 多级透视
  5. 综合实战:电商订单数据分析
  6. 小结与进阶建议

1. 数据清洗:缺失值处理

真实数据往往不完整,pandas 提供了丰富的缺失值处理工具。

1.1 检测缺失值

  • isna() / isnull():返回布尔型 DataFrame,True 表示缺失。
  • isna().any(axis=?):检查每列/行是否有缺失。
  • isna().sum():统计每列缺失数量。
python 复制代码
import pandas as pd
import numpy as np

df = pd.DataFrame({
    'A': [1, 2, np.nan, 4],
    'B': [5, np.nan, np.nan, 8],
    'C': [9, 10, 11, 12]
})

print(df.isna())
print(df.isna().any())      # 每列是否有缺失
print(df.isna().sum())      # 每列缺失个数

1.2 删除缺失值:dropna

python 复制代码
# 删除任何含有缺失值的行
df_clean = df.dropna()

# 删除任何含有缺失值的列
df_clean = df.dropna(axis=1)

# 仅当某列全部缺失时才删除
df_clean = df.dropna(how='all')

# 指定 subset:仅检查特定列
df_clean = df.dropna(subset=['A', 'B'])

1.3 填充缺失值:fillna

python 复制代码
# 用常数填充
df_filled = df.fillna(0)

# 用前一个值填充(向前填充)
df_filled = df.fillna(method='ffill')

# 用后一个值填充
df_filled = df.fillna(method='bfill')

# 针对不同列用不同值
df_filled = df.fillna({'A': 0, 'B': df['B'].mean()})

1.4 自定义替换为 NaN

某些数据中,特殊值(如 "N/A"-10)应视为缺失。

python 复制代码
df = df.replace({'N/A': np.nan, -1: np.nan, 0: np.nan})
# 或原地修改
df.replace({'N/A': np.nan, 0: np.nan}, inplace=True)

2. 数据合并:concat 与 merge

2.1 concat:轴向拼接

  • axis=0:纵向拼接(上下堆叠),要求列名一致。
  • axis=1:横向拼接(左右并排),要求行索引对齐。
  • ignore_index=True:重置索引。
python 复制代码
df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})

# 纵向拼接
df_vertical = pd.concat([df1, df2], axis=0, ignore_index=True)

# 横向拼接
df_horizontal = pd.concat([df1, df2], axis=1)

2.2 merge:键值关联(类似 SQL JOIN)

python 复制代码
left = pd.DataFrame({'key': ['X', 'Y', 'Z'], 'value_left': [1, 2, 3]})
right = pd.DataFrame({'key': ['X', 'Y', 'W'], 'value_right': [4, 5, 6]})

# 内连接(默认)
inner = pd.merge(left, right, on='key', how='inner')

# 左连接
left_join = pd.merge(left, right, on='key', how='left')

# 右连接
right_join = pd.merge(left, right, on='key', how='right')

# 外连接(全连接)
outer = pd.merge(left, right, on='key', how='outer')

# 多列关联:on=['col1', 'col2']
# 处理重复列名:suffixes=('_x', '_y')

2.3 join:基于索引的合并

python 复制代码
left = pd.DataFrame({'A': [1, 2]}, index=['a', 'b'])
right = pd.DataFrame({'B': [3, 4]}, index=['a', 'c'])
result = left.join(right, how='left')   # 默认左连接,基于索引

3. 分组与聚合:groupby 的威力

分组聚合是数据分析的核心范式:split-apply-combine

3.1 单字段分组

python 复制代码
df = pd.DataFrame({
    '类别': ['A', 'A', 'B', 'B', 'C'],
    '销售额': [100, 150, 200, 250, 300],
    '成本': [60, 80, 120, 140, 180]
})

grouped = df.groupby('类别')
print(grouped['销售额'].mean())   # 每类平均销售额
print(grouped['销售额'].sum())

3.2 多字段分组

python 复制代码
df['城市'] = ['北京', '上海', '北京', '上海', '北京']
grouped_multi = df.groupby(['类别', '城市'])
print(grouped_multi['销售额'].sum())

3.3 聚合函数 agg

  • 单列单函数:.agg({'列名': 'mean'})
  • 单列多函数:.agg({'销售额': ['sum', 'mean', 'count']})
  • 多列不同函数:.agg({'销售额': 'sum', '成本': 'mean'})
  • 自定义函数:.agg(lambda x: x.max() - x.min())
python 复制代码
result = df.groupby('类别').agg({
    '销售额': ['sum', 'mean'],
    '成本': 'min'
})
print(result)

3.4 过滤与变换

  • filter:根据分组条件过滤组(保留满足条件的整个组)。
  • transform:将聚合结果广播回原始行,常用于添加组内统计列。
python 复制代码
# 保留销售额总和大于 400 的组
filtered = df.groupby('类别').filter(lambda x: x['销售额'].sum() > 400)

# 添加组内平均值列
df['销售额_组内均指'] = df.groupby('类别')['销售额'].transform('mean')

4. 透视表与交叉表

4.1 交叉表 crosstab:频数统计

pd.crosstab 用于计算两个(或多个)分类变量的频数分布。

python 复制代码
df = pd.DataFrame({
    '性别': ['男', '女', '男', '女', '男'],
    '城市': ['北京', '上海', '北京', '北京', '上海'],
    '购买次数': [1, 3, 2, 1, 4]
})

# 性别 vs 城市的频数表
ct = pd.crosstab(df['性别'], df['城市'])
print(ct)

# 添加行/列总计
ct_margins = pd.crosstab(df['性别'], df['城市'], margins=True, margins_name='总计')

4.2 透视表 pivot_table:灵活聚合

类似 Excel 数据透视表,可指定行、列、值、聚合函数。

python 复制代码
# 按性别和城市,统计购买次数的平均值
pt = pd.pivot_table(df, 
                    values='购买次数', 
                    index='性别', 
                    columns='城市', 
                    aggfunc='mean')
print(pt)

# 多个聚合函数
pt_multi = pd.pivot_table(df,
                          values='购买次数',
                          index='性别',
                          columns='城市',
                          aggfunc=['sum', 'count'])

4.3 多级 index / 多 values

python 复制代码
# 多级行索引
pt_levels = pd.pivot_table(df,
                           values='购买次数',
                           index=['性别', '城市'],
                           aggfunc='sum')

# 多 values 列
pt_multi_values = pd.pivot_table(df,
                                 values=['购买次数', '性别'],
                                 index='城市',
                                 aggfunc='count')

5. 综合实战:电商订单数据分析

模拟一个电商订单数据集,完成从清洗到聚合的全流程。

python 复制代码
import pandas as pd
import numpy as np

# 创建订单数据
orders = pd.DataFrame({
    'order_id': range(1, 11),
    'user_id': [101, 102, 101, 103, 104, 101, 102, 105, 103, 106],
    'category': ['电子产品', '服装', '电子产品', '食品', '服装', '电子产品', '服装', '食品', '食品', '电子产品'],
    'amount': [299, 89, 450, 35, 120, 310, 150, 45, 60, 520],
    'discount': [0.1, 0.0, 0.15, 0.0, 0.05, 0.1, 0.0, 0.0, 0.05, 0.2]
})

# 故意引入一个缺失值
orders.loc[5, 'amount'] = np.nan

print("原始数据:")
print(orders)

# 1. 缺失值处理:用该品类平均金额填充
category_avg = orders.groupby('category')['amount'].transform('mean')
orders['amount'].fillna(category_avg, inplace=True)

# 2. 计算实际支付金额(金额 * (1 - 折扣))
orders['paid'] = orders['amount'] * (1 - orders['discount'])

# 3. 分组聚合:每用户的总支付金额和订单数
user_stats = orders.groupby('user_id').agg(
    总支付=('paid', 'sum'),
    订单数=('order_id', 'count')
).reset_index()

print("\n用户统计:")
print(user_stats)

# 4. 透视表:各类别在不同折扣区间的平均支付金额
orders['discount_bin'] = pd.cut(orders['discount'], bins=[-0.01, 0.05, 0.15, 0.21], labels=['低折扣', '中折扣', '高折扣'])
pt = pd.pivot_table(orders, values='paid', index='category', columns='discount_bin', aggfunc='mean')
print("\n透视表(品类×折扣区间 平均支付):")
print(pt)

# 5. 交叉表:用户 vs 品类购买频数
ct = pd.crosstab(orders['user_id'], orders['category'])
print("\n用户购买品类频次:")
print(ct)

6. 小结与进阶建议

本文系统介绍了 pandas 中四个核心进阶功能:

功能 核心方法 典型场景
缺失值处理 isna(), dropna(), fillna() 数据清洗
数据合并 concat(), merge(), join() 多表关联
分组聚合 groupby(), agg(), transform(), filter() 统计分析
透视表/交叉表 pivot_table(), crosstab() 多维汇总

经验法则

  • 处理缺失时,优先分析缺失原因,合理填充或删除。
  • 合并数据前确保关联键的数据类型一致。
  • 分组聚合时使用 agg 一次完成多个统计,代码更清晰。
  • 透视表是快速生成报表的利器,尤其是多维度交叉分析。

进阶方向

  • 时间序列数据的重采样(resample
  • 窗口函数(rolling, expanding
  • 性能优化:使用 eval()query() 处理大数据
  • 结合 matplotlib / seaborn 做可视化分析

建议读者将本文代码逐一运行,并尝试修改参数观察结果。掌握这些技能,你就能应对绝大多数数据处理需求。

相关推荐
hef2881 小时前
探索Pandas groupby的各种技巧和应用实例
pandas
结衣结衣.2 小时前
走进机器学习:新手必看的完整入门指南
人工智能·python·学习·机器学习
绘梨衣5472 小时前
某公开数据简单逆向
python·beautifulsoup
小江的记录本2 小时前
【Java并发编程】锁机制:volatile:JMM内存模型、可见性/禁止指令重排、内存屏障、单例模式中的应用(附《思维导图》+《面试高频考点清单》)
java·后端·python·mysql·单例模式·面试·职场和发展
csdn小瓯2 小时前
前端工程化:React + TypeScript + Tailwind CSS 的组件化实践
开发语言·人工智能·python
hef2882 小时前
R包grafify:简单操作实现高效统计绘图
开发语言·python·r语言
这是谁的博客?2 小时前
Python 异步编程核心原理与实践深度解析
java·网络·python·协程·asyncio·异步编程
战南诚2 小时前
力扣 之 198.打家劫舍
python·算法·leetcode
晚烛2 小时前
CANN 模型预热:消除首次推理延迟
开发语言·python