How to modify this Python define function code? - python

Could anyone please take a look at the following function code in Python?
import numpy as np
import scipy.stats as stats
from scipy.stats import poisson, norm
cs = 100
co = 300
mu = 4.7
G = poisson(mu)
p = G.pmf(np.arange(3*mu))
# Define Z(Q) function
def Z(Q):
for i in range(len(p)):
return sum(p[i]*cs*max((Q-i), 0) + p[i]*co*max((i-Q), 0))
# Plot Q and (Q)
import pylab as pl
x = []
y = []
for Q in range(0, 12):
x.append(Q)
y.append(Z(Q))
pl.plot(x, y, '-o')
pl.show()
Error Message shows up in the last 'Plot' procedure:
In Z(Q), 'numpy.float64' object is not iterable.
I would like Z(Q) returns value that sum each i in the range (0, len(p)), which is a function with variable Q. And finally the plot is Q(X Axis) and Z(Q)(Y Axis) for each Q it can be plotted.
How can I modify Z(Q)? Thank you!
And if I would like to output [Q, Z(Q)] how could I make it? My Code:
with open('opt.csv', 'wb') as fd:
a = csv.writer(fd, delimiter=',')
data1 = [['Order_Number', 'Cost'],
[Q, Z(Q)]]
a.writerows(data1)

If you're expecting Z(Q) to return multiple values, you may want to use the "yield" statement:
def Z(Q):
for i in range(len(p)):
yield sum(p[i]*cs*max((Q-i), 0) + p[i]*co*max((i-Q), 0))
This will allow it to be iterated over and will return the sum for each run of the for loop.
If you need the ouput as a list rather than a generic iterable, you'll either need to construct the list in that call, or wrap your call to Z(Q) in a list: list(Z(Q))
Edit:
After taking a closer look (and getting the right libraries installed...), my original answer seems to be incorrect. The stack trace (which would ideally be included in your question :) ) points to the return line in Z itself. This is because your original code is trying to run a call to sum every time it iterates over range(len(p)) rather than running it once on all the results.
You can adjust your code to do correctly return a single summed value by moving the sum outside the function, ie:
import numpy as np
import scipy.stats as stats
from scipy.stats import poisson, norm
cs = 100
co = 300
mu = 4.7
G = poisson(mu)
p = G.pmf(np.arange(3*mu))
# Define Z(Q) function
def Z(Q):
for i in range(len(p)):
yield p[i]*cs*max((Q-i), 0) + p[i]*co*max((i-Q), 0)
# Plot Q and (Q)
import pylab as pl
x = []
y = []
for Q in range(0, 12):
x.append(Q)
y.append(sum(Z(Q)))
pl.plot(x, y, '-o')
pl.show()
To summarise the changes:
Z(Q) now yields each iteration of the function as described
The sum operation is now run on the result of Z(Q)
I hope that helps!

Related

Plotting the mean square displacement of a 2D random walk as a function of δt

I've already created a code for random walk of 10000 steps and then repeated it 12 times and stored each run in a separate text file (which was required in the question). I then calculated the mean square displacement of it(not sure if it's done correct). I now need to 'plot my Mean Square Displacement as a function of δt, including errorbars σ = std(MSD)/√N, where std(MSD) is the standard deviation among the different runs and N is the number of runs.' and then compute the diffusion constant D from the curve and check that D = 2 (∆/dt) where dt = 1.
Here is my code so far:
import numpy as np
import matplotlib.pyplot as plt
import random as rd
import math
a = (np.zeros((10000, 2), dtype=np.float))
def randwalk(x,y):
theta= 2*math.pi*rd.random()
x+=math.cos(theta); # This uses the equation given, since we are told the spatial unit = 1
y+=math.sin(theta);
return (x,y)
x, y = 0.,0.
for i in range(10000): # Using for loop and range function to initialize the array
x, y = randwalk(x,y)
a[i,:] = x,y
fn_base = "random_walk_%i.txt" # Saves each run in a numbered text file, fn_base is a varaible to hold format
N = 12
for j in range(N):
rd.seed(j) # seed(j) explicitly sets the seed to random numbers
x , y = 0., 0.
for i in range(10000):
x, y = randwalk(x,y)
a[i,:] = x, y
fn = fn_base % j
np.savetxt(fn, a)
destinations = np.zeros((12, 2), dtype=np.float)
for j in range(12):
x, y = 0., 0.
for i in range(10000):
x, y = randwalk(x, y)
destinations[j] = x, y
square_distances = destinations[:,0] ** 2 + destinations[:,1] ** 2
m_s_d = np.mean(square_distances)
I think that to do it I just have to plot the msd against the number of steps? But I'm not sure how to do this. I saw a similar question on stackoverflow but the code for it is different than mine and I don't understand how to use that for my code.
I tried to do next
plt.figure()
t = 10000
plt.plot(m_s_d, t)
plt,show()
But this gives an error as the dimensions are not equal.
Edit ** I think my issue is that I am trying to plot it against number of steps when I should be plotting it against the change in time. However I can’t work out how to calculate the change in time dt?
Apologies in advance is question isn't formulated well, I am fairly new to computing. Thank you.

Iteration for the definition of a function

I would like to make an iteration in order to get a function verifying an integral equation. The integral operator is hidden in the function lambdaop. However, I just cannot iterate on the process getting an error
File "blablabla/.spyder-py3/temp.py", line 11, in integrand
return -0.5*f(x)*scipy.special.expi(-abs(x-tau))
TypeError: can't multiply sequence by non-int of type 'float'
that I do not understand. I have done here for only two functions by my ultimate goal would be to make n iteration. I guess the error comes from the way of defining the function that is not suitable (maybe not use "lambda definitions" ... ) but I do not want to create a vector of size n in place of the function since I want to integrate it after. Anyone has an idea how to fix this problem ?
import numpy as np
import matplotlib.pyplot as plt
import math
import scipy.integrate
import scipy.special
def initial(x):
return x + 2/3
def integrand(f,x,tau):
return -0.5*f(x)*scipy.special.expi(-abs(x-tau))
def lambdaop(f,x,tau):
def step(x,tau):
return integrand(f,x,tau)
g = lambda tau: scipy.integrate.quad(step,0,np.inf,args=(tau,))
return g
g = lambdaop(initial,1,2)
h = lambdaop(g,1,2)
print(h(5))
x = np.linspace(0,3,101)
y = np.linspace(0,3,101)
for i in np.arange(101):
y[i] = h(x[i])[0]
plt.plot(x,y)
plt.show()
I have not seen any other topic like mine but in case it is a duplicate, please excuse me.
Add some print statements in your integrand function.
For example,
def integrand(f,x,tau):
print('-------')
print('args:', f, x, tau)
v = f(x)
print(f'f({x})={v}')
s = scipy.special.expi(-abs(x-tau))
print(f's={s}')
result = -0.5*v*s
print('=====')
return result
and you'll see that:
f(1.0)=(inf, inf)
s=-0.0037793524098489063
The (inf, inf) is where the error message is coming from.

Bifurcation diagram in matplotlib

I'm trying to acquire the bifurcation diagram for the equation below:
(x is a function of t)
as:
And here is my snippet:
import numpy as np
import matplotlib.pyplot as plt
def pitch(r, x):
return r * x + np.power(x,3)- np.power(x,5)
n = 10000
r = np.linspace(-200, 200, n)
iterations = 1000
last = 100
x = 0
for i in range(iterations):
x = pitch(r,x)
if i >= (iterations - last):
plt.plot(r,x, ',k', alpha=0.02)
plt.title("Bifurcation diagram")
plt.show()
But the generated plot is not what it is supposed to be:
Edit:
Here is my recent attempt:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def pitch(s,x,r):
x = s[0]
dxdt = r * x + np.power(x,3)- np.power(x,5)
return [dxdt]
t = np.linspace(0,100)
s0=[-50]
r = np.linspace(-200, 200)
for i in r:
s = odeint(pitch,s0,t, args=(i,))
plt.plot(s,i,',k', alpha=0.02)
plt.title("Bifurcation diagram")
plt.show()
With this error:
raise ValueError("x and y must have same first dimension") ValueError:
x and y must have same first dimension
Could you give me some advice to fix this problem?!
I found a link to this post and decided to post a few remarks that might be helpful to someone stumbling upon it in the future.
I did not analyze the equation in detail but it is clear from the first sight that something interesting would happen when r is close to 0.
So we could study the behavior of the system for r in [-10,10]
You are right to use odeint instead of solving the Cauchy problem using Euler method coded by yourself.
This equation has an attractor in that it soon "forgets" the initial condition and slides towards the attractor, yet the choice of the attractor depends on where in relation to 0 do we start. Large positive initial conditions would slide to the negative attractor and vice versa as - x^5 is the term that defines the behavior at large x.
What we need to do is for each r in the range put a mark at the attractor that the solution slides to for each initial condition.
We first create a canvas to put marks into:
diagram = np.zeros((200,200))
And then for each combination of (r,s0) we put a point on the canvas at (r,s[-1]).
Here is the complete code
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def pitch(s,x,r):
x = s[0]
dxdt = r * x + np.power(x,3)- np.power(x,5)
return [dxdt]
t = np.arange(0,100,2)
s0=[-50]
N = 200 # Number of points along each side of the diagram
diagram = np.zeros((N,N))
rmin,rmax = -10,10
rrange = np.arange(rmin, rmax,(rmax-rmin)/N)
smin,smax = -5.0,5.0
srange = np.arange(smin,smax,2*(smax-smin)/N)
for i in rrange:
for s0 in srange:
s = odeint(pitch,[s0],t, args=(i,))
imgx = int((i-rmin)*N/(rmax-rmin))
imgy = int((s[-1]-smin)/(smax-smin)*N)
imgx = min(N-1,max(0,imgx)) # make sure we stay
imgy = min(N-1,max(0,imgy)) # within the diagram bounds
diagram[imgy,imgx] = 1
plt.title("Bifurcation diagram")
plt.imshow(np.flipud(diagram),cmap=cm.Greys,
extent=[rmin,rmax,smin,smax],aspect=(rmax-rmin)/(smax-smin))
plt.xlabel("r")
plt.ylabel("x")
plt.show()
And the resulting plot
When you zoom in into the region around 0 by setting (rmin,rmax) to (-0.5,0.5) you could see that the branches of the diagram do not start at 0
Instead as in the diagram drawn in the original post the branches start at roughly r=-0.25

Type error: Plotting an array including tuples

I'm just gonna solve and plot a nonlinear equation with matplotlib, but there is an error saying:
TypeError: zip argument #1 must support iteration
Can you help me fix it?...
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fsolve
r = np.arange(-100, 100, step=0.01, dtype=float)
def equation(p,r0):
x = p
r = r0
return (r * x + np.power(x,3)- np.power(x,5))
temp = []
for i in r:
x = fsolve(equation, 0, args=(i,))
temp.extend((i,x))
my_array = np.array(temp)
#print(my_array)
x, y = zip(*my_array)
plt.plot(x,y)
As #Julien said, you must use append instead of extend. Furthermore, I guess you can't see the result because there is no plt.show() in your snippet. You need to add that right after plt.plot(x,y). Then, the output will be:
You better change your initial guess to something else because 0 is the answer for the equation for all r. As an example, here is the result for 2:

numpy and statsmodels give different values when calculating correlations, How to interpret this?

I can't find a reason why calculating the correlation between two series A and B using numpy.correlate gives me different results than the ones I obtain using statsmodels.tsa.stattools.ccf
Here's an example of this difference I mention:
import numpy as np
from matplotlib import pyplot as plt
from statsmodels.tsa.stattools import ccf
#Calculate correlation using numpy.correlate
def corr(x,y):
result = numpy.correlate(x, y, mode='full')
return result[result.size/2:]
#This are the data series I want to analyze
A = np.array([np.absolute(x) for x in np.arange(-1,1.1,0.1)])
B = np.array([x for x in np.arange(-1,1.1,0.1)])
#Using numpy i get this
plt.plot(corr(B,A))
#Using statsmodels i get this
plt.plot(ccf(B,A,unbiased=False))
The results seem qualitatively different, where does this difference come from?
statsmodels.tsa.stattools.ccf is based on np.correlate but does some additional things to give the correlation in the statistical sense instead of the signal processing sense, see cross-correlation on Wikipedia. What happens exactly you can see in the source code, it's very simple.
For easier reference I copied the relevant lines below:
def ccovf(x, y, unbiased=True, demean=True):
n = len(x)
if demean:
xo = x - x.mean()
yo = y - y.mean()
else:
xo = x
yo = y
if unbiased:
xi = np.ones(n)
d = np.correlate(xi, xi, 'full')
else:
d = n
return (np.correlate(xo, yo, 'full') / d)[n - 1:]
def ccf(x, y, unbiased=True):
cvf = ccovf(x, y, unbiased=unbiased, demean=True)
return cvf / (np.std(x) * np.std(y))

Categories