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


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)

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

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

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


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.

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

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)

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

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.


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

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

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.


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)

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

-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)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.