Muszę obliczyć przykładową odległość Mahalanobisa w R pomiędzy każdą parą obserwacji w macierzy współzmiennych . Potrzebuję rozwiązania, które jest wydajne, tj. Obliczane są tylko odległości, a najlepiej realizowane w C / RCpp / Fortran itp. Zakładam, że , macierz kowariancji populacyjnej, jest nieznana i wykorzystuję próbkę macierz kowariancji na swoim miejscu.n ( n - 1 ) / 2 Σ
Szczególnie interesuje mnie to pytanie, ponieważ wydaje się, że nie ma metody „konsensusu” do obliczania par Mahalanobisa w parach odległości R, tj. Nie jest ona zaimplementowana dist
ani w funkcji, ani w cluster::daisy
funkcji. Ta mahalanobis
funkcja nie oblicza odległości parami bez dodatkowej pracy programisty.
Zostało to już zadane tutaj Odległość Pairwise Mahalanobis w R , ale rozwiązania tam wydają się nieprawidłowe.
Oto poprawna, ale strasznie nieefektywna (ponieważ obliczane są odległości ):
set.seed(0)
x0 <- MASS::mvrnorm(33,1:10,diag(c(seq(1,1/2,l=10)),10))
dM = as.dist(apply(x0, 1, function(i) mahalanobis(x0, i, cov = cov(x0))))
Łatwo jest to napisać w C, ale wydaje mi się, że coś podstawowego powinno mieć wcześniej istniejące rozwiązanie. Czy jest jeden
Istnieją inne rozwiązania, które nie są wystarczające : HDMD::pairwise.mahalanobis()
oblicza odległości, gdy wymagane są tylko unikalne odległości. compositions::MahalanobisDist()
wydaje się obiecujące, ale nie chcę, aby moja funkcja pochodziła z pakietu, który zależy rgl
, co poważnie ogranicza możliwość uruchamiania mojego kodu przez innych. Jeśli ta implementacja nie jest idealna, wolę napisać własną. Czy ktoś ma doświadczenie w tej funkcji?
źródło
Odpowiedzi:
Zaczynając od rozwiązania „succint” firmy ahfoss, użyłem rozkładu Cholesky'ego zamiast SVD.
Powinno być szybciej, ponieważ rozwiązywanie do przodu układu trójkątnego jest szybsze niż gęste mnożenie macierzy z odwrotną kowariancją ( patrz tutaj ). Oto testy porównawcze rozwiązań ahfoss i whuber w kilku ustawieniach:
Cholesky wydaje się być jednakowo szybszy.
źródło
Standardowa formuła dla kwadratowej odległości Mahalanobisa między dwoma punktami danych to
gdzie jest wektorem p × 1 odpowiadającym obserwacji i . Zazwyczaj macierz kowariancji jest szacowana na podstawie zaobserwowanych danych. Nie licząc inwersję macierzy, ta operacja wymaga P 2 + p mnożenia i P 2 + 2 s dodatki, każdy powtarzane n ( n - 1 ) / 2 razy.xi p×1 i p2+p p2+2p n(n−1)/2
Rozważ następujące wyprowadzenie:
gdzie . Zauważ, żexTiΣ-1qi=Σ−12xi . Zależy to od faktu, żeΣ-1xTiΣ−12=(Σ−12xi)T=qTi jest symetryczny, co wynika z faktu, że dla dowolnej symetrycznej macierzy diagonalnejA=PEPT,Σ−12 A=PEPT
Jeśli pozwolimy i zauważymy , że Σ - 1 jest symetryczny, widzimy, że Σ - 1A=Σ−1 Σ−1 musi być również symetryczne. JeśliXjestmacierząn×pobserwacji, aQjestmacierząn×ptaką, żeithrzęduQwynosiqi, wówczasQmożna zwięźle wyrazić jakoXΣ-1Σ−12 X n×p Q n×p ith Q qi Q . To i poprzednie wyniki implikują toXΣ−12
jedynymi operacjami, które są obliczane n ( n - 1 ) / 2 razy, sąmnożenia p i dodawania 2 p (w przeciwieństwie domnożenia p 2 + p oraz p 2 + 2 p
źródło
pair.diff()
znaczy, a także podać numeryczny przykład z wydrukami każdego kroku twojej funkcji? Dzięki.Spróbujmy tego, co oczywiste. Od
wynika z tego, że możemy obliczyć wektor
w czasie i macierzyO(p2)
w czasie , najprawdopodobniej przy użyciu wbudowanych szybkich (równoległych) operacji tablicowych, a następnie utwórz rozwiązanie jakoO(pn2+p2n)
gdzie jest iloczynem zewnętrznym w odniesieniu do + : ( a ⊕ b ) i j = a i + b j .⊕ + (a⊕b)ij=ai+bj.
R
Realizacja zwięźle paralele sformułowanie matematycznego (a zakłada się z nim, że rzeczywiście jest odwracalna z odwrotnym pisemnej godz tutaj):Należy zwrócić uwagę, że w celu zapewnienia zgodności z innymi rozwiązaniami zwracane są tylko unikalne elementy o przekątnej, a nie cała kwadratowa macierz odległości (symetryczna, zero na przekątnej). Wykresy rozrzutu pokazują, że jego wyniki są zgodne z wynikami
fastPwMahal
.W języku C i C ++, pamięć RAM może być ponownie użyty, a oblicza się na bieżąco, eliminując potrzebę stosowania pośredniego składowania u ⊕ u .u⊕u u⊕u
Badania czasowe z zakresie od 33 do 5000 i p w zakresie od 10 do 100 wskazują, że ta implementacja jest 1,5 do 5 razy szybsza niż w tym zakresie. Poprawa poprawia się wraz ze wzrostem wartości p i n . W związku z tym możemy spodziewać się wyższego poziomu dla mniejszych p . Próg rentowności występuje w okolicach p = 7 dla n ≥ 100n 33 5000 p 10 100 1.5 5 p n p p=7 n≥100 . To, czy te same zalety obliczeniowe tego prostego rozwiązania dotyczą innych implementacji, może zależeć od tego, jak dobrze wykorzystują one wektoryzowane operacje tablicowe.
fastPwMahal
fastPwMahal
źródło
apply
iouter
... z wyjątkiem wybuchuRcpp
.R
nie wydaje się, że nic z tego można zyskać.Jeśli chcesz obliczyć przykładową odległość Mahalanobisa, istnieje kilka sztuczek algebraicznych, które możesz wykorzystać. Wszystkie prowadzą do obliczenia par euklidesowych odległości, więc załóżmy, że możemyX n×p p O(np)
dist()
do tego użyć . Niech oznacza macierz danych n × p , która, jak zakładamy, jest wyśrodkowana, tak że jej kolumny mają średnią 0, i ma rangę p, tak że macierz kowariancji próbki nie jest pojedyncza. (Centrowanie wymaga operacji O ( n p ) .) Następnie macierz kowariancji próbki to S = X T X / n .Próbki Mahalanobisa w parach są takie same, jak pary X w euklidesowej odległości XX dla każdej macierzy L zgodnej L L T = S - 1 , na przykład pierwiastka lub czynnik Choleskiego. Wynika to z pewnej algebry liniowej i prowadzi do algorytmu wymagającego obliczenia S , S - 1 i rozkładu Choleskiego. W najgorszym przypadku złożoność to O ( n p 2 + p 3 ) .
Oto implementacja R drugiej metody, której nie mogę przetestować na iPadzie, której używam do napisania tej odpowiedzi.
źródło
To jest znacznie bardziej zwięzłe rozwiązanie. Wciąż opiera się na wyprowadzeniu obejmującym macierz kowariancji odwrotnego pierwiastka kwadratowego (patrz moja inna odpowiedź na to pytanie), ale używa tylko podstawy R i pakietu statystyk. Wydaje się być nieco szybszy (około 10% szybciej w niektórych testach, które przeprowadziłem). Zauważ, że zwraca odległość Mahalanobisa, w przeciwieństwie do kwadratowej odległości Maha.
Ta funkcja wymaga odwrotnej macierzy kowariancji i nie zwraca obiektu odległości - ale podejrzewam, że ta zredukowana wersja funkcji będzie bardziej użyteczna do układania użytkowników na stosie.
źródło
SQRT
rozkład Cholesky'egochol(invCovMat)
.Jeśli używasz tylko funkcji Fortran77 w interfejsie, twój podprogram jest wciąż wystarczająco przenośny dla innych.
źródło
Jest to bardzo prosty sposób, aby to zrobić za pomocą pakietu R „biotools”. W takim przypadku otrzymasz Matrycę Mahalanobisa o kwadracie odległości.
źródło
To jest ten rozszerzony kod, który moja stara odpowiedź przeniosła tutaj z innego wątku .
Od dłuższego czasu wykonuję obliczenia kwadratowej macierzy symetrycznej par Mahalanobisa w parach odległości w SPSS metodą macierzy kapelusza, stosując rozwiązanie układu równań liniowych (ponieważ jest ono szybsze niż odwracanie macierzy kowariancji).
Nie jestem użytkownikiem R, więc właśnie próbowałem odtworzyć @ahfoss ' ten przepis tutaj w SPSS wraz z „moim” przepisem, na danych 1000 przypadków przez 400 zmiennych, i znalazłem swoją drogę znacznie szybciej.
Szybszy sposób na obliczenie pełnej macierzy par Mahalanobisa w parach jest już zakończonyH
Tak więc wyśrodkuj kolumny macierzy danych, oblicz macierz kapelusza, pomnóż ją przez (n-1) i wykonaj operację przeciwną do podwójnego centrowania. Otrzymujesz macierz kwadratowych odległości Mahalanobisa.
W naszych ustawieniach „podwójnie centrowana” macierz jest w szczególności macierzą kapelusza (pomnożoną przez n-1), a nie euklidesowymi produktami skalarnymi, a wynikowa kwadratowa macierz odległości jest zatem kwadratową macierzą odległości Mahalanobisa, a nie kwadratową macierzą odległości euklidesową.
H= {H,H,...}
Kod w SPSS i czujniku prędkości znajduje się poniżej.
Ten pierwszy kod odpowiada @ahfoss funkcji
fastPwMahal
w cytowanej odpowiedzi . Jest to równoważne matematycznie. Ale obliczam pełną symetryczną macierz odległości (za pomocą operacji macierzowych), podczas gdy @ahfoss obliczył trójkąt macierzy symetrycznej (element po elemencie).Oto moja modyfikacja, aby przyspieszyć:
solve(X'X,X')
źródło
Opublikowana formuła nie oblicza tego, co według Ciebie obliczasz (statystyki U).
W opublikowanym przeze mnie kodzie używam
cov(x1)
jako macierzy skalowania (jest to wariancja różnic par danych). Używaszcov(x0)
(jest to macierz kowariancji oryginalnych danych). Myślę, że to błąd z twojej strony. Chodzi o to, żeby wykorzystać różnice par, ponieważ odciąża cię to od założenia, że wielowymiarowy rozkład twoich danych jest symetryczny wokół środka symetrii (lub żeby oszacować to centrum symetrii pod tym względem, ponieważcrossprod(x1)
jest proporcjonalnecov(x1)
). Oczywiście przez użyciecov(x0)
tracisz to.Jest to dobrze wyjaśnione w artykule, do którego odsyłam w mojej oryginalnej odpowiedzi.
źródło
Matteo Fasiolo
(i zakładam)whuber
w tym wątku. Twój jest inny. Byłbym zainteresowany zrozumieniem tego, co obliczasz, ale wyraźnie różni się on od dystansu Mahalanobisa, jak zwykle definiuje się.cov(x0)