【问题标题】:Fitting a curve to only a few data points仅将曲线拟合到几个数据点
【发布时间】:2019-09-17 19:53:39
【问题描述】:

我有一个只有 5 个数据点的散点图,我想将其拟合成曲线。我已经尝试过 polyfit 和以下代码,但都无法生成具有这么少数据点的曲线

def func(x, a, b, c):
 return a * np.exp(-b * x) + c
plt.plot(xdata, ydata, ".", label="Data");
optimizedParameters, pcov = opt.curve_fit(func, xdata, ydata);
plt.plot(xdata, func(xdata, *optimizedParameters), label="fit");

附件是一个情节示例,以及我试图制作的那种曲线的示例(为糟糕的绘图道歉)。谢谢!

【问题讨论】:

  • Imo 你应该添加你的导入和提供minimal reproducible example的点。
  • 抱歉,我正在使用熊猫,但它也适用于 x= (7e-09, 9e-09, 1e-08, 2e-8, 1e-6) 和 y=( 790、870、2400、2450、3100)。我认为我无法编辑问题以包含此内容。
  • 请注意,您的图像暗示了半对数图上的指数回归(参见 x 轴)。我想这不是你想要的。您可能想要在法线轴上进行简单回归,是吗?

标签: python curve-fitting


【解决方案1】:

这是一个示例图形 Python 拟合器,它使用您评论中的数据,拟合 Polytrope 类型的方程。在这个例子中,不需要记录数据。此处 X 轴以十对数刻度绘制。请注意,示例代码中的数据是浮点数的形式。

import numpy, scipy, matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

xData = numpy.array([7e-09, 9e-09, 1e-08, 2e-8, 1e-6])
yData = numpy.array([790.0, 870.0, 2400.0, 2450.0, 3100.0])


def func(x, a, b, offset): # polytrope equation from zunzun.com
    return  a / numpy.power(x, b) + offset


# these are the same as the scipy defaults
initialParameters = numpy.array([1.0, 1.0, 1.0])

# curve fit the test data
fittedParameters, pcov = curve_fit(func, xData, yData, initialParameters)

modelPredictions = func(xData, *fittedParameters) 

absError = modelPredictions - yData

SE = numpy.square(absError) # squared errors
MSE = numpy.mean(SE) # mean squared errors
RMSE = numpy.sqrt(MSE) # Root Mean Squared Error, RMSE
Rsquared = 1.0 - (numpy.var(absError) / numpy.var(yData))

print('Parameters:', fittedParameters)
print('RMSE:', RMSE)
print('R-squared:', Rsquared)

print()


##########################################################
# graphics output section
def ModelAndScatterPlot(graphWidth, graphHeight):
    f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
    axes = f.add_subplot(111)

    # first the raw data as a scatter plot
    axes.plot(xData, yData,  'D')

    # create data for the fitted equation plot
    xModel = numpy.linspace(min(xData), max(xData), 1000)
    yModel = func(xModel, *fittedParameters)

    # now the model as a line plot
    axes.plot(xModel, yModel)

    axes.set_xlabel('X Data') # X axis data label
    axes.set_ylabel('Y Data') # Y axis data label

    plt.xscale('log') # comment this out for default linear scaling


    plt.show()
    plt.close('all') # clean up after using pyplot

graphWidth = 800
graphHeight = 600
ModelAndScatterPlot(graphWidth, graphHeight)

【讨论】:

  • 这个答案同样有效,因为我们无法从这么少的点确定最佳拟合图是否应该有渐近线,或者只是一直在增长但在减速(这是对数的一个特征)。跨度>
  • 不错。你有你的多方方程的链接吗?
  • @pylang 我的 zunzun.com 开源 Python 网站对这个方程的拟合接口是 zunzun.com/Equation/2/Miscellaneous/Polytrope%20With%20Offset,我使用该站点的“函数查找器”对提供的数据进行方程搜索。该网站使用差分进化遗传算法来确定拟合非线性方程的初始参数估计,这使得此类方程搜索成为可能。
  • 谢谢。不错的网站。我的意思是将 y = a / xb + c 描述为“多方体”的资源。你有任何消息来源吗?
  • @pylang 我多年前的原始研究链接在我的源代码中为planetmath.org/encyclopedia/Polytrope.html,但现在这个链接似乎无效。请注意,该等式已将 x 提高到 b 次方,我在您的评论中没有看到。
【解决方案2】:

之后您必须选择要适合曲线的内容。从您的绘图的外观来看,您似乎正试图将其塑造成某种对数。

这是对数回归的图片:

对数回归将遵循 y = A + B ln(x) 的形式。 这本质上是一个线性回归拟合而不是拟合 y vs. x 我们正在尝试拟合 y 与 ln(x)。

因此,您可以只取数据集中点的 x 值的自然对数,并对其执行线性回归算法。对于 y=A + B ln(x),屈服系数为 A 和 B。

图片来源: http://mathworld.wolfram.com/LeastSquaresFittingLogarithmic.html

编辑:正如 James Phillips 在他的回答中指出的那样,也可以以 y=Ax^(-B) + C 的形式对曲线进行建模,因为对于这么少的点,无法确定图形是否具有水平渐近线或一直在增长但在减速。很多曲线可能(例如 y=A* B^(-x) +C 可能是另一条曲线),但您需要选择对数据建模的依据。

【讨论】:

  • 请查看我使用多线型方程对这个问题的回答。
  • 根据我的分析,您在编辑中断言“y=A* B^(-x) +C”将是所提供数据的候选拟合方程是不正确的。请提供该方程的拟合参数。
  • @JamesPhillips 我的意思是它可能是另一种模型。为了清楚起见,更正了它。不过,究竟是什么告诉你这不是一个合适的模型?
  • 在我的分析中,该方程与数据的拟合非常差 - 这就是我要求您提供拟合参数的原因。
【解决方案3】:

指数函数不能很好地拟合您的数据。考虑另一个建模函数。

给定

 import numpy as np
 import scipy.optimize as opt
 import matplotlib.pyplot as plt


%matplotlib inline


x_samp = np.array([7e-09, 9e-09, 1e-08, 2e-8, 1e-6])
y_samp = np.array([790, 870, 2400, 2450, 3100])


def func(x, a, b):
    """Return a exponential result."""
    return a + b*np.log(x)


def func2(x, a, b, c):
    """Return a 'power law' result."""
    return a/np.power(x, b) + c

代码

来自@Allan Lago 的对数模型:

# REGRESSION ------------------------------------------------------------------
x_lin = np.linspace(x_samp.min(), x_samp.max(), 50)

w, _ = opt.curve_fit(func, x_samp, y_samp)     
print("Estimated Parameters", w)  

# Model
y_model = func(x_lin, *w)


# PLOT ------------------------------------------------------------------------
# Visualize data and fitted curves
plt.plot(x_samp, y_samp, "ko", label="Data")
plt.plot(x_lin, y_model, "k--", label="Fit")
plt.xticks(np.arange(0, x_samp.max(), x_samp.max()/2))
plt.title("Least squares regression")
plt.legend(loc="upper left")

Estimated Parameters [8339.61062739  367.6992259 ]

使用@James Phillips 的“Polytrope”模型:

# REGRESSION ------------------------------------------------------------------
p0 = [1, 1, 1]
w, _ = opt.curve_fit(func2, x_samp, y_samp, p0=p0)     
print("Estimated Parameters", w)  

# Model
y_model = func2(x_lin, *w)


# PLOT ------------------------------------------------------------------------
# Visualize data and fitted curves
plt.plot(x_samp, y_samp, "ko", label="Data")
plt.plot(x_lin, y_model, "k--", label="Fit")
plt.xticks(np.arange(0, x_samp.max(), x_samp.max()/2))
plt.title("Least squares regression")
plt.legend()

Estimated Parameters [-3.49305043e-10  1.57259788e+00  3.05801283e+03]

【讨论】:

  • 这是两种方法的绝佳直接比较。酷。
  • 请注意,问题中发布的图像具有 X 轴的十年对数刻度。
  • 是的,我在之前的评论中提到了这个问题。
猜你喜欢
  • 1970-01-01
  • 2012-07-14
  • 1970-01-01
  • 2012-06-22
  • 1970-01-01
  • 2019-10-13
  • 2016-02-02
  • 2020-02-14
  • 2020-08-26
相关资源
最近更新 更多