як об'єднати 200 файлів CSV в Python


84

Хлопці, у мене тут є 200 окремих файлів csv з іменами від SH (1) до SH (200). Я хочу об'єднати їх в один файл CSV. Як я можу це зробити?


3
Яким чином ви б їх об'єднали? (Concatenate lines, ...)
tur1ng

6
Як ви хочете, щоб їх об’єднали? Кожен рядок у файлі CSV є рядком. Тож один простий варіант - просто об’єднати всі файли разом.
Джон-Ерік,

Кожен файл має два стовпці. Я хочу об'єднати їх в один файл із двома стовпцями послідовно.
Чак

1
@Chuck: Як щодо того, щоб взяти всі відповіді у своїх коментарях (на запитання та відповіді) та оновити своє запитання?
tumultous_rooster

2
Це питання має бути названий «Як CONCAT ...» замість «як злити ...»
colidyre

Відповіді:


96

Як сказав ghostdog74, але цього разу із заголовками:

fout=open("out.csv","a")
# first file:
for line in open("sh1.csv"):
    fout.write(line)
# now the rest:    
for num in range(2,201):
    f = open("sh"+str(num)+".csv")
    f.next() # skip the header
    for line in f:
         fout.write(line)
    f.close() # not really needed
fout.close()

11
Ви можете використовувати f.__next__()замість цього, якщо f.next()в python3.x.
tsveti_iko

5
Тільки примітка: можна використовувати with openсинтаксис і уникати вручну .close()введення файлів.
FatihAkici

2
яка різниця між f.next()та f.__next__()? коли я використовую перше, я отримав'_io.TextIOWrapper' object has no attribute 'next'
Джейсон Гол

до того, як fout.write(line)я б це зробив:if line[-1] != '\n': line += '\n'
shisui

65

Чому ви не можете просто sed 1d sh*.csv > merged.csv?

Іноді навіть не потрібно використовувати python!


21
У Windows, C: \> скопіювати * .csv merged.csv
авіаудар

6
Скопіюйте інформацію заголовка з одного файлу: sed -n 1p some_file.csv> merged_file.csv Скопіюйте всі, крім останнього рядка, з усіх інших файлів: sed 1d * .csv >> merged_file.csv
behas

3
@blinsay Він також додає заголовок кожного файлу CSV до об'єднаного файлу.
Міна

5
Як використовувати цю команду, не копіюючи інформацію заголовка для кожного наступного файлу після першого? Здається, інформація про заголовки з’являється неодноразово.
Джо

2
Це чудово, якщо вам не потрібно видаляти заголовок!
Blairg23,

51

Використовуйте прийняту відповідь StackOverflow, щоб створити список файлів csv, які потрібно додати, а потім запустіть цей код:

import pandas as pd
combined_csv = pd.concat( [ pd.read_csv(f) for f in filenames ] )

І якщо ви хочете експортувати його в один файл csv, використовуйте це:

combined_csv.to_csv( "combined_csv.csv", index=False )

@ wisty, @ Andy, припустимо, усі файли мають заголовки для кожного рядка - деякі рядки з різними заголовками. У кожному файлі немає заголовків для 2 стовпців. Як можна об’єднати, так що для кожного файлу додається лише стовпець.
Gathide

Куди експортується файл?

@ dirtysocks45, я змінив відповідь, щоб зробити це більш чітким.
Скоттттл

додати сортування: compiled_csv = pd.concat ([pd.read_csv (f) для f в іменах файлів], sort = False)
sailfish009

16
fout=open("out.csv","a")
for num in range(1,201):
    for line in open("sh"+str(num)+".csv"):
         fout.write(line)    
fout.close()

13

Я просто перегляну ще один приклад коду в кошику

from glob import glob

with open('singleDataFile.csv', 'a') as singleFile:
    for csvFile in glob('*.csv'):
        for line in open(csvFile, 'r'):
            singleFile.write(line)

2
@Andy Я не бачу різниці між stackoverflow, який нагадує мені проголосувати відповідь, і я нагадую людям поділитися своєю вдячністю (проголосувавши), якщо вони знайшли мою відповідь корисною. Я знаю, що це не Facebook, і я не мисливець за
подібними людьми

1
Це вже обговорювалося раніше , і кожного разу це вважалося неприйнятним.
Енді

10

Це залежить від того, що ви маєте на увазі під «злиттям» - чи мають вони однакові стовпці? У них є заголовки? Наприклад, якщо всі вони мають однакові стовпці, а заголовків немає, достатньо простої конкатенації (відкрийте цільовий файл для запису, прокрутіть джерела, що відкриваються для читання, використовуйте shutil.copyfileobj з джерела відкритого для читання в відкрите для написання місце, закрийте джерело, продовжуйте цикл - використовуйте withзаяву, щоб зробити закриття від вашого імені). Якщо вони мають однакові стовпці, але також заголовки, вам знадобиться readlineфайл кожного вихідного файлу, крім першого, після того, як ви відкриєте його для читання, перш ніж скопіювати в пункт призначення, щоб пропустити рядок заголовків.

Якщо у файлах CSV не всі однакові стовпці, то вам потрібно визначити, в якому сенсі ви їх "зливаєте" (як SQL JOIN? Або "горизонтально", якщо всі вони мають однакову кількість рядків? Тощо, тощо) ) - нам важко здогадатися, що ви маєте на увазі в такому випадку.


Кожен файл має два стовпці із заголовками. Я хочу об'єднати їх в один файл із двома стовпцями послідовно.
Чак

4

Невелика зміна наведеного вище коду, оскільки він насправді працює некоректно.

Це повинно бути наступним чином ...

from glob import glob

with open('main.csv', 'a') as singleFile:
    for csv in glob('*.csv'):
        if csv == 'main.csv':
            pass
        else:
            for line in open(csv, 'r'):
                singleFile.write(line)

3

Якщо об'єднаний CSV буде використовуватися в Python, просто використовуйте, globщоб отримати список файлів, до яких потрібно передати за fileinput.input()допомогою filesаргументу, а потім використовуйте csvмодуль, щоб прочитати все за один раз.


3

Досить просто об'єднати всі файли в каталог і об'єднати їх

import glob
import csv


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

3

Якщо ви працюєте на Linux / mac, ви можете це зробити.

from subprocess import call
script="cat *.csv>merge.csv"
call(script,shell=True)


1

Ви можете імпортувати CSV, після чого прокрутити всі файли CSV, читаючи їх до списку. Потім запишіть список назад на диск.

import csv

rows = []

for f in (file1, file2, ...):
    reader = csv.reader(open("f", "rb"))

    for row in reader:
        rows.append(row)

writer = csv.writer(open("some.csv", "wb"))
writer.writerows("\n".join(rows))

Вищезазначене не надто надійне, оскільки воно не обробляє помилок і не закриває будь-які відкриті файли. Це має спрацювати незалежно від того, чи мають окремі файли один або кілька рядків даних CSV. Також я не запускав цей код, але він повинен дати вам уявлення про те, що робити.


1

Над рішенням, яке зробило @Adders, а пізніше вдосконалило @varun, я реалізував невелике вдосконалення, залишивши весь об'єднаний CSV лише з головним заголовком:

from glob import glob

filename = 'main.csv'

with open(filename, 'a') as singleFile:
    first_csv = True
    for csv in glob('*.csv'):
        if csv == filename:
            pass
        else:
            header = True
            for line in open(csv, 'r'):
                if first_csv and header:
                    singleFile.write(line)
                    first_csv = False
                    header = False
                elif header:
                    header = False
                else:
                    singleFile.write(line)
    singleFile.close()

З найкращими побажаннями!!!


1

Ви можете просто використовувати вбудовану csvбібліотеку. Це рішення буде працювати, навіть якщо деякі з ваших файлів CSV мають дещо інші назви стовпців або заголовки, на відміну від інших найкращих відповідей.

import csv
import glob


filenames = [i for i in glob.glob("SH*.csv")]
header_keys = []
merged_rows = []

for filename in filenames:
    with open(filename) as f:
        reader = csv.DictReader(f)
        merged_rows.extend(list(reader))
        header_keys.extend([key for key in reader.fieldnames if key not in header_keys])

with open("combined.csv", "w") as f:
    w = csv.DictWriter(f, fieldnames=header_keys)
    w.writeheader()
    w.writerows(merged_rows)

Об’єднаний файл міститиме всі можливі стовпці ( header_keys), які можна знайти у файлах. Будь-які відсутні стовпці у файлі відображатимуться як порожні / порожні (але з збереженням решти даних файлу).

Примітка:

  • Це не спрацює, якщо у файлах CSV немає заголовків. У цьому випадку ви все ще можете користуватися csvбібліотекою, але замість використання DictReader& DictWriterвам доведеться працювати з базовим reader& writer.
  • Це може зіткнутися з проблемами, коли ви маєте справу з масивними даними, оскільки весь вміст зберігається в пам'яті ( merged_rowsсписок).

0

Я змінив те, що @wisty сказав, що працює з python 3.x, для тих з вас, у кого є проблеми з кодуванням, я також використовую модуль os, щоб уникнути жорсткого кодування

import os 
def merge_all():
    dir = os.chdir('C:\python\data\\')
    fout = open("merged_files.csv", "ab")
    # first file:
    for line in open("file_1.csv",'rb'):
        fout.write(line)
    # now the rest:
    list = os.listdir(dir)
    number_files = len(list)
    for num in range(2, number_files):
        f = open("file_" + str(num) + ".csv", 'rb')
        f.__next__()  # skip the header
        for line in f:
            fout.write(line)
        f.close()  # not really needed
    fout.close()

0

Ось сценарій:

  • Конкатенація файлів CSV з ім'ям SH1.csvвSH200.csv
  • Зберігаючи заголовки
import glob
import re

# Looking for filenames like 'SH1.csv' ... 'SH200.csv'
pattern = re.compile("^SH([1-9]|[1-9][0-9]|1[0-9][0-9]|200).csv$")
file_parts = [name for name in glob.glob('*.csv') if pattern.match(name)]

with open("file_merged.csv","wb") as file_merged:
    for (i, name) in enumerate(file_parts):
        with open(name, "rb") as file_part:
            if i != 0:
                next(file_part) # skip headers if not first file
            file_merged.write(file_part.read())

0

Оновлення відповіді Вісті для python3

fout=open("out.csv","a")
# first file:
for line in open("sh1.csv"):
    fout.write(line)
# now the rest:    
for num in range(2,201):
    f = open("sh"+str(num)+".csv")
    next(f) # skip the header
    for line in f:
         fout.write(line)
    f.close() # not really needed
fout.close()

0

Скажімо, у вас є 2 csvтаких файли:

csv1.csv:

id,name
1,Armin
2,Sven

csv2.csv:

id,place,year
1,Reykjavik,2017
2,Amsterdam,2018
3,Berlin,2019

і ви хочете, щоб результат був таким: csv3.csv:

id,name,place,year
1,Armin,Reykjavik,2017
2,Sven,Amsterdam,2018
3,,Berlin,2019

Тоді ви можете використовувати такий фрагмент для цього:

import csv
import pandas as pd

# the file names
f1 = "csv1.csv"
f2 = "csv2.csv"
out_f = "csv3.csv"

# read the files
df1 = pd.read_csv(f1)
df2 = pd.read_csv(f2)

# get the keys
keys1 = list(df1)
keys2 = list(df2)

# merge both files
for idx, row in df2.iterrows():
    data = df1[df1['id'] == row['id']]

    # if row with such id does not exist, add the whole row
    if data.empty:
        next_idx = len(df1)
        for key in keys2:
            df1.at[next_idx, key] = df2.at[idx, key]

    # if row with such id exists, add only the missing keys with their values
    else:
        i = int(data.index[0])
        for key in keys2:
            if key not in keys1:
                df1.at[i, key] = df2.at[idx, key]

# save the merged files
df1.to_csv(out_f, index=False, encoding='utf-8', quotechar="", quoting=csv.QUOTE_NONE)

За допомогою циклу ви можете досягти того самого результату для кількох файлів, що і у вашому випадку (200 файлів CSV).


0

Якщо файли не пронумеровані в порядку, скористайтеся безпроблемним підходом нижче: Python 3.6 на машині Windows:

import pandas as pd
from glob import glob

interesting_files = glob("C:/temp/*.csv") # it grabs all the csv files from the directory you mention here

df_list = []
for filename in sorted(interesting_files):

df_list.append(pd.read_csv(filename))
full_df = pd.concat(df_list)

# save the final file in same/different directory:
full_df.to_csv("C:/temp/merged_pandas.csv", index=False)

0

Проста у використанні функція:

def csv_merge(destination_path, *source_paths):
'''
Merges all csv files on source_paths to destination_path.
:param destination_path: Path of a single csv file, doesn't need to exist
:param source_paths: Paths of csv files to be merged into, needs to exist
:return: None
'''
with open(destination_path,"a") as dest_file:
    with open(source_paths[0]) as src_file:
        for src_line in src_file.read():
            dest_file.write(src_line)
    source_paths.pop(0)
    for i in range(len(source_paths)):
        with open(source_paths[i]) as src_file:
            src_file.next()
            for src_line in src_file:
                 dest_file.write(src_line)

0
import pandas as pd
import os

df = pd.read_csv("e:\\data science\\kaggle assign\\monthly sales\\Pandas-Data-Science-Tasks-master\\SalesAnalysis\\Sales_Data\\Sales_April_2019.csv")
files = [file for file in  os.listdir("e:\\data science\\kaggle assign\\monthly sales\\Pandas-Data-Science-Tasks-master\\SalesAnalysis\\Sales_Data")
for file in files:
    print(file)

all_data = pd.DataFrame()
for file in files:
    df=pd.read_csv("e:\\data science\\kaggle assign\\monthly sales\\Pandas-Data-Science-Tasks-master\\SalesAnalysis\\Sales_Data\\"+file)
    all_data = pd.concat([all_data,df])
    all_data.head()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.