Как случайным образом изменить 5 значений в двоичном списке? - PullRequest
4 голосов
/ 25 мая 2020

Я пишу алгоритм geneti c, в котором мне нужно выбрать 5 чисел из двоичного списка genotype и перевернуть их, так что 10 и 01. Я попытался поместить свой код в al oop с range(1,6), однако, когда я это делаю, он все еще меняет только одно из чисел. Ниже мой исходный код без l oop, который случайным образом выбирает одно из двоичных значений и изменяет его. Кто-нибудь знает, как это сделать лучше, кроме 5 элементов в списке?

genotype = [1,0,0,1,0,0,1,1,1,0]

def mutate(self):
  gene = random.choice(genotype)
  if genotype[gene] == 1:
    genotype[gene] = 0
  else:
    genotype[gene] = 1
  return genotype

Ответы [ 4 ]

5 голосов
/ 25 мая 2020

Вы можете использовать функцию random.sample(), чтобы получить 5 уникальных индексов из списка, а затем перевернуть их в al oop. Вот так:

import random
genotype = [1,0,0,1,0,0,1,1,1,0]

random_five = random.sample(range(len(genotype)), 5)
for i in random_five:
    genotype[i] = 0 if genotype[i] == 1 else 1

print(genotype)

Результат:

[1, 1, 0, 1, 1, 0, 0, 1, 0, 1]
2 голосов
/ 25 мая 2020

Хотя ваша основная проблема кажется решенной после ответа, данного ilyankou :

for i in random.sample(range(len(genotype)), 5):
    genotype[i] ^= 1

, и была предложена эта альтернативная (более реалистичная c) модель мутации:

for i in [random.choice(range(len(genotype))) for _ in range(5)]:
    genotype[i] ^= 1

Я нашел это наблюдение довольно сложным и несколько вдохновляющим

Я попытался поместить свой код в al oop с диапазоном (1 , 6) однако, когда я это делаю, он все еще меняет только одно из чисел.

Это всегда так? Может это быть или должно быть?

Я пробовал несколько запусков следующего кода (я удалил лишнее self из вашего оригинала)

import random
genotype = [1,0,0,1,0,0,1,1,1,0]

def mutate():
  gene = random.choice(genotype)
  if genotype[gene] == 1:
    genotype[gene] = 0
  else:
    genotype[gene] = 1
  return genotype

print(genotype)

for _ in range(1,6):
    mutate()

print(genotype)

и наблюдал только эти результаты:

  1. [0, 0, 0, 1, 0, 0, 1, 1, 1, 0] - ген с индексом 0 перевернут
  2. [1, 1, 0, 1, 0, 0, 1, 1, 1, 0] - ген с индексом 1 перевернут

И действительно, это должно быть таким для нечетное количество вызовов к функции mutate выше:

Потому что gene является одним из 0 и 1, и двойные перевороты на одном и том же гене воспроизводят начальное значение останутся только мутации, соответствующие генным индексам, которые выбираются нечетное количество раз, и, поскольку вы называете это range(1, 6) (нечетное общее количество), только один из 0 и 1 может иметь нечетное количество в общий процесс.

2 голосов
/ 25 мая 2020

random.choice(genotype) вернет случайный элемент из списка генотипов, ie, он будет равен 0 или 1. Итак, поскольку вы используете gene в качестве индекса, ваша функция будет всегда переворачивайте элемент либо по индексу 0, либо по индексу 1.

Вместо этого вы можете использовать функцию random.sample(population, k).

1 голос
/ 28 мая 2020

Ваш вопрос больше относится к проблеме разработки программного обеспечения, а не к стороне EA. Но я хотел бы дать несколько советов по поводу вашего дизайнерского решения по выбору 5 генов из генома. Вы ограничиваете EA исследовать пространство поиска для ваших решений, и ваш EA определенно может застрять в локальных оптимумах и не сможет сбежать, поскольку мутировавшие решения будут изменены только вокруг 5 генов (если ограничение связано с самой проблемой, ничего не могу с этим поделать). Например, EA может найти почти оптимальное решение, просто изменив 3 гена или изменив 7 генов. Если это выбор дизайна, вы можете рассмотреть возможность пересмотра своего дизайнерского решения для EA.

В целом сообщество EA использует вероятность мутации для генов. Когда кто-то хочет мутировать потомство, он основан на вероятности мутации гиперпараметра (Кроме того, поскольку это гиперпараметр, вы также можете настроить его для своей проблемы, чтобы позже достичь хороших результатов).

Допустим, ваше проектное решение мутации 5 генов является ограничением, и вы также хотели бы использовать настраиваемую вероятность мутации гиперпараметров. У вас может быть свое решение, как показано ниже:

import random

def mutate(genotype, m_probe):
  mutated_offspring = []
  mutated_genes_indexes = set()
  for index, gene in enumerate(genotype):
    if random.uniform(0, 1) >= m_probe and len(mutated_genes_indexes) < 5:
      mutated_offspring.append(int(not gene))
      mutated_genes_indexes.add(index)
    else:
      mutated_offspring.append(int(gene))
  print("Mutated genes indexes: ", mutated_genes_indexes)
  return mutated_offspring

# Each genes have 20% probability to get mutated! NOTE: with higher probability you might not find 5 genes mutated, 20 is chosen based on the constraint and can be tuned later with this constraint.
genotype = [1,0,0,1,0,0,1,1,1,0]
print(mutate(genotype, 0.20))

Мое предпочтительное дизайнерское решение было бы равным шансом для всех генов мутировать без ограничений. В этом случае решение может выглядеть следующим образом:

import random

def mutate(genotype, m_probe):
  mutated_offspring = []
  mutated_genes_indexes = set()
  for index, gene in enumerate(genotype):
    if random.uniform(0, 1) >= m_probe:
      mutated_offspring.append(int(not gene))
      mutated_genes_indexes.add(index)
    else:
      mutated_offspring.append(int(gene))
  print("Mutated genes indexes: ", mutated_genes_indexes)
  return mutated_offspring

genotype = [1,0,0,1,0,0,1,1,1,0]
print(mutate(genotype, 0.50))
...