Experiment: selekčný tlak

Cieľom je merať selekčný tlak rôznych metód selekcie. Ide o to, ako veľmi jednotlivé selekčné metódy uprednostňujú jedincov s vyššou vhodnosťou oproti jedincom s vhodnosťou nižšou.

Selekčný tlak bude meraný nepriamo pomocou určenia doby prevzatia (takeover time), čo je doba ktorú potrebuje jedinec s najväčšou vhodnosťou na to, aby sa stal dominantným v populácii (aby vyplnil celú populáciu svojimi kópiami). Čím je doba prevzatia menšia, tým silnejšie musel byť najlepší jedinec preferovaný voči ostatným jedincom a teda tým je vyvinutý selekčný tlak väčší.

Podstata experimentu

Je daná skupina jedincov, pričom každý z nich má pridelenú vhodnosť. Existuje jeden jedinec s najväčšou vhodnosťou (trebárs Φ(best)=1.0), zatiaľ čo ostatné jedince majú vhodnosť menšiu (môžu mať navzájom rôzne vhodnosti ale nie je to nutné).

Realizuje sa selekčný proces ako séria selekcií tvaru P -> P' -> P'' -> ... -> P''''''', pričom každá selekcia robí výber zo skupiny jedincov, ktorá vznikla ako výsledok predchádzajúcej selekcie. Toto reťazenie pokračuje dovtedy, kým nenastane jedna zo situácií:

  1. najlepší jedinec úplne vypadne z populácie (nebude v nej ani jedna jeho kópia),
  2. najlepší jedinec vyplní svojimi kópiami celú populáciu,
  3. uplynie maximálne povolený počet selekcií v sekvencii.

Keďže sa jedná o stochastický proces, tak musí byť viackrát opakovaný pre získanie spoľahlivej vzorky dát. Ak v rámci tohto opakovania sa viackrát stalo, že najlepší jedinec dominoval v populácii, tak sa určí priemerný počet selekcií, ktorý je potrebným pre dosiahnutie tejto dominancie.

Príprava

Pre prípravu experimentu je potrebné doplniť (nahradiť) kód bunke venovanej selekčnej metóde. Aktuálne je v nej imlementované vzorkovanie SSwR (teda základná ruleta). Je možné meniť metódu pre:

  1. premapovanie vhodnosti (aktuálne identita t.j. žiadne)
  2. určenie pravdepodobnosti selekcie (aktuálne proporcionálna selekcia)
  3. vzorkovanie jedného rodiča (aktuálne SSwR)
  4. selekciu rodičov (aktuálne opakovaná selekcia po jednom rodičovi)
In [1]:
import random
from functools import reduce
from operator import add
In [2]:
# Generovanie populácie

μ = 100  # veľkosť populácie
jedince = [1] + [0 for i in range(μ-1)]
#jedince
In [3]:
# Určenie vhodnosti jedincov

MIN = 0.2  # minimalna mozna vhodnosť jedincov (okrem najlepsieho)
MAX = 0.5  # maximalna mozna vhodnosť jedincov (okrem najlepsieho)

def Φ(jedinec):
    if jedinec == 1:
        return 1.0
    else:
        return random.uniform(MIN, MAX)

populacia = [(i, Φ(i)) for i in jedince]
#populacia
In [4]:
# Selekčná metóda - vyberá sa toľko rodičov, koľko je jedincov v populácii

def premapovanie_vhodnosti(jedince):    # identita
    map_fun = lambda x: x
    premap_Φ = [map_fun(x) for (_,x) in jedince]
    return premap_Φ
    
def urcenie_pravdepodobnosti_selekcie(premap_Φ, jedince):   # proporcionalna selekcia
    sum_Φ = reduce(add, premap_Φ)
    ps = [Φ/sum_Φ for Φ in premap_Φ]
    return ps

def vyber_rodica(ps, jedince):       # SSwR vzorkovanie - nepresne (maximalne rozpatie)
    jazycek = μ * random.random()

    index = 0
    sum_η = ps[index] * μ
    while(sum_η < jazycek):
        index += 1
        sum_η += ps[index] * μ

    return jedince[index]

def selekcia(jedince):
    premap_Φ = premapovanie_vhodnosti(jedince)
    ps = urcenie_pravdepodobnosti_selekcie(premap_Φ, jedince)
    
    rodicia = []
    for _ in range(μ):
        rodicia.append(vyber_rodica(ps, jedince))
    return rodicia
In [5]:
# Experiment - jeden beh

MAXPOC_SELEKCII = 2 * μ

def seria_selekcii(populacia):
    vyber_z_populacie = populacia
    for i in range(MAXPOC_SELEKCII):
        zdrojova_populacia = vyber_z_populacie
        
        vyber_z_populacie = selekcia(zdrojova_populacia)
        poc_kopii_najlepsieho = reduce(add, map(lambda x: x[0], vyber_z_populacie))
        
        if poc_kopii_najlepsieho == μ:
            return 'vyplnenie', i
        if poc_kopii_najlepsieho == 0:
            return 'strata', i+1
        
    return 'vyskyt', i+1
In [6]:
# Experiment - opakovane sekvencie selekcii

OPAKOVANIA = 1000

vysledky = [seria_selekcii(populacia) for _ in range(OPAKOVANIA)]

print(
    f"Pocet behov "
    f"\n   so stratou najlepsieho    : {len(list(filter(lambda x: x[0] == 'strata', vysledky)))}"
    f"\n   s dominanciou najlepsieho : {len(list(filter(lambda x: x[0] == 'vyplnenie', vysledky)))}"
    f"\n   s vyskytom najlepsieho    : {len(list(filter(lambda x: x[0] == 'vyskyt', vysledky)))}"
)

vyplnenia = list(map(lambda x: x[1], (filter(lambda x: x[0] == 'vyplnenie', vysledky))))
if vyplnenia != []:
    print(f"Pri dominancii najlepsi dominoval priemerne v {reduce(add,vyplnenia)/len(vyplnenia)}. iteracii")
Pocet behov 
   so stratou najlepsieho    : 85
   s dominanciou najlepsieho : 915
   s vyskytom najlepsieho    : 0
Pri dominancii najlepsi dominoval priemerne v 10.691803278688525. iteracii