Otwieranie pliku 20 GB do analizy za pomocą pand


33

Obecnie próbuję otworzyć plik z pandami i pytonem do celów uczenia maszynowego, idealnie byłoby dla mnie mieć je wszystkie w ramce danych. Teraz plik ma 18 GB, a moja pamięć RAM to 32 GB, ale wciąż pojawiają się błędy pamięci.

Czy z twojego doświadczenia jest to możliwe? Jeśli nie, czy znasz lepszy sposób na obejście tego? (Tabela gałęzi? Zwiększ rozmiar mojej pamięci RAM do 64? Utwórz bazę danych i uzyskaj do niej dostęp z Pythona)


Mam ten sam problem, sugeruję zwiększenie wymiany, stronicowania, rozmiaru dysku twardego.
Media

Przy ładowaniu danych obowiązuje zasada pandas, że musisz mieć 5-10 razy więcej pamięci RAM. Polecam wykonywanie inplaceoperacji, jawne wywołanie w garbage.collectorcelu cofnięcia alokacji obiektów.
Kiritee Gak

4
Ulepsz to pytanie, podając swój cel końcowy. Czy przeprowadzasz eksploracyjną analizę danych, czyścisz dane, trenujesz model lub co? Jakie dane?
Pete

1
Czy zastanawiałeś się nad użyciem dask ?
rpanai

Odpowiedzi:


32

Jeśli jest to plik csv i nie musisz uzyskiwać dostępu do wszystkich danych jednocześnie podczas szkolenia algorytmu, możesz odczytać go we fragmentach. Ta pandas.read_csvmetoda umożliwia odczytanie pliku w takich fragmentach:

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

Oto dokumentacja metody


czy dotyczy to również pliku zip?
James Wierzba

Powinno to działać, jeśli spakowany plik jest również plikiem csv, należy przekazać metodę kompresji jako argument do metody
Olel Daniel

22

Istnieją dwie możliwości: albo musisz mieć wszystkie dane w pamięci do przetwarzania (np. Algorytm uczenia maszynowego będzie chciał zużyć wszystkie z nich naraz), albo możesz się bez niego obejść (np. Twój algorytm potrzebuje tylko próbek wierszy lub kolumny jednocześnie).

W pierwszym przypadku musisz rozwiązać problem z pamięcią . Zwiększ rozmiar pamięci, wynajmij maszynę chmurową o wysokiej pamięci, używaj operacji wewnętrznych, dostarczaj informacji o typie danych, które czytasz, pamiętaj o usunięciu wszystkich nieużywanych zmiennych i zbieraniu śmieci itp

Jest bardzo prawdopodobne, że 32 GB pamięci RAM nie wystarczy, aby Pandas mógł obsłużyć twoje dane. Zauważ, że liczba całkowita „1” jest tylko jednym bajtem, gdy jest zapisana jako tekst, ale 8 bajtów, gdy jest reprezentowana jako int64(co jest wartością domyślną, gdy Pandas odczytuje ją z tekstu). Możesz zrobić ten sam przykład z liczbą zmiennoprzecinkową „1.0”, która float64domyślnie rozszerza się z ciągu 3-bajtowego na 8-bajtowy . Możesz zyskać trochę miejsca, informując Pandy dokładnie, jakich typów użyć dla każdej kolumny i wymuszając najmniejsze możliwe reprezentacje, ale nie zaczęliśmy nawet mówić o strukturze danych Pythona tutaj, co może dodać dodatkowy wskaźnik lub dwa tutaj lub tam łatwo , a wskaźniki mają po 8 bajtów na komputerze 64-bitowym.

Podsumowując: nie, 32 GB pamięci RAM prawdopodobnie nie wystarcza, aby Pandas mógł obsłużyć plik 20 GB.

W drugim przypadku (który jest bardziej realistyczny i prawdopodobnie dotyczy Ciebie) musisz rozwiązać problem z zarządzaniem danymi . Rzeczywiście, konieczność załadowania wszystkich danych, gdy naprawdę potrzebujesz tylko ich części do przetwarzania, może być oznaką złego zarządzania danymi. Tutaj jest wiele opcji:

  1. Użyj bazy danych SQL. Jeśli możesz, to prawie zawsze jest to pierwszy wybór i całkiem wygodne rozwiązanie. 20 GB wydaje się wielkością, z którą większość baz danych SQL poradziłaby sobie dobrze bez potrzeby dystrybucji nawet na (wyższej klasy) laptopie. Będziesz mógł indeksować kolumny, wykonywać podstawowe agregacje za pomocą SQL i pobierać potrzebne podpróbki do Pand w celu bardziej skomplikowanego przetwarzania za pomocą prostego pd.read_sql. Przeniesienie danych do bazy danych da również możliwość zastanowienia się nad faktycznymi typami danych i rozmiarami kolumn.

  2. Jeśli twoje dane są głównie numeryczne (tj. Tablice lub tensory), możesz rozważyć trzymanie ich w formacie HDF5 (patrz PyTables ), który pozwala wygodnie odczytywać tylko niezbędne fragmenty wielkich tablic z dysku. Podstawowe numpy.save i numpy.load osiągają ten sam efekt również poprzez mapowanie pamięci tablic na dysku. Dla GIS i powiązanych danych rastrowych istnieją dedykowane bazy danych , które mogą nie łączyć się z pandami tak bezpośrednio jak SQL, ale powinny również umożliwiać wygodne wykonywanie wycinków i zapytań.

  3. O ile mi wiadomo, Pandy nie obsługują takiego „częściowego” mapowania pamięci HDF5 lub tablic numpy. Jeśli nadal chcesz mieć rozwiązanie typu „czysta panda”, możesz spróbować obejść ten problem poprzez „dzielenie”: albo przechowując kolumny dużego stołu osobno (np. W osobnych plikach lub w osobnych „tabelach” pojedynczego HDF5 plik) i ładowanie tylko niezbędnych na żądanie lub osobne przechowywanie fragmentów wierszy . Będziesz jednak musiał zaimplementować logikę ładowania niezbędnych fragmentów, a tym samym wynaleźć na nowo rowery już wdrożone w większości baz danych SQL, więc być może opcja 1 byłaby jeszcze łatwiejsza. Jeśli jednak dane są dostarczane w pliku CSV, można je przetwarzać na części, określając chunksizeparametr na pd.read_csv.


5
W „pierwszym przypadku” należy wspomnieć o tym, że jeśli OP ma wiele danych o tej samej wartości w danych (takich jak zera), dane są traktowane jako rzadkie i można użyć raczej rzadkiej macierzy niż ramka danych pandy - rzadkie dane wymagają znacznie mniej pamięci.
Ricardo Cruz

9

Właśnie miałem ten problem kilka dni temu! Nie jestem pewien, czy to pomaga w konkretnym przypadku, ponieważ nie podajesz tak wielu szczegółów, ale moja sytuacja polegała na pracy w trybie offline na „dużym” zestawie danych. Dane uzyskano jako pliki CSV w formacie 20z gzip z liczników energii, dane szeregów czasowych w odstępach kilku sekund.

Plik IO:

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

Utwórz iterator porcji bezpośrednio nad plikiem gzip (nie rozpakowuj!)

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

Iteruj po kawałkach

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

Wewnątrz pętli porcji filtruję i próbkuję na czas. W ten sposób zmniejszyłem rozmiar z 20 GB do kilkuset MB HDF5 do dalszej eksploracji danych offline.


5

Z mojego doświadczenia wynika, że ​​inicjowanie za read_csv()pomocą parametru low_memory=Falsezwykle pomaga podczas czytania dużych plików. Nie sądzę, żebyś wspomniał o typie pliku, który czytasz, więc nie jestem pewien, czy ma to zastosowanie do twojej sytuacji.


1

Jeśli Twój plik to CSV, możesz po prostu zrobić to w Chunk by Chunk. Możesz po prostu zrobić:

import pandas as pd
for chunk in pd.read_csv(FileName, chunksize=ChunkSizeHere)
(Do your processing and training here)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.