Scipy拟合真实指数衰减数据时exp溢出警告的解决及模型适配问题
Hey there! Let's work through your problem together.
First: Is your model function a good fit for the data?
Absolutely! The dataset you shared clearly shows an exponential decay trend—starting high and tapering off to a steady baseline value. Your A*exp(-K*x)+C model is perfect for this pattern:
Arepresents the initial amplitude (the difference between the starting value and the baseline)Kis the decay constant (controls how fast the value drops)Cis the asymptotic baseline (the value y approaches as x gets very large)
Why are you seeing the overflow error and bad fit?
The issue comes down to numerical instability and poor initial parameter guesses:
- The default initial guess for
curve_fitis[1,1,1], which is totally mismatched for your data. When the algorithm starts iterating, it might try negative values forK, which turnsexp(-K*x)intoexp(large_positive_number)—that's what causes the overflow warning. - Even with positive
K, your x-values go up to ~5000 (and eventually 1e6), soexp(-K*x)can become extremely small or large ifKisn't scaled properly, throwing off the fitting process.
Fixes to get a good fit
Here's how to adjust your code to get accurate parameters:
1. Estimate reasonable initial parameters
Instead of letting curve_fit guess blindly, calculate initial values based on your data:
C: Take the minimum value of y (your baseline), which is ~30 for your test data.A: Subtract the baseline from the maximum y-value:3630 - 30 = 3600.K: Estimate using a midpoint in your data. For example, at x=100, y=851:851 ≈ 3600*exp(-K*100) + 30- Solve for K:
K ≈ -ln((851-30)/3600)/100 ≈ 0.0148
2. Updated code with initial guesses
# -*- coding: utf-8 -*- import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit x = np.array([ 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., 256., 289., 324., 361., 400., 441., 484., 529., 576., 625., 676., 729., 784., 841., 900., 961., 1024., 1089., 1156., 1225., 1296., 1369., 1444., 1521., 1600., 1681., 1764., 1849., 1936., 2025., 2116., 2209., 2304., 2401., 2500., 2601., 2704., 2809., 2916., 3025., 3136., 3249., 3364., 3481., 3600., 3721., 3844., 3969., 4096., 4225., 4356., 4489., 4624., 4761., 4943.]) y = np.array([3630., 2590., 2063., 1726., 1484., 1301., 1155., 1036., 936., 851., 778., 714., 657., 607., 562., 521., 485., 451., 421., 390., 362., 336., 312., 293., 279., 265., 253., 241., 230., 219., 209., 195., 183., 171., 160., 150., 142., 134., 127., 120., 114., 108., 102., 97., 91., 87., 83., 80., 76., 73., 70., 67., 64., 61., 59., 56., 54., 51., 49., 47., 45., 43., 41., 40., 38., 36., 35., 33., 31., 30.]) def model_func(x, A, K, C): return A * np.exp(-K * x) + C # Calculate initial guesses based on data initial_C = np.min(y) initial_A = np.max(y) - initial_C # Estimate K using x=100 as a reference point log_term = np.log((851 - initial_C)/initial_A) initial_K = -log_term / 100 initial_guess = [initial_A, initial_K, initial_C] # Fit with initial guess (increase maxfev if needed) opt_parms, parm_cov = curve_fit(model_func, x, y, p0=initial_guess, maxfev=10000) A, K, C = opt_parms # Generate fitted values fit_y = model_func(x, A, K, C) # Visualize results plt.clf() plt.title('Decay Data & Fitted Curve') plt.plot(x, y, 'r.', label='Actual Data') plt.plot(x, fit_y, 'b-', label='Fitted Function:\n $y = %0.2f e^{-%0.6f x} + %0.2f$' % (A, K, C)) plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left', fancybox=True, shadow=True) plt.xlabel('x') plt.ylabel('y') plt.tight_layout() plt.show() # Example: Apply to new data new_x = np.array([5000, 6000, 7000]) new_y_pred = model_func(new_x, A, K, C) print("Predicted values for new x:", new_y_pred)
3. For datasets with x up to 1e6: Scale your x-values
When x gets as large as 1,000,000, even small K values can make exp(-K*x) underflow or cause numerical issues. Fix this by scaling x (e.g., divide by 1000):
# Scale x to a smaller range x_scaled = x / 1000 # Adjust model to use scaled x def model_func_scaled(x_scaled, A, K, C): return A * np.exp(-K * x_scaled) + C # Adjust initial guess for K (multiply by 1000 to match scaling) initial_guess_scaled = [initial_A, initial_K * 1000, initial_C] # Fit scaled data opt_parms_scaled, _ = curve_fit(model_func_scaled, x_scaled, y, p0=initial_guess_scaled) # Predict new data (remember to scale new x too!) new_x = np.array([100000, 500000, 1000000]) new_x_scaled = new_x / 1000 new_y_pred = model_func_scaled(new_x_scaled, *opt_parms_scaled)
Final Notes
- The model you chose is absolutely correct for your exponential decay data.
- Always provide reasonable initial guesses for
curve_fit—it drastically improves fitting accuracy and stability. - For large x ranges, scaling is a simple way to avoid numerical overflow/underflow issues.
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

