<jupyter_start><jupyter_text>Equation Fitting with Different Error Minimization Engines <NAME>, 2019 This Python notebook is divided into two sections. The first one will briefly execute the fitting of an equation using a simple minimization function, while the second second will show the power of equation fitting using a **global** minimization function, which may sometimes be necessary for equations which have more than a handful of undetermined coefficients. scripts shown:* minfit.py* basinhopfit.py  Simple minimization (python optimize.minimize) The script for this example is **minfit.py**. The first thing we do is load our experimental data for the fit:<jupyter_code>'''LOAD EXPERIMENTAL DATA'''
import xlwings as xw

'CHANGE TO PATH OF EXCEL FILE WITH DATA'
path = r'C:\Users\garci\Dropbox (Personal)\scripts\statistics\templates-examples\minfit_template.xlsx'
book = xw.Book(path)

sheet='Sheet1'

from frame_pdsfit import lastRow

x=book.sheets[sheet].range('A2:A'+str(lastRow(sheet,book))).value
exps=book.sheets[sheet].range('B2:B'+str(lastRow(sheet,book))).value
print('experimental data \nx\n{}\ny\n{}'.format(x,exps))<jupyter_output>experimental data 
x
[-50.0, -40.90909091, -31.818181820000003, -22.727272730000003, -13.636363640000003, -4.545454550000002, 4.545454539999998, 13.636363629999998, 22.72727272, 31.81818181, 40.909090899999995, 49.99999998999999]
y
[162.0, 120.0, 100.0, 70.0, 80.0, 30.0, 50.0, 20.0, 60.0, 90.0, 130.0, 170.0]<jupyter_text>The next two code blocks that follow are the equation eqn() with the parameters to be fitted and the error minimization function to be minimized E() also known as the objective function. eqn() should be changed to the equation which you want to fit your data:<jupyter_code>def eqn(x,pars):
    
    C1,C2 = pars
    
    return C1*x**2 + C2

def E(pars):
    
    C1,C2= pars
    
    
    SUM = 0
    i=0
    while i < len(x):        
        SUM += ( eqn(x[i],pars)- exps[i] )**2 
#        SUM += (  ( eqn(x[i],pars)- exps[i] ) / exps[i]  )**2 

        i+=1
        
    return SUM<jupyter_output><empty_output><jupyter_text>The next code block is the engine used to minimize E(), which is Python's optimize.minimize. It also plots the data:<jupyter_code>def make():
        
    initial_guess = [-1, -1]
    result = optimize.minimize(E, initial_guess)
    
    print(result.x)
    x_theory=np.linspace(min(x),max(x),100)
    
    fit = eqn(x_theory,result.x)
    
    plt.figure()
    
    plt.plot(x,exps,'o',label='data')
    plt.text(0,1,'$s$')
    plt.plot(x_theory,fit,label='fit')
    plt.legend()<jupyter_output><empty_output><jupyter_text>The way I've written these scripts, execution is as easy as writing make()<jupyter_code>from minfit import *
make()<jupyter_output>fitted coefficients 
 [ 0.050739   40.19642886]<jupyter_text>Global minimization (python optimize.basinhopping) This walkthrough shows the implementation of the basinhopping minimization algorithm to an example which aims to find 7 coefficients of a 2-D Bessel function **basinhopfit.py**. As I've already run through the basic workings of the error minimization algorithm with the objective function, I will only execute the code and compare it with different amounts of data. First thing we do is we load our experimental data x's and y values. I have 'made' experimental data by randomly selecting points for the two variables x_1 and x_2 and compute them with *known* coefficients to generate the y experimental data. The known coefficients were also chosen arbitrarily, though their values will help us validate the fit; if the fitted values approach those of these coefficients, the fit works well. The template can be found in the statistics repository as basinhop_TEMPLATE.xlsx. *I encourage you to load by editing your directory on the script and not the terminal, as this makes it less messy<jupyter_code>import xlwings as xw
from basinhopfit import lastRow

path = r'C:\Users\garci\Dropbox (Personal)\scripts\statistics\templates-examples\basinhop_TEMPLATE.xlsx'
book = xw.Book(path)

sheet='Sheet1'
x1=book.sheets[sheet].range('A2:A'+str(lastRow(sheet,book))).value
x2=book.sheets[sheet].range('B2:B'+str(lastRow(sheet,book))).value
y_exps=book.sheets[sheet].range('C2:C'+str(lastRow(sheet,book))).value
print('experimental data:\ny\n{}\nx1\n{}\nx2\n{}'.format(y_exps,x1,x2))
print('number of experiments ',len(x1))

sheet='datagen'
kcoeffs = book.sheets[sheet].range('G2:G8').value
print('\n\nknown coefficients\n',kcoeffs)<jupyter_output>experimental data:
y
[1.5420983334460192, 1.322517601589812, 2.8800050453741237, 0.7070118569651526, 2.6297158782831067, -1.9500865454495924, 3.361357804871006, 2.2944251474891573, 2.234681196172063, 3.0264349658365575, 1.8736986124182584, -1.6344396691666914, 0.011562554271287162, 3.103083892441026]
x1
[0.09306632195825111, -0.26486491520959166, -0.23408672044747383, 0.1757720551500661, 0.08075438690732997, 0.024784521957015, 0.33763941560074645, 0.1893220072238694, -0.5201231046551272, -0.16803078966217075, 0.3546412829724228, -0.2145817375506121, 0.8991176227186377, 0.27191783806172504]
x2
[-0.3586287449160476, -0.36644726669400135, 0.18941665999286872, -0.9587716531070688, -0.24792717197939462, -0.5758362141136594, -0.06708774700848362, -0.28692329403196765, 0.3133613646742223, 0.013945444798898391, 0.33183476538310097, 0.5779268382801096, 0.8325501099509018, 0.11909433434099065]
number of experiments  14


known coefficients
 [1.0, 4.0, 4.0, 10.0, 2.0, 10.0, 3.0]<jupyter_text>This dataset has an equivalent of 14 experiments. The 'datagen' sheet shows how the data was generated and the values of the known coefficients. I've printed these values to validate the algorithm.Then we run the script. *niter* defines the number of basin hop iterations for the global minimization. We'll see how this parameter affects our estimates. Let's start with 1 iteration for this set of 14 experiments.<jupyter_code>from basinhopfit import * 

make(niter=1)<jupyter_output>global minimization results 
 fitted coefficients:
 [ 0.99999999  3.99999997  3.99999997 10.          1.99999995 10.00000002
  2.99999998]<jupyter_text>These fitted coefficients are already in close agreement with the known coefficients printed above. For our dataset of 14 experiments, 1 iteration is good enough to make a good estimate on the model. Let's try 100 iterations<jupyter_code>from basinhopfit import * 

make(100)<jupyter_output>global minimization results 
 fitted coefficients:
 [ 0.99999998  4.00000001  3.99999999 10.00000001  1.99999999  9.99999997
  3.00000001]<jupyter_text>The fitted coefficients are now even closer to the real values within a 7 floating point difference. 100 iterations thus give us significantly more accurate estimates, though the computational time is compromised. In here, it may matter how precise and accurate you want to be at the expense of time. Just for fun let's try a dataset of 224 experiments with niter=1. For this let's load the data from the 'datagen' sheet:<jupyter_code>sheet='datagen'
x1=book.sheets[sheet].range('A2:A'+str(lastRow(sheet,book))).value
x2=book.sheets[sheet].range('B2:B'+str(lastRow(sheet,book))).value
y_exps=book.sheets[sheet].range('C2:C'+str(lastRow(sheet,book))).value
#print('experimental data:\ny\n{}\nx1\n{}\nx2\n{}'.format(y_exps,x1,x2))
print('number of experiments ',len(x1))

kcoeffs = book.sheets[sheet].range('G2:G8').value
print('\n\nknown coefficients\n',kcoeffs)
from basinhopfit import * 

make(1)<jupyter_output>global minimization results 
 fitted coefficients:
 [ 0.99999999  3.99999997  3.99999998  9.99999999  1.99999995 10.00000001
  3.        ]
{'fraction_non_alphanumeric': 0.105655930871956, 'fraction_numerical': 0.16064414768263943, 'mean_word_length': 5.09170653907496, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 21, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '318784', 'license': 'Apache-2.0', 'n_tokens_mistral': 3389, 'n_tokens_neox': 2564, 'n_words': 753, 'path': 'minimization-fitting.ipynb', 'repo_name': 'andrewrgarcia/statistics', 'size': '7645'}