9

I need to solve a large set of linear systems, in the least-squares sense. I am having trouble in understanding the difference in computational efficiency of numpy.linalg.lstsq(a, b), np.dot(np.linalg.pinv(a), b) and the mathematical implementation.

I use the following matrices:

h=np.random.random((50000,100))
a=h[:,:-1].copy()
b=-h[:,-1].copy()

and the results of the algorithms are:


# mathematical implementation
%%timeit
np.dot(np.dot(np.linalg.inv(np.dot(a.T,a)),a.T),b)

10 loops, best of 3: 36.3 ms per loop


# numpy.linalg.lstsq implementation
%%timeit
np.linalg.lstsq(a, b)[0]

10 loops, best of 3: 103 ms per loop


%%timeit
np.dot(np.linalg.pinv(a), b)

1 loop, best of 3: 216 ms per loop


Why is there a difference?

4
  • 2
    Why they should be the same? Commented Jan 14, 2017 at 9:20
  • mathematically they return the same result Commented Jan 14, 2017 at 15:52
  • @blaz Are you looking to optimize them further or are you satisfied with these approaches and just trying to understand the timing differences? Commented Jan 14, 2017 at 17:47
  • I am just trying to understand first :). Commented Jan 14, 2017 at 19:00

1 Answer 1

12

The routine lstsq handles any systems: over-determined, under-determined, or well-determined. Its output is what you'd get from pinv(a)*b but it is faster than computing the pseudoinverse. Here's why:

General advice: do not compute the inverse matrix unless you actually need it. Solving a system for a particular right hand side is faster than inverting its matrix.

Yet, your approach via solving aTa = aTb is faster, even though you are inverting a matrix. What gives? The thing is, inverting aTa is only valid when a has full column rank. So you've restricted the problem to this particular situation, and gained in speed as a trade off for less generality and, as I show below, for less safety.

But inverting a matrix is still inefficient. If you know that a has full column rank, the following is faster than any of your three attempts:

np.linalg.solve(np.dot(a.T, a), np.dot(a.T, b))

That said, lstsq is still preferable to the above when dealing with poorly conditioned matrices. Forming the product aTa basically squares the condition number, so you are more likely to get meaningless results. Here is a cautionary example, using SciPy's linalg module (which is essentially equivalent to NumPy's but has more methods):

import numpy as np
import scipy.linalg as sl
a = sl.hilbert(10)    # a poorly conditioned square matrix of size 10
b = np.arange(10)     # right hand side
sol1 = sl.solve(a, b)
sol2 = sl.lstsq(a, b)[0]
sol3 = sl.solve(np.dot(a.T, a), np.dot(a.T, b))

Here lstsq gives almost the same output as solve (the unique solution of this system). Yet, sol3 is totally wrong because of numeric issues (which you won't even be warned about).

sol1:

  [ -9.89821788e+02,   9.70047434e+04,  -2.30439738e+06,
     2.30601241e+07,  -1.19805858e+08,   3.55637424e+08,
    -6.25523002e+08,   6.44058066e+08,  -3.58346765e+08,
     8.31333426e+07]

sol2:

  [ -9.89864366e+02,   9.70082635e+04,  -2.30446978e+06,
     2.30607638e+07,  -1.19808838e+08,   3.55645452e+08,
    -6.25535946e+08,   6.44070387e+08,  -3.58353147e+08,
     8.31347297e+07]

sol3:

  [  1.06913852e+03,  -4.61691763e+04,   4.83968833e+05,
    -2.08929571e+06,   4.55280530e+06,  -5.88433943e+06,
     5.92025910e+06,  -5.56507455e+06,   3.62262620e+06,
    -9.94523917e+05]
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.