Importe múltiples archivos csv en pandas y concatene en un DataFrame

404

Me gustaría leer varios archivos csv de un directorio en pandas y concatenarlos en un gran DataFrame. Sin embargo, no he podido resolverlo. Esto es lo que tengo hasta ahora:

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)

Supongo que necesito ayuda dentro del ciclo for ???

jonas
fuente
su código no hace nada porque no está agregando a su dfslista, no desea reemplazar la línea data = pd.read_csv(filename)con dfs.append(pd.read_csv(filename). Entonces necesitarías recorrer la lista y concat, no creo concatque funcione en una lista de dfs.
EdChum
también está mezclando un alias para el módulo con el nombre del módulo en su última línea, ¿no debería ser así big_frame = pd.concat(dfs, ignore_index=True)? De todos modos, una vez que tenga una lista de marcos de datos, deberá iterar sobre la lista y concat abig_frame
EdChum
Sí, edité el código, pero todavía no puedo construir un marco de datos concatenados a partir de los archivos csv, soy nuevo en Python, así que necesito más ayuda sobre esto
jonas
necesita hacer un bucle dfsahora, por lo que algo así for df in dfs: big_frame.concat(df, ignore_index=True)debería funcionar, también podría intentarlo en appendlugar de concattambién.
EdChum
¿Puedes decir más exactamente lo que no funciona? Porque concatdebería manejar una lista de DataFrames tan bien como lo hiciste. Creo que este es un muy buen enfoque.
joris

Respuestas:

457

Si tiene las mismas columnas en todos sus csvarchivos, puede probar el siguiente código. He agregado header=0para que después de leer la csvprimera fila se puedan asignar los nombres de columna.

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)
Gaurav Singh
fuente
Esto parece una antigua forma manual de hacer las cosas, especialmente. Como el ecosistema de Hapood tiene una creciente lista de herramientas donde puede realizar consultas SQL directamente en muchos directorios diferentes que contienen diferentes tipos de archivos (csv, json, txt, bases de datos) como si fuera una fuente de datos. Debe haber algo similar en Python, ya que ha tenido un salto de 20 años en hacer "big data".
Hexatónico
276
Lo mismo es más conciso, y quizás más rápido, ya que no usa una lista: df = pd.concat((pd.read_csv(f) for f in all_files)) Además, tal vez debería usarse en os.path.join(path, "*.csv")lugar de path + "/*.csv", lo que lo hace independiente del sistema operativo.
Sid
44
El uso de esta respuesta me permitió agregar una nueva columna con el nombre del archivo, por ejemplo, df['filename'] = os.path.basename(file_)en el archivo for_ loop ... ¿no está seguro de si la respuesta de Sid lo permite?
Curtisp
44
@curtisp aún puede hacerlo con la respuesta de Sid, solo use pandas.read_csv(f).assign(filename = foo)dentro del generador. assigndevolverá todo el marco de datos, incluida la nueva columnafilename
C8H10N4O2
Si tiene muchos archivos, usaría un generador en lugar de importar + agregar a una lista antes de concatenarlos a todos.
gustafbstrom
289

Una alternativa a la respuesta 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
Sid
fuente
2
@ Mike @Sid las dos últimas líneas pueden ser sustituidos por: pd.concat((pd.read_csv(f) for f in all_files), ignore_index=True). Los soportes internos son requeridos por Pandas versión 0.18.1
Igor Fobia
66
Recomiendo usar en glob.igloblugar de glob.glob; El primero regresa e iterador (en lugar de una lista) .
toto_tico
54
import glob, os    
df = pd.concat(map(pd.read_csv, glob.glob(os.path.join('', "my_files*.csv"))))
Jose Antonio Martin H
fuente
44
Excelente línea, especialmente útil si no se necesitan argumentos read_csv.
rafaelvalle
15
Si, por otro lado, se necesitan argumentos, esto se puede hacer con lambdas:df = pd.concat(map(lambda file: pd.read_csv(file, delim_whitespace=True), data_files))
fiedl
^ o con functools.partial, para evitar lambdas
cs95
34

La biblioteca Dask puede leer un marco de datos de múltiples archivos:

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

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

Los marcos de datos de Dask implementan un subconjunto de la API de marcos de datos de Pandas. Si todos los datos se ajustan a la memoria, puede llamardf.compute() para convertir el marco de datos en un marco de datos Pandas.

Jouni K. Seppänen
fuente
30

Casi todas las respuestas aquí son innecesariamente complejas (coincidencia de patrones globales) o dependen de bibliotecas de terceros adicionales. Puede hacer esto en 2 líneas usando todo lo que Pandas y Python (todas las versiones) ya han incorporado.

Para algunos archivos - 1 liner:

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

Para muchos archivos:

from os import listdir

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

Esta línea de pandas que establece el df utiliza 3 cosas:

  1. El mapa de Python (función, iterable) envía a la función (the pd.read_csv()) el iterable (nuestra lista), que es cada elemento csv en las rutas de archivo).
  2. La función read_csv () de Panda lee en cada archivo CSV de forma normal.
  3. Panda's concat () reúne todo esto bajo una variable df.
robmsmt
fuente
3
o simplementedf = pd.concat(map(pd.read_csv, glob.glob('data/*.csv))
muon
Probé el método prescrito por @muon. Pero, tengo varios archivos con encabezados (los encabezados son comunes). No quiero que se concatenen en el marco de datos. ¿Sabes cómo puedo hacer eso? Lo intenté df = pd.concat(map(pd.read_csv(header=0), glob.glob('data/*.csv))pero me dio un error "parser_f () falta 1 argumento posicional requerido: 'filepath_or_buffer'"
cadip92
14

Editar: busqué en Google en https://stackoverflow.com/a/21232849/186078 . Sin embargo, últimamente me parece más rápido hacer cualquier manipulación usando numpy y luego asignarlo una vez al marco de datos en lugar de manipular el marco de datos en sí de forma iterativa y parece funcionar también en esta solución.

Sinceramente, quiero que cualquiera que acceda a esta página considere este enfoque, pero no quiero adjuntar este gran fragmento de código como comentario y hacerlo menos legible.

Puede aprovechar numpy para acelerar realmente la concatenación del marco de datos.

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

Estadísticas de tiempo:

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 ---
SKG
fuente
¿Algún número para respaldar el "acelerar"? Específicamente, ¿es más rápido que stackoverflow.com/questions/20906474/… ?
ivan_pozdeev
No veo que el OP pida una forma de acelerar su concatenación, esto solo parece una reelaboración de una respuesta aceptada preexistente.
pydsigner
2
Eso no funcionará si los datos tienen tipos de columnas mixtas.
Pimin Konstantin Kefaloukos
1
@SKG perfecto ... esta es la única solución que funciona para mí. 500 archivos 400k filas en total en 2 segundos. Gracias por publicarlo.
FrankC
11

Si desea buscar de forma recursiva ( Python 3.5 o superior ), puede hacer lo siguiente:

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)

Tenga en cuenta que las tres últimas líneas se pueden expresar en una sola línea :

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

Puede encontrar la documentación de ** aquí . Además, usé en igloblugar de glob, ya que devuelve un iterador en lugar de una lista.



EDITAR: Función recursiva multiplataforma:

Puede envolver lo anterior en una función multiplataforma (Linux, Windows, Mac), para que pueda hacer:

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

Aquí está la función:

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)
toto_tico
fuente
11

Fácil y rápido

Importe dos o más csvsin tener que hacer una lista de nombres.

import glob

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

usando un trazador de líneas map, pero si desea especificar argumentos adicionales, puede hacer:

import pandas as pd
import glob
import functools

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

Nota: mappor sí solo no le permite suministrar argumentos adicionales.

muon
fuente
4

Si los múltiples archivos csv están comprimidos, puede usar zipfile para leerlos todos y concatenarlos de la siguiente manera:

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)))
Nim J
fuente
4

Otro en línea con comprensión de lista que permite utilizar argumentos con read_csv.

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

Basado en la buena respuesta de @ Sid.

Antes de concatenar, puede cargar archivos csv en un diccionario intermedio que da acceso a cada conjunto de datos en función del nombre del archivo (en el formulario dict_of_df['filename.csv'] ). Dicho diccionario puede ayudarlo a identificar problemas con formatos de datos heterogéneos, cuando los nombres de columna no están alineados, por ejemplo.

Importe módulos y ubique rutas de archivos:

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

Nota: OrderedDict no es necesario, pero mantendrá el orden de los archivos que podrían ser útiles para el análisis.

Cargue archivos csv en un diccionario. Luego concatenar:

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

Las claves son nombres de archivos fy los valores son el contenido del marco de datos de los archivos csv. En lugar de usarlo fcomo una clave de diccionario, también puede usar os.path.basename(f)u otros métodos os.path para reducir el tamaño de la clave en el diccionario solo a la parte más pequeña que sea relevante.

Paul Rougieux
fuente
3

Alternativa al uso de la pathlibbiblioteca (a menudo preferida sobre os.path).

Este método evita el uso iterativo de pandas concat()/ apped().

De la documentación de pandas:
Vale la pena señalar que concat () (y, por lo tanto, append ()) hace una copia completa de los datos, y que la reutilización constante de esta función puede crear un impacto significativo en el rendimiento. Si necesita usar la operación en varios conjuntos de datos, use una lista de comprensión.

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)
Henrik
fuente
-2

Así es como puedes hacer usando Colab en Google Drive

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')
Shaina Raza
fuente
-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)
YASH GUPTA
fuente