c#中的高斯拟合
本文关键字:拟合 高斯 | 更新日期: 2023-09-27 18:10:59
在我正在进行的一个项目中,我需要从一组点中获得高斯拟合-需要进行一些处理的均值和方差,并且可能需要一个误差程度(或精度级别)来让我弄清楚这组点是否真的具有正态分布。
我发现了这个问题
,但它仅限于3个点-而我需要一个适合任何数量的点。
我需要的是类似于labview的高斯峰值拟合
我看过mathdotnet和agforge.net(在同一个项目中使用两者),但我没有发现任何东西。
有谁知道c#或(容易转换的)C/c++或Java解决方案吗?
或者,我被告知应该使用迭代算法-我可以自己实现它(如果不是太复杂的数学)。知道我能用什么吗?我读了很多文章(在维基百科和其他通过谷歌找到的),但我还没有找到任何明确的解决方案。
In 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 = μ
这里我展示了一个示例,说明如何用任意数量的参数拟合任意函数,并为每个参数设置上/下界。就像RexCardan的例子一样,它是使用MathNet库完成的。
它不是很快,但它工作。
为了适应不同的函数,改变double gaussian(Vector<double> vectorArg)
方法。如果您更改vectorArg
的数量,您还需要调整:
-
CurveFit
中lowerBound
、upperBound
、initialGuess
元素的数量。 - 修改
return z => f(new DenseVector(new[] { parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], z }));
参数个数 - 修改
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);
标题>只需计算样本的平均值和标准差,这是高斯分布的两个参数。
对于"拟合优度",你可以做类似于CDF的均方误差。
我在ImageJ中找到了一个很好的实现,ImageJ是一个公共领域的图像处理程序,其源代码可在这里获得
转换成c#并适应我的需要。
感谢你们的回答…与我找到的解决方案没有严格关系,但不知何故,我在你的帮助下到达了那里:)
关于回复1 by Antonio Oct 18 '11 at 18:03:
我在ImageJ中找到了一个很好的实现,ImageJ是一个公共领域的图像处理程序,其源代码可在这里获得。
不幸的是,链接已经断开,但是你仍然可以在archive.org上找到一个快照:
https://imagej.nih.gov/ij/developer/source/ij/measure/CurveFitter.java.html(我本想把这个作为回答1的评论,但作为一个新用户,我显然不允许这样做。)
Ukko