在 R 中生成具有定义范围内定义相关性的随机值
Generate random values in R with a defined correlation in a defined range
对于一个科学项目,我正在寻找一种方法来生成特定范围内的随机数据(例如 min=0,max=100000),并且与另一个已经存在的变量具有一定的相关性 R。目标是稍微丰富数据集,以便生成一些更有意义的图表(不用担心,我正在处理虚构的数据)。
例如,我想使用以下数据生成与 r=-.78 相关的随机值:
var1 <- rnorm(100, 50, 10)
我已经遇到了一些非常好的解决方案(即 https://stats.stackexchange.com/questions/15011/generate-a-random-variable-with-a-defined-correlation-to-an-existing-variable),但只能得到非常小的值,我无法对其进行转换,因此在其他原始值的上下文中有意义。
下面的例子:
var1 <- rnorm(100, 50, 10)
n <- length(var1)
rho <- -0.78
theta <- acos(rho)
x1 <- var1
x2 <- rnorm(n, 50, 50)
X <- cbind(x1, x2)
Xctr <- scale(X, center=TRUE, scale=FALSE)
Id <- diag(n)
Q <- qr.Q(qr(Xctr[ , 1, drop=FALSE]))
P <- tcrossprod(Q) # = Q Q'
x2o <- (Id-P) %*% Xctr[ , 2]
Xc2 <- cbind(Xctr[ , 1], x2o)
Y <- Xc2 %*% diag(1/sqrt(colSums(Xc2^2)))
var2 <- Y[ , 2] + (1 / tan(theta)) * Y[ , 1]
cor(var1, var2)
我得到的 var2 值介于 -0.5 和 0.5 之间。平均值为 0。我想要更多的分布式数据,所以我可以简单地通过添加 50 来转换它,并且与我的第一个变量相比具有非常相似的范围。
你们中有人知道生成这种或多或少有意义的数据的方法吗?
非常感谢!
如果您对生成值的相关性和边际分布(即形状)感到满意,请将值(落在 (-.5, +.5) 之间)乘以 100,000,然后加上 50,000。
> c(-0.5, 0.5) * 100000 + 50000
[1] 0e+00 1e+05
edit:这种方法,或任何其他将 100,000 和 50,000 换成不同数字的方法,将是@gregor 推荐的 'linear transformation' 的示例- de-cillia.
从var1
开始,重命名为A
,使用10,000点:
set.seed(1)
A <- rnorm(10000,50,10) # Mean of 50
首先将 A
中的值转换为具有新的所需平均值 50,000
并具有反比关系(即相减):
B <- 1e5 - (A*1e3) # Note that { mean(A) * 1000 = 50,000 }
这只会导致 r = -1
。添加一些噪声以实现所需的 r
:
B <- B + rnorm(10000,0,8.15e3) # Note this noise has mean = 0
# the amount of noise, 8.15e3, was found through parameter-search
这有你想要的相关性:
cor(A,B)
[1] -0.7805972
查看方式:
plot(A,B)
注意
您的 B
值可能超出您的范围 0 100,000
。如果您使用不同的种子或生成更多数字,您可能需要过滤超出范围的值。
也就是说,当前范围是可以的:
range(B)
[1] 1668.733 95604.457
对于一个科学项目,我正在寻找一种方法来生成特定范围内的随机数据(例如 min=0,max=100000),并且与另一个已经存在的变量具有一定的相关性 R。目标是稍微丰富数据集,以便生成一些更有意义的图表(不用担心,我正在处理虚构的数据)。
例如,我想使用以下数据生成与 r=-.78 相关的随机值:
var1 <- rnorm(100, 50, 10)
我已经遇到了一些非常好的解决方案(即 https://stats.stackexchange.com/questions/15011/generate-a-random-variable-with-a-defined-correlation-to-an-existing-variable),但只能得到非常小的值,我无法对其进行转换,因此在其他原始值的上下文中有意义。
下面的例子:
var1 <- rnorm(100, 50, 10)
n <- length(var1)
rho <- -0.78
theta <- acos(rho)
x1 <- var1
x2 <- rnorm(n, 50, 50)
X <- cbind(x1, x2)
Xctr <- scale(X, center=TRUE, scale=FALSE)
Id <- diag(n)
Q <- qr.Q(qr(Xctr[ , 1, drop=FALSE]))
P <- tcrossprod(Q) # = Q Q'
x2o <- (Id-P) %*% Xctr[ , 2]
Xc2 <- cbind(Xctr[ , 1], x2o)
Y <- Xc2 %*% diag(1/sqrt(colSums(Xc2^2)))
var2 <- Y[ , 2] + (1 / tan(theta)) * Y[ , 1]
cor(var1, var2)
我得到的 var2 值介于 -0.5 和 0.5 之间。平均值为 0。我想要更多的分布式数据,所以我可以简单地通过添加 50 来转换它,并且与我的第一个变量相比具有非常相似的范围。
你们中有人知道生成这种或多或少有意义的数据的方法吗?
非常感谢!
如果您对生成值的相关性和边际分布(即形状)感到满意,请将值(落在 (-.5, +.5) 之间)乘以 100,000,然后加上 50,000。
> c(-0.5, 0.5) * 100000 + 50000
[1] 0e+00 1e+05
edit:这种方法,或任何其他将 100,000 和 50,000 换成不同数字的方法,将是@gregor 推荐的 'linear transformation' 的示例- de-cillia.
从var1
开始,重命名为A
,使用10,000点:
set.seed(1)
A <- rnorm(10000,50,10) # Mean of 50
首先将 A
中的值转换为具有新的所需平均值 50,000
并具有反比关系(即相减):
B <- 1e5 - (A*1e3) # Note that { mean(A) * 1000 = 50,000 }
这只会导致 r = -1
。添加一些噪声以实现所需的 r
:
B <- B + rnorm(10000,0,8.15e3) # Note this noise has mean = 0
# the amount of noise, 8.15e3, was found through parameter-search
这有你想要的相关性:
cor(A,B)
[1] -0.7805972
查看方式:
plot(A,B)
注意
您的 B
值可能超出您的范围 0 100,000
。如果您使用不同的种子或生成更多数字,您可能需要过滤超出范围的值。
也就是说,当前范围是可以的:
range(B)
[1] 1668.733 95604.457