【问题标题】:Gaussian fit in C#C#中的高斯拟合
【发布时间】:2011-12-06 05:05:09
【问题描述】:

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

我找到了这个question

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

我需要的类似于labviewGaussian Peak Fit

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

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

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

【问题讨论】:

标签: c# curve-fitting gaussian


【解决方案1】:

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

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

很遗憾,链接已损坏,但您仍然可以在 archive.org 上找到快照:

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

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

乌哥

【讨论】:

    【解决方案2】:

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

    它不是很快,但它可以工作。

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

    1. lowerBoundupperBoundinitialGuessCurveFit 中的元素数。
    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);
    

    【讨论】:

    • 谢谢,老问题,很高兴看到它们永不过期 :-) 干得好,我无法测试它(不再在那个应用程序上工作,甚至在 Windows 上也不能)但不管我认为你应该为你的努力竖起大拇指;-)。通过查看代码,它看起来就是我想要的。
    【解决方案3】:

    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 = μ
    

    【讨论】:

      【解决方案4】:

      我在ImageJ中找到了一个很好的实现,一个公共领域的图像处理程序,它的源代码可以在here找到

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

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

      【讨论】:

      • @ephraim 抱歉,我想我已经没有那个代码了,那是很久以前的事了
      【解决方案5】:

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

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

      【讨论】:

        猜你喜欢
        • 2013-10-12
        • 2017-06-14
        • 1970-01-01
        • 1970-01-01
        • 2018-08-07
        • 2017-08-30
        • 2012-07-15
        • 2015-07-26
        • 2021-10-14
        相关资源
        最近更新 更多