Bir Pandaların DataFrame'inin ne kadar belleğe ihtiyaç duyacağı nasıl tahmin edilir?


126

Merak ediyordum ... Diyelim ki, 400MB csv dosyasını bir pandas veri çerçevesine (read_csv veya read_table kullanarak) okuyorsam, bunun ne kadar belleğe ihtiyaç duyacağını tahmin etmenin bir yolu var mı? Veri çerçevelerini ve belleği daha iyi hissetmeye çalışıyorum ...


Her zaman sürece ve tek bir dosya için bellek kullanımına bakabilirsiniz. Eğer linux çalıştırıyorsanız, denemek topve sonra Shift + Mbenim bellek kullanımını sıralamak.
JayQuerie.com

Bu açık pandalar sorununun reklamını yapmam gerektiğini düşünüyorum .
Andy Hayden

3
4 milyon satırlık büyük bir veri çerçevem ​​var. Boş alt kümesinin hesaplanmasının saniyeler x=df.loc[[]]sürdüğünü 0.1(sıfır satır çıkarmak için) ve dahası, orijinal veri çerçevesi gibi yüzlerce megabayt bellek aldığını keşfettim, muhtemelen altından bazı kopyalamalardan dolayı.
osa

pandaların lider geliştiricisinden eski gönderi için yeni bağlantı
saladi

Yanıtlar:


98

df.memory_usage() her bir sütunun ne kadar kapladığını döndürecektir:

>>> df.memory_usage()

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

Dizinleri dahil etmek için geçin index=True.

Yani genel bellek tüketimini elde etmek için:

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

Ayrıca, geçiş deep=True, içerilen nesnelerin tam kullanımını hesaba katan daha doğru bir bellek kullanım raporu sağlar.

Bunun nedeni, bellek kullanımının dizinin bileşenleri olmayan öğeler tarafından tüketilen belleği içermemesidir deep=False(varsayılan durum).


1
tüm sütunların bellek kullanımlarının toplamı gerçekten bellek kullanımı üzerindeki etkidir? Daha fazla ek yük olacağını hayal edebiliyorum.
firelynx

14
Sen de gerçekten istiyorsundeep=True
smci

Df.memory_usage () toplamı sys.getsizeof (df) 'ye eşit değildir! Birçok genel gider var. SMCI belirtildiği gibi, İhtiyacınızdeep=True
avare

11
Bilginize, memory_usage()bellek kullanımını bayt cinsinden döndürür (beklediğiniz gibi).
engelen

2
Derin olan / olmayan arasında neden bu kadar büyük bir fark = Doğru?
Nguai al

83

İşte farklı yöntemlerin bir karşılaştırması - sys.getsizeof(df)en basitidir.

Bu örnek için, df814 satırlı, 11 sütunlu (2 inç, 9 nesne) bir veri çerçevesidir - 427 kb'lik bir şekil dosyasından okunur

sys.getsizeof (DF)

>>> sys içe aktar
>>> sys.getsizeof (df)
(sonuçları bayt cinsinden verir)
462456

df.memory_usage ()

>>> df.memory_usage ()
...
(her sütunu 8 bayt / satırda listeler)

>>> df.memory_usage (). sum ()
71712
(kabaca satırlar * sütunlar * 8 bayt)

>>> df.memory_usage (derin = Doğru)
(her sütunun tam bellek kullanımını listeler)

>>> df.memory_usage (derin = Doğru) .sum ()
(sonuçları bayt cinsinden verir)
462432

df.info ()

Dataframe bilgilerini standart çıktıya yazdırır. Teknik olarak bunlar kibibayttır (KiB), kilobayt değil - docstring'in dediği gibi, "Bellek kullanımı, insan tarafından okunabilir birimlerle gösterilir (temel-2 gösterimi)." Yani bayt elde etmek 1024 ile çarpılır, örneğin 451,6 KiB = 462,438 bayt.

>>> df.info ()
...
bellek kullanımı: 70.0+ KB

>>> df.info (memory_usage = 'derin')
...
bellek kullanımı: 451.6 KB

g Yukarıdaki kod hangi nesneyi veya modülü ifade ediyor?
zozo

@zozo woops - bir yazım hatasıydı - düzeltildi
Brian Burns

2
Kullandığım df.info(memory_usage="deep")bu "392,6 MB" döndürür, oysa sys.getsizeof(df)ve df.memory_usage(index=True, deep=True).sum()de dönüp yaklaşık "411718016" (~ 411MB). 3 sonucun neden tutarlı olmadığını açıklar mısınız? teşekkürler
Catbuilts

2
@BrianBurns: ile df.memory_usage(deep=True).sum()hemen hemen aynı döndürür df.memory_usage(index=True, deep=True).sum(). benim durumumda indexçok fazla hafıza almıyor. Yeterince ilginç bir şekilde 411718016/1024/1024 = 392.6, baytı MB'ye dönüştürmek için df.info(memory_usage="deep")kullanılabileceğini buldum , bu da kafamı karıştırıyor. Yine de yardımınız için teşekkürler: D. 2^10
Catbuilts

1
@Catbuilts Ah, bu onu açıklıyor! df.infomegabayt (10 ^ 6) değil, mebibayt (2 ^ 10) döndürüyor - yanıtı değiştirecek.
Brian Burns

43

Tartışmaya daha fazla veri getireceğimi düşündüm.

Bu konuda bir dizi test yaptım.

Python resourcepaketini kullanarak sürecimin bellek kullanımını elde ettim.

Ve csv'yi bir StringIOtampona yazarak, bayt cinsinden boyutunu kolayca ölçebildim.

Her biri 10.000 satır ile 1.000.000 satır arasında artan boyutlarda 20 veri çerçevesi oluşturan iki deney yaptım. Her ikisinde de 10 sütun var.

İlk deneyde veri setimde sadece kayan nokta kullandım.

Satır sayısının bir fonksiyonu olarak bellek csv dosyasına kıyasla bu şekilde artmıştır. (Megabayt cinsinden boyut)

Kayan girişli satır sayısının bir fonksiyonu olarak Megabayt cinsinden bellek ve CSV boyutu

İkinci deneyde de aynı yaklaşıma sahiptim, ancak veri kümesindeki veriler yalnızca kısa dizelerden oluşuyordu.

Dize girişli satır sayısının bir fonksiyonu olarak Megabayt cinsinden bellek ve CSV boyutu

Görünüşe göre csv boyutu ile veri çerçevesinin boyutu arasındaki ilişki oldukça değişebilir, ancak bellekteki boyut her zaman 2-3 kat daha büyük olacaktır (bu deneydeki çerçeve boyutları için)

Bu cevabı daha fazla deneyle tamamlamayı çok isterim, özel bir şey denememi istiyorsanız lütfen yorum yapın.


Y ekseniniz nedir?
Ilya V. Schurov

1
megabayt
cinsinden

31

Bunu tersten yapmanız gerekir.

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

Teknik olarak hafıza bununla ilgilidir (indeksleri içerir)

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

Dolayısıyla, 400 MB dosya ile 168 MB bellek, 20 kayan sütunluk 1 milyon satır

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

İkili HDF5 dosyası olarak yazıldığında ÇOK daha kompakt

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

Veriler rastgele olduğundan sıkıştırma çok fazla yardımcı olmuyor


Bu çok zekice! Dosyayı kullanarak okumanız gereken hafızayı nasıl ölçeceğiniz hakkında bir fikriniz var read_csvmı?
Andy Hayden

Okuduğunuz AS'yi nasıl ölçeceğiniz hakkında hiçbir fikriniz yok; IIRC, verileri saklamak için gereken son hafızanın 2 katına kadar olabilir (wes'in makalesinden), ancak sanırım onu ​​sabit + son hafızaya indirdi
Jeff

Ah, yeniden okumam gerekiyor, 2x'in belirli bir algoritma için uygun bir teorik minimum olduğunu hatırladım, eğer daha da azsa.
Andy Hayden

IO performansını (gerçek zamanlı) izlemek için iotopbeğen top/ kullanabilirsiniz htop.
Phillip Bulut

1
nbytesÖrneğin, bir veri çerçevesinde dizeleriniz varsa, büyük bir eksik tahmin olacaktır.
osa

10

Dizinizin s'lerini biliyorsanız, dtypeverilerinizi depolamak için gereken bayt sayısını + Python nesnelerinin kendileri için bir kısmını doğrudan hesaplayabilirsiniz. numpyDizilerin kullanışlı bir özelliği nbytes. Bunu DataFrameyaparak bir pandadaki dizilerden bayt sayısını elde edebilirsiniz.

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

objectdtype dizileri nesne başına 8 bayt depolar (nesne dtype dizileri bir opak için bir işaretçi depolar PyObject), bu nedenle csv'nizde dizeleriniz varsa, bunları dtype dizilerine read_csvdönüştürecek objectve hesaplamalarınızı buna göre ayarlamanız gerekir.

DÜZENLE:

Daha fazla ayrıntı için numpyskaler türleri sayfasına bakın object dtype. Yalnızca bir referans depolandığından, dizideki nesnenin boyutunu da hesaba katmanız gerekir. O sayfanın dediği gibi, nesne dizileri biraz Python listnesnelerine benzer .


Teşekkürler Phillip! Sadece açıklığa kavuşturmak için - bir dizge için, bir dizge nesnesine işaretçi için 8 bayta, artı gerçek dizge nesnesine ihtiyacımız var mı?
Anne

1
Evet, herhangi bir nesne türü için 8 baytlık bir işaretçiye ve boyuta (nesne) ihtiyacınız olacak
Viktor Kerkez

1
Df.blocks.values ​​() önerin df.blocks artık bir karar gibi görünüyor
MRocklin

8

Evet var. Pandalar, verilerinizi ndarraydtiplere göre gruplayarak 2 boyutlu uyuşmuş yapılarda depolar. ndarraytemelde küçük bir başlığa sahip ham bir C veri dizisidir. Böylece, sadece dtypeiçerdiği boyutu dizinin boyutlarıyla çarparak boyutunu tahmin edebilirsiniz .

Örneğin: 2 np.int32ve 5 np.float64sütunlu 1000 satırınız varsa, DataFrame'inizde bir 2x1000 np.int32dizisi ve aşağıdaki gibi bir 5x1000 np.float64dizisi olacaktır:

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


@AndyHayden İnşaat maliyeti ne demek? Bir örneğinin boyutu DataFrame?
Phillip Bulut

Teşekkürler Victor! @Andy - İnşaat maliyetinin ne kadar büyük olduğu hakkında bir fikriniz var mı?
Anne

Dahil değil, ancak Cython'da pandasçok verimli bir uygulaması var ( read_tablenumpy'nin loadtxt'inden çok daha iyi), bu yüzden verileri ayrıştırdığını ve doğrudan ndarray.
Viktor Kerkez

@PhillipCloud inşa etmek zorundasın, bu hafızayı alıyor .. Bahsedilen boyutun iki katı olduğunu hatırlıyorum sanırım? ...
Andy Hayden

6

Bunun python'daki herhangi bir nesnenin bellek içi boyutunu verdiğine inanıyorum. Dahili kişilerin pandalar ve uyuşukluk açısından kontrol edilmesi gerekir

>>> import sys
#assuming the dataframe to be df 
>>> sys.getsizeof(df) 
59542497
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.