5

在我正在进行的一个项目中,我需要从一组点中获得高斯拟合 - 需要一些处理的均值和方差,并且可能需要一个错误程度(或准确度级别)来让我弄清楚这组点是否真的具有正态分布。

我发现了这个问题

但它仅限于 3 点 - 而我需要一个可以处理任意数量点的合身。

我需要的是类似于labview Gaussian Peak Fit

我查看了 mathdotnet 和 aforge.net (在同一个项目中使用两者),但我没有找到任何东西。

有人知道任何 C# 或(易于转换的)C/C++ 或 Java 解决方案吗?

或者,有人告诉我应该使用迭代算法——我可以自己实现它(如果数学不太复杂的话)。关于我可以使用什么的任何想法?我已经阅读了很多文章(在 Wikipedia 和其他通过 Google 找到的文章),但我没有找到任何明确的解决方案指示。

4

5 回答 5

2

只需计算样本的均值和标准差,这是高斯分布的仅有的两个参数。

对于“拟合优度”,您可以执行 CDF 的均方误差之类的操作。

于 2011-10-12T15:22:45.947 回答
2

Math.Net ( nuget ) 中,您可以执行以下操作:

var real_σ = 0.5;
var real_μ = 0;

//Define gaussian function
var gaussian = new Func<double, double, double, double>((σ, μ, x) =>
{
    return Normal.PDF(μ, σ, x);
});

//Generate sample gaussian data
var data = Enumerable.Range(0, 41)
    .Select(x => -2 + x * 0.1)
    .Select(x => new { x, y = gaussian(real_σ, real_μ, x) });

var xs = data.Select(d => d.x).ToArray();
var ys = data.Select(d => d.y).ToArray();
var initialGuess_σ = 1;
var initialGuess_μ = 0;

var fit = Fit.Curve(xs, ys, gaussian, initialGuess_σ, initialGuess_μ);
//fit.Item1 = σ, fit.Item2 = μ
于 2019-07-23T21:25:51.743 回答
1

我在 ImageJ 中找到了一个很好的实现,这是一个公共领域的图像处理程序,其源代码可在此处获得

转换为 C# 并适应我的需要。

感谢你们的回答......与我找到的解决方案并不严格相关,但不知何故我在你的帮助下到达了那里:)

于 2011-10-18T18:03:59.100 回答
1

在这里,我展示了一个示例,说明如何使用任意数量的参数拟合任意函数,并为每个单独的参数设置上限/下限。就像RexCardan 的示例一样,它是使用MathNet库完成的。

它不是很快,但它确实有效。

为了适应不同的功能改变double gaussian(Vector<double> vectorArg)方法。如果更改vectorArgs 的数量还需要调整:

  1. 和中lowerBound的元素数。upperBoundinitialGuessCurveFit
  2. 改变参数个数return z => f(new DenseVector(new[] { parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], z }));
  3. 改变参数个数t => f(new DenseVector(new[] { p[0], p[1], p[2], p[3], p[4], p[5], t }))

双高斯的示例代码

using MathNet.Numerics;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearAlgebra.Double;
using System;
using System.Linq;

static class GaussianFit
{
    /// <summary>
    /// Non-linear least square Gaussian curve fit to data.
    /// </summary>
    /// <param name="mu1">x position of the first Gaussian.</param>
    /// <param name="mu2">x position of the second Gaussian.</param>
    /// <returns>Array of the Gaussian profile.</returns>
    public Func<double, double> CurveFit(double[] xData, double[] yData, double mu1, double mu2)
    {
        //Define gaussian function
        double gaussian(Vector<double> vectorArg)
        {
            double x = vectorArg.Last();
            double y = 
                vectorArg[0] * Normal.PDF(vectorArg[1], vectorArg[2], x)
                + vectorArg[3] * Normal.PDF(vectorArg[4], vectorArg[5], x);
            return y;
        }

        var lowerBound = new DenseVector(new[] { 0, mu1 * 0.98, 0.05, 0, mu2 * 0.98, 0.05 });
        var upperBound = new DenseVector(new[] { 1e10, mu1 * 1.02, 0.3, 1e10, mu2 * 1.02, 0.3 });
        var initialGuess = new DenseVector(new[] { 1000, mu1, 0.2, 1000, mu2, 0.2 });

        Func<double, double> fit = CurveFuncConstrained(
            xData, yData, gaussian, lowerBound, upperBound, initialGuess
        );

        return fit;
    }

    /// <summary>
    /// Non-linear least-squares fitting the points (x,y) to an arbitrary function y : x -> f(p0, p1, p2, x),
    /// returning a function y' for the best fitting curve.
    /// </summary>
    public static Func<double, double> CurveFuncConstrained(
        double[] x,
        double[] y,
        Func<Vector<double>, double> f,
        Vector<double> lowerBound,
        Vector<double> upperBound,
        Vector<double> initialGuess,
        double gradientTolerance = 1e-5,
        double parameterTolerance = 1e-5,
        double functionProgressTolerance = 1e-5,
        int maxIterations = 1000
    )
    {
        var parameters = CurveConstrained(
            x, y, f,
            lowerBound, upperBound, initialGuess,
            gradientTolerance, parameterTolerance, functionProgressTolerance,
            maxIterations
        );
        return z => f(new DenseVector(new[] { parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], z }));
    }

    /// <summary>
    /// Non-linear least-squares fitting the points (x,y) to an arbitrary function y : x -> f(p0, p1, p2, x),
    /// returning its best fitting parameter p0, p1 and p2.
    /// </summary>
    public static Vector<double> CurveConstrained(
        double[] x,
        double[] y,
        Func<Vector<double>, double> f,
        Vector<double> lowerBound,
        Vector<double> upperBound,
        Vector<double> initialGuess,
        double gradientTolerance = 1e-5,
        double parameterTolerance = 1e-5,
        double functionProgressTolerance = 1e-5,
        int maxIterations = 1000
    )
    {
        return FindMinimum.OfFunctionConstrained(
            (p) => Distance.Euclidean(
                Generate.Map(
                    x, 
                    t => f(new DenseVector(new[] { p[0], p[1], p[2], p[3], p[4], p[5], t }))
                    ), 
                y),
            lowerBound,
            upperBound,
            initialGuess,
            gradientTolerance,
            parameterTolerance,
            functionProgressTolerance,
            maxIterations
        );
    }

例子

在 x 位置 10 和 20 拟合两个高斯:

Func<double, double> fit = GaussianFit.Curvefit(x_data, y_data, 10, 20);
于 2020-09-09T09:19:43.897 回答
0

关于 Antonio 2011 年 10 月 18 日 18:03 的回答 1:

在 ImageJ 中找到了一个很好的实现,这是一个公共领域的图像处理程序,其源代码可在此处获得。

不幸的是,链接已损坏,但是您仍然可以在 archive.org 上找到快照:

https://imagej.nih.gov/ij/developer/source/ij/measure/CurveFitter.java.html

(我会将此作为评论发布以回答 1,但作为新用户,我显然不允许这样做。)

优子

于 2022-01-28T09:34:23.707 回答