diff --git a/src/FSharp/Fit.fs b/src/FSharp/Fit.fs
index 9aec4a93..40450cce 100644
--- a/src/FSharp/Fit.fs
+++ b/src/FSharp/Fit.fs
@@ -47,6 +47,14 @@ module Fit =
/// returning a function y' for the best fitting line.
let lineFunc x y = Fit.LineFunc(x,y) |> tofs
+ /// Least-Squares fitting the points (x,y) to a line y : x -> b*x,
+ /// returning its best fitting parameter b.
+ let lineThroughOrigin x y = Fit.LineThroughOrigin(x,y)
+
+ /// Least-Squares fitting the points (x,y) to a line y : x -> b*x,
+ /// returning a function y' for the best fitting line.
+ let lineThroughOriginFunc x y = Fit.LineThroughOriginFunc(x,y) |> tofs
+
/// Least-Squares fitting the points ((x0,x1,...,xk),y) to a linear surface y : X -> p0*x0 + p1*x1 + ... + pk*xk,
/// returning its best fitting parameters as [p0, p1, p2, ..., pk] array.
let multiDim intercept x y = Fit.MultiDim(x,y,intercept)
diff --git a/src/Numerics/Fit.cs b/src/Numerics/Fit.cs
index a07b668c..28805816 100644
--- a/src/Numerics/Fit.cs
+++ b/src/Numerics/Fit.cs
@@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
-// Copyright (c) 2009-2015 Math.NET
+// Copyright (c) 2009-2018 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@@ -61,6 +61,26 @@ namespace MathNet.Numerics
return z => intercept + slope*z;
}
+ ///
+ /// Least-Squares fitting the points (x,y) to a line through origin y : x -> b*x,
+ /// returning its best fitting parameter b,
+ /// where the intercept is zero and b the slope.
+ ///
+ public static double LineThroughOrigin(double[] x, double[] y)
+ {
+ return SimpleRegression.FitThroughOrigin(x, y);
+ }
+
+ ///
+ /// Least-Squares fitting the points (x,y) to a line through origin y : x -> b*x,
+ /// returning a function y' for the best fitting line.
+ ///
+ public static Func LineThroughOriginFunc(double[] x, double[] y)
+ {
+ double slope = SimpleRegression.FitThroughOrigin(x, y);
+ return z => slope * z;
+ }
+
///
/// Least-Squares fitting the points (X,y) = ((x0,x1,..,xk),y) to a linear surface y : X -> p0*x0 + p1*x1 + ... + pk*xk,
/// returning its best fitting parameters as [p0, p1, p2, ..., pk] array.
diff --git a/src/Numerics/LinearRegression/SimpleRegression.cs b/src/Numerics/LinearRegression/SimpleRegression.cs
index f3c6d162..16c72e48 100644
--- a/src/Numerics/LinearRegression/SimpleRegression.cs
+++ b/src/Numerics/LinearRegression/SimpleRegression.cs
@@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
-// Copyright (c) 2009-2013 Math.NET
+// Copyright (c) 2009-2018 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@@ -91,5 +91,56 @@ namespace MathNet.Numerics.LinearRegression
var xy = samples.UnpackSinglePass();
return Fit(xy.Item1, xy.Item2);
}
+
+ ///
+ /// Least-Squares fitting the points (x,y) to a line y : x -> b*x,
+ /// returning its best fitting parameter b,
+ /// where the intercept is zero and b the slope.
+ ///
+ /// Predictor (independent)
+ /// Response (dependent)
+ public static double FitThroughOrigin(double[] x, double[] y)
+ {
+ if (x.Length != y.Length)
+ {
+ throw new ArgumentException(string.Format(Resources.SampleVectorsSameLength, x.Length, y.Length));
+ }
+
+ if (x.Length <= 1)
+ {
+ throw new ArgumentException(string.Format(Resources.RegressionNotEnoughSamples, 2, x.Length));
+ }
+
+ double mxy = 0.0;
+ double mxx = 0.0;
+ for (int i = 0; i < x.Length; i++)
+ {
+ mxx += x[i]*x[i];
+ mxy += x[i]*y[i];
+ }
+
+ return mxy / mxx;
+ }
+
+
+ ///
+ /// Least-Squares fitting the points (x,y) to a line y : x -> b*x,
+ /// returning its best fitting parameter b,
+ /// where the intercept is zero and b the slope.
+ ///
+ /// Predictor-Response samples as tuples
+ public static double FitThroughOrigin(IEnumerable> samples)
+ {
+ double mxy = 0.0;
+ double mxx = 0.0;
+
+ foreach (var sample in samples)
+ {
+ mxx += sample.Item1 * sample.Item1;
+ mxy += sample.Item1 * sample.Item2;
+ }
+
+ return mxy / mxx;
+ }
}
}
diff --git a/src/UnitTests/FitTests.cs b/src/UnitTests/FitTests.cs
index e365a813..0a1b7808 100644
--- a/src/UnitTests/FitTests.cs
+++ b/src/UnitTests/FitTests.cs
@@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
-// Copyright (c) 2009-2016 Math.NET
+// Copyright (c) 2009-2018 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@@ -29,6 +29,8 @@
using System;
using System.Linq;
+
+using MathNet.Numerics.LinearRegression;
using MathNet.Numerics.Statistics;
using NUnit.Framework;
@@ -74,6 +76,28 @@ namespace MathNet.Numerics.UnitTests
}
}
+ [Test]
+ public void FitsToBestLineThroughOrigin()
+ {
+ // 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.LineThroughOrigin(x, y);
+ Assert.AreEqual(-0.467791, resp, 1e-4);
+
+ var resf = Fit.LineThroughOriginFunc(x, y);
+ foreach (var z in Enumerable.Range(-3, 10))
+ {
+ Assert.AreEqual(-0.467791 * z, resf(z), 1e-4);
+ }
+
+ var respSeq = SimpleRegression.FitThroughOrigin(Generate.Map2(x, y, Tuple.Create));
+ Assert.AreEqual(-0.467791, respSeq, 1e-4);
+ }
+
[Test]
public void FitsToMeanOnOrder0Polynomial()
{