複数のcsvファイルをパンダにインポートし、1つのDataFrameに連結する


404

ディレクトリからパンダにいくつかのcsvファイルを読み取り、それらを1つの大きなDataFrameに連結したいと思います。私はそれを理解することができませんでした。ここに私がこれまでに持っているものがあります:

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)

forループ内で助けが必要だと思いますか???


dfsリストに追加しないので、コードは何もしません。行data = pd.read_csv(filename)をに置き換えたくないですか?dfs.append(pd.read_csv(filename)あなたは、リスト上でループする必要があるだろうとconcat、私は考えていないconcatのリストに取り組むdf秒。
EdChum 2014年

また、最後の行でモジュールのエイリアスとモジュール名を混在させていますbig_frame = pd.concat(dfs, ignore_index=True)。そうではありませんか?データフレームのリストを取得したら、リストを反復処理して連結する必要がありますbig_frame
EdChum

はい、コードを編集しましたが、csv-filesから連結データフレームを構築することはまだできません。Pythonは初めてなので、さらにヘルプが必要です
jonas

dfs今ループする必要があるので、のようなものが機能するfor df in dfs: big_frame.concat(df, ignore_index=True)はずですが、append代わりに試すこともできますconcat
EdChum

何が機能していないのか、もっと正確に説明できますか?concatデータフレームのリストをあなたがしたようにうまく扱えるはずだからです。これは非常に良いアプローチだと思います。
ジョリス14年

回答:


456

すべてのcsvファイルに同じ列がある場合は、以下のコードを試すことができます。最初の行をheader=0読み取った後csv、列名として割り当てることができるように追加しました。

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)

これは、昔ながらの、いわゆる手動による方法のようです。Hapoodエコシステムには、さまざまなファイルタイプ(csv、json、txt、データベース)を含む多くの異なるディレクトリに対して直接SQLクエリを実行できるツールのリストが増えているため、まるで1つのデータソースであるかのようです。「ビッグデータ」を行うことに20年のジャンプスタートがあったので、Pythonにも同様のものがあるはずです。
Hexatonic 2015

275
同じことはより簡潔で、リストを使用しないのでおそらく高速です。df = pd.concat((pd.read_csv(f) for f in all_files)) また、OSに依存しないようにする ためos.path.join(path, "*.csv")に、の代わりに使用する必要がpath + "/*.csv"あります。
2016年

4
この回答を使用すると、たとえばdf['filename'] = os.path.basename(file_)for file_ループなどで、ファイル名を使用して新しい列を追加できます。SIDの回答でこれが許可されているかどうかわかりませんか?
curtisp 2016年

4
@curtispあなたはまだSidの答えでそれを行うことができますpandas.read_csv(f).assign(filename = foo)、ジェネレーターの中で使うだけです。 assign新しい列を含むデータフレーム全体を返しますfilename
C8H10N4O2 2017

多くのファイルがある場合は、インポートする代わりにジェネレータを使用して、それらをすべて連結する前にリストに追加します。
gustafbstrom

289

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最後の2行は次のように置き換えることができますpd.concat((pd.read_csv(f) for f in all_files), ignore_index=True)。内側のブラケットは、Pandasバージョン0.18.1で必要です
Igor

6
glob.iglob代わりに使用することをお勧めしglob.globます。最初のものは(リストの代わりに)反復子を返します。
toto_tico 2017

54
import glob, os    
df = pd.concat(map(pd.read_csv, glob.glob(os.path.join('', "my_files*.csv"))))

4
優れた1ライナー。read_csv引数が必要ない場合に特に役立ちます。
rafaelvalle

15
一方、引数が必要とされ、これはラムダで行うことができた場合:df = pd.concat(map(lambda file: pd.read_csv(file, delim_whitespace=True), data_files))
fiedl

^またはを使用してfunctools.partial、ラムダを回避
cs95 '27

34

Daskライブラリは、複数のファイルからデータフレームを読み取ることができます。

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

(出典:http : //dask.pydata.org/en/latest/examples/dataframe-csv.html

Daskデータフレームは、PandasデータフレームAPIのサブセットを実装します。すべてのデータがメモリに収まる場合は、を呼び出しdf.compute()てデータフレームをPandasデータフレームに変換できます


30

ここでの回答のほとんどすべてが、不必要に複雑(globパターンマッチング)であるか、追加のサードパーティライブラリに依存しています。これは、Pandasとpython(すべてのバージョン)に組み込まれているすべてを使用して、2行で実行できます。

いくつかのファイルの場合-1ライナー:

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

多くのファイル:

from os import listdir

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

dfを設定するこのパンダ行は、3つのものを利用します。

  1. Pythonのマップ(関数、反復可能)pd.read_csv()は、ファイルパス内のすべてのcsv要素である反復可能(リスト)を関数()に送信し ます。
  2. Pandaのread_csv()関数は、通常どおり各CSVファイルを読み取ります。
  3. Pandaのconcat()は、これらすべてを1つのdf変数にまとめます。

3
または単にdf = pd.concat(map(pd.read_csv, glob.glob('data/*.csv))
ミュオン

@muonで規定されている方法を試しました。しかし、私はヘッダー付きの複数のファイルを持っています(ヘッダーは一般的です)。それらをデータフレームに連結したくありません。どうすればそれを行うことができますか?試しdf = pd.concat(map(pd.read_csv(header=0), glob.glob('data/*.csv))ましたが、「parser_f()に必要な位置引数が1つありません: 'filepath_or_buffer'」というエラーが発生しました
cadip92

14

編集:https ://stackoverflow.com/a/21232849/186078にグーグルで進みました。しかし最近は、numpyを使用してデータフレーム自体を反復的に操作するのではなく、データフレームに1回割り当てることで操作を行う方が速くなり、このソリューションでも機能するようです。

私はこのページにアクセスする人にこのアプローチを検討してほしいと心から思っていますが、この巨大なコードをコメントとして添付して読みにくくしません。

numpyを利用して、データフレームの連結を本当に高速化できます。

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

タイミング統計:

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

「スピードアップ」を裏付ける数字はありますか?具体的には、stackoverflow.com / questions / 20906474 /…よりも高速ですか?
ivan_pozdeev 2016年

OPが彼の連結を高速化する方法を求めているのを見ていません。これは、既存の承認済みの回答を書き直したようなものです。
pydsigner 2016年

2
データに列タイプが混在している場合は機能しません。
Pimin Konstantin Kefaloukos 2017年

1
@SKGパーフェクト..これは私にとって唯一の有効な解決策です。500ファイル、合計2秒間で400k行。投稿いただきありがとうございます。
FrankC

11

再帰的検索したい場合(Python 3.5以降)、以下を実行できます。

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)

最後の3行は1 行で表すことができます。

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

** ここのドキュメントを見つけることができます。また、リストではなくイテレータを返すため、のiglob代わりに使用しました。glob



編集:マルチプラットフォーム再帰関数:

上記をマルチプラットフォーム関数(Linux、Windows、Mac)にラップできるため、次のことができます。

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

これが関数です:

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

簡単かつ高速

csv名前のリストを作成せずに、2つ以上のをインポートします。

import glob

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

8

1つのライナーでを使用mapしていますが、追加の引数を指定する場合は、次のようにします。

import pandas as pd
import glob
import functools

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

注:mapそれ自体では、追加の引数を指定できません。


4

複数のcsvファイルが圧縮されている場合は、zipfileを使用してすべてを読み取り、以下のように連結できます。

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

read_csvで引数を使用できるようにするリスト内包表記を備えた別のオンライン

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

3

@シドの良い答えに基づいています。

連結する前に、csvファイルを中間辞書にロードして、ファイル名(の形式dict_of_df['filename.csv'])に基づいて各データセットにアクセスできます。このようなディクショナリは、たとえば列名が整列していない場合に、異種データ形式の問題を特定するのに役立ちます。

モジュールをインポートし、ファイルパスを見つけます。

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

注:OrderedDict必須ではありませんが、分析に役立つファイルの順序が保持されます。

csvファイルを辞書に読み込みます。次に連結します:

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

キーはファイル名でf、値はcsvファイルのデータフレームコンテンツです。f辞書のキーとして使用する代わりに、os.path.basename(f)または他のos.pathメソッドを使用して、辞書内のキーのサイズを関連する小さな部分のみに減らすこともできます。


3

pathlibライブラリを使用した代替方法(多くの場合、よりも推奨os.path)。

この方法では、pandas concat()/の繰り返し使用を回避できますapped()

pandasのドキュメントから:
concat()(したがってappend())がデータの完全なコピーを作成し、この関数を常に再利用すると、パフォーマンスに大きな影響を与える可能性があることに注意してください。複数のデータセットに対して操作を使用する必要がある場合は、リスト内包表記を使用してください。

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

これは、GoogleドライブでColabを使用する方法です

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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.