nearPD                package:Matrix                R Documentation

_N_e_a_r_e_s_t _M_a_t_r_i_x _t_o _a _P_o_s_i_t_i_v_e _D_e_f_i_n_i_t_e _M_a_t_r_i_x

_D_e_s_c_r_i_p_t_i_o_n:

     Computes the nearest positive definite matrix to an approximate
     one, typically a correlation or variance-covariance matrix.

_U_s_a_g_e:

     nearPD(x, corr = FALSE, keepDiag = FALSE, do2eigen = TRUE,
            only.values = FALSE,
            eig.tol = 1e-06, conv.tol = 1e-07, posd.tol = 1e-08,
            maxit = 100, trace = FALSE)

_A_r_g_u_m_e_n_t_s:

       x: numeric n * n approximately positive definite matrix,
          typically an approximation to a correlation or covariance
          matrix.

    corr: logical indicating if the matrix should be a _correlation_
          matrix.

keepDiag: logical, generalizing 'corr': if 'TRUE', the resulting matrix
          should have the same diagonal ('diag(x)') as the input
          matrix.

do2eigen: logical indicating if a 'posdefify()' eigen step should be
          applied to the result of the Higham algorithm.

only.values: logical; if 'TRUE', the result is just the vector of eigen
          values of the approximating matrix.

 eig.tol: defines relative positiveness of eigenvalues compared to
          largest one, lambda_1. Eigen values lambda_k are treated as
          if zero when lambda_k / lambda_1 <= eig.tol.

conv.tol: convergence tolerance for Higham algorithm.

posd.tol: tolerance for enforcing positive definiteness (in the final
          'posdefify' step when 'do2eigen' is 'TRUE').

   maxit: maximum number of iterations allowed.

   trace: logical or integer specifying if convergence monitoring
          should be traced.

_D_e_t_a_i_l_s:

     This implements the algorithm of Higham (2002), and then forces
     positive definiteness using code from 'posdefify'.  The algorithm
     of Knol DL and ten Berge (1989) (not implemented here) is more
     general in (1) that it allows constraints to fix some rows (and
     columns) of the matrix and (2) to force the smallest eigenvalue to
     have a certain value.

     Note that setting 'corr = TRUE' just sets 'diag(.) <- 1' within
     the algorithm.

_V_a_l_u_e:

     If 'only.values = TRUE', a numeric vector of eigen values of the
     approximating matrix; Otherwise, as by default, an S3 object of
     'class' '"nearPD"', basically a list with components 

     mat: a matrix of class 'dpoMatrix', the computed positive-definite
          matrix.

eigenvalues: numeric vector of eigen values of 'mat'.

    corr: logical, just the argument 'corr'.

   normF: the Frobenius norm ('norm(x-X, "F")') of the difference
          between the original and the resulting matrix.

iterations: number of iterations needed.

converged: logical indicating if iterations converged.

_A_u_t_h_o_r(_s):

     Jens Oehlschlaegel donated a first version.  Subsequent changes by
     the Matrix package authors.

_R_e_f_e_r_e_n_c_e_s:

     Cheng, Sheung Hun and Higham, Nick (1998) A Modified Cholesky
     Algorithm Based on a Symmetric Indefinite Factorization; _SIAM J.
     Matrix Anal. Appl._, *19*, 1097-1110.

     Knol DL, ten Berge JMF (1989) Least-squares approximation of an
     improper correlation matrix by a proper one. _Psychometrika_ *54*,
     53-61.

     Higham, Nick (2002) Computing the nearest correlation matrix - a
     problem from finance; _IMA Journal of Numerical Analysis_ *22*,
     329-343.

_S_e_e _A_l_s_o:

     A first version of this (with non-optional 'corr=TRUE') has been
     available as 'nearcor()'; and more simple versions with a similar
     purpose 'posdefify()', both from package 'sfsmisc'.

_E_x_a_m_p_l_e_s:

      set.seed(27)
      m <- matrix(round(rnorm(25),2), 5, 5)
      m <- m + t(m)
      diag(m) <- pmax(0, diag(m)) + 1
      (m <- round(cov2cor(m), 2))

      str(near.m <- nearPD(m, trace = TRUE))
      round(near.m$mat, 2)
      norm(m - near.m$mat) # 1.102

      if(require("sfsmisc")) {
         m2 <- posdefify(m) # a simpler approach
         norm(m - m2)  # 1.185, i.e., slightly "less near"
      }

      round(nearPD(m, only.values=TRUE), 9)

     ## A longer example, extended from Jens' original,
     ## showing the effects of some of the options:

     pr <- Matrix(c(1,     0.477, 0.644, 0.478, 0.651, 0.826,
                    0.477, 1,     0.516, 0.233, 0.682, 0.75,
                    0.644, 0.516, 1,     0.599, 0.581, 0.742,
                    0.478, 0.233, 0.599, 1,     0.741, 0.8,
                    0.651, 0.682, 0.581, 0.741, 1,     0.798,
                    0.826, 0.75,  0.742, 0.8,   0.798, 1),
                  nrow = 6, ncol = 6)

     nc.  <- nearPD(pr, conv.tol = 1e-7) # default
     nc.$iterations  # 2
     nc.1 <- nearPD(pr, conv.tol = 1e-7, corr = TRUE)
     nc.1$iterations # 11 (!)
     ncr   <- nearPD(pr, conv.tol = 1e-15)
     str(ncr)# 3 iterations
     ncr.1 <- nearPD(pr, conv.tol = 1e-15, corr = TRUE)
     ncr.1 $ iterations #  27 !

     ## But indeed, the 'corr = TRUE' constraint did ensure a better solution;
     ## cov2cor() does not just fix it up equivalently :
     norm(pr - cov2cor(ncr$mat)) # = 0.09994
     norm(pr -       ncr.1$mat)  # = 0.08746

