Storing intermediate values in a numpy array - python

I'm trying to simulate a 2-d random walk, with direction 0 < θ < 2π and T=1000 steps.
a=np.zeros((1000,1000))
def randwalk(x,y):
theta=2*math.pi*rd.rand()
x+=math.cos(theta);
y+=math.sin(theta);
return (x,y)
How can I store all the intermediate coordinates in a? I was initially trying something of the form:
for i in range(1000):
for j in range(1000):
a[i,j] = randwalk(x,y)
But this doesn't seem to work at all.

The main obvious problem is that you want a 2D array of 1000 points, not a 1000x1000 array. For example, you say you want to take 1000 steps, but your nested loop takes 1,000,000.
import numpy as np
import matplotlib.pyplot as plt
import random as rd
import math
a=np.zeros((1000,2), dtype=np.float)
def randwalk(x,y):
theta=2*math.pi*rd.random()
x+=math.cos(theta);
y+=math.sin(theta);
return (x,y)
x, y = 0., 0.
for i in range(1000):
x, y = randwalk(x,y)
a[i,:] = x, y
plt.figure()
plt.plot(a[:,0], a[:,1])
plt.show()

You probably want something like
T = 1000
a = [(0,0)] * T
for i in range(1, len(a)):
a[i] = randwalk(*a[i - 1])
No need for numpy here.

You've got a type error. randwalk is returning a 2-tuple, and you're trying to set an array element where a float is expected.
First of all, you don't want a 1000 by 1000 array. This would give a million data points, and you only need 2000. I think what you want is something like this:
xs = np.zeros((1000))
ys = np.zeros((1000))
x = 0
y = 0
for i in range(1000):
xs[i], ys[i] = randwalk()
Also, should change the definition of randwalk to take no parameters, and to make x and y global variables:
def randwalk():
global x, y
As you have it, you're modifying the values of the parameters, but they aren't accumulated from call to call.

Related

Create a matrix using values from a tuple with numpy

I'm trying to create a matrix with values based on x,y values I have stored in a tuple. I use a loop to iterate over the tuple and perform a simple calculation on the data:
import numpy as np
# Trying to fit quadratic equation to the measured dots
N = 6
num_of_params = 3
# x values
x = (1,4,3,5,2,6)
# y values
y = (3.96, 24.96,14.15,39.8,7.07,59.4)
# X is a matrix N * 3 with the x values to the power of {0,1,2}
X = np.zeros((N,3))
Y = np.zeros((N,1))
print X,"\n\n",Y
for i in range(len(x)):
for p in range(num_of_params):
X[i][p] = x[i]**(num_of_params - p - 1)
Y[i] = y[i]
print "\n\n"
print X,"\n\n",Y
Is this can be achieved in an easier way? I'm looking for some way to init the matrix like X = np.zeros((N,3), read_values_from = x)
Is it possible? Is there another simple way?
Python 2.7
Extend array version of x to 2D with a singleton dim (dim with length=1) along the second one using np.newaxis/None. This lets us leverage NumPy broadcasting to get the 2D output in a vectorized manner. Similar philosophy for y.
Hence, the implementation would be -
X = np.asarray(x)[:,None]**(num_of_params - np.arange(num_of_params) - 1)
Y = np.asarray(y)[:,None]
Or use the built-in outer method for np.power to get X that takes care of the array conversion under the hoods -
X = np.power.outer(x, num_of_params - np.arange(num_of_params) - 1)
Alternatively, for Y, use np.expand_dims -
Y = np.expand_dims(y,1)

ask for help for a sum (sigma) function

need help to calculate this:
so, the total number of y is equal to number of x, and each y is calculated with one x and several a.
My code list below, it gives the correct results for a0. what is a simple way to calculate this? maybe a different version can also verify the results.
Thanks a lot.
import numpy as np
import matplotlib.pyplot as plt
a = np.array([1,2,3,4],float) # here we can give several a
b = np.asarray(list(enumerate(a)))
x = np.linspace(0.0,1.0,10)
y1 = []
for r in x:
y1.append(np.exp(np.sum((1-r)**2*a*((2*b[:,0]+1)*r-1+r)*(r-1+r)**(b[:,0]-1))))
y1=np.asarray(y1)
You can write almost literally the same in numpy:
def f(x, a):
x, a = np.asanyarray(x), np.asanyarray(a)
x = x[:, None] # create new dimension to sum along
i = np.arange(len(a)) # create counter
return np.sum((1-x)**2 * a * ((2*i + 1) * x - (1-x)) * (x - (1-x))**(i-1), axis=-1)
As a side note: there are obvious algebraic simplifications you could take advantage of.

Python: Repetition of 2-d random walk simulation

I'm simulating a 2-dimensional random walk, with direction 0 < θ < 2π and T=1000 steps. I already have:
a=np.zeros((1000,2), dtype=np.float)
def randwalk(x,y):
theta=2*math.pi*rd.rand() # Theta is a random angle between 0 and 2pi
x+=math.cos(theta); # Since spatial unit = 1
y+=math.sin(theta); # Since spatial unit = 1
return (x,y)
x, y = 0., 0.
for i in range(1000):
x, y = randwalk(x,y)
a[i,:] = x, y
This generates a single walk, and stores all intermediate coordinates in the numpy array a. How can I edit my code to repeat the walk 12 times (using a new random seed every time) and then save each run in a separate text file? Do I need a while loop within my randwalk function?
Guess:
rwalkrepeat = []
for _ in range(12):
a=np.zeros((1000,2), dtype=np.float)
x, y = 0., 0.
for i in range(1000):
x, y = randwalk(x,y)
a[i,:] = x, y
rwalkrepeat.append(a)
print rwalkrepeat
You don't need any explicit loops. The entire solution can be vectorized (untested):
nsteps = 1000
nwalks = 12
theta = 2 * np.pi * np.random.rand(nwalks, nsteps - 1)
xy = np.dstack((np.cos(theta), np.sin(theta)))
a = np.hstack((np.zeros((nwalks, 1, 2)), np.cumsum(xy, axis=1)))
An approach to this which sticks with the general form of your code is:
import numpy as np
import matplotlib.pyplot as plt
import random as rd
import math
a=np.zeros((1000,2), dtype=np.float)
def randwalk(x,y):
theta=2*math.pi*rd.random()
x+=math.cos(theta);
y+=math.sin(theta);
return (x,y)
fn_base = "my_random_walk_%i.txt"
for j in range(12):
rd.seed(j)
x, y = 0., 0.
for i in range(1000):
x, y = randwalk(x,y)
a[i,:] = x, y
fn = fn_base % j
np.savetxt(fn, a)
For the basic calculation, panda-34's and NPE's answers are also good, and take advantage of numpy's vectorization.
Here I used seed(j) to explicitly set the seed the random numbers. The advantage of this is that each result will be repeatable as long as the seed is the same, even if, say, they are not run in sequence, or you change the array length, etc. This isn't necessary though if one didn't want repeatable runs -- then random would just seed from the time and all random number throughout all runs would be different.
Explanation for file names: since OP requested saving each of multiple runs to different files, I thought it would be good to have numbered files, eg, here my_random_walk_0.txt, my_random_walk_1.txt, etc. In my example I used the name fn_base as a variable to hold the general format of the filename, so that, say, the code fn = fn_base % 17 would set fn equal to my_random_walk_17.txt (this is a bit old school for python, read about "string formatting" in python for more).
If you use numpy, why aren't you using numpy?
I'd do it this way:
n_moves = 1000
a = np.zeros((n_moves, 2))
for i in range(12):
thetas = (2*np.pi) * np.random.rand(n_moves-1)
a[1:,0] = np.cos(thetas)
a[1:,1] = np.sin(thetas)
a = np.add.accumulate(a, 0)

Strange behaviour with Gaussian random distribution

I'm running a bit of code whose purpose is to take a list/array of floats and an associated list/array of the same length acting as an "error" and shuffle the first list around according to a Gaussian distribution.
This is a MWE of the code:
import random
import numpy as np
def random_data(N, a, b):
# Generate some random data.
return np.random.uniform(a, b, N).tolist()
# Obtain values for x.
x = random_data(100, 0., 1.)
# Obtain error/sigma values for x.
x_sigma = random_data(100, 0., 0.2)
# Generate new x values shuffling each float around a
# Gaussian distribution with a given sigma.
x_gauss = random.gauss(np.array(x), np.array(x_sigma))
print x-x_gauss
What I find is that the result of doing x-x_gauss is a list of floats that is always either positive or negative. This means the random.gauss call is always assigning either a larger new value for each float in x or a smaller one for all values in x.
I would expect the random.gauss call to shuffle the floats in x around its values both to the right and to the left, since this is a random process.
Why is this not happening? Am I understanding something wrong about the process?
This is the definition of random.gauss:
def gauss(self, mu, sigma):
random = self.random
z = self.gauss_next
self.gauss_next = None
if z is None:
x2pi = random() * TWOPI
g2rad = _sqrt(-2.0 * _log(1.0 - random()))
z = _cos(x2pi) * g2rad
self.gauss_next = _sin(x2pi) * g2rad
return mu + z*sigma
Notice that is is generating one value for z, and returning mu + z*sigma.
Since mu and sigma are numpy arrays, this calculation is being done element-wise. Since sigma is positive, the shift z*sigma is either always positive or negative, depending on the sign of z
If you are using NumPy, unless there is a specific reason to do otherwise, I would use the np.random module to generate these values. It would be quicker than using a Python loop with calls to random.gauss:
import numpy as np
N = 100
x = np.random.uniform(0., 1., size=N)
x_sigma = np.random.uniform(0., 0.2, size=N)
z = np.random.normal(0, 1, size=N)
x_gauss = x + z*x_sigma
print x-x_gauss

Calculating next y using previous y element using numpy

I want to calculate the speed of a vehicle, to plot a graph with time in seconds on x axis, and speed in km/h on y axis. To do that, I need to get the previous calculated y value.
Example: y[x] = y[x-1] * a
a = 0,11768
x = np.arange(0, 100, 1) # 0 to 100 seconds
y = a * y[x-1] ??
plt.plot(x, y)
plt.show()
Is that possible with numpy, or should I do a loop to iterate over all indexes?
v=v0+at Assuming your acceleration is constant and v0=0there's no need to do what you want simply:
import numpy as np
import matplotlib.pyplot as plt
a = 0.11768 #is it in m/s^2? I've used m/s^2...
v=[] #velocity at a given time ‹
x = np.arange(0, 100, 1) # 0 to 100 seconds
for i in x: # ‹
v.append(i*a) #read it as a*t, in fact is t...use i*a*3.6 if you want km/h ‹
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x,v,)
plt.plot(x, v)
plt.ylabel(r'Velocity $(m/sec )$') #note if you want km/h use v.append(i*a*3.6) above
plt.xlabel(r'Time $(sec)$')
plt.show()
This is the result:
EDIT:
As suggest by Joe in his comment you should use v=a*x delating the lines marked with ‹in my code, for a more efficient way to do that!
Your calculation for y is wrong. Instead of multiplying the previous speed with the acceleration, you have to add the acceleration to that speed. An alternative way would be to multiply the acceleration with the time and add that to some initial speed. This way, you can use a simple list comprehension for y.
a = 0.11768 # acceleration (note the dot instead of comma!)
y0 = 0 # initial speed at time x = 0
X = numpy.arange(0, 100, 1)
Y = numpy.array([y0 + a * x for x in X])
When using Numpy, there's an even simpler way -- thanks to #JoeKington for pointing this out:
Y = y0 + a * X # multiplies each value of X with a and adds y0
I don't know if it's possible in numpy but I know how you can easily achieve it using pandas:
import pandas as pd
import numpy as np
a=0.11768
df = pd.DataFrame(np.arange(0, 100, 1),columns=['X'])
df['Y'] = a*df['X'].shift(1)
a = 0.11768
x = np.arange(0, 100, 1)
y = [1]
for i in range(1, len(x)-1):
y.append(a * y[i-1])

Categories

Resources