简体   繁体   中英

Accessing a value from an np.array from a while loop

I have the following piece of code:

import math
import numpy as np
from pylab import plot, show

    def model():
        Dt = 1
        time_step = 50

        #initializing the connection weights
        w1 = 1

        #initializing parameter values for the alogistic function
        steepness_SS_a=1
        speed_SS_a=1
        threshold_SS_a=1

        WS_a=1
        SS_a=0
        new_SS_a=np.array([SS_a])
        t=0.0
        timesteps=[t]    

        while t<30.0:

            new = SS_a + speed_SS_a * (
                    (
                        (1/(1+math.exp(-steepness_SS_a * (w1 * WS_a - threshold_SS_a))))
                        -
                        (1/(1+math.exp(steepness_SS_a *threshold_SS_a)))
                    )
                    *        
                    (1+math.exp(-steepness_SS_a*threshold_SS_a))
                    -
                    SS_a
                )
            new_SS_a = np.append(new_SS_a,new)

            SS_a=new 
            t = t + Dt     


            timesteps.append(t)

        print( timesteps )
        plot(new_SS_a)
        show()        

    model()   

It is a computational model (I actually have more variables, this is a simplified version of the code), and during a certain period of time, the states of the model like SS_a have to update. Right now, the code works, but I want to make it more transparant, so you can extract a value of a certain state for a certain timestep. I tried to do this with a for loop, and to give an index to each state for each timestep like this:

   for i in range (30)
        SS_a[i+1] = SS_a[i]+ speedfactor*(….. - SS_a(i))*Dt

, but this did not work because I can't add those values to a list. However, I wondered whether there is a possibility in the code I have now, with the while loop, to extract these values and make the model more declarative and transparant?

Now another option is to use the following format:

    import math
    from pylab import plot, show
    def model(Dt=1, time_step = 50, w1 = 1, steepness_SS_a=1, 
              speed_SS_a=1, threshold_SS_a=1, WS_a=1, SS_a=0, 
              t=0, t_final=30):
        result = [SS_a]
        timesteps =[]
        for ti in range(t,t_final+1,Dt):
            result.append(SS_a + speed_SS_a * (
                (
                    (1/(1+math.exp(-steepness_SS_a * (w1 * WS_a -       threshold_SS_a))))
                -
                    (1/(1+math.exp(steepness_SS_a *threshold_SS_a)))
                )
                *        
                (1+math.exp(-steepness_SS_a*threshold_SS_a))
                -
                SS_a
            )) #<- put here your complicate formula 
        timesteps.append(ti)

    print(result)
    print( timesteps )  
    plot(result)
    show()

model()`

However, the result is as follows:

    [0, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789, 0.3160602794142789]

But I am expecting the value to change. What can i do to improve this?

as you want to put in a list a new value that depend in the previous value put there, you can do it like in this example

result=[0] #we put the initial value in the list
for _ in range(30): # the _ is to signal that we don use that value
    result.append( 10 + result[-1] ) # negative indices access the element in reverse order, -1 is the last, -2 is the previous to that etc
print(result)

with append we add a element to the end of the list

so in your code that is

...
def model():
    ...
    SS_a = [0]  
    for _ in range(30):
        SS_a.append( SS_a[-1]+ speedfactor*(... - SS_a[-1])*Dt )
    ...
    plot(SS_a)
    show()

you can even make your model more flexible by using arguments and default values, that way if you want to make some change just change how you call the model and not your code, for example like this

import math
#import numpy as np 
from pylab import plot, show
def model(Dt=1, time_step = 50, w1 = 1, steepness_SS_a=1, 
          speed_SS_a=1, threshold_SS_a=1, WS_a=1, SS_a=0, 
          t=0, t_final=30):
    result = [SS_a]
    timesteps =[]
    for ti in range(t,t_final+1,Dt):
        result.append( ... ) #<- put here your complicate formula 
        timesteps.append(ti)
    print( timesteps )  
    plot(result)
    show()
    #return result  

model() 

with all those default values we preserve the original behavior, and if we want to do only a minor change like run that model until time 40 instead of 30 we simple call it as model(t_final=40) , you can also put a return of result so you can do some other manipulation later on, and we can also put a doct text to remember what each thing is in a easy way, like this

def model(Dt=1, time_step = 50, w1 = 1, steepness_SS_a=1, 
          speed_SS_a=1, threshold_SS_a=1, WS_a=1, SS_a=0, 
          t=0, t_final=30):
    """This is my model of ...
       where
       Dt: ...
       time_step: ... 
       w1: ...
       steepness_SS_a: ...
       speed_SS_a: ...
       threshold_SS_a: ...
       WS_a: ...
       SS_a: ...
       t: initial time
       t_final: final time
    """
    ...

and that we tell you a nice message that explain the model and how to used it is you call help on it help(model)


as you have several models, you can extract the commons part of each one in different pieces of code and make more general version of it so they can be used as lego block to build your different models, for example your original code can be broken like this

import math
#import numpy as np
from pylab import plot, show

def model_generator(fun, initial=0, t_ini=0, t_end=30, t_step=1 ):
    """Generator of all the values of the given function in the given
       time interval 

       fun: function of 2 arguments time and a previous value that 
            return a new value
       initial: initial value
       t_ini: initial time
       t_end: end time
       t_step: time interval"""
    yield initial
    new_value = initial
    for t in range(t_ini, t_end+1, t_step):
        new_value = fun(t, new_value)
        yield new_value

def model_plot(mod_gen):
    """plot a given model in the form of a iterable"""
    result = list( mod_gen )
    plot(result)
    show()         

def model_fun(t, SS_a, speed_SS_a=1, steepness_SS_a=1, w1=1, WS_a=1, threshold_SS_a=1  ):
    """function that represent my model of ..."""
    return SS_a + speed_SS_a * (
                (
                    (1/(1+math.exp(-steepness_SS_a * (w1 * WS_a - threshold_SS_a))))
                    -
                    (1/(1+math.exp(steepness_SS_a *threshold_SS_a)))
                )
                *        
                (1+math.exp(-steepness_SS_a*threshold_SS_a))
                -
                SS_a
            )        

def model_1():
    """original model"""
    model_plot( model_generator(model_fun) )  

def model_2():
    """original model but with speed_SS_a=2"""
    fun = lambda t,SS_a: model_fun(t, SS_a, speed_SS_a=2)
    model_plot( model_generator(fun) )

def model_3():
    """random test model """
    fun = lambda t,p: t**2
    model_plot( model_generator(fun) )    


model_1()   
model_2()
model_3()

in this one that complicate formula is extracted in a independent function model_fun as it only need 1 obligatory/variable parameter to work (everything else is a constant), model_generator do the work of map time to the values of a function that is given to it as a parameter (because in python everything is a object, even a function, by the way this a generator function) and that function is required to receive 2 arguments time and the previous value (I include time because that make more sense to me, therefore model_fun also receive it but is ignored) and also handle the time stuff and finally model_plot that do what its name imply.

With all the pieces ready I can make as many models as I want and I don't have to repeat anything and the work is reduced to defining only the function, and I can use lambda functions to modify how I call a previous function like in model_2 or define a new one like in model_3 , or make a totally new one and as long I follow the rules set by model_generator , as they said, the sky is the limit (or something like that).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM