将Python中的CSV与不同的列合并

将Python中的CSV与不同的列合并,python,csv,merge,Python,Csv,Merge,我有数百个大的CSV文件,我想合并成一个。但是,并非所有CSV文件都包含所有列。因此,我需要根据列名而不是列位置合并文件 需要明确的是:在合并的CSV中,来自没有该单元格列的行的单元格的值应为空 我不能使用pandas模块,因为它会耗尽内存 是否有一个模块可以做到这一点,或者一些简单的代码?csv.DictReader和csv.DictWriter类应该可以很好地工作(请参阅)。大概是这样的: import csv inputs = ["in1.csv", "in2.csv"] # etc

我有数百个大的CSV文件,我想合并成一个。但是,并非所有CSV文件都包含所有列。因此,我需要根据列名而不是列位置合并文件

需要明确的是:在合并的CSV中,来自没有该单元格列的行的单元格的值应为空

我不能使用pandas模块,因为它会耗尽内存


是否有一个模块可以做到这一点,或者一些简单的代码?

csv.DictReader和
csv.DictWriter
类应该可以很好地工作(请参阅)。大概是这样的:

import csv
inputs = ["in1.csv", "in2.csv"]  # etc

# First determine the field names from the top line of each input file
# Comment 1 below
fieldnames = []
for filename in inputs:
  with open(filename, "r", newline="") as f_in:
    reader = csv.reader(f_in)
    headers = next(reader)
    for h in headers:
      if h not in fieldnames:
        fieldnames.append(h)

# Then copy the data
with open("out.csv", "w", newline="") as f_out:   # Comment 2 below
  writer = csv.DictWriter(f_out, fieldnames=fieldnames)
  for filename in inputs:
    with open(filename, "r", newline="") as f_in:
      reader = csv.DictReader(f_in)  # Uses the field names in this file
      for line in reader:
        # Comment 3 below
        writer.writerow(line)
以上意见:

  • 您需要提前指定所有可能的字段名,以便
    DictWriter
    ,因此您需要在所有CSV文件中循环两次:一次查找所有标题,一次读取数据。没有更好的解决方案,因为在
    DictWriter
    可以写入第一行之前,需要知道所有的头。这一部分使用集合而不是列表会更有效(列表上的
    in
    操作符相对较慢),但对于几百个标题来说,这不会有多大区别。集合也会失去列表的确定顺序——每次运行代码时,列的顺序都会不同
  • 上面的代码是针对Python3的,在没有
    newline=”“
    的CSV模块中会发生奇怪的事情。删除Python2中的此选项
  • 此时,
    是一个dict,字段名作为键,列数据作为值。您可以在
    DictReader
    DictWriter
    构造函数中指定如何处理空值或未知值

  • 此方法不应耗尽内存,因为它不会一次加载整个文件。

    对于使用2.7的人,这会在“out.csv”中的记录之间添加一个额外的换行符。要解决此问题,只需将文件模式从“w”更改为“wb”。

    您可以使用pandas模块轻松完成此操作。此代码段假定您的所有csv文件都在当前文件夹中

    import pandas as pd
    import os
    
    all_csv = [file_name for file_name in os.listdir(os.getcwd()) if '.csv' in file_name]
    
    li = []
    
    for filename in all_csv:
        df = pd.read_csv(filename, index_col=None, header=0, parse_dates=True, infer_datetime_format=True)
        li.append(df)
    
    frame = pd.concat(li, axis=0, ignore_index=True)
    frame.to_csv('melted_csv.csv', index=False)
    

    由@Aaron Lockey提出的解决方案(这是公认的答案)对我来说效果很好,只是文件没有标题。输出没有标题,只有行数据。每列都没有标题(键)。因此,我插入以下内容:

    writer.writeheader()
    
    这对我来说非常好!现在整个代码如下所示:

        import csv
        ``inputs = ["in1.csv", "in2.csv"]  # etc
    
        # First determine the field names from the top line of each input file
    
    `# Comment 1 below
    
        `fieldnames = []
    
    
      with open(filename, "r", newline="") as f_in:
        reader = csv.reader(f_in)
        headers = next(reader)
        for h in headers:
          if h not in fieldnames:
            fieldnames.append(h)
    
    # Then copy the data
    with open("out.csv", "w", newline="") as f_out:   # Comment 2 below
      writer = csv.DictWriter(f_out, fieldnames=fieldnames)
    writer.writeheader() #this is the addition.       
    for filename in inputs:
            with open(filename, "r", newline="") as f_in:
              reader = csv.DictReader(f_in)  # Uses the field names in this file
              for line in reader:
                # Comment 3 below
                writer.writerow(line)
    

    谢谢这是可行的,但是输入CSV都有头,它们在合并文件中与上面的代码一起重复。除了第一个文件外,我如何删除每个文件的这一行?实际上,我的列在合并文档中没有对齐。试图找出为什么my out.csv中有.223列,但我的字段名长度是368…?非常感谢,这很有效!我做了两个小的调整:1)用open(“out.csv”,“w”)改为用open(“out.csv”,“wb”),否则我会因为某种原因每隔一行空白;2)添加f_out.write(str(fieldnames)+“\n”以获取合并csv中的标题。我需要在代码中添加一些内容。我添加了“writer.writeheader()”。也作为下面的解决方案单独编写。什么添加了额外的换行符?接受的答案?如果是,这应该是对接受的答案的评论,而不是单独的答案。您的缩进已关闭,但这非常有用,谢谢!