question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Orthogonal Distance Regression (ODR) not converging when I flip x and y input

See original GitHub issue

I’m having some trouble getting scipy’s Orthogonal Distance Regression (ODR) to converge on the same line if I flip the x input and y input (by same line, I mean I take the coefficients estimated by ODR, set y=0 and solve for x (or x=0 and solve for y when flipped) : y = mx + b x = my + b - the value of x is different when I flip x and y input). Because ODR should be calculating total least squares, the line should be the same no matter input order.

I’ve found that if I play with maxit and sstol I can get close to a convergence, but the values aren’t necessarily appropriate for every x/y pair.

Am I missing a step, or misunderstanding this? As you can see from the two figures below, when I flip x and y input I get different lines (you can visually tell they’re different by the number of points each intersects).

Reproducing code example:

import scipy.odr as odr  # orthogonal distance regression
import scipy
import seaborn as sns
from scipy.stats import linregress
import matplotlib.pyplot as plt
import pandas as pd

def linear_fit(coefs, x):
    '''Linear function y = m*x + b'''
    m,b = coefs
    return m*x + b

def perform_odr(x, y):
    OLS_m,OLS_b = linregress(x, y)[:2]  # estimate coefficients from OLS
    linmod = scipy.odr.Model(linear_fit)
    mydata = scipy.odr.Data(x, y)
    myodr = scipy.odr.ODR(mydata, linmod, beta0=[OLS_m, OLS_b]) #, maxit=75, sstol=0.000000001)
    return myodr.run()

def plot_odr(x, y, ax=None):
    """Plot Orthogonal Distance Regression line of best fit."""
    if ax is None:
        fig, ax = plt.subplots()

    fitted = perform_odr(x, y)
    
    fitted.pprint()
    print('y = %sx + %s' % tuple(round(coef, 5) for coef in fitted.beta))

    # extend line to boundaries of figure by adding points corresponding to xmin/xmax
    xlims = plt.xlim()
    ylims = plt.ylim()
    xnew = pd.Series(xlims[0]).append(x)
    xnew = xnew.append(pd.Series(xlims[1]))

    # plot
    plt.plot(xnew, linear_fit(fitted.beta, xnew), 'k-', linewidth=1.5, label='ODR regression', zorder=1)
    plt.xlim(xlims)
    plt.ylim(ylims)
    
    return ax, fitted



x = [25.88, 33.77, 26.55, 36.17, 36.57, 32.43, 38.65, 37.2, 33.57, 32.06, 25.48, 33.12, 26.24, 38.0, 37.25, 23.4, 34.28, 30.8, 34.22, 36.76, 30.46, 33.61, 35.32, 24.99, 39.23, 29.22, 32.54, 29.28, 31.31, 33.46, 28.06, 39.59, 28.98, 28.12, 27.21, 36.54, 25.35]

y = [0.05959377810359001, 0.06366157531738281, 0.03445526957511902, 0.021249201148748398, 0.013540455140173435, 0.033232174813747406, 0.02101573720574379, 0.021147532388567924, 0.014944841153919697, 0.02261320687830448, 0.04238538816571236, 0.02475816197693348, 0.04893920198082924, 0.01641816273331642, 0.02175772748887539, 0.029113013297319412, 0.019221415743231773, 0.019603392109274864, 0.01673588529229164, 0.020033005625009537, 0.02505655400454998, 0.03193040192127228, 0.02318655699491501, 0.032157305628061295, 0.017262479290366173, 0.02122090384364128, 0.04239807650446892, 0.028340162709355354, 0.02409830316901207, 0.029440563172101974, 0.026672156527638435, 0.010255633853375912, 0.02117013931274414, 0.027912333607673645, 0.020978346467018127, 0.015505819581449032, 0.02792999893426895]

fig, ax = plt.subplots()
plt.scatter(x,y)
ax,fit = plot_odr(x, y, ax)

fig, ax = plt.subplots()
plt.scatter(y,x)
ax,fit = plot_odr(y, x, ax)

Scipy/Numpy/Python version information:

import sys, scipy, numpy; print(scipy.__version__, numpy.__version__, sys.version_info)
1.6.2 1.20.2 sys.version_info(major=3, minor=8, micro=5, releaselevel='final', serial=0)

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:11 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
rkerncommented, Aug 17, 2021
1reaction
rkerncommented, Aug 17, 2021

I don’t think there is a bug. scipy.odr is a nonlinear solver, and it might not necessarily converge in the same way when representing what is conceptually the same problem in different ways.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Orthogonal distance regression (scipy.odr)
Why Orthogonal Distance Regression (ODR)? Sometimes one has measurement errors in the explanatory (a.k.a., “independent”) variable(s), not ...
Read more >
Linear Regression using scipy.ODR fails (Not full rank at ...
odr has worked for me before, and I don't see any errors in my code. The only reason I can think of is...
Read more >
Orthogonal Distance Regression - weight with two SDs?
I tried using /ODR=2 and weighting with /W=myY_SD, but still the other wave myX_SD should be used as weight. My data is parameters...
Read more >
Orthogonal distance regression using SciPy
Orthogonal regression is generally applied when both Y and X are susceptible to error and can also be applied to the transformable non-linear ......
Read more >
Orthogonal Distance Regression
Orthogonal Distance Regresson (ODR) is the name given to the com- ... At this point, we make no restrictions on the distribution of...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found