Pandalarda büyük, kalıcı DataFrame


93

Uzun süreli bir SAS kullanıcısı olarak python ve pandalara geçmeyi araştırıyorum.

Bununla birlikte, bugün bazı testler çalıştırırken, pandas.read_csv()128mb csv dosyasına çalışırken python'un belleğinin bitmesine şaşırdım . Yaklaşık 200.000 satırı ve çoğunlukla sayısal verilerden oluşan 200 sütunu vardı.

SAS ile bir csv dosyasını bir SAS veri kümesine aktarabilirim ve sabit sürücüm kadar büyük olabilir.

İçinde benzer bir şey var mı pandas?

Düzenli olarak büyük dosyalarla çalışıyorum ve dağıtılmış bir bilgi işlem ağına erişimim yok.


Pandalara aşina değilim, ancak dosya boyunca yineleyerek bakmak isteyebilirsiniz. pandas.pydata.org/pandas-docs/stable/…
monkut

Yanıtlar:


80

Prensipte bellek tükenmemelidir, ancak şu anda read_csvbazı karmaşık Python dahili sorunlarının neden olduğu büyük dosyalarda bellek sorunları vardır (bu belirsizdir, ancak uzun zamandır bilinmektedir: http://github.com/pydata / pandas / sorunlar / 407 ).

Şu anda mükemmel bir çözüm yok (işte sıkıcı bir çözüm: dosyayı satır satır önceden ayrılmış bir NumPy dizisine veya bellek eşlemeli dosyaya yazabilirsiniz-- np.mmap), ama bu benim çalışacağım yakın gelecekte. Diğer bir çözüm, dosyayı daha küçük parçalar halinde okumak (kullanmak iterator=True, chunksize=1000) ve ardından ile bitiştirmektir pd.concat. Sorun, tüm metin dosyasını belleğe büyük bir höpürtüyle çektiğinizde ortaya çıkar.


1
Diyelim ki dosyayı okuyabilir ve hepsini bir DataFrame'de birleştirebilirim. DataFrame bellekte yer almak zorunda mı? SAS ile, sabit sürücü alanım olduğu sürece her boyuttaki veri kümesiyle çalışabilirim. DataFrames ile aynı mı? Sabit disk alanıyla değil RAM tarafından kısıtlandıkları izlenimini edindim. Çaylak sorusu için özür dilerim ve yardımın için teşekkürler. Kitabını beğendim.
Zelazny7

3
Doğru, RAM tarafından kısıtlandın. SAS, gerçekten de "çekirdek dışı" büyük veri işleme için çok daha iyi desteğe sahiptir.
Wes McKinney

5
@WesMcKinney 0.10'a indiğiniz yeni csv yükleyici nedeniyle artık bu geçici çözümlere ihtiyaç duyulmayacak, değil mi?
Gabriel Grant

81

Wes elbette haklı! Sadece biraz daha eksiksiz bir örnek kod sağlamak için uğraşıyorum. 129 Mb dosyasında da aynı sorunu yaşadım, bu sorunu çözdü:

import pandas as pd

tp = pd.read_csv('large_dataset.csv', iterator=True, chunksize=1000)  # gives TextFileReader, which is iterable with chunks of 1000 rows.
df = pd.concat(tp, ignore_index=True)  # df is DataFrame. If errors, do `list(tp)` instead of `tp`

6
Sanırım sadece yapabilir df = concate(tp, ignore_index=True)misin?
Andy Hayden

@smci Bunu, x4 (550 Mb) veya x8 (1.1Gb) yinelenen aynı verilerle çabucak denedi. İlginç bir şekilde, [tp'de x için x] olsun ya da olmasın, x4 sorunsuz geçti ve x8 bir Bellek Hatasında çöktü.
2013

3
Bunu kullanırken bu hatayı alıyorum: AssertionError: first argument must be a list-like of pandas objects, you passed an object of type "TextFileReader". Burada ne olduğu hakkında bir fikriniz var mı?
Prince Kumar

3
Bu hata 0.14'te (yakında yayınlanacak), github.com/pydata/pandas/pull/6941 ; <0.14.0 için geçici çözüm yapılacakpd.concat(list(tp), ignore_index=True)
Jeff

1
ya değerler dizeler veya kategorikse - hatayı alıyorum: kategorik sonuçlarda uyumsuz kategoriler
As3adTintin

41

Bu daha eski bir iş parçacığı, ancak geçici çözümümü buraya atmak istedim. Başlangıçta chunksizeparametreyi denedim (10000 gibi oldukça küçük değerlerle bile), ancak pek yardımcı olmadı; bellek boyutuyla ilgili hala teknik sorunlar yaşıyordu (CSV'm ~ 7,5 Gb idi).

Şu anda, CSV dosyalarının parçalarını döngüsel bir yaklaşımla okudum ve bunları örneğin adım adım bir SQLite veritabanına ekliyorum:

import pandas as pd
import sqlite3
from pandas.io import sql
import subprocess

# In and output file paths
in_csv = '../data/my_large.csv'
out_sqlite = '../data/my.sqlite'

table_name = 'my_table' # name for the SQLite database table
chunksize = 100000 # number of lines to process at each iteration

# columns that should be read from the CSV file
columns = ['molecule_id','charge','db','drugsnow','hba','hbd','loc','nrb','smiles']

# Get number of lines in the CSV file
nlines = subprocess.check_output('wc -l %s' % in_csv, shell=True)
nlines = int(nlines.split()[0]) 

# connect to database
cnx = sqlite3.connect(out_sqlite)

# Iteratively read CSV and dump lines into the SQLite table
for i in range(0, nlines, chunksize):

    df = pd.read_csv(in_csv,  
            header=None,  # no header, define column header manually later
            nrows=chunksize, # number of rows to read at each iteration
            skiprows=i)   # skip rows that were already read

    # columns to read        
    df.columns = columns

    sql.to_sql(df, 
                name=table_name, 
                con=cnx, 
                index=False, # don't use CSV file index
                index_label='molecule_id', # use a unique column from DataFrame as index
                if_exists='append') 
cnx.close()    

4
Parçalanmış okuma özelliği için gerçekçi bir kullanım durumu görmek için süper kullanışlı. Teşekkürler.
Alex Kestner

5
Bu eski konuya küçük bir not: ve pandas.read_csvsağlarsanız, doğrudan (en azından şu anda kullandığım sürümde) bir yineleyici döndürür . Bu nedenle, her seferinde yeniden örneklemek yerine çağrı üzerinde bir döngü yaparsınız . Ancak, bu yalnızca arama ek yüküne mal olur, belki de önemli bir etkisi yoktur. iterator=Truechunksize=chunksizeforpd.read_csv
Joël

1
Merhaba Joel. Not için teşekkürler! iterator=TrueVe chunksizeyanlış hatırlamıyorsam parametreler zaten geri mevcuttu. Belki eski bir sürümde bellek patlamasına neden olan bir hata vardı - Pandalar'da büyük bir DataFrame okuduğumda bir dahaki sefere tekrar deneyeceğim (bu tür görevler için çoğunlukla Blaze kullanıyorum)

6

Aşağıda çalışma akışım var.

import sqlalchemy as sa
import pandas as pd
import psycopg2

count = 0
con = sa.create_engine('postgresql://postgres:pwd@localhost:00001/r')
#con = sa.create_engine('sqlite:///XXXXX.db') SQLite
chunks = pd.read_csv('..file', chunksize=10000, encoding="ISO-8859-1",
                     sep=',', error_bad_lines=False, index_col=False, dtype='unicode')

Dosya boyutunuzu temel alarak, yığın boyutunu daha iyi optimize etmelisiniz.

 for chunk in chunks:
        chunk.to_sql(name='Table', if_exists='append', con=con)
        count += 1
        print(count)

Veritabanındaki tüm verileri aldıktan sonra, ihtiyacınız olanları veritabanından sorgulayabilirsiniz.


3

Büyük csv dosyalarını yüklemek istiyorsanız, dask iyi bir seçenek olabilir. Pandalar API'sini taklit ettiği için pandalara oldukça benziyor

github'da dask bağlantısı


Teşekkürler, bunu yayınladığımdan beri dask ve parke formatını kullanıyorum.
Zelazny7

1

Pandas df yerine Pytable'ı kullanabilirsiniz. Büyük veri kümeleri için tasarlanmıştır ve dosya biçimi hdf5 biçimindedir. Dolayısıyla işlem süresi nispeten hızlıdır.

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.