Пайтон, функция random, математика, генетический отбор

программа является попыткой имитации генетического отбора в биологии, суть которого заключается в том, что при появлении потомства мама и папа дают ему свои гены, однако у людей гены бывают бракованными, в проге "2" это хороший ген, "1" это ген который работает на половину, а "0" это не рабочий ген (обычно такие люди рождаются мутантами и долго не живут), но в попытке написать это мы обнаружили что люди с единицами выражаются, и всё сводится либо к плохим(0) генам либо к хорошим(2) (в программе они по сути тождественны друг-другу), поводом написать программу стала наше желание узнать какие люди будут преобладать (ожидалось, что тех кого изначально было больше) в реальной жизни это работает не так как у нас в программе тк, ирл люди с мутациями обычно не оставляют потомства, да и не рождают только двух детей... вопрос: почему независимо от исходных значений единицы выраждаются, такого быть не должно это мы неправильно написали программу или что?

import numpy as np
import random as rd
def proc(): ## генирирует 1,2 или 0 с разными шансам у единицы 50%, у нуля и двойки по 25%
    a=0
    a = rd.randrange(1, 5)
    if a == 2:
        lst2.append(2)
    if a == 1 or a == 4:
        lst2.append(1)
    if a == 3:
        lst2.append(0)
lst=[]
lst2=[]
for i in range(45):
    lst.append(2)
for i in range(50):
    lst.append(1)
for i in range(5):
    lst.append(0)
print(lst)
for i in range(1000):
    rd.shuffle(lst)
    print(lst)
    for j in range(0,100,2):
        if lst[j]==2 and lst[j+1]==2:
            lst2.append(2)
            lst2.append(2)
        if lst[j] == 1 and lst[j + 1] == 2 or lst[j] == 2 and lst[j + 1] == 1:
            lst2.append(rd.randrange(1,3))
            lst2.append(rd.randrange(1,3))
        if lst[j] == 1 and lst[j + 1] == 1:
            proc()
            proc()
        if lst[j] == 1 and lst[j + 1] == 0 or lst[j] == 0 and lst[j + 1] == 1:
            lst2.append(rd.randrange(0, 2))
            lst2.append(rd.randrange(0, 2))
        if lst[j] == 2 and lst[j + 1] == 0 or lst[j] == 0 and lst[j + 1] == 2:
            lst2.append(1)
            lst2.append(1)
        if lst[j] == 0 and lst[j + 1] == 0:
            lst2.append(0)
            lst2.append(0)
    k1, k2, k3 = 0, 0, 0
    for i in range(100):
        if lst[i] == 2:
            k2 += 1
        if lst[i] == 1:
            k1 += 1
        if lst[i] == 0:
            k3 += 1
    print("2=", k2, " 1=", k1, " 0=", k3)
    lst = lst2
    lst2 = []
""

Ответы (1 шт):

Автор решения: CrazyElf

Проблемы:

  • В начальном заполнении
  • В правилах

Если вы посмотрите на правила, то по ним сохраняются стабильными все комбинации, кроме 1+1, которая рандомизируется в произвольные числа в определённом соотношении. Да, ещё есть шанс получить на выходе 1 и 1 по одному из правил, но для этого нужно сочетание 0+2 или 2+0. А теперь представьте себе ситуацию, когда чего-то одного у вас уже больше, чем другого - либо 0 либо 2. Много ли вы получите комбинаций 0+2 и 2+0 на выходе? Не больше, чем количество меньше встречающегося из этих двух чисел. Таким образом, если ситуация начнёт перекашиваться в какую-то сторону (в сторону 0 или в сторону 2), то количество 1 начнёт соответственно уменьшаться и чем дальше, тем сильнее.

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

Ну и в целом, эти правила можно было бы записать гораздо короче с помощью словаря, где ключом будет кортеж из двух значений, а значением можно прописать lambda, выдающую нужный результат (фиксированный, либо получаемый вызовом функции). Таким образом можно было бы код записать короче, проще и понятнее. Если не совсем ясно, я потом могу добавить такой код.

→ Ссылка