Powiedzmy, że mam tablicę NumPy:
x = np.array([0, 1, 2, 0, 4, 5, 6, 7, 0, 0])
Przy każdym indeksie chcę znaleźć odległość do najbliższej wartości zerowej. Jeśli sama pozycja jest zerem, zwróć zero jako odległość. Potem interesują nas tylko odległości do najbliższego zera, który znajduje się na prawo od aktualnej pozycji. Super naiwne podejście wyglądałoby tak:
out = np.full(x.shape[0], x.shape[0]-1)
for i in range(x.shape[0]):
j = 0
while i + j < x.shape[0]:
if x[i+j] == 0:
break
j += 1
out[i] = j
I wynik byłby:
array([0, 2, 1, 0, 4, 3, 2, 1, 0, 0])
Zauważam wzorzec odliczania / zmniejszania w danych wyjściowych pomiędzy zerami. Mogę być w stanie użyć lokalizacji zer (tj. zero_indices = np.argwhere(x == 0).flatten()
)
Jaki jest najszybszy sposób na uzyskanie pożądanej wydajności w czasie liniowym?
x.shape[0] - 1
)Odpowiedzi:
Podejście nr 1:
Searchsorted
do ratowania czasu liniowego w wektorowy sposób (zanim pojawią się faceci numba)!Podejście nr 2: Kolejne z niektórymi
cumsum
-Alternatywnie ostatni krok
cumsum
można zastąpićrepeat
funkcjonalnością -Podejście nr 3: Kolejne z przeważnie tylko
cumsum
-źródło
Możesz pracować z drugiej strony. Trzymaj licznik liczby niezerowych cyfr i przypisz je do elementu w tablicy. Jeśli widzisz 0, zresetuj licznik na 0
Edycja: jeśli po prawej stronie nie ma zera, musisz ponownie sprawdzić
źródło
Możesz użyć różnicy między indeksami każdej pozycji i skumulowanych maks. Pozycji zerowych, aby określić odległość do poprzedniego zera. Można to zrobić do przodu i do tyłu. Minimalna odległość do przodu i do tyłu do poprzedniego (lub następnego) zera będzie najbliższa:
wyniki:
Specjalny przypadek, w którym na zewnętrznych krawędziach nie ma zer:
działa również bez zer
[EDYCJA] rozwiązania niepoliczalne ...
jeśli szukasz rozwiązania O (N), które nie wymaga numpy, możesz zastosować tę strategię za pomocą funkcji akumulacji z itertools:
wynik:
Jeśli nie chcesz korzystać z żadnej biblioteki, możesz ręcznie gromadzić odległości w pętli:
wynik:
źródło
Moją pierwszą intuicją byłoby użycie krojenia. Jeśli x może być normalną listą zamiast tablicy numpy, możesz użyć
jeśli numpy jest konieczne, możesz użyć
ale jest to mniej wydajne, ponieważ znajdujesz wszystkie zerowe lokalizacje po prawej stronie wartości, a następnie wyciągasz tylko pierwszą. Zdecydowanie lepszy sposób na zrobienie tego w numpy.
źródło
Edycja: Przepraszam, źle zrozumiałem. To da ci odległość do najbliższych zer - może to być po lewej lub po prawej stronie. Ale możesz użyć
d_right
jako wyniku pośredniego. Nie obejmuje to jednak przypadku, w którym nie ma żadnego zera po prawej stronie.źródło