有没有办法创建符合以下参数的假数据集: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当然不精确,矢量不是由整数组成。
还有其他选择吗?
答案 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
答案 1 :(得分:4)
由于您希望得到精确的均值,标准差,最小值和最大值,因此您的第一个选择不会是随机数生成,因为您的样本不太可能与您的分布的均值和标准差完全匹配#39;重新吸取。相反,我会采用整数优化方法。您可以将变量x_i
定义为样本中出现整数i
的次数。您将定义决策变量x_30
,x_31
,...,x_210
并添加确保满足所有条件的约束:
x_30 + x_31 + ... + x_210 = 187
30*x_30 + 31*x_31 + ... + 210*x_210 = 187 * 67
x_30 - x_31 <= 1
,x_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))
对于您提供的参数,我们能够在返回所有整数值时获得精确的均值和标准差,并在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))
这种方法甚至更快(在0.1秒内)并且仍然返回完全符合所需平均值和标准偏差的分布。此外,给定来自连续分布的足够高质量的样本,这可以用于获得具有整数值并满足所需统计特性的不同形状的分布。