Genera una variabile casuale con una correlazione definita con una o più variabili esistenti


71

Per uno studio di simulazione devo generare variabili casuali che mostrano una correlazione (popolazione) predefinita a una variabile esistente .Y

Ho esaminato i Rpacchetti copulae CDVineche possono produrre distribuzioni multivariate casuali con una determinata struttura di dipendenza. Tuttavia, non è possibile fissare una delle variabili risultanti su una variabile esistente.

Tutte le idee e i collegamenti a funzioni esistenti sono apprezzati!


Conclusione: sono state presentate due risposte valide, con diverse soluzioni:

  1. Uno R script di caracal, che calcola una variabile casuale con una correlazione esatta (campione) a una variabile predefinita
  2. Una R funzione che mi sono trovata, che calcola una variabile casuale con una correlazione di popolazione definita a una variabile predefinita

[Aggiunta di @ttnphns: ho preso la libertà di espandere il titolo della domanda da un singolo caso a variabile fissa a un numero arbitrario di variabili fisse; cioè come generare una variabile con correzioni predefinite con alcune variabili fisse esistenti]


2
Vedi questa domanda correlata stats.stackexchange.com/questions/13382/… che affronta direttamente la tua domanda (almeno il lato teorico di essa).
Macro

Risposte:


56

Eccone un altro: per i vettori con media 0, la loro correlazione è uguale al coseno del loro angolo. Quindi un modo per trovare un vettore con esattamente la correlazione desiderata r , corrispondente ad un angolo θ :xrθ

  1. ottiene il vettore fisso e un vettore casuale x 2x1x2
  2. centrare entrambi i vettori (media 0), fornendo i vettori , ˙ x 2x˙1x˙2
  3. rendere ortogonale a ˙ x 1 (proiezione sul sottospazio ortogonale), dando ˙ x 2x˙2x˙1x˙2
  4. scala e ˙ x 2 alla lunghezza 1, dando ˉ x 1 e ˉ x 2x˙1x˙2x¯1x¯2
  5. è il vettore il cui angolo rispetto a ˉ x 1èθe la cui correlazione con ˉ x 1 è quindir. Questa è anche la correlazione ax1poiché le trasformazioni lineari lasciano invariata la correlazione.x¯2+(1/tan(θ))x¯1x¯1θx¯1rx1

Ecco il codice:

n     <- 20                    # length of vector
rho   <- 0.6                   # desired correlation = cos(angle)
theta <- acos(rho)             # corresponding angle
x1    <- rnorm(n, 1, 1)        # fixed given data
x2    <- rnorm(n, 2, 0.5)      # new random data
X     <- cbind(x1, x2)         # matrix
Xctr  <- scale(X, center=TRUE, scale=FALSE)   # centered columns (mean 0)

Id   <- diag(n)                               # identity matrix
Q    <- qr.Q(qr(Xctr[ , 1, drop=FALSE]))      # QR-decomposition, just matrix Q
P    <- tcrossprod(Q)          # = Q Q'       # projection onto space defined by x1
x2o  <- (Id-P) %*% Xctr[ , 2]                 # x2ctr made orthogonal to x1ctr
Xc2  <- cbind(Xctr[ , 1], x2o)                # bind to matrix
Y    <- Xc2 %*% diag(1/sqrt(colSums(Xc2^2)))  # scale columns to length 1

x <- Y[ , 2] + (1 / tan(theta)) * Y[ , 1]     # final new vector
cor(x1, x)                                    # check correlation = rho

inserisci qui la descrizione dell'immagine

Per la proiezione ortogonale , ho usato la decomposizione Q R per migliorare la stabilità numerica, da allora semplicemente P = Q Q .PQRP=QQ


Stavo cercando di riscrivere il codice nella sintassi SPSS. Mi imbatto nella decomposizione QR che restituisce la colonna 20x1. In SPSS ho l'ortonormalizzazione di Gram-Schmidt (che è anche una decomposizione QR) ma non riesco a replicare la colonna Q risultante. Puoi muovermi per la tua azione QR per favore. Oppure indica qualche soluzione per ottenere la proiezione. Grazie.
ttnphns,

@caracal, P <- X %*% solve(t(X) %*% X) %*% t(X)non produce r = 0.6, quindi non è questo il problema . Sono ancora confuso. (Sarei felice di imitare la tua espressione Q <- qr.Q(qr(Xctr[ , 1, drop=FALSE]))in SPSS ma non so come.)
ttnphns

@ttnphns Ci scusiamo per la confusione, il mio commento è stato per il caso generale. Applicandolo alla situazione nell'esempio: ottenere la matrice di proiezione tramite decomposizione QR serve solo per la stabilità numerica. È possibile ottenere la matrice di proiezione come se il sottospazio è attraversato dalle colonne di matrice X . In R, puoi qui scrivere perché il sottospazio è espanso dalla prima colonna di . La matrice per la proiezione sul complemento ortogonale è quindi IP. P=X(XX)1XXXctr[ , 1] %*% solve(t(Xctr[ , 1]) %*% Xctr[ , 1]) %*% t(Xctr[ , 1])Xctr
Caracal,

4
Qualcuno potrebbe chiarire come eseguire qualcosa di simile per più di due soli campioni? Ad esempio, se volessi 3 campioni correlati in coppia per rho, come posso trasformare questa soluzione per raggiungere questo obiettivo?
Andre Terra,

per il caso limite rho=1ho trovato utile fare qualcosa del genere if (isTRUE(all.equal(rho, 1))) rho <- 1-10*.Machine$double.epsNaN
:,

19

Descriverò la soluzione più generale possibile. Risolvere il problema in questa generalità ci consente di ottenere un'implementazione del software straordinariamente compatta: bastano solo due brevi righe di Rcodice.

Scegli un vettore , della stessa lunghezza di Y , in base a qualsiasi distribuzione ti piaccia. Lasciate Y sia i residui della regressione dei minimi quadrati di X contro Y : questo estrae il Y componente da X . Aggiungendo indietro un multiplo adeguato Y a Y , possiamo produrre un vettore aventi una correlazione desiderata ρ con Y . Fino a una costante additiva arbitraria e costante moltiplicativa positiva - che sei libero di scegliere in qualsiasi modo - la soluzione èXYYXYYXYYρY

XY;ρ=ρSD(Y)Y+1ρ2SD(Y)Y.

(" " sta per qualsiasi calcolo proporzionale a una deviazione standard.)SD


Ecco il Rcodice funzionante . Se non si fornisce , il codice trarrà i suoi valori dalla distribuzione normale standard multivariata.X

complement <- function(y, rho, x) {
  if (missing(x)) x <- rnorm(length(y)) # Optional: supply a default if `x` is not given
  y.perp <- residuals(lm(x ~ y))
  rho * sd(y.perp) * y + y.perp * sd(y) * sqrt(1 - rho^2)
}

Per illustrare, ho generato una casuale con 50 componenti e prodotto X Y ; ρ aventi varie correlazioni specificati con questo Y . Sono stati tutti creati con lo stesso vettore iniziale X = ( 1 , 2 , , 50 ) . Ecco i loro grafici a dispersione. I "rugplot" nella parte inferiore di ciascun pannello mostrano il vettore Y comune .Y50XY;ρYX=(1,2,,50)Y

figura

C'è una notevole somiglianza tra le trame, non c'è :-).


Se desideri sperimentare, ecco il codice che ha prodotto questi dati e la figura. (Non mi sono preoccupato di usare la libertà per spostare e ridimensionare i risultati, che sono operazioni facili.)

y <- rnorm(50, sd=10)
x <- 1:50 # Optional
rho <- seq(0, 1, length.out=6) * rep(c(-1,1), 3)
X <- data.frame(z=as.vector(sapply(rho, function(rho) complement(y, rho, x))),
                rho=ordered(rep(signif(rho, 2), each=length(y))),
                y=rep(y, length(rho)))

library(ggplot2)
ggplot(X, aes(y,z, group=rho)) + 
  geom_smooth(method="lm", color="Black") + 
  geom_rug(sides="b") + 
  geom_point(aes(fill=rho), alpha=1/2, shape=21) +
  facet_wrap(~ rho, scales="free")

A proposito, questo metodo generalizza prontamente a più di una : se è matematicamente possibile, troverà una X Y 1 , Y 2 , ... , Y k ; ρ 1 , ρ 2 , , ρ k avendo specificato correlazioni con un intero insieme di Y i . Basta usare i minimi quadrati ordinari per eliminare gli effetti di tutte le Y che da X e formare una combinazione lineare adatto della Y iYXY1,Y2,,Yk;ρ1,ρ2,,ρkYiYiXYie i residui. (Aiuta a farlo in termini di doppia base per , che si ottiene calcolando uno pseudo-inverso. Il codice seguente utilizza l'SVD di Y per farlo.)YY

Ecco uno schizzo dell'algoritmo in R, in cui sono indicati come colonne di una matrice :Yiy

y <- scale(y)             # Makes computations simpler
e <- residuals(lm(x ~ y)) # Take out the columns of matrix `y`
y.dual <- with(svd(y), (n-1)*u %*% diag(ifelse(d > 0, 1/d, 0)) %*% t(v))
sigma2 <- c((1 - rho %*% cov(y.dual) %*% rho) / var(e))
return(y.dual %*% rho + sqrt(sigma2)*e)

Quella che segue è un'implementazione più completa per coloro che desiderano sperimentare.

complement <- function(y, rho, x) {
  #
  # Process the arguments.
  #
  if(!is.matrix(y)) y <- matrix(y, ncol=1)
  if (missing(x)) x <- rnorm(n)
  d <- ncol(y)
  n <- nrow(y)
  y <- scale(y) # Makes computations simpler
  #
  # Remove the effects of `y` on `x`.
  #
  e <- residuals(lm(x ~ y))
  #
  # Calculate the coefficient `sigma` of `e` so that the correlation of
  # `y` with the linear combination y.dual %*% rho + sigma*e is the desired
  # vector.
  #
  y.dual <- with(svd(y), (n-1)*u %*% diag(ifelse(d > 0, 1/d, 0)) %*% t(v))
  sigma2 <- c((1 - rho %*% cov(y.dual) %*% rho) / var(e))
  #
  # Return this linear combination.
  #
  if (sigma2 >= 0) {
    sigma <- sqrt(sigma2) 
    z <- y.dual %*% rho + sigma*e
  } else {
    warning("Correlations are impossible.")
    z <- rep(0, n)
  }
  return(z)
}
#
# Set up the problem.
#
d <- 3           # Number of given variables
n <- 50          # Dimension of all vectors
x <- 1:n         # Optionally: specify `x` or draw from any distribution
y <- matrix(rnorm(d*n), ncol=d) # Create `d` original variables in any way
rho <- c(0.5, -0.5, 0)          # Specify the correlations
#
# Verify the results.
#
z <- complement(y, rho, x)
cbind('Actual correlations' = cor(cbind(z, y))[1,-1],
      'Target correlations' = rho)
#
# Display them.
#
colnames(y) <- paste0("y.", 1:d)
colnames(z) <- "z"
pairs(cbind(z, y))

YBTW, this method readily generalizes to more... Just use ordinary least squares... and form a suitable linear combination

1
@ttnphns L'ho fatto.
whuber

1
Grazie mille! Vedo, e ho codificato il tuo approccio oggi in SPSS per me stesso. Davvero un'ottima proposta tua. Non ho mai pensato alla nozione di doppia base applicabile per risolvere il compito.
ttnphns,

È possibile utilizzare un approccio simile per elaborare un vettore uniformemente distribuito? Cioè, ho un vettore esistente xe voglio generare un nuovo vettore ycorrelato xma voglio anche che il yvettore sia distribuito uniformemente.
Skumin,

@Skumin Prendi in considerazione l'uso di una copula per poter controllare la relazione tra i due vettori.
whuber

6

Ecco un altro approccio computazionale (la soluzione è adattata da un post sul forum di Enrico Schumann). Secondo Wolfgang (vedi commenti), questo è computazionalmente identico alla soluzione proposta da ttnphns.

ρρ

ρx

# returns a data frame of two variables which correlate with a population correlation of rho
# If desired, one of both variables can be fixed to an existing variable by specifying x
getBiCop <- function(n, rho, mar.fun=rnorm, x = NULL, ...) {
     if (!is.null(x)) {X1 <- x} else {X1 <- mar.fun(n, ...)}
     if (!is.null(x) & length(x) != n) warning("Variable x does not have the same length as n!")

     C <- matrix(rho, nrow = 2, ncol = 2)
     diag(C) <- 1

     C <- chol(C)

     X2 <- mar.fun(n)
     X <- cbind(X1,X2)

     # induce correlation (does not change X1)
     df <- X %*% C

     ## if desired: check results
     #all.equal(X1,X[,1])
     #cor(X)

     return(df)
}

La funzione può anche utilizzare distribuzioni marginali non normali regolando il parametro mar.fun. Si noti, tuttavia, che la fissazione di una variabile solo sembra funzionare con una variabile distribuita normalmente x! (che potrebbe riguardare il commento di Macro).

Si noti inoltre che il "piccolo fattore di correzione" dal post originale è stato rimosso in quanto sembra distorcere le correlazioni risultanti, almeno nel caso delle distribuzioni gaussiane e delle correlazioni di Pearson (vedere anche i commenti).


ρ

1
È facile dimostrare che, fatta eccezione per quella "piccola correzione a rho" (il cui scopo in questo contesto mi sfugge), questo è esattamente lo stesso di quanto suggerito in precedenza. Il metodo si basa semplicemente sulla decomposizione di Choleski della matrice di correlazione per ottenere la matrice di trasformazione desiderata. Vedi, ad esempio: en.wikipedia.org/wiki/… . E sì, questo ti darà solo due vettori la cui correlazione di popolazione è uguale rho.
Wolfgang,

La "piccola correzione a rho" era nel post originale ed è descritta qui . In realtà, non lo capisco davvero; ma un'indagine su 50000 correlazioni simulate con rho = .3 mostra che senza la "piccola correzione" viene prodotta una media di r di .299, mentre con la correzione una media di .312 (che è il valore del rho corretto) è prodotta. Pertanto ho rimosso quella parte dalla funzione.
Felix S,

So che questo è vecchio, ma voglio anche notare che questo metodo non funzionerà con matrici di correlazione definite non positive. Ad esempio - una correlazione di -1.
zzk,

1
Grazie; Ho notato che se x1 non è standardizzata media = 0, sd = 1, e si preferisce non ridimensionare esso, è necessario modificare la riga: X2 <- mar.fun(n)per X2 <- mar.fun(n,mean(x),sd(x))ottenere la correlazione desiderata tra X1 e X2
Dave M

6

XYXrXrY=rX+EE0sd=1r2XYrXYXρ=r

rEXEXYX1,X2,X3,...

XrYYrY


Aggiornamento dell'11 novembre 2017. Ho trovato questo vecchio thread oggi e ho deciso di espandere la mia risposta mostrando l'algoritmo del raccordo iterativo di cui parlavo inizialmente.

Y X

Disclamer: questa soluzione iterativa che ho trovato inferiore a quella eccellente basata sulla ricerca della doppia base e proposta oggi da @whuber in questo thread. La soluzione di @ whuber non è iterativa e, cosa più importante per me, sembra influenzare i valori della variabile "maiale" di input in qualche modo meno dell'algoritmo "mio" (sarebbe un vantaggio se il compito fosse "correggere" la variabile esistente e non generare una variabile casuale da zero). Tuttavia, sto pubblicando il mio per curiosità e perché funziona (vedi anche la nota a piè di pagina).

X1,X2,...,XmYYr1,r2,...,rmX

YXYY

  1. rdf=n1Sj=rjdfjX

  2. dfYXdf

  3. YXrb=(XX)1S

  4. YY^=Xb

  5. E=YY^

  6. SSS=dfSSY^

  7. EXjCj=i=1nEiXij

  8. EC0i

    Ei[corrected]=Eij=1mCjXijnj=1mXij2

    (il denominatore non cambia sulle iterazioni, calcola in anticipo)

    E0 EC

    Ei[corrected]=Eij=1mCjXij3i=1nXij2j=1mXij2

    1

  9. SSEEi[corrected]=EiSSS/SSE

    mrSSSn

  10. CErYY[corrected]=Y^+E

  11. Y

  12. Yr

YrY


1YX


1
Grazie per la tua risposta. Questa è una soluzione empirica / iterativa a cui stavo pensando anch'io. Per le mie simulazioni, tuttavia, ho bisogno di una soluzione più analitica senza una costosa procedura di adattamento. Fortunatamente, ho appena trovato una soluzione che posterò a breve ...
Felix S

Funziona per generare normali bivariati ma non funziona per una distribuzione arbitraria (o qualsiasi distribuzione non "additiva")
Macro

1
Non vedo perché proponi l'iterazione quando puoi produrre direttamente l'intero cono di soluzioni. C'è qualche scopo speciale in questo approccio?
whuber

1
Y

1
@whuber, il tuo commento è quello che stavo aspettando; in realtà la mia risposta (sull'eteroscedasticità, a cui mi collego) è stata intesa come una sfida per te: forse è un invito a pubblicare la tua soluzione, tanto accurata e brillante come al solito.
ttnphns,

4

Mi è venuta voglia di fare un po 'di programmazione, quindi ho preso la risposta eliminata di @ Adam e ho deciso di scrivere una bella implementazione in R. Mi concentro sull'uso di uno stile orientato alla funzionalità (ad esempio loop stile lapply). L'idea generale è quella di prendere due vettori, permutare casualmente uno dei vettori fino a quando non viene raggiunta una certa correlazione tra di loro. Questo approccio è molto bruto, ma è semplice da implementare.

Innanzitutto creiamo una funzione che permetta casualmente il vettore di input:

randomly_permute = function(vec) vec[sample.int(length(vec))]
randomly_permute(1:100)
  [1]  71  34   8  98   3  86  28  37   5  47  88  35  43 100  68  58  67  82
 [19]  13   9  61  10  94  29  81  63  14  48  76   6  78  91  74  69  18  12
 [37]   1  97  49  66  44  40  65  59  31  54  90  36  41  93  24  11  77  85
 [55]  32  79  84  15  89  45  53  22  17  16  92  55  83  42  96  72  21  95
 [73]  33  20  87  60  38   7   4  52  27   2  80  99  26  70  50  75  57  19
 [91]  73  62  23  25  64  51  30  46  56  39

... e crea alcuni dati di esempio

vec1 = runif(100)
vec2 = runif(100)

... scrivere una funzione che permetta il vettore di input e lo correla a un vettore di riferimento:

permute_and_correlate = function(vec, reference_vec) {
    perm_vec = randomly_permute(vec)
    cor_value = cor(perm_vec, reference_vec)
    return(list(vec = perm_vec, cor = cor_value))
  }
permute_and_correlate(vec2, vec1)
$vec
  [1] 0.79072381 0.23440845 0.35554970 0.95114398 0.77785348 0.74418811
  [7] 0.47871491 0.55981826 0.08801319 0.35698405 0.52140366 0.73996913
 [13] 0.67369873 0.85240338 0.57461506 0.14830718 0.40796732 0.67532970
 [19] 0.71901990 0.52031017 0.41357545 0.91780357 0.82437619 0.89799621
 [25] 0.07077250 0.12056045 0.46456652 0.21050067 0.30868672 0.55623242
 [31] 0.84776853 0.57217746 0.08626022 0.71740151 0.87959539 0.82931652
 [37] 0.93903143 0.74439384 0.25931398 0.99006038 0.08939812 0.69356590
 [43] 0.29254936 0.02674156 0.77182339 0.30047034 0.91790830 0.45862163
 [49] 0.27077191 0.74445997 0.34622648 0.58727094 0.92285322 0.83244284
 [55] 0.61397396 0.40616274 0.32203732 0.84003379 0.81109473 0.50573325
 [61] 0.86719899 0.45393971 0.19701975 0.63877904 0.11796154 0.26986325
 [67] 0.01581969 0.52571331 0.27087693 0.33821824 0.52590383 0.11261002
 [73] 0.89840404 0.82685046 0.83349287 0.46724807 0.15345334 0.60854785
 [79] 0.78854984 0.95770015 0.89193212 0.18885955 0.34303707 0.87332019
 [85] 0.08890968 0.22376395 0.02641979 0.43377516 0.58667068 0.22736077
 [91] 0.75948043 0.49734797 0.25235660 0.40125309 0.72147500 0.92423638
 [97] 0.27980561 0.71627101 0.07729027 0.05244047

$cor
[1] 0.1037542

... e ripetizione mille volte:

n_iterations = lapply(1:1000, function(x) permute_and_correlate(vec2, vec1))

Si noti che le regole di scoping di R assicurano che vec1e vec2si trovano nell'ambiente globale, al di fuori della funzione anonima utilizzata in precedenza. Quindi, le permutazioni sono tutte relative ai set di dati di test originali che abbiamo generato.

Successivamente, troviamo la massima correlazione:

cor_values = sapply(n_iterations, '[[', 'cor')
n_iterations[[which.max(cor_values)]]
$vec
  [1] 0.89799621 0.67532970 0.46456652 0.75948043 0.30868672 0.83244284
  [7] 0.86719899 0.55623242 0.63877904 0.73996913 0.71901990 0.85240338
 [13] 0.81109473 0.52571331 0.82931652 0.60854785 0.19701975 0.26986325
 [19] 0.58667068 0.52140366 0.40796732 0.22736077 0.74445997 0.40125309
 [25] 0.89193212 0.52031017 0.92285322 0.91790830 0.91780357 0.49734797
 [31] 0.07729027 0.11796154 0.69356590 0.95770015 0.74418811 0.43377516
 [37] 0.55981826 0.93903143 0.30047034 0.84776853 0.32203732 0.25235660
 [43] 0.79072381 0.58727094 0.99006038 0.01581969 0.41357545 0.52590383
 [49] 0.27980561 0.50573325 0.92423638 0.11261002 0.89840404 0.15345334
 [55] 0.61397396 0.27077191 0.12056045 0.45862163 0.18885955 0.77785348
 [61] 0.23440845 0.05244047 0.25931398 0.57217746 0.35554970 0.34622648
 [67] 0.21050067 0.08890968 0.84003379 0.95114398 0.83349287 0.82437619
 [73] 0.46724807 0.02641979 0.71740151 0.74439384 0.14830718 0.82685046
 [79] 0.33821824 0.71627101 0.77182339 0.72147500 0.08801319 0.08626022
 [85] 0.87332019 0.34303707 0.45393971 0.47871491 0.29254936 0.08939812
 [91] 0.35698405 0.67369873 0.27087693 0.78854984 0.87959539 0.22376395
 [97] 0.02674156 0.07077250 0.57461506 0.40616274

$cor
[1] 0.3166681

... o trova il valore più vicino a una correlazione di 0,2:

n_iterations[[which.min(abs(cor_values - 0.2))]]
$vec
  [1] 0.02641979 0.49734797 0.32203732 0.95770015 0.82931652 0.52571331
  [7] 0.25931398 0.30047034 0.55981826 0.08801319 0.29254936 0.23440845
 [13] 0.12056045 0.89799621 0.57461506 0.99006038 0.27077191 0.08626022
 [19] 0.14830718 0.45393971 0.22376395 0.89840404 0.08890968 0.15345334
 [25] 0.87332019 0.92285322 0.50573325 0.40796732 0.91780357 0.57217746
 [31] 0.52590383 0.84003379 0.52031017 0.67532970 0.83244284 0.95114398
 [37] 0.81109473 0.35554970 0.92423638 0.83349287 0.34622648 0.18885955
 [43] 0.61397396 0.89193212 0.74445997 0.46724807 0.72147500 0.33821824
 [49] 0.71740151 0.75948043 0.52140366 0.69356590 0.41357545 0.21050067
 [55] 0.87959539 0.11796154 0.73996913 0.30868672 0.47871491 0.63877904
 [61] 0.22736077 0.40125309 0.02674156 0.26986325 0.43377516 0.07077250
 [67] 0.79072381 0.08939812 0.86719899 0.55623242 0.60854785 0.71627101
 [73] 0.40616274 0.35698405 0.67369873 0.82437619 0.27980561 0.77182339
 [79] 0.19701975 0.82685046 0.74418811 0.58667068 0.93903143 0.74439384
 [85] 0.46456652 0.85240338 0.34303707 0.45862163 0.91790830 0.84776853
 [91] 0.78854984 0.05244047 0.58727094 0.77785348 0.01581969 0.27087693
 [97] 0.07729027 0.71901990 0.25235660 0.11261002

$cor
[1] 0.2000199

Per ottenere una correlazione più elevata, è necessario aumentare il numero di iterazioni.


2

Y1Y2,,YnR

Soluzione:

  1. CCT=R
  2. X2,,XnY1
  3. Y1
  4. Y=CXYiY1

Codice Python:

import numpy as np
import math
from scipy.linalg import toeplitz, cholesky
from statsmodels.stats.moment_helpers import cov2corr

# create the large correlation matrix R
p = 4
h = 2/p
v = np.linspace(1,-1+h,p)
R = cov2corr(toeplitz(v))

# create the first variable
T = 1000;
y = np.random.randn(T)

# generate p-1 correlated randoms
X = np.random.randn(T,p)
X[:,0] = y
C = cholesky(R)
Y = np.matmul(X,C)

# check that Y didn't change
print(np.max(np.abs(Y[:,0]-y)))

# check the correlation matrix
print(R)
print(np.corrcoef(np.transpose(Y)))

Uscita di prova:

0.0
[[ 1.   0.5  0.  -0.5]
 [ 0.5  1.   0.5  0. ]
 [ 0.   0.5  1.   0.5]
 [-0.5  0.   0.5  1. ]]
[[ 1.          0.50261766  0.02553882 -0.46259665]
 [ 0.50261766  1.          0.51162821  0.05748082]
 [ 0.02553882  0.51162821  1.          0.51403266]
 [-0.46259665  0.05748082  0.51403266  1.        ]]

Y1

@whuber era un refuso
Aksakal,

0

Genera variabili normali con la matrice di covarianza SAMPLING come indicato

covsam <- function(nobs,covm, seed=1237) {; 
          library (expm);
          # nons=number of observations, covm = given covariance matrix ; 
          nvar <- ncol(covm); 
          tot <- nvar*nobs;
          dat <- matrix(rnorm(tot), ncol=nvar); 
          covmat <- cov(dat); 
          a2 <- sqrtm(solve(covmat)); 
          m2 <- sqrtm(covm);
          dat2 <- dat %*% a2 %*% m2 ; 
          rc <- cov(dat2);};
          cm <- matrix(c(1,0.5,0.1,0.5,1,0.5,0.1,0.5,1),ncol=3);
          cm; 
          res <- covsam(10,cm)  ;
          res;

Genera variabili normali con la matrice di covarianza POPOLAZIONE come indicato

covpop <- function(nobs,covm, seed=1237) {; 
          library (expm); 
          # nons=number of observations, covm = given covariance matrix;
          nvar <- ncol(covm); 
          tot <- nvar*nobs;  
          dat <- matrix(rnorm(tot), ncol=nvar); 
          m2 <- sqrtm(covm);
          dat2 <- dat %*% m2;  
          rc <- cov(dat2); }; 
          cm <- matrix(c(1,0.5,0.1,0.5,1,0.5,0.1,0.5,1),ncol=3);
          cm; 
          res <- covpop(10,cm); 
          res

2
Devi imparare a formattare il codice nella risposta! C'è un'opzione specifica per contrassegnare il testo come frammenti di codice, usalo!
kjetil b halvorsen,

-6

Basta creare un vettore casuale e ordinare fino a ottenere r desiderato.


In quali situazioni sarebbe preferibile alle soluzioni di cui sopra?
Andy W,

Una situazione in cui un utente desidera una risposta semplice. Ho letto una domanda simile sul forum r, ed è la risposta che mi è stata data.
Adam,

3
r

3
Se questa risposta è stata data sul forum di r-help, sospetto che fosse (a) ironico (cioè inteso come uno scherzo), oppure (b) offerto da qualcuno che non è molto statisticamente sofisticato. Per dirla più sinteticamente, questa è una cattiva risposta alla domanda. -1
gung - Ripristina Monica
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.