Browse Source

Fit.Curve: non-linear least-squares curve fitting (scalar) #597

pull/601/head
Christoph Ruegg 8 years ago
parent
commit
a88e042a15
  1. 1
      MathNet.Numerics.sln.DotSettings
  2. 19
      src/Numerics.Tests/FitTests.cs
  3. 11
      src/Numerics/FindMinimum.cs
  4. 20
      src/Numerics/Fit.cs

1
MathNet.Numerics.sln.DotSettings

@ -81,5 +81,6 @@ OTHER DEALINGS IN THE SOFTWARE.
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Numerics/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>

19
src/Numerics.Tests/FitTests.cs

@ -320,5 +320,24 @@ namespace MathNet.Numerics.UnitTests
Assert.AreEqual(4.02159*Math.Sin(z) - 1.46962*Math.Cos(z) - 0.287476, resf(z), 1e-4);
}
}
[Test]
public void FitsCurveToBestLineThroughOrigin()
{
// Mathematica: Fit[{{1,4.986},{2,2.347},{3,2.061},{4,-2.995},{5,-2.352},{6,-5.782}}, {x}, x]
// -> -0.467791 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, (s,t) => s*t, -1.0);
Assert.AreEqual(-0.467791, resp, 1e-4);
var resf = Fit.CurveFunc(x, y, (s, t) => s * t, -1.0, 1e-10);
foreach (var z in Enumerable.Range(-3, 10))
{
Assert.AreEqual(-0.467791 * z, resf(z), 1e-4);
}
}
}
}

11
src/Numerics/FindMinimum.cs

@ -46,6 +46,17 @@ namespace MathNet.Numerics
return result.MinimizingPoint;
}
/// <summary>
/// Find vector x that minimizes the function f(x) using the Nelder-Mead Simplex algorithm.
/// For more options and diagnostics consider to use <see cref="NelderMeadSimplex"/> directly.
/// </summary>
public static double OfScalarFunction(Func<double, double> function, double initialGuess, double tolerance = 1e-8, int maxIterations = 1000)
{
var objective = ObjectiveFunction.Value(v => function(v[0]));
var result = NelderMeadSimplex.Minimum(objective, CreateVector.Dense(new[] { initialGuess }), tolerance, maxIterations);
return result.MinimizingPoint[0];
}
/// <summary>
/// Find vector x that minimizes the function f(x) using the Nelder-Mead Simplex algorithm.
/// For more options and diagnostics consider to use <see cref="NelderMeadSimplex"/> directly.

20
src/Numerics/Fit.cs

@ -32,6 +32,7 @@ using System.Linq;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearRegression;
using MathNet.Numerics.Providers.LinearAlgebra;
using MathNet.Numerics.Statistics;
namespace MathNet.Numerics
{
@ -334,5 +335,24 @@ namespace MathNet.Numerics
var parameters = LinearGeneric(x, y, method, functions);
return z => functions.Zip(parameters, (f, p) => p * f(z)).Sum();
}
/// <summary>
/// Non-linear least-squares fitting the points (x,y) to an arbitrary function y : x -> f(p, x),
/// returning its best fitting parameter p.
/// </summary>
public static double Curve(double[] x, double[] y, Func<double, double, double> f, double initialGuess, double tolerance = 1e-8, int maxIterations = 1000)
{
return FindMinimum.OfScalarFunction(p => Distance.Euclidean(Generate.Map(x, t => f(p, t)), y), initialGuess, tolerance, maxIterations);
}
/// <summary>
/// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x,
/// returning a function y' for the best fitting line.
/// </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)
{
var parameters = Curve(x, y, f, initialGuess, tolerance, maxIterations);
return z => f(parameters, z);
}
}
}

Loading…
Cancel
Save