Ajuster deux équations distinctes à une fonction (curve_fit)

Nov 23 2020

J'ai un problème: j'ai deux équations distinctes, l'une est une équation linéaire, l'autre est une équation exponentielle. Cependant, les deux équations ne doivent pas être valides en même temps, ce qui signifie qu'il existe deux régimes distincts.

Equation 1 (x < a): E*x
Equation 2 (x >=a): a+b*x+c*(1-np.exp(-d*np.array(x)))

Cela signifie que la première partie des données doit simplement être ajustée avec une équation linéaire et le reste doit être ajusté avec l'équation 2 mentionnée ci-dessus.

Les données que j'essaie d'adapter ressemblent à ceci (j'ai également ajouté des exemples de données, si les gens veulent essayer):

J'ai déjà essayé plusieurs choses, en définissant simplement une fonction d'ajustement avec une fonction heaviside:

def fit_fun(x,a,b,c,d,E):
    
    funktion1=E*np.array(x)
    
    funktion2=a+b*x+c*(1-np.exp(-d*np.array(x)))
           
    return np.heaviside(x+a,0)*funktion2+(1-np.heaviside(x+a,0))*funktion1

définir une fonction par morceaux:

def fit_fun(x,a,b,c,d,E):
    return np.piecewise(x, [x <= a, x > a], [lambda x: E*np.array(x), lambda x: a+b*x+c*(1-np.exp(-d*np.array(x)))])

pour enfin (ce qui me rapporte une erreur de fonction de formulaire?):

def plast_fun(x,a,b,c,d,E):
   
    out = E*x
    out [np.where(x >= a)] = a+b*x+c*(1-np.exp(-d+x))
    
    return out

Ne vous méprenez pas, j'obtiens «quelques» ajustements, mais ils semblent prendre l'une ou l'autre équation et ne pas utiliser les deux. J'ai également essayé d'utiliser plusieurs limites et suppositions initiales, mais cela ne change jamais.

Toute contribution serait vivement appréciée!

Données:

0.000000     -1.570670 
0.000434     83.292677 
0.000867     108.909402 
0.001301     124.121676 
0.001734     138.187659 
0.002168     151.278839 
0.002601     163.160478 
0.003035     174.255626 
0.003468     185.035092 
0.003902     195.629820 
0.004336     205.887161 
0.004769     215.611995 
0.005203     224.752083 
0.005636     233.436680 
0.006070     241.897851 
0.006503     250.352697 
0.006937     258.915168 
0.007370     267.569337 
0.007804     276.199005 
0.008237     284.646778 
0.008671     292.772349 
0.009105     300.489611 
0.009538     307.776858 
0.009972     314.666291 
0.010405     321.224211 
0.010839     327.531594 
0.011272     333.669261 
0.011706     339.706420 
0.012139     345.689265 
0.012573     351.628362 
0.013007     357.488150 
0.013440     363.185771 
0.013874     368.606298 
0.014307     373.635696 
0.014741     378.203192 
0.015174     382.315634 
0.015608     386.064126 
0.016041     389.592120 
0.016475     393.033854 
0.016908     396.454226 
0.017342     399.831519 
0.017776     403.107084 
0.018209     406.277016 
0.018643     409.441119 
0.019076     412.710982 
0.019510     415.987331 
0.019943     418.873140 
0.020377     421.178098 
0.020810     423.756827 

Jusqu'à présent, j'ai trouvé ces deux questions, mais je ne pouvais pas les comprendre: Ajustement de deux fonctions différentes avec boarder comme paramètre d'ajustement Ajuster une courbe pour les données constituées de deux régimes distincts

Réponses

2 FlavioMoraes Nov 23 2020 at 23:35

Je soupçonne que vous faites une erreur dans la deuxième équation, là où vous le faites a+b*x+c*(1-np.exp(-d+x)). où aest la valeur de l' xendroit où vous passez d'une courbe à l'autre. Je pense que vous devriez utiliser yplutôt la valeur de ce qui est a*E. Il est également très important de définir les paramètres initiaux de l'ajustement. J'ai exécuté le code suivant avec vos données dans un fichier .txt et l'ajustement semble assez bon comme vous pouvez le voir ci-dessous:

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

def fit_fun(x,a,b,c,d,E):
    return np.piecewise(x, [x <= a, x > a], [lambda x: E*x, lambda x: a*E+b*x+c*(1-np.exp(-d*x))])

df = pd.read_csv('teste.txt', delimiter='\s+', header=None)
df.columns = ['x','y']

xdata = df['x']
ydata = df['y']

p0 = [0.001,1,1,1,100000]
popt, pcov = optimize.curve_fit(fit_fun, xdata.values, ydata.values, p0=p0, maxfev=10000, absolute_sigma=True, method='trf')
print(popt)

plt.plot(xdata, ydata,'*')
plt.plot(xdata, fit_fun(xdata.values, *popt), 'r')
plt.show()