R/szbsvar.R

"szbsvar" <-
function(Y, p, z=NULL, lambda0, lambda1, lambda3, lambda4, lambda5,
         mu5, mu6, ident, qm=4){

    sanity.check.bsvar(list(Y=Y, p=p, z=z, lambda0=lambda0,
                           lambda1=lambda1, lambda3=lambda3,
                           lambda4=lambda4, lambda5=lambda5,
                           mu5=mu5, mu6=mu6, qm=qm, ident=ident))

    # Set up some constants we need
    m <- ncol(Y)                                  # number of endog variables
    nexog <- ifelse(is.null(z)==TRUE, 0, ncol(z)) # number of exog variables
    ncoef <- m*p + nexog + 1                      # plus 1 for the constant
    n<-nrow(Y);	 	                    # observations

    if(dim(ident)[1]!=m)
    {
        stop("Identification matrix 'ident' and dimension of 'Y' are nonconformable.")
    }


      # Compute the number of coefficients
    endog.ncoef<-(m*p)+1;  # AR coefficients plus intercept in each RF equation
    ndum<-m+1;             # of dummy observations
    capT<-n-p+ndum;        # degrees of freedom for the mixed estimation
    Ts<-n-p;  	     # # of actual data observations

      # Do some error checking of the identification scheme.
      # NEED to put this into the model.....

      # Define the linear restrictions from the identification matrix
      # for the free parameters

      # set up the linear restrictions for the parameters based on the A0
      # identification in ident
    Q <- array(0, c(m,m,m))
    for(i in 1:m)
    { Q[,,i] <- diag(ident[,i])
  }

      # Find the orthonormal bases for each of the Q matrices.  Need
      # thse because they define the null space for the squeezing the
      # parameters. This is just the null space for each matrix in Q.

    Ui <- sapply(1:m, function(i){null.space(Q[,,i])}, simplify=F)

      # Set up the prior

      # Prior mean of the regression parameters, Pi, for the ith equation
    Pi <- matrix(0, ncoef, m)
    diag(Pi) <- 1

      # Set up the prior for each equation using the resids from a
      # univariate AR model

      # Scale factors from univariate OLS
    s2i<-matrix(0,nrow=m,ncol=1)
    for(i in 1:m)
    {
        s2i[i,1] <- ar.ols(Y[,i], aic=FALSE,order.max=p,
                           intercept=TRUE,demean=FALSE)$var.pred
    }

      # Prior scale for A0 -- Si in the Waggoner and Zha notation
    S0 <- diag(m)
    diag(S0)<- 1/s2i

      # Prior for A+ or F coefficients -- same for all equations for now

      # Lag decays
      # create monthly lag decay to match 1/k decay in quarterly
      #  data where k = quarters
    if(qm==12)
    { j<-ceiling(p/3)^-lambda3;   	# last quarter (rounded up) eg. l2=13=>xx2=5
      b<-0
      if(p > 1)
      { b<-(log(1)-log(j))/(1-p) }
      a<-exp(-b);
  }

      # Find the lag decays for the variances over the p lags
    Aplus.prior.cov <- matrix(0, ncoef, 1)

      for(i in 1:p)
        { if(qm==12)
            { ld <- a*exp(b*i*lambda3) }
          for(j in 1:m)
            { if(qm==12)
                { Aplus.prior.cov[((i-1)*m+j),1] <- ld^2/s2i[j,1]
                } else {
                  Aplus.prior.cov[((i-1)*m+j),1] <- (1/i^lambda3)^2/s2i[j,1]
                }
            }
        }

      # Find the prior for A0 conditional prior variances
      A0.prior <- lambda0^2/s2i           # sg0bida
      Aplus.prior <- lambda0^2*lambda1^2*Aplus.prior.cov #sgpbida
      Aplus.prior[(m*p+1),1] <- (lambda0*lambda4)^2  # prior for intercept

      if(nexog>0)
        { Aplus.prior[(m*p+2):ncoef,1] <- lambda0^2*lambda5^2  # prior for eexog
        }

      Aplus.prior1 <- Aplus.prior[(m+1):ncoef,1] # sgppbd

      # Now compute the H matrices
      Hptd <- diag(as.vector(Aplus.prior))
      Hptdi <- diag(as.vector(1/Aplus.prior))

      # Now find the final covariance matrices for each of the i=1,..,m
      # equations.
      H0multi <- array(0, c(m, m, m))
      H0invmulti <- H0multi
      Hpmulti <- array(0, c(ncoef,ncoef,m))
      Hpmultiinv <- Hpmulti

      # This can be modified if we want to implement an asymmetric prior
      # across the columns (equations).
      H0td <- matrix(0, m, m)
      H0tdi <- H0td
      for (i in 1:m)
        { # A0 parts
          A0i <- A0.prior
          A0i.inv <- 1/A0i
          diag(H0td) <- A0i
          diag(H0tdi) <- 1/A0i
          H0multi[,,i] <- H0td
          H0invmulti[,,i] <- H0tdi

          # A+ parts
          Hpmulti[,,i] <- Hptd
          Hpmultiinv[,,i] <- Hptdi
        }

      # Now combine the prior with the linear restrictions --- maps from
      # a(i) and f(i) vectors into the b(i) and g(i) vectors of the
      # restricted model.  This is where we map from q(a_i, f_i) to
      # q(a_i, f_i | Q a_i = 0 and R f_i = 0)

      # This is where we make the Ptilde, H0tilde and Hptilde matrices for
      # the restricted system.

      Hpinv.tilde <- Hpmultiinv

      # Use sapply, since we do not know the size of the null spaces, so the
      # result needs to be dynamically sized

      Pi.tilde <- sapply(1:m, function(i){Pi%*%Ui[[i]]}, simplify=F)
      H0inv.tilde <- sapply(1:m, function(i)
                            {t(Ui[[i]])%*%H0invmulti[,,i]%*%Ui[[i]]}, simplify=F)

      # Set up the data
      # 1) Set up matrices of data and the moment matrices for the data

      # Test for the exogenous variables and check rank
      if (is.null(z))
        { num.exog <- 0 } else {
            num.exog <- ncol(z)
            z <- as.matrix(z)
            if(det(crossprod(cbind(rep(1,nrow(z)),z)))<=0)
            {
                stop("Matrix of exogenous variables, z has deficient rank.")
            }
        }

      # Create data matrix including dummy observations
      # X: Tx(m*p+1)
      # Y: Txm, ndum=m+1 prior dummy obs (sums of coeffs and coint).
      # mean of the first p data values = initial conditions
      if(p==1)
        { datint <- as.vector(Y[1,])
        } else {
          datint<-as.vector(apply(Y[1:p,],2,mean)) }

      # Y and X matrices with m+1 initial dummy observations
      X1<-matrix(0, nrow=capT, ncol=endog.ncoef)
      Y1<-matrix(0, nrow=capT, ncol=m)
      const<-matrix(1, nrow=capT)
      const[1:m,]<-0;	         # no constant for the first m periods
      X1[,endog.ncoef]<-const;

      # Build the dummy observations we need
      for(i in 1:m)
        {
          Y1[ndum,i]<-datint[i];
          Y1[i,i]<-datint[i];
          for(j in 1:p)
            { X1[ndum,m*(j-1)+i]<-datint[i];
              X1[i,m*(j-1)+i]<-datint[i];
            }
        }

      # Make the lags.  Note that constant is put last here when the lags are made
      for(i in 1:p)
        { X1[(ndum+1):capT,(m*(i-1)+1):(m*i)]<-matrix(Y[(p+1-i):(n-i),],ncol=m)
        }

      # Put on the exogenous regressors and make the constant the
      # first exog regressor after the AR coefs
      if(is.null(z)==F)
        {
          pad.z <- matrix(0,nrow=capT,ncol=ncol(z))
          pad.z[(ndum+1):capT,] <- matrix(z[(p+1):n,], ncol=ncol(z))
          X1<-cbind(X1,pad.z);
        }

      # 2) Dummy observations

      # Get the corresponding values of Y
      Y1[(ndum+1):capT,]<-matrix(Y[(p+1):n,],ncol=m);

      # Weight dummy observations
      X1[1:m,]<-mu5*X1[1:m,];
      Y1[1:m,]<-mu5*Y1[1:m,];
      X1[ndum,]<-mu6*X1[ndum,];
      Y1[ndum,]<-mu6*Y1[ndum,];

      # 3) Get moment matrices
      XX <- crossprod(X1)
      XY <- crossprod(X1, Y1)
      YY <- crossprod(Y1)

      # Compute the posterior moments -- combine the data and the
      # prior.  These are the posterior moments needed for the results
      # in Waggoner and Zha 2003, JEDC, eqns. 12 and 13 (the H_iu,
      # P_i, S_i below these equations

      # H_i^-1 matrices for equations 1...m
      Hpinv.posterior <- sapply(1:m, function(i) { XX + Hpinv.tilde[,,i] },
                                simplify=F)

      # Next two build the P_i, the "squeezed" matrices of the SVAR parameters
      P1.posterior <- sapply(1:m,
                             function(i) { XY%*%Ui[[i]] +
                                             Hpinv.tilde[,,i]%*%Pi.tilde[[i]] }, simplify=F)

      P.posterior <- sapply(1:m, function(i)
                            {solve(Hpinv.posterior[[i]])%*%P1.posterior[[i]] },
                            simplify=F)

      # S_i matrices are next -- these are the SVAR covariances for
      # the columns of A0, a_i.  Note that we do NOT include the
      # scaling by 1/T because this is not necessary for the posterior
      # draws.

      H0inv.posterior <- sapply(1:m, function(i)
                                { (t(Ui[[i]])%*%YY%*%Ui[[i]] + H0inv.tilde[[i]] +
                                   t(Pi.tilde[[i]])%*%Hpinv.tilde[,,i]%*%Pi.tilde[[i]] -
                                   t(P1.posterior[[i]])%*%P.posterior[[i]])
                          }, simplify=F)

      # Optimize the likelihood to solve for A0 parameters (the b's in
      # the "squeezed" model.  Here we are numerically computing the
      # peak of the PDF -- makes for more efficient draws from the
      # posterior later.

      # Find # free parameters in each equation and a vector of the
      # cusum for indexing them

      n0 <- sapply(1:m, function(i) {ncol(as.matrix(Ui[[i]]))})
      n0cum <- c(0,cumsum(n0))
      # Generate some random starting values.
      b <- (1/max(s2i))*(rnorm(sum(n0)))

      # Optimize the log posterior wrt A0.

      # Start with some Nelder-Mead simplex steps to get things
      # started in the right direction.
      cat("Estimating starting values for the numerical optimization\nof the log posterior of A(0)\n")

      max.obj <- optim(b, A0.llf, method=c("Nelder-Mead"),
                       control=list(maxit=6000, fnscale=capT, trace=0),
                       Ui=Ui, df=capT, H0inv.posterior=H0inv.posterior)

      # Do the final optimization with BFGS.
      cat("Estimating the final values for the numerical optimization\nof the log posterior of A(0)\n")

      max.obj <- optim(max.obj$par, A0.llf, method=c("BFGS"), hessian=F,
                       control=list(maxit=5000, fnscale=capT, trace=1),
                       Ui=Ui, df=capT,
                       H0inv.posterior=H0inv.posterior)

      # Check for convergence
      if(max.obj$convergence!=0)
        {
          stop("Estiamtes of A(0) did not converge.  You should restart the function with a new seed.")
        }


      # Build back the A0 from the b's estimated at the peak of the
      # log posterior pdf.

      # Estimate of A0 at the peak of the log-posterior.
      A0.mode <- b2a(max.obj$par, Ui)

      # Estimates of the SVAR posterior coefs for the lagged and
      # exogenous variables -- the F matrix defined in equations 13
      # and on page 351.

      # Build back the A+ and F coefficients from the sub-space of the SVAR
      # back to the unrestricted parameter space

      F.posterior <- matrix(0, ncoef, m)

      for (i in 1:m)
        { bj <- max.obj$par[(n0cum[i]+1):(n0cum[(i+1)])]
          gj <- P.posterior[[i]]%*%bj
          F.posterior[,i] <- gj
        }

      # Now map it all back to reduced form coefficients
      B.posterior <- F.posterior%*%solve(A0.mode)

      # Pluck out the arrays of the AR coefficients

      AR.coefs.posterior <- t(B.posterior[1:(m*p),])
      dim(AR.coefs.posterior) <- c(m,m,p)
      AR.coefs.posterior <- aperm(AR.coefs.posterior, c(2,1,3))

      # compute the structural innovations
      structural.innovations <- Y1%*%A0.mode - X1%*%F.posterior

      # reduced form exogenous coefficients
      if(nexog==0){
          exog.coefs <- NA
      } else {
          exog.coefs <- B.posterior[((m*p)+2):nrow(B.posterior),]
      }

    # gc() call for some cleanup
    gc(); gc();

      # Now build an output list / object for the B-SVAR model
    output <- list(XX=XX,                               # data matrix moments with dummy obs
                   XY=XY,
                   YY=YY,
                   y=Y,
                   Y=Y1,
                   X=X1,
                   structural.innovations=structural.innovations,
                   Ui=Ui,                                         # restriction transformation
                   Hpinv.tilde=Hpinv.tilde,    # Prior moments
                   H0inv.tilde=H0inv.tilde,
                   Pi.tilde=Pi.tilde,
                   Hpinv.posterior=Hpinv.posterior,
                   P.posterior=P.posterior,
                   H0inv.posterior=H0inv.posterior,
                   A0.mode=A0.mode,
                   F.posterior=F.posterior,
                   B.posterior=B.posterior,
                   ar.coefs=AR.coefs.posterior,
                   intercept=B.posterior[(m*p+1),],
                   exog.coefs=exog.coefs,
                   prior=c(lambda0,lambda1,lambda3,lambda4,lambda5,mu5,mu6),
                   df=capT,
                   n0=n0,
                   ident=ident,
                   b=max.obj$par
                   )
    class(output) <- c("BSVAR")
    attr(output, "eqnames") <- colnames(Y) # Get variable names for
                                           # attr

    return(output)
}


# Summary function for BSVAR models
"summary.BSVAR" <- function(object, ...)
{
    # Get p
    p <- dim(object$ar.coefs)[3]

    cat("------------------------------------------\n")
    cat("A0 restriction matrix\n")
    cat("------------------------------------------\n")
    prmatrix(object$ident)
    cat("\n")

    cat("------------------------------------------\n")
    cat("Sims-Zha Prior Bayesian Structural VAR\n")
    cat("------------------------------------------\n")
##     if(object$prior.type==0) prior.text <- "Normal-inverse Wishart"
##     if(object$prior.type==1) prior.text <- "Normal-flat"
##     if(object$prior.type==2) prior.text <- "Flat-flat"

    cat("Prior form : Sims-Zha\n")
    cat("Prior hyperparameters : \n")
    cat("lambda0 =", object$prior[1], "\n")
    cat("lambda1 =", object$prior[2], "\n")
    cat("lambda3 =", object$prior[3], "\n")
    cat("lambda4 =", object$prior[4], "\n")
    cat("lambda5 =", object$prior[5], "\n")
    cat("mu5     =", object$prior[6], "\n")
    cat("mu6     =", object$prior[7], "\n")
    cat("nu      =", dim(object$ar.coefs)[1]+1, "\n")

    cat("------------------------------------------\n")
    cat("Number of observations : ", nrow(object$Y), "\n")
    cat("Degrees of freedom per equation : ", nrow(object$Y)-nrow(object$Bhat), "\n")
    cat("------------------------------------------\n")

    cat("Posterior Regression Coefficients :\n")
    cat("------------------------------------------\n")
    cat("Reduced Form Autoregressive matrices: \n")
    for (i in 1:dim(object$ar.coefs)[3])
    {
        cat("B(", i, ")\n", sep="")
        prmatrix(round(object$ar.coefs[,,i], 6))
        cat("\n")
    }
    cat("------------------------------------------\n")
    cat("Reduced Form Constants\n")
    cat(round(object$intercept,6), "\n")
    cat("------------------------------------------\n")

    if(nrow(object$B.posterior)>m*p + 1)
    {
        cat("------------------------------------------\n")
        cat("Reduced Form Exogenous coefficients\n")
        prmatrix(object$B.posterior[(m*p+2):nrow(object$B.posterior),])
        cat("\n")
        cat("------------------------------------------\n")
    }

    # Now print the structural coefficients in the same way as the
    # RFs.
    cat("Structural Autoregressive matrices: \n")
    m <- dim(object$ar.coefs)[1]
    p <- dim(object$ar.coefs)[3]
    struct.ar <- object$F.posterior[1:(m*p),]
    dim(struct.ar) <- c(m, m, p)
    struct.ar <- aperm(struct.ar, c(2,1,3))
    for (i in 1:p)
    {
        cat("A(", i, ")\n", sep="")
        prmatrix(round(struct.ar[,,i], 6))
        cat("\n")
    }
    cat("------------------------------------------\n")
    cat("Structural Constants\n")
    cat(round(object$F.posterior[(m*p +1),],6), "\n")
    cat("------------------------------------------\n")

    if(nrow(object$B.posterior)>m*p + 1)
    {
        cat("------------------------------------------\n")
        cat("Structural Exogenous coefficients\n")
        prmatrix(object$F.posterior[(m*p+2):nrow(object$F.posterior),])
        cat("\n")
        cat("------------------------------------------\n")
    }


    cat("------------------------------------------\n")
    cat("Posterior mode of the A0 matrix\n")
    prmatrix(round(object$A0.mode,6))
    cat("\n")
    cat("------------------------------------------\n")

}

Try the MSBVAR package in your browser

Any scripts or data that you put into this service are public.

MSBVAR documentation built on May 30, 2017, 1:23 a.m.