web-dev-qa-db-fra.com

Importez plusieurs fichiers CSV dans pandas et concaténez-les dans un seul DataFrame

Je voudrais lire plusieurs fichiers csv d'un répertoire dans pandas et les concaténer dans un seul gros DataFrame. Je n'ai pas été capable de le comprendre cependant. Voici ce que j'ai jusqu'à présent:

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)

Je suppose que j'ai besoin d'aide dans la boucle ???

281
jonas

Si vous avez les mêmes colonnes dans tous vos fichiers csv, vous pouvez essayer le code ci-dessous. J'ai ajouté header=0 afin qu'après la lecture de csv, la première ligne puisse être affectée comme nom de colonne.

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)
320
Gaurav Singh

Une alternative à réponse de darindaCoder :

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
244
Sid
import glob, os    
df = pd.concat(map(pd.read_csv, glob.glob(os.path.join('', "my_files*.csv"))))
43
Jose Antonio Martin H

Presque toutes les réponses ici sont soit inutilement complexes (correspondance de modèle global), soit reposent sur des bibliothèques tierces supplémentaires. Vous pouvez le faire en 2 lignes en utilisant tout Pandas et python (toutes les versions) déjà intégrés.

Pour quelques dossiers - 1 liner:

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

Pour de nombreux fichiers:

from os import listdir

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

Cette ligne pandas qui définit le df utilise 3 choses:

  1. La carte de Python (fonction, itérable) envoie à la fonction (la pd.read_csv()) l'itérable (notre liste) qui représente tous les éléments csv des chemins de fichiers).
  2. La fonction read_csv () de Panda lit dans chaque fichier CSV normalement.
  3. Panda's concat () regroupe tous ces éléments sous une seule variable df.
18
robmsmt

La bibliothèque Dask peut lire une image de données à partir de plusieurs fichiers:

>>> import dask.dataframe as dd
>>> df = dd.read_csv('data*.csv')

(Source: http://dask.pydata.org/en/latest/examples/dataframe-csv.html )

Les images Dask implémentent un sous-ensemble de l'API Pandas dataframe. Si toutes les données entrent dans la mémoire, vous pouvez appeler df.compute() pour convertir le cadre de données en un cadre de données Pandas.

18
Jouni K. Seppänen

Edit: Je suis allé sur Google pour trouver mon chemin https://stackoverflow.com/a/21232849/186078 . Cependant, dernièrement, je trouve plus rapide de manipuler numpy avec une autre tâche, puis de l'attribuer une fois à dataframe plutôt que de manipuler celui-ci sur une base itérative, ce qui semble fonctionner également dans cette solution.

Je souhaite sincèrement que toute personne visitant cette page examine cette approche, mais je ne souhaite pas joindre cet énorme élément de code sous forme de commentaire afin de le rendre moins lisible.

Vous pouvez utiliser numpy pour accélérer réellement la concaténation de trames de données.

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"....]

Statistiques de chronométrage:

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 ---
12
SKG

Si vous voulez rechercher récursivement ( Python 3.5 ou supérieur ), vous pouvez procéder comme suit:

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)

Notez que les trois dernières lignes peuvent être exprimées en une ligne simple :

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

Vous pouvez trouver la documentation de **ici . De plus, j'ai utilisé iglob au lieu de glob, car il retourne un itérateur au lieu d'une liste.



EDIT: Fonction récursive multiplateforme:

Vous pouvez encapsuler ce qui précède dans une fonction multiplateforme (Linux, Windows, Mac), afin de pouvoir:

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

Voici la fonction:

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

Si plusieurs fichiers csv sont compressés, vous pouvez utiliser zipfile pour tout lire et concaténer comme ci-dessous:

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
Nim J

Basé sur la bonne réponse de @ Sid.

Avant de concaténer, vous pouvez charger les fichiers csv dans un dictionnaire intermédiaire qui donne accès à chaque ensemble de données en fonction du nom du fichier (sous la forme dict_of_df['filename.csv']). Un tel dictionnaire peut vous aider à identifier les problèmes liés aux formats de données hétérogènes, par exemple lorsque les noms de colonne ne sont pas alignés.

Importer des modules et localiser les chemins de fichiers:

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

Remarque: OrderedDict n'est pas nécessaire, mais il conservera l'ordre des fichiers pouvant être utile à l'analyse.

Chargez les fichiers CSV dans un dictionnaire. Puis concaténer:

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

Les clés sont des noms de fichier f et les valeurs représentent le contenu des trames de données des fichiers csv. Au lieu d'utiliser f comme clé de dictionnaire, vous pouvez également utiliser os.path.basename(f) ou d'autres méthodes os.path pour réduire la taille de la clé dans le dictionnaire à la plus petite partie c'est pertinent.

2
Paul Rougieux

une ligne utilisant map, mais si vous souhaitez spécifier des arguments supplémentaires, vous pouvez procéder comme suit:

import pandas as pd
import glob
import functools

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

Remarque: map be ne vous permet pas de fournir des arguments supplémentaires.

2
muon

Facile et rapide

Importez 2 ou plus de csv sans avoir à dresser une liste de noms.

import glob

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

J'ai trouvé cette méthode assez élégante.

import pandas as pd
import os

big_frame = pd.DataFrame()

for file in os.listdir():
    if file.endswith('.csv'):
        df = pd.read_csv(file)
        big_frame = big_frame.append(df, ignore_index=True)
2
Erfan

Un autre on-liner avec une compréhension de liste qui permet d'utiliser des arguments avec read_csv.

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