2016-01-18 24 views
9

W numpy, jeśli chcę porównać dwie tablice, na przykład chcę przetestować czy wszystkie elementy w A są mniejsze niż wartości w B, używam if (A < B).all():. Ale w praktyce wymaga to przydziału i oceny kompletnej macierzy C = A < B, a następnie wywoływania na niej C.all(). To trochę marnotrawstwa. Czy istnieje sposób na "skrócenie" porównania, tj. Bezpośrednio oceniać element po jednym elemencie (bez przydziału i obliczania tymczasowego C) i zatrzymywać i zwracać False po znalezieniu pierwszego nieprawidłowego porównania elementów?evalution porównania tablicy numpy

+1

Czy to "marnowanie" ma zauważalny wpływ na wydajność? – mfitzp

+0

W moim przypadku niewiele. Generalnie może to mieć wpływ - założę się, że przydzielenie dodatkowej tablicy 1000x1000x1000 może zaszkodzić wydajności. Pytałem z czystej ciekawości, uważam, że ta ocena skrótu byłaby bardzo przydatna. Istnieje funkcja 'allclose()', którą uważam, zatrzymać, gdy pierwszy niezgodny element zostanie znaleziony. Zaskoczyło mnie, że nie znalazłem "allequal (a, b)", "allless (a, b)" i "allgreater (a, b)", które wszyscy będą bardzo popularne w ich użytkowaniu, wierzę, ponieważ 'jeśli (A

+0

Po obejrzeniu źródła numpy, podczas gdy myślę, że nie ma wsparcia dla skrótu A mfitzp

Odpowiedz

0

Zwykły python and i or używają oceny skrótów, ale numpy nie.

(A < B).all() 

wykorzystuje numpy klocki, nadawanie, element po elemencie porównaniu z < i zmniejszenie all. < działa tylko z innymi operacjami binarnymi, plus, razy, lub, gt, le, itp. I all jest podobna do innych metod redukcji, może działać na całej tablicy lub wierszach lub przez kolumny.

Możliwe jest napisanie funkcji, która łączy all i < w jedną iterację, ale trudno byłoby uzyskać ogólność, którą właśnie opisałem.

Ale jeśli musisz wdrożyć rozwiązanie iteracyjne, z akcją skrótu i ​​zrobić to szybko, proponuję rozwinąć ten pomysł za pomocą nditer, a następnie skompilować go z cython.

http://docs.scipy.org/doc/numpy/reference/arrays.nditer.html to dobry samouczek na temat korzystania z nditer i prowadzi użytkownika przez jego używanie w cython. nditer zajmuje się nadawaniem i iteracją, pozwalając ci skoncentrować się na porównaniu i każdym skróceniu.

Oto szkic iteratora, które mogą być oddane do cython:

import numpy as np 

a = np.arange(4)[:,None] 
b = np.arange(2,5)[None,:] 
c = np.array(True) 
it = np.nditer([a, b, c], flags=['reduce_ok'], 
    op_flags = [['readonly'], ['readonly'],['readwrite']]) 
for x, y, z in it: 
    z[...] = x<y 
    if not z: 
     print('>',x,y) 
     break 
    else: 
     print(x,y) 
print(z) 

z przebiegu próby:

1420:~/mypy$ python stack34852272.py 
(array(0), array(2)) 
(array(0), array(3)) 
(array(0), array(4)) 
(array(1), array(2)) 
(array(1), array(3)) 
(array(1), array(4)) 
('>', array(2), array(2)) 
False 

zaczynać się domyślnie False, a inny break stan i masz skrócenie any. Generalizacja testu do obsługi <, <= itp. Będzie więcej pracy.

Wykonaj coś takiego w Pythonie, a następnie spróbuj w Cython. Jeśli masz problemy z tym krokiem, wróć z nowym pytaniem. SO ma dobrą bazę użytkowników Cython.

1

Jak duże są macierze? Sądzę, że są bardzo duże, np. A.shape = (1000000) lub większa, zanim wydajność stanie się problemem. Czy rozważasz użycie numpy views?

Zamiast porównywać (A < B).all() lub (A < B).any(), możesz spróbować zdefiniować widok, taki jak (A[:10] < B[:10]).all(). Oto prosty pętli, które mogą pracować:

k = 0 
while((A[k*10: (k+1)*10] < B[k*10: (k+1)*10]).all()): 
    k += 1 

Zamiast 10 można użyć 100 lub 10**3 wielkość segmentu chcesz. Oczywiście, jeśli rozmiar segmentu wynosi 1, mówisz:

k = 0 
while (A[k] < B[k]): 
    k+= 1 

Czasami porównywanie całej tablicy może spowodować zwiększenie intensywności pamięci. Jeśli A i B mają długość 10000 i muszę porównać każdą parę elementów, zabraknie mi miejsca.

+0

Dzielenie dużej tablicy z widokami jest bardzo sprytnym pomysłem, więc go ulepszam. Ale jest to okropny hak czegoś, co, jak sądzę, powinno być naturalnie w bibliotece. –