Пока у вас нет особых требований к распространению, вы можете использовать следующий метод перебора.
Сначала мы определим две функции для генерации случайных чисел, которые суммируются с данным total > 0
:
get_weights <- function(N, total = 1)
total * diff(c(0, sort(runif(N-1)), 1))
И до нуля:
get_weight_changes <- function(N, ratio = N)
(get_weights(N) - 1/N) / ratio
См. этот вопрос для заметок по алгоритму. Аргумент ratio
является эмпирическим параметром, который контролирует, насколько велико типичное изменение по сравнению с типичным абсолютным весом. Если это слишком мало, вам придется попробовать очень много случайных изменений веса, прежде чем один из них удовлетворит ваши условия. Если оно слишком велико, ваши изменения относительного веса будут намного меньше, чем допустимый диапазон.
Далее мы генерируем случайные веса и случайные изменения веса. Последнее делается до тех пор, пока мы не достигнем вектора случайного изменения веса, который удовлетворяет требованию минимального изменения:
N <- 40
ratio <- 300
w <- get_weights(N)
dw <- get_weight_changes(N, ratio)
while (any(abs(dw/w) > 0.02)) {
dw <- get_weight_changes(N, ratio)
}
Вот типичная гистограмма результирующих изменений веса:
![enter image description here](https://i.stack.imgur.com/ACARE.png)
Как видно, они далеко не одинаковы, но изменения веса отвечают всем требованиям.
Примечание: поскольку потенциально требуется очень много случайных чисел, я использую
library(dqrng)
dqRNGkind("Xoroshiro128+")
dqset.seed(42)
runif <- dqrunif
для использования на быстрых ГСЧ из пакета dqrng