Czy możesz zasugerować funkcję modułu z numpy / scipy, która może znaleźć lokalne maksima / minima w 1D tablicy numpy? Oczywiście najprostszym podejściem jest przyjrzenie się najbliższym sąsiadom, ale chciałbym mieć akceptowane rozwiązanie, które jest częścią numpy distro.
116
Odpowiedzi:
Jeśli szukasz wszystkich wpisów w tablicy 1d
a
mniejszych niż ich sąsiedzi, możesz spróbowaćMożesz również wygładzić swoją tablicę przed tym krokiem, używając
numpy.convolve()
.Myślę, że nie ma do tego dedykowanej funkcji.
źródło
<
ze>
daje lokalnym maksima zamiast minima[False False]
Jaki może być tutaj problem?W SciPy> = 0,11
Produkuje
Zauważ, że są to indeksy x, które są lokalnymi maks./min. Aby uzyskać wartości, spróbuj:
scipy.signal
zapewnia równieżargrelmax
iargrelmin
do znajdowania odpowiednio maksimów i minimów.źródło
np.random.random(12)
generuje 12 losowych wartości, są one używane do zademonstrowania funkcjiargrelextrema
.test02=np.array([10,4,4,4,5,6,7,6])
, to nie działa. Nie uznaje kolejnych wartości za lokalne minima.W przypadku krzywych z niezbyt dużym szumem polecam następujący mały fragment kodu:
+1
Jest ważny, ponieważdiff
zmniejsza oryginalny numer indeksu.źródło
[1, 2, 2, 3, 3, 3, 2, 2, 1]
, lokalne maksima są oczywiście gdzieś pomiędzy 3 w środku. Ale jeśli uruchomisz funkcje, które dostarczyłeś, uzyskasz maksymy przy indeksach 2,6 i minima przy indeksach 1,3,5,7, co dla mnie nie ma większego sensu.+1
zamiastnp.diff()
używaćnp.gradient()
.Inne podejście (więcej słów, mniej kodu), które może pomóc:
Lokalizacje lokalnych maksimów i minimów są również lokalizacjami przejść przez zero pierwszej pochodnej. Na ogół znacznie łatwiej jest znaleźć przejście przez zero niż bezpośrednio znaleźć lokalne maksima i minima.
Niestety, pierwsza pochodna ma tendencję do „wzmacniania” szumu, więc gdy w oryginalnych danych obecny jest znaczny szum, pierwszą pochodną najlepiej jest zastosować dopiero po zastosowaniu pewnego stopnia wygładzenia oryginalnych danych.
Ponieważ wygładzanie jest, w najprostszym sensie, filtrem dolnoprzepustowym, wygładzanie jest często najlepsze (cóż, najłatwiej) przy użyciu jądra splotu, a "kształtowanie" tego jądra może zapewnić zaskakującą ilość możliwości zachowania / ulepszenia funkcji . Proces znajdowania optymalnego jądra można zautomatyzować za pomocą różnych środków, ale najlepszym może być zwykła brutalna siła (dużo szybka do znalezienia małych jąder). Dobre jądro będzie (zgodnie z przeznaczeniem) znacznie zniekształcić oryginalne dane, ale NIE wpłynie to na lokalizację interesujących nas szczytów / dolin.
Na szczęście dość często odpowiednie jądro można utworzyć za pomocą prostego pliku SWAG („wykształcone przypuszczenie”). Szerokość jądra wygładzającego powinna być nieco szersza niż najszerszy oczekiwany „interesujący” szczyt w oryginalnych danych, a jego kształt będzie przypominał ten pik (falka o pojedynczej skali). Dla jąder zachowujących średnią (czym powinien być każdy dobry filtr wygładzający), suma elementów jądra powinna być dokładnie równa 1,00, a jądro powinno być symetryczne względem swojego środka (co oznacza, że będzie miało nieparzystą liczbę elementów.
Biorąc pod uwagę optymalne jądro wygładzające (lub niewielką liczbę jąder zoptymalizowanych pod kątem różnej zawartości danych), stopień wygładzenia staje się współczynnikiem skalującym („zysk”) jądra splotu.
Określenie „prawidłowego” (optymalnego) stopnia wygładzenia (wzmocnienia jądra splotu) można nawet zautomatyzować: Porównaj odchylenie standardowe danych pierwszej pochodnej z odchyleniem standardowym wygładzonych danych. Sposób, w jaki stosunek dwóch odchyleń standardowych zmienia się wraz ze zmianami stopnia wygładzania krzywki, aby przewidzieć efektywne wartości wygładzania. Wystarczy kilka ręcznych uruchomień danych (które są naprawdę reprezentatywne).
Wszystkie wcześniejsze rozwiązania opublikowane powyżej obliczają pierwszą pochodną, ale nie traktują jej jako miary statystycznej, ani też powyższe rozwiązania nie próbują wykonywać wygładzania zachowującego / wzmacniającego funkcję (aby pomóc subtelnym skokom „przeskoczyć” nad szumem).
Na koniec zła wiadomość: znajdowanie „prawdziwych” szczytów staje się prawdziwym bólem, gdy szum ma również cechy, które wyglądają jak prawdziwe szczyty (nakładające się pasmo). Kolejnym bardziej złożonym rozwiązaniem jest generalnie użycie dłuższego jądra splotu („szersza apertura jądra”), które bierze pod uwagę zależność między sąsiednimi „rzeczywistymi” pikami (takimi jak minimalne lub maksymalne współczynniki występowania pików) lub użycie wielu splot przebiega przy użyciu jąder o różnych szerokościach (ale tylko wtedy, gdy jest szybszy: podstawową prawdą matematyczną jest to, że splot liniowy wykonywany w sekwencji zawsze może być razem splatany w pojedynczy splot). Często jednak o wiele łatwiej jest najpierw znaleźć sekwencję przydatnych jąder (o różnych szerokościach) i połączyć je razem, niż bezpośrednio znaleźć ostateczne jądro w jednym kroku.
Mamy nadzieję, że dostarczy to wystarczających informacji, aby umożliwić Google (i być może dobry tekst dotyczący statystyk) wypełnienie luk. Naprawdę chciałbym mieć czas, aby podać działający przykład lub link do niego. Jeśli ktoś natknie się na taki w Internecie, opublikuj go tutaj!
źródło
Począwszy od wersji 1.1 SciPy, możesz również użyć find_peaks . Poniżej znajdują się dwa przykłady zaczerpnięte z samej dokumentacji.
Używając tego
height
argumentu, można wybrać wszystkie maksima powyżej określonego progu (w tym przykładzie wszystkie nieujemne maksima; może to być bardzo przydatne, jeśli mamy do czynienia z zaszumioną linią bazową; jeśli chcesz znaleźć minima, po prostu pomnóż wprowadzone dane autor-1
:):Kolejnym niezwykle pomocnym argumentem jest
distance
określenie minimalnej odległości między dwoma szczytami:źródło
Dlaczego nie skorzystać z wbudowanej funkcji Scipy signal.find_peaks_cwt do wykonania tego zadania?
wyniki:
pozdrowienia
źródło
Aktualizacja: nie byłem zadowolony z gradientu, więc uznałem, że jest bardziej niezawodny w użyciu
numpy.diff
. Daj mi znać, jeśli zrobisz to, co chcesz.Jeśli chodzi o szum, matematycznym problemem jest zlokalizowanie maksimów / minimów, jeśli chcemy spojrzeć na szum, możemy użyć czegoś takiego jak splot, o którym wspomniano wcześniej.
źródło
Chociaż to pytanie jest naprawdę stare. Uważam, że w numpy jest znacznie prostsze podejście (jeden liniowiec).
Aby znaleźć lokalne maksimum lub minimum, zasadniczo chcemy znaleźć, kiedy różnica między wartościami na liście (3-1, 9-3 ...) zmienia się z dodatniej na ujemną (maks.) Lub z ujemnej na dodatnią (min). Dlatego najpierw znajdujemy różnicę. Następnie znajdujemy znak, a następnie znajdujemy zmiany w znaku, ponownie biorąc różnicę. (Coś w rodzaju pierwszej i drugiej pochodnej w rachunku różniczkowym, tylko że mamy dane dyskretne i nie mamy funkcji ciągłej.)
Dane wyjściowe w moim przykładzie nie zawierają ekstrema (pierwszej i ostatniej wartości na liście). Podobnie jak w przypadku rachunku różniczkowego, jeśli druga pochodna jest ujemna, masz max, a jeśli jest dodatnia, masz min.
Tak więc mamy następujące zestawienie:
źródło
Żadne z tych rozwiązań nie zadziałało, ponieważ chciałem również znaleźć piki w centrum powtarzających się wartości. na przykład w
ar = np.array([0,1,2,2,2,1,3,3,3,2,5,0])
odpowiedź powinna brzmieć
Zrobiłem to za pomocą pętli. Wiem, że nie jest super czysty, ale spełnia swoje zadanie.
źródło
minm
imaxm
zawierają odpowiednio wskaźniki minimów i maksimów. W przypadku ogromnego zestawu danych da wiele maksym / minimów, więc w takim przypadku najpierw wygładź krzywą, a następnie zastosuj ten algorytm.źródło
Inne rozwiązanie wykorzystujące zasadniczo operatora dylatacji:
a dla minimów:
Również z
scipy.ndimage
was może zastąpićrank_filter(x, -1, size=3)
zgrey_dilation
irank_filter(x, 0, size=3)
zgrey_erosion
. Nie będzie to wymagało sortowania lokalnego, więc jest nieco szybsze.źródło
Inny:
źródło