Importe vários arquivos CSV para pandas e concatene em um DataFrame

404

Gostaria de ler vários arquivos csv de um diretório para pandas e concatená-los em um grande DataFrame. Ainda não consegui descobrir. Aqui está o que eu tenho até agora:

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)

Acho que preciso de ajuda dentro do loop for ???

jonas
fonte
seu código não faz nada porque você não está acrescentando à sua dfslista, que você não deseja substituir a linha data = pd.read_csv(filename)com dfs.append(pd.read_csv(filename). Você precisaria percorrer a lista e concat, acho que não concatfuncionará em uma lista de dfs.
EdChum
Também você está misturando um alias para o módulo com o nome do módulo em sua última linha, não deveria ser big_frame = pd.concat(dfs, ignore_index=True), de qualquer maneira uma vez que você tem uma lista de dataframes você precisará iterar sobre a lista e concat para?big_frame
EdChum
Sim, eu editei o código, mas eu ainda não sou capaz de construir uma trama de dados de concatenado a partir dos csv-arquivos, eu sou novo para python assim que eu preciso de mais ajuda sobre isso
jonas
você precisa fazer um loop dfsagora, para que algo como for df in dfs: big_frame.concat(df, ignore_index=True)funcione, você também pode tentar em appendvez de concattambém.
EdChum
Você pode dizer mais exatamente o que não está funcionando? Porque concatdeve lidar com uma lista de DataFrames tão bem quanto você. Eu acho que essa é uma abordagem muito boa.
Joris

Respostas:

456

Se você tiver as mesmas colunas em todos os seus csvarquivos, tente o código abaixo. Eu adicionei header=0para que, depois de ler a csvprimeira linha, possa ser atribuído como o nome da coluna.

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
fonte
Isto parece ser uma maneira antiga, também conhecida como manual, de fazer as coisas, esp. como o ecossistema Hapood tem uma lista crescente de ferramentas onde você pode executar consultas sql diretamente em muitos diretórios diferentes, contendo diferentes tipos de arquivos (csv, json, txt, bancos de dados) como se fosse uma fonte de dados. Deve haver algo semelhante no python, pois ele teve um salto de 20 anos no "big data".
Hexatonic
275
A mesma coisa mais concisa e talvez mais rápida, pois não usa uma lista: df = pd.concat((pd.read_csv(f) for f in all_files)) Além disso, talvez deva-se usar em os.path.join(path, "*.csv")vez de path + "/*.csv", o que o torna independente do SO.
Sid
4
O uso desta resposta me permitiu adicionar uma nova coluna com o nome do arquivo, por exemplo, df['filename'] = os.path.basename(file_)no loop for file_ .. não tem certeza se a resposta de Sid permite isso?
curtisp
4
@ curtisp você ainda pode fazer isso com a resposta de Sid, basta usar pandas.read_csv(f).assign(filename = foo)dentro do gerador. assignretornará todo o quadro de dados, incluindo a nova colunafilename
C8H10N4O2 04/04
Se você tiver muitos arquivos, eu usaria um gerador em vez de importar + anexar a uma lista antes de concatená-los todos.
gustafbstrom 19/02
289

Uma alternativa à resposta da 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
fonte
2
@ Mike @Sid as duas últimas linhas pode ser substituído por: pd.concat((pd.read_csv(f) for f in all_files), ignore_index=True). Os colchetes internos são exigidos pela versão 0.18.1 do Pandas
Igor Fobia
6
Eu recomendo usar em glob.iglobvez de glob.glob; O primeiro retorna e iterador (em vez de uma lista) .
Toto_tico 2/08
54
import glob, os    
df = pd.concat(map(pd.read_csv, glob.glob(os.path.join('', "my_files*.csv"))))
Jose Antonio Martin H
fonte
4
Excelente liner, especialmente útil se não forem necessários argumentos read_csv!
Rafaelvalle 9/11
15
Se, por outro lado, são necessários argumentos, isso pode ser feito com lambdas:df = pd.concat(map(lambda file: pd.read_csv(file, delim_whitespace=True), data_files))
Fiedl
^ ou com functools.partial, para evitar lambdas
cs95
34

A biblioteca do Dask pode ler um quadro de dados de vários arquivos:

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

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

Os quadros de dados do Dask implementam um subconjunto da API de quadro de dados do Pandas. Se todos os dados couberem na memória, você poderá ligardf.compute() para converter o quadro de dados em um quadro de dados do Pandas.

Jouni K. Seppänen
fonte
30

Quase todas as respostas aqui são desnecessariamente complexas (correspondência de padrões globais) ou dependem de bibliotecas adicionais de terceiros. Você pode fazer isso em duas linhas usando tudo o que o Pandas e o python (todas as versões) já incorporaram.

Para alguns arquivos - 1 liner:

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

Para muitos arquivos:

from os import listdir

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

Esta linha de pandas que define o df utiliza três coisas:

  1. O mapa do Python (função, iterável) envia para a função (the pd.read_csv()) o iterável (nossa lista), que é todo elemento csv nos caminhos de arquivos).
  2. A função read_csv () do Panda lê cada arquivo CSV normalmente.
  3. O concat () do Panda coloca tudo isso sob uma variável df.
robmsmt
fonte
3
ou apenasdf = pd.concat(map(pd.read_csv, glob.glob('data/*.csv))
muon
Eu tentei o método prescrito pelo @muon. Mas, eu tenho vários arquivos com cabeçalhos (cabeçalhos são comuns). Não quero que eles sejam concatenados no quadro de dados. Você sabe como posso fazer isso? Eu tentei, df = pd.concat(map(pd.read_csv(header=0), glob.glob('data/*.csv))mas deu um erro "parser_f () faltando 1 argumento posicional necessário: 'filepath_or_buffer'"
cadip92 03/03
14

Edit: Eu pesquisei no Google https://stackoverflow.com/a/21232849/186078 . No entanto, ultimamente, acho mais rápido fazer qualquer manipulação usando numpy e atribuí-la uma vez ao dataframe, em vez de manipular o próprio dataframe de forma iterativa, e parece funcionar também nessa solução.

Sinceramente, quero que qualquer pessoa que esteja acessando esta página considere essa abordagem, mas não queira anexar esse enorme código como comentário e torná-lo menos legível.

Você pode aproveitar o numpy para realmente acelerar a concatenação do quadro de dados.

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

Estatísticas de tempo:

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
fonte
Algum número para apoiar o "acelerar"? Especificamente, é mais rápido que o stackoverflow.com/questions/20906474/… ?
ivan_pozdeev
Não vejo o OP pedindo uma maneira de acelerar sua concatenação, isso apenas parece um retrabalho de uma resposta aceita pré-existente.
pydsigner
2
Isso não funcionará se os dados tiverem tipos de colunas mistos.
Pimin Konstantin Kefaloukos
11
@ SKG perfeito .. esta é a única solução de trabalho para mim. 500 arquivos, total de linhas de 400k em 2 segundos. Obrigado por publicá-lo.
FrankC
11

Se você deseja pesquisar recursivamente ( Python 3.5 ou superior ), faça o seguinte:

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)

Observe que as três últimas linhas podem ser expressas em uma única linha :

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

Você pode encontrar a documentação ** aqui . Além disso, usei em iglobvez de glob, pois ele retorna um iterador em vez de uma lista.



EDIT: Função recursiva multiplataforma:

Você pode agrupar o acima em uma função multiplataforma (Linux, Windows, Mac), para que você possa:

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

Aqui está a função:

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
fonte
11

Fácil e Rápido

Importe dois ou mais csvsem precisar fazer uma lista de nomes.

import glob

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

usando um liner map, mas se você quiser especificar argumentos adicionais, poderá:

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 si só não permite que você forneça argumentos adicionais.

muon
fonte
4

Se os vários arquivos csv estiverem compactados, você poderá usar o zipfile para ler todos e concatenar como abaixo:

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
fonte
4

Outro on-line com compreensão de lista que permite usar argumentos com read_csv.

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

Com base na boa resposta de @ Sid.

Antes de concatenar, você pode carregar arquivos csv em um dicionário intermediário que fornece acesso a cada conjunto de dados com base no nome do arquivo (no formulário dict_of_df['filename.csv']). Esse dicionário pode ajudá-lo a identificar problemas com formatos de dados heterogêneos, quando os nomes das colunas não estão alinhados, por exemplo.

Importe módulos e localize caminhos de arquivo:

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

Nota: OrderedDictnão é necessário, mas manterá a ordem dos arquivos que podem ser úteis para análise.

Carregar arquivos CSV em um dicionário. Em seguida, concatene:

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

Chaves são nomes de arquivos fe valores são o conteúdo do quadro de dados dos arquivos csv. Em vez de usar fcomo uma chave de dicionário, você também pode usar os.path.basename(f)ou outros métodos os.path para reduzir o tamanho da chave no dicionário apenas para a parte menor que for relevante.

Paul Rougieux
fonte
3

Alternativa usando a pathlibbiblioteca (geralmente preferida os.path).

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

Da documentação do pandas:
Vale a pena notar que concat () (e, portanto, append ()) faz uma cópia completa dos dados, e que a reutilização constante dessa função pode criar um impacto significativo no desempenho. Se você precisar usar a operação em vários conjuntos de dados, use uma compreensão da lista.

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
fonte
-2

É assim que você pode usar o Colab no 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
fonte
-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
fonte