Generate multivariate normal r.v.'s with rank-deficient covariance via Pivoted Cholesky Factorization

前端 未结 1 1876
Happy的楠姐
Happy的楠姐 2020-12-21 18:39

I\'m just beating my head against the wall trying to get a Cholesky decomposition to work in order to simulate correlated price movements.

I use the following code:<

1条回答
  •  借酒劲吻你
    2020-12-21 19:14

    There are two errors with your code:

    1. You did not use pivoting index to revert the pivoting done to the Cholesky factor. Note, pivoted Cholesky factorization for a semi-positive definite matrix A is doing:

      P'AP = R'R
      

      where P is a column pivoting matrix, and R is an upper triangular matrix. To recover A from R, we need apply the inverse of P (i.e., P'):

      A = PR'RP' = (RP')'(RP')
      

      Multivariate normal with covariance matrix A, is generated by:

      XRP'
      

      where X is multivariate normal with zero mean and identity covariance.

    2. Your generation of X

      X <- array(rnorm(ncol(R)), dim = c(10000,ncol(R)))
      

      is wrong. First, it should not be ncol(R) but nrow(R), i.e., the rank of X, denoted by r. Second, you are recycling rnorm(ncol(R)) along columns, and the resulting matrix is not random at all. Therefore, cor(X) is never close to an identity matrix. The correct code is:

      X <- matrix(rnorm(10000 * r), 10000, r)
      

    As a model implementation of the above theory, consider your toy example:

    A <- matrix(c(1,.95,.90,.95,1,.93,.90,.93,1), ncol=3)
    

    We compute the upper triangular factor (suppressing possible rank-deficient warnings) and extract inverse pivoting index and rank:

    R <- suppressWarnings(chol(A, pivot = TRUE))
    piv <- order(attr(R, "pivot"))  ## reverse pivoting index
    r <- attr(R, "rank")  ## numerical rank
    

    Then we generate X. For better result we centre X so that column means are 0.

    X <- matrix(rnorm(10000 * r), 10000, r)
    ## for best effect, we centre `X`
    X <- sweep(X, 2L, colMeans(X), "-")
    

    Then we generate target multivariate normal:

    ## compute `V = RP'`
    V <- R[1:r, piv]
    
    ## compute `Y = X %*% V`
    Y <- X %*% V
    

    We can verify that Y has target covariance A:

    cor(Y)
    #          [,1]      [,2]      [,3]
    #[1,] 1.0000000 0.9509181 0.9009645
    #[2,] 0.9509181 1.0000000 0.9299037
    #[3,] 0.9009645 0.9299037 1.0000000
    
    A
    #     [,1] [,2] [,3]
    #[1,] 1.00 0.95 0.90
    #[2,] 0.95 1.00 0.93
    #[3,] 0.90 0.93 1.00
    

    0 讨论(0)
提交回复
热议问题