/nearest_correlation

Python versions of nearest correlation matrix algorithms

Primary LanguagePythonBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

Python versions of nearest correlation matrix algorithms.

Build Status

This module will eventually contain several algorithms for solving nearest correlation matrix problems.

The only algorithm currently implemented is Nick Higham's. The code in this module is a port of the MATLAB original at http://nickhigham.wordpress.com/2013/02/13/the-nearest-correlation-matrix/

Run the test suite as follows:

python nearest_correlation_unittests.py

An example computation that finds the nearest correlation matrix to the input matrix:

In [1]: from nearest_correlation import nearcorr

In [2]: import numpy as np

In [3]: A = np.array([[2, -1, 0, 0], 
   ...:               [-1, 2, -1, 0],
   ...:               [0, -1, 2, -1], 
   ...:               [0, 0, -1, 2]])

In [4]: X = nearcorr(A)

In [5]: X
Out[5]: 
array([[ 1.        , -0.8084125 ,  0.1915875 ,  0.10677505],
       [-0.8084125 ,  1.        , -0.65623269,  0.1915875 ],
       [ 0.1915875 , -0.65623269,  1.        , -0.8084125 ],
       [ 0.10677505,  0.1915875 , -0.8084125 ,  1.        ]])

Here's an example using the weights parameter. weights is a vector defining a diagonal weight matrix diag(W):.

In [1]: from nearest_correlation import nearcorr

In [2]: import numpy as np

In [3]: A = np.array([[1, 1, 0],
   ...:               [1, 1, 1],
   ...:               [0, 1, 1]])

In [4]: weights = np.array([1,2,3])

In [5]: X = nearcorr(A, weights = weights)

In [6]: X
Out[6]: 
array([[ 1.        ,  0.66774961,  0.16723692],
       [ 0.66774961,  1.        ,  0.84557496],
       [ 0.16723692,  0.84557496,  1.        ]])

By default, the maximum number of iterations allowed before the algorithm gives up is 100. This can be changed using the max_iterations parameter. When the number of iterations exceeds max_iterations an exception is raised unless except_on_too_many_iterations = False

In [7]: A = np.array([[1, 1, 0],
   ...:               [1, 1, 1],
   ...:               [0, 1, 1]])

In [8]: nearcorr(A,max_iterations=10)
---------------------------------------------------------------------------
ExceededMaxIterationsError                Traceback (most recent call last)
<ipython-input-8-a79bc46a3452> in <module>()
----> 1 nearcorr(A,max_iterations=10)

/Users/walkingrandomly/Dropbox/nearest_correlation/nearest_correlation.py in nearcorr(A, tol, flag, max_iterations, n_pos_eig, weights, verbose, except_on_too_many_iterations)
    106                     message = "No solution found in "\
    107                               + str(max_iterations) + " iterations"
--> 108                 raise ExceededMaxIterationsError(message, X, iteration, ds)
    109             else:
    110                 # exceptOnTooManyIterations is false so just silently

ExceededMaxIterationsError: 'No solution found in 10 iterations'

If except_on_too_many_iterations=False, the best matrix found so far is quiety returned.

In [10]: nearcorr(A,max_iterations=10,except_on_too_many_iterations=False)
Out[10]: 
array([[ 1.        ,  0.76073699,  0.15727601],
       [ 0.76073699,  1.        ,  0.76073699],
       [ 0.15727601,  0.76073699,  1.        ]])

Continuing failed computations

If a computation failed because the the number of iterations exceeded max_iterations, it is possible to continue by passing the exception obejct to nearcorr:

from nearest_correlation import nearcorr, ExceededMaxIterationsError
import numpy as np

A = np.array([[1, 1, 0],
              [1, 1, 1],
              [0, 1, 1]])

# Is one iteration enough?
try:
    X = nearcorr(A, max_iterations=1)
except ExceededMaxIterationsError as e:
    restart = e # capture the Exception object
    print("1 iteration wasn't enough")

# start from where we left off using the default number of `max_iterations`
X = nearcorr(restart)

# This will give the correct result
print(X)