如何用Python的Pandas对比两个按ID排序的CSV文件
刚好我之前处理过类似的CSV对比需求,给你两个实用的解决方案,根据你的文件大小来选就好~
方案一:高效双指针法(适合大型CSV文件)
因为你的两个CSV都是按ID排序的,用双指针遍历可以避免把整个文件加载到内存,内存占用极低,处理大文件特别高效。
直接上代码:
import csv # 同时打开所有需要的文件 with open('File1.csv', 'r') as f1, open('File2.csv', 'r') as f2, \ open('diff.csv', 'w', newline='') as diff_file, \ open('onlyf1.csv', 'w', newline='') as onlyf1_file, \ open('onlyf2.csv', 'w', newline='') as onlyf2_file: # 初始化CSV读写器 reader1 = csv.reader(f1) reader2 = csv.reader(f2) diff_writer = csv.writer(diff_file) onlyf1_writer = csv.writer(onlyf1_file) onlyf2_writer = csv.writer(onlyf2_file) # 跳过并处理表头 next(reader1) next(reader2) # 写入diff.csv的自定义表头 diff_writer.writerow(['ID', 'x1', 'x2', 'diffx', 'y1', 'y2', 'diffy', 'z1', 'z2', 'diffz']) # 写入两个仅存文件的表头 onlyf1_writer.writerow(['ID']) onlyf2_writer.writerow(['ID']) # 初始化双指针(当前行) row1 = next(reader1, None) row2 = next(reader2, None) # 开始遍历两个文件 while row1 is not None and row2 is not None: id1 = int(row1[0]) id2 = int(row2[0]) if id1 == id2: # ID在两个文件都存在,计算差值写入diff.csv x1, y1, z1 = map(int, row1[1:]) x2, y2, z2 = map(int, row2[1:]) diffx = x1 - x2 diffy = y1 - y2 diffz = z1 - z2 diff_writer.writerow([id1, x1, x2, diffx, y1, y2, diffy, z1, z2, diffz]) # 同时移动两个指针 row1 = next(reader1, None) row2 = next(reader2, None) elif id1 < id2: # ID只在File1里,写入onlyf1.csv onlyf1_writer.writerow([id1]) row1 = next(reader1, None) else: # ID只在File2里,写入onlyf2.csv onlyf2_writer.writerow([id2]) row2 = next(reader2, None) # 处理其中一个文件遍历完后剩下的行 while row1 is not None: onlyf1_writer.writerow([int(row1[0])]) row1 = next(reader1, None) while row2 is not None: onlyf2_writer.writerow([int(row2[0])]) row2 = next(reader2, None)
代码解释:
- 用
csv模块处理文件,自动处理CSV的格式细节(比如逗号分隔、带引号的字段),比手动解析靠谱多了。 - 双指针逻辑:因为文件是按ID排序的,我们只需要比较当前两个行的ID,根据大小关系决定要处理哪一行,不用回头遍历,效率拉满。
- 最后处理剩余行:当其中一个文件先遍历完,把另一个文件剩下的ID写入对应的“仅存”文件。
方案二:直观字典法(适合小型CSV文件)
如果你的文件不大,用字典把其中一个文件的内容存起来,代码会更直观,容易理解和修改。
代码示例:
import csv # 先把File2的内容加载到字典里,键是ID,值是X/Y/Z的列表 file2_data = {} with open('File2.csv', 'r') as f2: reader = csv.reader(f2) next(reader) # 跳过表头 for row in reader: file2_data[int(row[0])] = row[1:] # 遍历File1,处理共同ID和仅在File1的ID with open('File1.csv', 'r') as f1, \ open('diff.csv', 'w', newline='') as diff_file, \ open('onlyf1.csv', 'w', newline='') as onlyf1_file: reader1 = csv.reader(f1) diff_writer = csv.writer(diff_file) onlyf1_writer = csv.writer(onlyf1_file) next(reader1) # 跳过表头 diff_writer.writerow(['ID', 'x1', 'x2', 'diffx', 'y1', 'y2', 'diffy', 'z1', 'z2', 'diffz']) onlyf1_writer.writerow(['ID']) for row in reader1: id1 = int(row[0]) x1, y1, z1 = map(int, row[1:]) if id1 in file2_data: # 匹配到共同ID,计算差值 x2, y2, z2 = map(int, file2_data[id1]) diffx = x1 - x2 diffy = y1 - y2 diffz = z1 - z2 diff_writer.writerow([id1, x1, x2, diffx, y1, y2, diffy, z1, z2, diffz]) del file2_data[id1] # 删除已匹配的ID,剩下的就是仅在File2的 else: # ID只在File1里 onlyf1_writer.writerow([id1]) # 处理仅在File2的ID with open('onlyf2.csv', 'w', newline='') as onlyf2_file: writer = csv.writer(onlyf2_file) writer.writerow(['ID']) # 因为原文件是排序的,这里对剩下的ID排序后写入,保持顺序一致 for id2 in sorted(file2_data.keys()): writer.writerow([id2])
代码解释:
- 先把File2的内容加载到字典,用ID作为键,这样查找起来是O(1)的速度。
- 遍历File1的时候,直接查字典就能知道ID是否存在于File2,存在就计算差值,不存在就写入onlyf1.csv。
- 最后字典里剩下的ID就是仅在File2的,排序后写入onlyf2.csv(保持和原文件一致的顺序)。
验证结果
用你给出的示例文件测试:
diff.csv会生成:
ID x1 x2 diffx y1 y2 diffy z1 z2 diffz 1 10 5 5 20 10 10 30 15 15 5 40 55 -15 50 12 38 60 22 38
(注:你的示例里diff.csv的ID1行x2写的是20,应该是笔误,代码会按照实际文件内容计算差值,如果需要调整差值方向(比如x2-x1),只需要修改diffx = x2 - x1这类代码即可)
onlyf1.csv:
ID 3
onlyf2.csv:
ID 2
完全符合你的需求~
内容的提问来源于stack exchange,提问作者Devesh Agrawal
相关产品推荐
相关产品推荐

