【问题标题】:How do I generate a range of specific numbers given mean?如何生成给定均值的一系列特定数字?
【发布时间】:2018-11-09 09:47:38
【问题描述】:

给定一个指定值的向量,例如:

x = c(4.0, 3.7, 3.3, 3.0, 2.7, 2.3, 2.0, 1.7, 1.3, 1.0)

我想创建一个任意长度的新向量,该向量仅包含 x 中随机采样的值,这将产生 3.15 的组合平均值。我曾尝试使用rnorm() 函数,但是,我只能生成等于3.15 平均值的随机数,而不是我想要的指定值。谁能指出我正确的方向?

【问题讨论】:

  • 这些特定值的逻辑是什么?
  • 您需要一定数量的值吗?在较短的长度下,您无法确定一组随机生成的数字是否具有特定的平均值(毕竟它们是随机的)。随着随机数的数量越来越大,这将不再是一个问题。一般来说,在 500 左右,如果您将随机数设置为围绕它旋转,您将非常接近 3.5。
  • 作为参考,在大多数美国学校中,提供的值是字母等级的学分权重(A = 4.0、A- = 3.7 等)
  • 正如@iod 提到的,没有抽样方案(甚至rnorm)可以保证样本均值是某个值。您希望样本均值正好是 3.15 还是大约 3.15?
  • 您的接近程度取决于您的样本量!一种解决方案(可能不是您想要的)是以相同的概率从 {3.0, 3.3} 中提取:sample(c(3.0, 3.3), size = 100, replace = TRUE)(将 100 替换为您想要的样本量)

标签: r


【解决方案1】:

你的问题的问题是有无数种方法可以从中采样

x = c(4.0, 3.7, 3.3, 3.0, 2.7, 2.3, 2.0, 1.7, 1.3, 1.0)

要获得大约3.15 的平均值,您只需为每个值指定一个概率。

在做

n = 20
sample(x, n, replace = TRUE)

假设每个值的可能性相同,您将得到接近2.5 的平均值。但是如果你重新加权概率,你可以更接近你想要的。一种方法可能是

p = 1/(x - 3.15)^2    # or try p = 1/abs(x - 3.15)
sample(x, n, replace = TRUE, prob = p)

其中p 的权重值更接近3.15,因此这些值更有可能被接受。它并不完美(意味着真正的预期值类似于3.12,大多数值只是2.73.03.3),但同样没有单一的解决方案。

【讨论】:

  • 我已经尝试过这种方法但没有发布答案,因为当我测试大 n 时,它并没有给出完全正确的平均值。 ^2abs 版本都存在同样的问题。我不太确定为什么它不起作用
  • @dww,这是因为3.15 周围的不对称性,并且坚持每个值都具有非零被选中的概率。如果您想获得3.15 的真实平均值,您可能必须手动选择p 的值(有无数种选择)。使用 ^2abs 意味着更像是一个起点或近似值。
  • 请注意3.15 = (3.3 + 3)/2,这是一种解决方案。您可以重复相同数量的 3 和 3.3 以获得其他组合。 mean(c(rep(3.3,42), rep(3,42))) = 3.15 还有(2.3+4)/2 = 3.15 所以你也可以添加任意数量的这些对。 mean(c(rep(3.3,42), rep(3,42), rep(2.3, 1066), rep(4,1066))) = 3.15
【解决方案2】:

这是我的蛮力方法:

samp315<-function(n=20, desmean=3.15, distance=0.001) { # create a function with default n=20 and range 3.149-3.151
  x<- c(4.0, 3.7, 3.3, 3.0, 2.7, 2.3, 2.0, 1.7, 1.3, 1.0)
  samp<-0 # reset samp to 0
  i<-0 # reset my counter to zero
  while (!between(mean(samp),desmean-distance,desmean+distance) & i<1000000) {  # the following will run continuously until a sample (samp) with a mean that falls within the specified range is found, OR until 1 million attempts have been made
    samp<-sample(x,n,replace=TRUE) # try to generate a sample of n times from the list of values (x)
    i=i+1 # add to counter towards 1 million
   }
  ifelse(i<1000000,samp,warning("Couldn't find an appropriate sample, please select a lower n, a desired mean closer to 2.5, or a greater distance"))  # if the while loop ended because the counter reached a million, exit with an error, otherwise, return the contents of samp.
 }

现在,每次你做samp315()

eg<-samp315()
mean(eg)
[1] 3.15
eg
[1] 3.0 3.7 3.0 3.7 3.3 3.7 3.3 3.3 4.0 1.0 1.7 3.0 2.0 4.0 3.7 3.7 2.3 3.3 4.0 3.3

如果您想要不同长度的样本,只需在samp315() 中输入您想要的任何数字。但是,数字越大,找到能够获得所需均值的样本所需的时间就越长。

您还可以通过设置 desmean 来更改所需的平均值,并通过将 distance 更改为与所需平均值的距离 (+/-) 来调整范围。默认值为 n=20,范围为 3.149 到 3.151。

为了避免极不可能的 n 和范围组合出现无限循环,我设置了最多 1m 个样本,之后函数退出并发出警告。

【讨论】:

  • 这太棒了,非常感谢,如果您能在逻辑上分解您的方法,我也将不胜感激!
  • 我在答案中添加了 cmets 来解释每一行的作用。基本上,就像我在开始时所说的那样,这是一种蛮力方法,它依赖于这样一个事实,即如果您模拟采样足够长的时间,最终您将获得任何可能的组合。所以我只是告诉它无限采样(或至少 100 万次),并且只有在所选样本的平均值落在给定范围内时才停止。
【解决方案3】:

正如@mickey 所指出的,我们可以根据每个项目与平均值的距离来加权每个项目的概率。然而,这并不完全奏效,因为 x 中有更多的元素低于所需的平均值,这会使采样偏向它们。我们可以通过调整相对于有多少元素高于或低于期望平均值的概率来解释这一点:

x = c(4.0, 3.7, 3.3, 3.0, 2.7, 2.3, 2.0, 1.7, 1.3, 1.0)
n = 100000
xbar=3.15

xhi = x[which(x>xbar)]
xlo = x[which(x<xbar)]
probhi = 1/(xhi-xbar)
problo = 1/(xbar-xlo)

probhi = probhi * length(problo) / length(probhi)

n=1e5
set.seed(1)
y = sample(x, size = n, replace = TRUE, prob = c(probhi,problo))
mean(y)
# [1] 3.150216

【讨论】:

  • 但这会留下一个问题,即在样本较低的情况下实际上无法获得所需的均值。我们可以将此解决方案与我的蛮力解决方案结合起来以提高效率,同时仍确保生成的样本提供所需的平均值。
猜你喜欢
  • 2019-08-08
  • 2023-02-04
  • 1970-01-01
  • 2011-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多