Выборка действительных чисел с ограничениями суммы и минимального значения - PullRequest
0 голосов
/ 25 июня 2019

Как можно выбрать N случайных значений, чтобы были соблюдены следующие ограничения?

  1. значения N в сумме составляют 1,0
  2. ни одно из значений не меньше 0,01 (или некоторого другого порога T << 1 / <em>N )

Следующая процедура была моей первой попыткой,

def proportions(N):
    proportions = list()
    for value in sorted(numpy.random.random(N - 1) * 0.98 + 0.01):
        prop = value - sum(proportions)
        proportions.append(prop)
    prop = 1.0 - sum(proportions)
    proportions.append(prop)
    return proportions

Бит * 0.98 + 0.01 был предназначен для применения ограничения ≥ 1%.Это работает на полях, но не работает внутри - если два случайных значения имеют расстояние <0,01, оно не фиксируется / не корректируется.Пример: </p>

>>> numpy.random.seed(2000)                                                                                            
>>> proportions(5)                                                                                                     
[0.3397481983960182, 0.14892479749759702, 0.07456518420712799, 0.005868759570153426, 0.43089306032910335]

Есть предложения по исправлению этого неправильного подхода или его замене более подходящим?

Ответы [ 2 ]

1 голос
/ 25 июня 2019

Вы можете адаптировать Хорошее решение Марка Дикинсона :

import random

def proportions(n):
    dividers = sorted(random.sample(range(1, 100), n - 1))
    return [(a - b) / 100 for a, b in zip(dividers + [100], [0] + dividers)]

print(proportions(5))
# [0.13, 0.19, 0.3, 0.34, 0.04]
# or
# [0.31, 0.38, 0.12, 0.05, 0.14]
# etc

Обратите внимание, что предполагается, что "ни одно из значений не меньше 0,01" является фиксированным порогом

ОБНОВЛЕНИЕ : Мы можем обобщить, если мы возьмем обратную величину порога и используем ее для замены жестко закодированных значений 100 в предлагаемом коде.

def proportions(N, T=0.01):
    limit = int(1 / T)
    dividers = sorted(random.sample(range(1, limit), N - 1))
    return [(a - b) / limit for a, b in zip(dividers + [limit], [0] + dividers)]
0 голосов
/ 25 июня 2019

Как насчет этого?

  • N / 2 раза, выберите случайное число x так, чтобы 1 / N + x & 1 / Nx соответствовали вашим ограничениям;добавить 1 / N + x & 1 / Nx
  • Если N нечетно, добавить 1 / N
...