使用不同的列在Python中合并CSV

时间:2014-10-28 00:40:55

标签: python csv merge

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

为了清楚起见:在合并的CSV中,对于来自没有该单元格列的行的单元格,值应为空。

我无法使用pandas模块,因为它会让我内存耗尽。

是否有可以执行该操作的模块或一些简单的代码?

4 个答案:

答案 0 :(得分:13)

csv.DictReadercsv.DictWriter类应运行良好(请参阅Python docs)。像这样:

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)

上述评论:

  1. 您需要提前指定所有可能的字段名称DictWriter,因此您需要遍历所有CSV文件两次:一次查找所有标题,一次查阅数据。没有更好的解决方案,因为在DictWriter可以写第一行之前需要知道所有标头。这部分使用集合代替列表会更有效(列表上的in运算符相对较慢),但它对于几百个标题不会产生太大影响。集合也会丢失列表的确定性排序 - 每次运行代码时,列都会以不同的顺序出现。
  2. 以上代码适用于Python 3,在没有newline=""的CSV模块中会发生奇怪的事情。为Python 2删除它。
  3. 此时,line是一个字典,字段名称为键,列数据为值。您可以在DictReaderDictWriter构造函数中指定如何处理空白或未知值。
  4. 此方法不应该耗尽内存,因为它永远不会立即加载整个文件。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

@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)

答案 3 :(得分:0)

您可以使用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)