As the title suggests, I am looking for an equivalent function or a suggestion on how to achieve the same thing deval does in MATLAB but in Python.
Code:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
#define model function that returns ds/dt, di/dt/ and dr/dt
def epidemic_model(state, t):
s, i, r = state
d_s = -0.06 * s * i
d_i = 0.06 *s * i - 7*i
d_r = 7 * i
return [d_s, d_i, d_r]
t = np.arange(0, 1, 0.01)
init_state = [990, 10, 0]
state = odeint(epidemic_model, init_state, t)
plt.xlabel('time')
plt.ylabel('population')
plt.plot(t, state)
Now my task is to find at which time the number of the infected population and recovered population is the same.
I would do this in MATLAB using deval, I am looking for a Python version of this.
Check dsolve function in the sympy package below:
http://docs.sympy.org/latest/modules/solvers/ode.html#dsolve
Solves any (supported) kind of ordinary differential equation and system of ordinary differential equations.
Also, solve a system of ordinary differential equations using integrate.solve_ivp from scipy package:
https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.solve_ivp.html#scipy-integrate-solve-ivp
This function numerically integrates a system of ordinary differential equations given an initial value
Related
I am trying to solve a 4th order bvp using the bvp solver in Python. The differential equation is of the form given below :-
d4w(x)/dx4=t/(t-w(x))
with boundary conditions w(0)=w(10)=w'(0)=w'(10)=0 . If t in the differential equation is a simple constant, the code is simple and is given by
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from scipy.integrate import solve_bvp
t=1
def fun(x, y):
return np.vstack([y[1], y[2], y[3], t/(t-y[0])])
def bc(ya, yb) :
return np.array([ya[0], ya[1], yb[0], yb[1]])
xmesh = np.linspace(0, 10, 100)
y = np.zeros((4, len(xmesh)))
sol = solve_bvp(fun, bc, xmesh, y)
plt.figure()
plt.plot(xmesh, sol.sol(xmesh)[0])
plt.legend()
But in my case, t is a pre-defined constant 1-D array. I am facing some issues in writing the code for this case. Any help regarding this will be highly appreciated.
My question is, how to return the mean value and variance of the estimated "kde"? Or is there any other package you known that can easily output mean value or variance value, like print kde.mean() or print kde.get_parameter(mean)?
import numpy as np
from scipy.stats import norm
from sklearn.neighbors import KernelDensity
N = 100
np.random.seed(1)
X = np.concatenate((np.random.normal(0, 1, int(0.3 * N)),np.random.normal(5, 1, int(0.7 * N))))[:, np.newaxis]
X_plot = np.linspace(-5, 10, 1000)[:, np.newaxis]
kde = KernelDensity(kernel='gaussian', bandwidth=0.5).fit(X)
In general, you need to do this numerically. I suggest 2 different approaches:
Integration
Monte Carlo Simulation
These approaches work for any kernel and any bandwidth.
Integration
Uses the fact that once we know the probability density function, we can easily compute mean and variance via integration.
Note that in scikit-learn the method score_samples returns log pdf and therefore one needs to "exp" it.
Monte Carlo Simulation
The idea here is to simply sample from your KDE and estimate population mean and variance via sample mean and variance.
Code
import numpy as np
from scipy.integrate import quad
from sklearn.neighbors import KernelDensity
N = 100
np.random.seed(1)
X = np.concatenate((np.random.normal(0, 1, int(0.3 * N)),np.random.normal(5, 1, int(0.7 * N))))[:, np.newaxis]
X_plot = np.linspace(-5, 10, 1000)[:, np.newaxis]
kde = KernelDensity(kernel='gaussian', bandwidth=0.5).fit(X)
# Mean and Variance - Integration
pdf = lambda x : np.exp(kde.score_samples([[x]]))[0]
mean_integration = quad(lambda x: x * pdf(x), a=-np.inf, b=np.inf)[0]
variance_integration = quad(lambda x: (x ** 2) * pdf(x), a=-np.inf, b=np.inf)[0] - mean_integration ** 2
# Mean and Variance - Monte Carlo
n_samples = 10000000
samples = kde.sample(n_samples)
mean_mc = samples.mean()
variance_mc = samples.var()
print('Mean:\nIntegration: {}\nMonte Carlo: {}\n'.format(mean_integration, mean_mc))
print('Variance\nIntegration: {}\nMonte Carlo: {}\n'.format(variance_integration, variance_mc))
Output:
Mean:
Integration: 3.560582852075697
Monte Carlo: 3.5595633705830934
Variance:
Integration: 6.645066811078639
Monte Carlo: 6.646732489654485
Principle
I ran into the same situation and you can find a working implementation for expectation in the statsmodels library, however interestingly enough it is patching scipy and not doing the same functions in it's own library.
They seem to have expect(), expect_v2() and expect_discrete() which uses a similar technique in the other answer that uses scipy.integrate.quad to do numerical integration.
TL;DR version
Also if you're lazy like me and go with the default sampling that statsmodels infers, you can get a quick expectation value by replacing the numerical integration with the dot product of density and support. It's probably 'close enough' for most purposes.
import numpy as np
import statsmodels.api as sm
import scipy
N = 100
np.random.seed(1)
X = np.concatenate((np.random.normal(0, 1, int(0.3 * N)),np.random.normal(5, 1, int(0.7 * N))))[:, np.newaxis]
X_plot = np.linspace(-5, 10, 1000)[:, np.newaxis]
kde = sm.nonparametric.KDEUnivariate(X)
kde.fit(kernel='gau', bw=0.5)
mean1 = np.dot(kde.density, kde.support) / kde.density.sum()
mean2 = scipy.integrate.quad(lambda x: kde.evaluate(x) * x, kde.support[0], kde.support[-1])
print('TL;DR version - Mean:', mean1)
print('Integration version - Mean:', mean2)
print('TL;DR version - Variance:', np.dot(kde.density, kde.support**2) / kde.density.sum() - mean1**2)
print('Integration version - Variance:', scipy.integrate.quad(lambda x: kde.evaluate(x) * x**2, kde.support[0], kde.support[-1])[0] - mean2[0]**2)
Output:
TL;DR version - Mean: 3.5605148164179368
Integration version - Mean: (3.5604536291684905, 1.9311947816995413e-08)
TL;DR version - Variance: 6.646077637181225
Integration version - Variance: 6.644042199345121
Difference between quad and dot
Please note that the quad method will not work with kernels other than Gaussian due to lack of evaluate(). For example, if you pass kernel='epa', fft=False when you fit, the only way is to use numpy.dot currently. This might change in future versions.
As an interesting effect, the seaborn library relies on statsmodels to display it's kde's however only works with Gaussian due to the above reason. For cdf's, it will show you the Gaussian cdf even if a different one is specified; pdf's seem to still honor the kerenel specification.
Reference
statsmodels.sandbox.sppatch
Also reproduced here in case the repository changes [Latest commit bfa3e69 on Jan 22], however if using this algorithm with statsmodels you might have to replace the pdf calls with evaluate calls.
I am trying to use sympy to solve an equation for a one dimensional steady state model of the solar wind. I have the code below
from sympy import Eq, var, solve
var('r',real=True)
eq = Eq((1./2.)*((CF**2)/(r))+CT*r**(gamma)+bm/(2.*muo) - CM)
a = solve(eq,r)
Where CF, CT, CM, gamma, muo, and bm are just real numbers. I am trying to solve the equation for r over a range of values for bm but it will not return any numbers. Upon running the block of code, my python notebook just displays that the code is running but doesnt return a value nor does it stop. Is there an alternative function or some sort of command I should be giving to sympy in order to make it work faster?
The equation involves the sum of two powers of r, including r**gamma. Unless gamma is a very small integer (between -4 and 4), there is no hope of solving this symbolically (which is what sympy is for).
To solve it numerically, you need scipy rather than sympy. For example:
from scipy.optimize import fsolve
func = lambda r : (1./2.)*((CF**2)/(r))+CT*r**(gamma)+bm/(2.*muo) - CM
# assign some numeric values to CF, CT, gamma, bm, muo, CM
sol = fsolve(func, 1) # 1 is the initial guess for the solver
I'm trying to solve the equation y'' + (epsilon-x^2)y = 0 numerically using odeint. I know the solutions (the wavefunctions of a QHO), but the output from odeint has no apparent relation to it. I can solve ODEs with constant coefficients just fine, but as soon as I move to variable ones, I can't solve any of the ones I tried. Here's my code:
#!/usr/bin/python2
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
import scipy.integrate as spi
x = np.linspace(-5,5,1e4)
n = 0
epsilon = 2*n+1
def D(Y,x):
return np.array([Y[1], (epsilon-x**2)*Y[0]])
Y0 = [0,1]
Y = spi.odeint(D,Y0,x)
# Y is an array with the first column being y(x) and the second y'(x) for all x
plt.plot(x,Y[:,0],label='num')
#plt.plot(x,Y[:,1],label='numderiv')
plt.legend()
plt.show()
And the plot:
[not enough rep:] https://drive.google.com/file/d/0B6840LH2NhNpdUVucUxzUGFpZUk/edit?usp=sharing
Look here for plots of solution: http://hyperphysics.phy-astr.gsu.edu/hbase/quantum/hosc5.html
It looks like your equation is not correctly interpreted. You have a differential equation y'' + (epsilon-x^2)y = 0, but you forget a minus sign in your vector form. In particular it should be
y[0]' = y[1]
y[1]' = -(epsilon-x^2)y[0]
So (adding the minus sign in front of the epsilon term
def D(Y,x):
return np.array([Y[1], -(epsilon-x**2)*Y[0]])
In fact the plot you have is consistent with the DE y'' + (epsilon-x^2)y = 0. Check it out: Wolphram Alpha
I was trying to use odeint to solve a problem. My code is as below:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
eta=1.24e-9/2
def fun(x):
f=1.05e-8*eta*x**(1.5)*np.exp(13.6/x)
return (np.sqrt(1.+4*f)-1)/2./f
x=np.arange(0,1,0.001)
y=odeint(fun,x,0)[0]
plt.plot(x,y)
plt.plot(x,x)
plt.show()
It the two curves are the same, which is obviously wrong. If I plot the function, it will looks like a step function, which is very very small before about 0.3 and exponentially goes to 1. Can you help me figure out what's wrong with it? Thank you!
There are several problems with your code, most of which you might be able to solve yourself if you read the docstring for odeint more carefully.
To get you started, the following is a simple example of solving a scalar differential equation with odeint. Instead of trying to understand (and possibly debug) your function, I'll use a very simple equation. I'll solve the equation dy/dt = a * y, with initial condition y(0) = 100. Once you have this example working, you can modify fun to solve your problem.
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def fun(y, t, a):
"""Define the right-hand side of equation dy/dt = a*y"""
f = a * y
return f
# Initial condition
y0 = 100.0
# Times at which the solution is to be computed.
t = np.linspace(0, 1, 51)
# Parameter value to use in `fun`.
a = -2.5
# Solve the equation.
y = odeint(fun, y0, t, args=(a,))
# Plot the solution. `odeint` is generally used to solve a system
# of equations, so it returns an array with shape (len(t), len(y0)).
# In this case, len(y0) is 1, so y[:,0] gives us the solution.
plt.plot(t, y[:,0])
plt.xlabel('t')
plt.ylabel('y')
plt.show()
Here's the plot:
More complicated examples of the use of odeint can be found in the SciPy Cookbook (scroll down to the bullet labeled "Ordinary differential equations").