パンダで分析するために20GBファイルを開く


33

現在、機械学習の目的でパンダとpythonを使用してファイルを開こうとしていますが、それらをすべてDataFrameに入れることが理想的です。現在、ファイルのサイズは18 GBで、RAMは32 GBですが、メモリエラーが発生し続けます。

あなたの経験からそれは可能ですか?そうでない場合、これを回避するより良い方法を知っていますか?(ハイブテーブル?RAMのサイズを64に増やしますか?データベースを作成し、Pythonからアクセスします)


同じ問題が発生しました。ハードドライブのスワップ、ページング、サイズを増やすことをお勧めします。
メディア

データを読み込む際の経験則でpandasは、5〜10倍のRAMが必要です。オブジェクトの割り当て解除をinplace明示的に呼び出す操作を行うことをお勧めしgarbage.collectorます。
Kiriteeガク

4
最終的な目標を明記して、この質問を改善します。探索的データ分析、データクリーニング、モデルのトレーニングなどを行っていますか?どのようなデータですか?
ピート

1
daskの使用を検討しましたか?
rpanai

回答:


32

csvファイルであり、アルゴリズムのトレーニング時に一度にすべてのデータにアクセスする必要がない場合は、チャンクで読み取ることができます。このpandas.read_csvメソッドを使用すると、次のようなチャンクでファイルを読み取ることができます。

import pandas as pd
for chunk in pd.read_csv(<filepath>, chunksize=<your_chunksize_here>)
    do_processing()
    train_algorithm()

ここにメソッドのドキュメントがあります


これはzipファイルにも適用されますか?
ジェームスヴィエルズバ

zipファイルもcsvファイルでも機能するはずです。圧縮タイプを引数としてメソッドに渡す必要があります
Olel Daniel

22

2つの可能性があります:処理のためにすべてのデータをメモリに保存する必要がある(たとえば、機械学習アルゴリズムが一度にすべてを消費する)か、それなしで実行できる(たとえば、アルゴリズムは行のサンプルのみを必要とする、または列を一度に)。

最初のケースでは、メモリの問題解決する必要があります。メモリサイズを増やし、ハイメモリクラウドマシンをレンタルし、インプレース操作を使用し、読み込んでいるデータのタイプに関する情報を提供し、使用されていない変数をすべて削除してゴミを収集するようにしてください。

パンダがデータを処理するには32 GBのRAMでは不十分である可能性が非常に高いです。整数「1」は、テキストとして保存される場合は1バイトであり、として表現される場合は8バイトint64です(Pandasがテキストからそれを読み込む場合のデフォルトです)。float64デフォルトで3バイト文字列から8バイトに展開する浮動小数点数「1.0」で同じ例を作成できます。Pandasに各列に使用する型を正確に知らせて、可能な限り最小の表現を強制することである程度のスペースを獲得できますが、ここでPythonのデータ構造のオーバーヘッドについては話しませんでした。 、およびポインターは64ビットマシンではそれぞれ8バイトです。

要約すると、いいえ、パンダが20GBのファイルを処理するには32GBのRAMではおそらく十分ではありません。

2番目のケース(より現実的で、おそらくあなたに当てはまる場合)では、データ管理の問題を解決する必要があります。実際、処理のためにデータの一部だけが本当に必要なときにすべてのデータをロードしなければならないことは、データ管理が悪い兆候かもしれません。ここには複数のオプションがあります。

  1. SQLデータベースを使用します。可能であれば、それはほとんど常に最初の選択肢であり、まともなソリューションです。20GBは、ほとんどのSQLデータベースが(ハイエンドの)ラップトップでも分散する必要なく十分に処理できるサイズのようです。列をインデックス化し、SQLを介して基本的な集計を行い、シンプルなを使用してより複雑な処理を行うために必要なサブサンプルをPandasに取得できますpd.read_sql。データをデータベースに移動すると、実際のデータ型と列のサイズについて考える機会も得られます。

  2. データのほとんどが数値(配列またはテンソル)である場合、HDF5形式(PyTablesを参照)で保持することを検討できます。これにより、ディスクから巨大な配列の必要なスライスのみを簡単に読み取ることができます。基本的なnumpy.saveとnumpy.loadは、ディスク上のアレイをメモリマッピングすることでも同じ効果を達成します。GISおよび関連するラスターデータの場合、専用の データベースがあり、SQLほど直接パンダに接続できない場合がありますが、スライスやクエリを合理的に便利に実行できるはずです。

  3. 私の知る限り、PandasはHDF5またはnumpy配列のこのような「部分的な」メモリマッピングをサポートしていません。それでも「純粋なパンダ」ソリューションのようなものが必要な場合は、「シャーディング」で回避しようとすることができます:巨大なテーブルのを別々に保存します(たとえば、単一のHDF5の別々のファイルまたはファイル)、必要なもののみをオンデマンドでロードするか、行チャンクを個別に保存します。ただし、必要なチャンクをロードするためのロジックを実装する必要があるため、ほとんどのSQLデータベースに既に組み込まれている自転車を再発明する必要があるため、ここではオプション1の方が簡単です。ただし、データがCSVの場合、chunksizeパラメーターをに指定することで、データをまとめて処理できますpd.read_csv


5
「最初のケース」で言及すべきことは、OPにデータ内に同じ値(ゼロなど)のエントリが多数ある場合、データはスパースであると言われ、scipyスパースマトリックスを使用できることです。パンダデータフレーム-スパースデータに必要なメモリがはるかに少なくなります。
リカルドクルス

9

数日前にこの問題が発生しました!多くの詳細を提供していないため、これが特定のケースで役立つかどうかはわかりませんが、私の状況は「大きな」データセットでオフラインで作業することでした。データは、エネルギーメーターから20GBのgzip圧縮CSVファイルとして取得され、数秒間隔で時系列データが取得されました。

ファイルIO:

data_root = r"/media/usr/USB STICK"
fname = r"meters001-050-timestamps.csv.gz"
this_file = os.path.join(data_root,fname)
assert os.path.exists(this_file), this_file
this_file

gzipファイル上にチャンクイテレータを直接作成します(解凍しないでください!)

cols_to_keep = [0,1,2,3,7]
column_names = ['METERID','TSTAMP','ENERGY','POWER_ALL','ENERGY_OUT',]
parse_dates = ['TSTAMP']
dtype={'METERID': np.int32, 
       'ENERGY': np.int32,
       'POWER_ALL': np.int32,
       'ENERGY_OUT': np.int32,
      }
df_iterator = pd.read_csv(this_file, 
                        skiprows=0, 
                        compression='gzip',
                        chunksize=1000000, 
                        usecols=cols_to_keep,
                        delimiter=";",
                        header=None,
                        names = column_names,
                      dtype=dtype,
                     parse_dates=parse_dates,
                     index_col=1,
                     )

チャンクを反復処理する

new_df = pd.DataFrame()
count = 0
for df in df_iterator:
    chunk_df_15min = df.resample('15T').first()
    #chunk_df_30min = df.resample('30T').first()
    #chunk_df_hourly = df.resample('H').first()
    this_df = chunk_df_15min
    this_df = this_df.pipe(lambda x: x[x.METERID == 1])
    #print("chunk",i)
    new_df = pd.concat([new_df,chunk_df_15min])
    print("chunk",count, len(chunk_df_15min), 'rows added')
    #print("chunk",i, len(temp_df),'rows added')
    #break
    count += 1

チャンクループ内では、時間通りにフィルタリングとリサンプリングを行っています。これを行うことで、オフラインデータをさらに調査するために、サイズを20GBから数百MBのHDF5に削減しました。


5

私の経験では、read_csv()パラメータを使用して初期化するとlow_memory=False、大きなファイルを読み込むときに役立ちます。あなたが読んでいるファイルの種類について言及したとは思わないので、これがあなたの状況にどのように当てはまるかわかりません。


1

ファイルがCSVの場合は、Chunk by Chunkで簡単に実行できます。あなたはただ単にすることができます:

import pandas as pd
for chunk in pd.read_csv(FileName, chunksize=ChunkSizeHere)
(Do your processing and training here)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.