Emerge Into Light
Emerge Into Light

Reputation: 27

General Random Walk generator questions

Alright so I have some general questions on how to continue on my python script for generating a set of random walks. So far, I have in my program a single 1-d random walk that works fine. My question is that I want to create a for loop in order to make it so multiple walkers, lets say 20 are processed by the program. How would I go about that. Also, I'm trying to find the displacement root mean squared value of each walker. I'm not sure how to go about that, I just know that I need to find the sum of all the differences between the total displacement and each individual step squared, and then divide by the total number of steps, but I am unsure how to code that as well. Any help would be appreciated, thanks! Here is my code thus far

import scipy as sp
import numpy as np
from numpy.random import *
from pylab import *

fwd = 0.5 #Probability to move forward
bwd = 1 - fwd #Probability to move backwards
N = 100 #Number of Steps
d_avg = 0

# Takes one step per second (Per N)
time = np.arange(N)

position = np.zeros(N)

for i in range (N-1):
    rn = np.random.uniform(0,1) # This generates a random number between (x,y)
    if rn < fwd:   # If the random number picked is >0.5
        step = 1 # move forward 1 step
    else:
        step = -1 # If the random number picked is not >0.5, then move backwards
    position[i+1]=position[i]+step
    d_avg+=position[i]

print(d_avg/N)



plot(time,position,'g-')
savetxt('1Dtrajectory.dat',position)
show()

Upvotes: 2

Views: 2127

Answers (1)

Scott
Scott

Reputation: 6389

To implement multiple walkers you could run another loop (though this is not my suggested solution; see suggested solution). You could create an empty two dimensional numpy array, step_matrix = np.zeros((num_walkers, num_steps)), and then add an outer loop (inner loop fills in each col, outer loop moves to the next row).

...
N = 10 #Number of Steps
d_avg = 0
nw = 2  # number of walkers
# Takes one step per second (Per N)
time = np.arange(N)
position = np.zeros(N)
walkers = np.zeros((nw, N))
for w in range(nw):
    for i in range (N-1):
        rn = np.random.uniform(0,1) # This generates a random number between (x,y)
        if rn < fwd:   # If the random number picked is >0.5
            step = 1 # move forward 1 step
        else:
            step = -1 # If the random number picked is not >0.5, then move backwards
        position[i+1]=position[i]+step
        d_avg+=position[i]
    walkers[w, :] = position
...

Now each row has the positions for each walker.

Note: Python and scipy / numpy already have methods to do these sorts of things without the need for nested loops however.

Suggested Solution: Assume all walkers start at 0.

I would write the multiple walker as such:

import numpy as np
from __future__ import division  # to force division of int to float
num_walkers = 3  # change as needed
num_steps = 10   # change as needed
prob = 0.5

step_matrix = np.random.randint(2, size=(num_walkers, num_steps))
step_matrix[step_matrix < prob] = -1
print step_matrix

prints:

[[-1  1 -1 -1 -1  1  1 -1  1  1]
 [ 1  1 -1 -1  1 -1 -1  1  1 -1]
 [-1 -1  1  1  1 -1 -1 -1 -1  1]]

So with no looping this gives an array where rows are the walkers, and columns are the steps.

Note: these are not the positions at each step as you keep track of, but rather the direction moved each step.

You describe you want what sounds like mean square error (mse), so I'll do my best:

total_displacement = np.sum(step_matrix, axis=1).reshape(num_walkers, 1)
print total_displacement

prints:

[[ 0]
 [ 0]
 [-2]]

So we have the total displacement for each walker, which is just the sum along the rows (sum of the steps). According to your description, we need to subtract this total displacement from each individual step, square this value, and sum each of these squared differences:

mse = np.sum(np.power((step_matrix - total_displacement), 2), axis=1).reshape(num_walkers,1)/num_steps

To put this all in one function:

def random_walkers(n_walkers, n_steps, p):
    import numpy as np
    from __future__ import division  # to force division of int to float
    step_matrix = np.random.randint(2, size=(n_walkers, n_steps))
    step_matrix[step_matrix < p] = -1
    total_displacement = np.sum(step_matrix, axis=1).reshape(n_walkers, 1)
    positions = np.zeros((n_walkers, n_steps+1))
    for i in range(n_steps):
        positions[:, i+1] = step_matrix[:, i] + positions[:, i]
    mse = np.sum(np.power((step_matrix - total_displacement), 2), axis=1).reshape(n_walkers,1)/n_steps
    return step_matrix, mse, positions

mat, mse, pos = random_walkers(2, 5, 0.5)
print mat
print mse
print pos

prints:

[[ 1  1 -1 -1  1]
 [ 1 -1 -1  1  1]]
[[ 1.6]
 [ 1.6]]
[[ 0.  1.  2.  1.  0.  1.]
 [ 0.  1.  0. -1.  0.  1.]]

Here pos is what you would want to plot, as it keeps track of the actual position over time. So just pick off a particular row and your plot would look as you expect.

Upvotes: 1

Related Questions