Is there a better way of doing this?
Scott David Daniels
Scott.Daniels at Acm.Org
Fri Mar 6 17:13:47 EST 2009
mattia wrote:
> Here is my last shot, where I get rid of all the old intermediate
> functions:
>
> def selection(fitness, population):
> lp = len(population)
> roulette_wheel = []
> for x in population:
> roulette_wheel += [x]*fitness(x)
> selected_population = [[]]*lp
> selected_population[:2] = sorted(population, key=fitness,
> reverse=True)[:2]
> selected_population[2:] = [choice(roulette_wheel) for _ in range
> (lp-2)]
Try something like this to choose likely couples:
import random
import bisect
def choose_pairs(fitness_population, decider=random):
'''Pick and yield pairs weighted by fitness for crossing.
We assume weighted_population has fitness already calculated.
decide is a parameter to allow testing.
'''
total = 0
cumulative = []
candidates = []
for fitness, individual in set(fitness_population):
# calculate total weights, extract real candidates
if fitness > 0:
total += fitness
cumulative.append(total)
candidates.append(individual)
assert len(candidates) > 1
while True:
# pick a candidate by weight
c0 = decider.random() * total
first = bisect.bisect_left(cumulative, c0)
if first:
weighting = cumulative[first] - cumulative[first - 1]
else:
weighting = cumulative[0]
# pick another distinct candidate by fitness
c1 = choice = decider.random() * (total - weighting)
if choice >= cumulative[first] - weighting:
choice += weight # adjust to avoid selecting first
second = bisect.bisect_left(cumulative, choice)
yield candidates[first], candidates[second]
--Scott David Daniels
Scott.Daniels at Acm.Org
More information about the Python-list
mailing list