Testowanie liniowej zależności między kolumnami macierzy

26

Mam macierz korelacji zwrotów bezpieczeństwa, których wyznacznikiem jest zero. (Jest to nieco zaskakujące, ponieważ macierz korelacji próbki i odpowiadająca jej macierz kowariancji powinny teoretycznie być określone dodatnio).

Moja hipoteza jest taka, że ​​co najmniej jedno zabezpieczenie jest liniowo zależne od innych papierów wartościowych. Czy w R jest funkcja, która sekwencyjnie testuje każdą kolumnę pod kątem macierzy zależności liniowej?

Na przykład jednym podejściem byłoby zbudowanie macierzy korelacji po jednym zabezpieczeniu na raz i obliczenie wyznacznika na każdym etapie. Gdy wyznacznik = 0, zatrzymaj się, gdy zidentyfikujesz papier wartościowy, który jest liniową kombinacją innych papierów wartościowych.

Doceniane są wszelkie inne techniki identyfikacji zależności liniowej w takiej macierzy.

Ram Ahluwalia
źródło
Twoja macierz jest dodatnia półokreślona, ​​jednak nie jest dodatnia, ponieważ jest pojedyncza.
ttnphns
Jakie są wymiary (liczba zmiennych; liczba próbek)?
Karl
Liczba kolumn = 480. Liczba wierszy dla każdej serii czasowej = 502. Zasadniczo okazuje się, że im większa seria czasowa, tym macierz kowariancji próbki ma tendencję do określania dodatniego. Istnieje jednak wiele przypadków, w których chciałbyś zastosować znacznie mniejszą wartość T (lub wykładniczą wagę), aby odzwierciedlić ostatnie warunki rynkowe.
Ram Ahluwalia,
3
Pytanie jest źle postawione. Jeśli macierz danych ma 480 na 502, to powiedzenie, że macierz ma rangę (przestrzeń kolumny macierzy ma wymiar q < 480 ), jest matematycznie równoważne ze stwierdzeniem, że jedna kolumna jest liniową kombinacją innych, ale można nie wybieraj jednej kolumny i mów, że jest to kolumna zależna liniowo. Nie ma więc procedury, aby to zrobić, a sugerowana procedura wybierze dość arbitralne zabezpieczenia w zależności od kolejności, w jakiej zostaną uwzględnione. q<480q<480
NRH
Macierz kowariancji jest symetryczna. Jest generowany przez transpozycję (A) * A. Matryca A ma wymiary 480 x 502. Jednak macierz kowariancji to 480 x 480
Ram Ahluwalia,

Odpowiedzi:

6

Wydaje się, że zadajesz naprawdę prowokujące pytanie: jak wykryć, biorąc pod uwagę szczególną macierz korelacji (lub kowariancję, lub sumę kwadratów i iloczynu), która kolumna jest liniowo zależna od tego. Przypuszczam, że operacja zamiatania mogłaby pomóc. Oto moja sonda w SPSS (nie R) do zilustrowania.

Wygenerujmy trochę danych:

        v1        v2        v3         v4          v5
    -1.64454    .35119   -.06384    -1.05188     .25192
    -1.78520   -.21598   1.20315      .40267    1.14790
     1.36357   -.96107   -.46651      .92889   -1.38072
     -.31455   -.74937   1.17505     1.27623   -1.04640
     -.31795    .85860    .10061      .00145     .39644
     -.97010    .19129   2.43890     -.83642    -.13250
     -.66439    .29267   1.20405      .90068   -1.78066
      .87025   -.89018   -.99386    -1.80001     .42768
    -1.96219   -.27535    .58754      .34556     .12587
    -1.03638   -.24645   -.11083      .07013    -.84446

Stwórzmy liniową zależność między V2, V4 i V5:

compute V4 = .4*V2+1.2*V5.
execute.

Zmodyfikowaliśmy naszą kolumnę V4.

matrix.
get X. /*take the data*/
compute M = sscp(X). /*SSCP matrix, X'X; it is singular*/
print rank(M). /*with rank 5-1=4, because there's 1 group of interdependent columns*/
loop i= 1 to 5. /*Start iterative sweep operation on M from column 1 to column 5*/
-compute M = sweep(M,i).
-print M. /*That's printout we want to trace*/
end loop.
end matrix.

Wydruki M w 5 iteracjach:

M
     .06660028    -.12645565    -.54275426    -.19692972    -.12195621
     .12645565    3.20350385    -.08946808    2.84946215    1.30671718
     .54275426    -.08946808    7.38023317   -3.51467361   -2.89907198
     .19692972    2.84946215   -3.51467361   13.88671851   10.62244471
     .12195621    1.30671718   -2.89907198   10.62244471    8.41646486

M
     .07159201     .03947417    -.54628594    -.08444957    -.07037464
     .03947417     .31215820    -.02792819     .88948298     .40790248
     .54628594     .02792819    7.37773449   -3.43509328   -2.86257773
     .08444957    -.88948298   -3.43509328   11.35217042    9.46014202
     .07037464    -.40790248   -2.86257773    9.46014202    7.88345168

M
    .112041875    .041542117    .074045215   -.338801789   -.282334825
    .041542117    .312263922    .003785470    .876479537    .397066281
    .074045215    .003785470    .135542964   -.465602725   -.388002270
    .338801789   -.876479537    .465602725   9.752781632   8.127318027
    .282334825   -.397066281    .388002270   8.127318027   6.772765022

M
   .1238115070   .0110941027   .0902197842   .0347389906   .0000000000
   .0110941027   .3910328733  -.0380581058  -.0898696977  -.3333333333
   .0902197842  -.0380581058   .1577710733   .0477405054   .0000000000
   .0347389906  -.0898696977   .0477405054   .1025348498   .8333333333
   .0000000000   .3333333333   .0000000000  -.8333333333   .0000000000

M
   .1238115070   .0110941027   .0902197842   .0347389906   .0000000000
   .0110941027   .3910328733  -.0380581058  -.0898696977   .0000000000
   .0902197842  -.0380581058   .1577710733   .0477405054   .0000000000
   .0347389906  -.0898696977   .0477405054   .1025348498   .0000000000
   .0000000000   .0000000000   .0000000000   .0000000000   .0000000000

Zauważ, że ostatecznie kolumna 5 zapełniła się zerami. Oznacza to (jak rozumiem), że V5 jest liniowo związany z niektórymi poprzednimi kolumnami. Które kolumny? Spójrz na iterację, w której ostatnia kolumna 5 nie jest pełna zer - iteracja 4. Widzimy tam, że V5 jest powiązane z V2 i V4 o współczynnikach -3333 i .8333: V5 = -33333 * V2 + .8333 * V4, co odpowiada do tego, co zrobiliśmy z danymi: V4 = .4 * V2 + 1.2 * V5.

W ten sposób wiedzieliśmy, która kolumna jest liniowo powiązana z którą inną. Nie sprawdziłem, jak pomocne jest powyższe podejście w bardziej ogólnym przypadku z wieloma grupami współzależności w danych. W powyższym przykładzie okazało się to jednak pomocne.

ttnphns
źródło
Czy to nie jest forma zredukowanego rzędu rzędów? Jeśli tak, to czy nie są dostępne pakiety / funkcje w R?
Arun
@Arun, nie jestem użytkownikiem R, więc nie mogę wiedzieć.
ttnphns
25

Oto proste podejście: oblicz rangę macierzy wynikającą z usunięcia każdej kolumny. Kolumny, które po usunięciu dają najwyższą rangę, są liniowo zależne (ponieważ usunięcie ich nie zmniejsza rangi, a usunięcie liniowo niezależnej kolumny powoduje).

W R:

rankifremoved <- sapply(1:ncol(your.matrix), function (x) qr(your.matrix[,-x])$rank)
which(rankifremoved == max(rankifremoved))
James
źródło
1
Niezwykle przydatna odpowiedź przy określaniu obrażającej kolumny w macierzy regresji, w której otrzymałem błąd system is exactly singular: U[5,5] = 0 , który, jak wiem, oznacza, że ​​problemem była kolumna 5 (wydaje się oczywista z perspektywy czasu, ponieważ jest to kolumna zer!)
Matt Weller,
W komentarzu Jamesa opublikował skrypt: rankifremoved <- sapply (1: ncol (your.matrix), function (x) qr (your.matrix [, - x]) $ rank), który (rankifremoved == max ( rankifremoved)) Zrobiłem test na macierzy, chciałbym wiedzieć na wyjściu R. Kolumny wyjścia są liniowo zależne? Podziękować!
@ EltonAraújo: Wyjście będzie wektorem podającym wskaźniki kolumn zależnych liniowo: so (2,4,5) na przykład w odpowiedzi ttnphns. Zastanawiam się jednak, w jaki sposób kwestie precyzji liczbowej wpłyną na tę metodę.
Scortchi - Przywróć Monikę
rankifremoved zawiera wszystkie kolumny, które są liniowo zależne między nimi lub między nimi. W niektórych aplikacjach możemy chcieć zachować kolumnę lub kilka kolumn i nie upuszczać wszystkich
MasterJedi
Czy to nie powinno zwrócić pustego zestawu your.matrix = matrix(1:4, 2)?
Holger Brandl,
15

Pytanie dotyczy „identyfikowania podstawowych [liniowych] zależności” między zmiennymi.

Szybkim i łatwym sposobem na wykrycie związków jest regresja dowolnej innej zmiennej (użycie stałej, nawet) względem tych zmiennych za pomocą ulubionego oprogramowania: każda dobra procedura regresji wykryje i zdiagnozuje kolinearność. (Nie będziesz nawet zawracał sobie głowy spoglądaniem na wyniki regresji: polegamy tylko na użytecznym skutku ubocznym konfiguracji i analizy macierzy regresji.)

Przy założeniu wykrycia kolinearności, co dalej? Analiza głównych składników (PCA) jest dokładnie tym, czego potrzeba: jej najmniejsze składniki odpowiadają relacjom prawie liniowym. Zależności te można odczytać bezpośrednio z „obciążeń”, które są liniowymi kombinacjami pierwotnych zmiennych. Małe ładunki (to znaczy te związane z małymi wartościami własnymi) odpowiadają prawie kolinearnościom. Wartość własna odpowiadałaby idealnej relacji liniowej. Nieco większe wartości własne, które są nadal znacznie mniejsze niż największe, odpowiadają przybliżonym relacjom liniowym.0

(Istnieje sztuka i sporo literatury związanej z identyfikowaniem, czym jest „małe” obciążenie. W celu modelowania zmiennej zależnej sugerowałbym włączenie jej do zmiennych niezależnych w PCA w celu identyfikacji składników - niezależnie od ich rozmiary - w których zmienna zależna odgrywa ważną rolę. Z tego punktu widzenia „mały” oznacza znacznie mniejszy niż jakikolwiek taki element.)


Spójrzmy na kilka przykładów. (Te służą Rdo obliczeń i kreślenia.) Rozpocznij od funkcji wykonywania PCA, wyszukiwania małych komponentów, kreślenia ich i zwracania między nimi relacji liniowych.

pca <- function(x, threshold, ...) {
  fit <- princomp(x)
  #
  # Compute the relations among "small" components.
  #
  if(missing(threshold)) threshold <- max(fit$sdev) / ncol(x)
  i <- which(fit$sdev < threshold)
  relations <- fit$loadings[, i, drop=FALSE]
  relations <- round(t(t(relations) / apply(relations, 2, max)), digits=2)
  #
  # Plot the loadings, highlighting those for the small components.
  #
  matplot(x, pch=1, cex=.8, col="Gray", xlab="Observation", ylab="Value", ...)
  suppressWarnings(matplot(x %*% relations, pch=19, col="#e0404080", add=TRUE))

  return(t(relations))
}

b,do,re,miZA

process <- function(z, beta, sd, ...) {
  x <- z %*% beta; colnames(x) <- "A"
  pca(cbind(x, z + rnorm(length(x), sd=sd)), ...)
}

b,,miZA=b+do+re+miZA=b+(do+re)/2)+misweep

n.obs <- 80 # Number of cases
n.vars <- 4 # Number of independent variables
set.seed(17)
z <- matrix(rnorm(n.obs*(n.vars)), ncol=n.vars)
z.mean <- apply(z, 2, mean)
z <- sweep(z, 2, z.mean)
colnames(z) <- c("B","C","D","E") # Optional; modify to match `n.vars` in length

b,,miZA

Wyniki

Dane wyjściowe związane z lewym górnym panelem to

       A  B  C  D  E
Comp.5 1 -1 -1 -1 -1

00ZA-b-do-re-mi

Wyjście dla górnego środkowego panelu było

       A     B     C     D     E
Comp.5 1 -0.95 -1.03 -0.98 -1.02

(ZA,b,do,re,mi)

       A     B     C     D     E
Comp.5 1 -1.33 -0.77 -0.74 -1.07

ZA=b+do+re+mi

1,1/2),1/2),1

W praktyce często nie jest tak, że jedną zmienną wyróżnia się jako oczywistą kombinację pozostałych: wszystkie współczynniki mogą mieć porównywalne rozmiary i różne znaki. Ponadto, gdy istnieje więcej niż jeden wymiar relacji, nie ma unikalnego sposobu ich określenia: konieczna jest dalsza analiza (taka jak redukcja wierszy) w celu zidentyfikowania użytecznej podstawy dla tych relacji. Tak działa świat: wszystko, co możesz powiedzieć, to to, że te konkretne kombinacje, które są generowane przez PCA, prawie nie zmieniają danych. Aby sobie z tym poradzić, niektóre osoby wykorzystują największe („główne”) komponenty bezpośrednio jako zmienne niezależne w regresji lub późniejszej analizie, bez względu na to, jaką by ona nie przyjęła. Jeśli to zrobisz, nie zapomnij najpierw usunąć zmiennej zależnej z zestawu zmiennych i powtórzyć PCA!


Oto kod do odtworzenia tej liczby:

par(mfrow=c(2,3))
beta <- c(1,1,1,1) # Also can be a matrix with `n.obs` rows: try it!
process(z, beta, sd=0, main="A=B+C+D+E; No error")
process(z, beta, sd=1/10, main="A=B+C+D+E; Small error")
process(z, beta, sd=1/3, threshold=2/3, main="A=B+C+D+E; Large error")

beta <- c(1,1/2,1/2,1)
process(z, beta, sd=0, main="A=B+(C+D)/2+E; No error")
process(z, beta, sd=1/10, main="A=B+(C+D)/2+E; Small error")
process(z, beta, sd=1/3, threshold=2/3, main="A=B+(C+D)/2+E; Large error")

(Musiałem manipulować progiem w przypadkach o dużym błędzie, aby wyświetlić tylko jeden komponent: to jest powód podania tej wartości jako parametru process).


Użytkownik ttnphns uprzejmie skierował naszą uwagę na ściśle powiązany wątek. Jedna z odpowiedzi (autorstwa JM) sugeruje opisane tutaj podejście.

Whuber
źródło
Wow, oto, co rozumiem z twojej odpowiedzi .. regresuj moje zmienne względem dowolnej innej zmiennej. Użyj VIF, a następnie zmienne związane z identyfikatorem. To działa. Czy najlepiej robić to jednocześnie z częściami danych? Czy usuwasz także coś, jeśli wykryjesz kolinearność za pomocą regresji wcześniej? Z tego, co rozumiem na temat PCA, ogólnie rzecz biorąc, używasz największych komputerów PC (wyjaśniając najwięcej wariancji) w oparciu o wartości własne, ponieważ wyjaśniają one większość wariancji, są one ładowane do różnych stopnie przy użyciu oryginalnych zmiennych. Nie jestem pewien, z jakimi małymi ładunkami i czym są kolinearne
Samuel
Ta odpowiedź wyjaśnia, jak interpretować małe elementy: wykazują one współliniowości. Tak, jeśli chcesz, możesz użyć podgrup zmiennych. Metoda regresji polega jedynie na wykryciu obecności kolinearności, a nie na identyfikacji zależności kolinearnych: to właśnie robi PCA.
whuber
"loadings," which are linear combinations of the original variablesZAZA-1
Czy mogę również poprosić o pozostawienie opinii o możliwym zastosowaniu operacji zamiatania ( stats.stackexchange.com/a/16391/3277 ) w zadaniu śledzenia liniowo zależnych podzbiorów zmiennych?
ttnphns
XX=UW.V.V.princompXV.=UW.W.UW.0XV.X
5

502×480

JM nie jest statystykiem
źródło
3

Zetknąłem się z tym problemem około dwa tygodnie temu i zdecydowałem, że muszę go ponownie odwiedzić, ponieważ w przypadku ogromnych zestawów danych niemożliwe jest zrobienie tych rzeczy ręcznie.

Utworzyłem pętlę for (), która oblicza pozycję macierzy po jednej kolumnie na raz. Tak więc dla pierwszej iteracji ranga będzie wynosić 1. Druga, 2. Dzieje się tak, dopóki ranga nie będzie MNIEJSZA niż numer kolumny, którego używasz.

Bardzo proste:

for (i in 1:47) {

  print(qr(data.frame[1:i])$rank) 
  print(i) 
  print(colnames(data.frame)[i])
  print("###") 
}

podział pętli for ()

  1. oblicza rangę dla i-tej kolumny
  2. wypisuje numer iteracji
  3. wypisuje nazwę kolumny w celach informacyjnych
  4. dzieli konsolę na „###”, aby można było łatwo przewijać

Jestem pewien, że możesz dodać instrukcję if, nie potrzebuję jej jeszcze, ponieważ mam do czynienia tylko z 50 kolumnami.

Mam nadzieję że to pomoże!

Nick P.
źródło
2
Chociaż teoretycznie nie ma w tym nic złego, jest to algorytm niestabilny numerycznie i nieefektywny. Zwłaszcza w przypadku dużej liczby kolumn może nie wykryć kolinearności bliskiej i fałszywie wykryć kolinearność tam, gdzie jej nie ma.
whuber
2

Ranga matrycy = liczba liniowo niezależnych kolumn (lub rzędów) macierzy. O n o n macierzy A , stopień (A) = n => (wszystkie kolumny i rzędy) są liniowo niezależne.

Bieg
źródło
2

Nie chodzi o to, że odpowiedź udzielona przez Whuber naprawdę wymaga rozszerzenia, ale pomyślałem, że przedstawię krótki opis matematyki.

XXv=0v0vXXλ=0XXXXXλ=0XXvλ

κjot=λmzaxλjot

XX=[0,0010000,0010000,001].
λ1=λ2)=λ3)=0,001
κ=λmzaxλmjan=1

Cytowania

Montgomery, D. (2012). Wprowadzenie do analizy regresji liniowej, wydanie 5. John Wiley & Sons Inc.

tjnel
źródło
1
X
QRXnkn>>kXR