Czy istnieje sposób numps-toniczny, np. Funkcja, aby znaleźć najbliższą wartość w tablicy?
Przykład:
np.find_nearest( array, value )
import numpy as np
def find_nearest(array, value):
array = np.asarray(array)
idx = (np.abs(array - value)).argmin()
return array[idx]
array = np.random.random(10)
print(array)
# [ 0.21069679 0.61290182 0.63425412 0.84635244 0.91599191 0.00213826
# 0.17104965 0.56874386 0.57319379 0.28719469]
value = 0.5
print(find_nearest(array, value))
# 0.568743859261
return np.abs(array-value).min()
daje złą odpowiedź. To daje ci minimalną odległość wartości bezwzględnej i jakoś musimy zwrócić rzeczywistą wartość tablicy. Możemy dodaćvalue
i zbliżyć się, ale wartość bezwzględna wrzuca klucz do rzeczy ...FutureWarning: 'argmin' is deprecated. Use 'idxmin' instead. The behavior of 'argmin' will be corrected to return the positional minimum in the future. Use 'series.values.argmin' to get the position of the minimum now.
Używanieidxmin
zamiastargmin
działa dla mnie z powyższym rozwiązaniem. (v3.6.4)JEŻELI twoja tablica jest posortowana i jest bardzo duża, jest to znacznie szybsze rozwiązanie:
Skaluje się to do bardzo dużych tablic. Możesz łatwo zmodyfikować powyższe, aby posortować w metodzie, jeśli nie możesz założyć, że tablica jest już posortowana. Jest to nadmiar w przypadku małych tablic, ale gdy stają się duże, jest to znacznie szybsze.
źródło
np.searchsorted
zajmuje około 2 µs dla mojego zestawu testowego, cała funkcja około 10 µs. Korzystanienp.abs
staje się jeszcze gorsze. Nie ma pojęcia, co tam robi python.math
procedury, zobacz tę odpowiedź .if/else
należy zastąpićidx = idx - (np.abs(value - array[idx-1]) < np.abs(value - array[idx])); return array[idx]
value
jest większy niżarray
największy element. Zmieniłemif
oświadczenie,if idx == len(array) or math.fabs(value - array[idx - 1]) < math.fabs(value - array[idx])
aby działało dla mnie!if idx > 0 and (idx == len(array) or math.fabs(value - array[idx-1]) < math.fabs(value - array[idx])):
Po niewielkiej modyfikacji powyższa odpowiedź działa z tablicami o dowolnym wymiarze (1d, 2d, 3d, ...):
Lub zapisany jako pojedynczy wiersz:
źródło
a[np.abs(a-a0).argmin)]
działa w porządku.a[np.sum(np.square(np.abs(a-a0)),1).argmin()]
.Podsumowanie odpowiedzi : jeśli ktoś ma posortowane,
array
kod bisekcji (podany poniżej) działa najszybciej. ~ 100-1000 razy szybciej dla dużych tablic i ~ 2-100 razy szybciej dla małych tablic. Nie wymaga też numpy. Jeśli masz nieposortowane,array
to jeśliarray
jest duże, należy najpierw rozważyć użycie sortowania O (n logn), a następnie bisekcji, a jeśliarray
jest małe, metoda 2 wydaje się najszybsza.Najpierw wyjaśnij, co rozumiesz przez najbliższą wartość . Często chce się odstępu w odciętej, np. Tablica = [0,0.7,2.1], wartość = 1,95, odpowiedź brzmiałaby idx = 1. Podejrzewam, że jest to przypadek (w przeciwnym razie można bardzo łatwo zmodyfikować następujące instrukcje warunkowe po znalezieniu interwału). Zwrócę uwagę, że optymalnym sposobem na wykonanie tego jest bisekcja (którą przedstawię jako pierwszą - zauważ, że w ogóle nie wymaga numpy i jest szybsza niż używanie funkcji numpy, ponieważ wykonują one operacje redundantne). Następnie przedstawię porównanie czasowe z innymi przedstawionymi tutaj przez innych użytkowników.
Przepołowienie:
Teraz zdefiniuję kod na podstawie innych odpowiedzi, każda zwróci indeks:
Teraz zmierzę kody: Zwróć uwagę, że metody 1,2,4,5 nie podają poprawnie interwału. Metody 1,2,4 zaokrąglają do najbliższego punktu w tablicy (np.> = 1,5 -> 2), a metoda 5 zawsze zaokrągla w górę (np. 1,45 -> 2). Tylko metody 3 i 6, i oczywiście bisekcja dają odpowiedni odstęp.
Dla bisekcji z dużą tablicą daje 4us w porównaniu do następnego najlepszego 180us i najdłuższego 1,21ms (~ 100-1000 razy szybciej). Dla mniejszych tablic jest ~ 2-100 razy szybszy.
źródło
array
jest mały, to metoda 2 wydaje się najszybsza”. jak mały miałeś na myśli @JoshAlbert?Oto rozszerzenie umożliwiające znalezienie najbliższego wektora w szeregu wektorów.
źródło
norm(..., axis=-1)
powinno być szybsze niż wyodrębnianiex,y
wartości za pomocą iteracji Pythona. Ponadto,x,y
są skalary tutaj? Potemnorm(x+y)
jest błąd, ponieważ np. Dystans(+1, -1)
będzie traktowany jako 0.idx = np.array([np.linalg.norm(x+y) for (x,y) in abs(array-value)]).argmin()
Jeśli nie chcesz używać Numpy, zrobi to:
źródło
Oto wersja, która obsłuży nieskalarną tablicę „wartości”:
Lub wersja, która zwraca typ liczbowy (np. Int, float), jeśli dane wejściowe są skalarne:
źródło
outer
metody ufunc, myślę, że będę jej częściej używać w przyszłości. Nawiasemarray[indices]
mówiąc, pierwsza funkcja powinna wrócić .np.subtract.outer
wygeneruje całą macierz produktu zewnętrznego, która jest naprawdę wolna i intensywnie zapamiętuje, jeśliarray
i / lubvalues
jest bardzo duża.Oto wersja z scipy dla @Ari Onasafari, odpowiedz „ aby znaleźć najbliższy wektor w szeregu wektorów ”
źródło
Oto szybka wektoryzowana wersja rozwiązania @ Dimitri, jeśli masz wiele
values
do wyszukiwania (values
może to być tablica wielowymiarowa):Benchmarki
> 100 razy szybszy niż użycie
for
pętli z rozwiązaniem @ Demitri`źródło
idx = np.searchsorted(array, values)
wtedy:idx[array[idx] - values>np.diff(array).mean()*0.5]-=1
i wreszciereturn array[idx]
W przypadku dużych tablic odpowiedź (doskonała) podana przez @Demitri jest znacznie szybsza niż odpowiedź oznaczona obecnie jako najlepsza. Dostosowałem jego dokładny algorytm na dwa sposoby:
Poniższa funkcja działa niezależnie od tego, czy tablica wejściowa jest posortowana.
Poniższa funkcja zwraca indeks tablicy wejściowej odpowiadający najbliższej wartości, która jest nieco bardziej ogólna.
Zauważ, że poniższa funkcja obsługuje również określony przypadek krawędzi, który prowadziłby do błędu w oryginalnej funkcji napisanej przez @Demitri. W przeciwnym razie mój algorytm jest identyczny z jego.
źródło
x = np.array([2038, 1758, 1721, 1637, 2097, 2047, 2205, 1787, 2287, 1940, 2311, 2054, 2406, 1471, 1460])
. Zfind_nearest(x, 1739.5)
(najbliższa wartość do pierwszego kwantyla) dostaję1637
(rozsądne) i1
(błąd?).To jest wektoryzowana wersja odpowiedzi Unutbu :
źródło
Myślę, że najbardziej pythonicznym sposobem byłoby:
To jest podstawowy kod. Możesz użyć go jako funkcji, jeśli chcesz
źródło
Wszystkie odpowiedzi są przydatne do zebrania informacji i napisania wydajnego kodu. Napisałem jednak mały skrypt w języku Python, aby zoptymalizować go pod kątem różnych przypadków. Najlepszym rozwiązaniem będzie posortowanie dostarczonej tablicy. Jeśli ktoś przeszukuje indeks najbliższego punktu o określonej wartości,
bisect
moduł jest najbardziej wydajny czasowo. Kiedy jedno wyszukiwanie indeksów odpowiada tablicy,numpy searchsorted
jest najbardziej wydajne.W [63]:% czasu bisect.bisect_left (xlist, 0.3) Czasy procesora: użytkownik 0 ns, sys: 0 ns, łącznie: 0 ns Czas ściany: 22,2 µs
W [64]:% czasu np. Wyszukiwanie posortowane (xar, 0.3, side = "left") Czasy procesora: użytkownik 0 ns, sys: 0 ns, ogółem: 0 ns Czas ściany: 98,9 µs
% czasu np.searchsorted (xar, randpts, side = "left") Czasy procesora: użytkownik 4 ms, sys: 0 ns, łącznie: 4 ms Czas ściany: 1,2 ms
Jeśli zastosujemy regułę multiplikatywną, to numpy powinno zająć ~ 100 ms, co oznacza ~ 83X szybciej.
źródło
Dla tablicy 2d, aby określić pozycję i, j najbliższego elementu:
źródło
źródło
Może pomocne w
ndarrays
:źródło