R/TVARestim.R

Defines functions grid condiStep onesearch nameB toLatex.TVAR plot.TVAR plot3 plot2 plot1 print.summary.TVAR summary.TVAR print.TVAR TVAR

Documented in TVAR

#'Multivariate Threshold Vector Autoregressive model
#'
#'Estimate a multivariate Threshold VAR (TVAR), either using lags as transition variable (default),
#'or specifying an external variable. 
#'
#'For fixed \code{th} and threshold variable, the model is linear, so
#'estimation can be done directly by CLS (Conditional Least Squares). The
#'search of the parameters values is made upon a grid of potential values. So
#'it is pretty slow.
#'
#'nthresh=1: estimation of one threshold model (two regimes) upon a grid of
#'\var{ngrid} values (default to ALL) possible thresholds and delays values.
#'
#'nthresh=2: estimation of two thresholds model (three regimes) Conditional on
#'the threshold found in model where nthresh=1, the second threshold is
#'searched. When both are found, a second grid search is made with 30 values
#'around each threshold.
#'
#'nthresh=3: DOES NOT estimate a 3 thresholds model, but a 2 thresholds model
#'with a whole grid over the thresholds parameters (so is really slow) with a
#'given delay, is there rather to check the consistency of the method nthresh=2
#'
#'@aliases TVAR OlsTVAR
#'@param data time series
#'@param lag Number of lags to include in each regime
#'@param include Type of deterministic regressors to include
#'@param model Whether the transition variable is taken in levels (TAR) or
#'difference (MTAR)
#'@param commonInter Whether the deterministic regressors are regime specific
#'(\code{commonInter}=FALSE) or not.
#'@param nthresh Number of thresholds
#'@param thDelay 'time delay' for the threshold variable (as multiple of
#'embedding time delay d) PLEASE NOTE that the notation is currently different
#'to univariate models in tsDyn. The left side variable is taken at time t, and
#'not t+1 as in univariate cases.
#'@param mTh combination of variables with same lag order for the transition
#'variable. Either a single value (indicating which variable to take) or a
#'combination
#'@param thVar Optional. External transition variable. 
#'@param trim trimming parameter indicating the minimal percentage of
#'observations in each regime
#'@param ngrid number of elements of the grid, especially for \code{nthresh=3}
#'@param gamma prespecified threshold values
#'@param around The grid search is restricted to \var{ngrid} values around this
#'point. Especially useful for \code{nthresh=3}.
#'@param plot Whether a plot showing the results of the grid search should be
#'printed
#'@param dummyToBothRegimes Whether the dummy in the one threshold model is
#'applied to each regime or not.
#'@param trace should additional infos be printed out?
#'@param trick type of R function called: \code{for} or \code{mapply}
#'@param max.iter Number of iterations for the algorithm
#'@return An object of class TVAR, with standard methods.
#'@author Matthieu Stigler
#'@seealso \code{\link{lineVar}} for the linear VAR/VECM,
#'\code{\link{TVAR.LRtest}} to test for TVAR, \code{\link{TVAR.sim}} to
#'simulate/bootstrap a TVAR.
#'@references Lo and Zivot (2001) "Threshold Cointegration and Nonlinear
#'Adjustment to the Law of One Price," Macroeconomic Dynamics, Cambridge
#'University Press, vol. 5(4), pages 533-76, September.
#'@keywords ts
#'@export
#'@examples
#'
#'data(zeroyld)
#'
#'tv <- TVAR(zeroyld, lag=2, nthresh=2, thDelay=1, trim=0.1, mTh=1, plot=FALSE)
#'
#'print(tv)
#'summary(tv)
#'
#'# a few useful methods:
#'plot(tv)
#'predict(tv)
#'c(AIC(tv), BIC(tv), logLik(tv))
TVAR <- function(data, lag, include = c( "const", "trend","none", "both"), model=c("TAR", "MTAR"), commonInter=FALSE, nthresh=1,thDelay=1, mTh=1,thVar, trim=0.1,ngrid, gamma=NULL,  around, plot=FALSE, dummyToBothRegimes=TRUE, trace=TRUE, trick="for", max.iter=2){
  
  ## arg matching
  model<-match.arg(model)
  include<-match.arg(include)
  
  y <- as.matrix(data)
  Torigin <- nrow(y) 	#Size of original sample
  T <- nrow(y) 		#Size of start sample
  p <- lag
  t <- T-p 		#Size of end sample
  k <- ncol(y) 		#Number of variables
  t<-T-p			#Size of end sample
  
  
  if(is.null(colnames(data)))
    colnames(data)<-paste("Var", c(1:k), sep="")
  if(max(thDelay)>p)
    stop("Max of thDelay should be smaller or equal to the number of lags")
  if(dummyToBothRegimes==FALSE&nthresh!= 1) 
    warning("The 'dummyToBothRegimes' argument is only relevant for one threshold models")
  
  Y <- y[(p+1):T,] #
  Z <- embed(y, p+1)[, -seq_len(k)]	#Lags matrix
  
  if(include=="const")
    Z<-cbind(1, Z)
  else if(include=="trend")
    Z<-cbind(seq_len(t), Z)
  else if(include=="both")
    Z<-cbind(rep(1,t),seq_len(t), Z)
  if(commonInter & include!="const")
    stop("commonInter argument only available with include = const")
  npar <- ncol(Z)			#Number of parameters
  
  
  ########################
  ### Threshold variable
  ########################
  
  ###External threshold variable
  if (!missing(thVar)) {		
    if (length(thVar) > Torigin) {
      z <- thVar[seq_len(Torigin)]
      warning("The external threshold variable is not of same length as the original variable")
    } else {
      z <- thVar
    }
    z<-embed(z,p+1)[,seq_len(max(thDelay))+1]		#if thDelay=2, ncol(z)=2
    combin<-NULL
  } ###Combination (or single value indicating position) of contemporaneous variables
  else {
    if (!length(mTh)%in%c(1,k))
      stop("length of 'mTh' should be equal to the number of variables, or just one")
    if(length(mTh)==1) {
      if(mTh>k)
        stop("Unable to select the ",mTh, "variable for the threshold. Please see again mTh ")
      combin <- matrix(0,ncol=1, nrow=k)
      combin[mTh,]<-1
    } else { 
      combin<-matrix(mTh,ncol=1, nrow=k)
    }
    zcombin <- y %*% combin
    if(model=="MTAR"){
      if(max(thDelay)<p) {
        z<-embed(diff(zcombin),p)[,seq_len(max(thDelay))+1]
      } else if(max(thDelay)==p){ {
        z<-embed(diff(zcombin),p+1)[,seq_len(max(thDelay))+1]
      }
        z<-rbind(0,as.matrix(z))}
    } else {
      z <- embed(zcombin,p+1)[,seq_len(max(thDelay))+1]		#if thDelay=2, ncol(z)=2
    }
  }
  
  trans<-as.matrix(z)
  
  ###############################
  ###Grid for transition variable
  ###############################
  
  allgammas <- sort(unique(trans[,1]))
  nga <- length(allgammas)
  ninter <- round(trim*nga)
  gammas <- allgammas[(trim*nga):((1-trim)*nga)]
  
  
  
  if(!missing(ngrid)){
    gammas <- allgammas[seq(from=ceiling(trim*nga), to=floor((1-trim)*nga), length.out=ngrid)]
  }
  if(!missing(gamma)){
    gammas<-gamma
    plot<-FALSE
  }
  
  Y_t<-t(Y)					#dim k x t
  
  if(!missing(around)){
    if(missing(ngrid)) ngrid<-20
    if(length(around)==1)
      gammas <- aroundGrid(around, allgammas,ngrid,trim, trace=trace)
    if(length(around)==2) {
      gammas <- aroundGrid(around[1], allgammas,ngrid,trim, trace=trace)
      gammas2 <- aroundGrid(around[2], allgammas,ngrid,trim, trace=trace)
    }
  }
  
  ######################
  ###One threshold functions					
  ######################
  
  #Model with dummy applied to only one regime
  loop1_onedummy <- function(gam1, thDelay){
    ##Threshold dummies
    dummyDown <- ifelse(trans[,thDelay]<=gam1, 1,0) * Z
    ndown<-mean(dummyDown)
    regimeDown<-dummyDown*Z
    ##SSR
    if(min(ndown, 1-ndown)>=trim){
      Z1 <- cbind(regimeDown, Z)		# dim t x k(p+1) 
      res <- crossprod(c(lm.fit(x=Z1, y=Y)$resid))
    }	else {
      res<-NA
    }
    return(res)
  } #end of the function
  
  
  #Model with dummy applied to both regimes
  loop1_twodummy <- function(gam1, thDelay){
    ##Threshold dummies
    d1<-ifelse(trans[,thDelay]<=gam1, 1,0)
    ndown<-mean(d1)
    ##SSR
    if(min(ndown, 1-ndown)>=trim){
      Z1 <- cbind(d1 * Z, (1-d1)*Z)    # dim k(p+1) x t
      res <- crossprod(c(lm.fit(x=Z1, y=Y)$resid))
    }	else{
      res<-NA
    }
    return(res)
  } #end of the function
  
  #Model with dummy applied to both regimes and a common intercept
  loop1_twodummy_oneIntercept <- function(gam1, thDelay){
    ##Threshold dummies
    d1<-ifelse(trans[,thDelay]<=gam1, 1,0)
    ndown<-mean(d1)
    if(min(ndown, 1-ndown)>=trim){
      Z1 <- cbind(1,d1 * Z[,-1], (1-d1)*Z[,-1])		# dim k(p+1) x t
      res <- crossprod(c(lm.fit(x=Z1, y=Y)$resid)) 
    } else {
      res<-NA
    }
    return(res)
  } #end of the function
  
  
  #######################
  ###Two thresholds functions
  #######################
  
  loop2 <- function(gam1, gam2,thDelay){
    ##Threshold dummies
    dummydown <- ifelse(trans[,thDelay]<=gam1, 1, 0)
    regimedown <- dummydown*Z
    ndown <- mean(dummydown)
    dummyup <- ifelse(trans[,thDelay]>gam2, 1, 0)
    regimeup <- dummyup*Z
    nup <- mean(dummyup)
    ##SSR from TVAR(3)
    #print(c(ndown,1-nup-ndown,nup))
    if(min(nup, ndown, 1-nup-ndown)>trim){
      Z2 <- cbind(regimedown, (1-dummydown-dummyup)*Z, regimeup)		# dim k(p+1) x t
      res <- crossprod(c(lm.fit(x=Z2, y=Y)$resid)) 
    }
    else
      res <- NA
    return(res)
  }
  
  loop2_oneIntercept <- function(gam1, gam2,thDelay){
    ##Threshold dummies
    dummydown <- ifelse(trans[,thDelay]<=gam1, 1, 0)
    regimedown <- dummydown*Z[,-1]
    ndown <- mean(dummydown)
    dummyup <- ifelse(trans[,thDelay]>gam2, 1, 0)
    regimeup <- dummyup*Z[,-1]
    nup <- mean(dummyup)
    ##SSR from TVAR(3)
    #print(c(ndown,1-nup-ndown,nup))
    if(min(nup, ndown, 1-nup-ndown)>trim){
      Z2 <- cbind(1,regimedown, (1-dummydown-dummyup)*Z, regimeup)		# dim k(p+1) x t	
      res <- crossprod(c(lm.fit(x=Z2, y=Y)$resid)) 
    }
    else
      res <- NA
    return(res)
  }
  ############################
  ###Search for one threshold
  ############################
  if(!missing(around))
    gammas <- aroundGrid(around,allgammas,ngrid,trim, trace=trace)
  if(dummyToBothRegimes){
    if(commonInter)
      func<-loop1_twodummy_oneIntercept
    else
      func <-loop1_twodummy
  } else {	
    func <- loop1_onedummy
  }
  
  bestone <- onesearch(thDelay,gammas, fun=func, trace=trace, gamma=gamma, plot=plot)
  bestThresh <- bestone$bestThresh
  bestDelay <- bestone$bestDelay
  allThSSR<-bestone$allres
  
  
  ############################
  ###Search for two threshold
  ############################
  
  
  if(nthresh==2){
    ###Conditionnal step
    if(commonInter)
      func2<-loop2_oneIntercept
    else
      func2<-loop2
    # secondBestThresh<-condiStep(allgammas, threshRef=bestThresh, delayRef=bestDelay,ninter=ninter, fun=func2)$newThresh
    # step2FirstBest<-condiStep(allgammas, threshRef=secondBestThresh, delayRef=bestDelay,ninter=ninter, fun=func2)
    
    last<-condiStep(allgammas, threshRef=bestThresh, delayRef=bestDelay, fun=func2, trim=trim, trace=trace)
    i<-1
    while(i<max.iter){
      b<-condiStep(allgammas, threshRef=last$newThresh, delayRef=bestDelay, fun=func2, trim=trim, trace=trace)
      if(b$SSR<last$SSR){	#minimum still not reached
        i<-i+1
        last<-b}
      else{			#minimum reached
        i<-max.iter
        last<-b}
    }
    
    bests<-c(last$threshRef, last$newThresh)
    
    ###Alternative step: grid around the points from first step
    smallThresh <- min(bests)		#bestThresh,secondBestThresh)
    gammasDown <- aroundGrid(around=smallThresh,allgammas,ngrid=30, trim=trim, trace=trace)
    
    bigThresh <- max(bests)			#bestThresh,secondBestThresh)
    gammasUp <- aroundGrid(around=bigThresh,allgammas,ngrid=30, trim=trim, trace=trace)
    
    bestThresh<-grid(gammasUp, gammasDown, fun=func2, method=trick, thDelay=bestDelay, trace=trace)
    
  }#end if nthresh=2
  
  ###Search both thresholds with d given
  
  if(nthresh==3){
    bestDelay <- thDelay
    if(missing(gamma)==FALSE){
      gammas <- gamma[1]
      gammas2 <- gamma[2]
      ninter<- 2
      cat("To be corrected!!")
    }
    if(missing(around)==FALSE){
      if(length(around)!=2)
        stop("Please give two thresholds possible values to search around")
      gammas <- aroundGrid(min(around), allgammas, ngrid=ngrid, trim=trim, trace=trace)
      gammas2 <- aroundGrid(max(around), allgammas, ngrid=ngrid, trim=trim, trace=trace)
    }
    else {
      gammas2 <- gammas
      if(length (gammas) * length(gammas2)/2>10000)
        cat("The function will compute about", length(gammas)*length(gammas2)/2, "operations. Take a coffee and come back\n")
    }
    if(length(thDelay)>1) stop("length of thDelay should not be bigger than 1. The whole search is made only upon the thresholds with given delay")
    
    store3 <- matrix(NA,ncol=length(gammas2), nrow=length(gammas))
    
    ###Loop
    for(i in seq_len(length(gammas))){
      gam1 <- gammas[i]
      for (j in seq_len(length(gammas))){
        gam2 <- gammas2[j]
        store3[i,j] <- loop2(gam1, gam2, thDelay=bestDelay)
      }
    }
    
    position <- which(store3==min(store3, na.rm=TRUE), arr.ind=TRUE)
    r <- position[1]
    c <- position[2]
    
    gamma1 <- gammas[r]
    gamma2 <- gammas2[c]
    bestThresh <- c(gamma1, gamma2)
    
  }#end n
  
  ##################################
  ###Best Model: set variables
  ##################################
  val <- if(commonInter) 1 else -(seq_len(ncol(Z)))
  
  if(nthresh==1){
    dummydown <- ifelse(trans[,bestDelay]<=bestThresh, 1, 0)
    ndown <- mean(dummydown)
    regimeDown <- dummydown*Z[,-val]
    dummyup<-1-dummydown
    if(dummyToBothRegimes) 
      regimeUp<-dummyup*Z[,-val]
    else regimeUp<-Z
    if(commonInter)
      Zbest<-cbind(1,regimeDown,regimeUp)
    else
      Zbest <- cbind(regimeDown,regimeUp)		# dim k(p+1) x t
  }
  
  if(nthresh==2|nthresh==3){
    dummydown <- ifelse(trans[,bestDelay]<=bestThresh[1], 1,0)
    ndown <- mean(dummydown)
    regimedown <- dummydown*Z[,-val]
    dummyup <- ifelse(trans[,bestDelay]>bestThresh[2], 1,0)
    nup <- mean(dummyup)
    regimeup <- dummyup*Z[,-val]
    dummymid<-1-dummydown-dummyup
    if(commonInter)
      Zbest <- cbind(1,regimedown,dummymid*Z[,-1], regimeup)	# dim k(p+1) x t
    else
      Zbest <- cbind(regimedown,dummymid*Z, regimeup)	# dim k(p+1) x t
  }
  
  Zbest_t <- t(Zbest)
  reg<-if(nthresh==1) dummydown+2*dummyup else dummydown+2*dummymid+3*dummyup
  regime <- c(rep(NA, T-t), reg)
  
  ##################################
  ### Best Model: estimate
  ##################################
  
  final <- lm.fit(x=Zbest, y=Y)
  
  Bbest <- t(final$coef)
  fitted <- final$fitted
  resbest <- final$residuals
  
  SSRbest <- as.numeric(crossprod(c(resbest)))
  nparbest<-nrow(Bbest)*ncol(Bbest)
  
  Sigmabest <- matrix(1/t*crossprod(resbest), ncol=k, dimnames=list(colnames(data), colnames(data)))
  SigmabestOls <- Sigmabest * (t/(t-ncol(Bbest)))
  
  ### naming and splitting B
  rownames(Bbest) <- paste("Equation", colnames(data))
  LagNames <- c(paste(rep(colnames(data), p), -rep(seq_len(p), each=k)))
  
  Bnames  <- c(switch(include, const="Intercept", trend="Trend", both=c("Intercept","Trend"), none=NULL), LagNames)
  Blist <- nameB(mat=Bbest, commonInter=commonInter, Bnames=Bnames, nthresh=nthresh, npar=npar)
  
  ## name the coefMat:
  BnamesVec <- if(inherits(Blist, "list")) c(sapply(Blist, colnames)) else colnames(Blist)
  colnames(Bbest) <- BnamesVec
  
  ##number of obs in each regime
  if(nthresh==1)
    nobs <- c(ndown=ndown, nup=1-ndown)
  else if (nthresh==2)
    nobs <- c(ndown=ndown, nmiddle=1-nup-ndown,nup=nup)
  
  ###Y and regressors matrix
  tZbest <- Zbest
  naX <- rbind(matrix(NA, ncol=ncol(tZbest), nrow=p), tZbest)
  YnaX <- cbind(data, naX)
  BlistMod <- nameB(mat=Bbest, commonInter=commonInter, Bnames=Bnames, nthresh=nthresh, npar=npar,sameName=FALSE )
  BnamesVecMod <- if(inherits(BlistMod, "list")) c(sapply(BlistMod, colnames)) else colnames(BlistMod)
  colnames(YnaX) <- c(colnames(data),BnamesVecMod)
  
  ###elements to return
  specific <- list()
  specific$allgammas <- allgammas
  specific$gammas <- gammas
  specific$thDelay <- bestDelay
  specific$Thresh <- bestThresh
  specific$nthresh <- nthresh
  specific$transCombin <- combin
  specific$regime <- regime
  specific$nreg <- nthresh+1
  specific$nrowB <- npar
  specific$nobs <- nobs
  specific$oneMatrix <- commonInter
  specific$threshEstim <- ifelse(is.null(gamma), TRUE, FALSE)
  specific$allThSSR <- allThSSR#SSR values for all the th computed
  specific$Bnames <- Bnames
  specific$timeAttributes <- attributes(data[,1])
  
  ## input arguments to return
  inputArgs <-  list()
  inputArgs$model <-  model
  inputArgs$commonInter <-  commonInter
  inputArgs$trim <- trim
  inputArgs$mTh <- mTh
  inputArgs$dummyToBothRegimes <- dummyToBothRegimes
  inputArgs$call <- match.call()
  
  
  z<-list(coefficients=Blist, coeffmat=Bbest, residuals=resbest, model=YnaX, 
          nobs_regimes=nobs, k=k, t=t, T=T,nparB=nparbest, df.residual=t-ncol(Bbest),
          fitted.values=fitted, lag=lag, include=include,model.specific=specific, 
          usedThVar=trans[,bestDelay], trim=trim, 
          qr = final$qr, inputArgs = inputArgs)
  class(z) <- c("TVAR","nlVar")
  attr(z, "levelTransVar") <- model
  attr(z, "transVar") <- if(!missing(thVar)) "external" else "internal"
  attr(z, "varsLevel") <- "level"
  
  if(plot){
    layout(matrix(1:ifelse(z$model.specific$threshEstim,3,2), ncol=1))
    plot1(bestThresh, nthresh,usedThVar=z$usedThVar)
    plot2(bestThresh, nthresh,usedThVar=z$usedThVar, trim=z$trim)
    if(z$model.specific$threshEstim)
      plot3(bestThresh, nthresh,allTh=z$model.specific$allThSSR)
  }
  return(z)
}	#end of the whole function


#' @export
print.TVAR<-function(x,...){
# 	NextMethod(...)
	cat("Model TVAR with ", x$model.specific$nthresh, " thresholds\n\n")
	print(x$coefficients)
	cat("\nThreshold value")
	print(paste(x$model.specific$Thresh, collapse=" "))
}

#' @export
summary.TVAR<-function(object,...){
	x<-object
	xspe<-x$model.specific
	k<-x$k
	t<-x$t
	p<-x$lag
	Z<-t(as.matrix(tail.matrix(x$model[,-c(1:k)],t)))
	
	###Stdev, VarCov
	SigmabestOls <- matrix(1/x$df.residual*crossprod(x$residuals),ncol=k)
	VarCovB <- SigmabestOls %x% solve(tcrossprod(Z))
	StDevB<-matrix(diag(VarCovB)^0.5, nrow=k, byrow=TRUE)
	Tvalue<-x$coeffmat/StDevB
	StDevB<-nameB(StDevB,commonInter=xspe$oneMatrix, Bnames=xspe$Bnames, nthresh=xspe$nthresh, npar=xspe$nrowB)
	Pval <- 2* pt(abs(Tvalue), df=x$df.residual, lower.tail=FALSE)
	Pval<-nameB(Pval,commonInter=xspe$oneMatrix, Bnames=xspe$Bnames, nthresh=xspe$nthresh, npar=xspe$nrowB)

	## export results
	x$coefficients<-asListIfMat(x$coefficients)
	x$StDev<-asListIfMat(StDevB)
	x$Pvalues<-asListIfMat(Pval)
	x$Tvalues<-Tvalue
	x$VarCov<-asListIfMat(VarCovB)
	ab<-list()
	symp<-list()
	stars<-list()
	for(i in 1:length(x$Pvalues)){
		symp[[i]] <- symnum(x$Pvalues[[i]], corr=FALSE,cutpoints = c(0,  .001,.01,.05, .1, 1), symbols = c("***","**","*","."," "))
		stars[[i]]<-matrix(symp[[i]], nrow=nrow(x$Pvalues[[i]]))
		ab[[i]]<-matrix(paste(x$coefficients[[i]],"(", x$StDev[[i]],")",stars[[i]], sep=""), nrow=nrow(x$StDev[[i]]))
		dimnames(ab[[i]])<-dimnames(x$coefficients[[1]])
	}
	attributes(ab)<-attributes(x$coefficients)
	x$stars<-stars
	x$starslegend<-symp[[1]]
	x$bigcoefficients<-ab
	x$aic<-AIC.nlVar(x)
	x$bic<-BIC.nlVar(x)
	x$SSR<-deviance(x)
	class(x)<-c("summary.TVAR", "TVAR", "nlVar")
	return(x)
}

#' @export
print.summary.TVAR<-function(x,digits = max(3, getOption("digits") - 3), signif.stars = getOption("show.signif.stars"),...){
	coeftoprint<-list()
	for(i in 1:length(x$bigcoefficients)){
		a<-myformat(x$coefficients[[i]], digits)
		b<-myformat(x$StDev[[i]], digits)
		if(getOption("show.signif.stars"))
			stars<-x$stars[[i]]	
		else
			stars<-NULL
		coeftoprint[[i]]<-matrix(paste(a,"(", b,")",stars, sep=""), nrow=nrow(x$StDev[[1]]))
		dimnames(coeftoprint[[i]])<-dimnames(x$coefficients[[1]])
	}
	cat("Model TVAR with ", x$model.specific$nthresh, " thresholds\n")
	cat("\nFull sample size:",x$T, "\tEnd sample size:", x$t) 
	cat("\nNumber of variables:", x$k,"\tNumber of estimated parameters:", x$npar,"+",x$model.specific$nthresh)
	cat("\nAIC",x$aic , "\tBIC", x$bic, "\t SSR", x$SSR,"\n\n")
	print(noquote(coeftoprint))
	if (signif.stars) 
	        cat("---\nSignif. codes: ", attr(x$starslegend, "legend"), "\n")
	cat("\nThreshold value:",x$model.specific$Thresh)
	if(!x$model.specific$threshEstim)
		cat(" (user specified)")
	cat("\nPercentage of Observations in each regime:", percent(x$model.specific$nobs,3,TRUE), "\n")
}




plot1<-function(th,nthresh,usedThVar){
plot.ts(usedThVar, ylab="")
  title("Threshold variable used")
  abline(h=th, col=2:(nthresh+1))
  legend("topleft", lty=1, bg="white", col=2:(nthresh+1), legend=c(paste("th", 1:nthresh)))
}

plot2<-function(th,nthresh, usedThVar,trim){
nga <- length(usedThVar)
  orderedThVar<-sort(usedThVar)
  lt<-rep(".",nga)
  lt[(trim*nga):((1-trim)*nga)]<-1
  #plot(seq_len(nga), allgammas, pch=lt, xlab="Sorted values", ylab="")
  if(nthresh==1)
    numTh<-which.min(abs(orderedThVar-th))
  else{
    numTh1<-which.min(abs(orderedThVar-th[1]))
    numTh2<-which.min(abs(orderedThVar-th[2]))
    numTh<-c(numTh1, numTh2)}
  ts.plot(orderedThVar, xlab="", ylab="")
  title("Ordered threshold variable")
  abline(v=c(trim*nga,(1-trim)*nga), col=4)
  points(numTh, th, col=c(2:(nthresh+1)),cex=2)
  leg<-c(paste("trim=", trim),paste("th", 1:nthresh))
  legend("topleft", lty=1, col=c(4,2:(nthresh+1)), legend=leg, bg="white")
}

#Plot for the grid search
plot3 <- function(th,nthresh, allTh, type = "p"){
    allDelay<-unique(allTh[,1])
    col <- rep(allDelay,length.out=nrow(allTh))+1
    if(nthresh==1) {
      posBestTh<-which(allTh[,2]==th)
    } else {
      posBestTh1 <- which(allTh[, 2] == th[1])
      posBestTh2 <- which(allTh[, 2] == th[2])
      posBestTh <- c(posBestTh1, posBestTh2)
    }
    plot(allTh[,2], allTh[,3], col=col,xlab="Threshold Value",ylab="SSR", type = type)
    title("Results of the grid search")
    points(th,allTh[posBestTh,3], col=c(2:(nthresh+1)), cex=2)
    leg<-c(paste("Threshold Delay", allDelay),(paste("th", 1:nthresh)))
    legend("topleft", pch=1, legend=leg, col=c(allDelay+1,c(2:(nthresh+1))), bg="white")
}

#' @export
plot.TVAR<-function(x,ask=interactive(), ...){
  th<-x$model.specific$Thresh
  nthresh<-x$model.specific$nthresh
  op <- par(no.readonly=TRUE)
  #par(ask=ask)
  layout(matrix(1:ifelse(x$model.specific$threshEstim,3,2), ncol=1))
  plot1(th, nthresh,usedThVar=x$usedThVar)
  plot2(th, nthresh,usedThVar=x$usedThVar, trim=x$trim)
  if(x$model.specific$threshEstim)
    plot3(th, nthresh,allTh=x$model.specific$allThSSR)
  par(op)
}


#' @export
toLatex.TVAR<-function(object,..., digits=4, parenthese=c("StDev","Pvalue")){
	x<-object
	parenthese<-match.arg(parenthese)
	x$coefficients<-asListIfMat(x$coefficients)
	if(inherits(x,"summary.TVAR")){
		coeftoprint <-list()
		for(i in 1:length(x$coefficients)){
			a<-myformat(x$coefficients[[i]],digits, toLatex=TRUE)
			if(parenthese=="StDev")
				b<-myformat(x$StDev[[i]],digits,toLatex=TRUE)
			else if(parenthese=="Pvalue")
				b<-myformat(x$Pvalues[[i]],digits,toLatex=TRUE)
			if(getOption("show.signif.stars"))
				stars<-paste("^{",x$stars[[i]],"}", sep="")
			else
				stars<-NULL
			coeftoprint[[i]]<-matrix(paste(a,"(",b,")",stars, sep=""),ncol=ncol(a), nrow=nrow(a))
		}#end for
	}#end if

	else{
		coeftoprint <-rapply(x$coefficients,myformat, digits=digits,toLatex=TRUE, how="list")}
	varNames<-rownames(coeftoprint[[1]])
	res<-character()
	res[1]<-"%insert in the preamble and uncomment the line you want for usual /medium /small matrix"
	res[2]<-"%\\usepackage{amsmath} \\newenvironment{smatrix}{\\begin{pmatrix}}{\\end{pmatrix}} %USUAL"
	res[3]<-"%\\usepackage{amsmath} \\newenvironment{smatrix}{\\left(\\begin{smallmatrix}}{\\end{smallmatrix}\\right)} %SMALL"
	res[4]<-"%\\usepackage{nccmath} \\newenvironment{smatrix}{\\left(\\begin{mmatrix}}{\\end{mmatrix}\\right)} %MEDIUM"
	res[5]<-"\\begin{equation}"
	res[6]<- "\\begin{smatrix} %explained vector"
	res[7]<-TeXVec(paste("X_{t}^{",seq(1, x$k),"}", sep=""))
	res[8]<- "\\end{smatrix}="
	#if(!x$model.specific$oneMatrix)
	res[length(res)+1]<- "\\left\\{"
 	res[length(res)+1]<-"\\begin{array}{ll}"
	Th<-x$model.specific$Thresh
	nthresh<-length(Th)
	###Condition for the threshold
	if(nthresh%in%c(1,2)){
		cond<-paste(c("& \\text{if Th}<","& \\text{if Th}>"), Th)}
	if(nthresh==2){
		cond[3]<-cond[2]
		cond[2]<-paste("& \\text{if }",Th[1], "< \\text{Th} <", Th[2])
 		}
	###Adds the const/trend and lags
	for(i in 1:(nthresh+1)){
		if(x$model.specific$oneMatrix){
			regimei<-coeftoprint[[1]]
			j<-i}
		else{
			regimei<-coeftoprint[[i]]
			j<-1}
 		res<-include(x, res, regimei)
		ninc<-switch(x$include, "const"=1, "trend"=1,"none"=0, "both"=2)
		res<-LagTeX(res, x, regimei, skip=ninc+x$lag*x$k*(j-1))
		res[length(res)+1]<- paste(cond[i], "\\\\")
	}
	res[length(res)+1]<-"\\end{array}"
	res[length(res)+1]<-"\\right."
	res[length(res)+1]<-"\\end{equation}"
	res<-gsub("slash", "\\", res, fixed=TRUE)
	res<-res[res!="blank"]
	return(structure(res, class="Latex"))

}


nameB <- function(mat, commonInter, Bnames, nthresh, npar, model=c("TVAR","TVECM"), TVECMmodel="All", sameName=TRUE){
  model <- match.arg(model)
  addRegLetter <- if(sameName) NULL else  c("L ", if(nthresh==1) NULL else "M ", "H ")
  if(model=="TVAR")
    sBnames <- Bnames[-which(Bnames=="Intercept")]
  else if(model=="TVECM")
    sBnames <- Bnames[-which(Bnames=="ECT")]

##1 threshold
  if(nthresh==1){
    if(commonInter){
      if(model=="TVAR"){
        colnames(mat) <- c("Intercept", paste(rep(addRegLetter, each=length(sBnames)),rep(sBnames,2),sep=""))
      } else if(model=="TVECM") {
        colnames(mat) <- c("ECT-","ECT+", sBnames)
      }
      Blist <- mat
    } else {
      colnames(mat) <- paste(rep(addRegLetter, each=length(Bnames)),rep(Bnames,2),sep="")
      Bdown <- mat[,c(1:npar)]
      Bup <- mat[,-c(1:npar)]
      Blist <- list(Bdown=Bdown, Bup=Bup)
    }
##2 thresholds
  } else { 
    if(commonInter){
      if(model=="TVAR")
        colnames(mat) <- c("Intercept", paste(rep(addRegLetter, each=length(sBnames)), rep(sBnames,3),sep=""))
      else if(model=="TVECM")
        colnames(mat) <- c("ECT-","ECT+", sBnames)
      Blist <- mat}
    else{
      colnames(mat) <- paste(rep(addRegLetter, each=length(Bnames)), rep(Bnames,3), sep="")
      Bdown <- mat[,c(1:npar)]
      Bmiddle <- mat[,c(1:npar)+npar]
      Bup <- mat[,c(1:npar)+2*npar]		
      colnames(Bmiddle) <- Bnames
      Blist <- list(Bdown=Bdown, Bmiddle=Bmiddle,Bup=Bup)}
  }
  return(Blist)
}

onesearch <- function(thDelay,gammas, fun, trace, gamma, plot){
  grid1 <- expand.grid(thDelay,gammas)				#grid with delay and gammas
  store <- mapply(fun,thDelay=grid1[,1],gam1=grid1[,2])
  posBestThresh <- which(store==min(store, na.rm=TRUE), arr.ind=TRUE)[1]
  
  if(trace)
    cat("Best unique threshold", grid1[posBestThresh,2],"\n")
  if(length(thDelay)>1&trace)
    cat("Best Delay", grid1[posBestThresh,1],"\n")
  res <- list(bestThresh=grid1[posBestThresh,2],bestDelay=grid1[posBestThresh,1], allres=cbind(grid1,store))
  return(res)
}#end of function one search

condiStep <- function(allTh, threshRef, delayRef, fun, trim, trace=TRUE, More=NULL){
  allThUniq <- unique(allTh)
  ng <- length(allTh)
  down <- ceiling(trim*ng)
  
   #correction for case with few unique values
  if(allTh[down]==allTh[down+1]){
    sames <- which(allTh==allTh[down])
    down <-sames[length(sames)]+1
  }
  up <- floor(ng*(1-trim))
  #correction for case with few unique values
  if(allTh[up]==allTh[up-1]){
    up <- which(allTh==allTh[up])[1]-1
  }
  ninter <- max(down, ng-up)
  nMin <- ceiling(trim*ng)

  possibleThresh <- abs(allTh-threshRef)
  wh.thresh <- max(which(possibleThresh==min(possibleThresh)))
  
#search for a second threshold smaller than the first one
  if(wh.thresh>down+nMin){
    upInter <- wh.thresh-nMin
    if(allTh[upInter]==allTh[upInter-1])
      upInter <- which(allTh==allTh[upInter])[1]-1
    gammaMinus <- unique(allTh[seq(from=down+1, to=upInter)])
    #if only one unique value in middle regime
     if(allThUniq[which(allThUniq==allTh[upInter])+1]==allTh[wh.thresh]){
       gammaMinus <- head(gammaMinus, -1)#cut last one
      }
    if(length(gammaMinus)>0)
      storeMinus <- mapply(fun,gam1=gammaMinus,gam2=threshRef, thDelay=delayRef, MoreArgs=More)
    else
      storeMinus <- NA
  }
  else
    storeMinus <- NA
  
	#search for a second threshold higher than the first
  if(wh.thresh<up-nMin){
    downInter <- wh.thresh+nMin
    if(FALSE){#allTh[downInter]==allTh[wh.thresh]){
      samesTh <-which(allTh==allTh[downInter])
      downInter <-samesTh[length(samesTh)]+nMin
    }    
    if(allTh[downInter]==allTh[downInter+1]){
      samesInter <-which(allTh==allTh[downInter])
      downInter <-samesInter[length(samesInter)]+1
    }
    gammaPlus <- unique(allTh[seq(from=downInter, to=up)])
          #if only one unique value in middle regime
    if(allThUniq[which(allThUniq==allTh[downInter])-1]==allTh[wh.thresh]){
      gammaPlus <- gammaPlus[-1]#cut first one
    }
    if(length(gammaPlus)>1)
      storePlus <- mapply(fun,gam1=threshRef,gam2=gammaPlus, thDelay=delayRef,MoreArgs=More)
    else
      storePlus <- NA
  }
  else
    storePlus <- NA

	#results
  store2 <- c(storeMinus, storePlus)
  positionSecond <- which(store2==min(store2, na.rm=TRUE), arr.ind=TRUE)
  positionSecond <-  positionSecond[1] ## arbitrary, in case multiple values
  if(positionSecond<=length(storeMinus)) {
    newThresh <- gammaMinus[positionSecond]
  } else {
    newThresh <- gammaPlus[positionSecond - length(storeMinus)]
  }
  SSR <- min(store2, na.rm = TRUE)
  if(trace)
    cat("Second best: ",newThresh, " (conditionnal on th= ",threshRef, " and Delay= ", delayRef," ) \t SSR/AIC: ", SSR, "\n", sep="")
  list(threshRef=threshRef, newThresh=newThresh, SSR=SSR)
}


###Function for nthresh=2, Alternative step: grid around the points from first step
grid<-function(gammasUp, gammasDown, fun, trace=TRUE, method=c("for", "apply", "mapply"),...){
	store <- matrix(NA,ncol=length(gammasUp), nrow=length(gammasDown))
	method<-match.arg(method)
	if(method=="for"){
		#Grid search
		for(i in seq_len(length(gammasDown))){
			gam1 <- gammasDown[i]
			for(j in 1: length(gammasUp)){
				gam2 <- gammasUp[j]
				store[i,j] <- fun(gam1=gam1, gam2=gam2,...)
			}
		}

		#Finding the best result
		positionIter <- which(store==min(store, na.rm=TRUE), arr.ind=TRUE)
		rIter <- positionIter[1]
		cIter <- positionIter[2]
	
		gamma1Iter <- gammasDown[rIter]
		gamma2Iter <- gammasUp[cIter]

		bestThresh <- c(gamma1Iter, gamma2Iter)
	}
	else if(method=="apply"){
		grid<-expand.grid(gammasDown,gammasUp)
# 		fun(gam1=gam1, gam2=gam2, d=bestDelay)
		temp<-function(a) fun(gam1=c(a)[1],gam2=c(a)[2],...)
		store<-apply(grid,1,temp)
		bests<-which(store==min(store, na.rm=TRUE))
		if(length(bests)>1) {
			warning("There were ",length(bests), " thresholds values which minimize the SSR in the first search, the first one was taken") 	
			bests<-bests[1]}
# 		beta_grid<-grid[bests,1]
# 		bestGamma1<-grid[bests,2]
		bestThresh <- c(grid[bests,1], grid[bests,2])
	}
	else if(method=="mapply"){
		grid<-expand.grid(gammasDown,gammasUp)	
		store<-mapply(fun, gam1=grid[,1],gam2=grid[,2], MoreArgs=list(...))
		bests<-which(store==min(store, na.rm=TRUE))
		if(length(bests)>1) {
			warning("There were ",length(bests), " thresholds values which minimize the SSR in the first search, the first one was taken") 	
			bests<-bests[1]}
# 		beta_grid<-grid[bests,1]
# 		bestGamma1<-grid[bests,2]
		bestThresh <- c(grid[bests,1], grid[bests,2])
	}
	if(trace)
		cat("\nSecond step best thresholds", bestThresh, "\t\t SSR:", min(store, na.rm=TRUE), "\n")
	return(bestThresh)
}#end of grid function
#  VAR<-TVAR(dat[1:300,], lag=2, nthresh=2,thDelay=1, plot=FALSE, commonInter=TRUE, include="const", trick="apply", max.iter=5)

#  system.time(TVAR(dat, lag=2, nthresh=2,thDelay=1, plot=FALSE, commonInter=TRUE, include="const", trick="apply"))
#  system.time(TVAR(dat, lag=2, nthresh=2,thDelay=1, plot=FALSE, commonInter=TRUE, include="const", trick="mapply"))
#  system.time(TVAR(dat, lag=2, nthresh=2,thDelay=1, plot=FALSE, commonInter=TRUE, include="const", trick="for"))

if(FALSE) { #usage example
###Hansen Seo data
library(tsDyn)
#data(zeroyld)
dat<-zeroyld
environment(TVAR)<-environment(star)
environment(summary.TVAR)<-environment(star)

VAR<-TVAR(as.matrix(dat[1:100,]),lag=2, nthresh=1,thDelay=1,trim=0.1, plot=FALSE, commonInter=TRUE, include="const", gamma=c(3.016, 3.307))

VAR<-TVAR(dat[1:100,],lag=2, nthresh=2,thDelay=1,trim=0.1, plot=FALSE, commonInter=TRUE, include="const", gamma=c(3.016, 3.307))
VAR<-TVAR(dat[1:100,], lag=2, nthresh=2,thDelay=1,trim=0.1, plot=FALSE, commonInter=TRUE, include="const")
#lag2, 2 thresh, trim00.05: 561.46

class(VAR)
VAR
print(VAR)
logLik(VAR)
AIC(VAR)
BIC(VAR)
coef(VAR)
deviance(VAR)
summary(VAR)
toLatex(VAR)
toLatex(summary(VAR))
VAR[["model.specific"]][["oneMatrix"]]
###TODO
#pre specified gamma: not working!
#Bname: give different output... either matrix or list... to improve
}

Try the tsDyn package in your browser

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

tsDyn documentation built on June 22, 2024, 11:03 a.m.