Как убедиться, что пара элементов в np.random.choice не отображаются вместе в цикле?

#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 могут быть улучшены, чтобы мы не включали повторные проверки. Я обновлю его позже