Function Repository Resource:

OrthogonalLineFit

Source Notebook

Find the best fitting line with respect to orthogonal distance

Contributed by: Jan Mangaldan

ResourceFunction["OrthogonalLineFit"][data]

finds the best fitting orthogonal distance regression line to data.

Details

Orthogonal distance regression is also known as orthogonal least squares or total least squares.
The orthogonal distance regression line is the line for which its orthogonal distance from the given data is minimized.
ResourceFunction["OrthogonalLineFit"] returns an InfiniteLine object.

Examples

Basic Examples (2) 

Parameters for a 2D line:

In[1]:=
BlockRandom[SeedRandom[42, Method -> "ExtendedCA"];
 {p0, v0} = {RandomReal[{-2, 2}, 2], Normalize[RandomVariate[NormalDistribution[], 2]]}]
Out[1]=
Image

Generate some points near the line:

In[2]:=
BlockRandom[SeedRandom[42, Method -> "ExtendedCA"];
 pts = Table[
   p0 + t v0 + RandomVariate[NormalDistribution[0, 1/15], 2], {t, RandomReal[1, 25]}]]
Out[2]=
Image

Find the orthogonal distance regression line:

In[3]:=
ofit = ResourceFunction["OrthogonalLineFit"][pts]
Out[3]=
Image

Compare the regression line and the true line with the data:

In[4]:=
Legended[
 Graphics[{{Directive[AbsolutePointSize[6], Brown], Point[pts]},
   {Directive[AbsoluteThickness[2], ColorData[97, 1]], ofit},
   {Directive[AbsoluteThickness[2], ColorData[97, 3]], InfiniteLine[p0, v0]}}, Frame -> True, PlotRangeClipping -> True],
 LineLegend[{ColorData[97, 1], ColorData[97, 3]}, {"orthogonal fit", "true line"}]]
Out[4]=
Image

Parameters for a 3D line:

In[5]:=
BlockRandom[SeedRandom[42, Method -> "ExtendedCA"];
 {p0, v0} = {RandomReal[{-2, 2}, 3], Normalize[RandomVariate[NormalDistribution[], 3]]}]
Out[5]=
Image

Generate some points near the line:

In[6]:=
BlockRandom[SeedRandom[42, Method -> "ExtendedCA"];
 pts = Table[
   p0 + t v0 + RandomVariate[NormalDistribution[0, 1/8], 3], {t, RandomReal[1, 25]}]]
Out[6]=
Image

Find the orthogonal distance regression line:

In[7]:=
ofit = ResourceFunction["OrthogonalLineFit"][pts]
Out[7]=
Image

Compare the regression line and the true line with the data:

In[8]:=
Legended[
 Graphics3D[{{Directive[AbsolutePointSize[6], Brown], Point[pts]},
   {Directive[AbsoluteThickness[2], ColorData[97, 1]], ofit},
   {Directive[AbsoluteThickness[2], ColorData[97, 3]], InfiniteLine[p0, v0]}}, Axes -> True],
 LineLegend[{ColorData[97, 1], ColorData[97, 3]}, {"orthogonal fit", "true line"}]]
Out[8]=
Image

Scope (2) 

Here is a list of values:

In[9]:=
v = {1, 3, 7, 11, 19};

When coordinates are not given, OrthogonalLineFit assumes the values are to be paired up with 1,2,:

In[10]:=
ofit = ResourceFunction["OrthogonalLineFit"][v]
Out[10]=
Image
In[11]:=
ListPlot[v, Epilog -> {ColorData[97, 3], ofit}]
Out[11]=
Image

Properties and Relations (6) 

Here is some data:

In[12]:=
data = {{0., 1.}, {1., 0.}, {3., 2.}, {5., 4.}};

This computes the parameters for the orthogonal distance regression line using the definition:

In[13]:=
{pm, vm} = Partition[
  NArgMin[Total[
    RegionDistance[InfiniteLine[{px, py}, {vx, vy}], #]^2 & /@ data], {px, py, vx, vy}], 2]
Out[13]=
Image

Use OrthogonalLineFit to get the best-fit line:

In[14]:=
ofit = ResourceFunction["OrthogonalLineFit"][data]
Out[14]=
Image

Use RegionMember to compare the equations for the best fit line generated by both methods:

In[15]:=
Simplify[{RegionMember[InfiniteLine[pm, vm], {x, y}], RegionMember[ofit, {x, y}]}, {x, y} \[Element] Reals]
Out[15]=
Image

Construct a function from the orthogonal fit:

In[16]:=
oFun[x_] = Expand[y /. First[Solve[Last[%], y]]]
Out[16]=
Image

Compare the orthogonal fit with the conventional least-squares fit:

In[17]:=
lFun[x_] = Fit[data, {1, x}, x]
Out[17]=
Image
In[18]:=
Plot[{oFun[x], lFun[x]}, {x, 0, 5}, Epilog -> {Directive[AbsolutePointSize[4], ColorData[97, 4]], Point[data]}, PlotLegends -> {"orthogonal fit", "least-squares fit"}]
Out[18]=
Image

Version History

  • 1.0.0 – 01 February 2021

Source Metadata

Related Resources

License Information