如何为 Scipy.optimize curve_fit 修复 "OptimizeWarning: Covariance of the parameters could not be estimated"?
How to fix the "OptimizeWarning: Covariance of the parameters could not be estimated" for Scipy.optimize curve_fit?
我试图使用 curve_fit 函数将曲线拟合到我设计的点。但是,我收到了警告消息,而不是 curve_fit 函数输出的数据。请在下面找到随附的屏幕截图。
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import numpy as np
#Fitting function
def func(x, a, b):
print("x: "+str(x))
print("b: "+str(b))
#return a*np.exp(b*x)
#return a*x+b
return a*x/(b+x)
#Experimental x and y data points
xData = np.array([ 31875.324,31876.35,31877.651,31878.859,31879.771,31880.657,31881.617,31882.343, \
31883.099,31883.758,31884.489,31885.311,31886.084,31886.736,31887.582,31888.262, \
31888.908,31889.627,31890.312,31890.989,31891.534,31892.142,31892.759,31893.323, \
31893.812,31894.397,31894.928,31895.555,31896.211,31896.797,31898.16,31898.761, \
31899.462,31900.099,31900.609,31901.197,31901.815,31902.32,31902.755,31903.235, \
31903.698,31904.232,31904.776,31905.291,31905.806,31906.182,31906.533,31906.843, \
31907.083,31907.175,31822.221,31833.14,31846.066,31860.254,31875.324], dtype=np.longdouble)
yData = np.array([ 7999.026,7999.483,8000.048,8000.559,8000.937,8001.298,8001.683,8001.969,8002.263, \
8002.516,8002.793,8003.101,8003.387,8003.625,8003.931,8004.174,8004.403,8004.655, \
8004.892,8005.125,8005.311,8005.517,8005.725,8005.913,8006.076,8006.269,8006.443, \
8006.648,8006.861,8007.05,8007.486,8007.677,8007.899,8008.1,8008.259,8008.443, \
8008.636,8008.793,8008.929,8009.077,8009.221,8009.386,8009.554,8009.713,8009.871, \
8009.987,8010.095,8010.19,8010.264,8010.293,7956.451,7969.307,7981.115,7991.074,7999.026], dtype=np.longdouble)
#Plot experimental data points
plt.plot(xData, yData, 'bo', label='experimental-data')
# Initial guess for the parameters
initialGuess = [31880.0,8000.0]
#Perform the curve-fit
popt, pcov = curve_fit(func, xData, yData, initialGuess)
print("popt"+str(popt))
#x values for the fitted function
xFit = np.arange(0.0, 50.0, 0.001, dtype=np.longdouble)
print("xFit"+str(xFit))
#Plot the fitted function
plt.plot(xFit, func(xFit, *popt), 'r', label='fit params: a=%5.3f, b=%5.3f' % tuple(popt))
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
The screeshot for the warning message.
The plot for the result.
试试这个合身,效果不错。原始函数不会真正适合数据。对于大 x
,它会收敛到 a
。没关系。一个下降到较小的 x
但前提是 b
为正。此外,缺少一个缩放 drop-rate 的参数。因此,使用 a<0
和 b<0
可以得到正确的形状,但会收敛到一个负数。即缺少偏移量。因此使用 y = a + b / ( x + c )
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy.integrate import cumtrapz
import numpy as np
#Fitting function
def func( x, a, b, c ):
return a + b / ( x + c )
#Experimental x and y data points
xData = np.array([
31875.324, 31876.35, 31877.651, 31878.859, 31879.771, 31880.657,
31881.617, 31882.343, 31883.099, 31883.758, 31884.489, 31885.311,
31886.084, 31886.736, 31887.582, 31888.262, 31888.908, 31889.627,
31890.312, 31890.989, 31891.534, 31892.142, 31892.759, 31893.323,
31893.812, 31894.397, 31894.928, 31895.555, 31896.211, 31896.797,
31898.16, 31898.761, 31899.462, 31900.099, 31900.609, 31901.197,
31901.815, 31902.32, 31902.755, 31903.235, 31903.698, 31904.232,
31904.776, 31905.291, 31905.806, 31906.182, 31906.533, 31906.843,
31907.083, 31907.175, 31822.221, 31833.14, 31846.066, 31860.254,
31875.324
], dtype=float )
yData = np.array([
7999.026, 7999.483, 8000.048, 8000.559, 8000.937, 8001.298,
8001.683, 8001.969, 8002.263, 8002.516, 8002.793, 8003.101,
8003.387, 8003.625, 8003.931, 8004.174, 8004.403, 8004.655,
8004.892, 8005.125, 8005.311, 8005.517, 8005.725, 8005.913,
8006.076, 8006.269, 8006.443, 8006.648, 8006.861, 8007.05,
8007.486, 8007.677, 8007.899, 8008.1, 8008.259, 8008.443,
8008.636, 8008.793, 8008.929, 8009.077, 8009.221, 8009.386,
8009.554, 8009.713, 8009.871, 8009.987, 8010.095, 8010.19,
8010.264, 8010.293, 7956.451, 7969.307, 7981.115, 7991.074,
7999.026
], dtype=float )
#x values for the fitted function
xFit = np.linspace( 31820, 31950, 150 )
### sorting and shifting t get reasonable values
### scaling also would be a good idea, but I skip this part here
mx=np.mean( xData )
my=np.mean( yData )
data = np.column_stack( ( xData - mx , yData - my ) )
data = np.sort( data, axis=0 )
### getting good starting values using the fact that
### int x y = ( b + a c) x + a/2 x^2 - c * ( int y ) + const
### With two simple and fast numerical integrals, hence, we get a good
### guess for a, b, c from a simple linear fit.
Sy = cumtrapz( data[:, 1], data[:, 0], initial = 0 )
Sxy = cumtrapz( data[:, 0] * data[:, 1], data[:, 0], initial = 0 )
ST = np.array([
data[:, 0], data[:, 0]**2, Sy, np.ones( len( data ) )
])
S = np.transpose( ST )
A = np.dot( ST, S )
eta = np.dot( ST, Sxy )
sol = np.linalg.solve( A, eta )
a = 2 * sol[1]
c = -sol[2]
b = sol[0] - a * c
print( "a = {}".format( a ) )
print( "b = {}".format( b ) )
print( "c = {}".format( c ) )
sol, cov = curve_fit( func, xData, yData, p0 = (a + my, b, c - mx) )
print( "linear fit vs non-linear fit:" )
print( a + my, b, c - mx )
print( sol )
fig = plt.figure()
ax = fig.add_subplot( 1, 1, 1 )
ax.plot( xData, yData, ls='', marker ='+', label="data")
ax.plot( xFit, func( xFit, a + my, b, c - mx), ls=':', label="linear guess")
ax.plot( xFit, func( xFit, *sol ), label="non-linear fit" )
ax.legend( loc=0 )
plt.show()
提供
[ 8054 -6613 -31754]
和
我试图使用 curve_fit 函数将曲线拟合到我设计的点。但是,我收到了警告消息,而不是 curve_fit 函数输出的数据。请在下面找到随附的屏幕截图。
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import numpy as np
#Fitting function
def func(x, a, b):
print("x: "+str(x))
print("b: "+str(b))
#return a*np.exp(b*x)
#return a*x+b
return a*x/(b+x)
#Experimental x and y data points
xData = np.array([ 31875.324,31876.35,31877.651,31878.859,31879.771,31880.657,31881.617,31882.343, \
31883.099,31883.758,31884.489,31885.311,31886.084,31886.736,31887.582,31888.262, \
31888.908,31889.627,31890.312,31890.989,31891.534,31892.142,31892.759,31893.323, \
31893.812,31894.397,31894.928,31895.555,31896.211,31896.797,31898.16,31898.761, \
31899.462,31900.099,31900.609,31901.197,31901.815,31902.32,31902.755,31903.235, \
31903.698,31904.232,31904.776,31905.291,31905.806,31906.182,31906.533,31906.843, \
31907.083,31907.175,31822.221,31833.14,31846.066,31860.254,31875.324], dtype=np.longdouble)
yData = np.array([ 7999.026,7999.483,8000.048,8000.559,8000.937,8001.298,8001.683,8001.969,8002.263, \
8002.516,8002.793,8003.101,8003.387,8003.625,8003.931,8004.174,8004.403,8004.655, \
8004.892,8005.125,8005.311,8005.517,8005.725,8005.913,8006.076,8006.269,8006.443, \
8006.648,8006.861,8007.05,8007.486,8007.677,8007.899,8008.1,8008.259,8008.443, \
8008.636,8008.793,8008.929,8009.077,8009.221,8009.386,8009.554,8009.713,8009.871, \
8009.987,8010.095,8010.19,8010.264,8010.293,7956.451,7969.307,7981.115,7991.074,7999.026], dtype=np.longdouble)
#Plot experimental data points
plt.plot(xData, yData, 'bo', label='experimental-data')
# Initial guess for the parameters
initialGuess = [31880.0,8000.0]
#Perform the curve-fit
popt, pcov = curve_fit(func, xData, yData, initialGuess)
print("popt"+str(popt))
#x values for the fitted function
xFit = np.arange(0.0, 50.0, 0.001, dtype=np.longdouble)
print("xFit"+str(xFit))
#Plot the fitted function
plt.plot(xFit, func(xFit, *popt), 'r', label='fit params: a=%5.3f, b=%5.3f' % tuple(popt))
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
The screeshot for the warning message. The plot for the result.
试试这个合身,效果不错。原始函数不会真正适合数据。对于大 x
,它会收敛到 a
。没关系。一个下降到较小的 x
但前提是 b
为正。此外,缺少一个缩放 drop-rate 的参数。因此,使用 a<0
和 b<0
可以得到正确的形状,但会收敛到一个负数。即缺少偏移量。因此使用 y = a + b / ( x + c )
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy.integrate import cumtrapz
import numpy as np
#Fitting function
def func( x, a, b, c ):
return a + b / ( x + c )
#Experimental x and y data points
xData = np.array([
31875.324, 31876.35, 31877.651, 31878.859, 31879.771, 31880.657,
31881.617, 31882.343, 31883.099, 31883.758, 31884.489, 31885.311,
31886.084, 31886.736, 31887.582, 31888.262, 31888.908, 31889.627,
31890.312, 31890.989, 31891.534, 31892.142, 31892.759, 31893.323,
31893.812, 31894.397, 31894.928, 31895.555, 31896.211, 31896.797,
31898.16, 31898.761, 31899.462, 31900.099, 31900.609, 31901.197,
31901.815, 31902.32, 31902.755, 31903.235, 31903.698, 31904.232,
31904.776, 31905.291, 31905.806, 31906.182, 31906.533, 31906.843,
31907.083, 31907.175, 31822.221, 31833.14, 31846.066, 31860.254,
31875.324
], dtype=float )
yData = np.array([
7999.026, 7999.483, 8000.048, 8000.559, 8000.937, 8001.298,
8001.683, 8001.969, 8002.263, 8002.516, 8002.793, 8003.101,
8003.387, 8003.625, 8003.931, 8004.174, 8004.403, 8004.655,
8004.892, 8005.125, 8005.311, 8005.517, 8005.725, 8005.913,
8006.076, 8006.269, 8006.443, 8006.648, 8006.861, 8007.05,
8007.486, 8007.677, 8007.899, 8008.1, 8008.259, 8008.443,
8008.636, 8008.793, 8008.929, 8009.077, 8009.221, 8009.386,
8009.554, 8009.713, 8009.871, 8009.987, 8010.095, 8010.19,
8010.264, 8010.293, 7956.451, 7969.307, 7981.115, 7991.074,
7999.026
], dtype=float )
#x values for the fitted function
xFit = np.linspace( 31820, 31950, 150 )
### sorting and shifting t get reasonable values
### scaling also would be a good idea, but I skip this part here
mx=np.mean( xData )
my=np.mean( yData )
data = np.column_stack( ( xData - mx , yData - my ) )
data = np.sort( data, axis=0 )
### getting good starting values using the fact that
### int x y = ( b + a c) x + a/2 x^2 - c * ( int y ) + const
### With two simple and fast numerical integrals, hence, we get a good
### guess for a, b, c from a simple linear fit.
Sy = cumtrapz( data[:, 1], data[:, 0], initial = 0 )
Sxy = cumtrapz( data[:, 0] * data[:, 1], data[:, 0], initial = 0 )
ST = np.array([
data[:, 0], data[:, 0]**2, Sy, np.ones( len( data ) )
])
S = np.transpose( ST )
A = np.dot( ST, S )
eta = np.dot( ST, Sxy )
sol = np.linalg.solve( A, eta )
a = 2 * sol[1]
c = -sol[2]
b = sol[0] - a * c
print( "a = {}".format( a ) )
print( "b = {}".format( b ) )
print( "c = {}".format( c ) )
sol, cov = curve_fit( func, xData, yData, p0 = (a + my, b, c - mx) )
print( "linear fit vs non-linear fit:" )
print( a + my, b, c - mx )
print( sol )
fig = plt.figure()
ax = fig.add_subplot( 1, 1, 1 )
ax.plot( xData, yData, ls='', marker ='+', label="data")
ax.plot( xFit, func( xFit, a + my, b, c - mx), ls=':', label="linear guess")
ax.plot( xFit, func( xFit, *sol ), label="non-linear fit" )
ax.legend( loc=0 )
plt.show()
提供
[ 8054 -6613 -31754]
和