根据各种分布创建相关变量
Create correlated variables following various distributions
问题
在 R 中,我想创建 n
个长度为 L
的变量,其关系由名为 cor_matrix
的 correlation matrix 给出。重要的一点是 n
变量可能遵循不同的分布(包括连续分布与离散分布)。
相关帖子
how-to-generate-sample-data-with-exact-moments
generate-a-random-variable-with-a-defined-correlation-to-an-existing-variable
r-constructing-correlated-variables
根据上面列出的 third post 修改,以下是所有 n
变量连续且来自相同分布的解决方案。
library(psych)
set.seed(199)
fun = function(cor_matrix, list_distributions, L)
{
n = length(list_distributions)
if (ncol(cor_matrix) != nrow(cor_matrix)) stop("cor_matrix is not square")
if (nrow(cor_matrix) != n) stop("the length of list_distributions should match the number of columns and rows of cor_matrix")
if (L<=1) stop("L should be > 1")
fit = principal(cor_matrix, nfactors=n, rotate="none")
loadings = matrix(fit$loadings[1:n, 1:n], nrow=n,ncol=n,byrow=F)
cases = t(sapply(1:n, FUN=function(i, L) list_distributions[[i]](L), L=L))
multivar = loadings %*% cases
T_multivar = t(multivar)
vars=as.data.frame(T_multivar)
return(vars)
}
L = 1000
cor_matrix = matrix(c (1.00, 0.90, 0.20 ,
0.90, 1.00, 0.40 ,
0.20, 0.40, 1.00),
nrow=3,ncol=3,byrow=TRUE)
list_distributions = list(function(L)rnorm(L,0,2), function(L)rnorm(L,10,10), function(L) rnorm(L,0,1))
vars = fun(cor_matrix, list_distributions, L)
cor(vars)
plot(vars)
但是,不能创建具有以下分布的相关变量
list_distributions = list(function(L)rnorm(L,0,2), function(L)round(rnorm(L,10,10)), function(L) runif(L,0,1))
vars = fun(cor_matrix, list_distributions, L)
cor(vars)
plot(vars)
按照@NatePope 和@JoshO'Brien 的建议使用联结函数
library(mvtnorm)
set.seed(199)
fun = function(cor_matrix, list_distributions, L)
{
n = length(list_distributions)
# Correlated Gaussian variables
Gauss = rmvnorm(n=L, mean = rep(0,n), sig=cor_matrix)
# convert them to uniform distribution.
Unif = pnorm(Gauss)
# Convert them to whatever I want
vars = sapply(1:n, FUN = function(i) list_distributions[[i]](Unif[,i]))
return(vars)
}
L = 2000
cor_matrix = matrix(c (1.00, 0.90, 0.80 ,
0.90, 1.00, 0.6,
0.80, 0.6, 1.00),
nrow=3,ncol=3,byrow=TRUE)
list_distributions = list(function(L) qpois(L,7), function(L) round(qnorm(L,100,10)), function(L) qnorm(L,-100,1))
vars = fun(cor_matrix, list_distributions, L)
cor(vars)
plot(as.data.frame(vars))
此解决方案默认创建相关的正态分布变量,然后将它们转换为均匀分布的变量。可能有一个性能更高的解决方案可以直接创建均匀分布的相关变量。
问题
在 R 中,我想创建 n
个长度为 L
的变量,其关系由名为 cor_matrix
的 correlation matrix 给出。重要的一点是 n
变量可能遵循不同的分布(包括连续分布与离散分布)。
相关帖子
how-to-generate-sample-data-with-exact-moments
generate-a-random-variable-with-a-defined-correlation-to-an-existing-variable
r-constructing-correlated-variables
根据上面列出的 third post 修改,以下是所有 n
变量连续且来自相同分布的解决方案。
library(psych)
set.seed(199)
fun = function(cor_matrix, list_distributions, L)
{
n = length(list_distributions)
if (ncol(cor_matrix) != nrow(cor_matrix)) stop("cor_matrix is not square")
if (nrow(cor_matrix) != n) stop("the length of list_distributions should match the number of columns and rows of cor_matrix")
if (L<=1) stop("L should be > 1")
fit = principal(cor_matrix, nfactors=n, rotate="none")
loadings = matrix(fit$loadings[1:n, 1:n], nrow=n,ncol=n,byrow=F)
cases = t(sapply(1:n, FUN=function(i, L) list_distributions[[i]](L), L=L))
multivar = loadings %*% cases
T_multivar = t(multivar)
vars=as.data.frame(T_multivar)
return(vars)
}
L = 1000
cor_matrix = matrix(c (1.00, 0.90, 0.20 ,
0.90, 1.00, 0.40 ,
0.20, 0.40, 1.00),
nrow=3,ncol=3,byrow=TRUE)
list_distributions = list(function(L)rnorm(L,0,2), function(L)rnorm(L,10,10), function(L) rnorm(L,0,1))
vars = fun(cor_matrix, list_distributions, L)
cor(vars)
plot(vars)
但是,不能创建具有以下分布的相关变量
list_distributions = list(function(L)rnorm(L,0,2), function(L)round(rnorm(L,10,10)), function(L) runif(L,0,1))
vars = fun(cor_matrix, list_distributions, L)
cor(vars)
plot(vars)
按照@NatePope 和@JoshO'Brien 的建议使用联结函数
library(mvtnorm)
set.seed(199)
fun = function(cor_matrix, list_distributions, L)
{
n = length(list_distributions)
# Correlated Gaussian variables
Gauss = rmvnorm(n=L, mean = rep(0,n), sig=cor_matrix)
# convert them to uniform distribution.
Unif = pnorm(Gauss)
# Convert them to whatever I want
vars = sapply(1:n, FUN = function(i) list_distributions[[i]](Unif[,i]))
return(vars)
}
L = 2000
cor_matrix = matrix(c (1.00, 0.90, 0.80 ,
0.90, 1.00, 0.6,
0.80, 0.6, 1.00),
nrow=3,ncol=3,byrow=TRUE)
list_distributions = list(function(L) qpois(L,7), function(L) round(qnorm(L,100,10)), function(L) qnorm(L,-100,1))
vars = fun(cor_matrix, list_distributions, L)
cor(vars)
plot(as.data.frame(vars))
此解决方案默认创建相关的正态分布变量,然后将它们转换为均匀分布的变量。可能有一个性能更高的解决方案可以直接创建均匀分布的相关变量。