Numpy arrays incorrectly have identical values? - python

I have a small program where I am playing with creating an evolutionary algorithm related to disease spread. I have run into an issue that has driven me slightly mad trying to figure out the problem.
I have two numpy arrays, "infections", which is an array where each element is binary representation of whether that individual has been exposed and "current_infections", that is only ongoing infections and is supposed to be incremented by days.
For Example:
infections = [0,0,0,1,1]
current_infections = [0,0,0,15,0]
This would represent five individuals, individual three has had the disease for 15 days and individual four has had it for long enough that they have recovered and no longer currently have it.
infections = []
current_infections = []
responsible_infections = []
spread_rate = 0.1
contagious_period = 20
initial_node_infections = 2
current_network = #this is an array of adjacency matrices for nodes in a network
#initial infections.
def initialize_infections():
global infections, current_infections, responsible_infections
responsible_infections = np.zeros(current_network.shape[0])
infections = np.zeros(current_network.shape[0])
for each in rd.sample(range(len(current_network)), k=initial_node_infections):
infections[each] = 1
current_infections = infections[:]
# runs a day in simulation.
# returns 1 if there are still ongoing infections at the end of day, 0 if not
def progress_day():
global current_infections
print(np.sum(current_infections), np.sum(infections)) #should not be equivalent, yet they are
for i in range(len(current_infections)):
if current_infections[i] >= 1 and current_infections[i]<contagious_period:
current_infections[i]+=1
elif current_infections[i]>=contagious_period:
#patient recovered
current_infections[i] = 0
for i in range(contacts_per_day):
for j in range(len(current_infections)):
if current_infections[j] >= 1:
spread_infection(current_network[j], j)
if not np.sum(current_infections):
return 0
else:
return 1
#given infected node it calculates spread of disease to adjacent nodes.
def spread_infection(person, rp):
global infections, current_infections, responsible_infections
for x in range(len(person)):
if person[x] == 1 and infections[x] == 0 and rd.random()<=spread_rate:
current_infections[x] = 1
infections[x] = 1
responsible_infections[rp]+=1 #infections a given person is responsible for.
def main():
global current_infections, infections
initialize_infections()
day = 0
while day<100:
if not progress_day():
break
day+=1
main()
For some reason changes made to an element in current_infections are also being made to that element in infections so they are both incrementing. Am i doing something incorrectly with numpy such that they are somehow the same array?

current_infections = infections[:] makes current_infections a view over the elements in infections. Use current_infections = infections.copy().

Related

How to set up this programm idea? : Elliott Wave Counter on Stock Charts by finding Minima and Maxima and how they relate to each other

My Idea is as follows and i want to really get to learn more about programming and how to structure a program:
I want to let count waves on a stock chart.
Within the Elliott Wave Rules are some specifications, like (most basic):
Wave 2 never retraces more than 100% of wave 1.
Wave 3 cannot be the shortest of the three impulse waves, namely waves 1, 3 and 5.
Wave 4 does not overlap with the price territory of wave 1, except in the
rare case of a diagonal triangle formation.
(from Wikipedia https://en.wikipedia.org/wiki/Elliott_wave_principle#Wave_rules_and_guidelines)
There are more sophisticated rules of course, but in my imagination, they could be addressed by the same iterative logic like in which I want to apply my rules.
Please guys, and girls, give me feedback on my thoughts if they make any sense in structure and layout to set up a program or not, because i lack experience here:
I want to find the minima and maxima, and give them a wavecount depending on the minima and maxima before.
Therefore i would check every candle (every closing price, day, hour, etc) if the value is below or above the previous value and also values. For example:
If there are two candles going up, then one down, then three up, then two down, then two up, this could be a complete Impulsewave, according to the above-listed rules. In total, i would have 10 candles and the following rules must apply:
The third candle (or the first that goes down, after the two going up) must not close below the starting price of the initial candle. AND also it must be met, that the following candles (how much that would become) must all go up in a row, unless they overcome the price of the previous maxima (the second candle).
When the price starts to drop again, it could be counted as wave 4 then (second minima in a sequence) and when it goes up again, this would indicate wave 5.
Then it also must be met, that, if the price starts to go down again, it does not close below the first maxima (in this case the second candle).
And so on and so on.
My question now is: Is this kind of looping through certain data points is even a appropriate way to approach that kind of project? Or am I totally wrong here?
I just thought: because of the fractal character of Elliott waves, I would only need very basic rules, that would depend on, what the same iterative process spits out the previous times it is scanning data points.
What do you think?
Is there a better, a smarter way to realise what i am planing to do?
And also, how I could do this in a good way?
Maybe there is also a way to just feed some patterns into a predefined execution structure and then let this run over data points just as price charts.
What would your approach look like?
Thanks a lot and best wishes, Benjamin
Here is my idea/code for finding highs and lows. It's doenst work standalone. If you have any idea, how it can help to find waves, let me know.
import pandas as pd
import config.Text
class AnalyzerHighLow(object):
def __init__(self, df):
self.high_low = None
self.df = df.close.values
self.highs = pd.DataFrame(columns=[config.Text.date, config.Text.extrema, config.Text.type])
self.lows = pd.DataFrame(columns=[config.Text.date, config.Text.extrema, config.Text.type])
def highlow(self):
idx_start = 0
self.find_high(self.df, idx_start)
self.find_low(self.df, idx_start)
self.high_low = pd.concat([self.highs, self.lows], ignore_index=True, sort=True, axis=0)
self.high_low = self.high_low.sort_values(by=[config.Text.date])
self.high_low = self.high_low.reset_index(drop=True)
return self.high_low
def find_high(self, high_low, idx_start):
pvt_high = high_low[idx_start]
reached = False
for i in range(idx_start + 1, len(high_low)):
act_high = high_low[i]
if act_high > pvt_high:
reached = True
pvt_high = act_high
elif act_high < pvt_high and reached is True:
self.highs.loc[i - 1] = [i - 1, pvt_high, config.Text.maxima]
return self.find_high(high_low, i)
elif act_high < pvt_high:
pvt_high = high_low[i]
if (reached is True) and (i == (len(high_low))):
self.highs.loc[i - 1] = [i - 1, pvt_high, config.Text.maxima]
def find_low(self, high_low, idx_start):
pvt_low = high_low[idx_start]
reached = False
for i in range(idx_start + 1, len(high_low)):
act_low = high_low[i]
if act_low < pvt_low:
reached = True
pvt_low = act_low
elif act_low > pvt_low and reached is True:
self.lows.loc[i - 1] = [i - 1, pvt_low, config.Text.minima]
return self.find_low(high_low, i)
elif act_low > pvt_low:
pvt_low = high_low[i]
if (reached is True) and (i == (len(high_low) - 1)):
self.lows.loc[i - 1] = [i - 1, pvt_low, config.Text.minima]

Monte Carlo simulation of Birthday paradox in python 3

The birthday paradox is that everyone has equal probability of having a birthday on any given of 365 days. We start adding people in a room. What is the probability that 2 people have birthdays on same day as a function of number of people in the room? The code I wrote is as follows:
import numpy as np
import matplotlib.pyplot as plt
x=[0]
y=[0]
for j in range(1000):
if j!=0:
freq = []
L1 = list(np.random.randint(low = 1, high=366, size = j))
result = list((i, L1.count(i)) for i in L1)
for a_tuple in result:
freq.append(a_tuple[1])
print(freq)
rep = j - freq.count(1)
prob = rep/j
y = y + [prob]
x = x + [j]
print(prob)
plt.plot(x,y)
Here, in L1 = list(np.random.randint(low = 1, high=366, size = j)) I select the day on which someone would have a birthday and in result = list((i, L1.count(i)) for i in L1) I calculate the frequency of birthdays on each day. The entire thing is looped over to account for increasing number of people.
In the following for loop, I isolate the unique events and find repetitions and store the value in rep.
Next I calculated the probability as fraction of people sharing birthdays and plotted them as a function of number.
However, the question requires me to find the probability of just one shared birthday. How do I calculate that? I think I have to loop this entire thing for number of trials but that just gives an accurate solution with less variations of the same program. Currently my program gives fraction of people having shared birthdays I think.
Birthday problem Wikipedia for better reference
NOTE
I assume that when n persons have been in the room, they are all thrown out of the room and then n+1 persons enter the room.
========================================
I would think of it this way;
First, set probs = [0]*365. Now, say 2 persons get in the room - we then write their birthdays onto a piece of paper and check, if those two dates are equal. If they are, we increase probs[2] by 1 (yes, theres some indexes that we don't need, and Python is 0-indexed etc. but to keep it simple).
Now do the same for 3 persons, for 4 persons, for 5 persons ... all the way up to 365.
Your array might look something like probs==[0,0,0,0,0,1,0,1,1,0,1,1,1,1,0,1....].
You can now start over from 2 persons (still keeping the same array as before i.e don't create a new one with 0's!), then 3 persons etc. and start over 1000 times. Your array might look like
probs==[0,0,2,0,4,1,5,2,9,12,10,17....,967,998]
If you divide that array by 1000 (elementwise) you now have your simulated probability as a function of n persons.
import numpy as np
import matplotlib.pyplot as plt
N_TOTAL_PERS= 366
N_SIM = 10000 #number of simulations
counts = np.zeros(N_TOTAL_PERS)
for _ in range(N_SIM):
for n in range(2,N_TOTAL_PERS):
b_days = np.random.randint(1,366,size=n) #Get each persons birth-day
counts [n] += len(b_days) != len(set(b_days)) #Increment if some birthdays are equal
total_probs = counts/N_SIM #convert to probabilities
total_probs[70] #Get the probability when 70 persons are together (0.9988)
plt.plot(range(N_TOTAL_PERS),total_probs)
which generates a plot that looks like
You should run multiple experiments for different number of people in the room. Note that for N_people > 365, the probability should compute equal to 1.
Refactoring your code, and changing the logic a bit, I came up with the following:
import numpy as np
import matplotlib.pyplot as plt
def random_birthdays(n_people):
return list(np.random.randint(low=1, high=366, size=n_people))
def check_random_room(n_people):
"""
Generates a random sample of `n_people` and checks if at least two of them
have the same birthday
"""
birthdays = random_birthdays(n_people)
return len(birthdays) != len(set(birthdays))
def estimate_probability(n_people, n_experiments):
results = [check_random_room(n_people) for _ in range(n_experiments)]
return sum(results)/n_experiments
N_EXPERIMENTS = 1000
x = list(range(1, 400))
y = [estimate_probability(x_i, N_EXPERIMENTS) for x_i in x]
plt.plot(x, y)
plt.show()

How to convert bar count to time, in midi? (music)

Given a midi file, how can one convert the bar count to time?
Generally, how can one easily map the bar count, in entire numbers, to the time in seconds in the song
Using pretty midi, my solution
import pretty_midi as pm
def get_bar_to_time_dict(self,song,id):
def get_numerator_for_sig_change(signature_change,id):
# since sometime pretty midi count are wierd
if int(signature_change.numerator)==6 and int(signature_change.denominator)==8:
# 6/8 goes to 2 for sure
return 2
return signature_change.numerator
# we have to take into account time-signature-changes
changes = song.time_signature_changes
beats = song.get_beats()
bar_to_time_dict = dict()
# first bar is on first position
current_beat_index = 0
current_bar = 1
bar_to_time_dict[current_bar] = beats[current_beat_index]
for index_time_sig, _ in enumerate(changes):
numerator = get_numerator_for_sig_change(changes[index_time_sig],id)
# keep adding to dictionary until the time signature changes, or we are in the last change, in that case iterate till end of beats
while index_time_sig == len(changes) - 1 or beats[current_beat_index] < changes[index_time_sig + 1].time:
# we have to increase in numerator steps, minus 1 for counting logic of natural counting
current_beat_index += numerator
if current_beat_index > len(beats) - 1:
# we labeled all beats so end function
return bar_to_time_dict
current_bar += 1
bar_to_time_dict[current_bar] = beats[current_beat_index]
return bar_to_time_dict
song = pm.PrettyMIDI('some_midi_file.midi')
get_bar_to_time_dict(song)
If anyone knows a function in pretty midi or music21 that solves the same issue please let me know, couldn't find one.
EDIT: There was also an issue with 6/8 beats, I think this covers all edge cases(not 100% sure)

Python programming probability marble out of a bag coding

Hey I'm new to programming but I cant seem to code probability questions. For example, how would I code this?
A box contains 12 transistors of type A and 18 of type B. one transistor is taken out at random and returned. This process is repeated. Determine the probability that the first chosen is type A and second is type B. Thanks!
This is my first try.
from scipy import stats as st
import numpy as np
import random
total=30
totalA=12
totalB=18
def transistor():
return random.choice("A","B")
random.seed(0)
for _in range(30):
try1=transistor()
try2=transistor()
if try1="A":
prob1=totalA/total
else:
prob1=totalB/total
if try2="A":
prob2=totalA/total
else:
prob2=totalB/total
if try1=="A" and try2=="A"
prob=2*totalA/total
If you're trying to run a simulation, this code will give you a probability from 10000 trials. It will generate a different result every time. The more trials, the more accurate it is. The correct, theoretical answer is 0.24.
import random
trials = 10000 # total number of trials
totalA = 12 # total number of A transistors
totalB = 18 # total number of B transistors
successes = 0 # variable keeping track of how many successful pulls there were
choicelist = list("A" * totalA + "B" * totalB) # list containing transitors to correct proportion
def transistor():
return random.choice(choicelist) # pick a random transistor from list
for i in range(trials):
try1 = transistor()
try2 = transistor()
if try1 == "A" and try2 == "B": # if first pull is type A and second is type B...
successes += 1 # ...then it's successful
print float(successes) / trials # print out the proportion of successes to trials

Genetic Algorithm - creatures in 2d world are not learning

Goal -
I am trying to implement a genetic algorithm to optimise the fitness of a
species of creatures in a simulated two-dimensional world. The world contains edible foods, placed at random, and a population of monsters (your basic zombies). I need the algorithm to find behaviours that keep the creatures well fed and not dead.
What i have done -
So i start off by generating a 11x9 2d array in numpy, this is filled with random floats between 0 and 1. I then use np.matmul to go through each row of the array and multiply all of the random weights by all of the percepts (w1+p1*w2+p2....w9+p9) = a1.
This first generation is run and I then evaluate the fitness of each creature using (energy + (time of death * 100)). From this I build a list of creatures who performed above the average fitness. I then take the best of these "elite" creatures and put them back into the next population. For the remaining space I use a crossover function which takes two randomly selected "elite" creatures and mixes their genes. I have tested two different crossover functions one which does a two point crossover on each row and one which takes a row from each parent until the new child has a complete chromosome. My issue is that the creatures just don't really seem to be learning, at 75 turns I will only get 1 survivor every so often.
I am fully aware this might not be enough to go off but I am truly stuck on this and cannot figure out how to get these creatures to learn even though I think I am implementing the correct procedures. Occasionally I will get a 3-4 survivors rather than 1 or 2 but it appears to occur completely randomly, doesn't seem like there is much learning happening.
Below is the main section of code, it includes everything I have done but none of the provided code for the simulation
#!/usr/bin/env python
from cosc343world import Creature, World
import numpy as np
import time
import matplotlib.pyplot as plt
import random
import itertools
# You can change this number to specify how many generations creatures are going to evolve over.
numGenerations = 2000
# You can change this number to specify how many turns there are in the simulation of the world for a given generation.
numTurns = 75
# You can change this number to change the world type. You have two choices - world 1 or 2 (described in
# the assignment 2 pdf document).
worldType=2
# You can change this number to modify the world size.
gridSize=24
# You can set this mode to True to have the same initial conditions for each simulation in each generation - good
# for development, when you want to have some determinism in how the world runs from generation to generation.
repeatableMode=False
# This is a class implementing you creature a.k.a MyCreature. It extends the basic Creature, which provides the
# basic functionality of the creature for the world simulation. Your job is to implement the AgentFunction
# that controls creature's behaviour by producing actions in response to percepts.
class MyCreature(Creature):
# Initialisation function. This is where your creature
# should be initialised with a chromosome in a random state. You need to decide the format of your
# chromosome and the model that it's going to parametrise.
#
# Input: numPercepts - the size of the percepts list that the creature will receive in each turn
# numActions - the size of the actions list that the creature must create on each turn
def __init__(self, numPercepts, numActions):
# Place your initialisation code here. Ideally this should set up the creature's chromosome
# and set it to some random state.
#self.chromosome = np.random.uniform(0, 10, size=numActions)
self.chromosome = np.random.rand(11,9)
self.fitness = 0
#print(self.chromosome[1][1].size)
# Do not remove this line at the end - it calls the constructors of the parent class.
Creature.__init__(self)
# This is the implementation of the agent function, which will be invoked on every turn of the simulation,
# giving your creature a chance to perform an action. You need to implement a model here that takes its parameters
# from the chromosome and produces a set of actions from the provided percepts.
#
# Input: percepts - a list of percepts
# numAction - the size of the actions list that needs to be returned
def AgentFunction(self, percepts, numActions):
# At the moment the percepts are ignored and the actions is a list of random numbers. You need to
# replace this with some model that maps percepts to actions. The model
# should be parametrised by the chromosome.
#actions = np.random.uniform(0, 0, size=numActions)
actions = np.matmul(self.chromosome, percepts)
return actions.tolist()
# This function is called after every simulation, passing a list of the old population of creatures, whose fitness
# you need to evaluate and whose chromosomes you can use to create new creatures.
#
# Input: old_population - list of objects of MyCreature type that participated in the last simulation. You
# can query the state of the creatures by using some built-in methods as well as any methods
# you decide to add to MyCreature class. The length of the list is the size of
# the population. You need to generate a new population of the same size. Creatures from
# old population can be used in the new population - simulation will reset them to their
# starting state (not dead, new health, etc.).
#
# Returns: a list of MyCreature objects of the same length as the old_population.
def selection(old_population, fitnessScore):
elite_creatures = []
for individual in old_population:
if individual.fitness > fitnessScore:
elite_creatures.append(individual)
elite_creatures.sort(key=lambda x: x.fitness, reverse=True)
return elite_creatures
def crossOver(creature1, creature2):
child1 = MyCreature(11, 9)
child2 = MyCreature(11, 9)
child1_chromosome = []
child2_chromosome = []
#print("parent1", creature1.chromosome)
#print("parent2", creature2.chromosome)
for row in range(11):
chromosome1 = creature1.chromosome[row]
chromosome2 = creature2.chromosome[row]
index1 = random.randint(1, 9 - 2)
index2 = random.randint(1, 9 - 2)
if index2 >= index1:
index2 += 1
else: # Swap the two cx points
index1, index2 = index2, index1
child1_chromosome.append(np.concatenate([chromosome1[:index1],chromosome2[index1:index2],chromosome1[index2:]]))
child2_chromosome.append(np.concatenate([chromosome2[:index1],chromosome1[index1:index2],chromosome2[index2:]]))
child1.chromosome = child1_chromosome
child2.chromosome = child2_chromosome
#print("child1", child1_chromosome)
return(child1, child2)
def crossOverRows(creature1, creature2):
child = MyCreature(11, 9)
child_chromosome = np.empty([11,9])
i = 0
while i < 11:
if i != 10:
child_chromosome[i] = creature1.chromosome[i]
child_chromosome[i+1] = creature2.chromosome[i+1]
else:
child_chromosome[i] = creature1.chromosome[i]
i += 2
child.chromosome = child_chromosome
return child
# print("parent1", creature1.chromosome[:3])
# print("parent2", creature2.chromosome[:3])
# print("crossover rows ", child_chromosome[:3])
def newPopulation(old_population):
global numTurns
nSurvivors = 0
avgLifeTime = 0
fitnessScore = 0
fitnessScores = []
# For each individual you can extract the following information left over
# from the evaluation. This will allow you to figure out how well an individual did in the
# simulation of the world: whether the creature is dead or not, how much
# energy did the creature have a the end of simulation (0 if dead), the tick number
# indicating the time of creature's death (if dead). You should use this information to build
# a fitness function that scores how the individual did in the simulation.
for individual in old_population:
# You can read the creature's energy at the end of the simulation - it will be 0 if creature is dead.
energy = individual.getEnergy()
# This method tells you if the creature died during the simulation
dead = individual.isDead()
# If the creature is dead, you can get its time of death (in units of turns)
if dead:
timeOfDeath = individual.timeOfDeath()
avgLifeTime += timeOfDeath
else:
nSurvivors += 1
avgLifeTime += numTurns
if individual.isDead() == False:
timeOfDeath = numTurns
individual.fitness = energy + (timeOfDeath * 100)
fitnessScores.append(individual.fitness)
fitnessScore += individual.fitness
#print("fitnessscore", individual.fitness, "energy", energy, "time of death", timeOfDeath, "is dead", individual.isDead())
fitnessScore = fitnessScore / len(old_population)
eliteCreatures = selection(old_population, fitnessScore)
print(len(eliteCreatures))
newSet = []
for i in range(int(len(eliteCreatures)/2)):
if eliteCreatures[i].isDead() == False:
newSet.append(eliteCreatures[i])
print(len(newSet), " elites added to pop")
remainingRequired = w.maxNumCreatures() - len(newSet)
i = 1
while i in range(int(remainingRequired)):
newSet.append(crossOver(eliteCreatures[i], eliteCreatures[i-1])[0])
if i >= (len(eliteCreatures)-2):
i = 1
i += 1
remainingRequired = w.maxNumCreatures() - len(newSet)
# Here are some statistics, which you may or may not find useful
avgLifeTime = float(avgLifeTime)/float(len(population))
print("Simulation stats:")
print(" Survivors : %d out of %d" % (nSurvivors, len(population)))
print(" Average Fitness Score :", fitnessScore)
print(" Avg life time: %.1f turns" % avgLifeTime)
# The information gathered above should allow you to build a fitness function that evaluates fitness of
# every creature. You should show the average fitness, but also use the fitness for selecting parents and
# spawning then new creatures.
# Based on the fitness you should select individuals for reproduction and create a
# new population. At the moment this is not done, and the same population with the same number
# of individuals is returned for the next generation.
new_population = newSet
return new_population
# Pygame window sometime doesn't spawn unless Matplotlib figure is not created, so best to keep the following two
# calls here. You might also want to use matplotlib for plotting average fitness over generations.
plt.close('all')
fh=plt.figure()
# Create the world. The worldType specifies the type of world to use (there are two types to chose from);
# gridSize specifies the size of the world, repeatable parameter allows you to run the simulation in exactly same way.
w = World(worldType=worldType, gridSize=gridSize, repeatable=repeatableMode)
#Get the number of creatures in the world
numCreatures = w.maxNumCreatures()
#Get the number of creature percepts
numCreaturePercepts = w.numCreaturePercepts()
#Get the number of creature actions
numCreatureActions = w.numCreatureActions()
# Create a list of initial creatures - instantiations of the MyCreature class that you implemented
population = list()
for i in range(numCreatures):
c = MyCreature(numCreaturePercepts, numCreatureActions)
population.append(c)
# Pass the first population to the world simulator
w.setNextGeneration(population)
# Runs the simulation to evaluate the first population
w.evaluate(numTurns)
# Show the visualisation of the initial creature behaviour (you can change the speed of the animation to 'slow',
# 'normal' or 'fast')
w.show_simulation(titleStr='Initial population', speed='normal')
for i in range(numGenerations):
print("\nGeneration %d:" % (i+1))
# Create a new population from the old one
population = newPopulation(population)
# Pass the new population to the world simulator
w.setNextGeneration(population)
# Run the simulation again to evaluate the next population
w.evaluate(numTurns)
# Show the visualisation of the final generation (you can change the speed of the animation to 'slow', 'normal' or
# 'fast')
if i==numGenerations-1:
w.show_simulation(titleStr='Final population', speed='normal')

Categories

Resources