处理多个CSV数据文件时,最常见的需求之一就是将两个文件合并成一个完整的数据集。Python中的pandas提供了concat()和merge()等方法,可以根据实际数据结构选择合适的合并方式。对于简单的上下拼接,concat()更加直接;如果两个CSV文件存在共同字段,需要按照某个列进行关联,则更适合使用merge()。
一、准备两个CSV文件
假设有两个文件:
users_1.csv
csvid,name,age 1,张三,25 2,李四,30 3,王五,28
users_2.csv
csvid,name,age 4,赵六,26 5,钱七,32 6,孙八,29
两个文件的字段结构一致,希望将它们纵向合并,可以直接使用pandas的concat()方法。
二、使用concat合并两个CSV文件
最简单的实现方式如下:
Python运行import pandas as pd df1 = pd.read_csv("users_1.csv") df2 = pd.read_csv("users_2.csv") result = pd.concat([df1, df2], ignore_index=True) result.to_csv("users_all.csv", index=False, encoding="utf-8-sig")
执行后,users_all.csv中的数据为:
csvid,name,age 1,张三,25 2,李四,30 3,王五,28 4,赵六,26 5,钱七,32 6,孙八,29
这里的ignore_index=True非常实用。它会重新生成连续的DataFrame索引,避免两个原始文件的索引重复。
index=False则用于保存CSV时不写入pandas默认生成的行索引,否则最终文件可能会多出一列没有实际业务意义的数据。
三、两个CSV字段不完全一致怎么办
实际项目中,两个CSV文件的列结构不一定完全相同。例如:
users_1.csv:
csvid,name,age 1,张三,25 2,李四,30
users_2.csv:
csvid,name,city 3,王五,北京 4,赵六,上海
仍然可以使用concat():
Python运行import pandas as pd df1 = pd.read_csv("users_1.csv") df2 = pd.read_csv("users_2.csv") result = pd.concat([df1, df2], ignore_index=True) print(result)
得到的结果类似:
id name age city 0 1 张三 25.0 NaN 1 2 李四 30.0 NaN 2 3 王五 NaN 北京 3 4 赵六 NaN 上海
pandas会自动按照列名进行对齐。某个文件不存在的字段会填充为NaN。
这种机制比直接拼接文本文件更加安全,因为它不会简单地按照字符位置连接,而是根据DataFrame的列结构完成数据对齐。
四、按照共同字段合并两个CSV文件
如果两个CSV文件不是简单的上下拼接,而是存在关联关系,就应该考虑merge()。
例如,第一个文件保存用户信息:
csvid,name 1,张三 2,李四 3,王五
第二个文件保存订单信息:
csvuser_id,product,price 1,笔记本电脑,5999 2,手机,3999 3,显示器,1299
两个文件通过用户ID建立关系,可以这样处理:
Python运行import pandas as pd users = pd.read_csv("users.csv") orders = pd.read_csv("orders.csv") result = pd.merge( users, orders, left_on="id", right_on="user_id", how="inner" ) print(result)
输出结果:
id name user_id product price 0 1 张三 1 笔记本电脑 5999 1 2 李四 2 手机 3999 2 3 王五 3 显示器 1299
merge()的核心是指定两个数据集之间的关联字段。
如果两个DataFrame使用相同的列名,例如都通过id关联,则代码可以简化:
Python运行result = pd.merge(df1, df2, on="id", how="inner")
五、merge中的how参数如何选择
how决定两个CSV文件的连接方式,常用的有四种。
1. inner:内连接
Python运行result = pd.merge(df1, df2, on="id", how="inner")
只保留两个文件中都存在的ID。
适合需要筛选出“双方都有对应数据”的场景。
2. left:左连接
Python运行result = pd.merge(df1, df2, on="id", how="left")
以第一个DataFrame为基础,第一个文件中的数据全部保留。如果第二个文件没有匹配记录,对应字段会显示为NaN。
3. right:右连接
Python运行result = pd.merge(df1, df2, on="id", how="right")
与left相反,以第二个DataFrame的数据为基础。
4. outer:全连接
Python运行result = pd.merge(df1, df2, on="id", how="outer")
两个文件中的数据都会保留,没有匹配的数据使用NaN填充。
因此,如果只是把两个结构相同的CSV文件上下合并,应优先考虑concat();如果是根据ID、订单号、商品编号等字段进行数据关联,则通常使用merge()。
六、合并后处理重复数据
多个CSV文件可能包含重复记录。如果业务上不允许重复数据,可以使用drop_duplicates():
Python运行result = pd.concat([df1, df2], ignore_index=True) result = result.drop_duplicates() result.to_csv("users_all.csv", index=False, encoding="utf-8-sig")
如果只希望按照某个字段判断重复,可以指定subset:
Python运行result = result.drop_duplicates(subset=["id"])
如果重复数据中需要保留最后一条记录,可以使用:
Python运行result = result.drop_duplicates( subset=["id"], keep="last" )
其中keep="first"保留第一条,keep="last"保留最后一条,keep=False则会删除所有重复记录。
七、合并前处理中文CSV编码
中文CSV文件经常会遇到乱码问题。Windows环境下生成的CSV文件可能使用GBK编码,可以在读取时明确指定:
Python运行df1 = pd.read_csv("users_1.csv", encoding="gbk") df2 = pd.read_csv("users_2.csv", encoding="gbk")
如果文件采用UTF-8编码:
Python运行df1 = pd.read_csv("users_1.csv", encoding="utf-8")
保存中文CSV时,可以使用:
Python运行result.to_csv( "users_all.csv", index=False, encoding="utf-8-sig" )
utf-8-sig对Windows环境下的Excel兼容性通常比较好,可以减少直接用Excel打开CSV时出现中文乱码的情况。
八、一次合并多个CSV文件
如果实际需求从两个CSV扩展到了几十甚至上百个文件,没有必要逐个编写pd.concat()。
例如当前目录下有:
data/ ├── data_01.csv ├── data_02.csv ├── data_03.csv └── data_04.csv
可以使用glob批量获取CSV文件:
Python运行import glob import pandas as pd files = glob.glob("data/*.csv") dataframes = [pd.read_csv(file) for file in files] result = pd.concat(dataframes, ignore_index=True) result.to_csv( "all_data.csv", index=False, encoding="utf-8-sig" )
这种方式适合日志、销售数据、业务报表等按照日期或批次拆分保存的CSV数据。
如果合并后的文件也放在相同目录中,则需要注意避免下一次运行时把已经生成的结果文件再次读取进去。可以单独指定输入目录,或者排除输出文件。
九、合并前检查CSV结构
为了避免不同文件的字段存在明显差异,可以在合并之前检查列名:
Python运行import pandas as pd df1 = pd.read_csv("users_1.csv") df2 = pd.read_csv("users_2.csv") print(df1.columns.tolist()) print(df2.columns.tolist())
也可以检查数据规模:
Python运行print(df1.shape) print(df2.shape)
如果两个文件结构应该完全一致,还可以进行判断:
Python运行if list(df1.columns) != list(df2.columns): raise ValueError("两个CSV文件的列结构不一致") result = pd.concat([df1, df2], ignore_index=True)
这种检查方式适合自动化数据处理脚本,可以在数据格式发生变化时及时停止,而不是生成一个看似正常、实际存在问题的结果文件。
十、处理不同列顺序的CSV文件
假设两个文件拥有相同字段,但列顺序不同:
文件1:id,name,age 文件2:age,id,name
使用concat()时,pandas会根据列名进行对齐:
Python运行result = pd.concat([df1, df2], ignore_index=True)
因此通常不需要手动调整列顺序。
如果希望最终文件严格按照指定顺序输出,可以重新排列:
Python运行result = result[["id", "name", "age"]]
这样可以保证最终CSV的字段顺序符合业务要求。
十一、处理两个CSV中的同名字段
使用merge()时,如果两个DataFrame除了关联字段外还存在相同名称的列,pandas通常会自动添加后缀。
例如:
Python运行result = pd.merge( df1, df2, on="id", how="inner", suffixes=("_left", "_right") )
如果两个文件都有name字段,最终可能出现:
name_left name_right
通过suffixes可以让这些字段名称更加容易理解。
十二、合并后验证数据是否正确
完成CSV合并后,不建议直接认为任务已经结束。可以简单检查行数、字段和缺失值:
Python运行print("数据行数:", len(result)) print("字段:", result.columns.tolist()) print(result.head())
检查缺失值:
Python运行print(result.isnull().sum())
如果使用concat()进行两个文件的纵向合并,并且两个文件没有重复记录,理论上的总行数通常应该接近:
Python运行expected = len(df1) + len(df2) print("预期行数:", expected) print("实际行数:", len(result))
如果中间使用了drop_duplicates(),实际行数小于预期则属于正常情况,但仍然应该进一步确认删除的重复记录是否符合业务规则。
十三、一个完整的CSV合并示例
对于字段一致、需要纵向合并的两个CSV,可以采用下面这种较完整的写法:
Python运行import pandas as pd file1 = "users_1.csv" file2 = "users_2.csv" output_file = "users_all.csv" df1 = pd.read_csv(file1, encoding="utf-8") df2 = pd.read_csv(file2, encoding="utf-8") # 检查字段 if set(df1.columns) != set(df2.columns): raise ValueError("两个CSV文件的字段不一致") # 按照第一个文件的字段顺序统一列 df2 = df2[df1.columns] # 合并数据 result = pd.concat( [df1, df2], ignore_index=True ) # 删除完全重复的记录 result = result.drop_duplicates() # 保存结果 result.to_csv( output_file, index=False, encoding="utf-8-sig" ) print(f"合并完成,共保存 {len(result)} 条数据")
这个版本增加了字段检查、列顺序统一、重复数据处理以及结果统计,更适合实际项目中的数据处理脚本。
十四、concat和merge应该怎么选
两种方法虽然都可以实现“合并”,但解决的问题并不相同。
| 方法 | 主要用途 | 常见场景 |
|---|---|---|
pd.concat() | 沿行或列方向拼接 | 多个结构相似的CSV合并 |
pd.merge() | 根据字段建立关联 | 用户表与订单表关联 |
drop_duplicates() | 删除重复记录 | 合并后数据去重 |
read_csv() | 读取CSV | 将CSV转换为DataFrame |
to_csv() | 输出CSV | 保存合并后的数据 |
可以简单理解为:数据是一批一批追加的,用concat();数据需要通过某个字段“对应起来”,用merge()。
对于最常见的“把两个结构相同的CSV文件合成一个CSV文件”需求,核心代码其实只有几行:
Python运行import pandas as pd df1 = pd.read_csv("file1.csv") df2 = pd.read_csv("file2.csv") result = pd.concat([df1, df2], ignore_index=True) result.to_csv("result.csv", index=False, encoding="utf-8-sig")
掌握read_csv()、concat()、merge()和to_csv()之后,就能够覆盖大多数pandas CSV合并场景。实际使用时,应先明确两个文件是“纵向追加”还是“按照字段关联”,再选择对应的方法,这样既能避免数据错位,也便于后续的数据清洗和分析。