AI-For-Beginners/translations/de/lessons/6-Other/21-GeneticAlgorithms/Genetic.ipynb

707 lines
32 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"# Genetische Algorithmen\n",
"\n",
"Dieses Notebook ist Teil des [AI for Beginners Curriculum](http://github.com/microsoft/ai-for-beginners).\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"import random\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import math\n",
"import time"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Ein wenig Theorie\n",
"\n",
"**Genetische Algorithmen** (GA) basieren auf einem **evolutionären Ansatz** der KI, bei dem Methoden der Populationsentwicklung verwendet werden, um eine optimale Lösung für ein gegebenes Problem zu finden. Sie wurden 1975 von [John Henry Holland](https://en.wikipedia.org/wiki/John_Henry_Holland) vorgeschlagen.\n",
"\n",
"Genetische Algorithmen basieren auf den folgenden Ideen:\n",
"* Gültige Lösungen für das Problem können als **Gene** dargestellt werden.\n",
"* **Crossover** ermöglicht es, zwei Lösungen zu kombinieren, um eine neue gültige Lösung zu erhalten.\n",
"* **Selektion** wird verwendet, um optimalere Lösungen mithilfe einer **Fitnessfunktion** auszuwählen.\n",
"* **Mutationen** werden eingeführt, um die Optimierung zu destabilisieren und uns aus einem lokalen Minimum herauszuführen.\n",
"\n",
"Wenn Sie einen genetischen Algorithmus implementieren möchten, benötigen Sie Folgendes:\n",
"\n",
" * Eine Methode, um die Problemlösungen mithilfe von **Genen** $g\\in\\Gamma$ zu codieren.\n",
" * Auf der Menge der Gene $\\Gamma$ müssen wir eine **Fitnessfunktion** $\\mathrm{fit}: \\Gamma\\to\\mathbb{R}$ definieren. Kleinere Funktionswerte entsprechen besseren Lösungen.\n",
" * Einen **Crossover-Mechanismus**, um zwei Gene zu kombinieren und eine neue gültige Lösung zu erhalten $\\mathrm{crossover}: \\Gamma^2\\to\\Gamma$.\n",
" * Einen **Mutationsmechanismus** $\\mathrm{mutate}: \\Gamma\\to\\Gamma$.\n",
"In vielen Fällen sind Crossover und Mutation recht einfache Algorithmen, um Gene als numerische Sequenzen oder Bitvektoren zu manipulieren.\n",
"\n",
"Die spezifische Implementierung eines genetischen Algorithmus kann je nach Fall variieren, aber die allgemeine Struktur ist wie folgt:\n",
"\n",
"1. Wählen Sie eine Anfangspopulation $G\\subset\\Gamma$.\n",
"2. Wählen Sie zufällig eine der Operationen aus, die in diesem Schritt ausgeführt werden sollen: Crossover oder Mutation.\n",
"3. **Crossover**:\n",
" * Wählen Sie zufällig zwei Gene $g_1, g_2 \\in G$.\n",
" * Berechnen Sie das Crossover $g=\\mathrm{crossover}(g_1,g_2)$.\n",
" * Wenn $\\mathrm{fit}(g)<\\mathrm{fit}(g_1)$ oder $\\mathrm{fit}(g)<\\mathrm{fit}(g_2)$ - ersetzen Sie das entsprechende Gen in der Population durch $g$.\n",
"4. **Mutation** - Wählen Sie ein zufälliges Gen $g\\in G$ und ersetzen Sie es durch $\\mathrm{mutate}(g)$.\n",
"5. Wiederholen Sie ab Schritt 2, bis wir einen ausreichend kleinen Wert von $\\mathrm{fit}$ erhalten oder bis das Limit der Anzahl der Schritte erreicht ist.\n",
"\n",
"Typische Aufgaben, die durch GA gelöst werden:\n",
"1. Optimierung von Zeitplänen\n",
"1. Optimales Packen\n",
"1. Optimales Schneiden\n",
"1. Beschleunigung der erschöpfenden Suche\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Problem 1: Gerechte Schatzaufteilung\n",
"\n",
"**Aufgabe**: \n",
"Zwei Personen haben einen Schatz gefunden, der Diamanten unterschiedlicher Größen (und entsprechend unterschiedlicher Preise) enthält. Sie müssen den Schatz in zwei Teile aufteilen, sodass der Preisunterschied 0 (oder minimal) ist.\n",
"\n",
"**Formale Definition**: \n",
"Wir haben eine Menge von Zahlen $S$. Wir müssen sie in zwei Teilmengen $S_1$ und $S_2$ aufteilen, sodass $$\\left|\\sum_{i\\in S_1}i - \\sum_{j\\in S_2}j\\right|\\to\\min$$ und $S_1\\cup S_2=S$, $S_1\\cap S_2=\\emptyset$.\n",
"\n",
"Zunächst definieren wir die Menge $S$:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[8344 2197 9335 3131 5863 9429 3818 9791 15 5455 1396 9538 4872 6549\n",
" 8587 5986 6021 9764 8102 5083 5739 7684 8498 3007 6599 820 7490 2372\n",
" 9370 5235 3525 3154 859 1906 8159 3950 2173 2988 2050 349 8713 2284\n",
" 4177 6033 1651 9176 5049 8201 171 5081 1216 3756 4711 2757 7738 1272\n",
" 5650 6584 5395 9004 7797 969 8104 1283 1392 4001 5768 445 274 256\n",
" 8239 8015 4381 9021 1189 8879 1411 3539 6526 8011 136 7230 2332 451\n",
" 5702 2989 4320 2446 9578 8486 4027 2410 9588 8981 2177 1493 3232 9151\n",
" 4835 5594 6859 8394 369 3200 126 4259 2283 7755 2014 2458 8327 8082\n",
" 7413 7622 1206 5533 8751 3495 5868 8472 6850 3958 3149 4672 4810 6274\n",
" 4700 6134 4627 4616 6656 9949 884 2256 7419 1926 7973 5319 5967 9158\n",
" 3823 7697 9466 5675 5412 9784 5426 8209 3421 1136 6047 4429 8001 4417\n",
" 1381 722 7350 6018 6235 7860 5853 7660 5937 6242 1 9552 3971 8302\n",
" 2633 9227 7283 154 8599 4269 9392 8539 1630 368 2409 9351 3838 9814\n",
" 6186 5743 5083 1325 1610 779 3643 3262 5768 8725 961 4611 6310 4788\n",
" 1648 5951 8118 7779]\n"
]
}
],
"source": [
"N = 200\n",
"S = np.array([random.randint(1,10000) for _ in range(N)])\n",
"print(S)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lassen Sie uns jede mögliche Lösung des Problems durch einen Binärvektor $B\\in\\{0,1\\}^N$ kodieren, wobei die Zahl an der $i$-ten Position zeigt, zu welcher der Mengen ($S_1$ oder $S_2$) die $i$-te Zahl in der ursprünglichen Menge $S$ gehört. Die Funktion `generate` wird diese zufälligen Binärvektoren erzeugen.\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[1 0 0 1 1 1 1 1 0 1 1 1 0 0 1 0 1 1 1 0 0 1 1 0 1 1 0 0 1 0 1 0 1 0 1 1 1\n",
" 0 1 1 1 0 1 0 0 1 0 0 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 0 1 1 0 0 0 0 1 0 1 0\n",
" 1 0 0 0 0 0 1 1 0 1 0 0 1 0 1 0 0 1 1 0 0 1 1 1 0 0 1 1 0 1 1 0 0 0 0 1 1\n",
" 1 0 1 0 0 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 1 1 0 1 0 1 0 1 0 0 1 1 1 0 0 1 1\n",
" 0 1 1 0 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0 1 1 0 1 1 0 0 1 1 0\n",
" 0 0 0 1 0 1 1 0 1 1 0 1 0 0 0]\n"
]
}
],
"source": [
"def generate(S):\n",
" return np.array([random.randint(0,1) for _ in S])\n",
"\n",
"b = generate(S)\n",
"print(b)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lassen Sie uns nun die Funktion `fit` definieren, die die \"Kosten\" der Lösung berechnet. Es wird die Differenz zwischen der Summe der beiden Mengen $S_1$ und $S_2$ sein:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"trusted": true
},
"outputs": [
{
"data": {
"text/plain": [
"133784"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def fit(B,S=S):\n",
" c1 = (B*S).sum()\n",
" c2 = ((1-B)*S).sum()\n",
" return abs(c1-c2)\n",
"\n",
"fit(b)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nun müssen wir Funktionen für Mutation und Kreuzung definieren:\n",
"* Für die Mutation wählen wir ein zufälliges Bit aus und negieren es (ändern von 0 zu 1 und umgekehrt).\n",
"* Für die Kreuzung nehmen wir einige Bits aus einem Vektor und einige Bits aus einem anderen. Wir verwenden die gleiche `generate`-Funktion, um zufällig auszuwählen, welche Bits aus welchen der Eingabemasken übernommen werden.\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"def mutate(b):\n",
" x = b.copy()\n",
" i = random.randint(0,len(b)-1)\n",
" x[i] = 1-x[i]\n",
" return x\n",
"\n",
"def xover(b1,b2):\n",
" x = generate(b1)\n",
" return b1*x+b2*(1-x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lass uns eine Anfangspopulation der Lösungen $P$ der Größe `pop_size` erstellen:\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"pop_size = 30\n",
"P = [generate(S) for _ in range(pop_size)]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nun, die Hauptfunktion zur Durchführung der Evolution. `n` ist die Anzahl der Evolutionsschritte, die durchgeführt werden sollen. In jedem Schritt:\n",
"* Mit einer Wahrscheinlichkeit von 30 % führen wir eine Mutation durch und ersetzen das Element mit der schlechtesten `fit`-Funktion durch das mutierte Element.\n",
"* Mit einer Wahrscheinlichkeit von 70 % führen wir ein Crossover durch.\n",
"\n",
"Die Funktion gibt die beste Lösung (Gen, das der besten Lösung entspricht) und die Historie der minimalen `fit`-Funktion in der Population bei jeder Iteration zurück.\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[0 0 0 1 1 0 0 0 0 1 1 1 0 1 0 0 0 1 0 1 0 1 0 1 0 1 1 0 0 0 0 0 1 0 1 1 0\n",
" 0 0 0 1 1 0 0 1 0 0 0 0 0 1 0 0 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1 1 0 1 0 0 0\n",
" 0 1 1 1 0 1 0 1 1 1 1 1 0 0 0 1 1 0 1 0 0 1 0 0 1 1 1 1 1 1 1 1 0 1 0 1 1\n",
" 0 1 1 0 0 0 0 1 1 1 1 0 1 0 0 1 0 1 1 1 0 1 0 0 0 0 0 0 1 1 0 0 0 1 1 0 0\n",
" 1 0 1 1 1 1 1 0 1 0 1 0 1 1 1 0 0 0 1 1 0 0 0 0 0 0 1 1 1 0 1 0 0 0 1 0 1\n",
" 0 1 0 1 0 0 1 1 1 0 1 1 0 0 1] 4\n"
]
}
],
"source": [
"def evolve(P,S=S,n=2000):\n",
" res = []\n",
" for _ in range(n):\n",
" f = min([fit(b) for b in P])\n",
" res.append(f)\n",
" if f==0:\n",
" break\n",
" if random.randint(1,10)<3:\n",
" i = random.randint(0,len(P)-1)\n",
" b = mutate(P[i])\n",
" i = np.argmax([fit(z) for z in P])\n",
" P[i] = b\n",
" else:\n",
" i = random.randint(0,len(P)-1)\n",
" j = random.randint(0,len(P)-1)\n",
" b = xover(P[i],P[j])\n",
" if fit(b)<fit(P[i]):\n",
" P[i]=b\n",
" elif fit(b)<fit(P[j]):\n",
" P[j]=b\n",
" else:\n",
" pass\n",
" i = np.argmin([fit(b) for b in P])\n",
" return (P[i],res)\n",
"\n",
"(s,hist) = evolve(P)\n",
"print(s,fit(s))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Man kann sehen, dass es uns gelungen ist, die `fit`-Funktion erheblich zu minimieren! Hier ist der Graph, der zeigt, wie sich die `fit`-Funktion für die gesamte Population während des Prozesses verhält.\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"trusted": true
},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"plt.plot(hist)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Problem 2: N-Damen-Problem\n",
"\n",
"**Aufgabe**: \n",
"Du musst $N$ Damen auf einem Schachbrett der Größe $N\\times N$ so platzieren, dass sie sich gegenseitig nicht angreifen.\n",
"\n",
"Zunächst lösen wir das Problem ohne genetische Algorithmen, indem wir eine vollständige Suche durchführen. Wir können den Zustand des Schachbretts durch die Liste $L$ darstellen, wobei die $i$-te Zahl in der Liste die horizontale Position der Dame in der $i$-ten Reihe angibt. Es ist ziemlich offensichtlich, dass jede Lösung nur eine Dame pro Reihe haben wird und jede Reihe eine Dame enthalten muss.\n",
"\n",
"Unser Ziel ist es, die erste Lösung für das Problem zu finden, nach der wir die Suche beenden. Du kannst diese Funktion leicht erweitern, um alle möglichen Positionen für die Damen zu generieren.\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[1, 5, 8, 6, 3, 7, 2, 4]\n"
]
},
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"N = 8\n",
"\n",
"def checkbeats(i_new,j_new,l):\n",
" for i,j in enumerate(l,start=1):\n",
" if j==j_new:\n",
" return False\n",
" else:\n",
" if abs(j-j_new) == i_new-i:\n",
" return False\n",
" return True\n",
"\n",
"def nqueens(l,N=8,disp=True):\n",
" if len(l)==N:\n",
" if disp: print(l)\n",
" return True\n",
" else:\n",
" for j in range(1,N+1):\n",
" if checkbeats(len(l)+1,j,l):\n",
" l.append(j)\n",
" if nqueens(l,N,disp): return True\n",
" else: l.pop()\n",
" return False\n",
" \n",
"nqueens([],8)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lassen Sie uns nun messen, wie lange es dauert, eine Lösung für das 20-Damen-Problem zu finden:\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"10.6 s ± 2.17 s per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit nqueens([],20,False)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lassen Sie uns dasselbe Problem mit einem genetischen Algorithmus lösen. Diese Lösung ist inspiriert von [diesem Blogbeitrag](https://kushalvyas.github.io/gen_8Q.html).\n",
"\n",
"Wir werden jede Lösung durch dieselbe Liste der Länge $N$ darstellen, und als `fit`-Funktion nehmen wir die Anzahl der Damen, die sich gegenseitig angreifen:\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"def fit(L):\n",
" x=0\n",
" for i1,j1 in enumerate(L,1):\n",
" for i2,j2 in enumerate(L,1):\n",
" if i2>i1:\n",
" if j2==j1 or (abs(j2-j1)==i2-i1): x+=1\n",
" return x"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Da die Berechnung der Fitnessfunktion zeitaufwendig ist, speichern wir jede Lösung in der Population zusammen mit dem Wert der Fitnessfunktion. Lassen Sie uns die Anfangspopulation generieren:\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"trusted": true
},
"outputs": [
{
"data": {
"text/plain": [
"[(array([2, 3, 8, 7, 5, 4, 1, 6]), 4),\n",
" (array([3, 4, 5, 1, 2, 8, 6, 7]), 8),\n",
" (array([1, 3, 7, 4, 5, 8, 6, 2]), 6),\n",
" (array([1, 5, 4, 6, 8, 3, 7, 2]), 4),\n",
" (array([3, 5, 7, 1, 8, 6, 4, 2]), 3)]"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def generate_one(N):\n",
" x = np.arange(1,N+1)\n",
" np.random.shuffle(x)\n",
" return (x,fit(x))\n",
"\n",
"def generate(N,NP):\n",
" return [generate_one(N) for _ in range(NP)]\n",
"\n",
"generate(8,5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Jetzt müssen wir Mutations- und Kreuzungsfunktionen definieren. Die Kreuzung würde zwei Gene miteinander kombinieren, indem sie an einem zufälligen Punkt aufgebrochen und zwei Teile von verschiedenen Genen zusammengefügt werden.\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"trusted": true
},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 2, 7, 8])"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def mutate(G):\n",
" x=random.randint(0,len(G)-1)\n",
" G[x]=random.randint(1,len(G))\n",
" return G\n",
" \n",
"def xover(G1,G2):\n",
" x=random.randint(0,len(G1))\n",
" return np.concatenate((G1[:x],G2[x:]))\n",
"\n",
"xover([1,2,3,4],[5,6,7,8])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"def choose_rand(P):\n",
" N=len(P[0][0])\n",
" mf = N*(N-1)//2 # max fitness fn\n",
" z = [mf-x[1] for x in P]\n",
" tf = sum(z) # total fitness\n",
" w = [x/tf for x in z]\n",
" p = np.random.choice(len(P),2,False,p=w)\n",
" return p[0],p[1]\n",
"\n",
"def choose(P):\n",
" def ch(w):\n",
" p=[]\n",
" while p==[]:\n",
" r = random.random()\n",
" p = [i for i,x in enumerate(P) if x[1]>=r]\n",
" return random.choice(p)\n",
" N=len(P[0][0])\n",
" mf = N*(N-1)//2 # max fitness fn\n",
" z = [mf-x[1] for x in P]\n",
" tf = sum(z) # total fitness\n",
" w = [x/tf for x in z]\n",
" p1=p2=0\n",
" while p1==p2:\n",
" p1 = ch(w)\n",
" p2 = ch(w)\n",
" return p1,p2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nun definieren wir die Hauptschleife der Evolution. Wir werden die Logik leicht anders gestalten als im vorherigen Beispiel, um zu zeigen, dass man kreativ sein kann. Wir werden so lange iterieren, bis wir die perfekte Lösung gefunden haben (Fitnessfunktion = 0). In jedem Schritt nehmen wir die aktuelle Generation und erzeugen eine neue Generation derselben Größe. Dies geschieht mit der Funktion `nxgeneration` anhand der folgenden Schritte:\n",
"\n",
"1. Verwerfe die am wenigsten geeigneten Lösungen dafür gibt es die Funktion `discard_unfit`.\n",
"2. Füge der Generation einige zufällige Lösungen hinzu.\n",
"3. Erstelle eine neue Generation der Größe `gen_size`, indem du für jedes neue Gen die folgenden Schritte ausführst:\n",
" - Wähle zwei zufällige Gene aus, mit einer Wahrscheinlichkeit proportional zur Fitnessfunktion.\n",
" - Berechne ein Crossover.\n",
" - Wende eine Mutation mit der Wahrscheinlichkeit `mutation_prob` an.\n"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"trusted": true
},
"outputs": [
{
"data": {
"text/plain": [
"(array([4, 7, 5, 3, 1, 6, 8, 2]), 0)"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mutation_prob = 0.1\n",
"\n",
"def discard_unfit(P):\n",
" P.sort(key=lambda x:x[1])\n",
" return P[:len(P)//3]\n",
"\n",
"def nxgeneration(P):\n",
" gen_size=len(P)\n",
" P = discard_unfit(P)\n",
" P.extend(generate(len(P[0][0]),3))\n",
" new_gen = []\n",
" for _ in range(gen_size):\n",
" p1,p2 = choose_rand(P)\n",
" n = xover(P[p1][0],P[p2][0])\n",
" if random.random()<mutation_prob:\n",
" n=mutate(n)\n",
" nf = fit(n)\n",
" new_gen.append((n,nf))\n",
" '''\n",
" if (nf<=P[p1][1]) or (nf<=P[p2][1]):\n",
" new_gen.append((n,nf))\n",
" elif (P[p1][1]<P[p2][1]):\n",
" new_gen.append(P[p1])\n",
" else:\n",
" new_gen.append(P[p2])\n",
" '''\n",
" return new_gen\n",
" \n",
"def genetic(N,pop_size=100):\n",
" P = generate(N,pop_size)\n",
" mf = min([x[1] for x in P])\n",
" n=0\n",
" while mf>0:\n",
" #print(\"Generation {0}, fit={1}\".format(n,mf))\n",
" n+=1\n",
" mf = min([x[1] for x in P])\n",
" P = nxgeneration(P)\n",
" mi = np.argmin([x[1] for x in P])\n",
" return P[mi]\n",
"\n",
"genetic(8)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Es ist interessant, dass wir meistens ziemlich schnell eine Lösung finden können, aber in einigen seltenen Fällen erreicht die Optimierung ein lokales Minimum, und der Prozess bleibt für lange Zeit stecken. Es ist wichtig, dies zu berücksichtigen, wenn man die durchschnittliche Zeit misst: Während der genetische Algorithmus in den meisten Fällen schneller als die vollständige Suche ist, kann er in einigen Fällen länger dauern. Um dieses Problem zu überwinden, macht es oft Sinn, die Anzahl der zu berücksichtigenden Generationen zu begrenzen, und wenn wir nicht in der Lage sind, die Lösung zu finden - können wir von vorne beginnen.\n"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The slowest run took 18.71 times longer than the fastest. This could mean that an intermediate result is being cached.\n",
"26.4 s ± 28.7 s per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"%timeit genetic(10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Haftungsausschluss**: \nDieses Dokument wurde mit dem KI-Übersetzungsdienst [Co-op Translator](https://github.com/Azure/co-op-translator) übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5"
},
"kernelspec": {
"display_name": "Python 3.6",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.5"
},
"coopTranslator": {
"original_hash": "1012c117808753433f6e2696e775ff4b",
"translation_date": "2025-08-31T15:41:19+00:00",
"source_file": "lessons/6-Other/21-GeneticAlgorithms/Genetic.ipynb",
"language_code": "de"
}
},
"nbformat": 4,
"nbformat_minor": 2
}