#python
Вопрос:
Я хотел бы создать список из 3 чисел со статистическими весами. Я нашел функцию random.choices, которая делает это дружелюбно.
random.choices(population=[0,1,2], weights = [0.4,0.3,0.3], k=100)
Но в дополнение к этому я хотел бы применить некоторые ограничения к этой генерации случайных чисел, где я хотел бы
- запретить последовательное появление 0
- запретите 2-му повторяться более двух раз подряд
похоже, функция random.choices() не обладает такой функциональностью. У кого-нибудь есть предложения о том, как подойти к этому?
С наилучшими пожеланиями и заранее спасибо за вашу помощь!
Ответ №1:
Поскольку выборки, выводимые random.choices
(помните: с заменой), статистически независимы, просто выбросьте тех участников, которые нарушают ваши ограничения. Вот пример генератора:
def restricted_choices(population, weights=None, k=1, restrictions={}):
"""Yield k values from `population` with restrictions.
Works almost like `random.choices()`.
For every item (k, v) in `restrictions` holds:
the yielded sequence does not include a sub-sequence `v * [k]`.
"""
N = 0 # count how many values we have yielded so far
last_value = None # last value that was yielded
repeat_count = 0 # how often it has been yielded in a row
while N < k:
while True:
x = random.choices(population, weights)[0]
if x == last_value and 1 repeat_count == restrictions.get(x, 0):
continue
break
yield x
N = 1
if x == last_value:
repeat_count = 1
else:
repeat_count = 1
last_value = x
Используйте его вот так:
list(restricted_choices(population=[0,1,2], weights = [0.4,0.3,0.3],
k=100, restrictions={0:2, 2:3}))
Однако обратите внимание, что результирующая последовательность больше не будет [.4, .3, .3]
распределяться.
Комментарии:
1. Привет! Большое спасибо за ваш ответ Х. Доблер! Работает как заклинание. Я надеялся сам выяснить, как переписать эту функцию динамическим способом, чтобы она могла обрабатывать различные объемы и ограничения типов без необходимости переписывать. В настоящее время я нахожусь на этом этапе:
2.
def nchoices_with_restrictions(probability_splits,restrictions): choice_list = [] i = 0 while i < 100: while True: x = rd.choices(range(len(probability_splits)), weights = probability_splits)[0] for restriction in restrictions: if x == restriction: continue choice_list.append(x) i = 1 break return choice_list
3. Который не только ужасно отформатирован, но и просто не работает.
4. Я не знаю, о каких ограничениях вы думаете. В любом случае, чтобы реализовать ограничения, отображающие произвольное количество элементов в обратном направлении , я бы предложил использовать a
collections.deque
в качестве гибкой заменыlast1
,last2
а для «кодирования» ваших ограничений вы могли бы использовать что-то вродеforbidden={0: [[0]], 2: [[2,2]]}
примера в вопросе.5. Привет! Спасибо за ваш ответ1 Ограничения будут одного и того же типа, так как все они будут ограничивать количество встречающихся в определенное время. Таким образом, вместо того, чтобы 0 не разрешалось повторяться последовательно, 1 не разрешалось бы повторяться 8 раз подряд. Также может быть введено еще несколько ограничений. В моем примере действовало только два правила, но желаемая функция должна была обрабатывать теоретически бесконечное количество правил. (На практике более 5, вероятно, не потребуется)