多项式拟合深度指南:从 polyfit() 到 curve_fit()

2025-12-13

不用担心,我会用友好且清晰的简体制中文,结合常见的问题、替代方法和示例代码来为你详细讲解!

numpy.polyfit(x, y, deg) 函数通过最小二乘法来找到一个最佳拟合数据的多项式的系数。

x 你的数据点的 X 坐标数组。

y 你的数据点的 Y 坐标数组。

deg 你想要拟合的多项式的次数(degree)。

当拟合的多项式次数(deg)很高时(比如 deg>10),polyfit 可能会遇到数值不稳定性问题。这会导致拟合结果不准确,甚至出现“龙格现象” (Runge's phenomenon)。

问题表现 拟合曲线在数据点之间出现剧烈震荡,尤其是在边界附近。

根本原因 基础多项式(1,x,x2,…)在高阶时变得近似线性相关。

与其直接增加多项式次数,不如使用正交多项式,例如 切比雪夫多项式,它们在数值上更稳定。

替代方法 使用 numpy.polynomial 模块中的切比雪夫拟合 (chebfit)。这个模块是 NumPy 推荐的替代 polyfit 的方法之一,它在高阶拟合中表现更优。

import numpy as np

import matplotlib.pyplot as plt

# 示例数据(模拟 Runge 现象)

x = np.linspace(-1, 1, 11)

# 龙格函数 f(x) = 1 / (1 + 25*x^2)

y = 1.0 / (1.0 + 25.0 * x**2)

x_new = np.linspace(-1, 1, 100)

deg = 10 # 高阶拟合

# --- 1. 传统 polyfit (可能不稳定) ---

# p_coeffs = np.polyfit(x, y, deg)

# y_poly = np.polyval(p_coeffs, x_new)

# --- 2. 推荐替代方案: 切比雪夫拟合 (数值更稳定) ---

# 使用 numpy.polynomial.chebyshev.chebfit

from numpy.polynomial import Chebyshev as C

c_coeffs = C.fit(x, y, deg)

y_cheb = c_coeffs(x_new)

# 绘图比较

plt.figure(figsize=(10, 5))

plt.plot(x, y, 'o', label='原始数据点')

plt.plot(x_new, y_cheb, 'r-', label=f'Chebyshev 拟合 (Deg={deg})')

# plt.plot(x_new, y_poly, 'b--', label=f'Polyfit 拟合 (Deg={deg}, 风险)') # 留作对比,但建议使用 chebfit

plt.title('Chebyshev 拟合的数值稳定性')

plt.legend()

plt.grid(True)

plt.show()

numpy.polyfit() 只能进行多项式拟合。如果你需要用非多项式函数(如指数函数、对数函数、三角函数等)来拟合数据,polyfit 就无能为力了。

最佳替代方案 使用 SciPy 库中的 scipy.optimize.curve_fit 函数。这是进行任意非线性函数拟合的“万能”工具。

import numpy as np

from scipy.optimize import curve_fit

import matplotlib.pyplot as plt

# 拟合目标: 指数函数 f(x) = a * exp(b * x) + c

def exponential_func(x, a, b, c):

return a * np.exp(b * x) + c

# 示例数据 (带有噪声的指数数据)

x_data = np.linspace(0, 4, 50)

y_ideal = 2.5 * np.exp(-0.5 * x_data) + 1.0

y_data = y_ideal + 0.2 * np.random.normal(size=len(x_data))

# --- 使用 curve_fit 进行拟合 ---

# popt: 最佳参数 (a, b, c)

# pcov: 协方差矩阵

popt, pcov = curve_fit(exponential_func, x_data, y_data,

p0=[1.0, -0.1, 1.0]) # p0 是参数的初始猜测值,很重要!

# 拟合结果

y_fit = exponential_func(x_data, *popt)

print(f"拟合参数 (a, b, c): {popt}")

# 绘图比较

plt.figure(figsize=(10, 5))

plt.plot(x_data, y_data, 'bo', label='原始数据')

plt.plot(x_data, y_fit, 'r-', label=f'指数拟合: y = {popt[0]:.2f}*exp({popt[1]:.2f}*x) + {popt[2]:.2f}')

plt.title('使用 scipy.optimize.curve_fit 进行非多项式拟合')

plt.legend()

plt.grid(True)

plt.show()

当你的 X 坐标数据的范围很大(例如 105 或 10−5),或者 X 数据的中心远离 0 时,计算可能会遇到浮点精度问题。

最佳实践 在拟合前对 X 数据进行标准化(Scaling)或中心化(Centering),使 X 数据的范围大致在 [−1,1] 附近。

import numpy as np

# 示例数据 (X 值很大)

x_original = np.linspace(100000, 100010, 11)

y = 2 * x_original - 5 + np.random.normal(0, 1, 11)

deg = 1

# --- 1. 数据中心化/标准化 ---

# 中心化 X 数据: 减去平均值

x_mean = np.mean(x_original)

x_scaled = x_original - x_mean

# --- 2. 使用缩放后的 X 进行拟合 ---

# 拟合结果是 p(x_scaled) = a_scaled * x_scaled + b_scaled 的系数

p_scaled = np.polyfit(x_scaled, y, deg)

# --- 3. 结果转换 (重要!) ---

# 拟合多项式是 P(x) = a_scaled * (x - x_mean) + b_scaled

a_final = p_scaled[0]

b_final = p_scaled[1] - p_scaled[0] * x_mean

print(f"原始 X 拟合结果 (可能不稳定): {np.polyfit(x_original, y, deg)}")

print(f"缩放后 X 拟合结果 (a, b): {a_final:.4f}, {b_final:.4f}")

# 注意:在 deg=1 且数据线性关系很好的情况下,差异可能不明显,但在高阶时效果显著。

目标/问题推荐的函数优点标准多项式拟合numpy.polyfit()简单,快速,适用于低阶多项式。高阶多项式拟合numpy.polynomial.chebfit()数值更稳定,推荐用于 deg>5 的情况。任意函数拟合scipy.optimize.curve_fit()万能工具,可拟合指数、对数、三角等任何自定义函数。

Copyright © 2088 世界杯决赛_世界杯是 - rchzwh.com All Rights Reserved.
友情链接
top