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) # False2. 使用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)六、实际应用场景
场景一:批量读取多个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进行拼接,然后通过多级索引提取特定子集的数据,并展平为单层索引。
本文涉及AI创作
内容由AI创作,请仔细甄别