1

I am new to Python and I am trying to use a small data frame and plot it. But I also want to use curve_fit in order to get the values of some parameter.

######Fitting Using Data Frame######

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit

#   Data into a dictionary
data = {'keV':[22.16,32.19,8.05,17.48,13.39,44.47,5],'ToT':[31.68,39.87,10.67,26.38,21.4,53.56,0]}

#   Create dataframe and get only the values of arrays
df = pd.DataFrame(data)
xdata = df['keV'].values
ydata = df['ToT'].values

#   Main function for the mathematical method
def main_test(x, a, b,c,t):
    return a*x +b - c/(x-t)

#   Guess of the fit values
guess = [1,1,100,150]

n = len(xdata)
#   Empty np array that will get these values
y = np.empty(n)
#   Repeat in all these times

c, cov = curve_fit(main_test,xdata,ydata)
#    THE MOST IMPORTANT PART OF THE CODE. TO GET THE PARAMETERS VALUES.
print(c)

for sample in range(n):
#   Populating y with guess numbers = Prediction
   y[sample] = main_test(xdata[sample],a[0],b[1],c[2],t[3])

    plt.figure(figsize=(6,4))
    plt.scatter(xdata,ydata)
    plt.plot(xdata, y,'r.')
    plt.show()

RuntimeError: Optimal parameters not found: Number of calls to function has reached maxfev = 1000.

2
  • Try increasing the maxfev parameter? Commented Jul 4, 2019 at 6:48
  • @ItamarMushkin this was starting parameters, please see my answer to this question. Commented Jul 4, 2019 at 12:54

1 Answer 1

1

This was a matter of finding good starting parameters. Here is a graphical solver using your data and equation, with scipy's differential_evolution genetic algorithm module used to determine initial parameter estimates for curve_fit(). That scipy module uses the Latin Hypercube algorithm to ensure a thorough search of parameter space, requiring bounds within which to search. As the search bounds can be generous, I first tried search bounds of +/- 100.0 for all of the parameters and that worked.

plot

import numpy, scipy, matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy.optimize import differential_evolution
import warnings

keV = [22.16,32.19,8.05,17.48,13.39,44.47,5]
ToT = [31.68,39.87,10.67,26.38,21.4,53.56,0]

# rename data to re-use previous example code
xData = numpy.array(keV)
yData = numpy.array(ToT)


# mathematical model
def func(x, a, b,c,t):
    return a*x +b - c/(x-t)


# function for genetic algorithm to minimize (sum of squared error)
def sumOfSquaredError(parameterTuple):
    warnings.filterwarnings("ignore") # do not print warnings by genetic algorithm
    val = func(xData, *parameterTuple)
    return numpy.sum((yData - val) ** 2.0)


def generate_Initial_Parameters():    
    parameterBounds = []
    parameterBounds.append([-100.0, 100.0]) # search bounds for a
    parameterBounds.append([-100.0, 100.0]) # search bounds for b
    parameterBounds.append([-100.0, 100.0]) # search bounds for c
    parameterBounds.append([-100.0, 100.0]) # search bounds for t

    # "seed" the numpy random number generator for repeatable results
    result = differential_evolution(sumOfSquaredError, parameterBounds, seed=3)
    return result.x

# by default, differential_evolution completes by calling curve_fit() using parameter bounds
geneticParameters = generate_Initial_Parameters()

# now call curve_fit without passing bounds from the genetic algorithm,
# just in case the best fit parameters are aoutside those bounds
fittedParameters, pcov = curve_fit(func, xData, yData, geneticParameters)
print('Fitted parameters:', fittedParameters)
print()

modelPredictions = func(xData, *fittedParameters) 

absError = modelPredictions - yData

SE = numpy.square(absError) # squared errors
MSE = numpy.mean(SE) # mean squared errors
RMSE = numpy.sqrt(MSE) # Root Mean Squared Error, RMSE
Rsquared = 1.0 - (numpy.var(absError) / numpy.var(yData))

print()
print('RMSE:', RMSE)
print('R-squared:', Rsquared)

print()


##########################################################
# graphics output section
def ModelAndScatterPlot(graphWidth, graphHeight):
    f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
    axes = f.add_subplot(111)

    # first the raw data as a scatter plot
    axes.plot(xData, yData,  'D')

    # create data for the fitted equation plot
    xModel = numpy.linspace(min(xData), max(xData))
    yModel = func(xModel, *fittedParameters)

    # now the model as a line plot
    axes.plot(xModel, yModel)

    axes.set_xlabel('keV') # X axis data label
    axes.set_ylabel('ToT') # Y axis data label

    plt.show()
    plt.close('all') # clean up after using pyplot

graphWidth = 800
graphHeight = 600
ModelAndScatterPlot(graphWidth, graphHeight)
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! It worked really well... Now, I will just 'interpret' and try to understand better your code. Thank you again.
The best possible result is always, "It Worked".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.