Remove items from list sequentially based on variable index - python

def FitnessSelection(population, relative_fitness):
selected_chromosomes = []
selected1 = random.choices(population, weights = relative_fitness, k = 1)
ind1 = selected1[0][1][0]
del relative_fitness[ind1]
del population[ind1]
selected2 = random.choices(population, weights = relative_fitness, k = 1)
ind2 = selected2[0][1][0]
del relative_fitness[ind2]
del population[ind1]
selected = selected1, selected2
selected_chromosomes = [i[0] for i in selected]
return (selected_chromosomes)
I am trying to perform a random weighted selection from a list, however, I cant have the same item selected twice, therefore I am trying to exclude the selected items immediately after selection so it won't be in the population in the list for the next run of the function.
The problem is that the program is running but I don't think the items are being excluded
I have the items in the following structure
population=[[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [4], [0]],
[[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1], [3], [1]],
[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [4], [2]],
[[1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0], [1], [3]]]
Where the last brackets of each string is an index counter. I am trying to isolate the counter and exclude the item in the same position, but when I check the population afterward, they were not excluded.
Does anyone know what could be wrong with this approach?
p.s. - I'm sorry for not posting a standalone program, I couldn't make it work in a small sample like this.
Thanks!

Related

My code with in function does not perform the task but does the same while out of it?

Here's my code where I am flipping a bit, crossing over two lists and selecting random elements of lists:
def selRandom(individuals, k):
return [random.choice(individuals) for i in range(k)]
def cxOnePoint(ind1, ind2):
size = min(len(ind1), len(ind2))
cxpoint = random.randint(1, size - 1)
ind1[cxpoint:], ind2[cxpoint:] = ind2[cxpoint:], ind1[cxpoint:]
return ind1, ind2
def mutFlipBit(individual, indpb):
for i in range(len(individual)):
if random.random() < indpb:
individual[i] = type(individual[i])(not individual[i])
return individual,
def operators(selection, crossover, mutation, parent, k, indvpb):
select = ['randomSelection']
cx = ['OnePoint']
mutate = ['flipBitMutate']
if selection not in select:
return "invalid"
else:
if selection == 'randomSelection':
(parent) = selRandom(parent, k)
if crossover not in cx:
return "invalid"
else:
if crossover == 'OnePoint':
ind = cxOnePoint(parent[0], parent[1])
if mutation not in mutate:
return "not valid"
else:
if mutation == 'flipBitMutate':
mutatedIndvidual = mutFlipBit(ind[0], indvpb)
return parent, ind, mutatedIndvidual
I run this to execute the code:
indv = ([1,0,1,0,1,0,1,1],[0,1,0,1,0,0,0,1],[0,0,1,1,1,1,0,0],[0,1,1,1,0,0,0,1],[1,0,0,0,1,1,1,1])
selection = 'randomSelection'
crossover = 'OnePoint'
mutation = 'flipBitMutate'
selected_parent, ind, mutatedIndvidual = operators(selection = selection , crossover = crossover, mutation = mutation, parent = indv, k = 3, indvpb = 0.1 )
print("Parents:\n",indv)
print("Selected parent to reproduce:\n",selected_parent)
print("Crossover offsprings:\n",ind)
print("Mutated offsprings",mutatedIndvidual)
And get the result:
Parents:
([1, 0, 1, 0, 1, 0, 1, 1], [1, 1, 1, 1, 0, 0, 1, 0], [0, 0, 1, 1, 1, 1, 0, 0], [0, 1, 0, 1, 0, 0, 0, 1], [1, 0, 0, 0, 1, 1, 1, 1])
Selected parent to reproduce:
[[1, 1, 1, 1, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0, 0, 1], [1, 1, 1, 1, 0, 0, 1, 0]]
Crossover offsprings:
([1, 1, 1, 1, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0, 0, 1])
Mutated offsprings ([1, 1, 1, 1, 0, 0, 1, 0],)
So the code is executing but is not functioning. It randomely selects from the tuple and then it does not crossovers (mixes the bits from two lists) or flips the bits. If I test run the code separately (out of the operator method) it works:
a = [1,1,1,1,1,1,1,1]
b = [0,0,0,0,0,0,0,0]
c = [1,0,0,0,1,1,0,1]
d= (a,b,c)
print("selecting randomely:\n",selRandom(d,1))
print("TESTING CROSSOVER\n", cxOnePoint(a,b))
print("Mutate:\n",mutFlipBit(a,0.4))
and got the proper result:
selecting randomely:
[[0, 0, 0, 0, 0, 0, 0, 0]]
TESTING CROSSOVER
([1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1])
Mutate:
([0, 1, 1, 1, 1, 1, 1, 1],)
What is the logical mistake that I am making here?
Thank you!
To answer my own question:
I have assigned original lists in the mutFlipBit() and cxOnePoint and I changed my 'mutFlipBit()' to:
def mutation(individual, indp):
return [not ind if random.random() < indp else ind for ind in individual]
This worked for me

How can i group and sum elements in matrix, without using itertools.groupby?

the problem that I am facing is simple. I have matrix as list of lists like this:
[[0, 0, 1, 0, 0, 0, 0], [0, 1, 0, 1, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 1], [0, 0, 0, 1, 1, 1, 0], [0, 0, 1, 0, 1, 0, 0]]
And I want to get is tuple that has grouped occurrences of 1 for rows on one side and for cols on the other. So for the matrix above it would be like this:
([[1], [1, 1, 1], [7], [2, 1], [3], [1, 1]],[[1], [2], [1, 2, 1], [4], [1, 2], [1, 1], [3]])
As you can see it "sums" adjascent duplicates so list like this [1,0,1,1] would resolve in [[1],[0],[2]]
I tried working on the rows and ended up with this:
for line in matrix:
new_list = []
for value in line:
if new_list and new_list[-1][0] == value:
new_list[-1].append(value)
else:
new_list.append([value])
result_list.append(new_list)
This splits the list into duplicates but does not sum the adjascent and still leaves 0 in the result.
Does anyone have good solution for both rows and colls to achieve my desired Tuple?
PS: I know i could use itertools.groupby but I am trying to solve it without it.
Assuming your data is in data, here you go:
def grp(data):
result = []
for row in data:
count = 0
row_result = []
for c in row:
if c==0:
if count > 0:
row_result.append(count)
count = 0
else:
count += 1
if count > 0:
row_result.append(count)
result.append(row_result)
return result
data = [[0, 0, 1, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1],
[0, 0, 1, 1, 0, 0, 1],
[0, 0, 0, 1, 1, 1, 0],
[0, 0, 1, 0, 1, 0, 0]]
print((grp(data),grp(zip(*data)))
gives me your desired result (using Python 3).

Replace every two items in a list for a respective value in a dictionary

I used a program to convert an integer vector to binary, now I need to do the reverse operation, but I believe the logic I am using it's not correct.
population=[[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [6], [0]],
[[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1], [4], [1]],
[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [6], [2]],
[[1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0], [4], [3]]]
def BinaryConversion2(population):
binary_return = []
binary_index = {(0,0): 0, (0,1): 1, (1,0): 2, (1,1): 3}
for game in range (0, len(population)):
converted = [s for num in population[game][0] for s in binary_index[num]]
binary_return.append(converted)
return (binary_return)
I need to replace every two bits of the binary strings in brackets for the respective dictionary value, but I believe the problem here is that the program is indexing single bits, so it is not working properly.
Does anyone know how to reference every two items in the list for the dictionary respective values? Or anything else that might be useful in this case.
Thank you!
for game in population:
binary_return = [binary_index[(i,j)] for i,j in zip(game[0][0::2], game[0][1::2])]
This is a simple solution that works.
population=[[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [6], [0]],
[[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1], [4], [1]],
[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [6], [2]],
[[1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0], [4], [3]]]
binary_index = {(0,0): 0, (0,1): 1, (1,0): 2, (1,1): 3}
#zipping
list2 = []
for i in [num[0] for num in population]:
it = iter(i)
list2.append(zip(it,it))
converted = [[binary_index[s] for s in num]for num in list2]
With this you will get the output in same form as your population list, but I have no idea on what are two single element lists in your each entry, so i just dropped it. You can edit it if you like.

Remove (or replace) items in a multi-level list based on one of the parameters inside

population=[[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [4], [0]],
[[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1], [3], [1]],
[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [4], [2]],
[[1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0], [1], [3]]]
selected_chromosomes=[[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [5], [2]],
[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [3], [0]]]
child1=[0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0]
child2=[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1]
def PopulationAdjustment(population, selected_chromosomes):
for game in range(0, len(selected_chromosomes)):
if game in selected_chromosomes[game][2]==game in population[game][2]:
population.remove(game)
return population
So the objective here is to replace the parents for the children in a population (list), my approach was to delete the parents then append the children, based on the same counter. The structure of the list is [[chromosome],[fitness],[counter]], however they are not exactly the same since I manipulated the fitness during the selection to avoid 0 probabilities.
I am trying to index the items that have the same counter and delete them from the list, then the next step would be just to append the children.
Ive been trying some different ways but I couldnt get it working properly, any thoughts on how to fix that? Also, if there is a way of replacing them directly by the children without having to perform 2 steps (remove and append) it would be aslo very welcome. Thanks!!
You said "I am trying to index the items that have the same counter and delete them from the list". While that's possible, it's easier (and faster) to just build a new list that contains the chromosomes that you want to keep, unless population is huge.
We first scan the selected_chromosomes to extract their counter numbers into a set so we can look them up quickly.
population=[
[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [4], [0]],
[[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1], [3], [1]],
[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [4], [2]],
[[1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0], [1], [3]],
]
selected_chromosomes=[
[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [5], [2]],
[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [3], [0]],
]
def population_adjustment(population, selected_chromosomes):
# Create a set of the counter numbers to remove
drop = {u[-1][0] for u in selected_chromosomes}
# Copy the wanted chromosomes to a new list
return [u for u in population if u[-1][0] not in drop]
new_pop = population_adjustment(population, selected_chromosomes)
for row in new_pop:
print(row)
output
[[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1], [3], [1]]
[[1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0], [1], [3]]
If the population list is huge, or you have some other reason to keep the original list (eg, there are multiple references to it in various places), here's how to delete the unwanted lists. We have to be careful, though. Removing items from a list that you're iterating over is dangerous, since removal disturbs the indices of the remaining list items, as shown here. It's a bit like cutting a tree branch that you're sitting on. If you cut in the wrong place, Bad Things happen. ;) The simplest way is to iterate over the list in reverse.
population=[
[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [4], [0]],
[[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1], [3], [1]],
[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [4], [2]],
[[1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0], [1], [3]],
]
selected_chromosomes=[
[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [5], [2]],
[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [3], [0]],
]
def population_adjustment(population, selected_chromosomes):
# Create a set of the counter numbers to remove
drop = {u[-1][0] for u in selected_chromosomes}
# Iterate backwards over population so we can safely delete sublists
for i in range(len(population)-1, -1, -1):
k = population[i][-1][0]
if k in drop:
del population[i]
# Since we mutate `population` we should return `None`, as is conventional in Python.
# This return statement isn't necessary, since `None` is the default return value,
# but it's nice to be explicit
return None
population_adjustment(population, selected_chromosomes)
for row in population:
print(row)
This code produces the same output as the previous version, so I won't repeat it.

Mutation of a binary vector inside a list

import random
chosen=[[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [3], [0]],
[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [5], [2]]]
def mutation(chosen, mp):
for i in range(len(chosen)):
if random.random() < mp:
chosen[0][i] = type(chosen[0][i])(not chosen[0][i])
return (chosen)
mp=0.9 #probability
mutated=mutation(chosen, mp)
print (mutated)
Assuming that chosen stands for the selected individuals in a population, I am trying to mutate the binary vectors (at random position) based on the given probability. and return it in a different list (I am still not sure if the extra list is necessary).
It's not really working as expected, anyone knows what could be wrong in the code?
File "<ipython-input-229-91852a46fa82>", line 9, in mutation
chosen[0][i] = type(chosen[0][i])(not chosen[0][i])
TypeError: 'bool' object is not iterable
Also, if someone knows a more convenient way for this it would be totally welcome.
Thank you!
I'm still guessing at what you want, but if you just want to flip one of the binary bits:
import random
chosen=[[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [3], [0]],
[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [5], [2]]]
def mutation(chosen, mp):
for i in range(len(chosen)):
if random.random() < mp:
pos = random.randrange(len(chosen[i][0]))
chosen[i][0][pos] = 0 if chosen[i][0][pos] else 1
# before
for item in chosen:
print(item)
print()
mutation(chosen, 1) # 100% of the time, for now
# after
for item in chosen:
print(item)
Output (note last bit changed and 3rd bit changed in the rows):
[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [3], [0]]
[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [5], [2]]
[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0], [3], [0]]
[[0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [5], [2]]

Categories

Resources