Python scipy.optimize curve_fit幂律拟合报错:达到maxfev=1000上限
Hey there, let's work through this curve_fit issue you're hitting with your power law model. That maxfev error usually means the optimizer can't lock in on valid parameters—most often because it's starting from bad initial guesses or hitting invalid parameter values during iteration. Let's break down the fixes step by step:
First, let's diagnose the root causes
- No initial parameter guess:
curve_fitdefaults to starting with all parameters set to 1, which is way off for your data. Your x values start at 2.5 and y starts at 52, so the default guesses don't align with your data's scale. - Invalid parameter values during fitting: If
x0ends up being larger than any x value,x - x0becomes negative. Raising that to a non-integer exponent creates complex numbers, which breaks the optimizer. - Model complexity: Your power law has 4 parameters (
amp,ex,x0,y0)—more parameters mean the optimizer needs clearer guidance to converge.
Step-by-Step Fixes
1. Add a reasonable initial guess for parameters
Start with values that make sense for your data:
amp: Start with 1 (since y increases slowly with x)ex: Start with 1 (linear behavior, a safe starting point for an increasing trend)x0: Set to 0, which ensuresx - x0is always positive for your x valuesy0: Set to 50, close to your minimum y value of 52
2. Add bounds to avoid invalid parameter values
Prevent the optimizer from trying values that break your model:
- Ensure
x0is always less than the smallest x value (sox - x0stays positive) - Restrict
y0to a range near your minimum y value - Keep
ampandexpositive since your data is increasing
3. Increase maxfev (only after fixing guesses/bounds)
If the optimizer still can't converge, give it more iterations to work with.
Modified Working Code
import matplotlib.pyplot as plt import numpy as np from scipy.optimize import curve_fit def powerlaw(x, amp, ex, x0, y0): return (amp * np.power((x - x0), ex) + y0) x = np.array([2.5 , 3.51778656, 4.53557312, 4.55335968, 5.57114625, 5.58893281, 5.60671937, 5.62450593, 5.64229249, 8.66007905, 8.67786561, 9.69565217, 9.71343874, 9.7312253 , 10.74901186, 10.76679842, 10.78458498, 11.80237154, 11.8201581 , 11.83794466, 11.85573123, 11.87351779, 12.89130435, 3.5 , 3.48221344, 4.46442688, 4.44664032, 5.42885375, 5.41106719, 6.39328063, 6.37549407, 6.35770751, 6.33992095, 7.32213439, 8.30434783, 9.28656126, 11.2687747 , 11.25098814, 11.23320158, 11.21541502, 11.19762846, 11.1798419 , 12.16205534, 12.14426877, 12.12648221, 13.10869565]) y = np.array([52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74]) # Define initial parameter guess p0 = [1, 1, 0, 50] # Set bounds to avoid invalid values x_min = x.min() bounds = ( [0, 0, -np.inf, 45], # Lower bounds: amp>=0, ex>=0, x0 can be any <x_min, y0>=45 [10, 10, x_min - 0.1, 55] # Upper bounds: amp<=10, ex<=10, x0 <x_min, y0<=55 ) # Run curve_fit with improved settings try: popt, pcov = curve_fit(powerlaw, x, y, p0=p0, bounds=bounds, maxfev=5000) print("Optimal parameters found:", popt) # Plot to verify the fit x_fit = np.linspace(x.min(), x.max(), 100) y_fit = powerlaw(x_fit, *popt) plt.scatter(x, y, label="Raw Data") plt.plot(x_fit, y_fit, 'r-', label="Power Law Fit") plt.xlabel("x") plt.ylabel("y") plt.legend() plt.show() except Exception as e: print(f"Fitting error: {e}")
Extra Tips
If the fit still doesn't look great, consider simplifying your model. Your data shows a roughly linear increase with some overlapping segments—you might try fitting a simpler power law (e.g., remove x0 and y0 by scaling your data: x_scaled = x - x.min(), y_scaled = y - y.min(), then fit amp * x_scaled**ex). This reduces parameter count and makes convergence easier.
内容的提问来源于stack exchange,提问作者NHToledo

