Come riorganizzare i dati 2D per ottenere una correlazione?


9

Ho il seguente set di dati semplice con due variabili continue; vale a dire:

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

Distribuzione di base

Ho bisogno di riorganizzare i dati in modo che la correlazione tra le variabili sia ~ 0,6. Devo mantenere costanti i mezzi e le altre statistiche descrittive (sd, min, max, ecc.) Di entrambe le variabili.

So che è possibile effettuare quasi tutte le correlazioni con i dati forniti, ovvero:

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

inserisci qui la descrizione dell'immagine

Se provo ad usare la samplefunzione per questo compito:

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))
}

Ottengo una gamma abbastanza ampia di correlazioni:

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

ma questo intervallo dipende dal numero di righe nel frame di dati e diminuisce con l'aumentare delle dimensioni.

> 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

La mia domanda è:

Come riorganizzare tale set di dati per ottenere una correlazione (ovvero 0,7)? (Sarà anche utile se il metodo rimuoverà la dipendenza dalla dimensione del set di dati)

Risposte:


6

Ecco un modo per riorganizzare i dati basato sulla generazione di numeri casuali aggiuntivi.

Tracciamo campioni da una distribuzione normale bivariata con correlazione specificata. Successivamente, calcola le file dei ed valori otteniamo. Questi gradi vengono utilizzati per ordinare i valori originali. Per questo approccio, abbiamo il miglior ordinamento sia dei valori che originali .y x yxyxy

Innanzitutto, creiamo il set di dati effettivo (come nel tuo esempio).

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

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

Ora, specifichiamo una matrice di correlazione.

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

Generiamo dati casuali seguendo una distribuzione normale bivariata con , (per entrambe le variabili) e la correlazione specificata. In R, questo può essere fatto con la funzione dal pacchetto. Usiamo per indicare che la correlazione è la correlazione empirica (non la correlazione della popolazione).σ = 1μ=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

I dati casuali corrispondono perfettamente alla correlazione specificata.

Successivamente, calcoliamo i ranghi dei dati casuali.

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

Per utilizzare le classifiche per i dati originali in d, dobbiamo ordinare i dati originali.

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

Ora, possiamo usare i gradi per specificare l'ordine dei dati ordinati.

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

La correlazione ottenuta non corrisponde perfettamente a quella specificata, ma la differenza è relativamente piccola.

Qui, dx_sorted[rx]e dy_sorted[ry]sono ricampionate le versioni dei dati originali in d.


2
+1 Questo è abbastanza bello. I passaggi sono 1) generare dati normali con la giusta correlazione di Pearson, 2) rendere i dati originali e i dati generati corrispondano esattamente alle correlazioni di rango, 3) i dati originali hanno all'incirca la stessa correlazione di Pearson ora. Perché funziona? C'è un risultato analitico che dice che lo fa? Disuguaglianze limitanti che tengono le varie misure di correlazione vicine tra loro per distribuzioni ben educate o qualcosa del genere?
Bill

1
@Bill Non riesco a spiegare l'approccio analiticamente. È solo un'idea che mi è venuta in mente. Tuttavia, hai riassunto i passaggi in un modo carino. Grazie.
Sven Hohenstein,

2

Per generare due distribuzioni uniformi con una correlazione specifica, funzionerà l'algoritmo Ruscio & Kaczetow (2008). Essi forniscono il codice R . Puoi quindi trasformarti con una semplice funzione lineare per ottenere il tuo obiettivo min, max, media e SD.

Algoritmo di Ruscio & Kaczetow

XoYoX1Y1X1Y1X0Y0X1,Y1X2Y2

Si noti che questo è molto simile alla soluzione di @Sven Hohenstein, tranne per il fatto che è iterativo, quindi la correlazione intermedia si avvicina sempre di più alla correlazione target fino a quando non sono indistinguibili. Inoltre, tieni presente che questo algoritmo può essere utilizzato per generare una grande popolazione (ad esempio, N = 1 milione) da cui estrarre campioni più piccoli, utile se hai bisogno di un errore di campionamento.

Per un post correlato: correlazione e distribuzioni non normali

Conservazione delle statistiche descrittive

Non vi è alcuna garanzia che l'algoritmo produrrà esattamente gli stessi descrittori. Tuttavia, poiché la media e la DS di una distribuzione uniforme sono determinate dal suo minimo e massimo, puoi semplicemente regolare il minimo e il massimo per sistemare tutto.

XgYgXfYfXY

Xf=(Xg-mion(X))*(mun'X(X)-mion(X))/(mun'X(Xg)-mion(Xg))

Yf

Riferimento:

Ruscio, J., & Kaczetow, W. (2008). Simulazione di dati non normali multivariati mediante un algoritmo iterativo. Ricerca comportamentale multivariata, 43, 355–381. DOI: 10,1080 / 00273170802285693


1

Immagino che quando dici "ricampiona" intendi "simulare", che è più generale. Quello che segue è il modo più conciso che conosco per simulare dati normali e bivariati con una correlazione specificata. Sostituisci i tuoi valori desiderati con r e 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")

3
No, intendo davvero "ricampionare". Devo mantenere costanti i mezzi e le altre statistiche descrittive (sd, min, max) di entrambe le variabili. Aggiornato la domanda.
Yuriy Petrovskiy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.