From ae40803c6fb14e28be0dc628af9bab90121a4bea Mon Sep 17 00:00:00 2001 From: Mach-2 Date: Fri, 10 Mar 2023 11:39:17 -0800 Subject: [PATCH 1/3] replace random.random with np.random.choice in selRoulette --- deap/tools/selection.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/deap/tools/selection.py b/deap/tools/selection.py index e6fdcaf5e..a2e1a3228 100644 --- a/deap/tools/selection.py +++ b/deap/tools/selection.py @@ -78,25 +78,19 @@ def selRoulette(individuals, k, fit_attr="fitness"): :param fit_attr: The attribute of individuals to use as selection criterion :returns: A list of selected individuals. - This function uses the :func:`~random.random` function from the python base - :mod:`random` module. + This function uses the :func:`random.choice()` function from the NumPy library .. warning:: The roulette selection by definition cannot be used for minimization or when the fitness can be smaller or equal to 0. """ - s_inds = sorted(individuals, key=attrgetter(fit_attr), reverse=True) - sum_fits = sum(getattr(ind, fit_attr).values[0] for ind in individuals) - chosen = [] - for i in range(k): - u = random.random() * sum_fits - sum_ = 0 - for ind in s_inds: - sum_ += getattr(ind, fit_attr).values[0] - if sum_ > u: - chosen.append(ind) - break + fits = [getattr(ind, fit_attr).values[0] for ind in individuals] + sum_fits = sum(fits) + fit_proportions = [i/sum_fits for i in fits] + + chosen_positions = np.random.choice(k,k,p=fit_proportions) + chosen = [individuals[position] for position in chosen_positions] return chosen From 5dc894740243914d7966f592705be5d8b86c890c Mon Sep 17 00:00:00 2001 From: Mach-2 Date: Fri, 10 Mar 2023 12:16:57 -0800 Subject: [PATCH 2/3] use random.choices in selRoulette --- deap/tools/selection.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/deap/tools/selection.py b/deap/tools/selection.py index a2e1a3228..bc6563a0f 100644 --- a/deap/tools/selection.py +++ b/deap/tools/selection.py @@ -85,13 +85,11 @@ def selRoulette(individuals, k, fit_attr="fitness"): or when the fitness can be smaller or equal to 0. """ - fits = [getattr(ind, fit_attr).values[0] for ind in individuals] + fits = [getattr(ind,fit_attr).values[0] for ind in individuals] sum_fits = sum(fits) - fit_proportions = [i/sum_fits for i in fits] + fitness_proportions = [i/sum_fits for i in fits] - chosen_positions = np.random.choice(k,k,p=fit_proportions) - chosen = [individuals[position] for position in chosen_positions] - + chosen = random.choices(individuals, weights=fitness_proportions, k=k) return chosen From 51367932d0d565bdde2bb124cc34ef0bfe6be35a Mon Sep 17 00:00:00 2001 From: Mach-2 Date: Fri, 10 Mar 2023 12:30:25 -0800 Subject: [PATCH 3/3] avoid dividing by zero when all individuals have zero fitness --- deap/tools/selection.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/deap/tools/selection.py b/deap/tools/selection.py index bc6563a0f..6ba96d3a9 100644 --- a/deap/tools/selection.py +++ b/deap/tools/selection.py @@ -78,7 +78,8 @@ def selRoulette(individuals, k, fit_attr="fitness"): :param fit_attr: The attribute of individuals to use as selection criterion :returns: A list of selected individuals. - This function uses the :func:`random.choice()` function from the NumPy library + This function uses the :func:`~random.choices` function from the python base + :mod:`random` module. .. warning:: The roulette selection by definition cannot be used for minimization @@ -87,7 +88,10 @@ def selRoulette(individuals, k, fit_attr="fitness"): fits = [getattr(ind,fit_attr).values[0] for ind in individuals] sum_fits = sum(fits) - fitness_proportions = [i/sum_fits for i in fits] + if sum_fits == 0: + # If all individuals have zero fitness, evenly distribute probability of selection + fitness_proportions = [1/k for i in fits] + else: fitness_proportions = [i/sum_fits for i in fits] chosen = random.choices(individuals, weights=fitness_proportions, k=k) return chosen