Bagaimana cara memperkirakan berapa banyak memori yang dibutuhkan DataFrame Pandas?

126

Saya bertanya-tanya ... Jika saya membaca, katakanlah, file csv 400MB ke dalam bingkai data panda (menggunakan read_csv atau read_table), adakah cara untuk menebak berapa banyak memori yang dibutuhkan ini? Hanya mencoba untuk merasakan bingkai data dan memori yang lebih baik ...

Anne
sumber
Anda selalu dapat melihat proses & penggunaan memori untuk satu file. Jika Anda menjalankan linux, coba topdan kemudian Shift + Mmemilah penggunaan memori saya.
JayQuerie.com
Saya merasa saya harus mengiklankan masalah panda terbuka ini .
Andy Hayden
3
Saya memiliki kerangka data besar dengan 4 juta baris. Saya menemukan bahwa subset kosongnya x=df.loc[[]]membutuhkan beberapa 0.1detik untuk dihitung (untuk mengekstrak baris nol) dan, lebih jauh lagi, membutuhkan ratusan megabyte memori, sama seperti dataframe asli, mungkin karena beberapa penyalinan di bawahnya.
osa
tautan baru untuk posting lama oleh pengembang utama panda
saladi

Jawaban:

98

df.memory_usage() akan mengembalikan seberapa banyak setiap kolom menempati:

>>> df.memory_usage()

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

Untuk memasukkan indeks, teruskan index=True .

Jadi untuk mendapatkan konsumsi memori secara keseluruhan:

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

Juga, lewat deep=True akan memungkinkan laporan penggunaan memori yang lebih akurat, yang menjelaskan penggunaan penuh objek yang ada.

Ini karena penggunaan memori tidak menyertakan memori yang dikonsumsi oleh elemen yang bukan merupakan komponen dari array if deep=False(kasus default).

Aleksey Sivokon
sumber
1
apakah jumlah penggunaan memori semua kolom benar-benar berdampak pada penggunaan memori? Saya bisa membayangkan ada lebih banyak overhead.
firelynx
14
Anda juga benar-benar ingindeep=True
smci
Jumlah df.memory_usage () tidak sama dengan sys.getsizeof (df)! Ada banyak biaya tambahan. Seperti yang disebutkan smci, Anda perludeep=True
gelandangan
11
FYI, memory_usage()mengembalikan penggunaan memori dalam byte (seperti yang Anda harapkan).
engelen
2
Mengapa ada perbedaan besar antara dengan / tanpa deep = True?
Nguai al
83

Berikut perbandingan metode yang berbeda - sys.getsizeof(df)paling sederhana.

Untuk contoh ini, dfadalah dataframe dengan 814 baris, 11 kolom (2 ints, 9 objek) - baca dari shapefile 427kb

sys.getsizeof (df)

>>> impor sys
>>> sys.getsizeof (df)
(memberikan hasil dalam byte)
462456

df.memory_usage ()

>>> df.memory_usage ()
...
(daftar setiap kolom pada 8 byte / baris)

>>> df.memory_usage (). sum ()
71712
(kira-kira baris * cols * 8 byte)

>>> df.memory_usage (dalam = Benar)
(daftar penggunaan memori penuh setiap kolom)

>>> df.memory_usage (dalam = Benar) .sum ()
(memberikan hasil dalam byte)
462432

df.info ()

Mencetak info bingkai data ke stdout. Secara teknis ini adalah kibibyte (KiB), bukan kilobyte - seperti yang dikatakan oleh docstring, "Penggunaan memori ditampilkan dalam unit yang dapat dibaca manusia (representasi basis-2)." Jadi untuk mendapatkan byte akan dikalikan dengan 1024, misal 451,6 KiB = 462.438 byte.

>>> df.info ()
...
penggunaan memori: 70.0+ KB

>>> df.info (memory_usage = 'deep')
...
penggunaan memori: 451,6 KB
Brian Burns
sumber
Objek atau modul apa yang g dirujuk kode di atas?
zozo
@zozo woops - salah ketik - diperbaiki
Brian Burns
2
Saya menggunakan df.info(memory_usage="deep"), itu mengembalikan "392.6 MB", sedangkan sys.getsizeof(df)dan df.memory_usage(index=True, deep=True).sum()keduanya mengembalikan sekitar "411718016" (~ 411MB). Bisakah Anda menjelaskan mengapa 3 hasil tidak konsisten? terima kasih
Catbuilts
2
@ BrianBurns: df.memory_usage(deep=True).sum()mengembalikan hampir sama dengan df.memory_usage(index=True, deep=True).sum(). dalam kasus saya, indextidak memakan banyak memori. Yang cukup menarik, saya menemukan bahwa 411718016/1024/1024 = 392.6, df.info(memory_usage="deep")mungkin digunakan 2^10untuk mengkonversi byte ke MB , yang membuat saya bingung. Terima kasih atas bantuan Anda: D.
Catbuilts
1
@Catbuilts Ah, sudah jelas! df.infomengembalikan mebibyte (2 ^ 10), bukan megabyte (10 ^ 6) - akan mengubah jawabannya.
Brian Burns
43

Saya pikir saya akan membawa lebih banyak data ke diskusi.

Saya menjalankan serangkaian tes tentang masalah ini.

Dengan menggunakan resourcepaket python saya mendapatkan penggunaan memori dari proses saya.

Dan dengan menulis csv ke dalam StringIObuffer, saya dapat dengan mudah mengukur ukurannya dalam byte.

Saya menjalankan dua eksperimen, masing-masing membuat 20 kerangka data dengan ukuran yang meningkat antara 10.000 baris dan 1.000.000 baris. Keduanya memiliki 10 kolom.

Dalam percobaan pertama saya hanya menggunakan float di dataset saya.

Ini adalah bagaimana memori meningkat dibandingkan dengan file csv sebagai fungsi dari jumlah baris. (Ukuran dalam Megabyte)

Memori dan ukuran CSV dalam Megabyte sebagai fungsi dari jumlah baris dengan entri float

Percobaan kedua saya memiliki pendekatan yang sama, tetapi data dalam dataset hanya terdiri dari string pendek.

Memori dan ukuran CSV dalam Megabyte sebagai fungsi dari jumlah baris dengan entri string

Tampaknya hubungan ukuran csv dan ukuran dataframe bisa sangat bervariasi, namun ukuran di memori akan selalu lebih besar dengan faktor 2-3 (untuk ukuran frame dalam percobaan ini)

Saya ingin melengkapi jawaban ini dengan lebih banyak eksperimen, beri komentar jika Anda ingin saya mencoba sesuatu yang istimewa.

firelynx
sumber
Apa sumbu y Anda?
Ilya V. Schurov
1
max_rss dan ukuran csv pada disk dalam megabyte
firelynx
31

Anda harus melakukan ini secara terbalik.

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

Secara teknis memori adalah tentang ini (yang termasuk indeks)

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

Jadi 168MB dalam memori dengan file 400MB, 1 juta baris dari 20 kolom float

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

JAUH lebih ringkas jika ditulis sebagai file HDF5 biner

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

Datanya acak, jadi kompresi tidak banyak membantu

Jeff
sumber
Itu sangat pintar! Ada ide bagaimana mengukur memori yang Anda butuhkan untuk membaca file menggunakan read_csv?
Andy Hayden
Tidak tahu bagaimana mengukur SAAT Anda membaca; IIRC dapat mencapai 2x memori terakhir yang diperlukan untuk menyimpan data (dari artikel wes), tetapi saya pikir dia membawanya ke memori konstan + terakhir
Jeff
Ah, saya perlu membaca ulang, saya ingat 2x adalah min teoretis yang nyaman untuk algoritme tertentu, jika kurang dari itu coool.
Andy Hayden
Anda dapat menggunakan iotopsuka top/ htopuntuk menonton (dalam waktu nyata) kinerja IO.
Phillip Cloud
1
nbytesakan meremehkan bruto jika Anda memiliki string misalnya dalam dataframe.
osa
10

Jika Anda mengetahui dtypes dari array Anda, maka Anda dapat langsung menghitung jumlah byte yang diperlukan untuk menyimpan data Anda + beberapa untuk objek Python itu sendiri. Atribut numpyarray yang berguna adalah nbytes. Anda bisa mendapatkan jumlah byte dari array di panda DataFramedengan melakukan

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

objectdtype array menyimpan 8 byte per objek (array dtype objek menyimpan pointer ke buram PyObject), jadi jika Anda memiliki string di csv Anda, Anda perlu memperhitungkan yang read_csvakan mengubahnya menjadi objectarray dtype dan menyesuaikan perhitungan Anda.

EDIT:

Lihat numpyhalaman jenis skalar untuk lebih jelasnya di object dtype. Karena hanya referensi yang disimpan, Anda juga perlu mempertimbangkan ukuran objek dalam array. Seperti yang dikatakan halaman itu, array objek agak mirip dengan listobjek Python .

Phillip Cloud
sumber
Terima kasih Phillip! Hanya untuk memperjelas - untuk sebuah string kita membutuhkan 8 byte sebagai pointer ke objek string, ditambah objek string yang sebenarnya?
Anne
1
Ya, untuk semua tipe objek Anda memerlukan pointer 8 byte + ukuran (objek)
Viktor Kerkez
1
Sarankan df.blocks.values ​​() Sepertinya df.blocks sekarang menjadi dict
MRocklin
8

Ya ada. Panda akan menyimpan data Anda dalam ndarraystruktur numpy 2 dimensi yang mengelompokkannya berdasarkan dtypes. ndarraypada dasarnya adalah larik data C mentah dengan header kecil. Jadi Anda bisa memperkirakan ukurannya hanya dengan mengalikan ukuran dtypeisinya dengan dimensi array.

Misalnya: jika Anda memiliki 1000 baris dengan 2 np.int32dan 5 np.float64kolom, DataFrame Anda akan memiliki satu np.int32array 2x1000 dan satu np.float64array 5x1000 yaitu:

4bytes * 2 * 1000 + 8bytes * 5 * 1000 = 48000 bytes

Viktor Kerkez
sumber
@AndyHayden Apa maksud Anda biaya konstruksi? Ukuran instance DataFrame?
Phillip Cloud
Terima kasih Victor! @Andy - Adakah yang tahu seberapa besar biaya konstruksi?
Anne
Ini tidak termasuk, tetapi pandasmemiliki implementasi yang sangat efisien read_tabledi Cython (ini jauh lebih baik daripada numpy loadtxt) jadi saya berasumsi bahwa itu mem-parser dan menyimpan data langsung ke file ndarray.
Viktor Kerkez
@PhillipCloud Anda harus membuatnya, yang membutuhkan memori .. Sepertinya saya ingat dua kali ukuran yang disebutkan? ...
Andy Hayden
6

Ini saya percaya ini memberikan ukuran dalam memori objek apa pun di python. Bagian dalam perlu diperiksa terkait dengan panda dan numpy

>>> import sys
#assuming the dataframe to be df 
>>> sys.getsizeof(df) 
59542497
Zaher Abdul Azeez
sumber