如何模拟满足特定约束(例如具有特定均值和标准偏差)的数据?


56

这个问题是由我的荟萃分析问题引起的。但是我想这对于在您要创建与现有已发布数据集完全相同的数据集的教学环境中也很有用。

我知道如何从给定的分布中生成随机数据。因此,例如,如果我读到了一项研究的结果,该研究具有:

  • 平均102
  • 标准偏差5.2
  • 样本大小为72。

我可以rnorm在R中使用生成类似的数据。例如,

set.seed(1234)
x <- rnorm(n=72, mean=102, sd=5.2)

当然,平均值和标准差将分别不完全等于102和5.2:

round(c(n=length(x), mean=mean(x), sd=sd(x)), 2)
##     n   mean     sd 
## 72.00 100.58   5.25 

通常,我对如何模拟满足一组约束的数据感兴趣。在上述情况下,约束条件是样本大小,均值和标准差。在其他情况下,可能会有其他限制。例如,

  • 可能知道数据或基础变量的最小值和最大值。
  • 可能已知该变量仅采用整数值或仅采用非负值。
  • 数据可能包含具有相互关系的多个变量。

问题

  • 通常,我该如何模拟完全满足一组约束的数据?
  • 是否有关于此的文章?R中是否有任何程序可以做到这一点?
  • 为了举例说明,我应该并且应该如何模拟变量,使其具有特定的均值和sd?

1
为什么要它们与发布的结果完全一样?如果没有他们的数据样本,这些人口平均值和标准差的估计值也不是。给定这些估计的不确定性,谁能说您上面显示的样本与他们的观察结果不一致?
加文·辛普森

4
因为这个问题似乎是在收集错过标记(IMHO)的答复,所以我想指出,从概念上讲答案很简单:将相等约束视为边际分布,而将不平等约束视为截断的多元类似物。截断相对容易处理(通常使用拒绝采样);更困难的问题是找到一种方法来采样这些边际分布。这意味着要么在给定分布和约束的情况下对边际进行采样,要么进行积分以找到边际分布并从中进行采样。
ub

4
顺便说一句,最后一个问题对于位置规模的分布族来说是微不足道的。例如,x<-rnorm(72);x<-5.2*(x-mean(x))/sd(x)+102把戏。
ub

1
@whuber,因为枢机主教在对我的答案的评论(提到了这个“技巧”)和对另一个答案的评论中暗示-这种方法通常不会将变量保留在相同的分布族中,因为您要划分通过样品标准偏差。
2012年

5
@Macro这是一个很好的观点,但最好的回答可能是“当然它们不会具有相同的分布”!所需的分布是基于约束条件的分布。通常,它将与父代分布的家族不同。例如,大小为4且样本均值为0且SD 1为正态分布的样本中的每个元素在[-1.5,1.5]上的概率几乎相同,这是因为条件将上下限置于可能的值上。
ub

Answers:


26

通常,要使样本均值和方差恰好等于预先指定的值,可以适当地移动和缩放变量。具体来说,如果是样本,则新变量X1,X2,...,Xn

Zi=c1(XiX¯sX)+c2

其中是样本均值,而是样本方差,使得的样本均值恰好是并且它们的样本方差是恰好是。一个类似构造的示例可以限制范围-s 2 X =1X¯=1ni=1nXiŽc ^2Ç1sX2=1n1i=1n(XiX¯)2Zic2c1

Bi=a+(ba)(Ximin({X1,...,Xn})max({X1,...,Xn})min({X1,...,Xn}))

将产生一个限制为间隔的数据集。 B1,...,Bn(a,b)

注意:通常,这些类型的移位/缩放将改变数据的分布族,即使原始数据来自位置范围族。

正态分布的上下文中,通过设置mvrnorm功能,R 您可以使用预先设定的样本均值/协方差来模拟正态(或多元正态)数据empirical=TRUE。具体来说,如果样本均值和(协方差)等于预先指定的值,则此函数将根据正态分布变量条件分布模拟数据。请注意,@ whuber在对主要问题的评论中指出,所得的边际分布正常。

这是一个简单的单变量示例,其中样本均值(来自的样本)被约束为0,样本标准偏差为1。我们可以看到,第一个元素比正态分布更类似于均匀分布分配:n=4

library(MASS)
 z = rep(0,10000)
for(i in 1:10000)
{
    x = mvrnorm(n = 4, rep(0,1), 1, tol = 1e-6, empirical = TRUE)
    z[i] = x[1]
}
hist(z, col="blue")

                  在此处输入图片说明


1
该不会正态分布,尽管它们可以是大约所以如果样本大小是大的。@Sean的答案的第一条评论暗示了这一点。Zi
红衣主教2012年

1
好吧,这是一件很自然的事情……通常不会造成太多麻烦。
红衣主教2012年

1
+1。顺便说一句,在该示例中,制服是确切的答案。(在图的末尾明显的下降是R绘制直方图的
产物

1
@whuber,感谢您激励这个例子。考虑到边际分布随样本均值/方差而变化的事实,看来,OP精神上最好的“答案”就是模拟总体均值/方差等于作为样本报告的数据数量(由OP自己建议),不是吗?这样,您将获得与所需数量“相似”的样本数量,而边际分布就是您想要的数量。
2012年

1
@whuber,如果您的样本正常,则具有,是吗?所讨论的“新”变量将只是的线性组合。Ti=(XiX¯)/stTi
2012年

22

关于您的论文要求,有:

这不是您要找的东西,但可能会成为工厂的要点。


似乎没有人提到过另一种策略。可以从大小为的集合中生成(伪)随机数据,以便整个集合满足约束,只要剩余的数据固定为适当的值即可。所需的值应该可以由方程,代数和一些肘部润滑脂组成的系统求解。 NkNkkk

例如,要从将具有给定样本均值和方差的正态分布生成一组数据,则需要固定两个点的值:和。由于样本均值是:必须为: 样本方差为: 因此(在将替换为,挫败/分发和重新排列... ),我们得到: Nx¯s2yz

x¯=i=1N2xi+y+zN
y
y=Nx¯(i=1N2xi+z)
s2=i=1N2(xix¯)2+(yx¯)2+(zx¯)2N1
y
2(Nx¯i=1N2xi)z2z2=Nx¯2(N1)+i=1N2xi2+[i=1N2xi]22Nx¯i=1N2xi(N1)s2
如果我们取,则和作为RHS的取反,我们可以使用二次公式来求解。例如,在中,可以使用以下代码: a=2b=2(Nx¯i=1N2xi)czR
find.yz = function(x, xbar, s2){
  N    = length(x) + 2
  sumx = sum(x)
  sx2  = as.numeric(x%*%x)          # this is the sum of x^2
  a    = -2
  b    = 2*(N*xbar - sumx)
  c    = -N*xbar^2*(N-1) - sx2 - sumx^2 + 2*N*xbar*sumx + (N-1)*s2
  rt   = sqrt(b^2 - 4*a*c)

  z    = (-b + rt)/(2*a)
  y    = N*xbar - (sumx + z)
  newx = c(x, y, z)
  return(newx)
}

set.seed(62)
x    = rnorm(2)
newx = find.yz(x, xbar=0, s2=1)
newx                                # [1] 0.8012701  0.2844567  0.3757358 -1.4614627
mean(newx)                          # [1] 0
var(newx)                           # [1] 1

关于这种方法,有些事情要理解。首先,不能保证它能正常工作。例如,您的初始数据可能不存在值和,这将使结果集的方差等于。考虑: N2yzs2

set.seed(22)    
x    = rnorm(2)
newx = find.yz(x, xbar=0, s2=1)
Warning message:
In sqrt(b^2 - 4 * a * c) : NaNs produced
newx                                # [1] -0.5121391  2.4851837        NaN        NaN
var(c(x, mean(x), mean(x)))         # [1] 1.497324

其次,尽管标准化使您所有变量的边际分布更加均匀,但是此方法仅影响最后两个值,但使它们的边际分布偏斜:

set.seed(82)
xScaled = matrix(NA, ncol=4, nrow=10000)
for(i in 1:10000){
  x           = rnorm(4)
  xScaled[i,] = scale(x)
}

(插入图)

set.seed(82)
xDf = matrix(NA, ncol=4, nrow=10000)
i   = 1
while(i<10001){
  x       = rnorm(2)
  xDf[i,] = try(find.yz(x, xbar=0, s2=2), silent=TRUE)  # keeps the code from crashing
  if(!is.nan(xDf[i,4])){ i = i+1 }                      # increments if worked
}

(插入图)

第三,结果样本看起来可能不太正常。看起来好像有“异常值”(即,点来自与其余数据不同的数据生成过程),因为实际上是这种情况。对于较大的样本量,这不太可能出现问题,因为来自生成数据的样本统计信息应收敛到所需值,因此需要较少的调整。对于较小的样本,您始终可以将此方法与接受/拒绝算法结合使用,该算法会再次尝试生成的样本具有超出可接受范围(例如,@ cardinal的注释)的形状统计信息(例如,偏斜度和峰度),或者扩展这种方法可以生成均值,方差,偏度峰度(不过,我将代数交给您)。或者,您可以生成少量样本,并使用具有最小(例如)Kolmogorov-Smirnov统计量的样本。

library(moments)
set.seed(7900)  
x = rnorm(18)
newx.ss7900 = find.yz(x, xbar=0, s2=1)
skewness(newx.ss7900)                       # [1] 1.832733
kurtosis(newx.ss7900) - 3                   # [1] 4.334414
ks.test(newx.ss7900, "pnorm")$statistic     # 0.1934226

set.seed(200)  
x = rnorm(18)
newx.ss200 = find.yz(x, xbar=0, s2=1)
skewness(newx.ss200)                        # [1] 0.137446
kurtosis(newx.ss200) - 3                    # [1] 0.1148834
ks.test(newx.ss200, "pnorm")$statistic      # 0.1326304 

set.seed(4700)  
x = rnorm(18)
newx.ss4700 = find.yz(x, xbar=0, s2=1)
skewness(newx.ss4700)                       # [1]  0.3258491
kurtosis(newx.ss4700) - 3                   # [1] -0.02997377
ks.test(newx.ss4700, "pnorm")$statistic     # 0.07707929S

(添加剧情)


10

通用技术是“拒绝方法”,您可以在其中拒绝不符合约束条件的结果。除非您有某种指导(例如MCMC),否则您可能会生成很多被拒绝的案例(取决于您的方案)!

在寻找均值和标准差之类的地方,可以创建某种距离度量以说离目标有多远,可以使用优化来搜索可为您提供所需输出的输入变量价值观。

作为一个丑陋的例子,我们将寻找一个长度为100且均值= 0和标准差= 1的随机均匀向量。

# simplistic optimisation example
# I am looking for a mean of zero and a standard deviation of one
# but starting from a plain uniform(0,1) distribution :-)
# create a function to optimise
fun <- function(xvec, N=100) {
  xmin <- xvec[1]
  xmax <- xvec[2]
  x <- runif(N, xmin, xmax)
  xdist <- (mean(x) - 0)^2 + (sd(x) - 1)^2
  xdist
}
xr <- optim(c(0,1), fun)

# now lets test those results
X <- runif(100, xr$par[1], xr$par[2])
mean(X) # approx 0
sd(X)   # approx 1

7
以零概率发生的约束很难满足。;-)对于手头的特定示例,进行适当的移位和扩展很容易达到既定目标,尽管您可能想更深入地分析一下这种操作如何扰乱数据的分布。
主教

谢谢。当然,拒绝小于最小值和大于最大值的观察很容易。我可以看到如何将其定义为优化问题。看到一些示例,或者对接下来要阅读的内容提出一些建议,将是很棒的。
Jeromy Anglim 2012年

1
@cardinal-同意。应该看一下输入的模拟数字和输出的分布(即直方图),因为有时它们看起来确实很奇怪!
肖恩2012年

9

R中是否有任何程序可以做到这一点?

所述Runuran ř包中包含用于生成随机变元的许多方法。它使用来自UNU.RAN(通用非统一RAndom编号生成器)项目的C库。我对随机变量生成领域的了解有限,但是Runuran 插图提供了很好的概述。以下是来自小插图的Runuran软件包中的可用方法:

连续分布:

  • 自适应拒绝采样
  • 逆变换密度抑制
  • 逆CDF的多项式插值
  • 简单均匀率法
  • 变换密度抑制

离散分布:

  • 离散自动拒绝反演
  • Alias-Urn方法
  • 离散反演的导表法

多元分布:

  • 匀速比的运行算法
  • 多元朴素均匀率法

例:

举个简单的例子,假设您要生成一个介于0到100之间的正态分布:

require("Runuran")

## Normal distribution bounded between 0 and 100
d1 <- urnorm(n = 1000, mean = 50, sd = 25, lb = 0, ub = 100)

summary(d1)
sd(d1)
hist(d1)

urnorm()函数是一个方便的包装函数。我相信在幕后它使用逆CDF的多项式插值法,但不确定。对于更复杂的事物,例如,离散的正态分布范围在0到100之间:

require("Runuran")

## Discrete normal distribution bounded between 0 and 100
# Create UNU.RAN discrete distribution object
discrete <- unuran.discr.new(pv = dnorm(0:100, mean = 50, sd = 25), lb = 0, ub = 100)

# Create UNU.RAN object using the Guide-Table Method for Discrete Inversion
unr <- unuran.new(distr = discrete, method = "dgt")

# Generate random variates from the UNU.RAN object
d2 <- ur(unr = unr, n = 1000)

summary(d2)
sd(d2)
head(d2)
hist(d2)

3

似乎昨天才发布了一个满足您要求的R包! Simstudy作者:基思· 戈德菲尔德

模拟数据集以探索建模技术或更好地理解数据生成过程。用户指定一组协变量之间的关系,并根据这些规范生成数据。最终数据集可以代表来自随机对照试验,重复测量(纵向)设计和聚类随机试验的数据。丢失可以使用各种机制(MCAR,MAR,NMAR)生成。


1
在小插图中或程序的主页上均未提及严格的约束条件。您为什么认为此程序包满足从条件分布中提取的要求?
gg

2

这个答案来得太晚了,大概没有意义,但是总有一个MCMC解决方案。即,将样本的联合密度投影到约束定义的流形上,例如 然后唯一的问题是在该流形上模拟值,即找到正确尺寸的参数化。Bornn,Shephard和Solgi 在2015年发表的一篇论文研究了这个问题(有一个有趣的,甚至不是最终的答案)。

i=1nf(xi)
i=1nxi=μ0i=1nxi2=σ02

2

此答案考虑了另一种方法,其中您要强制变量位于指定范围内并另外规定均值和/或方差。

将注意力集中在单位间隔。让我们使用加权平均值作为一般性,因此用固定一些权重,或者如果您要标准权重则设置假设数量和代表期望的(加权)均值和(加权)方差。的上限是必要的,因为这是单位间隔上可能的最大方差。我们有兴趣在这些力矩限制下从绘制一些变量。[0,1]wk[0,1]k=1Nwk=1wk=1/Nμ(0,1)0<σ2<μ(1μ)σ2x1,...,xN[0,1]

首先,我们从任何分布(如绘制一些变量。这种分布将影响最终分布的形状。然后,我们使用逻辑函数将它们限制为单位间隔:y1,...,yNN(0,1)[0,1]

xk=11+e(ykvh)

但是,在执行此操作之前,如上式所示,我们将转换为平移和标度。这类似于@Macro答案中的第一个方程式。现在的诀窍是选择和,以使变换后的变量具有所需的矩。也就是说,我们需要以下一项或两项才能成立: ykhvhvx1,...,xN

μ=k=1Nwk1+e(ykvh)σ2=k=1Nwk(1+e(ykvh))2(k=1Nwk1+e(ykvh))2

通过解析将和这些方程式进行分析是不可行的,但是在数字上这样做是直接的,特别是因为相对于和导数易于计算。它只需要牛顿方法的几次迭代。vhvh

作为第一个示例,假设我们只关心约束加权平均值而不是方差。修复,,,。然后,对于基础分布,和我们分别得出以下直方图,并且变量的均值正好为(即使对于小):v = 1 瓦特ķ = 1 / Ñ Ñ = 200000 Ñ 0 1 Ñ 0μ=0.8v=1wk=1/NN=200000N(0,1)UNIF 0 1 0.8 ÑN(0,0.1)Unif(0,1) 0.8N

例1

接下来,让我们约束均值和方差。取,,并考虑三个期望的标准偏差。使用相同的基础分布,这是每个的直方图:瓦特ķ = 1 / Ñ Ñ = 2000 σ = 0.1 0.05 0.01 Ñ 0 1 μ=0.2wk=1/NN=2000σ=0.1,0.05,0.01N(0,1)

例子2

请注意,这些可能看起来有点beta分布,但不是。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.