2015-06-08 22 views
5

Napisałem program i profilowałem go. Wąskie gardła są następujące (w przypadku korzystania z macierz rzadką):Najszybszy sposób na uzyskanie dostępu do wartości i umieszczenie ich w macierzy

26534 0.775 0.000 66.657 0.003 compressed.py:638(__setitem__) 
    26534 2.240 0.000 59.438 0.002 compressed.py:688(_set_many) 
    13318 2.993 0.000 50.024 0.004 compressed.py:742(_insert_many) 
3034231 23.087 0.000 38.101 0.000 defmatrix.py:312(__getitem__) 

Jeśli stosować gęstą matrycę, a następnie czynności te są powolne (posiada init matrycę do zera)

3034072 24.902 0.000 41.135 0.000 defmatrix.py:312(__getitem__) 
    11780 19.586 0.002 19.586 0.002 {numpy.core.multiarray.zeros} 

Rzadki wersja matrycy jest szybsza (193 w porównaniu z 178s). Ale szukanie i umieszczanie w rzędach jest dla mnie wąskim gardłem. Próbowałem użyć funkcji take, gdzie używam range() do utworzenia tablicy zawierającej indeksy wiersza. Jest to jednak znacznie gorsze (o współczynnik 10000) niż to, co obecnie robię, czyli dla matrycy X, X[idx,:] do wstawiania i X.getrow(idx).todense() do robienia.

Czy istnieje lepszy sposób na dostęp do tych wierszy i ich zastępowanie? Moje macierze są dość duże (~ 100000 wierszy 20-500 col).

Edytuj: Używam csr_matrix (ale otwarty na wszelkiego rodzaju rzadkie matrycy - ten wydawał się odpowiedni do przechwytywania wierszy). Poniżej znajduje się seria testów, które dają MWE. Prędkości wynoszą około 3E-4s, 7E-3s, .1s. Jest to dla mnie zaskakujące i zastanawiam się, czy jest to szybszy sposób niż najwyższe podejście. Jeśli usunę wywołanie todense(), rzadki czas zostanie przecięty na pół - ale to wciąż wydaje się dość powolne.

import numpy as np 
from time import time 
from scipy.sparse import csr_matrix 

def testFancy(mat,idxs): 
    for i in idxs: 
     x = mat[i,:] 

def testTake(mat,idxs): 
    for i in idxs: 
     x = mat.take(range(i*50,i*50+50)) 

def testSparse(mat,idxs): 
    for i in idxs: 
     x = mat.getrow(i).todense() 

mat = np.random.rand(50000,50) 
idxs = np.random.randint(50000-1, size=1000) 

#fancy 
t0 = time() 
testFancy(mat,idxs) 
t1 = time() 
print str(t1-t0) 

#take 
t0 = time() 
testTake(mat,idxs) 
t1 = time() 
print str(t1-t0) 

#sparse 
mat = csr_matrix((50000,50)) 
t0 = time() 
testSparse(mat,idxs) 
t1 = time() 
print str(t1-t0) 
+2

Pomoże to [mcve] (http://stackoverflow.com/help/mcve). – wwii

+1

Czy możesz podać minimalny przykład pracy, który możemy skopiować i wkleić? Trudno powiedzieć cokolwiek innego. – rth

+1

Należy również zauważyć, że istnieją różne implementacje macierzy rzadkiej. Od samego pojęcia 'rzadka macierz 'możemy jedynie zgadywać podstawową strukturę danych. – cel

Odpowiedz

1

Wystarczy użyć fantazyjne indeksowanie, zarówno dla pobierania i ustawiania wiersze w tablicy,

import numpy as np 
from scipy.sparse import csr_matrix 

mat_ds = np.random.rand(50000,50) 
mat_csr = csr_matrix((50000,50)) 
mat_lil = mat_csr.tolil() 

idxs = np.random.randint(50000-1, size=1000) 

print(mat_sp[idxs, :].todense()) 
print(mat_csr[idxs, :]) 

mat_sp[idxs, :] = 2.0 # or any other expression that makes sens here 
mat_csr[idxs, :] = 2.0 

to nie powinno mieć znaczenia, czy macierze są skąpe lub nie. To będzie szybsze niż jakiekolwiek niestandardowe rozwiązanie z pętlą (~ 250x szybciej niż w przypadku testSparse w moim przypadku).

Oczywiście przypisanie do rzadkiej tablicy powinno być wykonane w taki sposób, aby zachować rzadkość, albo zostanie ono ponownie przydzielone, co jest kosztowne dla csr_matrix. Na przykład powyższy przykład generuje ostrzeżenie z tego powodu.

Edytuj: w odpowiedzi na komentarze. Rozważmy odpytywanie tylko jeden wiersz,

In [1]: %timeit -n 1 mat_csr[0, :].todense() 
1 loops, best of 3: 101 µs per loop 

In [2]: %timeit -n 1 mat_lil[0, :].todense() 
1 loops, best of 3: 157 µs per loop 

In [3]: %timeit -n 1 mat_ds[0, :] 
The slowest run took 8.25 times longer than the fastest. This could mean that an intermediate result is being cached 
1 loops, best of 3: 954 ns per loop 

więc tak, zapytań gęstej matrycy, jest 10 do 100 razy szybciej niż rozrzedzony tablicy z wynikiem oddanych tak gęsty (czy używasz CSR lub lil tablice), bo nie ma mniej narzutów. Nic nie można z tym zrobić, po prostu musisz dokonać wyboru, czy potrzebujesz rzadkich tablic, czy nie.

+0

Pętla miała jedynie znormalizować czas obliczeń. Dostępy będą wykonywane po jednym wierszu naraz. – user671931

+0

@ user671931 Zaktualizowałem odpowiedź, aby uwzględnić twoje komentarze. – rth

0

Próbowałem użyć dok_mat: rix. Wynik na mojego testu jest 0.03s i ogólny wniosek jest 66s z:

3034124 11.833 0.000 20.293 0.000 defmatrix.py:312(__getitem__) 

To wydaje się być miły kompromis - ale zastanawiam się, czy to może być lepiej.