查看全课大纲(第 59 / 101 节)
  1. 1.数据分析基本概念
  2. 2.学习数据分析的一般路线
  3. 3.数据分析的流程
  4. 4.数据类型
  5. 5.环境部署(1)
  6. 6.环境部署(2)
  7. 7.课程介绍
  8. 8.TXT文件操作
  9. 9.JSON文件操作
  10. 10.CSV文件操作
  11. 11.Excel文件操作
  12. 12.数据库及SQL常用语法
  13. 13.数据库基本操作
  14. 14.数据库多表连接
  15. 15.实战:欧洲职业足球数据库分析
  16. 16.爬虫简介
  17. 17.URL管理模块
  18. 18.网页下载模块
  19. 19.网页解析模块(1)
  20. 20.网页解析模块(2)
  21. 21.Scrapy简介
  22. 22.Scrapy使用步骤(1)
  23. 23.Scrapy使用步骤(2)
  24. 24.Scrapy使用步骤(3)
  25. 25.Scrapy使用步骤(4)
  26. 26.实战:获取国内城市空气质量指数数据
  27. 27.NumPy和SciPy介绍
  28. 28.多维数组
  29. 29.多维数组操作
  30. 30.NumPy的常用方法
  31. 31.向量化介绍
  32. 32.向量化及通用函数
  33. 33.实战:2016美国大选分析
  34. 34.数据结构-Series
  35. 35.数据结构-DataFrame
  36. 36.数据结构-Index
  37. 37.Series的索引操作
  38. 38.DataFrame的索引操作
  39. 39.索引操作总结
  40. 40.运算与对齐
  41. 41.函数应用操作(1) -- map
  42. 42.函数应用操作 (2) -- apply applymap
  43. 43.文件读写操作
  44. 44.排序操作
  45. 45.数据清洗--处理缺失数据
  46. 46.数据清洗--处理重复数据
  47. 47.数据清洗--替换数据
  48. 48.常用统计方法(1) -- describe quantile
  49. 49.常用统计方法(2) -- sum mean median count
  50. 50.常用统计方法(3) -- max min idxmax idxmin
  51. 51.常用统计方法(4) -- mad var std cumsum
  52. 52.实战:全球食品数据分析
  53. 53.层级索引
  54. 54.分组与聚合介绍
  55. 55.分组操作(1) -- GroupBy对象及常用聚合操作
  56. 56.分组操作(2) -- 自定义分组及聚合操作
  57. 57.透视表介绍
  58. 58.透视表操作
  59. 59.数据规整(1) -- 数据合并concat
  60. 60.数据规整(2) -- 数据连接merge
  61. 61.数据重构(3) -- 数据重构stack unstack
  62. 62.实战:互联网电影资料库分析
  63. 63.探索性数据分析EDA介绍
  64. 64.EDA的目的
  65. 65.EDA常用工具
  66. 66.Matplotlib绘图基本介绍
  67. 67.Matplotlib画布
  68. 68.散点图和柱状图的绘制
  69. 69.直方图的绘制
  70. 70.矩阵绘图
  71. 71.子图的使用
  72. 72.Matplotlib颜色、标记、线型
  73. 73.Matplotlib坐标刻度、标签、图例、标题
  74. 74.Seaborn介绍
  75. 75.数据集分布可视化(1) -- 单变量分布、双变量分布
  76. 76.数据集分布可视化(2) -- 变量关系可视化
  77. 77.类别数据可视化 -- 类别散布图、类别内数据分布、类别内统计图
  78. 78.交互式数据可视化工具Bokeh介绍
  79. 79.Bokeh绘制散点图、柱状图、盒子图、弦图
  80. 80.Bokeh绘制常用图形元素
  81. 81.3D绘图 -- mplot3d
  82. 82.3D曲线可视化
  83. 83.3D散点图可视化
  84. 84.3D柱状图可视化
  85. 85.Pandas绘图
  86. 86.实战:Lending Club借贷数据探索性分析及可视化
  87. 87.机器学习介绍及应用场景
  88. 88.机器学习建模介绍 (1) -- 分类
  89. 89.机器学习建模介绍 (2) -- 回归
  90. 90.机器学习建模介绍 (3) -- 聚类
  91. 91.机器学习分类
  92. 92.机器学习工具scikit-learn
  93. 93.使用scikit-learn的流程
  94. 94.数据集准备及划分
  95. 95.模型选择
  96. 96.数据预处理及特征工程
  97. 97.过拟合与欠拟合
  98. 98.模型调参介绍
  99. 99.模型调参方法
  100. 100.模型测试及评价
  101. 101.实战:通过移动设备行为数据预测性别和年龄

数据规整(1) -- 数据合并concat

约 9 分钟

📺 正在播放小象学院官方高清录播(支持倍速与清晰度调节)

用 pd.concat 合并数据

小象实战讲义 · Python数据分析实战

在实际数据分析工作中,我们常常需要将多个数据集合并成一个,例如将不同时间段、不同来源或不同维度的数据整合起来。Pandas 提供了强大的数据合并工具,其中 pd.concat 是最基础、最灵活的一个。本节将详细讲解如何使用 concat 函数,按照指定的轴方向合并多个 DataFrame,并深入理解其在不同列名和索引情况下的行为。

💡 核心导读

  • pd.concat 的基本用法:掌握如何通过 objs 和 axis 参数合并多个 DataFrame。
  • 纵向合并(axis=0):理解当列名相同时的简单堆叠,以及列名不同时自动补空的外连接行为。
  • 横向合并(axis=1):理解当行索引相同时的简单并排,以及行索引不同时自动补空的外连接行为。
  • 合并的本质:认识到 concat 默认使用外连接(outer join),确保所有数据都被保留,缺失位置用 NaN 填充。

认识 pd.concat

pd.concat 是 Pandas 中用于沿特定轴(行或列)将多个 Pandas 对象(通常是 DataFrame 或 Series)连接在一起的函数。它的核心参数有两个:

  • objs:一个需要合并的 Pandas 对象序列,通常是一个包含多个 DataFrame 的列表。
  • axis:指定合并方向的轴。axis=0 表示按索引方向(纵向)拼接,使数据“变长”;axis=1 表示按列方向(横向)拼接,使数据“变宽”。默认值为 0。

此外,concat 默认使用外连接(outer join)的方式进行合并。这意味着,在合并时,所有输入对象中的索引(或列名)都会被保留,对于在某个对象中不存在的索引(或列名),其对应的值会被填充为缺失值(NaN)。

为了演示,我们先构造三个简单的 DataFrame。

import pandas as pd
import numpy as np

# 构造第一个DataFrame:df1
df1 = pd.DataFrame({
    'A': ['A0', 'A1', 'A2', 'A3'],
    'B': ['B0', 'B1', 'B2', 'B3'],
    'C': ['C0', 'C1', 'C2', 'C3'],
    'D': ['D0', 'D1', 'D2', 'D3']
}, index=[0, 1, 2, 3])

# 构造第二个DataFrame:df2,列名与df1相同,行索引不同
df2 = pd.DataFrame({
    'A': ['A4', 'A5', 'A6', 'A7'],
    'B': ['B4', 'B5', 'B6', 'B7'],
    'C': ['C4', 'C5', 'C6', 'C7'],
    'D': ['D4', 'D5', 'D6', 'D7']
}, index=[4, 5, 6, 7])

# 构造第三个DataFrame:df3,部分列名与df1不同
df3 = pd.DataFrame({
    'C': ['C8', 'C9', 'C10', 'C11'],
    'D': ['D8', 'D9', 'D10', 'D11'],
    'E': ['E8', 'E9', 'E10', 'E11'],
    'F': ['F8', 'F9', 'F10', 'F11']
}, index=[0, 1, 2, 3])

print("df1:")
print(df1)
print("\ndf2:")
print(df2)
print("\ndf3:")
print(df3)
df1:
    A   B   C   D
0  A0  B0  C0  D0
1  A1  B1  C1  D1
2  A2  B2  C2  D2
3  A3  B3  C3  D3

df2:
    A   B   C   D
4  A4  B4  C4  D4
5  A5  B5  C5  D5
6  A6  B6  C6  D6
7  A7  B7  C7  D7

df3:
     C    D    E    F
0   C8   D8   E8   F8
1   C9   D9   E9   F9
2  C10  D10  E10  F10
3  C11  D11  E11  F11

纵向合并 (axis=0)

纵向合并是将多个 DataFrame 在垂直方向上堆叠起来,类似于在数据库中添加新的记录行。这是通过设置 axis=0(默认值)来实现的。

列名相同的情况

当所有要合并的 DataFrame 列名完全相同时,纵向合并是最直观的。Pandas 会简单地将它们上下堆叠,生成一个行数变多、列数不变的新 DataFrame。

import pandas as pd

# 重新构造df1和df2用于演示
df1_same_col = pd.DataFrame({
    'A': ['A0', 'A1', 'A2', 'A3'],
    'B': ['B0', 'B1', 'B2', 'B3'],
    'C': ['C0', 'C1', 'C2', 'C3'],
    'D': ['D0', 'D1', 'D2', 'D3']
}, index=[0, 1, 2, 3])

df2_same_col = pd.DataFrame({
    'A': ['A4', 'A5', 'A6', 'A7'],
    'B': ['B4', 'B5', 'B6', 'B7'],
    'C': ['C4', 'C5', 'C6', 'C7'],
    'D': ['D4', 'D5', 'D6', 'D7']
}, index=[4, 5, 6, 7])

result_vertical_same = pd.concat([df1_same_col, df2_same_col], axis=0)
print("纵向合并(列名相同):")
print(result_vertical_same)
纵向合并(列名相同):
    A   B   C   D
0  A0  B0  C0  D0
1  A1  B1  C1  D1
2  A2  B2  C2  D2
3  A3  B3  C3  D3
4  A4  B4  C4  D4
5  A5  B5  C5  D5
6  A6  B6  C6  D6
7  A7  B7  C7  D7

可以看到,df1 的 4 行和 df2 的 4 行被合并成了一个拥有 8 行的新 DataFrame,列保持不变。

列名不同的情况

如果待合并的 DataFrame 列名不完全相同,concat 会如何处理?它会采用外连接的策略:将所有出现过的列名都作为新 DataFrame 的列。对于某个 DataFrame 中不存在的列,其对应的行位置会被填充为 NaN。

import pandas as pd

# 重新构造df1和df3用于演示
df1_diff_col = pd.DataFrame({
    'A': ['A0', 'A1', 'A2', 'A3'],
    'B': ['B0', 'B1', 'B2', 'B3'],
    'C': ['C0', 'C1', 'C2', 'C3'],
    'D': ['D0', 'D1', 'D2', 'D3']
}, index=[0, 1, 2, 3])

df3_diff_col = pd.DataFrame({
    'C': ['C8', 'C9', 'C10', 'C11'],
    'D': ['D8', 'D9', 'D10', 'D11'],
    'E': ['E8', 'E9', 'E10', 'E11'],
    'F': ['F8', 'F9', 'F10', 'F11']
}, index=[0, 1, 2, 3])

result_vertical_diff = pd.concat([df1_diff_col, df3_diff_col], axis=0)
print("纵向合并(列名不同):")
print(result_vertical_diff)
纵向合并(列名不同):
     A    B    C    D    E    F
0   A0   B0   C0   D0  NaN  NaN
1   A1   B1   C1   D1  NaN  NaN
2   A2   B2   C2   D2  NaN  NaN
3   A3   B3   C3   D3  NaN  NaN
0  NaN  NaN   C8   D8   E8   F8
1  NaN  NaN   C9   D9   E9   F9
2  NaN  NaN  C10  D10  E10  F10
3  NaN  NaN  C11  D11  E11  F11

分析结果:

  • 新 DataFrame 的列是所有列名的并集:A, B, C, D, E, F。
  • 对于来自 df1 的前 4 行,列 E 和 F 不存在,因此填充为 NaN。
  • 对于来自 df3 的后 4 行,列 A 和 B 不存在,因此也填充为 NaN。
  • 列 C 和 D 是两个 DataFrame 共有的,因此数据被完整保留。

这就是“外连接”的体现:保留所有数据,缺失部分用空值填充。

横向合并 (axis=1)

横向合并是将多个 DataFrame 在水平方向上并排连接,类似于为现有数据表添加新的字段(列)。这是通过设置 axis=1 来实现的。

行索引相同的情况

当所有要合并的 DataFrame 行索引完全相同时,横向合并会简单地将它们左右并排,生成一个列数变多、行数不变的新 DataFrame。

import pandas as pd

# 重新构造df1和df3(它们行索引相同)
df1_same_idx = pd.DataFrame({
    'A': ['A0', 'A1', 'A2', 'A3'],
    'B': ['B0', 'B1', 'B2', 'B3'],
    'C': ['C0', 'C1', 'C2', 'C3'],
    'D': ['D0', 'D1', 'D2', 'D3']
}, index=[0, 1, 2, 3])

df3_same_idx = pd.DataFrame({
    'C': ['C8', 'C9', 'C10', 'C11'],
    'D': ['D8', 'D9', 'D10', 'D11'],
    'E': ['E8', 'E9', 'E10', 'E11'],
    'F': ['F8', 'F9', 'F10', 'F11']
}, index=[0, 1, 2, 3])

result_horizontal_same_idx = pd.concat([df1_same_idx, df3_same_idx], axis=1)
print("横向合并(行索引相同):")
print(result_horizontal_same_idx)
横向合并(行索引相同):
    A   B   C   D    C    D    E    F
0  A0  B0  C0  D0   C8   D8   E8   F8
1  A1  B1  C1  D1   C9   D9   E9   F9
2  A2  B2  C2  D2  C10  D10  E10  F10
3  A3  B3  C3  D3  C11  D11  E11  F11

结果中,df1 的列(A, B, C, D)和 df3 的列(C, D, E, F)被并排放在了一起。注意,列名 C 和 D 出现了重复,Pandas 会保留它们,这在某些情况下可能需要后续处理(如重命名)。

行索引不同的情况

如果待合并的 DataFrame 行索引不完全相同,concat 同样会采用外连接的策略:将所有出现过的行索引都作为新 DataFrame 的行索引。对于某个 DataFrame 中不存在的行索引,其对应的列位置会被填充为 NaN。

import pandas as pd

# 重新构造df1和df2(它们行索引不同)
df1_diff_idx = pd.DataFrame({
    'A': ['A0', 'A1', 'A2', 'A3'],
    'B': ['B0', 'B1', 'B2', 'B3'],
    'C': ['C0', 'C1', 'C2', 'C3'],
    'D': ['D0', 'D1', 'D2', 'D3']
}, index=[0, 1, 2, 3])

df2_diff_idx = pd.DataFrame({
    'A': ['A4', 'A5', 'A6', 'A7'],
    'B': ['B4', 'B5', 'B6', 'B7'],
    'C': ['C4', 'C5', 'C6', 'C7'],
    'D': ['D4', 'D5', 'D6', 'D7']
}, index=[4, 5, 6, 7])

result_horizontal_diff_idx = pd.concat([df1_diff_idx, df2_diff_idx], axis=1)
print("横向合并(行索引不同):")
print(result_horizontal_diff_idx)
横向合并(行索引不同):
     A    B    C    D    A    B    C    D
0   A0   B0   C0   D0  NaN  NaN  NaN  NaN
1   A1   B1   C1   D1  NaN  NaN  NaN  NaN
2   A2   B2   C2   D2  NaN  NaN  NaN  NaN
3   A3   B3   C3   D3  NaN  NaN  NaN  NaN
4  NaN  NaN  NaN  NaN   A4   B4   C4   D4
5  NaN  NaN  NaN  NaN   A5   B5   C5   D5
6  NaN  NaN  NaN  NaN   A6   B6   C6   D6
7  NaN  NaN  NaN  NaN   A7   B7   C7   D7

分析结果:

  • 新 DataFrame 的行索引是所有行索引的并集:0, 1, 2, 3, 4, 5, 6, 7。
  • 对于行索引 0-3,df2 中没有对应的数据,因此其对应的列(右边的 A, B, C, D)全部为 NaN。
  • 对于行索引 4-7,df1 中没有对应的数据,因此其对应的列(左边的 A, B, C, D)全部为 NaN。

这再次体现了外连接的原则:保留所有索引,确保没有数据丢失,缺失处用 NaN 补齐。

📝 动手练一练

  1. 概念辨析:pd.concat 在纵向合并(axis=0)时,如果遇到列名不同的情况,它是如何处理最终结果的列名的?这种行为对应数据库连接中的哪种连接类型?
👉 点击查看参考答案

pd.concat 在纵向合并时,如果列名不同,它会取所有输入 DataFrame 列名的并集作为最终结果的列名。对于某个 DataFrame 中不存在的列,在最终结果中对应的行位置会用缺失值 NaN 填充。这种行为对应数据库连接中的外连接(Outer Join),它保留了所有输入中的所有列(字段)。

  1. 动手实践:请创建两个小的 DataFrame,df_a 包含列 [‘X‘, ‘Y‘] 和索引 [0, 1],df_b 包含列 [‘Y‘, ‘Z‘] 和索引 [1, 2]。然后分别对它们进行: a) 纵向合并(axis=0),观察结果。 b) 横向合并(axis=1),观察结果。 手动计算或运行代码验证你的猜想。
👉 点击查看参考答案
import pandas as pd

df_a = pd.DataFrame({'X': ['x0', 'x1'], 'Y': ['y0', 'y1']}, index=[0, 1])
df_b = pd.DataFrame({'Y': ['y1', 'y2'], 'Z': ['z1', 'z2']}, index=[1, 2])

print("df_a:")
print(df_a)
print("\ndf_b:")
print(df_b)

print("\n纵向合并 (axis=0):")
print(pd.concat([df_a, df_b], axis=0))

print("\n横向合并 (axis=1):")
print(pd.concat([df_a, df_b], axis=1))
df_a:
    X   Y
0  x0  y0
1  x1  y1

df_b:
    Y   Z
1  y1  z1
2  y2  z2

纵向合并 (axis=0):
     X   Y    Z
0   x0  y0  NaN
1   x1  y1  NaN
1  NaN  y1   z1
2  NaN  y2   z2

横向合并 (axis=1):
     X    Y    Y    Z
0   x0   y0  NaN  NaN
1   x1   y1   y1   z1
2  NaN  NaN   y2   z2

结果分析:

  • 纵向合并:列名为 X, Y, Z 的并集。df_a 没有 Z 列,df_b 没有 X 列,对应位置补 NaN。行索引也被保留,所以出现了两个索引 1。
  • 横向合并:行索引为 0, 1, 2 的并集。df_b 没有索引 0 的数据,df_a 没有索引 2 的数据,对应位置补 NaN。列名 Y 出现了重复。

本章小结

本节我们深入学习了 Pandas 中用于数据合并的基础函数 pd.concat。它就像数据的“胶水”,能够灵活地将多个 DataFrame 沿行或列的方向粘合在一起。

📋 行动清单

  • 掌握核心参数:记住 pd.concat([df1, df2, ...], axis=0或1) 的基本调用方式,理解 axis 参数对合并方向的决定性作用。
  • 理解外连接行为:在脑海中建立这样的认知:concat 默认采用外连接,会保留所有输入对象的索引(或列名),缺失数据自动填充为 NaN。这是处理列名或索引不一致情况时的关键。
  • 动手验证边界情况:在 Jupyter Notebook 或 Python 脚本中,亲自创建几个列名、索引部分相同、部分不同的 DataFrame,用 concat 进行纵向和横向合并,观察结果,加深理解。

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 本节课件:数据规整(1) -- 数据合并concat
    PDF · 225KB
    下载
  • 全套课件打包(第1-5章)
    ZIP · 12.8MB
    下载
  • 全套课件打包(第6-8章)
    ZIP · 15MB
    下载
  • 实战数据集:AppleStore 应用商城分析
    ZIP · 329KB
    下载
  • 实战数据集:女性服装电商分析
    ZIP · 2.8MB
    下载
  • Python 数据分析环境搭建指南
    PDF · 2MB
    下载
  • Scrapy 安装教程
    PDF · 12.7MB
    下载
  • 附加实战项目:AppleStore 应用商城数据分析
    ZIP · 0.3MB · ipynb + CSV 数据
    下载
  • 附加实战项目:银行电话营销数据分析
    ZIP · 0.4MB · ipynb + CSV 数据
    下载
  • 附加实战项目:女性服装电商评论数据分析
    ZIP · 2.7MB · ipynb + CSV 数据
    下载
  • 附加实战项目:美国化学学会杂志数据分析
    ZIP · 34.2MB · ipynb + SQLite 数据库
    下载