#python #numpy #montecarlo
Вопрос:
В настоящее время я пытаюсь запустить симуляцию МонтеКарло без замены, используя np.random.choice, но в списке есть определенные элементы, которые не могут отображаться вместе. Например, если у меня есть список из пяти элементов: RO, MI, VE,NA, SI, и каждый цикл создает группу из четырех элементов, RO может отображаться с VE, MI или NA, но не может отображаться с SI на каждой итерации. Таким образом,цикл типа: [RO,MI,VE,NA] является правильным,но не: [RO,MI, SI, NA], поскольку SI появляется в той же группе, что и RO. Это код, который я в настоящее время использую (который создает неправильную группировку):
np.random.seed(42)
portfolio=[]
for i in range(0,10000):
port_gar = list(np.random.choice(cities, size=4, replace=False, p=cities_prob))
portfolio.append(port_gar)
print(portfolio)
Я в недоумении относительно того, что можно было бы сделать, и любая помощь была бы признательна. Спасибо!
Комментарии:
1. Почему бы не разделить города на две группы: те, которые могут смешиваться и сочетаться без ограничений, и все города, которые нельзя сгруппировать вместе в их собственном списке. Затем возьмите X предметов из городов, которые могут смешиваться, а затем один предмет из городов, которые не играют хорошо.
2. @blorgon Да, на самом деле у меня около 300, но в качестве примера я использовал пять! Я подумал о том, чтобы поставить оператор if после random.choice, чтобы указать, что если два элемента не отображаются вместе в группе, добавить эту группу во второй список (портфолио). Но я не уверен, что это сработает с несколькими исключениями :/
3. @blorgon
replace=False
гарантирует уникальные предметы, если в списке есть хотя быsize
уникальные предметы.4. Да, @тревор-поуп , я думал о встроенном
choice
.5. Я обновил свое решение с учетом этого.
Ответ №1:
Я представляю два решения, оба из которых используют random
модуль из стандартной библиотеки. Я рекомендую этот подход по сравнению с использованием numpy, так как вы никак не можете воспользоваться преимуществами numpy здесь, и особенно потому, что в конце вы даже не получите массив numpy (вы используете numpy только для генерации случайных чисел).
Решение 1. в каждой выборке есть ровно один город из группы «эксклюзивные города».
Что-то, что вы могли бы сделать, — это выделить свои города, которые не играют хорошо, в отдельную группу от других:
import random
random.seed(42)
n = 10 # whatever total number of items you want per sample
num_samples = 10000 # total number of samples
free_cities = [...] # all cities in this group play nicely together
exclusive_cities = [...] # cities in this group cannot be grouped in a sample, so we will only ever choose one city at a time from this group
portfolio = []
for _ in range(num_samples):
free_sample = random.sample(free_cities, k=(n-1))
exclusive_sample = random.sample(exclusive_cities, k=1)
portfolio.append(random.sample(free_sample exclusive_sample, k=n))
Вот надуманный пример:
n = 6
num_samples = 10
free_cities = ["AW", "JB", "EX", "HZ", "MZ", "XQ", "KA", "MW", "WZ", "UD"]
exclusive_cities = ["RO", "VE", "SI", "NA"]
portfolio = []
for _ in range(num_samples):
free_sample = random.sample(free_cities, k=(n-1))
exclusive_sample = random.sample(exclusive_cities, k=1)
portfolio.append(random.sample(free_sample exclusive_sample, k=n))
Выход:
>>> portfolio
[['AW', 'EX', 'WZ', 'RO', 'MZ', 'JB'],
['RO', 'MZ', 'KA', 'WZ', 'XQ', 'EX'],
['AW', 'MW', 'VE', 'JB', 'WZ', 'XQ'],
['NA', 'WZ', 'JB', 'MW', 'EX', 'MZ'],
['SI', 'UD', 'AW', 'JB', 'WZ', 'MW'],
['MZ', 'JB', 'UD', 'VE', 'WZ', 'HZ'],
['NA', 'KA', 'UD', 'AW', 'MW', 'WZ'],
['JB', 'NA', 'UD', 'KA', 'WZ', 'MW'],
['MZ', 'RO', 'JB', 'HZ', 'AW', 'XQ'],
['WZ', 'HZ', 'UD', 'JB', 'VE', 'XQ']]
Теперь следует знать, что это гарантирует, что в каждой выборке будет ровно один город из exclusive_cities
группы:
for sample in portfolio:
print(set(sample) amp; set(exclusive_cities))
Выход:
# Every sample has one item from the exclusive_cities group
{'RO'}
{'RO'}
{'VE'}
{'NA'}
{'SI'}
{'VE'}
{'NA'}
{'NA'}
{'RO'}
{'VE'}
Решение 2. в каждой выборке есть не более одного города из группы «эксклюзивные города».
Если это не ваше желаемое поведение, вы можете использовать дополнительный «бросок монеты», чтобы определить, отображаются ли в данном примере 1 или 0 эксклюзивных городов с этой незначительной модификацией приведенной выше логики:
n = 6
num_samples = 10
portfolio = []
for _ in range(num_samples):
include = random.choice((0, 1))
free_sample = random.sample(free_cities, k=(n - include))
exclusive_sample = random.sample(exclusive_cities, k=include)
portfolio.append(random.sample(free_sample exclusive_sample, k=n))
Теперь ваши образцы могут включать или не включать эксклюзивный город, но все равно только один максимум:
# An empty set means an exclusive city isn't present in that sample
set()
set()
{'SI'}
{'NA'}
set()
{'RO'}
{'SI'}
{'VE'}
set()
{'RO'}
Ответ №2:
Не зная больше об ограничениях, по которым города могут отображаться в списке, самым простым решением может быть случайное создание городов до тех пор, пока у вас не будет достаточного количества допустимых городов. Например:
def check_valid(port_gar):
is_valid = True
if 'RO' in port_gar:
is_valid = is_valid and ('NA' not in port_gar and 'VE' not in port_gar)
if 'NA' in port_gar:
is_valid = is_valid and 'VE' not in port_gar
# Add other checks for constraints here
return is_valid
portfolio = []
while len(portfolio) < 10000:
port_gar = list(np.random.choice(cities, size=4, replace=False, p=cities_prob))
if check_valid(port_gar):
portfolio.append(port_gar)
print(portfolio)
Это определенно не самая эффективная реализация, но если количество выборок относительно невелико (в данном случае 10000), а количество городов велико, то производительность должна быть хорошей.
Комментарии:
1. Было бы гораздо лучше запустить счетчик , который увеличивается каждый раз, когда добавляется образец
portfolio
, таким образом, вы не вызываетеlen
каждую итерацию, что крайне неэффективно.2. Согласен, и заявления if могут быть улучшены, чтобы мы не включали повторные проверки. Я обновлю его позже