Error in minimization using scipy - python

I am trying to minimize a function using spicy but the estimate of sigma is way off. Any help would be greatly appreciated.
Here's my code so far:-
import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
from pylab import plot, show, grid, xlabel, ylabel
np.set_printoptions(linewidth=999999)
from scipy.stats import multivariate_normal
import scipy.stats as stats
from numpy import sqrt
from numpy import exp
from numpy import log
from numpy import pi
# Process parameters
beta=1.5
sigma=0.01
theta=0.7
T=50
N=1000
dt = T/N
#n=1 ## number of simulations
M = np.zeros((N))
#for k in range(n):
# Iterate to compute the steps of the Brownian motion.
for i in range(N):
M[i]=(theta + (M[i-1]-theta)*exp(-beta*dt)) + sigma*np.random.normal(0,sqrt((1-exp(-2*beta*dt))/2*beta))
M[0] = 0.7 ## initial value
#print(M)
def mle(params):
beta = params[0]
theta = params[1]
sigma = params[2]
alpha = exp(-beta*dt)
eta = (sigma**2)*(1-exp(-2*beta*dt))/(2*beta)
LL = -(-N/2*log(2*pi)-N*log(sqrt(eta)) - (np.sum((M[i]-M[i-1]*alpha - theta*(1-alpha))**2))/(2*eta))
return(LL)
initParams = [1, 1, 1]
#params1 = np.array([1,1,1])
res = minimize(mle, initParams ,method='nelder-mead')
print(res.x)
What I am getting is this:-
runfile('/Users/achalawasthi/Desktop/testmle.py', wdir='/Users/achalawasthi/Desktop')
[ 1.84035906e+00 7.41336913e-01 2.00523821e-23]
As you can see, the estimate of sigma is way off. I do not understand why this is happening ? My intuition is that there is some instability and that sigma just goes away. Would putting some bounds on sigma help?
Thanks

Related

Second order coupled ODE using ODEINT

I am new to solving coupled ODEs with python, I am wondering if my approach is correct, currently this code outputs a graph that looks nothing like the expected output. These are the equations I am trying to solve:
And here is the code I am using (for the functions f_gr, f_sc_phi and f_gTheta you can just put any constant value)
import Radial as rd
import ScatteringAzimuthal as sa
import PolarComponent as pc
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
#gamma for now set to 1
g_mm = 1
def f(u,t):
#y1 = thetadot :: y2 = phidot :: y3 = cdot
rho, theta, y1, phi, y2, c, y3 = u
p = [y1, (pc.f_gTheta(theta,524.1+rho)/(c*np.cos(phi))-(g_mm*y1)+(2*y1*y2*np.tan(phi))-(2*y3*y1/c)),
y2, ((sa.f_sc_phi(theta,524.1+rho/c))-(g_mm*y2)-(2*y3*y2/c)-(np.sin(phi)*np.cos(phi)*y2**2)),
y3, (rd.f_gr(theta,524.1+rho)-(g_mm*y3)+(c*y2**2)+(c*(y1**2)*(np.cos(phi)**2))), phi]
return p
time = np.linspace(0,10,100)
z2 = odeint(f,[0.1,np.pi/2,0.1,np.pi/2,0.1,0.1,0.1], time)
rhoPl = z2[:,0]
thetaPl = z2[:,1]
phiPl = z2[:,3]
'''
plt.plot(rhoPl,time)
plt.plot(thetaPl,time)
plt.plot(phiPl,time)
plt.show()
'''
x = rhoPl*np.sin(thetaPl)*np.cos(phiPl)
y = rhoPl*np.sin(thetaPl)*np.sin(phiPl)
z = rhoPl*np.cos(thetaPl)
plt.plot(x,time)
plt.plot(y,time)
plt.plot(z,time)
plt.show()
when I change the time from 0.1 to 5 I get an error:
ODEintWarning: Excess work done on this call (perhaps wrong Dfun type). Run with full_output = 1 to get quantitative information.
Any ideas on how to improve this code or if my approach is completely incorrect?
Code for Radial.py
import numpy as np
from scipy.special import spherical_jn
from scipy.special import spherical_yn
import sympy as sp
import matplotlib.pyplot as plt
R_r = 5.6*10**(-5)
l = 720
n_w = 1.326
#k = 524.5/R_r
X_r = 524.5
# R is constant r is changing
def f_gr(theta,x):
f = ((sp.sin(theta))**(2*l-2))*(1+(sp.cos(theta))**2)
b = (spherical_jn(l,n_w*x)*spherical_jn(l,n_w*x,True))+(spherical_yn(l,n_w*x)*spherical_yn(l,n_w*x,True))
c = (spherical_jn(l,n_w*X_r)*spherical_jn(l,n_w*X_r,True))+(spherical_yn(l,n_w*X_r)*spherical_yn(l,n_w*X_r,True))
n = b/c
f = f*n
return f
Code for ScatteringAzimuthal.py
from scipy.special import spherical_jn, spherical_yn
import numpy as np
import matplotlib.pyplot as plt
l = 720
n_w = 1.326
n_p = 1.572
X_r = 524.5
R_r = 5.6*10**(-5)
R_p = 7.5*10**(-7)
k = X_r/R_r
def f_sc_phi(theta,x):
f = (2/3)*(n_w**2)*((X_r**3)/x)*((R_p**3)/(R_r**3))*(((n_p**2)-(n_w**2))/((n_p**2)+(2*(n_w**2))))
g = np.sin(theta)**(2*l-3)
numerator = (l*(1+np.sin(theta))- np.cos(2*theta))\
*((spherical_jn(l,n_w*x)*spherical_jn(l,n_w*x))+(spherical_yn(l,n_w*x)*spherical_yn(l,n_w*x)))
denominator = ((spherical_jn(l,n_w*X_r)*spherical_jn(l,n_w*X_r,True))\
+(spherical_yn(l,n_w*X_r)*spherical_yn(l,n_w*X_r,True)))
m = numerator/denominator
final = f*g*m
return final
And Code for PolarComponent.py
import numpy as np
from scipy.special import spherical_yn, spherical_jn
import matplotlib.pyplot as plt
l = 720
n_w = 1.326
X_r = 524.5 #this value is implemented in the ode file
#define dimensionless polar component
#X_r is radius, x is variable
def f_gTheta(theta,x):
bessel1 = (spherical_jn(l,n_w*x)*spherical_jn(l,n_w*x)) + \
(spherical_yn(l,n_w*x)*spherical_yn(l,n_w*x))
bessel2 = ((spherical_yn(l,n_w*X_r)*spherical_yn(l,n_w*X_r,True)) + \
(spherical_yn(l,n_w*X_r)*spherical_yn(l,n_w*X_r,True)))*n_w*x
bessels = bessel1/bessel2
rest = (np.sin(theta)**(2*l-3))*((l-1)*(1+(np.cos(theta)**2)) \
-((np.sin(theta)**2)*np.cos(theta)))
final = rest*bessels
return final
Here is a link that I really like for simulating second order odes. It has an optamization twist on it because it is fitting the model to match a simulation. It has a couple of examples for odeint and also gekko.

Python (matplotlib) only show normalized values, how do I get absolute values

Please have a check at this code, input data is much larger than 1, the plotted data has max value of 1, so it has to be normalized. I would like them to be absolute values. How can this be done. Many thanks.
import numpy as np
from fipy import *
from matplotlib import pyplot as plt
from scipy.integrate import odeint
import warnings
import time
import pdb
warnings.filterwarnings("ignore", category=DeprecationWarning)
Declare variable values
critical_radius = 1e-10
moments = 4
xf = 5e-3
yf = 2.95e-4
nx = 100
ny = 100
nelm = nx*ny
dx = xf / (nx - 1)
dy = yf / (ny - 1)
Create a 2D mesh
mesh = Grid2D(dx=dx, dy=dy, nx=nx, ny=ny)
phi = CellVariable(name = "moment 0",mesh = mesh, value = 0.)
phi_ss = phi.copy()
print(phi_ca)
store_no_180=np.load('store_no_180.npy')
show the values of the data
a=store_no_180[99,0,:]
phi_ss.value=a
viewer= Viewer(vars=phi_ss,title = "moment0")
viewer.plot()

Numpy FFT over few seconds

I'm trying to understand how fft in python works (or in general).
When I have a signal that is recorded for a few seconds I can only display one second of that FFT.
Is there a way to take all of the data and averaged this out?
I did this before in LabView.
Can any one help?
Here is an example code that I'm using.
from numpy import linspace, sin, pi, log10, average, arange
from matplotlib.pyplot import plot, show, figure
from numpy.fft import fft, fftfreq
N = 1000 * 60 * 4
dt = 1 / 1000
x = linspace(0, N*dt, N)
freq = linspace(10, 200, N)
sinsweep = sin(x*freq)
mavg = [average(sinsweep[i*60:(i+1)*60]) for i in range(int(N/60))]
plot(freq, sinsweep, '.')
plot(linspace(10, 200, int(N/60)), mavg, '.')
f = figure()
t = arange(60)
sp = fft(mavg, n=60)
freq = fftfreq(t.shape[-1])
plot(sp.imag)
show()
I give some modification to your code, to obtain a beautiful spectrum. First I increase the number of points to verify Shannon criterion. And some tricks to
improve speed.
from numpy import linspace, sin, pi, log10, average, arange
from matplotlib.pyplot import plot, show, figure
from numpy.fft import fft, fftfreq
close()
N = 10000 * 60 * 4
dt = 1 / 10000
t = arange(0, N*dt, dt)
freq = linspace(10, 200, N)
sinsweep = sin(t*freq)
mavg = sinsweep.reshape(-1,60).mean(1)
tm=t[::60]
figure('signal')
plot(tm, mavg)
sp = fft(mavg)
freq = fftfreq(tm.size,dt*60)
valid=freq>0
figure('spectrum')
plot(freq[valid],abs(sp[valid]))
show()
for
Is it what you expected ?

Plotting elliptical orbits

I'm trying to write a code that plots the elliptical paths of an object using the equation for the ellipse r=a(1-e^2)/(1+e*cos(theta)). I'd also like this data to be put into an array for other use.
from numpy import *#Imports Python mathematical functions library
import matplotlib.pyplot as plt #Imports plot library
from pylab import *
a = 5
e = 0.3
theta = 0
while theta <= 2*pi:
r = (a*(1-e**2))/(1+e*cos(theta))
print("r = ",r,"theta = ",theta)
plt.polar(theta, r)
theta += pi/180
plt.show()
The code spits out correct values for r and theta, but the plot is blank. The polar plot window appears, but there is nothing plotted.
Please help. Thanks in advance.
Do not call plt.polar once for every point. Instead, call it once, with all the data as input:
import numpy as np #Imports Python mathematical functions library
import matplotlib.pyplot as plt #Imports plot library
cos = np.cos
pi = np.pi
a = 5
e = 0.3
theta = np.linspace(0,2*pi, 360)
r = (a*(1-e**2))/(1+e*cos(theta))
plt.polar(theta, r)
print(np.c_[r,theta])
plt.show()
By the way, numpy can do the calculation as a two-liner, instead of using a while-loop:
theta = np.linspace(0,2*pi, 360) # 360 equally spaced values between 0 and 2*pi
r = (a*(1-e**2))/(1+e*cos(theta))
This defines theta and r as numpy arrays (rather than single values).
I think you need to do points.append([theta,r]) then at the end plt.polar(points) ... that makes a kinda neat design too
from numpy import *#Imports Python mathematical functions library
import matplotlib.pyplot as plt #Imports plot library
from pylab import *
a = 5
e = 0.3
theta = 0
points = []
while theta <= 2*pi:
r = (a*(1-e**2))/(1+e*cos(theta))
print("r = ",r,"theta = ",theta)
points.append((theta, r))
theta += pi/180
#plt.polar(points) #this is cool but probably not what you want
plt.polar(*zip(*points))
plt.show()

skew normal distribution in scipy

Does anyone know how to plot a skew normal distribution with scipy?
I supose that stats.norm class can be used but I just can't figure out how.
Furthermore, how can I estimate the parameters describing the skew normal distribution of a unidimensional dataset?
From the Wikipedia description,
from scipy import linspace
from scipy import pi,sqrt,exp
from scipy.special import erf
from pylab import plot,show
def pdf(x):
return 1/sqrt(2*pi) * exp(-x**2/2)
def cdf(x):
return (1 + erf(x/sqrt(2))) / 2
def skew(x,e=0,w=1,a=0):
t = (x-e) / w
return 2 / w * pdf(t) * cdf(a*t)
# You can of course use the scipy.stats.norm versions
# return 2 * norm.pdf(t) * norm.cdf(a*t)
n = 2**10
e = 1.0 # location
w = 2.0 # scale
x = linspace(-10,10,n)
for a in range(-3,4):
p = skew(x,e,w,a)
plot(x,p)
show()
If you want to find the scale, location, and shape parameters from a dataset use scipy.optimize.leastsq, for example using e=1.0,w=2.0 and a=1.0,
fzz = skew(x,e,w,a) + norm.rvs(0,0.04,size=n) # fuzzy data
def optm(l,x):
return skew(x,l[0],l[1],l[2]) - fzz
print leastsq(optm,[0.5,0.5,0.5],(x,))
should give you something like,
(array([ 1.05206154, 1.96929465, 0.94590444]), 1)
The accepted answer is more or less outdated, because a skewnorm function is now implemented in scipy. So the code can be written a lot shorter:
from scipy.stats import skewnorm
import numpy as np
from matplotlib import pyplot as plt
X = np.linspace(min(your_data), max(your_data))
plt.plot(X, skewnorm.pdf(X, *skewnorm.fit(your_data)))

Categories

Resources