当前位置:首页>python>Python 零基础100天—Day75 Pandas 数据合并

Python 零基础100天—Day75 Pandas 数据合并

  • 2026-10-11 07:06:11
Python 零基础100天—Day75 Pandas 数据合并

🐍 Python Day75:Pandas 数据合并 — 多表关联与透视表

🕐 预计用时:2-3 小时 | 🎯 目标:掌握 merge、concat、join、透视表和交叉表


📖 今日目录

  1. merge(类似 SQL JOIN)
  2. concat(拼接)
  3. join(索引合并)
  4. 透视表(pivot_table)
  5. 交叉表(crosstab)
  6. melt(宽表转长表)
  7. 今日练习
  8. 今日小结

1. merge(类似 SQL JOIN)

import pandas as pd# 订单表orders = pd.DataFrame({    '订单号': [1001, 1002, 1003, 1004, 1005],    '客户ID': [1, 2, 1, 3, 2],    '金额': [100, 200, 150, 300, 250]})# 客户表customers = pd.DataFrame({    '客户ID': [1, 2, 3, 4],    '姓名': ['小明', '小红', '小刚', '小美'],    '城市': ['北京', '上海', '广州', '深圳']})# === 内连接(默认)—— 只保留两表都有的 ===pd.merge(orders, customers, on='客户ID')#   订单号  客户ID  金额  姓名  城市# 0  1001      1  100  小明  北京# 1  1002      2  200  小红  上海# 2  1003      1  150  小明  北京# 3  1004      3  300  小刚  广州# 4  1005      2  250  小红  上海# 注意:客户ID=4(小美)没有出现,因为她没有订单# merge 默认 sort=False,保留左表(orders)的行顺序# === 左连接 —— 保留左表所有行 ===pd.merge(orders, customers, on='客户ID', how='left')# === 右连接 —— 保留右表所有行 ===pd.merge(orders, customers, on='客户ID', how='right')# 小美(客户ID=4)也会出现,金额为 NaN# === 外连接 —— 保留所有行 ===pd.merge(orders, customers, on='客户ID', how='outer')# === 列名不同时用 left_on / right_on ===df1 = pd.DataFrame({'客户编号': [1, 2], '金额': [100, 200]})df2 = pd.DataFrame({'id': [1, 2], '姓名': ['小明', '小红']})pd.merge(df1, df2, left_on='客户编号', right_on='id')# === 多列合并 ===pd.merge(df1, df2, on=['列1', '列2'])
连接方式
SQL 等价
Pandas
说明
内连接
INNER JOIN
how='inner'
只保留两表都有的
左连接
LEFT JOIN
how='left'
保留左表所有行
右连接
RIGHT JOIN
how='right'
保留右表所有行
外连接
FULL OUTER
how='outer'
保留所有行

2. concat(拼接)

import pandas as pd# 纵向拼接(上下堆叠)—— 行数增加df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})pd.concat([df1, df2])#    A  B# 0  1  3# 1  2  4# 0  5  7# 1  6  8# 重置索引pd.concat([df1, df2], ignore_index=True)# 横向拼接(左右拼接)—— 列数增加df1 = pd.DataFrame({'A': [1, 2]})df2 = pd.DataFrame({'B': [3, 4]})pd.concat([df1, df2], axis=1)#    A  B# 0  1  3# 1  2  4# 列名不完全一致时df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})df2 = pd.DataFrame({'B': [5, 6], 'C': [7, 8]})pd.concat([df1, df2], ignore_index=True, sort=True)# 缺失的列用 NaN 填充# 标记来源pd.concat([df1, df2], keys=['表1', '表2'])#       A  B    C# 表1 0  1  3  NaN#    1  2  4  NaN# 表2 0 NaN  5  7#    1 NaN  6  8

💡 merge vs concat:• merge:按某列关联(类似 SQL JOIN)→ 左右扩展• concat:简单拼接(上下堆叠或左右拼接)→ 不需要关联键问自己:两张表有没有"共同字段"要关联?有 → 用 merge | 没有 → 用 concat


3. join(索引合并)

import pandas as pd# join 是 merge 的简化版——基于索引合并df1 = pd.DataFrame({'A': [1, 2, 3]}, index=['a', 'b', 'c'])df2 = pd.DataFrame({'B': [4, 5, 6]}, index=['a', 'b', 'd'])df1.join(df2)       # 左连接(默认)#    A    B# a  1  4.0# b  2  5.0# c  3  NaNdf1.join(df2, how='inner')   # 内连接#    A  B# a  1  4# b  2  5df1.join(df2, how='outer')   # 外连接#      A    B# a  1.0  4.0# b  2.0  5.0# c  3.0  NaN# d  NaN  6.0# 多表 joindf3 = pd.DataFrame({'C': [7, 8]}, index=['a', 'b'])df1.join([df2, df3])

4. 透视表(pivot_table)

import pandas as pddf = pd.DataFrame({    '日期': ['2026-01', '2026-01', '2026-02', '2026-02', '2026-03', '2026-03'],    '部门': ['技术', '市场', '技术', '市场', '技术', '市场'],    '城市': ['北京', '上海', '北京', '上海', '北京', '上海'],    '薪资': [15000, 12000, 18000, 15000, 16000, 13000]})# === 基本透视表 ===df.pivot_table(    values='薪资',        # 要聚合的值    index='部门',          # 行    aggfunc='mean'         # 聚合函数)#       薪资# 部门# 市场  13333# 技术  16333# === 多维透视表 ===df.pivot_table(    values='薪资',    index='部门',    columns='城市',    aggfunc='mean',    fill_value=0)# 城市    上海    北京# 部门# 市场  13333      0# 技术      0  16333# 注:数据中"市场"只在"上海","技术"只在"北京",交叉组合无数据用 fill_value=0 填充# === 多个聚合函数 ===df.pivot_table(    values='薪资',    index='部门',    aggfunc=['mean', 'sum', 'count'])# === 边际汇总(margins=True)===df.pivot_table(    values='薪资',    index='部门',    columns='城市',    aggfunc='sum',    margins=True,          # 添加行列合计    margins_name='合计')# === 类似 SQL 的分组统计 ===# 每个部门的平均薪资、最高薪资、人数df.pivot_table(    values='薪资',    index='部门',    aggfunc={'薪资': ['mean', 'max', 'count']})

5. 交叉表(crosstab)

import pandas as pd# 交叉表:统计两个分类变量的频次df = pd.DataFrame({    '性别': ['男', '女', '男', '女', '男', '女', '男'],    '是否吸烟': ['是', '否', '是', '是', '否', '否', '否'],    '年龄': [25, 30, 35, 28, 40, 22, 33]})pd.crosstab(df['性别'], df['是否吸烟'])# 是否吸烟  否  是# 性别# 女       2  1# 男       2  2# 带归一化(比例)pd.crosstab(df['性别'], df['是否吸烟'], normalize='index')  # 按行归一化pd.crosstab(df['性别'], df['是否吸烟'], normalize='columns')  # 按列归一化# 带边际汇总pd.crosstab(df['性别'], df['是否吸烟'], margins=True)# 带聚合值pd.crosstab(    df['性别'],    df['是否吸烟'],    values=df['年龄'],     # 聚合的值    aggfunc='mean'         # 平均年龄)

6. melt(宽表转长表)

import pandas as pd# 宽表(人好读)wide = pd.DataFrame({    '姓名': ['小明', '小红'],    '语文': [90, 85],    '数学': [95, 88],    '英语': [88, 92]})# 宽表 → 长表(机器好处理)long = pd.melt(    wide,    id_vars=['姓名'],         # 保持不变的列    var_name='科目',          # 列名 → 新列名    value_name='成绩'         # 值 → 新列名)#    姓名  科目  成绩# 0  小明  语文   90# 1  小红  语文   85# 2  小明  数学   95# 3  小红  数学   88# 4  小明  英语   88# 5  小红  英语   92# 长表 → 宽表(人好读)wide_again = long.pivot_table(    index='姓名',    columns='科目',    values='成绩').reset_index()

💡 宽表 vs 长表:• 宽表:每列一个变量,人好读 → 适合报表展示• 长表:所有值在一列,机器好处理 → 适合数据分析、可视化melt() = 宽 → 长 | pivot_table() = 长 → 宽


7. 今日练习

🏋️ 练习 1:订单分析

# 创建订单表和商品表:# 1. 用 merge 关联,得到每笔订单的商品名称和单价# 2. 计算每个商品的总销售额# 3. 用 pivot_table 生成 商品×月份 的销售额透视表

🏋️ 练习 2:多表拼接

# 有 3 个月的销售数据(1月、2月、3月各一个 CSV)# 1. 用 concat 合并为一个 DataFrame# 2. 添加"月份"列标记来源# 3. 按月份分组统计总销售额

🏋️ 练习 3:宽表长表转换

# 给定一个宽表格式的成绩单:# 姓名 | 语文 | 数学 | 英语# 1. 用 melt 转为长表# 2. 用 pivot_table 转回宽表# 3. 用 crosstab 统计各等级的人数

8. 今日小结

知识点
核心内容
merge
按列关联(inner/left/right/outer),类似 SQL JOIN
concat
简单拼接(axis=0 上下 / axis=1 左右)
join
基于索引合并,merge 的简化版
pivot_table
透视表:values + index + columns + aggfunc
crosstab
交叉表:统计两个分类变量的频次
melt
宽表转长表:id_vars + var_name + value_name

🎉 Pandas 阶段完结!Day 73-75 你掌握了 Pandas 三大核心:✅ 数据读写 · 索引筛选 · 缺失值处理✅ 分组聚合 · 数据合并 · 透视表 · 宽长表转换接下来进入 Matplotlib 可视化(Day 76)—— 把数据变成图表,让数据"说话"!

最新文章

随机文章