Объединение нескольких CSV файлов без повторения заголовков (с использованием Python)

Я начинающий с Python. У меня есть несколько файлов CSV (более 10), и все они имеют одинаковое количество столбцов. Я хотел бы объединить их все в один файл CSV, где у меня не будет повторяться заголовки.

По сути, мне нужно иметь только первую строку со всеми заголовками, и с этого момента мне нужно объединить все строки из всех файлов CSV. Как мне это сделать?

Вот что я попробовал до сих пор.

import glob
import csv



with open('output.csv','wb') as fout:
    wout = csv.writer(fout,delimiter=',') 
    interesting_files = glob.glob("*.csv") 
    for filename in interesting_files: 
        print 'Processing',filename 
    # Open and process file
        h = True
        with open(filename,'rb') as fin:
                fin.next()#skip header
        for line in csv.reader(fin,delimiter=','):
                wout.writerow(line)

Ответ 1

Хотя я считаю, что лучшим ответом является метод @valentin, вы можете сделать это без использования модуля csv:

import glob

interesting_files = glob.glob("*.csv") 

header_saved = False
with open('output.csv','wb') as fout:
    for filename in interesting_files:
        with open(filename) as fin:
            header = next(fin)
            if not header_saved:
                fout.write(header)
                header_saved = True
            for line in fin:
                fout.write(line)

Ответ 2

Если вы находитесь в системе linux:

head -1 director/one_file.csv > output csv   ## writing the header to the final file
tail -n +2  director/*.csv >> output.csv  ## writing the content of all csv starting with second line into final file

Ответ 3

Если вы не против накладных расходов, вы можете использовать pandas, который поставляется с распространенными дистрибутивами python. Если вы планируете делать больше со списками таблиц, я рекомендую использовать pandas вместо того, чтобы писать собственные библиотеки.

import pandas as pd
import glob
interesting_files = glob.glob("*.csv")
df_list = []
for filename in sorted(interesting_files):
    df_list.append(pd.read_csv(filename))
full_df = pd.concat(df_list)

full_df.to_csv('output.csv')

Еще немного на pandas. Поскольку он предназначен для работы с таблицами как данные, он знает, что первая строка является заголовком. При чтении CSV он отделяет таблицу данных от заголовка, который хранится в метаданных dataframe, стандартного типа данных в pandas. Если вы конкатенируете несколько из этих dataframes, он объединяет только файлы данных, если их заголовки одинаковы. Если заголовки не совпадают, он не работает и дает вам ошибку. Вероятно, хорошо, если ваш каталог загрязнен CSV файлами из другого источника.

Другое дело: я добавил sorted() вокруг interesting_files. Я предполагаю, что ваши файлы названы по порядку, и этот порядок должен быть сохранен. Я не уверен в glob, но функции os не обязательно возвращают файлы, отсортированные по их имени.

Ответ 4

Ваш отступ неправильный, вам нужно поместить цикл внутри блока. Вы также можете передать объект файла в writer.writerows.

import csv
with open('output.csv','wb') as fout:
    wout = csv.writer(fout)
    interesting_files = glob.glob("*.csv")
    for filename in interesting_files:
        print 'Processing',filename
        with open(filename,'rb') as fin:
                next(fin) # skip header
                wout.writerows(fin)

Ответ 5

Ваша попытка почти работает, но проблемы:

  • Вы открываете файл для чтения, но закрываете его перед записью строк.
  • ты никогда не пишешь название Вы должны написать это один раз
  • Также вы должны исключить output.csv из "glob", иначе вывод также находится во вводе!

Здесь исправленный код, передающий объект csv непосредственно в метод csv.writerows для более короткого и быстрого кода. Также запись заголовка из первого файла в выходной файл.

import glob
import csv

output_file = 'output.csv'
header_written = False

with open(output_file,'w',newline="") as fout:  # just "wb" in python 2
    wout = csv.writer(fout,delimiter=',')
    # filter out output
    interesting_files = [x for x in glob.glob("*.csv") if x != output_file]
    for filename in interesting_files:
        print('Processing {}'.format(filename))
        with open(filename) as fin:
            cr = csv.reader(fin,delmiter=",")
            header = cr.next() #skip header
            if not header_written:
                wout.writerow(header)
                header_written = True
            wout.writerows(cr)

Обратите внимание, что решения, использующие необработанную построчную обработку, упускают важный момент: если заголовок является многострочным, он с треском проваливается, несколько раз портя строку заголовка/повторяя ее часть, эффективно повреждая файл.

Модуль CSV (или панды тоже) изящно обрабатывает эти случаи.