Reputation:
I am working on a genetic algorithm, and I found a code that works, and now I am trying to understand, but I saw this return statement:
return sum(1 for expected, actual in zip(target, guess)
if expected == actual)
What does it do?
Here is the full code:
main.py:
from population import *
while True:
child = mutate(bestParent)
childFitness = get_fitness(child)
if bestFitness >= childFitness:
continue
print(child)
if childFitness >= len(bestParent):
break
bestFitness = childFitness
bestParent = child
population.py:
import random
geneSet = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!.,1234567890-_=+!@#$%^&*():'[]\""
target = input()
def generate_parent(length):
genes = []
while len(genes) < length:
sampleSize = min(length - len(genes), len(geneSet))
genes.extend(random.sample(geneSet, sampleSize))
parent = ""
for i in genes:
parent += i
return parent
def get_fitness(guess):
return sum(1 for expected, actual in zip(target, guess)
if expected == actual)
def mutate(parent):
index = random.randrange(0, len(parent))
childGenes = list(parent)
newGene, alternate = random.sample(geneSet, 2)
childGenes[index] = alternate \
if newGene == childGenes[index] \
else newGene
child = ""
for i in childGenes:
child += i
return child
def display(guess):
timeDiff = datetime.datetime.now() - startTime
fitness = get_fitness(guess)
print(str(guess) + "\t" + str(fitness) + "\t" + str(timeDiff))
random.seed()
bestParent = generate_parent(len(target))
bestFitness = get_fitness(bestParent)
print(bestParent)
This is the full code of an working genetic algorithm. I modified some parts to make it more readable for me.
The return statement is in the population.py file, in the get_fitness function.
Upvotes: 4
Views: 994
Reputation: 15320
There are several things going on:
return sum(...)
this means that you are returning a number.
The inner part of the sum
is a generator expression
which creates and runs an implicit loop.
In this case, 1 for expected, actual in zip(target, guess) if expected == actual
creates a sequence of 1
values, with one entry created each time the guard condition is true (expected == actual
).
So this line is effectively creating code like: sum(1, 1, 1, 1, ...)
Within the generator expression, you have a zip
call. The zip expression will take the two (or more!) sequences, and convert them into a single sequence with tuples of two (or more!) values. That is, zip(['a', 'b', 'c'], [1, 2, 3])
will produce as its output a sequence like [('a', 1), ('b', 2), ('c', 3)]
.
So if your expected
is [1, 2, 3]
and your actual
is [1, 1, 3]
, you will get a zip result like:
expected = [1, 2, 3]
actual = [1, 1, 3]
zip(expected, actual) # [(1, 1), (2, 1), (3, 3)]
The generator expression contains a for
which uses what was once called "tuple unpacking" to assign multiple targets in its target_list
from a single aggregate (tuple) value.
So when the zip expression produces (1, 1)
the for expected, actual
unpacks that into expected=1, actual=1
.
Thus, the zip
takes two equal-length sequences and pairs their corresponding elements: a[0] with b[0], a[1] with b[1], etc. The for
generator expression assigns those elements into variables called expected
and actual
. The for...if
generator conditional part compares the expected == actual
values, and either generates a value or does not generate a value. Thus, the length of the resulting sequence is guaranteed to be less than or equal to the length of the input sequences, but you don't know how long it will be. The expression part of the generator is simply 1
. So you have a variable-length sequence of 1's. It's not 1 or 0. It's 1 or no-entry. Add up all the 1's, and that's the result.
Upvotes: 1
Reputation: 780
It is a type of List Comprehension that makes use of the zip() function.
Basically, the code is saying:
Upvotes: 1
Reputation: 30977
Let's break that down:
return sum(1 for expected, actual in zip(target, guess)
if expected == actual)
could be written as:
total = 0
for i in range(len(target)):
if target[i] == guess[i]:
total = total + 1
return total
zip(a, b)
makes a list of pairs of items from a
and b
, like:
zip([1, 2, 3], ['a', 'b', 'c'])
yields [(1, 'a'), (2, 'b'), (3, 'c')]
. So the zip(target, guess)
expression returns a list of the first item from target
and the first item of guess
, then the second item from target
and the second from guess
, and so on.
The for expected, actual in zip()
bit unpacks the pairs of values from the output of zip()
, so the first of the pair (from target
) goes to the variable expected
, and the second of the pair (from guess
) goes to the variable actual
.
The 1 ... if expected == actual
bit says "emit a value of 1 for every item from zip()
if the value in expected
equals the value in actual
.
sum()
adds up the number of 1
values from the for loop.
Ta-da! Now you have the count of items where the expected and actual values are the same. There are a couple of reasons to write it this way:
Upvotes: 5
Reputation: 21
I think it returns the total number of matches where actual= expected. Essentially I think it is checking how many times the algorithms model was able to correctly predict
Upvotes: 1