【问题标题】:Why am I getting a System.ArithmeticException in this example doing a non-linear regression to a Gaussian为什么我在这个例子中得到一个 System.ArithmeticException 对高斯进行非线性回归
【发布时间】:2017-11-29 21:24:24
【问题描述】:

我正在将一些我在 Matlab 中原型化的代码移植到 C# 中,并且需要对我的示例数据执行高斯非线性回归。我目前正在尝试 Accord.Net,并在example here 之后提出了以下代码。

不幸的是,我遇到了这个异常,但不明白为什么:

System.ArithmeticException:错误计算产生了一个非有限的数字。请确保输入数据中没有常量列。”

带有错误信息:

错误计算产生了一个非有限的数字。请确保输入数据中没有常量列。

这是我想出的代码:

    public static double[] FitGaussian()
    {
        var nls = CreateGaussianFitObject(new[] { 1.43e+04, 0.05093, 0.8098 }, 100, 0);

        double[,] data =
        {
            { -0.2,    12973.3071 },
            { -0.1,    13846.1569 },
            { -0,      14243.9094 },
            {  0.1,    14215.6044 },
            {  0.2,    13840.9077 },
        };

        // Extract inputs and outputs
        double[][] inputs = data.GetColumn(0).ToJagged();
        double[] outputs = data.GetColumn(1);

        var regression = nls.Learn(inputs, outputs);

        var result = regression.Coefficients;
        return result;
    }

    public static NonlinearLeastSquares CreateGaussianFitObject(double[] StartValues, int maxIterations, double tolerance)
    {
        Func<double, double, double, double> expFnc = (mu, sig, x) => m.Exp(-m.Pow((x - mu) / sig, 2));

        var nls = new NonlinearLeastSquares()
        {
            NumberOfParameters = 3,

            // Reference Gaussian Distributioon used in Matlab: f(x) =  a1*exp(-((x-b1)/c1)^2)
            //Function = (w, x) => w[0] * System.Math.Exp(-System.Math.Pow((x[0] - w[1]) / w[2], 2)),
            Function = (w, x) => w[0] * expFnc(w[1],w[2],x[0]),

            // Derivative in respect to the weights:
            Gradient = (w, x, r) =>
            {
                r[0] = expFnc(w[1], w[2], x[0]); // e^(-(x - b1)^2/c1^2)   <=>   diff a1*exp(-((x-b1)/c1)^2) w.r.t. a1
                r[1] = (2 * w[0] * (x[0] - w[1]) * expFnc(w[1], w[2], x[0])) / m.Pow(w[2],2); // (2 a1 (x - b1) e^(-(x - b1)^2/c1^2))/c1^2   <=>   diff a1*exp(-((x-b1)/c1)^2) w.r.t. b1
                r[2] = (2 * w[0] * m.Pow((x[0] - w[1]),2) * expFnc(w[1], w[2], x[0])) / m.Pow(w[2],3); // (2 a1 (x - b1)^2 e^(-(x - b1)^2/c1^2))/c1^3   <=>   diff a1*exp(-((x-b1)/c1)^2) w.r.t. c1
            },

            Algorithm = new LevenbergMarquardt()
            {
                MaxIterations = maxIterations,
                Tolerance = tolerance
            }
        };

        return nls;
    }

我已经仔细检查了梯度函数(我怀疑它是罪魁祸首),它似乎没问题。

对应的Matlab代码是这样的:

x = [-0.2,-0.1,0,0.1,0.2];
y = [12973.3071,13846.1569,14243.9094,14215.6044,13840.9077];
f = fit(x.',y.','gauss1');
fitObject = f;

给出这个输出:

f = 

     General model Gauss1:
     f(x) =  a1*exp(-((x-b1)/c1)^2)
     Coefficients (with 95% confidence bounds):
       a1 =    1.43e+04  (1.419e+04, 1.441e+04)
       b1 =     0.05093  (0.03501, 0.06686)
       c1 =      0.8098  (0.7263, 0.8932)

如您所见,我什至尝试将 Matlab 中的预期系数作为 C# 实现的起始值。

我还对上面引用的example 感到困惑,因为在我看来他们切换了系数和输入(?)。

【问题讨论】:

    标签: c# matlab nonlinear-optimization non-linear-regression accord.net


    【解决方案1】:

    我忘记在构造函数NonlinearLeastSquares()中使用参数StartValues,导致异常。它应该是:

        var nls = new NonlinearLeastSquares()
        {
            NumberOfParameters = 3,
            StartValues = StartValues,
            // Reference Gaussian Distributioon used in Matlab: f(x) =  a1*exp(-((x-b1)/c1)^2)
            //Function = (w, x) => w[0] * System.Math.Exp(-System.Math.Pow((x[0] - w[1]) / w[2], 2)),
            Function = (w, x) => w[0] * expFnc(w[1],w[2],x[0]),
    
            // Derivative in respect to the weights:
            Gradient = (w, x, r) =>
            {
                r[0] = expFnc(w[1], w[2], x[0]); // e^(-(x - b1)^2/c1^2)   <=>   diff a1*exp(-((x-b1)/c1)^2) w.r.t. a1
                r[1] = (2 * w[0] * (x[0] - w[1]) * expFnc(w[1], w[2], x[0])) / m.Pow(w[2],2); // (2 a1 (x - b1) e^(-(x - b1)^2/c1^2))/c1^2   <=>   diff a1*exp(-((x-b1)/c1)^2) w.r.t. b1
                r[2] = (2 * w[0] * m.Pow((x[0] - w[1]),2) * expFnc(w[1], w[2], x[0])) / m.Pow(w[2],3); // (2 a1 (x - b1)^2 e^(-(x - b1)^2/c1^2))/c1^3   <=>   diff a1*exp(-((x-b1)/c1)^2) w.r.t. c1
            },
    
            Algorithm = new LevenbergMarquardt()
            {
                MaxIterations = maxIterations,
                Tolerance = tolerance
            }
        };
    

    如果没有明确设置,显然StartValues 被设置为一个零数组。这导致除以零,因此导致异常。我通过添加

    发现了这一点
    Debug.WriteLine($"Weights: w[0]: {w[0]}, w[1]: {w[1]}, w[2]: {w[2]}");
    Debug.WriteLine($"Result: r[0]: {r[0]}, r[1]: {r[1]}, r[2]: {r[2]}");
    

    到 Gradient 属性的 lambda 表达式。

    【讨论】:

      猜你喜欢
      • 2021-09-17
      • 2018-07-29
      • 2021-06-17
      • 1970-01-01
      • 2020-01-02
      • 1970-01-01
      • 2021-06-24
      • 1970-01-01
      • 2020-05-09
      相关资源
      最近更新 更多