Selezione, Crossover e Mutazione
Strategie di selezione
La selezione è un processo cruciale negli algoritmi genetici, determina quali individui contribuiscono alla generazione successiva, bilanciando fitness e diversità. Esistono diverse strategie di selezione ampiamente utilizzate:
- Selezione a ruota della roulette: Assegna a ciascun individuo una probabilità di selezione proporzionale alla sua fitness. Immagina una ruota in cui la dimensione di ogni fetta corrisponde alla fitness; gli individui con fitness più elevata hanno una maggiore probabilità di essere selezionati;
- Selezione tramite torneo: Seleziona casualmente un gruppo (torneo) di individui e sceglie il migliore tra loro come genitore. Questo metodo è semplice ed efficace, e la dimensione del torneo può controllare la pressione selettiva;
- Selezione basata sul rango: Ordina gli individui in base alla fitness e assegna le probabilità di selezione in base al loro rango piuttosto che alla fitness assoluta. Questo aiuta a evitare la dominanza di pochi individui con fitness elevata, specialmente in problemi con grandi differenze di fitness.
1234567891011121314151617import random def tournament_selection(population, fitnesses, tournament_size=3): """ Selects one individual from the population using tournament selection. """ # Randomly pick tournament_size individuals selected_indices = random.sample(range(len(population)), tournament_size) # Find the one with the highest fitness best_index = max(selected_indices, key=lambda idx: fitnesses[idx]) return population[best_index] # Example usage population = [[0,1,1,0], [1,0,0,1], [1,1,0,0], [0,0,1,1]] fitnesses = [3, 2, 5, 4] parent = tournament_selection(population, fitnesses, tournament_size=2) print("Selected parent:", parent)
Operatori di crossover
Dopo la selezione, gli algoritmi genetici utilizzano il crossover per creare nuovi individui combinando informazioni da due genitori. Il crossover introduce variazione e consente all'algoritmo di esplorare nuove combinazioni di tratti all'interno della popolazione.
Tipi comuni di crossover:
-
Crossover a punto singolo: Un punto di crossover viene scelto casualmente. La prima parte di un genitore viene combinata con la parte rimanente dell'altro.
-
Crossover a due punti: Due punti vengono selezionati casualmente. Il segmento tra di essi viene scambiato tra i genitori per produrre la prole.
-
Crossover uniforme: Ogni gene della prole viene scelto casualmente da uno dei due genitori con uguale probabilità.
12345678910111213141516171819import random def single_point_crossover(parent1, parent2): """ Performs single-point crossover between two parents. """ if len(parent1) != len(parent2): raise ValueError("Parents must be of the same length") point = random.randint(1, len(parent1) - 1) child1 = parent1[:point] + parent2[point:] child2 = parent2[:point] + parent1[point:] return child1, child2 # Example usage p1 = [1, 0, 1, 0, 1] p2 = [0, 1, 0, 1, 0] offspring1, offspring2 = single_point_crossover(p1, p2) print("Offspring 1:", offspring1) print("Offspring 2:", offspring2)
Ruolo della Mutazione
La mutazione è uno dei meccanismi chiave negli algoritmi genetici. Introduce nuovo materiale genetico nella popolazione, aiutando l'algoritmo a evitare la stagnazione e a continuare l'esplorazione di nuove soluzioni. Senza la mutazione, la popolazione potrebbe diventare troppo simile, causando il blocco della ricerca in ottimi locali.
Perché la Mutazione è Importante
- Previene la convergenza prematura: la mutazione assicura che la popolazione non diventi troppo uniforme, evitando una convergenza subottimale;
- Mantiene la diversità: introducendo alterazioni casuali, la mutazione mantiene una vasta gamma di variazioni genetiche disponibili per le generazioni future;
- Permette di sfuggire agli ottimi locali: piccoli cambiamenti casuali consentono all'algoritmo di esplorare nuove aree dello spazio di ricerca che potrebbero portare a soluzioni migliori;
- Bilancia il crossover: mentre il crossover combina tratti esistenti, la mutazione ne introduce di nuovi, garantendo che l'algoritmo continui a generare possibilità inedite.
Insieme, queste proprietà rendono la mutazione essenziale per un processo di ricerca robusto e adattivo.
Operatori di Mutazione Comuni
Diverse rappresentazioni del problema richiedono tecniche di mutazione differenti. I due operatori più utilizzati sono:
- Mutazione bit-flip: per rappresentazioni binarie — inverte un bit da 0 a 1 o da 1 a 0, introducendo cambiamenti piccoli e controllati;
- Mutazione di scambio: per rappresentazioni basate su permutazioni (ad esempio, problemi di ordinamento) — scambia due elementi all'interno di un individuo per generare una nuova configurazione.
1234567891011121314151617181920import random def bit_flip_mutation(individual, mutation_rate=0.1): """ Performs bit-flip mutation on a binary list. """ mutated = [] for gene in individual: if random.random() < mutation_rate: mutated.append(1 - gene) # Flip bit else: mutated.append(gene) return mutated # Example usage original = [1, 0, 1, 1, 0] mutated = bit_flip_mutation(original, mutation_rate=0.5) print("Original:", original) print("Mutated:", mutated)
Grazie per i tuoi commenti!
Chieda ad AI
Chieda ad AI
Chieda pure quello che desidera o provi una delle domande suggerite per iniziare la nostra conversazione
Awesome!
Completion rate improved to 6.25
Selezione, Crossover e Mutazione
Scorri per mostrare il menu
Strategie di selezione
La selezione è un processo cruciale negli algoritmi genetici, determina quali individui contribuiscono alla generazione successiva, bilanciando fitness e diversità. Esistono diverse strategie di selezione ampiamente utilizzate:
- Selezione a ruota della roulette: Assegna a ciascun individuo una probabilità di selezione proporzionale alla sua fitness. Immagina una ruota in cui la dimensione di ogni fetta corrisponde alla fitness; gli individui con fitness più elevata hanno una maggiore probabilità di essere selezionati;
- Selezione tramite torneo: Seleziona casualmente un gruppo (torneo) di individui e sceglie il migliore tra loro come genitore. Questo metodo è semplice ed efficace, e la dimensione del torneo può controllare la pressione selettiva;
- Selezione basata sul rango: Ordina gli individui in base alla fitness e assegna le probabilità di selezione in base al loro rango piuttosto che alla fitness assoluta. Questo aiuta a evitare la dominanza di pochi individui con fitness elevata, specialmente in problemi con grandi differenze di fitness.
1234567891011121314151617import random def tournament_selection(population, fitnesses, tournament_size=3): """ Selects one individual from the population using tournament selection. """ # Randomly pick tournament_size individuals selected_indices = random.sample(range(len(population)), tournament_size) # Find the one with the highest fitness best_index = max(selected_indices, key=lambda idx: fitnesses[idx]) return population[best_index] # Example usage population = [[0,1,1,0], [1,0,0,1], [1,1,0,0], [0,0,1,1]] fitnesses = [3, 2, 5, 4] parent = tournament_selection(population, fitnesses, tournament_size=2) print("Selected parent:", parent)
Operatori di crossover
Dopo la selezione, gli algoritmi genetici utilizzano il crossover per creare nuovi individui combinando informazioni da due genitori. Il crossover introduce variazione e consente all'algoritmo di esplorare nuove combinazioni di tratti all'interno della popolazione.
Tipi comuni di crossover:
-
Crossover a punto singolo: Un punto di crossover viene scelto casualmente. La prima parte di un genitore viene combinata con la parte rimanente dell'altro.
-
Crossover a due punti: Due punti vengono selezionati casualmente. Il segmento tra di essi viene scambiato tra i genitori per produrre la prole.
-
Crossover uniforme: Ogni gene della prole viene scelto casualmente da uno dei due genitori con uguale probabilità.
12345678910111213141516171819import random def single_point_crossover(parent1, parent2): """ Performs single-point crossover between two parents. """ if len(parent1) != len(parent2): raise ValueError("Parents must be of the same length") point = random.randint(1, len(parent1) - 1) child1 = parent1[:point] + parent2[point:] child2 = parent2[:point] + parent1[point:] return child1, child2 # Example usage p1 = [1, 0, 1, 0, 1] p2 = [0, 1, 0, 1, 0] offspring1, offspring2 = single_point_crossover(p1, p2) print("Offspring 1:", offspring1) print("Offspring 2:", offspring2)
Ruolo della Mutazione
La mutazione è uno dei meccanismi chiave negli algoritmi genetici. Introduce nuovo materiale genetico nella popolazione, aiutando l'algoritmo a evitare la stagnazione e a continuare l'esplorazione di nuove soluzioni. Senza la mutazione, la popolazione potrebbe diventare troppo simile, causando il blocco della ricerca in ottimi locali.
Perché la Mutazione è Importante
- Previene la convergenza prematura: la mutazione assicura che la popolazione non diventi troppo uniforme, evitando una convergenza subottimale;
- Mantiene la diversità: introducendo alterazioni casuali, la mutazione mantiene una vasta gamma di variazioni genetiche disponibili per le generazioni future;
- Permette di sfuggire agli ottimi locali: piccoli cambiamenti casuali consentono all'algoritmo di esplorare nuove aree dello spazio di ricerca che potrebbero portare a soluzioni migliori;
- Bilancia il crossover: mentre il crossover combina tratti esistenti, la mutazione ne introduce di nuovi, garantendo che l'algoritmo continui a generare possibilità inedite.
Insieme, queste proprietà rendono la mutazione essenziale per un processo di ricerca robusto e adattivo.
Operatori di Mutazione Comuni
Diverse rappresentazioni del problema richiedono tecniche di mutazione differenti. I due operatori più utilizzati sono:
- Mutazione bit-flip: per rappresentazioni binarie — inverte un bit da 0 a 1 o da 1 a 0, introducendo cambiamenti piccoli e controllati;
- Mutazione di scambio: per rappresentazioni basate su permutazioni (ad esempio, problemi di ordinamento) — scambia due elementi all'interno di un individuo per generare una nuova configurazione.
1234567891011121314151617181920import random def bit_flip_mutation(individual, mutation_rate=0.1): """ Performs bit-flip mutation on a binary list. """ mutated = [] for gene in individual: if random.random() < mutation_rate: mutated.append(1 - gene) # Flip bit else: mutated.append(gene) return mutated # Example usage original = [1, 0, 1, 1, 0] mutated = bit_flip_mutation(original, mutation_rate=0.5) print("Original:", original) print("Mutated:", mutated)
Grazie per i tuoi commenti!