【问题标题】:Scipy curve_fit for Two Dimensions Not Working - Object Too Deep?二维的 Scipy curve_fit 不起作用 - 对象太深?
【发布时间】:2019-04-16 12:18:22
【问题描述】:

我有一个 2400 x 2400 的数据数组,看起来像这样:

data = [[-2.302670298082603040e-01 -2.304885241061924717e-01 -2.305029774024092148e-01 -2.304807100897505734e-01 -2.303702531336284665e-01 -2.307144352067780346e-01...
[-2.302670298082603040e-01 -2.304885241061924717e-01 -2.305029774024092148e-01 -2.304807100897505734e-01 -2.303702531336284665e-01 -2.307144352067780346e-01...
...

我正在尝试拟合以下二维高斯函数:

def Gauss2D(x, mux, muy, sigmax, sigmay, amplitude, offset, rotation):
    assert len(x) == 2
    X = x[0]
    Y = x[1]
    A = (np.cos(rotation)**2)/(2*sigmax**2) + (np.sin(rotation)**2)/(2*sigmay**2)
    B = (np.sin(rotation*2))/(4*sigmay**2) - (np.sin(2*rotation))/(4*sigmax**2)
    C = (np.sin(rotation)**2)/(2*sigmax**2) + (np.cos(rotation)**2)/(2*sigmay**2)
    G = amplitude*np.exp(-((A * (X - mux) ** 2) + (2 * B * (X - mux) * (Y - muy)) + (C * (Y - muy) ** 2))) + offset
    return G

这个数据,使用 scipy curve_fit。因此,我将自变量(坐标)的域定义如下:

vert = np.arange(2400, dtype=float)
horiz = np.arange(2400, dtype=float)
HORIZ, VERT = np.meshgrid(horiz, vert)

作为参数的初始估计:

po = np.asarray([1200., 1200., 300., 300., 0.14, 0.22, 0.], dtype=float)

这样我就可以执行以下拟合:

popt, pcov = curve_fit(Gauss2D, (HORIZ, VERT), data, p0=po)

这将返回以下错误消息,我不知道为什么:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
ValueError: object too deep for desired array
---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
<ipython-input-11-ebba75332bfa> in <module>()
----> 1 curve_fit(Gauss2D, (HORIZ, VERT), data, p0=po)

/home/harrythegenius/anaconda3/lib/python3.6/site-packages/scipy/optimize/minpack.py in curve_fit(f, xdata, ydata, p0, sigma, absolute_sigma, check_finite, bounds, method, jac, **kwargs)
734         # Remove full_output from kwargs, otherwise we're passing it in twice.
735         return_full = kwargs.pop('full_output', False)
--> 736         res = leastsq(func, p0, Dfun=jac, full_output=1, **kwargs)
737         popt, pcov, infodict, errmsg, ier = res
738         cost = np.sum(infodict['fvec'] ** 2)

/home/harrythegenius/anaconda3/lib/python3.6/site-packages/scipy/optimize/minpack.py in leastsq(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag)
385             maxfev = 200*(n + 1)
386         retval = _minpack._lmdif(func, x0, args, full_output, ftol, xtol,
--> 387                                  gtol, maxfev, epsfcn, factor, diag)
388     else:
389         if col_deriv:

error: Result from function call is not a proper array of floats.

我不理解“对象对于所需数组而言太深”的消息。我还看到了针对此错误消息的多个在线解决方案,其中一个可以通过确保传递给 curve_fit 的所有数据类型都是浮点数或检查数组的维度是否正确来修复它。我已经一次又一次地尝试了这两种方法,但没有任何区别。那么这个有什么问题呢?

【问题讨论】:

  • 澄清一下,data.shapedata.dtype 是什么?您需要显示一些数据检查。
  • 形状为 (2400, 2400)。
  • dtype 是 float64
  • HORIZ 是一个二维数组,(2400,2400)。您是否尝试过使用 (horiz, vert) 来调用它?
  • 如果您给我们minimal reproducible example,我们可以复制粘贴并运行,我们也许可以提供更多帮助。

标签: python optimization scipy curve-fitting gaussian


【解决方案1】:

好的,伙计们,我自己解决了这个问题。正如我所怀疑的,这是一个维度问题。

curve_fit 应用于二维数组的适当尺寸如下:

  • 函数 - 一维,在这种情况下,除非强制执行,否则它与数据集具有相同的维度
  • x 数据 - (2, n*m),其中 n 和 m 是数据数组的维度
  • y 数据 - (n*m)
  • 初始参数列表 - 一个一维数组,简单地包含所有参数,其顺序与函数中所述的顺序相同

因此,我保持参数数组不变,但对函数进行了以下更改:

def Gauss2D(x, mux, muy, sigmax, sigmay, amplitude, offset, rotation):
    assert len(x) == 2
    X = x[0]
    Y = x[1]
    A = (np.cos(rotation)**2)/(2*sigmax**2) + (np.sin(rotation)**2)/(2*sigmay**2)
    B = (np.sin(rotation*2))/(4*sigmay**2) - (np.sin(2*rotation))/(4*sigmax**2)
    C = (np.sin(rotation)**2)/(2*sigmax**2) + (np.cos(rotation)**2)/(2*sigmay**2)
    G = amplitude*np.exp(-((A * (X - mux) ** 2) + (2 * B * (X - mux) * (Y - muy)) + (C * (Y - muy) ** 2))) + offset
    return G.ravel()

我将以下内容传递给 x 数据参数:

x = np.vstack((HORIZ.ravel(), VERT.ravel()))

这是 y 数据参数:

y = data.ravel()

因此,我使用以下方法对其进行了优化:

curve_fit(Gauss2D, x, y, po)

效果很好。

【讨论】:

    【解决方案2】:

    根据 cmets,这是一个使用 curve_fit() 的 3D 曲面拟合器,它具有 3D 散点图、3D 曲面图和等高线图。

    import numpy, scipy, scipy.optimize
    import matplotlib
    from mpl_toolkits.mplot3d import  Axes3D
    from matplotlib import cm # to colormap 3D surfaces from blue to red
    import matplotlib.pyplot as plt
    
    graphWidth = 800 # units are pixels
    graphHeight = 600 # units are pixels
    
    # 3D contour plot lines
    numberOfContourLines = 16
    
    
    def SurfacePlot(func, data, fittedParameters):
        f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
    
        matplotlib.pyplot.grid(True)
        axes = Axes3D(f)
    
        x_data = data[0]
        y_data = data[1]
        z_data = data[2]
    
        xModel = numpy.linspace(min(x_data), max(x_data), 20)
        yModel = numpy.linspace(min(y_data), max(y_data), 20)
        X, Y = numpy.meshgrid(xModel, yModel)
    
        Z = func(numpy.array([X, Y]), *fittedParameters)
    
        axes.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=1, antialiased=True)
    
        axes.scatter(x_data, y_data, z_data) # show data along with plotted surface
    
        axes.set_title('Surface Plot (click-drag with mouse)') # add a title for surface plot
        axes.set_xlabel('X Data') # X axis data label
        axes.set_ylabel('Y Data') # Y axis data label
        axes.set_zlabel('Z Data') # Z axis data label
    
        plt.show()
        plt.close('all') # clean up after using pyplot or else thaere can be memory and process problems
    
    
    def ContourPlot(func, data, fittedParameters):
        f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
        axes = f.add_subplot(111)
    
        x_data = data[0]
        y_data = data[1]
        z_data = data[2]
    
        xModel = numpy.linspace(min(x_data), max(x_data), 20)
        yModel = numpy.linspace(min(y_data), max(y_data), 20)
        X, Y = numpy.meshgrid(xModel, yModel)
    
        Z = func(numpy.array([X, Y]), *fittedParameters)
    
        axes.plot(x_data, y_data, 'o')
    
        axes.set_title('Contour Plot') # add a title for contour plot
        axes.set_xlabel('X Data') # X axis data label
        axes.set_ylabel('Y Data') # Y axis data label
    
        CS = matplotlib.pyplot.contour(X, Y, Z, numberOfContourLines, colors='k')
        matplotlib.pyplot.clabel(CS, inline=1, fontsize=10) # labels for contours
    
        plt.show()
        plt.close('all') # clean up after using pyplot or else thaere can be memory and process problems
    
    
    def ScatterPlot(data):
        f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
    
        matplotlib.pyplot.grid(True)
        axes = Axes3D(f)
        x_data = data[0]
        y_data = data[1]
        z_data = data[2]
    
        axes.scatter(x_data, y_data, z_data)
    
        axes.set_title('Scatter Plot (click-drag with mouse)')
        axes.set_xlabel('X Data')
        axes.set_ylabel('Y Data')
        axes.set_zlabel('Z Data')
    
        plt.show()
        plt.close('all') # clean up after using pyplot or else thaere can be memory and process problems
    
    
    def func(data, a, alpha, beta):
        t = data[0]
        p_p = data[1]
        return a * (t**alpha) * (p_p**beta)
    
    
    if __name__ == "__main__":
        xData = numpy.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0])
        yData = numpy.array([11.0, 12.1, 13.0, 14.1, 15.0, 16.1, 17.0, 18.1, 90.0])
        zData = numpy.array([1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.0, 9.9])
    
        data = [xData, yData, zData]
    
        initialParameters = [1.0, 1.0, 1.0] # these are the same as scipy default values in this example
    
        # here a non-linear surface fit is made with scipy's curve_fit()
        fittedParameters, pcov = scipy.optimize.curve_fit(func, [xData, yData], zData, p0 = initialParameters)
    
        ScatterPlot(data)
        SurfacePlot(func, data, fittedParameters)
        ContourPlot(func, data, fittedParameters)
    
        print('fitted prameters', fittedParameters)
    
        modelPredictions = func(data, *fittedParameters) 
    
        absError = modelPredictions - zData
    
        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(zData))
        print('RMSE:', RMSE)
        print('R-squared:', Rsquared)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-01
      • 1970-01-01
      • 2018-06-07
      • 2022-09-22
      • 2015-01-21
      • 2016-12-27
      • 2019-04-15
      • 2021-09-25
      相关资源
      最近更新 更多