PandasのDataFrameに必要なメモリ量を見積もるにはどうすればよいですか?


125

私は不思議に思っています...たとえば、400MBのcsvファイルをpandasデータフレームに(read_csvまたはread_tableを使用して)読み取っている場合、これに必要なメモリ量を推測する方法はありますか?データフレームとメモリのより良い感覚を得ようとしています...


あなたはいつもプロセスを見ることができます&それは単一のファイルのメモリ使用量です。Linuxを実行している場合は、しようとtopしてからShift + M、私のメモリ使用量をソートします。
JayQuerie.com 2013

このオープンパンダの問題を宣伝する必要があると思います。
アンディヘイデン

3
400万行の大きなデータフレームがあります。その空のサブセットx=df.loc[[]]0.1(ゼロ行を抽出するために)計算されるのに数秒かかり、さらに、元のデータフレームと同じように、おそらくその下のコピーのために数百メガバイトのメモリがかかることを発見しました。
osa 2014年

回答:


97

df.memory_usage() 各列の占有量を返します。

>>> df.memory_usage()

Row_ID            20906600
Household_ID      20906600
Vehicle           20906600
Calendar_Year     20906600
Model_Year        20906600
...

インデックスを含めるには、を渡しindex=Trueます。

したがって、全体的なメモリ消費量を取得するには:

>>> df.memory_usage(index=True).sum()
731731000

また、渡すdeep=Trueことで、より正確なメモリ使用量レポートが有効になり、含まれているオブジェクトの完全な使用量が明らかになります。

これは、メモリ使用量には、配列のコンポーネントではない要素deep=False(デフォルトの場合)によって消費されるメモリが含まれないためです。


1
すべての列のメモリ使用量の合計は、実際にメモリ使用量に影響を与えますか?オーバーヘッドが増えることが想像できます。
firelynx 2015年

14
あなたも本当に欲しいdeep=True
smci

df.memory_usage()の合計がsys.getsizeof(df)と等しくない!多くのオーバーヘッドがあります。smciが述べたように、必要なものdeep=True
vagabond

11
参考までmemory_usage()に、(予想どおり)メモリ使用量をバイト単位で返します。
engelen 2017

2
なぜ、deep = Trueの有無でこのような大きな違いがあるのですか?
Nguai al

83

これが異なる方法の比較です- sys.getsizeof(df)最も簡単です。

この例の場合、df814行、11列(2 int、9オブジェクト)のデータフレームです-427kbシェープファイルから読み取ります

sys.getsizeof(df)

>>>インポートシステム
>>> sys.getsizeof(df)
(結果をバイトで与える)
462456

df.memory_usage()

>>> df.memory_usage()
...
(各列を8バイト/行でリストします)

>>> df.memory_usage()。sum()
71712
(おおよそ行*列* 8バイト)

>>> df.memory_usage(deep = True)
(各列の完全なメモリ使用量をリストします)

>>> df.memory_usage(deep = True).sum()
(結果をバイトで与える)
462432

df.info()

データフレーム情報を標準出力に出力します。技術的にはこれらはキロバイトではなくキビバイト(KiB)です-docstringが言うように、「メモリ使用量は人間が読める単位(base-2表現)で表示されます。」したがって、バイトを取得するには1024を掛けます。たとえば、451.6 KiB = 462,438バイトです。

>>> df.info()
...
メモリ使用量:70.0+ KB

>>> df.info(memory_usage = 'deep')
...
メモリ使用量:451.6 KB

g 上記のコードが参照するオブジェクトまたはモジュールは何ですか?
zozo

woops @zozo -固定-タイプミスだった
ブライアン・バーンズ

2
私はを使用df.info(memory_usage="deep")していますが、「392.6 MB」を返しますがsys.getsizeof(df)df.memory_usage(index=True, deep=True).sum()どちらも約「411718016」(〜411MB)を返します。3つの結果が一致しない理由を説明していただけますか?おかげで
Catbuilt

2
@BrianBurns:とdf.memory_usage(deep=True).sum()ほぼ同じ結果を返しますdf.memory_usage(index=True, deep=True).sum()。私の場合、indexメモリはあまり必要ありません。興味深いことに、私はを見つけた411718016/1024/1024 = 392.6ので、 df.info(memory_usage="deep")を使用2^10してバイトMBに変換する場合があり、混乱します。とにかくあなたの助けをありがとう:D。
Catbuiltは2018年

1
@Catbuiltsああ、それはそれを説明しています!df.infoメガバイト(10 ^ 6)ではなく、メビバイト(2 ^ 10)を返します-答えを修正します。
ブライアンバーンズ

43

もう少しデータを議論に持っていきたいと思いました。

この問題について一連のテストを実行しました。

Python resourceパッケージを使用して、プロセスのメモリ使用量を取得しました。

そして、csvをStringIOバッファーに書き込むことで、そのサイズをバイト単位で簡単に測定できました。

私は2つの実験を実行し、それぞれが10,000行と1,000,000行の間でサイズが増加する20データフレームを作成しました。どちらも10列です。

最初の実験では、データセットで浮動小数点のみを使用しました。

これは、csvファイルと比較して、行数の関数としてメモリがどのように増加したかです。(メガバイト単位のサイズ)

floatエントリのある行数の関数としてのメガバイト単位のメモリとCSVサイズ

2番目の実験でも同じアプローチをとりましたが、データセット内のデータは短い文字列のみで構成されていました。

文字列エントリを持つ行数の関数としてのメガバイト単位のメモリおよびCSVサイズ

csvのサイズとデータフレームのサイズの関係はかなり変化するようですが、メモリ内のサイズは常に2〜3倍大きくなります(この実験のフレームサイズの場合)。

私はより多くの実験でこの回答を完成させたいと思います。何か特別なことを試してもらいたい場合はコメントしてください。


あなたのy軸は何ですか?
Ilya V. Schurov

1
メガバイト単位のディスク上のmax_rssおよびcsvサイズ
firelynx 2018

31

これを逆に行う必要があります。

In [4]: DataFrame(randn(1000000,20)).to_csv('test.csv')

In [5]: !ls -ltr test.csv
-rw-rw-r-- 1 users 399508276 Aug  6 16:55 test.csv

技術的にはメモリはこれについてです(インデックスを含みます)

In [16]: df.values.nbytes + df.index.nbytes + df.columns.nbytes
Out[16]: 168000160

したがって、メモリが168MB、ファイルが400MB、100万行、20フロート列

DataFrame(randn(1000000,20)).to_hdf('test.h5','df')

!ls -ltr test.h5
-rw-rw-r-- 1 users 168073944 Aug  6 16:57 test.h5

バイナリHDF5ファイルとして書き込むと、はるかにコンパクト

In [12]: DataFrame(randn(1000000,20)).to_hdf('test.h5','df',complevel=9,complib='blosc')

In [13]: !ls -ltr test.h5
-rw-rw-r-- 1 users 154727012 Aug  6 16:58 test.h5

データはランダムだったので、圧縮はあまり役に立ちません


それはとても賢いです!を使用してファイルを読み取るために必要なメモリを測定する方法はありますread_csvか?
アンディヘイデン

読んだままのASの測定方法はわかりません。IIRCデータを保持するために必要な最終メモリの最大2倍になる可能性があります(ウェスの記事から)、しかし彼はそれを一定の+最終メモリに低下させたと思います
Jeff

ああ、もう一度読む必要があります。2xが特定のアルゴリズムにとって便利な理論上の最小値であることを思い出しました。
アンディヘイデン

iotoplike top/ htopを使用して(リアルタイムで)IOパフォーマンスを監視できます。
Phillip Cloud

1
nbytesたとえば、データフレームに文字列がある場合は、かなり過小評価されます。
osa 2015年

10

dtype配列のsがわかっている場合は、データを保存するために必要なバイト数と、Pythonオブジェクト自体のバイト数を直接計算できます。numpy配列の有用な属性はですnbytes。あなたはパンダにアレイからのバイト数を取得することができますDataFrame実行して

nbytes = sum(block.values.nbytes for block in df.blocks.values())

objectdtype配列はオブジェクトごとに8バイトを格納します(オブジェクトdtype配列はopaqueへのポインターを格納しますPyObject)。したがって、csvに文字列がある場合、read_csvそれらを考慮に入れて、それらをobjectdtype配列に変換し、それに応じて計算を調整する必要があります。

編集:

の詳細については、numpyスカラー型のページをご覧くださいobject dtype。参照のみが保存されるため、配列内のオブジェクトのサイズも考慮する必要があります。そのページが言うように、オブジェクト配列はPython listオブジェクトにいくぶん似ています。


ありがとうフィリップ!ただ明確にするために-文字列の場合、文字列オブジェクトへのポインタと実際の文字列オブジェクトに8バイトが必要ですか?
アン

1
はい、どのオブジェクトタイプでも、8バイトのポインタ+ size(object)が必要です
Viktor Kerkez

1
df.blocks.values()を提案するdf.blocksが口述になっているようです
MRocklin

8

はいあります。パンダは、データをndarraydtypeでグループ化した2次元の複雑な構造に格納します。ndarray基本的には、小さなヘッダーを持つ生のCデータ配列です。したがって、そのサイズにdtype配列の次元を乗算するだけで、そのサイズを見積もることができます。

例:2行np.int32と5 np.float64列の1000行がある場合、DataFrameには2x1000 np.int32アレイが1つと5x1000 アレイが1つnp.float64あります。

4バイト* 2 * 1000 + 8バイト* 5 * 1000 = 48000バイト


@AndyHayden建設費とはどういう意味ですか?のインスタンスのサイズDataFrame
Phillip Cloud

ビクターに感謝!@Andy-建設費がどれほど大きいかについてのアイデアはありますか?
アン

これは含まれていませんpandasread_table、Cythonの非常に効率的な実装があり(numpyのloadtxtよりもはるかに優れています)、データを解析して直接に格納すると想定していndarrayます。
Viktor Kerkez 2013

@PhillipCloudあなたはそれを構築しなければなりません、それはメモリを必要とします...私は言及されているサイズの2倍を覚えているようです...
Andy Hayden

6

これにより、Pythonの任意のオブジェクトがメモリ内のサイズになります。内部はパンダとナンピーに関してチェックする必要があります

>>> import sys
#assuming the dataframe to be df 
>>> sys.getsizeof(df) 
59542497
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.