Сгенерировать несколько случайных чисел, чтобы равное значение в python
Итак, вот сделка: я хочу (например) генерировать 4 псевдослучайных числа, которые при объединении будут равны 40. Как это может быть купол в python? Я мог бы генерировать случайное число 1-40, затем генерировать другое число между 1 и остальным и т.д., Но тогда у первого числа будет больше шансов "захватить" больше.
Ответы
Ответ 1
b = random.randint(2, 38)
a = random.randint(1, b - 1)
c = random.randint(b + 1, 39)
return [a, b - a, c - b, 40 - c]
(Я предполагаю, что вам нужны целые числа, так как вы сказали "1-40", но это можно было бы легко обобщить для float.)
Вот как это работает:
- вырезать общий диапазон в два раза, b. Нечетный диапазон - это то, что они будут по крайней мере на 2 ниже середины и не менее 2 выше. (Это происходит от вашего 1 минимального значения по каждому значению).
- вырезать каждый из этих диапазонов двумя случайными способами. Опять же, оценки должны учитывать 1 минимум.
- вернуть размер каждого фрагмента. Они добавят до 40.
Ответ 2
Здесь стандартное решение. Это похоже на ответ Лоуренса Гонсалвеса, но имеет два преимущества перед этим ответом.
- Он одинаков: каждая комбинация из 4-х положительных целых чисел, составляющих до 40, с равной вероятностью может придумать эту схему.
а также
- его легко адаптировать к другим суммам (7 номеров, суммируя до 100 и т.д.)
import random
def constrained_sum_sample_pos(n, total):
"""Return a randomly chosen list of n positive integers summing to total.
Each such list is equally likely to occur."""
dividers = sorted(random.sample(range(1, total), n - 1))
return [a - b for a, b in zip(dividers + [total], [0] + dividers)]
Пример выходов:
>>> constrained_sum_sample_pos(4, 40)
[4, 4, 25, 7]
>>> constrained_sum_sample_pos(4, 40)
[9, 6, 5, 20]
>>> constrained_sum_sample_pos(4, 40)
[11, 2, 15, 12]
>>> constrained_sum_sample_pos(4, 40)
[24, 8, 3, 5]
Объяснение: существует взаимно-однозначное соответствие между (1) 4-мя кортежами (a, b, c, d)
натуральных чисел, так что a + b + c + d == 40
, и (2) тройками целых чисел (e, f, g)
с 0 < e < f < g < 40
, и последнее легко получить, используя random.sample
. Соответствие задается как (e, f, g) = (a, a + b, a + b + c)
в одном направлении, и (a, b, c, d) = (e, f - e, g - f, 40 - g)
в обратном направлении.
Если вы хотите, чтобы неотрицательные целые числа (т.е. допускали 0
) вместо положительных, то есть простое преобразование: если (a, b, c, d)
- неотрицательные целые числа, суммирующие до 40
то (a+1, b+1, c+1, d+1)
являются положительными целыми числами, суммирующимися в 44
, и наоборот. Используя эту идею, мы имеем:
def constrained_sum_sample_nonneg(n, total):
"""Return a randomly chosen list of n nonnegative integers summing to total.
Each such list is equally likely to occur."""
return [x - 1 for x in constrained_sum_sample_pos(n, total + n)]
Графическая иллюстрация constrained_sum_sample_pos(4, 10)
, благодаря @FM. (Отредактировано немного.)
0 1 2 3 4 5 6 7 8 9 10 # The universe.
| | # Place fixed dividers at 0, 10.
| | | | | # Add 4 - 1 randomly chosen dividers in [1, 9]
a b c d # Compute the 4 differences: 2 3 4 1
Ответ 3
Сгенерируйте 4 случайных числа, вычислите их сумму, разделите каждую на сумму и умножьте на 40.
Если вам нужны целые числа, это потребует небольшой неслучайности.
Ответ 4
Использовать полиномиальное распределение
from numpy.random import multinomial
multinomial(40, [1/4.] * 4)
Ответ 5
В диапазоне [1,37] (с разрешенными повторами) существует только 37 ^ 4 = 1,874,161 единиц из четырех целых чисел. Перечислите их, сохраните и подсчитайте перестановки, которые составляют до 40.
(Это будет намного меньшее число, N).
Нарисуйте равномерно распределенные случайные целые числа K в интервале [0, N-1] и вернем K-ю перестановку. Это легко увидеть, чтобы гарантировать равномерное распределение по пространству возможных исходов, причем каждая позиция последовательности одинаково распределена. (Многие ответы, которые я вижу, будут иметь окончательный выбор, предвзятый ниже, чем первые три!)
Ответ 6
Предполагая, что вы хотите, чтобы они были равномерно распределены, и предполагая, что вы не хотите повторений
addends = []
picks = range(1, 34)
while sum(addends) != 40:
addends = random.sample(picks, 3)
if sum(addends) > 39:
continue
addends.append(40 - sum(addends))