Bardzo duże macierze używające Pythona i NumPy

86

NumPy to niezwykle przydatna biblioteka, a korzystając z niej stwierdziłem, że z łatwością radzi sobie z dość dużymi macierzami (10000 x 10000), ale zaczyna borykać się z czymkolwiek znacznie większym (próbując stworzyć macierz o wymiarach 50000 x 50000 zawodzi). Oczywiście wynika to z ogromnych wymagań dotyczących pamięci.

Czy istnieje sposób na natywne tworzenie ogromnych macierzy w NumPy (powiedzmy 1 milion na 1 milion) w jakiś sposób (bez posiadania kilku terabajtów pamięci RAM)?

Piotr
źródło

Odpowiedzi:

91

PyTables i NumPy to droga do zrobienia.

PyTables będzie przechowywać dane na dysku w formacie HDF, z opcjonalną kompresją. Moje zbiory danych często podlegają kompresji 10x, co jest przydatne w przypadku dziesiątek lub setek milionów wierszy. Jest również bardzo szybki; mój 5-letni laptop może przetwarzać dane, wykonując agregację GROUP BY, podobną do SQL, z prędkością 1 000 000 wierszy na sekundę. Nieźle jak na rozwiązanie oparte na Pythonie!

Dostęp do danych jako ponowne zapisywanie NumPy jest tak prosty, jak:

data = table[row_from:row_to]

Biblioteka HDF dba o wczytywanie odpowiednich fragmentów danych i konwersję do NumPy.

Stephen Simmons
źródło
4
Więc nadal musisz samodzielnie podzielić dane na kawałki do przetworzenia? To tylko sposób na uproszczenie konwersji do iz plików dyskowych?
endolith
Jest jakaś szansa, że ​​mógłbyś rozszerzyć swoją odpowiedź o nieco większą jasność i kilka przykładów?
Adam B
56

numpy.arraymają żyć w pamięci. Jeśli chcesz pracować z matrycami większymi niż twoja pamięć RAM, musisz to obejść. Istnieją co najmniej dwa podejścia, które możesz zastosować:

  1. Wypróbuj bardziej wydajną reprezentację macierzy, która wykorzystuje każdą specjalną strukturę, którą mają twoje macierze. Na przykład, jak inni już zauważyli, istnieją wydajne struktury danych dla rzadkich macierzy (macierzy z dużą ilością zer), takich jak scipy.sparse.csc_matrix.
  2. Zmodyfikuj swój algorytm, aby działał na podmacierzy . Z dysku można odczytać tylko bloki macierzy, które są aktualnie używane w obliczeniach. Algorytmy zaprojektowane do działania w klastrach zwykle działają blokowo, ponieważ dane są rozproszone na różnych komputerach i przekazywane tylko wtedy, gdy są potrzebne. Na przykład algorytm Foxa do mnożenia macierzy (plik PDF) .
Roberto Bonvallet
źródło
4
3- Wejdź do paradygmatu Big Data i przestudiuj rozwiązania, takie jak MapReduce
Medeiros
W przypadku numeru 2, jak zdecydujesz, jak duże będą twoje kawałki? Czy na tej podstawie można zmierzyć ilość wolnej pamięci i zmierzyć rozmiar fragmentów?
endolith
30

Powinieneś być w stanie użyć numpy.memmap do mapowania pamięci pliku na dysku. W nowszym Pythonie i 64-bitowej maszynie powinieneś mieć niezbędną przestrzeń adresową, bez ładowania wszystkiego do pamięci. System operacyjny powinien obsługiwać tylko przechowywanie części pliku w pamięci.

DopplerShift
źródło
19
Czy możesz podać przykład, jak go użyć do zrobienia czegoś, co nie mieści się w pamięci?
endolith
24

Aby obsłużyć rzadkie macierze, potrzebujesz scipypakietu, który znajduje się na górze numpy- zobacz tutaj, aby uzyskać więcej informacji na temat opcji macierzy rzadkich, które scipydają ci.

Alex Martelli
źródło
11

Post Stefano Boriniego skłonił mnie do przyjrzenia się, jak daleko są już tego typu rzeczy.

To jest to. Wydaje się, że zasadniczo robi to, co chcesz. HDF5 pozwoli ci przechowywać bardzo duże zbiory danych, a następnie uzyskiwać do nich dostęp i używać ich w taki sam sposób, jak robi to NumPy.

SingleNegationElimination
źródło
9
Lepszym wyborem mogą być PyTables. Jest wyższy niż podstawowa funkcjonalność HDF5 (H5Py to niewiele więcej niż niskopoziomowy interfejs API dostępny z Pythona). Również wersja beta 2.2 z zeszłego tygodnia ma narzędzia do rozwiązania tego problemu: pytables.org/moin/ReleaseNotes/Release_2.2b1 Dodano wyrażenie , klasa [która] może oceniać wyrażenia (takie jak „3 * a + 4 * b”) działające na dowolnie dużych tablice przy optymalizacji zasobów [...]. Jest podobny do pakietu Numexpr, ale oprócz obiektów NumPy akceptuje również jednorodne tablice dyskowe, takie jak obiekty Array, CArray, EArray i Column PyTables.
AFoglia
5

Upewnij się, że używasz 64-bitowego systemu operacyjnego i 64-bitowej wersji języka Python / NumPy. Należy zauważyć, że na architekturach 32-bitowych można zwykle zaadresować 3 GB pamięci (z około 1 GB utraconym na potrzeby operacji we / wy mapowanych w pamięci i tym podobnych).

Dzięki 64-bitowym tablicom i tablicom rzeczy większym niż dostępna pamięć RAM możesz uciec z pamięcią wirtualną, chociaż sytuacja będzie wolniejsza, jeśli będziesz musiał się zamienić. Również mapy pamięci (patrz numpy.memmap) to sposób na pracę z ogromnymi plikami na dysku bez ładowania ich do pamięci, ale znowu, aby móc pracować z dużą ilością użytecznych funkcji, musisz mieć 64-bitową przestrzeń adresową. PyTables zrobi to również za Ciebie.

dwf
źródło
4

Czasami jednym prostym rozwiązaniem jest użycie niestandardowego typu dla elementów macierzy. W dtypezależności od zakresu potrzebnych numerów możesz użyć instrukcji, a szczególnie mniejszych dla swoich przedmiotów. Ponieważ Numpy domyślnie bierze pod uwagę największy typ obiektu, może to być pomocny pomysł w wielu przypadkach. Oto przykład:

In [70]: a = np.arange(5)

In [71]: a[0].dtype
Out[71]: dtype('int64')

In [72]: a.nbytes
Out[72]: 40

In [73]: a = np.arange(0, 2, 0.5)

In [74]: a[0].dtype
Out[74]: dtype('float64')

In [75]: a.nbytes
Out[75]: 32

Oraz z niestandardowym typem:

In [80]: a = np.arange(5, dtype=np.int8)

In [81]: a.nbytes
Out[81]: 5

In [76]: a = np.arange(0, 2, 0.5, dtype=np.float16)

In [78]: a.nbytes
Out[78]: 8
Kasravnd
źródło
3

Czy zastanawiasz się, jak poradzić sobie z macierzą 2500000000 elementów bez terabajtów pamięci RAM?

Sposobem na obsłużenie 2 miliardów elementów bez 8 miliardów bajtów pamięci RAM jest nieprzechowywanie macierzy w pamięci.

Oznacza to znacznie bardziej wyrafinowane algorytmy pobierania go z systemu plików w częściach.

S.Lott
źródło
7
Nie prawda. Jeśli 99,99% (dla realistycznego przykładu) pierwiastków wynosi zero, to wszystkie dane macierzy mogą być przechowywane w pamięci. Nie ma potrzeby używania do 4 bajtów na każde zero, skoro możesz po prostu zapisać listę (row, column, value)tych wpisów, które istnieją.
Eric Wilson,
6
@EricWilson: Gdzie w pytaniu sugeruje to, że macierz jest rzadka? Całkowicie za tym tęskniłem. Czy możesz podać wycenę?
S.Lott
1

Zwykle, gdy mamy do czynienia z dużymi macierzami, implementujemy je jako rzadkie macierze .

Nie wiem, czy numpy obsługuje rzadkie macierze, ale zamiast tego znalazłem to .

Nick Dandoulakis
źródło
1

O ile wiem o numpy, nie, ale mogę się mylić.

Mogę zaproponować Ci alternatywne rozwiązanie: napisz macierz na dysku i dostęp do niej fragmentami. Proponuję format pliku HDF5. Jeśli potrzebujesz tego w sposób przejrzysty, możesz ponownie zaimplementować interfejs ndarray, aby podzielić macierz zapisaną na dysku w pamięci. Zachowaj ostrożność, jeśli zmodyfikujesz dane, aby zsynchronizować je z powrotem na dysku.

Stefano Borini
źródło
A jeśli chcę uzyskać dostęp do całej matrycy 57600 na 57600?
Gunjan Naik,