126

I'm using numpy.linalg.eig to obtain a list of eigenvalues and eigenvectors:

A = someMatrixArray
from numpy.linalg import eig as eigenValuesAndVectors

solution = eigenValuesAndVectors(A)

eigenValues = solution[0]
eigenVectors = solution[1]

I would like to sort my eigenvalues (e.g. from lowest to highest), in a way I know what is the associated eigenvector after the sorting.

I'm not finding any way of doing that with python functions. Is there any simple way or do I have to code my sort version?

Jorge Leitao
  • 19,085
  • 19
  • 85
  • 121

3 Answers3

202

Use numpy.argsort. It returns the indices one would use to sort the array.

import numpy as np
import numpy.linalg as linalg

A = np.random.random((3,3))
eigenValues, eigenVectors = linalg.eig(A)

idx = eigenValues.argsort()[::-1]   
eigenValues = eigenValues[idx]
eigenVectors = eigenVectors[:,idx]

If the eigenvalues are complex, the sort order is lexicographic (that is, complex numbers are sorted according to their real part first, with ties broken by their imaginary part).

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 36
    Incidentally, it's more common to sort from largest to smallest eigenvalue. just use: `idx = eigenValues.argsort()[::-1]`. – Carl F. May 24 '13 at 12:21
  • 7
    to get k largest eigenvalues k=2 idx = eigenValues.argsort()[-k:][::-1] – mrgloom May 22 '14 at 07:18
  • 3
    For k=1 one can use `eigenVectors[:, eigenValues.argmax()]` – utapyngo Dec 08 '14 at 11:42
  • @CarlF. definitely a useful trick, but is it really more common? LAPACK (DSYEV) uses ascending order, I think that's a commonly used implementation (which Matlab and Python use)... Not that it really matters. upvote since it's useful trick anyway :-) – Mark Mar 27 '16 at 16:09
  • 2
    @MaxNoe: Per [the docs](https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.eig.html), "The eigenvalues are not necessarily ordered." – unutbu Sep 06 '17 at 17:05
  • 2
    Ah, i was using eigh: The eigenvalues in ascending order, each repeated according to its multiplicity. – MaxNoe Sep 06 '17 at 17:30
  • @utapyngo Thanks; these comments answered my question; "the eigenvalues are not necessarily ordered," but "the eigenvalues ARE associated with their respective eigenvectors" – Nathan majicvr.com Jan 08 '19 at 14:01
7

Above answer by unutbu is very crisp and concise. But, here is another way we can do it which more general and can be used for lists as well.

eval, evec =  sp.eig(A)
ev_list = zip( eval, evec )
ev_list.sort(key=lambda tup:tup[0], reverse=False)
eval, evec = zip(*ev_list)

This tup[0] is the eigenvalue based on which the sort function will sort the list.

reverse = False is for increasing order.

ShikharDua
  • 9,411
  • 1
  • 26
  • 22
  • AttributeError: 'zip' object has no attribute 'sort' =? could u help – nuri Jun 16 '22 at 23:16
  • I believe this is subtly wrong. When you zip the eigen values array and eigen vectors array together what happens is that each eigen value is paired with a *row* from the eigen vector array, but scipy returns eigen vectors as *columns* (i.e., evec[:,i] is the i-th eigen vector. ) In short the correct approach would be `zip(eval, evec.T)`. – kalebo Dec 02 '22 at 23:51
5

The ubuntu's piece of code doesn't work on my Python 3.6.5. It leads run-time errors. So, I refactored his/her code to this one which works ok on my test cases:

import numpy as np
from numpy import linalg as npla
#
def eigen(A):
    eigenValues, eigenVectors = npla.eig(A)
    idx = np.argsort(eigenValues)
    eigenValues = eigenValues[idx]
    eigenVectors = eigenVectors[:,idx]
    return (eigenValues, eigenVectors)
std.approach
  • 51
  • 1
  • 7