创建符合以下参数的假数据集:N,mean,sd,min和max

时间:2015-09-26 01:48:58

标签: r mathematical-optimization

有没有办法创建符合以下参数的假数据集:N,mean,sd,min和max?

我想创建187个整数尺度分数的样本,其平均值为67,标准差为17,观察范围在[30,210]范围内。我试图展示一个关于统计能力的概念性课程,我想创建一个看起来像已发布结果的分布数据。此示例中的比例分数是30个项目的总和,每个项目的范围可以从1到7.我不需要构成比例分数的单个项目的数据,但这将是一个奖励。

我知道我可以使用rnorm(),但值不是整数,而最小值和最大值可能超过我可能的值。

scaleScore <- rnorm(187, mean = 67, sd = 17)

我也知道我可以使用sample()来获得保持在此范围内的整数,但平均值和标准偏差将不正确。

scaleScore <- sample(30:210, 187, replace=TRUE)

@ Pascal的提示让我在urnorm()包裹中Runuran

set.seed(5)
scaleScore <- urnorm(n=187, mean=67, sd=17, lb=30, ub=210)
mean(scaleScore)
# [1] 68.51758
sd(scaleScore)
# [1] 16.38056
min(scaleScore)
# [1] 32.15726
max(scaleScore)
# [1] 107.6758

平均值和SD当然不精确,矢量不是由整数组成。

还有其他选择吗?

2 个答案:

答案 0 :(得分:4)

我能够在method="SANN" optim()使用蛮力,即m0 <- 67 sd0 <- 17 min <- 30 max <- 210 n <- 187 合理地接近:

目标值/约束:

set.seed(101)
mm <- min:max
x0 <- sample(mm,size=n,replace=TRUE)

设置初始值:

objfun <- function(x) {
    (mean(x)-m0)^2+(sd(x)-sd0)^2
}

目标函数(距所需均值/ sd的距离;范围和N将受到约束)

candfun <- function(x) {
    x[sample(n,size=1)] <- sample(mm,size=1)
    return(x)
}
objfun(x0)  ## initial badness: 4088.621
set.seed(101)
o1 <- optim(par=x0,fn=objfun,gr=candfun,
      method="SANN",control=list(maxit=1e6))
mean(o1$par) ## 66.978
sd(o1$par) ## 17.22
plot(table(o1$par))

新参数集的候选分布:随机重新采样一个值

@inherits

enter image description here

答案 1 :(得分:4)

无模板的整数优化

由于您希望得到精确的均值,标准差,最小值和最大值,因此您的第一个选择不会是随机数生成,因为您的样本不太可能与您的分布的均值和标准差完全匹配#39;重新吸取。相反,我会采用整数优化方法。您可以将变量x_i定义为样本中出现整数i的次数。您将定义决策变量x_30x_31,...,x_210并添加确保满足所有条件的约束:

  • 187个样本:这可以通过约束x_30 + x_31 + ... + x_210 = 187
  • 进行编码
  • 67的平均值:这可以通过约束30*x_30 + 31*x_31 + ... + 210*x_210 = 187 * 67
  • 进行编码
  • 对变量的逻辑约束:变量必须采用非负整数值
  • &#34;看起来像真实数据&#34; 这显然是一个定义不明确的概念,但我们可能要求相邻数字的频率差异不超过1。是x_30 - x_31 <= 1x_30 - x_31 >= -1形式的线性约束,依此类推每个连续对。我们还可以要求每个频率不超过某个任意定义的上限(I&#39; ll使用10)。

最后,我们希望标准偏差尽可能接近17,这意味着我们希望方差尽可能接近17 ^ 2 = 289.我们可以将变量y定义为我们与这种方差匹配程度的上限,我们可以最小化y:

y >= ((30-67)^2 * x_30 + (31-67)^2 * x_31 + ... + (210-67)^2 * x_210) - (289 * (187-1))
y >= -((30-67)^2 * x_30 + (31-67)^2 * x_31 + ... + (210-67)^2 * x_210) + (289 * (187-1))

这是一个非常简单的优化问题,需要使用像lpSolve

这样的求解器来解决
library(lpSolve)
get.sample <- function(n, avg, stdev, lb, ub) {
  vals <- lb:ub
  nv <- length(vals)
  mod <- lp(direction = "min",
            objective.in = c(rep(0, nv), 1),
            const.mat = rbind(c(rep(1, nv), 0),
                              c(vals, 0),
                              c(-(vals-avg)^2, 1),
                              c((vals-avg)^2, 1),
                              cbind(diag(nv), rep(0, nv)),
                              cbind(diag(nv)-cbind(rep(0, nv), diag(nv)[,-nv]), rep(0, nv)),
                              cbind(diag(nv)-cbind(rep(0, nv), diag(nv)[,-nv]), rep(0, nv))),
            const.dir = c("=", "=", ">=", ">=", rep("<=", nv), rep("<=", nv), rep(">=", nv)),
            const.rhs = c(n, avg*n, -stdev^2 * (n-1), stdev^2 * (n-1), rep(10, nv), rep(1, nv), rep(-1, nv)),
            all.int = TRUE)
  rep(vals, head(mod$solution, -1))
}
samp <- get.sample(187, 67, 17, 30, 210)
summary(samp)
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#      30      64      69      67      74     119
sd(samp)
# [1] 17
plot(table(samp))

enter image description here

对于您提供的参数,我们能够在返回所有整数值时获得精确的均值和标准差,并在0.4秒内在计算机中完成计算。

使用模板进行整数优化

获得类似于真实数据的另一种方法&#34;将定义一个起始连续分布(例如,您在原始帖子中包含的urnorm函数的结果),并以最能实现您的均值和标准偏差目标的方式将值四舍五入为整数。这实际上只引入了两类新约束:某些值的样本数上限是可以向上或向下舍入以获得该值的样本数,并且两个连续频率之和的下限是落在这两个整数之间的连续样本数。同样,这很容易用lpSolve实现,并且运行效率不高:

library(lpSolve)
get.sample2 <- function(n, avg, stdev, lb, ub, init.dist) {
  vals <- lb:ub
  nv <- length(vals)
  lims <- as.vector(table(factor(c(floor(init.dist), ceiling(init.dist)), vals)))
  floors <- as.vector(table(factor(c(floor(init.dist)), vals)))
  mod <- lp(direction = "min",
            objective.in = c(rep(0, nv), 1),
            const.mat = rbind(c(rep(1, nv), 0),
                              c(vals, 0),
                              c(-(vals-avg)^2, 1),
                              c((vals-avg)^2, 1),
                              cbind(diag(nv), rep(0, nv)),
                              cbind(diag(nv) + cbind(rep(0, nv), diag(nv)[,-nv]), rep(0, nv))),
            const.dir = c("=", "=", ">=", ">=", rep("<=", nv), rep(">=", nv)),
            const.rhs = c(n, avg*n, -stdev^2 * (n-1), stdev^2 * (n-1), lims, floors),
            all.int = TRUE)
  rep(vals, head(mod$solution, -1))
}

library(Runuran)
set.seed(5)
init.dist <- urnorm(n=187, mean=67, sd=17, lb=30, ub=210)
samp2 <- get.sample2(187, 67, 17, 30, 210, init.dist)
summary(samp2)
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#      32      57      66      67      77     107
sd(samp2)
# [1] 17
plot(table(samp2))

enter image description here

这种方法甚至更快(在0.1秒内)并且仍然返回完全符合所需平均值和标准偏差的分布。此外,给定来自连续分布的足够高质量的样本,这可以用于获得具有整数值并满足所需统计特性的不同形状的分布。