如何用Python高效对比CSV文件并基于id计算count差值
如何高效对比两个CSV文件的id并计算count差值?
你遇到的嵌套循环效率问题确实很典型——当处理大文件时,O(n²)的时间复杂度会让运行速度急剧下降。咱们可以通过字典映射的方式把时间复杂度降到O(n+m)(n和m分别是两个CSV的行数),同时降低内存占用,让处理流程高效很多。
问题回顾
你有两个CSV文件,需要根据id匹配,计算CSV1 count - CSV2 count的差值,预期输出包含id和对应的差值。原来的嵌套循环方法虽然能实现功能,但数据量一大就会变得很慢。
高效实现思路
核心思路是先把其中一个CSV的id和count存储到字典中(字典的查找操作是O(1)时间复杂度),然后遍历另一个CSV,直接通过字典快速匹配对应的count并计算差值。
代码实现(使用DictReader,可读性高)
import csv # 先加载CSV2的数据到字典,key为id,value为转换后的整数count csv2_map = {} with open('csv2.csv', 'r') as csv2_file: reader = csv.DictReader(csv2_file) for row in reader: csv2_map[row['id']] = int(row['count']) # 处理CSV1并生成结果文件 with open('csv1.csv', 'r') as csv1_file, open('diff_result.csv', 'w', newline='') as result_file: csv1_reader = csv.DictReader(csv1_file) result_writer = csv.DictWriter(result_file, fieldnames=['id', 'Diff']) # 写入结果表头 result_writer.writeheader() for row in csv1_reader: current_id = row['id'] csv1_count = int(row['count']) # 从字典获取对应id的count,不存在则默认0(可根据需求调整) csv2_count = csv2_map.get(current_id, 0) diff_value = csv1_count - csv2_count result_writer.writerow({'id': current_id, 'Diff': diff_value})
更节省内存的版本(使用csv.reader,适合超大型文件)
如果你的CSV文件特别大(比如GB级别),用csv.reader代替DictReader可以进一步降低内存消耗,因为它不需要存储每行的字段名映射:
import csv csv2_map = {} with open('csv2.csv', 'r') as csv2_file: reader = csv.reader(csv2_file) next(reader) # 跳过表头行 for row in reader: csv2_map[row[0]] = int(row[1]) with open('csv1.csv', 'r') as csv1_file, open('diff_result.csv', 'w', newline='') as result_file: csv1_reader = csv.reader(csv1_file) result_writer = csv.writer(result_file) # 写入结果表头 result_writer.writerow(['id', 'Diff']) next(csv1_reader) # 跳过CSV1的表头 for row in csv1_reader: current_id = row[0] csv1_count = int(row[1]) csv2_count = csv2_map.get(current_id, 0) diff_value = csv1_count - csv2_count result_writer.writerow([current_id, diff_value])
为什么这个方法更高效?
- 时间复杂度:加载CSV2到字典是O(m),遍历CSV1是O(n),总时间复杂度为O(n+m),相比嵌套循环的O(n*m),在数据量较大时性能提升非常明显(比如1万行的两个文件,嵌套循环是1亿次操作,而这个方法只需要2万次)。
- 内存占用:不需要把两个完整的CSV文件都加载到内存中(除非你主动转成列表),而是边读边处理,适合大文件场景。
边界情况处理
代码中用csv2_map.get(current_id, 0)处理了id只在CSV1中存在的情况,默认CSV2的count为0。如果你的需求是跳过这类id,或者标记为N/A,可以修改这部分逻辑:
# 跳过不存在的id if current_id not in csv2_map: continue # 或者标记为缺失 diff_value = csv1_count - csv2_map.get(current_id, None)
内容的提问来源于stack exchange,提问作者scrpaingnoob
相关产品推荐
相关产品推荐

