Jak zmienić kolejność danych 2D, aby uzyskać korelację?

9

Mam następujący prosty zestaw danych z dwiema zmiennymi ciągłymi; to znaczy:

d = data.frame(x=runif(100,0,100),y = runif(100,0,100))
plot(d$x,d$y)
abline(lm(y~x,d), col="red")
cor(d$x,d$y) # = 0.2135273

Podstawowa dystrybucja

Muszę zmienić dane tak, aby korelacja między zmiennymi wynosiła ~ 0,6. Muszę utrzymać średnie i inne statystyki opisowe (sd, min, max itp.) Obu zmiennych na stałym poziomie.

Wiem, że możliwe jest dokonanie prawie dowolnej korelacji z podanymi danymi, tj .:

d2 = with(d,data.frame(x=sort(x),y=sort(y)))
plot(d2$x,d2$y)
abline(lm(y~x,d2), col="red")
cor(d2$x,d2$y) # i.e. 0.9965585

wprowadź opis zdjęcia tutaj

Jeśli spróbuję użyć samplefunkcji do tego zadania:

cor.results = c()
for(i in 1:1000){
    set.seed(i)
    d3 = with(d,data.frame(x=sample(x),y=sample(y)))
    cor.results =  c(cor.results,cor(d3$x,d3$y))
}

Dostaję dość szeroki zakres korelacji:

> summary(cor.results)
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
-0.281600 -0.038330 -0.002498 -0.001506  0.034380  0.288800

ale ten zakres zależy od liczby wierszy w ramce danych i maleje wraz ze wzrostem wielkości.

> d = data.frame(x=runif(1000,0,100),y = runif(1000,0,100))
> cor.results = c()
> for(i in 1:1000){
+ set.seed(i)
+ d3 = with(d,data.frame(x=sample(x),y=sample(y)))
+ cor.results =  c(cor.results,cor(d3$x,d3$y))
+ }
> summary(cor.results)
      Min.    1st Qu.     Median       Mean    3rd Qu.       Max. 
-0.1030000 -0.0231300 -0.0005248 -0.0005547  0.0207000  0.1095000

Moje pytanie brzmi:

Jak zmienić porządek takiego zestawu danych, aby uzyskać korelację (tj. 0,7)? (Dobrze będzie również, jeśli metoda usunie zależność od rozmiaru zestawu danych)

Jurij Pietrowski
źródło

Odpowiedzi:

6

Oto jeden ze sposobów zmiany kolejności danych, oparty na generowaniu dodatkowych liczb losowych.

Pobieramy próbki z dwuwymiarowego rozkładu normalnego z określoną korelacją. Następnie obliczamy szeregi i wartości otrzymujemy. Rangi te służą do porządkowania oryginalnych wartości. W tym podejściu mamy najlepsze sortowanie zarówno oryginalnych wartości i .xyxy

Najpierw tworzymy rzeczywisty zestaw danych (jak w twoim przykładzie).

set.seed(1)
d <- data.frame(x = runif(100, 0, 100), y = runif(100, 0, 100))

cor(d$x, d$y)
# [1] 0.01703215

Teraz określamy macierz korelacji.

corr <- 0.7  # target correlation
corr_mat <- matrix(corr, ncol = 2, nrow = 2)
diag(corr_mat) <- 1
corr_mat
#      [,1] [,2]
# [1,]  1.0  0.7
# [2,]  0.7  1.0

Generujemy losowe dane według dwuwymiarowego rozkładu normalnego z , (dla obu zmiennych) i określoną korelacją. W R można to zrobić za pomocą funkcji z pakietu. Używamy, aby wskazać, że korelacja jest korelacją empiryczną (a nie korelacją populacyjną).μ=0σ=1mvrnormMASSempirical = TRUE

library(MASS)
mvdat <- mvrnorm(n = nrow(d), mu = c(0, 0), Sigma = corr_mat, empirical = TRUE)

cor(mvdat)
#      [,1] [,2]
# [1,]  1.0  0.7
# [2,]  0.7  1.0

Losowe dane idealnie pasują do określonej korelacji.

Następnie obliczamy szeregi losowych danych.

rx <- rank(mvdat[ , 1], ties.method = "first")
ry <- rank(mvdat[ , 2], ties.method = "first")

Aby wykorzystać rangi dla oryginalnych danych d, musimy posortować oryginalne dane.

dx_sorted <- sort(d$x)
dy_sorted <- sort(d$y)

Teraz możemy użyć rang do określenia kolejności posortowanych danych.

cor(dx_sorted[rx], dy_sorted[ry])
# [1] 0.6868986

Uzyskana korelacja nie jest idealnie zgodna z określoną, ale różnica jest stosunkowo niewielka.

Tutaj dx_sorted[rx]i dy_sorted[ry]są ponownie próbkowane wersje oryginalnych danych w d.

Sven Hohenstein
źródło
2
+1 To całkiem fajne. Kroki są następujące: 1) wygeneruj normalne dane z właściwą korelacją Pearsona, 2) spraw, aby oryginalne dane i wygenerowane dane dokładnie odpowiadały korelacjom rang, 3) oryginalne dane mają teraz w przybliżeniu tę samą korelację Pearsona. Dlaczego to działa? Czy istnieje wynik analityczny stwierdzający, że tak jest? Ograniczające nierówności utrzymujące różne miary korelacji blisko siebie dla dobrze zachowanych rozkładów czy coś takiego?
Bill
1
@ Bill Nie potrafię analitycznie wyjaśnić tego podejścia. To tylko pomysł, który przyszedł mi do głowy. Jednak ładnie podsumowałeś kroki. Dzięki.
Sven Hohenstein
2

Aby wygenerować dwa jednolite rozkłady z określoną korelacją, zadziała algorytm Ruscio i Kaczetow (2008). Zapewniają one kod R . Następnie można przekształcić za pomocą prostej funkcji liniowej, aby uzyskać docelową wartość minimalną, maksymalną, średnią i SD.

Algorytm Ruscio i Kaczetowa

Podsumuję przypadek dwuwariantowy, ale może on również działać z problemami wielowymiarowymi. Nieskorelowane i są generowane z dowolnym kształtem (np. Jednolitym). Następnie i są generowane jako dwuwymiarowe normalne z korelacją pośrednią. i są zastępowane przez i w sposób zachowujący rangę. Dostosuj korelację pośrednią, aby była wyższa lub niższa w zależności od tego, czy r ( ) jest za niskie, czy za wysokie. i są generowane jako dwuwymiarowe normalne z nową korelacją pośrednią. Powtarzać.XoYoX1Y1X1Y1X0Y0X1,Y1X2Y2

Zauważ, że jest to bardzo podobne do rozwiązania @ Svena Hohensteina, z tą różnicą, że jest iteracyjne, więc korelacja pośrednia będzie się zbliżać do korelacji docelowej, dopóki nie będzie nie do odróżnienia. Zauważ też, że ten algorytm może być użyty do wygenerowania dużej populacji (np. N = 1 milion), z której można pobrać mniejsze próbki - jest to przydatne, jeśli potrzebujesz błędu próbkowania.

Dla pokrewnego postu: Korelacje i rozkłady niestandardowe

Zachowanie statystyki opisowej

Nie ma gwarancji, że algorytm wygeneruje dokładnie takie same opisy. Ponieważ jednak średnia rozkładu równomiernego i SD są określone przez jego min i maks, możesz po prostu dostosować min i maks, aby wszystko naprawić.

Niech i będą twoimi zmiennymi wygenerowanymi z ostatniej iteracji algorytmu Ruscio & Kaczetow, i będą twoimi zmiennymi końcowymi, które masz nadzieję (z opisami celów), a i będą twoimi oryginalnymi zmiennymi w zbiorze danych. XgYgXfYfXY

Oblicz Xf=(Xgmin(X))(max(X)min(x))/(max(Xg)min(Xg))

Zrób to samo dlaYf

Odniesienie:

Ruscio, J., i Kaczetow, W. (2008). Symulowanie wielowymiarowych nienormalnych danych przy użyciu iteracyjnego algorytmu. Multivariate Behavioural Research, 43, 355–381. doi: 10.1080 / 00273170802285693

Anthony
źródło
1

Zgaduję, że mówiąc „ponownie próbkuj” masz na myśli „symuluj”, co jest bardziej ogólne. Poniżej znajduje się najbardziej zwięzły sposób, jaki znam do symulacji normalnych danych dwuwymiarowych z określoną korelacją. Zastąp własne pożądane wartości r i n.

r = .6
n = 1000
x = rnorm(n) 
z = rnorm(n) 
y = (r/(1-r^2)^.5)*x + z

cor(x,y)
plot(x,y)
abline(lm(y~x), col="red")
rolando2
źródło
3
Nie, naprawdę mam na myśli „resample”. Muszę utrzymać średnie i inne statystyki opisowe (sd, min, max) obu zmiennych na stałym poziomie. Zaktualizowałem pytanie.
Jurij Pietrowski