pin_drop当前位置:知识文库 ❯ 图文

pandas concat拼接教程 - 数据表轴向拼接合并详解

pd.concat()是pandas中用于沿轴向拼接多个DataFrame或Series的函数。与merge()基于键的关联不同,concat是基于位置和数据结构的拼接,非常适合将多个相同结构的数据表上下或左右连接。

一、concat基本用法

代码示例

import pandas as pd
import numpy as np

# 创建示例数据
df1 = pd.DataFrame({
    'name': ['Alice', 'Bob'],
    'age': [25, 30],
    'city': ['北京', '上海']
})

df2 = pd.DataFrame({
    'name': ['Charlie', 'David'],
    'age': [35, 28],
    'city': ['广州', '深圳']
})

# 基本concat(默认沿axis=0纵向拼接)
result = pd.concat([df1, df2])
print("纵向拼接结果:")
print(result)

# 重置索引
result = pd.concat([df1, df2], ignore_index=True)
print("重置索引:")
print(result)

关键参数说明:

  • objs:要拼接的DataFrame或Series列表

  • axis:拼接轴向,0为纵向(行),1为横向(列)

  • join:连接方式,'outer'(并集)或'inner'(交集)

  • ignore_index:是否忽略原索引,生成新连续索引

  • keys:为每个输入数据添加层级索引标签

  • verify_integrity:检查是否有重复索引

二、轴向拼接(axis参数)

1. 纵向拼接(axis=0,默认)

代码示例

# 纵向拼接:上下堆叠
df3 = pd.DataFrame({
    'name': ['Eve', 'Frank'],
    'age': [22, 33],
    'city': ['杭州', '成都']
})

result = pd.concat([df1, df2, df3], ignore_index=True)
print(f"拼接了3个DataFrame,共{len(result)}行")
print(result)

2. 横向拼接(axis=1)

代码示例

# 横向拼接:左右连接
df_a = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie']
})

df_b = pd.DataFrame({
    'age': [25, 30, 35],
    'city': ['北京', '上海', '广州']
})

# 按列拼接
result = pd.concat([df_a, df_b], axis=1)
print("横向拼接结果:")
print(result)

# 注意:横向拼接按索引对齐
df_x = pd.DataFrame({'val': [100, 200]}, index=[0, 2])
df_y = pd.DataFrame({'val': [300, 400]}, index=[1, 2])

result = pd.concat([df_x, df_y], axis=1)
print("按索引对齐的横向拼接:")
print(result)

三、索引处理与keys参数

1. 保留原始索引

代码示例

# 保留原始索引(默认行为)
result = pd.concat([df1, df2])
print("保留原始索引:")
print(result.index.tolist())  # [0, 1, 0, 1]

# 检查索引重复
print(result.index.is_unique)  # False

2. 使用keys创建多级索引

代码示例

# 使用keys参数标记数据来源
result = pd.concat([df1, df2], keys=['Q1', 'Q2'])
print("带keys的多级索引:")
print(result)

# 访问特定key的数据
print("Q1数据:")
print(result.loc['Q1'])

# 使用names参数命名层级
result = pd.concat([df1, df2], keys=['Q1', 'Q2'], 
                   names=['quarter', 'row_id'])
print(result)

3. 验证索引完整性

代码示例

# verify_integrity=True 会检查重复索引
try:
    result = pd.concat([df1, df2], verify_integrity=True)
except ValueError as e:
    print(f"索引重复错误:{e}")

# 配合ignore_index使用
result = pd.concat([df1, df2], ignore_index=True, 
                   verify_integrity=True)
print("无重复索引,验证通过")

四、join参数与列对齐

代码示例

# 创建列不完全相同的DataFrame
df1 = pd.DataFrame({
    'A': ['A0', 'A1'],
    'B': ['B0', 'B1']
})

df2 = pd.DataFrame({
    'B': ['B2', 'B3'],
    'C': ['C2', 'C3']  # df1中没有C列
})

# outer连接(默认):保留所有列,缺失填NaN
outer = pd.concat([df1, df2], join='outer')
print("outer连接(保留所有列):")
print(outer)

# inner连接:只保留共同列
inner = pd.concat([df1, df2], join='inner')
print("inner连接(只保留共同列):")
print(inner)

提示join='outer'会保留所有列(并集),缺失值用NaN填充;join='inner'只保留所有DataFrame都有的列(交集)。根据业务需求选择合适的join方式。

五、concat与append

append()方法在pandas 2.0版本中已被废弃,推荐使用concat()替代。

代码示例

# 旧写法(已废弃)
# result = df1.append(df2, ignore_index=True)

# 推荐写法
result = pd.concat([df1, df2], ignore_index=True)

# 追加单行数据
new_row = pd.DataFrame([{'name': 'Grace', 'age': 26, 'city': '南京'}])
result = pd.concat([df1, new_row], ignore_index=True)

# 性能对比:批量concat比多次append高效得多
# 错误做法(循环中反复concat/append)
# for row in rows:
#     df = pd.concat([df, row])  # 非常慢!

# 正确做法(一次性concat)
df = pd.concat([pd.DataFrame([r]) for r in rows], ignore_index=True)
对比项 concat merge join
拼接方式 按轴向拼接 按列键关联 按索引关联
输入数量 多个(列表) 两个 两个
SQL等价 UNION ALL JOIN JOIN(基于索引)
适用场景 相同结构数据堆叠 不同表按关联键合并 基于索引快速合并
对齐依据 索引(axis=1)或列名 连接键列 索引

六、实际应用场景

场景一:批量读取多个CSV文件

代码示例

import glob
import os

# 模拟多个CSV文件路径(实际使用时替换为真实路径)
csv_files = ['data_q1.csv', 'data_q2.csv', 'data_q3.csv']

# 方法1:列表推导 + concat(推荐)
dfs = [pd.read_csv(f) for f in csv_files]
combined = pd.concat(dfs, ignore_index=True)

# 方法2:带数据来源标记
dfs_with_keys = []
for f in csv_files:
    df = pd.read_csv(f)
    df['source_file'] = os.path.basename(f)
    dfs_with_keys.append(df)

combined = pd.concat(dfs_with_keys, ignore_index=True)
print(combined)

场景二:DataFrame拆分与重组

代码示例

# 将大数据集按条件拆分后再处理
df = pd.DataFrame({
    'name': ['A', 'B', 'C', 'D', 'E', 'F'],
    'score': [85, 42, 90, 55, 78, 38],
    'group': ['G1', 'G1', 'G2', 'G2', 'G3', 'G3']
})

# 按条件拆分
passed = df[df['score'] >= 60]
failed = df[df['score'] < 60]

# 对拆分后的数据分别处理
passed = passed.assign(status='及格')
failed = failed.assign(status='不及格', make_up=True)

# 重新拼接
result = pd.concat([passed, failed], ignore_index=True)
print(result)

场景三:时间序列数据拼接

代码示例

# 按月拼接时间序列数据
months = ['2024-01', '2024-02', '2024-03']
dfs = []

for month in months:
    # 模拟按月读取数据
    df = pd.DataFrame({
        'date': pd.date_range(f'{month}-01', periods=5),
        'value': np.random.randint(100, 200, 5)
    })
    df['month'] = month
    dfs.append(df)

# 拼接并按日期排序
combined = pd.concat(dfs, ignore_index=True)
combined = combined.sort_values('date').reset_index(drop=True)
print(combined)

小贴士

性能优化:当需要拼接大量DataFrame时,先将它们放入列表,最后一次性调用pd.concat(),避免在循环中反复拼接。对于超大数据集,考虑使用copy=False参数减少内存拷贝。更多详情参考pandas concat官方文档

常见问题

concat 和 merge 应该如何选择?

concat适合将结构相同(或相似)的多个DataFrame沿轴向拼接,类似SQL的UNION;merge适合将两个DataFrame按某个键进行关联,类似SQL的JOIN。如果你有两份结构相同的月度数据要上下拼接,用concat;如果你有员工表和薪资表要按工号关联,用merge。

concat后索引重复了怎么办?

如果只是需要连续索引,使用ignore_index=True即可。如果需要保留数据来源信息,可以使用keys参数创建多级索引。如果后续操作依赖唯一索引,可以concat后调用reset_index(drop=True)。

append 方法为什么被废弃了?

append本质上是concat的封装,但功能有限且容易引起误解。pandas官方认为维持两个功能重叠的API会增加维护成本,且append的性能问题经常让用户误以为它比concat高效。建议使用pd.concat([df1, df2])替代df1.append(df2)。

如何高效拼接大量小DataFrame?

最推荐的做法:1) 将所有DataFrame收集到列表中;2) 一次性调用pd.concat(list, ignore_index=True)。不要在循环中反复concat,每次concat都会创建新对象,时间复杂度为O(n²)。如果数据量极大,考虑使用dask或polars等工具。

练习1

创建3个结构相同的DataFrame(模拟3个月的销售数据),使用concat将它们纵向拼接,并为每行添加月份标记。

练习2

有两个DataFrame列不完全相同,分别使用join='outer'和join='inner'进行拼接,比较结果差异。

练习3

使用keys参数对多个DataFrame进行拼接,然后通过多级索引提取特定子集的数据,并展平为单层索引。

标签: pandas concat 数据拼接 DataFrame Python UNION

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: pandas merge合并教程 - 数据表JOIN连接操作详解 下一篇: Pandas透视表pivot_table完整教程 - 数据分析必备技能

poll相关推荐