Pandalarla analiz için 20GB'lık bir dosya açmak


33

Şu anda makine öğrenmesi amacıyla panda ve python içeren bir dosya açmaya çalışıyorum, hepsinin DataFrame'de olması benim için ideal. Şimdi dosya 18GB büyüklüğünde ve RAM'im 32 GB'dir ancak sürekli bellek hataları alıyorum.

Tecrübelerinden mümkün mü? Eğer bu sorunu çözmenin daha iyi bir yolunu bilmiyorsanız? (kovan tablosu? RAM'imin boyutunu 64'e yükseltir? Bir veritabanı oluşturur ve python'dan erişirsiniz)


Aynı sorunu yaşadım, sabit sürücünüzün takas, disk belleği ve boyutunu artırmanızı öneririm.
Medya

Veri yüklenirken kural pandasolarak, 5-10 kat daha fazla RAM’e sahip olmanız gerekir. inplaceİşlemleri yapmanızı öneririm , garbage.collectornesneleri ayırmak için açıkça çağrı yapın.
Kiritee Gak

4
Son amacınızı belirterek bu soruyu daha iyi yapın. Keşfedici veri analizi, veri temizliği, bir model eğitimi ya da ne yapıyorsunuz? Ne tür veri?
Pete

1
Dask kullanmayı düşündünüz mü?
rpanai

Yanıtlar:


32

Eğer bu bir csv dosyasıysa ve algoritmanızı geliştirirken bir kerede tüm verilere erişmeniz gerekmiyorsa, parçaları toplayabilirsiniz. Bu pandas.read_csvyöntem, bir dosyayı aşağıdaki gibi parçalara okumanıza izin verir:

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

İşte yöntemin belgeleri


Bu zip dosyası için de geçerli midir?
James Wierzba

Sıkıştırılmış dosyayı da bir csv dosyası ise işe
yaramalı

22

İki olasılık vardır: ya tüm verilerinizi işleme almak için bellekte tutmanız gerekir (örneğin, makine öğrenim algoritmanızın hepsini bir kerede tüketmek istersiniz) ya da onsuz da yapabilirsiniz (örneğin, algoritmanız sadece satır örneklerine ihtiyaç duyar veya aynı anda sütunlar).

İlk durumda, bir hafıza problemini çözmeniz gerekecektir . Bellek büyüklüğünüzü artırın, yüksek bellek bir bulut makinesi kiralayın, şirket içi işlemleri kullanın, okuduğunuz veri türü hakkında bilgi verin, kullanılmamış tüm değişkenleri sildiğinizden ve çöp topladığınızdan emin olun.

Pandaların verilerinizi ele alması için 32GB RAM'in yetmemesi çok muhtemel. "1" tamsayısının metin olarak saklandığında sadece bir bayt olduğunu, ancak temsil edildiği zaman 8 bayt olduğunu int64(Pandalar metinden okuduğunda varsayılan olduğunu) unutmayın. Aynı örneği, float64varsayılan olarak 3 baytlık bir dizgeden 8 baytlık bir alana yayılan "1.0" kayan nokta sayısıyla yapabilirsiniz . Panda'ların her sütun için hangi tiplerin kullanılacağını kesin olarak bildirerek ve mümkün olan en küçük gösterimleri zorlayarak biraz yer kazanabilirsiniz, ancak buraya ya da oraya kolayca bir ya da iki tane ekleyebilecek Python'un veri yapısını tepeden konuşmaya bile başlamadık. ve işaretçiler 64 bitlik bir makinede her biri 8 bayttır.

Özetlemek gerekirse: Hayır, Pandaların 20GB'lik bir dosyayı işlemesi için 32GB RAM yeterli değildir.

İkinci durumda (daha gerçekçi ve muhtemelen sizin için geçerli), bir veri yönetimi problemini çözmeniz gerekir . Aslında, işlemek için yalnızca bir kısmına ihtiyaç duyduğunuzda tüm verileri yüklemek zorunda kalmak, kötü veri yönetiminin bir işareti olabilir. Burada birden fazla seçenek var:

  1. Bir SQL veritabanı kullanın. Yapabiliyorsanız, neredeyse her zaman ilk tercih ve terbiyeli bir çözümdür. Çoğu SQL veritabanının (yüksek kaliteli) bir dizüstü bilgisayarda bile dağıtılmaya gerek kalmadan işleyebileceği boyutta 20GB ses geliyor. Sütunları indeksleyebilir, SQL ile basit toplamalar yapabilir ve basit bir kullanarak daha karmaşık işleme için gerekli alt örnekleri Panda'lara alabilirsiniz pd.read_sql. Verileri bir veritabanına taşımak, sütunlarınızın gerçek veri türlerini ve boyutlarını düşünmek için size bir fırsat sağlayacaktır .

  2. Verileriniz çoğunlukla sayısalsa (yani diziler veya tansörler), yalnızca gerekli büyük dizileri diskten kolayca okumanızı sağlayan bir HDF5 biçiminde (bkz. PyTable'lar ) tutmayı düşünebilirsiniz . Temel numpy.save ve numpy.load , dizileri de diskte bellek eşleme yoluyla aynı etkiyi sağlar. CBS ve ilgili raster veriler için pandalara doğrudan SQL kadar bağlanamayan ama aynı zamanda uygun bir şekilde dilimler ve sorgular yapmanıza izin vermesi gereken özel veritabanları vardır .

  3. Pandalar, bildiğim kadarıyla HDF5 veya numpy dizilerinin bu “kısmi” bellek haritalarını desteklemiyor. Hala bir tür "saf pandalar" çözümü istiyorsan, "keskinleştirerek" çalışmayı deneyebilirsin: ya büyük masanın sütunlarını ayrı olarak (örneğin ayrı dosyalar halinde ya da tek bir HDF5'in ayrı "masalarında" saklayarak) dosya) ve sadece talep üzerine gerekli olanları yükleme veya satır parçalarını ayrı ayrı saklama . Ancak, daha sonra gerekli parçaları yükleme mantığını uygulamanız gerekecek, böylece çoğu SQL veritabanında önceden hazırlanmış olan bisikletleri yeniden icat etmeniz gerekecek, belki de seçenek 1 burada daha kolay olacaktı. Verileriniz bir CSV'ye gelirse, chunksizeparametresini belirterek topaklarda işleyebilirsiniz pd.read_csv.


5
"İlk durumda" belirtilmesi gereken bir şey, OP'nin verilerde aynı değere sahip çok sayıda girişi olması durumunda (sıfırlar gibi), verilerin seyrek olduğu söylenir ve dağınık bir seyrek matris kullanılabileceği söylenir. pandalar dataframe - seyrek veri çok daha az hafıza gerektirir.
Ricardo Cruz

9

Birkaç gün önce bu sorunu yaşadım! Çok fazla ayrıntı vermediğinizden bu sizin durumunuza yardımcı olup olmadığından emin değilim, ancak durumum 'büyük' ​​bir veri setinde çevrimdışı çalışmaktı. Veriler, birkaç saniye aralıklarla enerji sayaçlarından, zaman serisi verilerinden 20 GB gzipli CSV dosyaları olarak elde edildi.

IO Dosyası:

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

Doğrudan gzip dosyasının üzerinde bir yığın yineleyici oluşturun (unzip yapmayın!)

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

Topakları iter

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

Öbek döngüsünün içinde, zaman zaman bazı filtreleme ve yeniden örnekleme yapıyorum. Bunu yaparak, daha fazla çevrimdışı veri araştırması için boyutu 20 GB'tan birkaç yüz MB HDF5'e düşürdüm.


5

Deneyimlerime göre, büyük dosyaları okurken read_csv()parametre ile başlatma low_memory=Falseyardımcı olur. Okuduğunuz dosya türünden bahsettiğinizi sanmıyorum, bu yüzden durumunuza bunun ne kadar uygulanabilir olduğundan emin değilim.


1

Dosyanız bir CSV ise, bunu Chunk by Chunk'ta yapabilirsiniz. Sadece basitçe yapabilirsiniz:

import pandas as pd
for chunk in pd.read_csv(FileName, chunksize=ChunkSizeHere)
(Do your processing and training here)
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.