Browse Source

Fit.Curve: extended to 2 and 3 parameters #597

pull/601/head
Christoph Ruegg 8 years ago
parent
commit
7374ecb1b5
  1. 20
      src/Numerics.Tests/FitTests.cs
  2. 42
      src/Numerics/Fit.cs

20
src/Numerics.Tests/FitTests.cs

@ -339,5 +339,25 @@ namespace MathNet.Numerics.UnitTests
Assert.AreEqual(-0.467791 * z, resf(z), 1e-4); Assert.AreEqual(-0.467791 * z, resf(z), 1e-4);
} }
} }
[Test]
public void FitsCurveToBestLine()
{
// Mathematica: Fit[{{1,4.986},{2,2.347},{3,2.061},{4,-2.995},{5,-2.352},{6,-5.782}}, {1, x}, x]
// -> 7.01013 - 2.08551*x
var x = Enumerable.Range(1, 6).Select(Convert.ToDouble).ToArray();
var y = new[] { 4.986, 2.347, 2.061, -2.995, -2.352, -5.782 };
var resp = Fit.Curve(x, y, (m, s, t) => m + s*t, 1.0, -1.0, 1e-12);
Assert.AreEqual(7.01013, resp.Item1, 1e-4);
Assert.AreEqual(-2.08551, resp.Item2, 1e-4);
var resf = Fit.CurveFunc(x, y, (m, s, t) => m + s * t, 1.0, -1.0, 1e-12);
foreach (var z in Enumerable.Range(-3, 10))
{
Assert.AreEqual(7.01013 - 2.08551 * z, resf(z), 1e-4);
}
}
} }
} }

42
src/Numerics/Fit.cs

@ -345,13 +345,51 @@ namespace MathNet.Numerics
} }
/// <summary> /// <summary>
/// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x, /// Non-linear least-squares fitting the points (x,y) to an arbitrary function y : x -> f(p0, p1, x),
/// returning a function y' for the best fitting line. /// returning its best fitting parameter p0 and p1.
/// </summary>
public static Tuple<double, double> Curve(double[] x, double[] y, Func<double, double, double, double> f, double initialGuess0, double initialGuess1, double tolerance = 1e-8, int maxIterations = 1000)
{
return FindMinimum.OfFunction((p0, p1) => Distance.Euclidean(Generate.Map(x, t => f(p0, p1, t)), y), initialGuess0, initialGuess1, tolerance, maxIterations);
}
/// <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 Tuple<double, double, double> Curve(double[] x, double[] y, Func<double, double, double, double, double> f, double initialGuess0, double initialGuess1, double initialGuess2, double tolerance = 1e-8, int maxIterations = 1000)
{
return FindMinimum.OfFunction((p0, p1, p2) => Distance.Euclidean(Generate.Map(x, t => f(p0, p1, p2, t)), y), initialGuess0, initialGuess1, initialGuess2, tolerance, maxIterations);
}
/// <summary>
/// Non-linear least-squares fitting the points (x,y) to an arbitrary function y : x -> f(p, x),
/// returning a function y' for the best fitting curve.
/// </summary> /// </summary>
public static Func<double, double> CurveFunc(double[] x, double[] y, Func<double, double, double> f, double initialGuess, double tolerance = 1e-8, int maxIterations = 1000) public static Func<double, double> CurveFunc(double[] x, double[] y, Func<double, double, double> f, double initialGuess, double tolerance = 1e-8, int maxIterations = 1000)
{ {
var parameters = Curve(x, y, f, initialGuess, tolerance, maxIterations); var parameters = Curve(x, y, f, initialGuess, tolerance, maxIterations);
return z => f(parameters, z); return z => f(parameters, z);
} }
/// <summary>
/// Non-linear least-squares fitting the points (x,y) to an arbitrary function y : x -> f(p0, p1, x),
/// returning a function y' for the best fitting curve.
/// </summary>
public static Func<double, double> CurveFunc(double[] x, double[] y, Func<double, double, double, double> f, double initialGuess0, double initialGuess1, double tolerance = 1e-8, int maxIterations = 1000)
{
var parameters = Curve(x, y, f, initialGuess0, initialGuess1, tolerance, maxIterations);
return z => f(parameters.Item1, parameters.Item2, z);
}
/// <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> CurveFunc(double[] x, double[] y, Func<double, double, double, double, double> f, double initialGuess0, double initialGuess1, double initialGuess2, double tolerance = 1e-8, int maxIterations = 1000)
{
var parameters = Curve(x, y, f, initialGuess0, initialGuess1, initialGuess2, tolerance, maxIterations);
return z => f(parameters.Item1, parameters.Item2, parameters.Item3, z);
}
} }
} }

Loading…
Cancel
Save