Chcę obliczyć średnią zbioru danych cyklicznych. Na przykład mogę mieć kilka próbek z odczytu kompasu. Problem polega oczywiście na tym, jak radzić sobie z zawijaniem. Ten sam algorytm może być przydatny dla tarczy zegara.
Rzeczywiste pytanie jest bardziej skomplikowane - co oznaczają statystyki na kuli lub w przestrzeni algebraicznej, która „otacza”, np. Grupa addytywna mod n. Odpowiedź może nie być jednoznaczna, np. Średnia 359 stopni i 1 stopień może wynosić 0 stopni lub 180, ale statystycznie 0 wygląda lepiej.
To jest dla mnie prawdziwy problem programistyczny i staram się, aby nie wyglądał jak zwykły problem matematyczny.
Odpowiedzi:
Oblicz wektory jednostkowe z kątów i weź kąt ich średniej.
źródło
Kwestia ta została szczegółowo zbadana w książce: „Statistics On Spheres”, Geoffrey S. Watson, University of Arkansas Lecture Notes in the Mathematical Sciences, 1983 John Wiley & Sons, Inc., jak wspomniano na stronie http: //catless.ncl. ac.uk/Risks/7.44.html#subj4 autor: Bruce Karsh.
Dobry sposób na oszacowanie średniego kąta A na podstawie zestawu pomiarów kątów a [i] 0 <= i
Metoda podana przez starblue jest równoważna obliczeniowo, ale jego powody są jaśniejsze i prawdopodobnie bardziej wydajne programowo, a także działają dobrze w przypadku zerowym, więc chwała mu.
Temat jest teraz bardziej szczegółowo omawiany w Wikipedii i przy innych zastosowaniach, takich jak części ułamkowe.
źródło
Widzę problem - na przykład, jeśli masz kąt 45 'i kąt 315', „naturalna” średnia będzie równa 180 ', ale żądana wartość to w rzeczywistości 0'.
Myślę, że Starblue jest na czymś. Po prostu oblicz współrzędne kartezjańskie (x, y) dla każdego kąta i dodaj razem otrzymane wektory. Wymaganym wynikiem powinno być przesunięcie kątowe końcowego wektora.
Na razie ignoruję, że kurs kompasu zaczyna się na północy i biegnie zgodnie z ruchem wskazówek zegara, podczas gdy „normalne” współrzędne kartezjańskie zaczynają się od zera wzdłuż osi X, a następnie idą w kierunku przeciwnym do ruchu wskazówek zegara. Niezależnie od tego matematyka powinna działać w ten sam sposób.
źródło
cos()
,sin()
iatan2()
dać przybliżeń (dobrych, ale nadal się przez 1 lub 2 ulps), więc tym bardziej Średnio więcej błędów dołączyć.DLA SZCZEGÓLNEGO PRZYPADKU DWÓCH KĄTÓW:
Odpowiedź ((a + b) mod 360) / 2 jest ZŁA . Dla kątów 350 i 2 najbliższy punkt to 356, a nie 176.
Wektor jednostkowy i rozwiązania trygonometryczne mogą być zbyt drogie.
To, co otrzymałem z małego majsterkowania, to:
źródło
Ackb ma rację, że tych rozwiązań opartych na wektorach nie można uznać za prawdziwe średnie kątów, są one jedynie średnią odpowiedników wektorów jednostkowych. Jednak rozwiązanie sugerowane przez ACKB nie wydaje się matematycznie poprawne.
Poniższe rozwiązanie jest matematycznie wyprowadzone z celu minimalizacji (kąt [i] - avgAngle) ^ 2 (gdzie różnica jest korygowana, jeśli to konieczne), co czyni go prawdziwą średnią arytmetyczną kątów.
Po pierwsze, musimy dokładnie przyjrzeć się, w których przypadkach różnica między kątami jest inna niż różnica między ich odpowiednikami z normalną liczbą. Rozważ kąty x i y, jeśli y> = x - 180 i y <= x + 180, to możemy bezpośrednio użyć różnicy (xy). W przeciwnym razie, jeśli pierwszy warunek nie zostanie spełniony, w obliczeniach musimy użyć (y + 360) zamiast y. Odpowiednio, jeśli drugi warunek nie jest spełniony, musimy użyć (y-360) zamiast y. Ponieważ równanie krzywej minimalizujemy tylko zmiany w punktach, w których te nierówności zmieniają się z prawdziwego na fałszywy lub odwrotnie, możemy rozdzielić pełny [0,360) zakres na zestaw segmentów oddzielonych tymi punktami. Następnie musimy tylko znaleźć minimum każdego z tych segmentów, a następnie minimum minimum każdego segmentu, które jest średnią.
Oto obraz pokazujący, gdzie występują problemy przy obliczaniu różnic kątów. Jeśli x znajduje się w szarym obszarze, wystąpi problem.
Aby zminimalizować zmienną, w zależności od krzywej, możemy wziąć pochodną tego, co chcemy zminimalizować, a następnie znaleźć punkt zwrotny (gdzie pochodna = 0).
Tutaj zastosujemy ideę zminimalizowania kwadratowej różnicy w celu wyprowadzenia wspólnego wzoru na średnią arytmetyczną: suma (a [i]) / n. Krzywą y = sum ((a [i] -x) ^ 2) można zminimalizować w ten sposób:
Teraz zastosuj to do krzywych z naszymi dostosowanymi różnicami:
b = podzbiór a gdzie poprawna (kątowa) różnica a [i] -xc = podzbiór a gdzie poprawna (kątowa) różnica (a [i] -360) -x cn = wielkość cd = podzbiór a gdzie poprawna (kątowa) różnica (a [i] +360) -x dn = rozmiar d
Samo to nie wystarczy, aby uzyskać minimum, podczas gdy działa dla normalnych wartości, które mają nieograniczony zbiór, więc wynik z pewnością będzie mieścił się w zakresie zestawu i dlatego jest ważny. Potrzebujemy minimum mieszczącego się w zakresie (określonym przez segment). Jeśli minimum jest mniejsze niż dolna granica naszego segmentu, to minimum tego segmentu musi znajdować się w dolnej granicy (ponieważ krzywe kwadratowe mają tylko 1 punkt zwrotny), a jeśli minimum jest większe niż górna granica naszego segmentu, to minimum segmentu jest na Górna granica. Gdy mamy minimum dla każdego segmentu, po prostu znajdujemy ten, który ma najniższą wartość tego, co minimalizujemy (suma ((b [i] -x) ^ 2) + suma (((c [i] -360 ) -b) ^ 2) + suma (((d [i] +360) -c) ^ 2)).
Oto obraz krzywej, który pokazuje, jak zmienia się w punktach, w których x = (a [i] +180)% 360. Zbiór danych, o którym mowa, to {65,92,230,320,250}.
Oto implementacja algorytmu w Javie, w tym kilka optymalizacji, jego złożoność wynosi O (nlogn). Można go zredukować do O (n), jeśli zastąpisz sortowanie oparte na porównaniu sortowaniem bez porównania, takim jak sortowanie radix.
Średnia arytmetyczna zbioru kątów może nie zgadzać się z intuicyjnym wyobrażeniem o tym, jaka powinna być średnia. Na przykład średnia arytmetyczna zbioru {179,179,0,181,181} wynosi 216 (i 144). Odpowiedź, o której natychmiast pomyślisz, to prawdopodobnie 180, jednak dobrze wiadomo, że na średnią arytmetyczną duży wpływ mają wartości krawędzi. Należy również pamiętać, że kąty nie są wektorami, tak atrakcyjne, jak może się to czasami wydawać, gdy mamy do czynienia z kątami.
Algorytm ten oczywiście ma również zastosowanie do wszystkich wielkości, które są zgodne z arytmetyką modularną (z minimalną korektą), takich jak pora dnia.
Chciałbym również podkreślić, że chociaż jest to prawdziwa średnia kątów, w przeciwieństwie do rozwiązań wektorowych, to niekoniecznie oznacza, że jest to rozwiązanie, którego powinieneś użyć, średnia odpowiednich wektorów jednostkowych może być wartością, którą faktycznie używasz powinien być używany.
źródło
Musisz dokładniej zdefiniować średnią . W konkretnym przypadku dwóch kątów mogę wymyślić dwa różne scenariusze:
Nie rozumiem jednak, jak można uogólnić drugą alternatywę dla przypadku więcej niż dwóch kątów.
źródło
Podobnie jak w przypadku wszystkich średnich, odpowiedź zależy od wyboru miernika. Dla danej miary M, średnia niektórych kątów a_k w [-pi, pi] dla k w [1, N] jest tym kątem a_M, który minimalizuje sumę kwadratów odległości d ^ 2_M (a_M, a_k). W przypadku średniej ważonej po prostu uwzględnia się w sumie wagi w_k (takie, że sum_k w_k = 1). To jest,
a_M = arg min_x sum_k w_k d ^ 2_M (x, a_k)
Dwie powszechne metryki to Frobenius i Riemann. W przypadku miernika Frobeniusa istnieje bezpośredni wzór, który odpowiada zwykłemu pojęciu średniego namiaru w statystykach cyklicznych. Szczegółowe informacje można znaleźć w „Means and Averaging in the Group of Rotations”, Maher Moakher, SIAM Journal on Matrix Analysis and Applications, tom 24, wydanie 1, 2002.
http://link.aip.org/link/?SJMAEL/24/1/1
Oto funkcja dla GNU Octave 3.2.4, która wykonuje obliczenia:
źródło
Chciałbym udostępnić metodę, której użyłem, z mikrokontrolerem, który nie miał możliwości zmiennoprzecinkowych ani trygonometrycznych. Nadal musiałem „uśrednić” 10 nieprzetworzonych odczytów łożysk, aby wyrównać zmiany.
To nie jest idealne; może się zepsuć. W tym przypadku uszło mi to na sucho, ponieważ urządzenie obraca się bardzo wolno. Opublikuję to na wypadek, gdyby ktoś inny pracował z podobnymi ograniczeniami.
źródło
Po angielsku:
W Pythonie:
Tablica kątów #numpy NX1
źródło
Oto pełne rozwiązanie: (dane wejściowe to tablica namiarów w stopniach (0-360)
źródło
W Pythonie, z kątami pomiędzy [-180, 180)
Detale:
Dla średniej z dwóch kątów istnieją dwie średnie oddalone od siebie o 180 °, ale możemy chcieć bliższej średniej.
Wizualnie, średnia z niebieskiego ( b ) i zielonego ( a ) daje turkusowy punkt:
Kąty „zawijają się” (np. 355 + 10 = 5), ale standardowa arytmetyka ignoruje ten punkt rozgałęzienia. Jeśli jednak kąt b jest przeciwny do punktu rozgałęzienia, to ( b + g ) / 2 daje najbliższą średnią: punkt w kolorze turkusowym.
Dla dowolnych dwóch kątów możemy obrócić zadanie tak, aby jeden z kątów był przeciwny do punktu rozgałęzienia, wykonać standardowe uśrednienie, a następnie obrócić z powrotem.
źródło
Poszedłbym drogą wektorową, używając liczb zespolonych. Mój przykład jest w Pythonie, który ma wbudowane liczby zespolone:
Zwróć uwagę, że Python nie musi tworzyć tymczasowej nowej listy wektorów, wszystkie powyższe można wykonać w jednym kroku; Po prostu wybrałem ten sposób, aby przybliżyć pseudokod mający zastosowanie również w innych językach.
źródło
Oto kompletne rozwiązanie C ++:
Przyjmuje kąty w postaci wektorów podwójnych i zwraca średnią po prostu jako podwójną. Kąty muszą być podane w stopniach i oczywiście średnia jest również w stopniach.
źródło
avgCos
jest średnią ze składników x iavgSin
jest średnią ze składników y. Parametry funkcji arcus tangens toatan2( y, x )
. Więc nie powinien zamiast tego twój kod:atan2( avgSin, avgCos )
??Opierając się na odpowiedzi Alnitaka , napisałem metodę Java do obliczania średniej z wielu kątów:
Jeśli twoje kąty są w radianach:
Jeśli twoje kąty są w stopniach:
źródło
Oto pomysł: utwórz średnią iteracyjnie, zawsze obliczając średnią z kątów, które są najbliżej siebie, zachowując wagę.
Inny pomysł: znajdź największą lukę między podanymi kątami. Znajdź punkt, który dzieli ją na pół, a następnie wybierz przeciwległy punkt na okręgu jako zero odniesienia, na podstawie którego obliczysz średnią.
źródło
Przedstawmy te kąty punktami na obwodzie koła.
Czy możemy założyć, że wszystkie te punkty leżą na tej samej połowie koła? (W przeciwnym razie nie ma oczywistego sposobu zdefiniowania „średniego kąta”. Pomyśl o dwóch punktach na średnicy, np. 0 stopni i 180 stopni - czy średnia wynosi 90 stopni czy 270 stopni? Co się stanie, gdy mamy 3 lub więcej równomiernie rozłożyć punkty?)
Przy takim założeniu jako „początek” wybieramy dowolny punkt na tym półkolu i mierzymy podany zbiór kątów względem tego początku (nazywamy to „kątem względnym”). Zauważ, że względny kąt ma wartość bezwzględną dokładnie mniejszą niż 180 stopni. Na koniec, weź średnią tych kątów względnych, aby uzyskać pożądany średni kąt (w stosunku do naszego pochodzenia oczywiście).
źródło
Nie ma jednej „właściwej odpowiedzi”. Zalecam przeczytanie książki KV Mardia i PE Jupp, „Directional Statistics”, (Wiley, 1999), w celu dokładnej analizy.
źródło
(Chcę tylko podzielić się moim punktem widzenia z teorii szacowania lub wnioskowania statystycznego)
Próba Nimble'a polega na uzyskaniu oszacowania MMSE ^ zestawu kątów, ale jest to jeden z wyborów, aby znaleźć „uśredniony” kierunek; można również znaleźć oszacowanie MMAE ^ lub inne oszacowanie jako kierunek „uśredniony”, i zależy to od twojego kwantyfikującego błędu kierunku; lub bardziej ogólnie w teorii estymacji, definicja funkcji kosztu.
^ MMSE / MMAE odpowiada minimalnemu średniemu kwadratowi / błędowi bezwzględnemu.
ACKB powiedział: "Średni kąt phi_avg powinien mieć taką właściwość, że sum_i | phi_avg-phi_i | ^ 2 staje się minimalny ... coś uśrednia, ale nie kąty"
---- kwantyfikujesz błędy w sensie średniokwadratowym i jest to jeden z najczęściej stosowanych sposobów, ale nie jedyny. Odpowiedź preferowana przez większość ludzi tutaj (tj. Suma wektorów jednostkowych i uzyskanie kąta wyniku) jest w rzeczywistości jednym z rozsądnych rozwiązań. Jest to (można udowodnić) estymator ML, który służy jako "uśredniony" kierunek, jaki chcemy, jeśli kierunki wektorów są modelowane jako rozkład von Misesa. Ta dystrybucja nie jest wyszukana i jest po prostu okresowo próbkowaną dystrybucją z Guassian 2D. Zobacz Eqn. (2.179) w książce Bishopa „Rozpoznawanie wzorców i uczenie maszynowe”. Ponownie, w żadnym wypadku nie jest to jedyny najlepszy kierunek do reprezentowania "średniego" kierunku, jednak jest całkiem rozsądny, który ma zarówno dobre uzasadnienie teoretyczne, jak i prostą implementację.
Zwinny powiedział: „potwierdzenie ma rację, że tych rozwiązań opartych na wektorach nie można uznać za prawdziwe średnie kątów, są one jedynie średnią odpowiedników wektorów jednostkowych”
----to nie jest prawda. „Odpowiedniki wektora jednostkowego” ujawniają informacje o kierunku wektora. Kąt jest wielkością bez uwzględnienia długości wektora, a wektor jednostkowy to coś z dodatkową informacją, że długość wynosi 1. Możesz zdefiniować wektor „jednostkowy” tak, aby miał długość 2, to nie ma znaczenia.
źródło
Oto całkowicie arytmetyczne rozwiązanie wykorzystujące średnie kroczące i zwracające uwagę na normalizację wartości. Jest szybki i dostarcza poprawnych odpowiedzi, jeśli wszystkie kąty są po jednej stronie koła (w granicach 180 ° od siebie).
Jest to równoważne matematycznie z dodaniem przesunięcia, które przesuwa wartości do zakresu (0, 180), obliczeniem średniej, a następnie odjęciem przesunięcia.
Komentarze opisują, jaki zakres może przyjąć określona wartość w danym momencie
źródło
Cóż, jestem ogromnie spóźniony na imprezę, ale pomyślałem, że dodam moje 2 centy, ponieważ nie mogłem znaleźć żadnej ostatecznej odpowiedzi. W końcu zaimplementowałem następującą wersję metody Mitsuta w Javie, która, mam nadzieję, zapewnia proste i solidne rozwiązanie. Zwłaszcza, że odchylenie standardowe zapewnia zarówno dyspersję miary, jak i, jeśli sd == 90, wskazuje, że kąty wejściowe dają niejednoznaczną średnią.
EDYCJA: Właściwie zdałem sobie sprawę, że moja oryginalna implementacja może być jeszcze bardziej uproszczona, w rzeczywistości niepokojąco prosta, biorąc pod uwagę całą rozmowę i trygonometrię, które mają miejsce w innych odpowiedziach.
... a dla wszystkich maniaków (Java), możesz użyć powyższego podejścia, aby uzyskać średni kąt w jednej linii.
źródło
Alnitak ma właściwe rozwiązanie. Rozwiązanie Nicka Fortescue jest funkcjonalnie takie samo.
W szczególnym przypadku gdzie
(sum (x_component) = 0,0 && sum (y_component) = 0,0) // np. 2 kąty po 10 i 190 stopni.
użyj sumy 0,0 stopni
Obliczeniowo musisz przetestować ten przypadek, ponieważ atan2 (0., 0) jest niezdefiniowane i spowoduje błąd.
źródło
Średni kąt phi_avg powinien mieć taką właściwość, że sum_i | phi_avg-phi_i | ^ 2 staje się minimalny, gdzie różnica musi być w [-Pi, Pi) (ponieważ może być krótsza, aby przejść na drugą stronę!). Można to łatwo osiągnąć poprzez normalizację wszystkich wartości wejściowych do [0, 2Pi), utrzymanie bieżącej średniej phi_run i wybranie normalizacji | phi_i-phi_run | do [-Pi, Pi) (dodając lub odejmując 2Pi). Większość powyższych sugestii robi coś innego, co nie ma tej minimalnej właściwości, tj. Uśrednia coś , ale nie kąty.
źródło
Rozwiązałem problem z pomocą odpowiedzi od @David_Hanak. Jak stwierdza:
Więc obliczyłem średnią wszystkich kątów. A potem wszystkie kąty, które są mniejsze, zwiększ je o 360. Następnie oblicz ponownie średnią, dodając je wszystkie i dzieląc przez ich długość.
Działa świetnie.
źródło
Funkcja Pythona:
źródło
Możesz użyć tej funkcji w Matlabie:
źródło
Możesz zobaczyć rozwiązanie i małe wyjaśnienie w poniższym linku, dla DOWOLNEGO języka programowania: https://rosettacode.org/wiki/Aagues/Mean_angle
Na przykład rozwiązanie C ++ :
Wynik:
Lub rozwiązanie Matlab :
źródło
Chociaż odpowiedź Starblue'a podaje kąt średniego wektora jednostkowego, możliwe jest rozszerzenie pojęcia średniej arytmetycznej na kąty, jeśli przyjmiesz, że może istnieć więcej niż jedna odpowiedź w zakresie od 0 do 2 * pi (lub od 0 ° do 360 °). Na przykład, średnia 0 ° i 180 ° może wynosić 90 ° lub 270 °.
Średnia arytmetyczna ma tę właściwość, że jest pojedynczą wartością z minimalną sumą kwadratów odległości do wartości wejściowych. Odległość wzdłuż okręgu jednostkowego między dwoma wektorami jednostkowymi można łatwo obliczyć jako odwrotność cosinusa ich iloczynu skalarnego. Jeśli wybierzemy wektor jednostkowy, minimalizując sumę kwadratu odwrotnego cosinusa iloczynu skalarnego naszego wektora i każdego wejściowego wektora jednostkowego, otrzymamy równoważną średnią. Pamiętaj, że w wyjątkowych przypadkach mogą obowiązywać dwa lub więcej minimum.
Pojęcie to można rozszerzyć na dowolną liczbę wymiarów, ponieważ odległość wzdłuż sfery jednostkowej można obliczyć dokładnie w taki sam sposób, jak odległość wzdłuż okręgu jednostkowego - odwrotność cosinusa iloczynu skalarnego dwóch wektorów jednostkowych.
Dla okręgów możemy rozwiązać tę średnią na wiele sposobów, ale proponuję następujący algorytm O (n ^ 2) (kąty są w radianach, a ja unikam obliczania wektorów jednostkowych):
Jeśli wszystkie kąty znajdują się w granicach 180 ° od siebie, możemy użyć prostszego algorytmu O (n) + O (sort) (ponownie używając radianów i unikając wektorów jednostkowych):
Aby użyć stopni, po prostu zamień pi na 180. Jeśli planujesz użyć większej liczby wymiarów, najprawdopodobniej będziesz musiał użyć metody iteracyjnej w celu obliczenia średniej.
źródło
Problem jest niezwykle prosty. 1.Upewnij się, że wszystkie kąty mieszczą się w przedziale od -180 do 180 stopni. 2. a Dodaj wszystkie kąty nieujemne, weź ich średnią i LICZ ile 2. b. Dodaj wszystkie kąty ujemne, weź ich średnią i LICZ ile. 3. Weź różnicę pos_average minus neg_average Jeśli różnica jest większa niż 180, zmień różnicę na 360 minus różnica. W przeciwnym razie po prostu zmień znak różnicy. Zauważ, że różnica jest zawsze nieujemna. Average_Angle równa się pos_average plus różnica razy „waga”, ujemna liczba podzielona przez sumę ujemnej i dodatniej liczby
źródło
Oto trochę kodu Java do średnich kątów, myślę, że jest dość solidny.
źródło
Mam inną metodę niż @Starblue, która daje „poprawne” odpowiedzi na niektóre z powyższych kątów. Na przykład:
Wykorzystuje sumę różnic między kolejnymi kątami. Kod (w Matlabie):
źródło
[-90,90,40]
i[90,-90,40]
; Nie sądzę, aby nieprzemienna średnia była bardzo użyteczna.