Impor beberapa file csv ke dalam panda dan gabungkan menjadi satu DataFrame

404

Saya ingin membaca beberapa file csv dari direktori menjadi panda dan menggabungkannya menjadi satu DataFrame besar. Saya belum bisa mengetahuinya. Inilah yang saya miliki sejauh ini:

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)

Saya kira saya butuh bantuan dalam for for loop ???

jonas
sumber
kode Anda tidak melakukan apa-apa karena Anda tidak menambahkan ke dfsdaftar Anda , jangan Anda ingin mengganti baris data = pd.read_csv(filename)dengan dfs.append(pd.read_csv(filename). Anda kemudian perlu untuk mengulang daftar dan concat, saya tidak berpikir concatakan bekerja pada daftar dfs.
EdChum
juga Anda sedang mencampur alias untuk modul dengan nama modul di baris terakhir Anda, bukankah begitu big_frame = pd.concat(dfs, ignore_index=True)?, toh begitu Anda memiliki daftar kerangka data, Anda perlu mengulangi daftar itu dan big_frame
menyambung
Ya, saya mengedit kode, tapi saya masih tidak bisa membangun dataframe gabungan dari file-file csv, saya baru di python jadi saya butuh bantuan lebih lanjut tentang ini
jonas
Anda perlu mengulang dfssekarang, jadi sesuatu seperti for df in dfs: big_frame.concat(df, ignore_index=True)harus bekerja, Anda juga bisa mencoba, appendbukan concatjuga.
EdChum
Bisakah Anda tahu persis apa yang tidak berfungsi? Karena concatseharusnya menangani daftar DataFrames baik-baik saja seperti yang Anda lakukan. Saya pikir ini adalah pendekatan yang sangat bagus.
Joris

Jawaban:

457

Jika Anda memiliki kolom yang sama di semua csvfile Anda maka Anda dapat mencoba kode di bawah ini. Saya telah menambahkan header=0agar setelah membaca csvbaris pertama dapat ditetapkan sebagai nama kolom.

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
sumber
Ini seperti cara manual alias kuno dalam melakukan sesuatu, khususnya. karena ekosistem Hapood memiliki daftar alat yang berkembang di mana Anda dapat melakukan kueri sql langsung pada banyak direktori berbeda yang berisi jenis file berbeda (csv, json, txt, database) seolah-olah itu adalah salah satu sumber data. Pasti ada sesuatu yang mirip dengan python, karena telah memiliki lompatan 20 tahun mulai melakukan "data besar".
Hexatonic
275
Hal yang sama lebih ringkas, dan mungkin lebih cepat karena tidak menggunakan daftar: df = pd.concat((pd.read_csv(f) for f in all_files)) Juga, salah satu mungkin harus menggunakan os.path.join(path, "*.csv")bukan path + "/*.csv", yang membuatnya OS independen.
Sid
4
Menggunakan jawaban ini memungkinkan saya untuk menambahkan kolom baru dengan nama file misalnya dengan df['filename'] = os.path.basename(file_)dalam for file_ loop .. tidak yakin apakah jawaban Sid memungkinkan ini?
curtisp
4
@curtisp Anda masih bisa melakukannya dengan jawaban Sid, cukup gunakan pandas.read_csv(f).assign(filename = foo)di dalam generator. assignakan mengembalikan seluruh kerangka data termasuk kolom barufilename
C8H10N4O2
Jika Anda memiliki banyak file, saya akan menggunakan generator daripada mengimpor + menambahkan ke daftar sebelum menggabungkan semuanya.
gustafbstrom
289

Alternatif jawaban 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
sumber
2
@ Mike @Sid final dua baris dapat diganti dengan: pd.concat((pd.read_csv(f) for f in all_files), ignore_index=True). Kurung bagian dalam diperlukan oleh Pandas versi 0.18.1
Igor Fobia
6
Saya sarankan menggunakan glob.iglobdaripada glob.glob; Yang pertama kembali dan iterator (bukan daftar) .
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
sumber
4
Unggul satu liner, sangat berguna jika tidak diperlukan argumen read_csv!
rafaelvalle
15
Jika, di sisi lain, argumen diperlukan, ini dapat dilakukan dengan lambdas:df = pd.concat(map(lambda file: pd.read_csv(file, delim_whitespace=True), data_files))
fiedl
^ atau dengan functools.partial, untuk menghindari lambdas
cs95
34

Pustaka Dask dapat membaca kerangka data dari banyak file:

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

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

Kerangka data Dask mengimplementasikan subset API kerangka data Pandas. Jika semua data masuk ke dalam memori, Anda dapat menelepondf.compute() untuk mengubah kerangka data menjadi kerangka data Pandas.

Jouni K. Seppänen
sumber
30

Hampir semua jawaban di sini tidak rumit (pencocokan pola glob) atau bergantung pada pustaka pihak ke-3 tambahan. Anda dapat melakukan ini dalam 2 baris menggunakan semua Pandas dan python (semua versi) sudah ada di dalamnya.

Untuk beberapa file - 1 liner:

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

Untuk banyak file:

from os import listdir

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

Baris panda ini yang mengatur df menggunakan 3 hal:

  1. Peta Python (function, iterable) mengirimkan ke function (the pd.read_csv()) the iterable (daftar kami) yang merupakan setiap elemen csv dalam filepaths.
  2. Fungsi read_csv () Panda membaca di setiap file CSV seperti biasa.
  3. Konser Panda () membawa semua ini di bawah satu variabel df.
robmsmt
sumber
3
atau hanyadf = pd.concat(map(pd.read_csv, glob.glob('data/*.csv))
muon
Saya mencoba metode yang ditentukan oleh @muon. Tapi, saya punya banyak file dengan header (header umum). Saya tidak ingin mereka digabungkan dalam kerangka data. Apakah Anda tahu bagaimana saya bisa melakukannya? Saya mencoba df = pd.concat(map(pd.read_csv(header=0), glob.glob('data/*.csv))tetapi memberikan kesalahan "parser_f () tidak ada 1 argumen posisi yang diperlukan: 'filepath_or_buffer'"
cadip92
14

Sunting: Saya googled dengan cara saya ke https://stackoverflow.com/a/21232849/186078 . Namun akhir-akhir ini saya menemukan lebih cepat untuk melakukan manipulasi menggunakan numpy dan kemudian menugaskannya sekali untuk dataframe daripada memanipulasi dataframe itu sendiri secara iteratif dan tampaknya bekerja dalam solusi ini juga.

Saya sungguh-sungguh ingin ada yang memukul halaman ini untuk mempertimbangkan pendekatan ini, tetapi tidak ingin melampirkan sepotong kode besar ini sebagai komentar dan membuatnya kurang mudah dibaca.

Anda dapat memanfaatkan numpy untuk benar-benar mempercepat rangkaian dataframe.

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

Statistik waktu:

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
sumber
Adakah angka untuk mendukung "percepat"? Secara khusus, apakah ini lebih cepat daripada stackoverflow.com/questions/20906474/… ?
ivan_pozdeev
Saya tidak melihat OP meminta cara untuk mempercepat rangkaiannya, ini hanya tampak seperti pengerjaan ulang dari jawaban yang diterima yang sudah ada sebelumnya.
pydsigner
2
Itu tidak akan berfungsi jika data memiliki tipe kolom campuran.
Pimin Konstantin Kefaloukos
1
@ KGK sempurna .. ini adalah satu-satunya solusi yang berfungsi untuk saya. Total 500 file 400k baris dalam 2 detik. Terima kasih telah mempostingnya.
FrankC
11

Jika Anda ingin mencari secara rekursif ( Python 3.5 atau lebih tinggi ), Anda dapat melakukan hal berikut:

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)

Perhatikan bahwa tiga baris terakhir dapat diekspresikan dalam satu baris tunggal :

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

Anda dapat menemukan dokumentasi di ** sini . Juga, saya menggunakan iglobsebagai gantinya glob, karena mengembalikan iterator bukan daftar.



EDIT: Fungsi rekursif multiplatform:

Anda dapat membungkus di atas ke dalam fungsi multi platform (Linux, Windows, Mac), sehingga Anda dapat melakukan:

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

Inilah fungsinya:

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

Mudah dan Cepat

Impor dua atau lebih csvtanpa harus membuat daftar nama.

import glob

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

satu liner menggunakan map, tetapi jika Anda ingin menentukan argumen tambahan, Anda bisa melakukan:

import pandas as pd
import glob
import functools

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

Catatan: mapdengan sendirinya tidak memungkinkan Anda memberikan argumen tambahan.

muon
sumber
4

Jika beberapa file csv di-zip, Anda dapat menggunakan zipfile untuk membaca semua dan menggabungkannya seperti di bawah ini:

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

On-liner lain dengan pemahaman daftar yang memungkinkan untuk menggunakan argumen dengan read_csv.

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

Berdasarkan jawaban yang baik dari @ Sid.

Sebelum digabungkan, Anda dapat memuat file csv ke kamus perantara yang memberikan akses ke setiap kumpulan data berdasarkan nama file (dalam formulir dict_of_df['filename.csv']). Kamus seperti itu dapat membantu Anda mengidentifikasi masalah dengan format data yang heterogen, ketika nama kolom tidak selaras misalnya.

Impor modul dan temukan jalur file:

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

Catatan: OrderedDicttidak perlu, tetapi itu akan menjaga urutan file yang mungkin berguna untuk analisis.

Muat file csv ke dalam kamus. Kemudian gabungkan:

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

Kunci adalah nama file fdan nilai adalah konten bingkai data dari file csv. Alih-alih menggunakan fsebagai kunci kamus, Anda juga dapat menggunakan metode os.pathos.path.basename(f) atau lainnya untuk mengurangi ukuran kunci dalam kamus menjadi hanya bagian yang lebih kecil yang relevan.

Paul Rougieux
sumber
3

Alternatif menggunakan pathlibperpustakaan (sering lebih disukai os.path).

Metode ini menghindari penggunaan berulang panda concat()/ apped().

Dari dokumentasi panda:
Perlu dicatat bahwa concat () (dan karenanya append ()) membuat salinan lengkap dari data, dan bahwa terus-menerus menggunakan kembali fungsi ini dapat membuat kinerja yang signifikan. Jika Anda perlu menggunakan operasi pada beberapa dataset, gunakan pemahaman daftar.

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

Inilah yang dapat Anda lakukan dengan menggunakan Colab di 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
sumber
-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
sumber