Importieren Sie mehrere CSV-Dateien in Pandas und verketten Sie sie in einem DataFrame


403

Ich möchte mehrere CSV-Dateien aus einem Verzeichnis in Pandas lesen und sie zu einem großen DataFrame verketten. Ich habe es allerdings nicht herausgefunden. Folgendes habe ich bisher:

import glob
import pandas as pd

# get data file names
path =r'C:\DRO\DCL_rawdata_files'
filenames = glob.glob(path + "/*.csv")

dfs = []
for filename in filenames:
    dfs.append(pd.read_csv(filename))

# Concatenate all data into one DataFrame
big_frame = pd.concat(dfs, ignore_index=True)

Ich denke ich brauche etwas Hilfe innerhalb der for-Schleife ???


nichts Code tut , weil Sie nicht auf Ihre anfügen dfsListe, finden Sie nicht die Linie ersetzen möchten data = pd.read_csv(filename)mit dfs.append(pd.read_csv(filename). Sie müssten dann die Liste durchlaufen und concatich glaube nicht, dass concateine Liste von dfs funktioniert .
EdChum

Außerdem mischen Sie einen Alias ​​für das Modul mit dem Modulnamen in Ihrer letzten Zeile, oder big_frame = pd.concat(dfs, ignore_index=True)? Wenn Sie eine Liste von Datenrahmen haben, müssen Sie die Liste durchlaufen und sich anbig_frame
EdChum

Ja, ich habe den Code bearbeitet, aber ich bin immer noch nicht in der Lage, einen verketteten Datenrahmen aus den CSV-Dateien zu erstellen. Ich bin neu in Python, daher brauche ich weitere Hilfe
Jonas

Sie müssen dfsjetzt eine Schleife durchführen , damit so etwas wie for df in dfs: big_frame.concat(df, ignore_index=True)funktionieren sollte. Sie können es auch versuchen, appendanstatt concatauch.
EdChum

Können Sie genauer sagen, was nicht funktioniert? Denn concatsollte eine Liste von DataFrames genauso gut verarbeiten wie Sie. Ich denke, das ist ein sehr guter Ansatz.
Joris

Antworten:


455

Wenn Sie in all Ihren csvDateien dieselben Spalten haben , können Sie den folgenden Code ausprobieren. Ich habe hinzugefügt, header=0damit nach dem Lesen die csverste Zeile als Spaltenname vergeben werden kann.

import pandas as pd
import glob

path = r'C:\DRO\DCL_rawdata_files' # use your path
all_files = glob.glob(path + "/*.csv")

li = []

for filename in all_files:
    df = pd.read_csv(filename, index_col=None, header=0)
    li.append(df)

frame = pd.concat(li, axis=0, ignore_index=True)

Dies scheint eine altmodische oder auch manuelle Vorgehensweise zu sein, insb. Das Hapood-Ökosystem verfügt über eine wachsende Liste von Tools, mit denen Sie SQL-Abfragen direkt in vielen verschiedenen Verzeichnissen mit unterschiedlichen Dateitypen (CSV, JSON, TXT, Datenbanken) ausführen können, als wäre es eine Datenquelle. In Python muss es etwas Ähnliches geben, da es seit 20 Jahren einen Startschuss für "Big Data" gibt.
Hexatonisch

275
Das Gleiche ist prägnanter und vielleicht schneller, da keine Liste verwendet wird: df = pd.concat((pd.read_csv(f) for f in all_files)) Außerdem sollte man vielleicht os.path.join(path, "*.csv")stattdessen eine verwenden path + "/*.csv", was das Betriebssystem unabhängig macht.
Sid

4
Mit dieser Antwort konnte ich eine neue Spalte mit dem Dateinamen hinzufügen, z. B. mit df['filename'] = os.path.basename(file_)in der for file_-Schleife. Sie sind sich nicht sicher, ob Sids Antwort dies zulässt?
Curtisp

4
@curtisp Sie können das immer noch mit Sids Antwort tun, verwenden Sie es einfach pandas.read_csv(f).assign(filename = foo)im Generator. assignwird den gesamten Datenrahmen einschließlich der neuen Spalte zurückgebenfilename
C8H10N4O2

Wenn Sie viele Dateien haben, würde ich einen Generator verwenden, anstatt + an eine Liste anzuhängen, bevor Sie alle verketten.
Gustafbstrom

289

Eine Alternative zu darindaCoders Antwort :

path = r'C:\DRO\DCL_rawdata_files'                     # use your path
all_files = glob.glob(os.path.join(path, "*.csv"))     # advisable to use os.path.join as this makes concatenation OS independent

df_from_each_file = (pd.read_csv(f) for f in all_files)
concatenated_df   = pd.concat(df_from_each_file, ignore_index=True)
# doesn't create a list, nor does it append to one

2
@Mike @Sid Die letzten beiden Zeilen können ersetzt werden durch : pd.concat((pd.read_csv(f) for f in all_files), ignore_index=True). Die inneren Klammern werden von Pandas Version 0.18.1
Igor Fobia

6
Ich empfehle glob.iglobanstelle von glob.glob; Der erste kehrt zurück und iteriert (anstelle einer Liste) .
toto_tico

54
import glob, os    
df = pd.concat(map(pd.read_csv, glob.glob(os.path.join('', "my_files*.csv"))))

4
Hervorragender Einzeiler, besonders nützlich, wenn keine read_csv-Argumente benötigt werden!
Rafaelvalle

15
Wenn andererseits Argumente benötigt werden, kann dies mit Lambdas geschehen:df = pd.concat(map(lambda file: pd.read_csv(file, delim_whitespace=True), data_files))
fiedl

^ oder mit functools.partial, um Lambdas zu vermeiden
cs95


30

Fast alle Antworten hier sind entweder unnötig komplex (Glob Pattern Matching) oder basieren auf zusätzlichen Bibliotheken von Drittanbietern. Sie können dies in zwei Zeilen tun, indem Sie alles verwenden, was Pandas und Python (alle Versionen) bereits eingebaut haben.

Für ein paar Dateien - 1 Liner:

df = pd.concat(map(pd.read_csv, ['data/d1.csv', 'data/d2.csv','data/d3.csv']))

Für viele Dateien:

from os import listdir

filepaths = [f for f in listdir("./data") if f.endswith('.csv')]
df = pd.concat(map(pd.read_csv, filepaths))

Diese Pandas-Linie, die den df setzt, verwendet drei Dinge:

  1. Pythons Map (Funktion, iterierbar) sendet an die Funktion (die pd.read_csv()) die iterable (unsere Liste), die jedes CSV-Element in Dateipfaden ist.
  2. Die Funktion read_csv () von Panda liest jede CSV-Datei wie gewohnt ein .
  3. Pandas concat () bringt all dies unter eine df-Variable.

3
oder einfachdf = pd.concat(map(pd.read_csv, glob.glob('data/*.csv))
Myon

Ich habe die von @muon vorgeschriebene Methode ausprobiert. Aber ich habe mehrere Dateien mit Headern (Header sind üblich). Ich möchte nicht, dass sie im Datenrahmen verkettet werden. Weißt du wie ich das machen kann? Ich habe es versucht, df = pd.concat(map(pd.read_csv(header=0), glob.glob('data/*.csv))aber es gab einen Fehler "parser_f () fehlt 1 erforderliches Positionsargument: 'filepath_or_buffer'"
cadip92

14

Bearbeiten: Ich habe meinen Weg in https://stackoverflow.com/a/21232849/186078 gegoogelt . In letzter Zeit finde ich es jedoch schneller, Manipulationen mit numpy durchzuführen und sie dann einmal dem Datenrahmen zuzuweisen, anstatt den Datenrahmen selbst iterativ zu manipulieren, und es scheint auch in dieser Lösung zu funktionieren.

Ich möchte aufrichtig, dass jemand, der auf diese Seite trifft, diesen Ansatz in Betracht zieht, aber ich möchte diesen riesigen Code nicht als Kommentar anhängen und ihn weniger lesbar machen.

Sie können numpy nutzen, um die Verkettung von Datenrahmen wirklich zu beschleunigen.

import os
import glob
import pandas as pd
import numpy as np

path = "my_dir_full_path"
allFiles = glob.glob(os.path.join(path,"*.csv"))


np_array_list = []
for file_ in allFiles:
    df = pd.read_csv(file_,index_col=None, header=0)
    np_array_list.append(df.as_matrix())

comb_np_array = np.vstack(np_array_list)
big_frame = pd.DataFrame(comb_np_array)

big_frame.columns = ["col1","col2"....]

Timing-Statistiken:

total files :192
avg lines per file :8492
--approach 1 without numpy -- 8.248656988143921 seconds ---
total records old :1630571
--approach 2 with numpy -- 2.289292573928833 seconds ---

Irgendwelche Zahlen, um die "Beschleunigung" zu unterstützen? Ist es schneller als stackoverflow.com/questions/20906474/… ?
ivan_pozdeev

Ich sehe nicht, dass das OP nach einer Möglichkeit fragt, seine Verkettung zu beschleunigen. Dies scheint nur eine Überarbeitung einer bereits vorhandenen akzeptierten Antwort zu sein.
Pydsigner

2
Das funktioniert nicht, wenn die Daten gemischte Spaltentypen haben.
Pimin Konstantin Kefaloukos

1
@SKG perfekt .. das ist die einzige funktionierende Lösung für mich. 500 Dateien 400.000 Zeilen insgesamt in 2 Sekunden. Danke, dass du es gepostet hast.
FrankC

11

Wenn Sie rekursiv suchen möchten ( Python 3.5 oder höher ), können Sie Folgendes tun:

from glob import iglob
import pandas as pd

path = r'C:\user\your\path\**\*.csv'

all_rec = iglob(path, recursive=True)     
dataframes = (pd.read_csv(f) for f in all_rec)
big_dataframe = pd.concat(dataframes, ignore_index=True)

Beachten Sie, dass die drei letzten Zeilen in einer einzigen Zeile ausgedrückt werden können :

df = pd.concat((pd.read_csv(f) for f in iglob(path, recursive=True)), ignore_index=True)

Die Dokumentation finden Sie ** hier . Auch ich verwenden iglobstatt glob, da es eine gibt Iterator statt einer Liste.



EDIT: Multiplattform rekursive Funktion:

Sie können das oben Genannte in eine Multiplattform-Funktion (Linux, Windows, Mac) einbinden, um Folgendes zu tun:

df = read_df_rec('C:\user\your\path', *.csv)

Hier ist die Funktion:

from glob import iglob
from os.path import join
import pandas as pd

def read_df_rec(path, fn_regex=r'*.csv'):
    return pd.concat((pd.read_csv(f) for f in iglob(
        join(path, '**', fn_regex), recursive=True)), ignore_index=True)

11

Einfach und schnell

Importieren Sie zwei oder mehr Namen csv, ohne eine Liste mit Namen erstellen zu müssen.

import glob

df = pd.concat(map(pd.read_csv, glob.glob('data/*.csv')))

8

Ein Liner verwendet map, aber wenn Sie zusätzliche Argumente angeben möchten, können Sie Folgendes tun:

import pandas as pd
import glob
import functools

df = pd.concat(map(functools.partial(pd.read_csv, sep='|', compression=None), 
                    glob.glob("data/*.csv")))

Hinweis: An mapsich können Sie keine zusätzlichen Argumente angeben.


4

Wenn mehrere CSV-Dateien komprimiert sind, können Sie zipfile verwenden, um alle zu lesen und wie folgt zu verketten:

import zipfile
import numpy as np
import pandas as pd

ziptrain = zipfile.ZipFile('yourpath/yourfile.zip')

train=[]

for f in range(0,len(ziptrain.namelist())):
    if (f == 0):
        train = pd.read_csv(ziptrain.open(ziptrain.namelist()[f]))
    else:
        my_df = pd.read_csv(ziptrain.open(ziptrain.namelist()[f]))
        train = (pd.DataFrame(np.concatenate((train,my_df),axis=0), 
                          columns=list(my_df.columns.values)))

4

Ein weiterer Onliner mit Listenverständnis, der die Verwendung von Argumenten mit read_csv ermöglicht.

df = pd.concat([pd.read_csv(f'dir/{f}') for f in os.listdir('dir') if f.endswith('.csv')])

3

Basierend auf der guten Antwort von @ Sid.

Vor dem Verketten können Sie CSV-Dateien in ein Zwischenwörterbuch laden, das den Zugriff auf jeden Datensatz basierend auf dem Dateinamen (im Formular dict_of_df['filename.csv']) ermöglicht. Ein solches Wörterbuch kann Ihnen helfen, Probleme mit heterogenen Datenformaten zu identifizieren, wenn beispielsweise Spaltennamen nicht ausgerichtet sind.

Importieren Sie Module und suchen Sie Dateipfade:

import os
import glob
import pandas
from collections import OrderedDict
path =r'C:\DRO\DCL_rawdata_files'
filenames = glob.glob(path + "/*.csv")

Hinweis: OrderedDictist nicht erforderlich, behält jedoch die Reihenfolge der Dateien bei, die für die Analyse hilfreich sein können.

Laden Sie CSV-Dateien in ein Wörterbuch. Dann verketten:

dict_of_df = OrderedDict((f, pandas.read_csv(f)) for f in filenames)
pandas.concat(dict_of_df, sort=True)

Schlüssel sind Dateinamen fund Werte sind der Datenrahmeninhalt von CSV-Dateien. Anstatt fals Wörterbuchschlüssel zu verwenden, können Sie auch os.path.basename(f)oder andere os.path- Methoden verwenden, um die Größe des Schlüssels im Wörterbuch nur auf den kleineren Teil zu reduzieren, der relevant ist.


3

Alternative Nutzung der pathlibBibliothek (oft bevorzugt os.path).

Diese Methode vermeidet die iterative Verwendung von Pandas concat()/ apped().

Aus der Pandas-Dokumentation:
Es ist erwähnenswert, dass concat () (und daher append ()) eine vollständige Kopie der Daten erstellt und dass die ständige Wiederverwendung dieser Funktion zu einem erheblichen Leistungseinbruch führen kann. Wenn Sie die Operation für mehrere Datensätze verwenden müssen, verwenden Sie ein Listenverständnis.

import pandas as pd
from pathlib import Path

dir = Path("../relevant_directory")

df = (pd.read_csv(f) for f in dir.glob("*.csv"))
df = pd.concat(df)

-2

So können Sie Colab in Google Drive verwenden

import pandas as pd
import glob

path = r'/content/drive/My Drive/data/actual/comments_only' # use your path
all_files = glob.glob(path + "/*.csv")

li = []

for filename in all_files:
    df = pd.read_csv(filename, index_col=None, header=0)
    li.append(df)

frame = pd.concat(li, axis=0, ignore_index=True,sort=True)
frame.to_csv('/content/drive/onefile.csv')

-3
import pandas as pd
import glob

path = r'C:\DRO\DCL_rawdata_files' # use your path
file_path_list = glob.glob(path + "/*.csv")

file_iter = iter(file_path_list)

list_df_csv = []
list_df_csv.append(pd.read_csv(next(file_iter)))

for file in file_iter:
    lsit_df_csv.append(pd.read_csv(file, header=0))
df = pd.concat(lsit_df_csv, ignore_index=True)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.