Случайная выборка для получения точной суммы
Я хочу пробовать 140 номеров от 1000 до 100000, так что сумма этих 140 номеров составляет около 2 миллионов (2000000):
sample(1000:100000,140)
так что:
sum(sample(1000:100000,140)) = 2000000
Любые указатели, как я могу это достичь?
Ответы
Ответ 1
Существует алгоритм генерации таких случайных чисел.
Первоначально созданный для MATLAB, есть реализация R:
Surrogate::RandVec
Цитата из комментария сценария MATLAB:
% This generates an n by m array x, each of whose m columns
% contains n random values lying in the interval [a,b], but
% subject to the condition that their sum be equal to s. The
% scalar value s must accordingly satisfy n*a <= s <= n*b. The
% distribution of values is uniform in the sense that it has the
% conditional probability distribution of a uniform distribution
% over the whole n-cube, given that the sum of the x is s.
%
% The scalar v, if requested, returns with the total
% n-1 dimensional volume (content) of the subset satisfying
% this condition. Consequently if v, considered as a function
% of s and divided by sqrt(n), is integrated with respect to s
% from s = a to s = b, the result would necessarily be the
% n-dimensional volume of the whole cube, namely (b-a)^n.
%
% This algorithm does no "rejecting" on the sets of x it
% obtains. It is designed to generate only those that satisfy all
% the above conditions and to do so with a uniform distribution.
% It accomplishes this by decomposing the space of all possible x
% sets (columns) into n-1 dimensional simplexes. (Line segments,
% triangles, and tetrahedra, are one-, two-, and three-dimensional
% examples of simplexes, respectively.) It makes use of three
% different sets of 'rand' variables, one to locate values
% uniformly within each type of simplex, another to randomly
% select representatives of each different type of simplex in
% proportion to their volume, and a third to perform random
% permutations to provide an even distribution of simplex choices
% among like types. For example, with n equal to 3 and s set at,
% say, 40% of the way from a towards b, there will be 2 different
% types of simplex, in this case triangles, each with its own
% area, and 6 different versions of each from permutations, for
% a total of 12 triangles, and these all fit together to form a
% particular planar non-regular hexagon in 3 dimensions, with v
% returned set equal to the hexagon area.
%
% Roger Stafford - Jan. 19, 2006
Пример:
test <- Surrogate::RandVec(a=1000, b=100000, s=2000000, n=140, m=1, Seed=sample(1:1000, size = 1))
sum(test$RandVecOutput)
# 2000000
hist(test$RandVecOutput)
Ответ 2
Вот хит и промах. Основная идея заключается в том, что поиск 140 чисел, сумма которых составляет 2000000, такая же, как разрыв 1: 2000000 на 140 штук, что требует 139 точек выреза. Также обратите внимание, что минимум 1000 несколько раздражает. Просто вычтите его из всех проблемных данных и добавьте их обратно в конец:
rand.nums <- function(a,b,n,k){
#finds n random integers in range a:b which sum to k
while(TRUE){
x <- sample(1:(k - n*a),n-1, replace = TRUE) #cutpoints
x <- sort(x)
x <- c(x,k-n*a) - c(0,x)
if(max(x) <= b-a) return(a+x)
}
}
Тогда rand.nums(1000,100000,140,2000000)
оценивает до 140 целых чисел в заданном диапазоне, которые суммируются до 2000000. Для этих вариантов параметров функция возвращается почти мгновенно. Для других вариантов параметров решение может быть либо невозможно, либо настолько жестко ограничено, что нахождение одного случайно невозможно. Таким образом, следует проявлять осторожность при использовании функции. Он может быть изменен путем добавления параметра maxtrials
и возврата NA
если maxtrials превышено без нахождения решения.
Ответ 3
Вот некоторые хакерские способы получить около 2 миллионов. Надеюсь, кто-то опубликует более умное решение.
В этом случае мы используем аргумент prob
чтобы сделать более мелкие значения более вероятными, и мы выбираем экспоненту методом проб и ошибок. Этот метод сильно искажен для выбора более низких значений в пределах диапазона, указанного в OP.
x1 = sample(1000:100000,140, prob=(1e5:1e3)^5.5)
mean(replicate(100, sum(sample(1000:100000,140, prob=(1e5:1e3)^5.5))))
[1] 2015620
В этом варианте мы выбираем из усеченного нормального (усеченного на заданных границах). Сначала мы установили среднее значение 2e6/140 = 14285.71. Однако, если стандартное отклонение достаточно велико, чтобы привести к множеству значений вблизи нижней границы, усечение смещает среднее значение выше, поэтому мы добавляем исправление, выбранное методом проб и ошибок.
library(truncnorm)
x2 = rtruncnorm(140, 1e3, 1e5, mean=0.82*2e6/140, sd=1e4)
mean(replicate(1000, sum(rtruncnorm(140, 1e3, 1e5, mean=0.82*2e6/140, sd=1e4))))
[1] 2008050
Если вы установите меньшее стандартное отклонение, коррекция не требуется. Однако вы получаете меньше значений, которые далеки от среднего значения.
mean(replicate(1000, sum(rtruncnorm(140, 1e3, 1e5, mean=2e6/140, sd=0.5e4))))
[1] 2008494
В любом случае показатель для sample
подхода или поправка к усеченной норме могут быть выбраны автоматическим поиском с допуском на то, насколько средняя сумма отличается от 2 миллионов.
Вот некоторые типичные распределения выходных данных:
Ответ 4
Вот попытка, пытающаяся изменить верхнюю связь. Идея состоит в том, чтобы уменьшить верхнюю границу, когда сумма становится выше.
sup<- 100000
tir <- vector(length = 140)
for(i in 1:140){
print(i)
tir[i] <- sample(1000:sup,1)
sup <- max(1001,min(sup,abs(2000000 - sum(tir,na.rm = T))/(140-i)*2))
}
sum(tir)
[1] 2001751