Exponential regression function Python - python

I am trying to implement a exponential regression function. sp stands for sympy. I use numpy and sympy. Firstly, in func_exp I tried to use np.exp but it generated an error (attribute error), so I decided to use sympy instead. Well, this is the code
import numpy as np
from numpy.linalg import matrix_rank
import scipy
import scipy.integrate
import random
import matplotlib.pyplot as plt
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
from sympy import integrate
import sympy as sp
x, y = sp.symbols('x, y')
sp.init_printing(use_unicode=True,use_latex='mathjax')
def exponential_regression (x_data, y_data):
def func_exp(x, a, b):
return a*sp.exp(b*x)
popt, pcov = scipy.optimize.curve_fit(func_exp, x_data, y_data)
a = popt[0] # componente a, Parámetro ÓPTimo (popt).
b = popt[1] # componente b, Parámetro ÓPTimo (popt).
plt.figure()
puntos = plt.plot(x_data, y_data, 'x', color='xkcd:maroon')
curva_regresion = plt.plot(x_data, func_exp(x_data, a, b), color='xkcd:teal')
plt.show(puntos, curva_regresion)
return func_exp(x, a, b)
I try to execute:
x_data = np.arange(0, 51) # Crea un array de 0 a 50.
y_data = np.array([0.001, 0.199, 0.394, 0.556, 0.797, 0.891, 1.171, 1.128, 1.437,
1.525, 1.720, 1.703, 1.895, 2.003, 2.108, 2.408, 2.424,2.537,
2.647, 2.740, 2.957, 2.58, 3.156, 3.051, 3.043, 3.353, 3.400,
3.606, 3.659, 3.671, 3.750, 3.827, 3.902, 3.976, 4.048, 4.018,
4.286, 4.353, 4.418, 4.382, 4.444, 4.485, 4.465, 4.600, 4.681,
4.737, 4.792, 4.845, 4.909, 4.919, 5.100])
exponential_regression(x_data, y_data)
And I get:
exponential_regression(x_data, y_data)
TypeError: Cannot cast array data from dtype('O') to dtype('float64') according to the rule 'safe'
Traceback (most recent call last):
File "<ipython-input-122-ee7c243ae4b0>", line 1, in <module>
exponential_regression(x_data, y_data)
File "/Volumes/TOSHIBA/spline.py", line 35, in exponential_regression
popt, pcov = scipy.optimize.curve_fit(func_exp, x_data, y_data)
File "/Applications/anaconda3/lib/python3.6/site-packages/scipy/optimize/minpack.py", line 742, in curve_fit
res = leastsq(func, p0, Dfun=jac, full_output=1, **kwargs)
File "/Applications/anaconda3/lib/python3.6/site-packages/scipy/optimize/minpack.py", line 387, in leastsq
gtol, maxfev, epsfcn, factor, diag)
error: Result from function call is not a proper array of floats.
What is wrong? Thanks in advance!

Here is a minimal example for your fit function as close as possible to your code but removing all unnecessary elements. You can easily remove c to adhere to your requirements:
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
def func_exp(x, a, b, c):
#c = 0
return a * np.exp(b * x) + c
def exponential_regression (x_data, y_data):
popt, pcov = curve_fit(func_exp, x_data, y_data, p0 = (-1, 0.01, 1))
print(popt)
puntos = plt.plot(x_data, y_data, 'x', color='xkcd:maroon', label = "data")
curva_regresion = plt.plot(x_data, func_exp(x_data, *popt), color='xkcd:teal', label = "fit: {:.3f}, {:.3f}, {:.3f}".format(*popt))
plt.legend()
plt.show()
return func_exp(x_data, *popt)
x_data = np.arange(0, 51)
y_data = np.array([0.001, 0.199, 0.394, 0.556, 0.797, 0.891, 1.171, 1.128, 1.437,
1.525, 1.720, 1.703, 1.895, 2.003, 2.108, 2.408, 2.424,2.537,
2.647, 2.740, 2.957, 2.58, 3.156, 3.051, 3.043, 3.353, 3.400,
3.606, 3.659, 3.671, 3.750, 3.827, 3.902, 3.976, 4.048, 4.018,
4.286, 4.353, 4.418, 4.382, 4.444, 4.485, 4.465, 4.600, 4.681,
4.737, 4.792, 4.845, 4.909, 4.919, 5.100])
exponential_regression(x_data, y_data)
Output with c = 0:
Output with c != 0:
Main changes explained:
Removed sympy - it has nothing to do with the fitting procedure.
The definition of the exponential fit function is placed outside exponential_regression, so it can be accessed from other parts of the script. It uses np.exp because you work with numpy arrays in scipy.
Added the parameter p0 which contains the initial guesses for the parameters. Fit functions are often sensitive to this initial guess because of local extrema.
Unpack variables with *popt to make it more flexible for different numbers of variables. a = popt[0], b = popt[1], etc.
Removed unnecessary imports. Keep your namespace free from clutter.

Related

Curve fitting with scipy in python to find correction parameters (can't multiply sequence by non-int of type 'numpy.float64')

I'm trying to fit the function h = a0L(1-a1L**(-w1) to my graph and find the parameters a0, a1, and w1. I cant figure out why it's not working. I keep getting the error: can't multiply sequence by non-int of type 'numpy.float64'. Here is a snippet of my code:
L = [8, 16, 32, 64, 128, 256]
Average_height = [12.973731636721096,26.52865044449718,53.85333875018466,108.90761725203599,219.30647736483996,428.833120246036]
def correction(L, a0, a1, w1):
return a0*L*(1-a1*L**(-w1))
popt, pcov = curve_fit(correction, L, Average_height, bounds =([0,0,-10], [10,10,10]))
a0, a1, w1 = popt
print((a0, a1, w1))
plt.plot(L, correction(L, *popt), 'r-')
plt.show()
As hpaulj already mentioned, you should use numpy arrays. There was also a stray comma that must have been a typo because otherwise, you would have had different numbers of x- and y-values. Finally, you cannot generally use the Python power function ** with numpy arrays - there is the dedicated numpy function np.power for this. Changing the code accordingly leads to this:
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
L = np.asarray([8, 16, 32, 64, 128, 256])
Average_height = np.asarray([12.973731636721096,26.52865044449718,53.85333875018466,108.90761725203599,219.30647736483996,428.833120246036])
def correction(L, a0, a1, w1):
return a0*L*(1-a1* np.power(L, -w1))
popt, pcov = curve_fit(correction, L, Average_height, bounds =([0,0,-10], [10,10,10]))
print(*popt)
#1.6836463115082618 9.999999999965157 2.717334174156468
plt.scatter(L, Average_height, label="Data")
plt.plot(L, correction(L, *popt), 'r-', label="fit")
plt.show()
Output

curve_fit TypeError: Improper input: N=2 must not exceed M=1

I'm trying to fit a sine curve to data I imported from a .mat file.
from scipy.io import loadmat
data=loadmat('TP4.mat')
x_data=data['x']
y_data=data['y']
def TEST(x,a,b):
return (a*np.sin(b*x))
params2,params_covariance2=optimize.curve_fit(TEST,x_data,y_data)
I've been searching why for an hour now, but it returns me the error :
params2,params_covariance2=optimize.curve_fit(TEST,x_data,y_data)
File "D:\python\lib\site-packages\scipy\optimize\minpack.py", line 784, in curve_fit
res = leastsq(func, p0, Dfun=jac, full_output=1, **kwargs)
File "D:\python\lib\site-packages\scipy\optimize\minpack.py", line 414, in leastsq
raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m))
TypeError: Improper input: N=2 must not exceed M=1
Does someone have the answer to why it keeps doing that with the curve_fit ?
x_data is a array (1,50) :
[[-5. -4.79591837 -4.59183673 -4.3877551 -4.18367347 -3.97959184
-3.7755102 -3.57142857 -3.36734694 -3.16326531 -2.95918367 -2.75510204
-2.55102041 -2.34693878 -2.14285714 -1.93877551 -1.73469388 -1.53061224
-1.32653061 -1.12244898 -0.91836735 -0.71428571 -0.51020408 -0.30612245
-0.10204082 0.10204082 0.30612245 0.51020408 0.71428571 0.91836735
1.12244898 1.32653061 1.53061224 1.73469388 1.93877551 2.14285714
2.34693878 2.55102041 2.75510204 2.95918367 3.16326531 3.36734694
3.57142857 3.7755102 3.97959184 4.18367347 4.3877551 4.59183673
4.79591837 5. ]]
and y_data is an array (1,50) too :
[[ 1.93850755 3.90748334 0.74775799 3.80239638 3.32772828 2.71107852
2.85786376 2.50109072 2.62484054 0.11701355 -1.34835766 -1.03896612
-1.82007581 -1.49086175 -2.56849896 -4.68713822 -3.15843002 -2.77910422
-2.87940036 1.73778484 0.31566242 1.81945211 2.58367122 3.26765109
1.79831117 3.35824518 4.25703245 0.96006812 1.24266396 0.75338212
-0.70009445 -1.12690812 -1.09354647 -3.46942727 -3.67550846 -4.53297036
-2.55420957 -2.87671367 -2.33624323 -1.37104854 1.36564919 1.61563281
2.46671249 2.6525523 2.4522091 2.96971773 2.56662355 3.35746594
2.03000529 2.81887444]]
Your arrays are in an unexpected shape, so we have to reshape them. Since np.reshape() creates a different view, we have to use np.shape()
from scipy import optimize
import numpy as np
from matplotlib import pyplot as plt
def TEST(x,a,b):
return a*np.sin(b*x)
#random test data
np.random.seed(1234)
n=100
x_data = np.linspace(0, 10, n)
y_data = TEST(x_data, 0.2, -0.4) + np.random.normal(scale=0.01,size=n)
#your data structure
x_data.shape = (1, n)
y_data.shape = (1, n)
#print(x_data)
#print(y_data)
#changing the shape of the data for scipy
#if you remove this block you can reproduce your error message
x_data.shape = (n,)
y_data.shape = (n,)
#print(x_data)
#print(y_data)
params2,params_covariance2=optimize.curve_fit(TEST,x_data,y_data, p0=[0.1, 0.1])
print(params2)
y_fit = TEST(x_data, *params2)
plt.plot(x_data, y_data, label="values")
plt.plot(x_data, y_fit, label="fit")
plt.legend()
plt.show()
Output
[ 0.1992707 -0.40013289]

How to fit data logarithmic in python?

I've been trying to fit some data I have gained from some simulations. From the curve, I guess a logarithmic fit would be ideal. However, the curve comes looking out quite funky. I've also tried higher order polynomials and np.polyfit, but I couldn't get either to work.
Any help would be appreciated!
from scipy.optimize import curve_fit
import numpy as np
import matplotlib.pyplot as plt
xdata=[9.24104360013e-06, 4.72619458107e-06, 4.03957328857e-06, 9.78301182748e-06, 1.36994566431e-05, 1.16294573409e-05, 7.70899546232e-06, 2.72587766232e-06, 2.19089955631e-06, 5.34851640035e-06, 7.84434545123e-06, 7.6524185787e-06, 1.00592536363e-05, 6.08711035578e-07, 4.08259572135e-07, 5.74424798328e-07, 6.20036326494e-07, 4.34755225756e-06, 4.72832211908e-06, 1.25156011417e-06, 1.44996714816e-05, 3.79992166335e-06, 4.45935911838e-06, 6.6307841155e-06, 2.38540191336e-06, 9.4649801666e-07, 9.11518608157e-06, 3.1944675219e-06, 5.32674287313e-06, 1.48463901861e-05, 3.41127723277e-06, 3.40027150288e-06, 3.33064781566e-06, 2.12828505238e-06, 7.22565690506e-06, 7.86527964811e-06, 2.25791582571e-06, 1.94875869207e-05, 1.54712884424e-05, 5.82300791075e-06, 9.5783833758e-06, 1.89519143607e-05, 1.03731970283e-05, 2.53090894753e-05, 9.26047056658e-06, 1.05428610146e-05, 2.89162870493e-05, 4.78624726782e-05, 1.00005855557e-05, 6.88617910928e-05]
ydata=[0.00281616449359, 0.00257023004939, 0.00250030932407, 0.00284317789756, 0.00300158447316, 0.00291690879783, 0.00274898865728, 0.0023625485679, 0.0023018015629, 0.00259860025555, 0.00269155777824, 0.00265941197135, 0.0028073724168, 0.00192920496041, 0.00182900945464, 0.00191452746379, 0.00193227563253, 0.00253266811688, 0.00255961306471, 0.00212426145702, 0.00285906942634, 0.00247877245272, 0.0025348504727, 0.00269881922057, 0.00232270371493, 0.00204672286703, 0.00281306442303, 0.00241938445736, 0.00261083321385, 0.00287440363274, 0.00244324770882, 0.00244364989768, 0.00244593671433, 0.00228714406931, 0.00263301289418, 0.00269385915315, 0.0022968948347, 0.00313898537645, 0.00305650121575, 0.00265291893623, 0.00278748794063, 0.00312801724905, 0.00289450806538, 0.00313176225397, 0.00284010926578, 0.0028957865422, 0.00335438183977, 0.00360421739757, 0.00270734995952, 0.00377301191882]
plt.plot(xdata,ydata,'o')
x = np.array(xdata, dtype=float) #transform your data in a numpy array of floats
y = np.array(ydata, dtype=float) #so the curve_fit can work
#def func(x,a,b,c):
# return a*x**2+ b*x +c
def func(x,a,b):
return a*np.log(x)+ b
popt, pcov = curve_fit(func, x, y)
plt.plot(x, func(x, *popt), label="Fitted Curve")
plt.show()
Sort x before plotting
x_sorted = np.sort(x)
plt.plot(x_sorted, func(x_sorted, *popt), label="Fitted Curve")
plt.show()

Computing second partial derivatives in tensorflow

I'm approximating a 2D function using a neural network. I've managed to get the approximation working, but now I need to compute the first and second order partial derivatives (du/dx, du/dy, du^2/dx^2, and du^2/dy^2) for my loss function for this particular application. I'm doing it like this:
def train_neural_network_batch(x_ph, predict=False):
prediction = neural_network_model(x_ph)
pred_dx = tf.gradients(prediction, x1_ph)
pred_dx2 = tf.gradients(tf.gradients(prediction, x1_ph), x1_ph)
pred_dy = tf.gradients(prediction, x2_ph)
pred_dy2 = tf.gradients(tf.gradients(prediction, x2_ph), x2_ph)
Assuming N training points, x_ph is shape (N**2,2) (it is the 2D input to the function), and x1_ph and x2_ph just contain the columns of x_ph, respectively. The lines that are supposed to compute the second derivatives throw errors:
File "/usr/local/lib/python3.6/site-packages/tensorflow/python/ops/gradients_impl.py", line 630, in gradients
gate_gradients, aggregation_method, stop_gradients)
File "/usr/local/lib/python3.6/site-packages/tensorflow/python/ops/gradients_impl.py", line 683, in _GradientsHelper
gradient_uid)
File "/usr/local/lib/python3.6/site-packages/tensorflow/python/ops/gradients_impl.py", line 239, in _DefaultGradYs
with _maybe_colocate_with(y.op, gradient_uid, colocate_gradients_with_ops):
AttributeError: 'NoneType' object has no attribute 'op'
The code works fine when I have a 1D function and compute the second derivatives like above FWIW. I'm assuming there's something obvious I'm missing about the data structures in the neural network that is causing the error. Anyone knows what's wrong? The following MWE works just fine btw:
# Load Modules
import tensorflow as tf
import numpy as np
import math, random
import matplotlib.pyplot as plt
from pylab import meshgrid,cm,imshow,contour,clabel,colorbar,axis,title,show
from mpl_toolkits.mplot3d import Axes3D
# Create the arrays x and y that contains the inputs and the outputs of the function to approximate
N = 40
a = 0.0;
b = 2.0*np.pi;
xin = np.arange(a, b, (b-a)/N).reshape((N,1))
yin = np.arange(a, b, (b-a)/N).reshape((N,1))
X_tmp,Y_tmp = meshgrid(xin,yin)
X = np.reshape(X_tmp,(N**2,1))
Y = np.reshape(Y_tmp,(N**2,1))
# This is the exact second partial of Z = sin(x+y) with respect to x
Zxx = -np.sin(X_tmp+Y_tmp)
# Create the arrays x, y, and z that contains the inputs and the outputs of the function to approximate
x = tf.placeholder('float', [N**2,1])
y = tf.placeholder('float', [N**2,1])
z = tf.sin(x+y)
var_grad = tf.gradients(tf.gradients(z,x), x)
with tf.Session() as session:
var_grad_val = session.run(var_grad,feed_dict={x:X, y:Y})
grad1 = np.reshape(var_grad_val,(N,N))
fig = plt.figure()
ax = Axes3D(plt.gcf())
surf = ax.plot_surface(X1, X2, grad1, cmap=cm.coolwarm)
plt.show()
fig = plt.figure()
ax = Axes3D(plt.gcf())
surf = ax.plot_surface(X1, X2, abs(grad1-Zxx), cmap=cm.coolwarm)
plt.show()

morse potential fit using python and curve fit from scipy

I am trying to fit a morse potential using a python and scipy.
The morse potential is defined as:
V = D*(exp(-2*m*(x-u)) - 2*exp(-m*(x-u)))
where D, m and u are the parameters I need to extract.
Unfortunately the fit is not satisfactory as you can see below (sorry I do not have 10 reputation so the image has to be clicked). Could anyone help me please? I must say I am not the best programmer with python.
Here is my code:
from scipy.optimize import curve_fit
import numpy as np
import matplotlib.pyplot as plt
xdata2=np.array([1.0 ,1.1 ,1.2 ,1.3 ,1.4 ,1.5 ,1.6 ,1.7 ,1.8 ,1.9 ,2.0 ,2.1 ,2.2 ,2.3 ,2.4 ,2.5 ,2.6 ,2.7 ,2.8 ,2.9 ,3.0 ,3.1 ,3.2 ,3.3 ,3.4 ,3.5 ,3.6 ,3.7 ,3.8 ,3.9 ,4.0 ,4.1 ,4.2 ,4.3 ,4.4 ,4.5 ,4.6 ,4.7 ,4.8 ,4.9 ,5.0 ,5.1 ,5.2 ,5.3 ,5.4 ,5.5 ,5.6 ,5.7 ,5.8 ,5.9])
ydata2=[-1360.121815,-1368.532641,-1374.215047,-1378.090480,-1380.648178,-1382.223113,-1383.091562,-1383.479384,-1383.558087,-1383.445803,-1383.220380,-1382.931531,-1382.609269,-1382.273574,-1381.940879,-1381.621299,-1381.319042,-1381.036231,-1380.772039,-1380.527051,-1380.301961,-1380.096257,-1379.907700,-1379.734621,-1379.575837,-1379.430693,-1379.299282,-1379.181303,-1379.077272,-1378.985220,-1378.903626,-1378.831588,-1378.768880,-1378.715015,-1378.668910,-1378.629996,-1378.597943,-1378.572742,-1378.554547,-1378.543296,-1378.539843,-1378.543593,-1378.554519,-1378.572747,-1378.597945,-1378.630024,-1378.668911,-1378.715015,-1378.768915,-1378.831593]
t=np.linspace(0.1,7)
def morse(q, m, u, x ):
return (q * (np.exp(-2*m*(x-u))-2*np.exp(-m*(x-u))))
popt, pcov = curve_fit(morse, xdata2, ydata2, maxfev=40000000)
yfit = morse(t,popt[0], popt[1], popt[2])
print popt
plt.plot(xdata2, ydata2,"ro")
plt.plot(t, yfit)
plt.show()
Old fit before gboffi's comment
I am guessing the exact depth of the morse potential does not interest you overly much. So I added an additional parameter to shift the morse potential up and down (v), includes #gboffis comment. Furthermore, the first argument of your function must be the arguments, not the parameters you want to fit (see http://docs.scipy.org/doc/scipy-0.16.1/reference/generated/scipy.optimize.curve_fit.html)
In addition, such fits are dependent on your starting position. The following should give you what you want.
from scipy.optimize import curve_fit
import numpy as np
import matplotlib.pyplot as plt
xdata2=np.array([1.0 ,1.1 ,1.2 ,1.3 ,1.4 ,1.5 ,1.6 ,1.7 ,1.8 ,1.9 ,2.0 ,2.1 ,2.2 ,2.3 ,2.4 ,2.5 ,2.6 ,2.7 ,2.8 ,2.9 ,3.0 ,3.1 ,3.2 ,3.3 ,3.4 ,3.5 ,3.6 ,3.7 ,3.8 ,3.9 ,4.0 ,4.1 ,4.2 ,4.3 ,4.4 ,4.5 ,4.6 ,4.7 ,4.8 ,4.9 ,5.0 ,5.1 ,5.2 ,5.3 ,5.4 ,5.5 ,5.6 ,5.7 ,5.8 ,5.9])
ydata2=[-1360.121815,-1368.532641,-1374.215047,-1378.090480,-1380.648178,-1382.223113,-1383.091562,-1383.479384,-1383.558087,-1383.445803,-1383.220380,-1382.931531,-1382.609269,-1382.273574,-1381.940879,-1381.621299,-1381.319042,-1381.036231,-1380.772039,-1380.527051,-1380.301961,-1380.096257,-1379.907700,-1379.734621,-1379.575837,-1379.430693,-1379.299282,-1379.181303,-1379.077272,-1378.985220,-1378.903626,-1378.831588,-1378.768880,-1378.715015,-1378.668910,-1378.629996,-1378.597943,-1378.572742,-1378.554547,-1378.543296,-1378.539843,-1378.543593,-1378.554519,-1378.572747,-1378.597945,-1378.630024,-1378.668911,-1378.715015,-1378.768915,-1378.831593]
t=np.linspace(0.1,7)
tstart = [1.e+3, 1, 3, 0]
def morse(x, q, m, u , v):
return (q * (np.exp(-2*m*(x-u))-2*np.exp(-m*(x-u))) + v)
popt, pcov = curve_fit(morse, xdata2, ydata2, p0 = tstart, maxfev=40000000)
print popt # [ 5.10155662 1.43329962 1.7991549 -1378.53461345]
yfit = morse(t,popt[0], popt[1], popt[2], popt[3])
#print popt
#
#
#
plt.plot(xdata2, ydata2,"ro")
plt.plot(t, yfit)
plt.show()

Categories