样本最多

use*_*502 5 r sampling

如果我想采样数字来创建一个矢量我做:

set.seed(123)
x <- sample(1:100,200, replace = TRUE)
sum(x)
# [1] 10228
Run Code Online (Sandbox Code Playgroud)

如果我想抽样20个总和为100的随机数,然后是30个数字但仍然总和为100,那么我认为这将是一个比看上去更具挑战性的.?sample并且搜索Google并未向我提供线索.然后,如果不足够接近(例如在5之内)期望的总和,则采样的循环然后拒绝可能需要一些时间.

有没有更好的方法来实现这一目标?

一个例子是:

foo(10,100) # ten random numbers that sum to 100. (not including zeros)
# 10,10,20,7,8,9,4,10,2,20
Run Code Online (Sandbox Code Playgroud)

A5C*_*2T1 3

这是另一个尝试。它不使用sample,而是使用runif。我在显示总和的输出中添加了一条可选的“消息”,可以使用showSum参数触发该消息。还有一个Tolerance参数指定需要距离目标多近。

SampleToSum <- function(Target = 100, VecLen = 10, 
                        InRange = 1:100, Tolerance = 2, 
                        showSum = TRUE) {
  Res <- vector()
  while ( TRUE ) {
    Res <- round(diff(c(0, sort(runif(VecLen - 1)), 1)) * Target)
    if ( all(Res > 0)  & 
         all(Res >= min(InRange)) &
         all(Res <= max(InRange)) &
         abs((sum(Res) - Target)) <= Tolerance ) { break }
  }
  if (isTRUE(showSum)) cat("Total = ", sum(Res), "\n")
  Res
}
Run Code Online (Sandbox Code Playgroud)

这里有些例子。

注意默认设置和设置之间的区别Tolerance = 0

set.seed(1)
SampleToSum()
# Total =  101 
#  [1] 20  6 11 20  6  3 24  1  4  6
SampleToSum(Tolerance=0)
# Total =  100 
#  [1] 19 15  4 10  1 11  7 16  4 13
Run Code Online (Sandbox Code Playgroud)

您可以使用 来验证此行为replicateTolerance = 0这是设置并运行该函数 5 次的结果。

system.time(output <- replicate(5, SampleToSum(
  Target = 1376,
  VecLen = 13,
  InRange = 10:200,
  Tolerance = 0)))
# Total =  1376 
# Total =  1376 
# Total =  1376 
# Total =  1376 
# Total =  1376 
#    user  system elapsed 
#   0.144   0.000   0.145
output
#       [,1] [,2] [,3] [,4] [,5]
#  [1,]   29   46   11   43  171
#  [2,]  103  161  113  195  197
#  [3,]  145  134   91  131  147
#  [4,]  154  173  138   19   17
#  [5,]  197   62  173   11   87
#  [6,]  101  142   87  173   99
#  [7,]  168   61   97   40  121
#  [8,]  140  121   99  135  117
#  [9,]   46   78   31  200   79
# [10,]  140  168  146   17   56
# [11,]   21  146  117  182   85
# [12,]   63   30  180  179   78
# [13,]   69   54   93   51  122
Run Code Online (Sandbox Code Playgroud)

Tolerance = 5设置并运行该功能 5 次也是如此。

system.time(output <- replicate(5, SampleToSum(
  Target = 1376,
  VecLen = 13,
  InRange = 10:200,
  Tolerance = 5)))
# Total =  1375 
# Total =  1376 
# Total =  1374 
# Total =  1374 
# Total =  1376 
#    user  system elapsed 
#   0.060   0.000   0.058 
output
#       [,1] [,2] [,3] [,4] [,5]
#  [1,]   65  190  103   15   47
#  [2,]  160   95   98  196  183
#  [3,]  178  169  134   15   26
#  [4,]   49   53  186   48   41
#  [5,]  104   81  161  171  180
#  [6,]   54  126   67  130  182
#  [7,]   34  131   49  113   76
#  [8,]   17   21  107   62   95
#  [9,]  151  136  132  195  169
# [10,]  194  187   91  163   22
# [11,]   23   69   54   97   30
# [12,]  190   14  134   43  150
# [13,]  156  104   58  126  175
Run Code Online (Sandbox Code Playgroud)

毫不奇怪,将容差设置为 0 会使函数变慢。


速度(或缺乏速度)

请注意,由于这是一个“随机”过程,因此很难猜测找到正确的数字组合需要多长时间。例如,使用set.seed(123),我连续运行了三次以下测试:

system.time(SampleToSum(Target = 1163,
                        VecLen = 15,
                        InRange = 50:150))
Run Code Online (Sandbox Code Playgroud)

第一次运行仅用时 9 秒多一点。第二次仅用了 7.5 秒多一点。第三次用时......不到 381 秒!这有很多变化!

出于好奇,我在函数中添加了一个计数器,第一次运行尝试了55026 次才得到满足我们所有条件的向量!(我没有费心去尝试第二次和第三次尝试。)

最好在函数中添加一些错误或健全性检查,以确保输入合理。例如,人们不应该能够输入SampleToSum(Target = 100, VecLen = 10, InRange = 15:50),因为范围为 15 到 50,因此无法达到 100 并且向量中有 10 个值。