jak scalić 200 plików csv w Pythonie


83

Chłopaki, mam tutaj 200 oddzielnych plików csv o nazwach od SH (1) do SH (200). Chcę połączyć je w jeden plik CSV. Jak mogę to zrobić?


3
W jaki sposób je scalisz? (Linie konkatenowane, ...)
tur1ng

6
Jak chcesz, aby zostały połączone? Każdy wiersz w pliku CSV to wiersz. Tak więc jedną prostą opcją jest po prostu połączenie wszystkich plików razem.
Jon-Eric

Każdy plik ma dwie kolumny. Chcę połączyć je w jeden plik z dwiema kolumnami po kolei.
Chuck,

1
@Chuck: Co powiesz na zbieranie wszystkich odpowiedzi w swoich komentarzach (na pytanie i odpowiedzi) i aktualizowanie pytania?
tumultous_rooster

2
To pytanie powinno być nazwane „Jak concat ...” zamiast „jak scalić ...”
colidyre

Odpowiedzi:


95

Jak powiedział ghostdog74, ale tym razem z nagłówkami:

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
możesz użyć f.__next__()zamiast tego, jeśli f.next()w python3.x.
tsveti_iko

5
Tylko uwaga: można użyć with openskładni i uniknąć ręcznego .close()wprowadzania plików.
FatihAkici

2
jaka jest różnica między f.next()i f.__next__()? kiedy używam tego pierwszego, otrzymałem'_io.TextIOWrapper' object has no attribute 'next'
Jason Goal

zanim fout.write(line)to zrobię:if line[-1] != '\n': line += '\n'
shisui

65

Dlaczego nie możesz po prostu sed 1d sh*.csv > merged.csv?

Czasami nie musisz nawet używać Pythona!


21
W systemie Windows C: \> kopiuj * .csv scalony.csv
nalot,

6
Skopiuj informacje nagłówka z jednego pliku: sed -n 1p jakiś_plik.csv> scaled_file.csv Skopiuj wszystko oprócz ostatniej linii ze wszystkich innych plików: sed 1d * .csv >> scaled_file.csv
behas

3
@blinsay Dodaje również nagłówek w każdym pliku CSV do scalonego pliku.
Mina

5
Jak używać tego polecenia bez kopiowania informacji nagłówka dla każdego kolejnego pliku po pierwszym? Wydaje się, że wielokrotnie pojawiają się informacje z nagłówka.
Joe

2
To świetnie, jeśli nie musisz usuwać nagłówka!
Blairg23

51

Użyj zaakceptowanej odpowiedzi StackOverflow, aby utworzyć listę plików CSV, które chcesz dołączyć, a następnie uruchom ten kod:

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

A jeśli chcesz wyeksportować go do pojedynczego pliku csv, użyj tego:

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

@ wisty, @ Andy, przypuśćmy, że wszystkie pliki mają tytuły dla każdego wiersza - niektóre wiersze mają różne tytuły. Brak nagłówków dla dwóch kolumn w każdym pliku. Jak można scalić, tak że do każdego pliku dodawana jest tylko kolumna.
Gathide,

Gdzie plik jest eksportowany?

@ dirtysocks45, zmieniłem odpowiedź, aby była bardziej wyraźna.
scottlittle

dodaj sort: linked_csv = pd.concat ([pd.read_csv (f) for f w nazwach plików], 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

Przejdę tylko przez inny przykład kodu w koszyku

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 Nie widzę różnicy między przepełnieniem stosu przypominającym mi o głosowaniu nad odpowiedzią a przypominającym ludziom, aby podzielili się uznaniem (poprzez głosowanie), jeśli uznają moją odpowiedź za przydatną. Wiem, że to nie jest Facebook i nie jestem łowcą jak łowcą ...
Norfeldt

1
Zostało to omówione wcześniej i za każdym razem uznawane było za niedopuszczalne.
Andy

10

To zależy, co masz na myśli, mówiąc „scalanie” - czy mają te same kolumny? Czy mają nagłówki? Na przykład, jeśli wszystkie mają te same kolumny i nie mają nagłówków, wystarczy prosta konkatenacja (otwórz plik docelowy do zapisu, pętla nad źródłami otwierającymi każde z nich do odczytu, użyj shutil.copyfileobj ze źródła open-for-reading do miejsce docelowe otwarte do zapisu, zamknij źródło, kontynuuj zapętlanie - użyj withinstrukcji, aby wykonać zamknięcie w swoim imieniu). Jeśli mają te same kolumny, ale także nagłówki, będziesz potrzebować znaku readlinena każdym pliku źródłowym z wyjątkiem pierwszego, po otwarciu go do odczytu przed skopiowaniem do miejsca docelowego, aby pominąć wiersz nagłówków.

Jeśli pliki CSV nie mają tych samych kolumn, musisz zdefiniować, w jakim sensie je „scalasz” (np. SQL JOIN? Lub „poziomo”, jeśli wszystkie mają tę samą liczbę wierszy? Itd.) ) - trudno nam zgadnąć, co masz na myśli w tym przypadku.


Każdy plik ma dwie kolumny z nagłówkami. Chcę połączyć je w jeden plik z dwiema kolumnami po kolei.
Chuck

4

Niewielka zmiana w powyższym kodzie, ponieważ w rzeczywistości nie działa on poprawnie.

Powinno wyglądać następująco ...

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

Całkiem łatwo połączyć wszystkie pliki w katalogu i scalić je

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

Jeśli pracujesz na Linuksie / Macu, możesz to zrobić.

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


1

Możesz zaimportować csv, a następnie przejrzeć wszystkie pliki CSV i odczytać je na liście. Następnie zapisz listę z powrotem na dysk.

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

Powyższe nie jest bardzo niezawodne, ponieważ nie obsługuje błędów ani nie zamyka żadnych otwartych plików. Powinno to działać niezależnie od tego, czy poszczególne pliki mają jeden lub więcej wierszy danych CSV. Nie uruchomiłem również tego kodu, ale powinien dać ci pomysł, co robić.


1

W przypadku rozwiązania, które sprawiło, że @Adders i później zostało ulepszone przez @varun, zaimplementowałem trochę ulepszeń, pozostawiając cały scalony plik CSV tylko z głównym nagłówkiem:

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

Z poważaniem!!!


1

Możesz po prostu skorzystać z wbudowanej csvbiblioteki. To rozwiązanie zadziała, nawet jeśli niektóre z Twoich plików CSV mają nieco inne nazwy kolumn lub nagłówki, w przeciwieństwie do innych odpowiedzi najczęściej wybieranych.

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)

Scalony plik będzie zawierał wszystkie możliwe kolumny ( header_keys), które można znaleźć w plikach. Wszelkie brakujące kolumny w pliku byłyby renderowane jako puste / puste (ale z zachowaniem reszty danych pliku).

Uwaga:

  • To nie zadziała, jeśli Twoje pliki CSV nie mają nagłówków. W takim przypadku możesz nadal korzystać z csvbiblioteki, ale zamiast używać DictReader& DictWriter, będziesz musiał pracować z podstawowym reader& writer.
  • Może to powodować problemy, gdy masz do czynienia z ogromnymi danymi, ponieważ cała zawartość jest przechowywana w pamięci ( merged_rowslista).

0

Zmodyfikowałem to, co @wisty powiedział, że działa z pythonem 3.x, dla tych z Was, którzy mają problem z kodowaniem, również używam modułu os, aby uniknąć twardego kodowania

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

Oto skrypt:

  • Łączenie plików CSV o nazwie SH1.csv doSH200.csv
  • Zachowanie nagłówków
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

Aktualizuję odpowiedź Wisty dla Pythona3

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

Powiedzmy, że masz 2 csv takie pliki:

csv1.csv:

id,name
1,Armin
2,Sven

csv2.csv:

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

i chcesz, aby wynik był taki jak ten csv3.csv:

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

W tym celu możesz użyć następującego fragmentu kodu:

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)

Za pomocą pętli możesz osiągnąć ten sam wynik dla wielu plików, jak w twoim przypadku (200 plików csv).


0

Jeśli pliki nie są ponumerowane w kolejności, zastosuj bezproblemowe podejście poniżej: Python 3.6 na komputerze z systemem 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

Łatwa w użyciu funkcja:

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()
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.