2014-05-02 5 views
39

jestem stara się wybrać konkretne kolumny za rzędzie numpy matrycy. Jestem po dobrej drodze rozwiązując następujący problemNumpy wybierając konkretny indeks kolumny za rzędem za pomocą listy indeksów

Załóżmy, że mam następującą macierz którą nazwałbym X

[1, 2, 3] 
[4, 5, 6] 
[7, 8, 9] 

Mam też listę indeksów kolumn na każdy rząd, który nazwałbym Y

[1, 0, 2] 

muszę uzyskać wartości

[2] 
[4] 
[9] 

zamiast listy z inde xe Y Mogę również wytworzyć macierz o tym samym kształcie co X, gdzie każda kolumna jest wartością bool/(int w zakresie 0-1 wartość wskazującą, czy jest to wymagana kolumna.

[0, 1, 0] 
[1, 0, 0] 
[0, 0, 1] 

wiem, można to zrobić z iteracji na tablicy i wybierając wartości kolumny muszę, ale zastanawiałem się, czy istnieje lepsze rozwiązanie. Będzie to często wykonywane na dużych tablicach danych i dlatego muszę działać tak szybko, jak to tylko możliwe.

Dziękuję

Odpowiedz

46

Jeśli masz tablicę logiczną można zrobić bezpośredni wybór w oparciu o które tak:

>>> a = np.array([True, True, True, False, False]) 
>>> b = np.array([1,2,3,4,5]) 
>>> b[a] 
array([1, 2, 3]) 

aby przejść wraz ze swoim początkowym przykład można wykonać następujące czynności:

>>> a = np.array([[1,2,3], [4,5,6], [7,8,9]]) 
>>> b = np.array([[False,True,False],[True,False,False],[False,False,True]]) 
>>> a[b] 
array([2, 4, 9]) 

Można również dodać w arange i dokonać bezpośredniego wyboru, ale w zależności od tego, jak generujesz tablicę boolowską i jaki jest twój kod li ke YMMV.

>>> a = np.array([[1,2,3], [4,5,6], [7,8,9]]) 
>>> a[np.arange(len(a)), [1,0,2]] 
array([2, 4, 9]) 

Mam nadzieję, że pomoże, daj mi znać, jeśli masz więcej pytań.

+4

+1 dla przykładu używając 'arange'.Było to szczególnie przydatne dla pobierania różnych bloków z wielu macierzy (tak w zasadzie przypadku 3D tego przykładu). – Griddo

+1

Witam, czy mógłbyś wyjaśnić, dlaczego musimy użyć 'arange' zamiast': '? Wiem, że twój sposób działa, a mój nie, ale chciałbym zrozumieć, dlaczego. – marcotama

+0

@tamzord, ponieważ jest to tablica numpy, a nie lista pytonów vanilla, więc składnia ':' nie działa w ten sam sposób. –

1

Można to zrobić za pomocą iteratora. Tak:

np.fromiter((row[index] for row, index in zip(X, Y)), dtype=int) 

Czas:

N = 1000 
X = np.zeros(shape=(N, N)) 
Y = np.arange(N) 

#@Aशwini चhaudhary 
%timeit X[np.arange(len(X)), Y] 
10000 loops, best of 3: 30.7 us per loop 

#mine 
%timeit np.fromiter((row[index] for row, index in zip(X, Y)), dtype=int) 
1000 loops, best of 3: 1.15 ms per loop 

#mine 
%timeit np.diag(X.T[Y]) 
10 loops, best of 3: 20.8 ms per loop 
+1

OP wspomniał, że powinien działać szybko na * dużych * tablicach, więc twoje testy porównawcze nie są zbyt reprezentatywne. Ciekaw jestem, jak twoja ostatnia metoda działa dla (dużo) większych tablic! –

+0

@moarningsun: Zaktualizowano. 'np.diag (X.T [Y])' jest tak powolny ... Ale 'np.diag (X.T)' jest tak szybki (10us). Nie wiem dlaczego. –

1

Jako czysty numpythonic podejściu można uzyskać indeksy z drugiej osi używając np.take(), to przekątna wynik byłby to oczekiwany wynik:

np.diagonal(np.take(arr, idx, axis=1)) 

Demo:

>>> arr = np.array([[1, 2, 3], 
... [4, 5, 6], 
... [7, 8, 9]]) 
>>> 
>>> idx = [1, 0, 2] 
>>> 
>>> np.diagonal(np.take(arr, idx, axis=1)) 
array([2, 4, 9]) 
+1

Prawdopodobnie nie jest to liczba numpythonic, ponieważ będzie skalować się strasznie przy większych tablicach i ma znacznie większy koszt pamięci. – miradulo

Powiązane problemy