R/DLM.R

Defines functions DLM

Documented in DLM

#' Dynamic Linear Model Function on panel data 
#'
#' A function to run DLM and post-modelling calculation on panel data for Marketing-Mix modelling
#'
#' @param spec a character vector for parallel computation; for example, rep("localhost",3) means open 3 local R sessions.
#' @param data a data.table class object as modelling dataset.
#' @param model.name a character for the name of your model, used in output file names.
#' @param contrb.date a character for the time period of your contribution calculation time window, used in output file names.
#' @param group a character for cross section variable name name in modelling dataset.
#' @param date.var a character for date variable name in modelling dataset.
#' @param start.date.m a character for the start date of modelling; format is YYYY-MM-DD.
#' @param end.date.m a character for the end date of modelling; format is YYYY-MM-DD.
#' @param start.date.c a character for the start date of post-modelling contribution calculation; format is YYYY-MM-DD.
#' @param end.date.m c character for the end date of post-modelling contribution calculation; format is YYYY-MM-DD.
#' @param is.output TRUE output decomp tables.
#' @param is.graph TRUE graph AVP chart.
#' @param clv a numeric for value calcualtion of dependent, such as NPV or CLV. Default value is 1.
#' @param varlist a character vector for the independent variable names, if no independent, then put c(). 
#'    Always put variables required NEGATIVE coefficient at the beginning, then POSITIVE coefficient variables, and variables NOT required the sign of coefficient in the end.
#'    The order would be used in a build-in coefficient sign check feature. If no sign check needed, then the order doesn't matter.
#' @param num_ng_coef a numeric for the number of variables required negative cofficient.
#' @param iter a numeric for the number of iteration of coefficient sign check. Default value is 100. If no sign check needed, please put 1.
#' @param dum a character vector for variables in varlist which is not required sign(the last several variables from the above vector),if none then put c().
#' @param dum_matrix a numeric matrix for the variables in the dum vector, which specify the cross section that each variable would have impact on. If dum is c(), then put NA.
#'    Row is cross section and column is variables in dum vector. Only put 1 or 0 to specify whether a variable has impact or not.
#' @param dep a character for dependent variable name.
#' @param actual a character for actual depdendent before indexed.
#' @param mean a character for weight used to index actual dependent.
#' @param CI.level a numeric for confidence interval level in output; range is from 0 to 1. For example, 0.95 means 95 percent CI level.
#' @param level_type a numeric for the type of level component in DLM; 1 represents level type; 2 represents level+slope type.
#' @param var_coef a numeric for the variance of independent coefficient; 0 reprensents constant coef, non-zero value represents time-varying coef. For example, 1^2 means the standard deviation of each coef is 1 and time-varying;
#'    "est" means estimated by model itself.
#' @param var_level a numeric for the variance of level component; 0 reprensents constant coef, non-zero value represents time-varying coef. For example, 1^2 means the standard deviation of each coef is 1 and time-varying;
#'    "est" means estimated by model itself.
#' @param var_slope a numeric for the variance of slope component; 0 reprensents constant coef, non-zero value represents time-varying coef. For example, 1^2 means the standard deviation of each coef is 1 and time-varying;
#'    "est" means estimated by model itself.
#' @param var_sea a numeric for the variance of seasonality component; 0 reprensents constant coef, non-zero value represents time-varying coef. For example, 1^2 means the standard deviation of each coef is 1 and time-varying;
#'    "est" means estimated by model itself.
#' @param per_sea a numeric for the period of seasonality variable. For example, in weekly data, 52 means the period is 52 weeks.
#' @param ord_sea a numeric for the number of harmonics of seasonality component which is a Fourier series.
#' @param optim.method a charater for the optimization method used in MLE. Default is "L-BFGS-B". Any other method in stats::optim is available.
#' @param optim.lb a numeric for the lower bond of optimization. Defualt is -Inf.
#' @param optim.ub a numeric for the upper bond of optimization. Defualt is Inf.   
#'    
#'    
#' @return a list of modeling result. It contains the following components:
#'    stat: Diagnostic Statistics
#'    coef: a coefficient table if possible
#'
#' @export

DLM=function(
  spec,
  data,
  model.name,
  contrb.date,
  group,
  date.var,
  start.date.m,
  end.date.m,
  start.date.c,
  end.date.c,
  is.output=F,
  is.graph=T,
  clv=1,
  varlist,
  dum,
  dum_matrix,
  num_ng_coef,
  dep,
  actual,
  mean,
  CI.level=0.95,
  iter=100,
  level_type,
  var_coef,
  var_level,
  var_slope,
  per_sea,
  ord_sea,
  var_sea,
  optim.method="L-BFGS-B",
  optim.lb=-Inf,
  optim.ub=Inf
){
  #library(dlm);library(reshape2);library(data.table);library(doSNOW)
  ############################################################################
  # 1, Setup
  ############################################################################
  # spec=rep("localhost",2) # for parallel computation, only change the number which stands for # of threads
  # model.name="DDA_EX"  # Name of model, for output files' name
  # contrb.date="2012" # The time period to compute contribution, for output files' name
  # group="market" # Cross section column name in dataset
  # date.var="date" # date column name in dataset
  # start.date.m="2007-01-01" # Start date for modelling
  # end.date.m="2013-12-31" # End date for modelling
  # # Compute contribution
  # start.date.c="2012-01-01" # Starting date for computing contribution
  # end.date.c="2012-12-31" # Ending date for computing contribution
  # is.output=F
  # is.graph=T
  # clv=263 # CLV
  # # Vector of all the independent variable names, if no independent, then put c()
  # # Always put variables required NEGATIVE coef at the beginning, and variables NOT required the sign of coef in the end
  # varlist=c(
  # 
  # )
  # 
  # # Vector of variables above without coef sign constraint ( the last several variables from the above vector),if nothing then put c()
  # dum=c(
  # 
  # )
  # 
  # # For the variables in the dum vector above, specify the DMA's they would have impact on.If nothing then put NA
  # dum_matrix=NA
  # 
  # num_ng_coef=2 # no. of negative coef variables
  # dep="chkopens_ext_adji" # dependent var name
  # actual="chkopens_ext_adj" # actual var name
  # mean="chkopens_ext_adjm"# mean of actual var name
  # 
  # # DLM setup
  # CI.level=0.95 # CI level
  # 
  # iter=1 # no. of iteration for model selection
  # 
  # level_type=2 # Moving base type: 1 represents level type; 2 represents level+slope type
  # 
  # var_coef=0 # Variance of covariate coef: 0 reprensents constant coef, non-zero value represents time-varying coef. For instance, 1^2 means the standard deviation of each coef is 1 and they are time-varying coef's.
  # # "est" means estimated by model
  # 
  # var_level=5e-3^2  # Variance of the level part of moving base. 0 reprensents constant level, non-zero value represents time-varying level.
  # # "est" means estimated by model
  # 
  # var_slope=0 # Variance of the slope part of moving base. 0 reprensents constant slope, non-zero value represents time-varying slope.
  # # "est" means estimated by model
  # 
  # per_sea=52 # Period of seasonality variable. For instance, I'm using weekly data, so my season period is 52 weeks which is one year.
  # 
  # ord_sea=6 # No. of harmonics of seasonality variable. The season var is a Fourier series so that no. of harmonic need to be specified.
  # 
  # var_sea=0 # Variance of the seasonality. 0 reprensents constant seasonality, non-zero value represents time-varying seasonality, which means for each period, seasonality is different.
  # # "est" means estimated by model
  # 
  # optim.method="L-BFGS-B" # Optimization method for variance of error estimation. Usually don't need to change.
  # 
  # optim.lb=-Inf # Lower bound of variance of error for optimization. Usually don't need to change.
  # 
  # optim.ub=Inf # Upper bound of variance of error for optimization. Usually don't need to change.
  
  ############################################################################
  # 2, Code part ( CORE PART, DON'T CHANGE ANYTHING WITHIN THIS PART)
  ############################################################################
  # Split data by market
  start=Sys.time()
  data[is.na(data)]=0
  market=unique(data[[group]])
  setnames(data,date.var,"date")
  data=data[data$date>=start.date.m&data$date<=end.date.m,]
  data.dma=vector("list",length(market))
  y=vector("list",length(market))
  ymean=vector("list",length(market))
  yreal=vector("list",length(market))
  x=vector("list",length(market))
  
  for (i in 1:length(market)){ #i=1
    data.dma[[i]]=data[data[group]==market[i],]
    y[[i]]=data.dma[[i]][,dep]
    ymean[[i]]=data.dma[[i]][,mean]
    yreal[[i]]=data.dma[[i]][,actual]
    if(length(varlist)!=0) x[[i]]=data.frame(data.table(data.dma[[i]])[,varlist,with=F])
  }
  date=data.dma[[1]]$date
  coef.check.pre=matrix(1,nc=length(market),nr=length(varlist),dimnames=list(varlist,market))
  
  # build the trend and season part
  
  p=NA
  if (level_type==2){
    if ((var_level=="est") & (var_slope!="est")){
      ploy=dlmModPoly(level_type,dV=p,dW=c(exp(p),var_slope))
      no.par=2
    }else if ((var_level!="est") & (var_slope=="est")){
      ploy=dlmModPoly(level_type,dV=p,dW=c(var_level,exp(p)))
      no.par=2
    }else if (var_level=="est" & var_slope=="est"){
      ploy=dlmModPoly(level_type,dV=p,dW=c(exp(p),exp(p)))
      no.par=3
    }else {
      ploy=dlmModPoly(level_type,dV=p,dW=c(var_level,var_slope))
      no.par=1
    }
    
  }else if (level_type==1){
    if (var_level=="est"){
      ploy=dlmModPoly(level_type,dV=p,dW=c(exp(p)))
      no.par=2
    }else{
      ploy=dlmModPoly(level_type,dV=p,dW=c(var_level))
      no.par=1
    }
    
  }else {stop("The order of lever is greater than 2.")}
  
  if (var_sea=="est"){
    sea=dlmModTrig(s=per_sea,q=ord_sea,dV=0,dW=p)
    no.par=no.par+1
  }else{
    sea=dlmModTrig(s=per_sea,q=ord_sea,dV=0,dW=var_sea)
  }
  ploy1=ploy
  sea1=sea
  
  if(length(varlist)==0) iter=1
  
  # DLM loop starts
  for (loop in 1:iter){ 
    #loop=1
    print(paste("********** Round",loop,", Time: ",format(Sys.time(), "%H:%M:%S"),"**********",sep=" "))
    if(length(varlist)!=0) coef.table=matrix(0,nr=length(varlist),nc=length(market),dimnames=list(varlist,market))  
    
    comb <- function(x, ...) {
      lapply(seq_along(x),
             function(i) c(x[[i]], lapply(list(...), function(y) y[[i]])))
    }
    cl=makeCluster(spec,type="SOCK",outfile="")
    registerDoSNOW(cl)
    result=foreach(i = 1:length(market),.combine='comb', .multicombine=T,.packages=c("dlm"),
                   .init=list(list(),list(),list(),list(),list(),list(),list())) %dopar% { 
                     print(paste("modelling on :",market[i],", Market #:",i,
                                 ", Time: ",format(Sys.time(), "%H:%M:%S"),sep=""))
                     ploy=ploy1
                     sea=sea1
                     build=function(p){
                       
                       ploy$V[is.na(ploy$V)]=exp(p[1])
                       n=1
                       no=sum(is.na(ploy$W))
                       if(no!=0){
                         ploy$W[is.na(ploy$W)]=exp(p[(n+1):(n+no)])
                         n=n+no
                       }
                       
                       if(var_sea=="est") {
                         sea$W[is.na(sea$W)]=exp(p[n+1])
                         n=n+1
                       }
                       if (length(varlist) !=0){
                         if(var_coef=="est"){
                           reg=dlmModReg(x[[i]],addInt=F,dV=0,dW = rep(p[n+1], ncol(x[[i]])))
                         }else{
                           reg=dlmModReg(x[[i]],addInt=F,dV=0,dW = rep(var_coef, ncol(x[[i]])))
                         }
                         mod=reg+ploy+sea
                       }else{
                         mod=ploy+sea
                       }
                       return(mod)
                       
                     }
                     
                     mle=dlmMLE(y[[i]],rep(0,no.par),build,
                                method=optim.method,lower=optim.lb,upper=optim.ub)
                     mod=as.dlm(build(mle$par))
                     ##################
                     #mod[[i]]$JFF[1,][mod[[i]]$JFF[1,]!=0]=0
                     ###################
                     f=dlmFilter(y[[i]],mod)
                     s=dlmSmooth(f)
                     cov=dlmSvd2var(s$U.S,s$D.S)[[1]]
                     if(length(varlist)!=0){
                       coef=t(tail(dropFirst(s$s[,1:sum(coef.check.pre[,i])]),n=1))[,1]
                       coef.table[coef.check.pre[,i]==1,i]=coef
                       coef.table1=coef.table[,i]
                     }
                     
                     if(length(varlist)!=0) list(mle,mod,f,s,cov,coef,coef.table1) else list(mle,mod,f,s,cov,NULL,NULL)
                   }
    mle=result[[1]]
    mod=result[[2]]
    f=result[[3]]
    s=result[[4]]
    cov=result[[5]]
    if(length(varlist)!=0) {
      coef=result[[6]]
      coef.table=do.call(cbind,result[[7]])
    }
    stopCluster(cl)
    
    
    # Model Selection
    if(length(varlist)!=0){
      coef.check=matrix(0,nr=nrow(coef.table),nc=ncol(coef.table),dimnames=list(varlist,market))
      for (i in 1:nrow(coef.table)){#i=1
        if (i <=num_ng_coef){
          coef.check[i,coef.table[i,]<0]=1
          #coef.check[i,coef.table[i,]>0]=0
        }else{
          #coef.check[i,coef.table[i,]<0]=0
          coef.check[i,coef.table[i,]>0]=1
        }
      }
      if (length(dum)!=0){
        for (j in 1:length(dum)){#i=1
          coef.check[dum[j],]=dum_matrix[,j]
        }
      }
      
      coef.change=coef.check-coef.check.pre
      if (sum(coef.change)==0) {
        print("modelling is done.") 
        break 
      }
      
      # Recreate the regressor matrix
      for (j in 1:length(market)){#j=1
        x[[j]]=as.data.frame(x[[j]][,varlist[coef.check[,j]==1]])
      }
      coef.check.pre=coef.check
    }
    
  } #DLM loop
  if(length(varlist)!=0) colnames(coef.table)=market
  
  # coef table for output
  if(length(varlist)!=0){
    var.in=rep(0,length(varlist))
    for (i in 1:length(varlist)){
      if (sum(coef.table[i,])!=0) var.in[i]=1
    }
    coef.table.output=data.frame(var=varlist,status=var.in,coef.table)
  } 
  
  
  # compute decomp
  level=vector("list",length(market))
  slope=vector("list",length(market))
  trend=vector("list",length(market))
  sea=vector("list",length(market))
  reg=vector("list",length(market))
  predict=vector("list",length(market))
  decomp=vector("list",length(market))
  res=vector("list",length(market))
  
  for (i in 1:length(market)){ #i=1
    if (level_type==2){
      
      if(length(varlist)!=0){
        level[[i]]=dropFirst(s[[i]]$s[,ncol(x[[i]])+1])*ymean[[i]]
        slope[[i]]=dropFirst(s[[i]]$s[,ncol(x[[i]])+2])*ymean[[i]]
        trend[[i]]=level[[i]]+slope[[i]]
        sea[[i]]=apply(dropFirst(s[[i]]$s[,(ncol(x[[i]])+3):ncol(s[[i]]$s)]),1,sum)*ymean[[i]]
        reg[[i]]=x[[i]]*dropFirst(s[[i]]$s[,1:sum(coef.check.pre[,i])])*ymean[[i]]
        predict[[i]]=(apply(reg[[i]],1,sum)+trend[[i]]+sea[[i]])
        res[[i]]=yreal[[i]]-predict[[i]]
        decomp[[i]]=data.frame(date=date,market=rep(market[i],length(date)),actual=yreal[[i]],
                               predict=predict[[i]],upper=predict[[i]]+qnorm(CI.level+(1-CI.level)/2)*sqrt(sum(res[[i]]^2)/(length(yreal[[i]])-nrow(W(mod[[i]])))),
                               lower=predict[[i]]-qnorm(CI.level+(1-CI.level)/2)*sqrt(sum(res[[i]]^2)/(length(yreal[[i]])-nrow(W(mod[[i]])))),residual=res[[i]],
                               level=trend[[i]],season=sea[[i]],reg=apply(reg[[i]],1,sum),reg[[i]])
      }else{
        level[[i]]=dropFirst(s[[i]]$s[,1])*ymean[[i]]
        slope[[i]]=dropFirst(s[[i]]$s[,2])*ymean[[i]]
        trend[[i]]=level[[i]]+slope[[i]]
        sea[[i]]=apply(dropFirst(s[[i]]$s[,3:ncol(s[[i]]$s)]),1,sum)*ymean[[i]]
        predict[[i]]=trend[[i]]+sea[[i]]
        res[[i]]=yreal[[i]]-predict[[i]]
        decomp[[i]]=data.frame(date=date,market=rep(market[i],length(date)),actual=yreal[[i]],
                               predict=predict[[i]],upper=predict[[i]]+qnorm(CI.level+(1-CI.level)/2)*sqrt(sum(res[[i]]^2)/(length(yreal[[i]])-nrow(W(mod[[i]])))),
                               lower=predict[[i]]-qnorm(CI.level+(1-CI.level)/2)*sqrt(sum(res[[i]]^2)/(length(yreal[[i]])-nrow(W(mod[[i]])))),residual=res[[i]],
                               level=trend[[i]],season=sea[[i]])
      }
      
      
    }else if (level_type==1){
      
      if(length(varlist)!=0){
        level[[i]]=dropFirst(s[[i]]$s[,ncol(x[[i]])+1])*ymean[[i]]
        trend[[i]]=level[[i]]
        sea[[i]]=apply(dropFirst(s[[i]]$s[,(ncol(x[[i]])+2):ncol(s[[i]]$s)]),1,sum)*ymean[[i]]
        reg[[i]]=x[[i]]*dropFirst(s[[i]]$s[,1:sum(coef.check.pre[,i])])*ymean[[i]]
        predict[[i]]=(apply(reg[[i]],1,sum)+trend[[i]]+sea[[i]])
        res[[i]]=yreal[[i]]-predict[[i]]
        decomp[[i]]=data.frame(date=date,market=rep(market[i],length(date)),actual=yreal[[i]],
                               predict=predict[[i]],upper=predict[[i]]+qnorm(CI.level+(1-CI.level)/2)*sqrt(sum(res[[i]]^2)/(length(yreal[[i]])-nrow(W(mod[[i]])))),
                               lower=predict[[i]]-qnorm(CI.level+(1-CI.level)/2)*sqrt(sum(res[[i]]^2)/(length(yreal[[i]])-nrow(W(mod[[i]])))),residual=res[[i]],
                               level=trend[[i]],season=sea[[i]],reg=apply(reg[[i]],1,sum),reg[[i]])
      }else{
        level[[i]]=dropFirst(s[[i]]$s[,1])*ymean[[i]]
        trend[[i]]=level[[i]]
        sea[[i]]=apply(dropFirst(s[[i]]$s[,2:ncol(s[[i]]$s)]),1,sum)*ymean[[i]]
        predict[[i]]=trend[[i]]+sea[[i]]
        res[[i]]=yreal[[i]]-predict[[i]]
        decomp[[i]]=data.frame(date=date,market=rep(market[i],length(date)),actual=yreal[[i]],
                               predict=predict[[i]],upper=predict[[i]]+qnorm(CI.level+(1-CI.level)/2)*sqrt(sum(res[[i]]^2)/(length(yreal[[i]])-nrow(W(mod[[i]])))),
                               lower=predict[[i]]-qnorm(CI.level+(1-CI.level)/2)*sqrt(sum(res[[i]]^2)/(length(yreal[[i]])-nrow(W(mod[[i]])))),residual=res[[i]],
                               level=trend[[i]],season=sea[[i]])
      }
    }
  }
  
  rbind.ordered=function(x,y,fill){ 
    # x: dataset1; y: dataset2; fill: character or number for missing value
    
    diffCol = setdiff(colnames(x),colnames(y))
    if (length(diffCol)>0){
      cols=colnames(y)
      temp=matrix(fill,nr=nrow(y),nc=length(diffCol))
      y=cbind(y,temp)
      colnames(y)=c(cols,diffCol)
    }
    
    diffCol = setdiff(colnames(y),colnames(x))
    if (length(diffCol)>0){
      cols=colnames(x)
      temp=matrix(fill,nr=nrow(x),nc=length(diffCol))
      x=cbind(x,temp)
      colnames(x)=c(cols,diffCol)
    }
    return(rbind(x, y[, colnames(x)]))
  }
  if(length(varlist)!=0){
    decomp.na=matrix(nr=0,nc=10+length(varlist),dimnames=
                       list(NULL,c("date","market","actual","predict","upper","lower","residual","level","season","reg",varlist)))
  }else{
    decomp.na=matrix(nr=0,nc=10,dimnames=
                       list(NULL,c("date","market","actual","predict","upper","lower","residual","level","season","reg")))
  }
  
  for (i in 1:length(market)){
    decomp.na=rbind.ordered(decomp.na,decomp[[i]],fill=0)
  }
  decomp_temp=melt(decomp.na,id=c("market","date"))
  decomp.agg=dcast(decomp_temp,date~variable,sum)
  
  # diagnose
  res=decomp.agg$residual
  MAPE=mean(abs(res)/decomp.agg$actual)*100
  temp=rep(0,(length(res)-1))
  for (i in 1:(length(res)-1)){
    temp[i]=res[i+1]-res[i]
  }
  dw=sum(temp^2)/sum(res^2)
  r2=1-sum(res^2)/sum((decomp.agg$actual-mean(decomp.agg$actual))^2)
  diagnose=data.frame(MAPE=MAPE,DW=dw,Rsquare=r2,level_type=level_type,var_coef=var_coef,
                      var_level=var_level,var_slope=var_slope,ord_sea=ord_sea,var_sea=var_sea,CI.level=CI.level,
                      no.unknown.par=no.par,optim.method=optim.method,
                      optim.ub=optim.ub,optim.lb=optim.lb)
  
  # compute contribution
  decomp=decomp.agg
  decomp=decomp[decomp$date>=start.date.c&decomp$date<=end.date.c,]
  decomp_name=names(decomp)
  contb=rep(0,ncol(decomp))
  account=rep(0,ncol(decomp))
  npv=rep(0,ncol(decomp))
  for (i in 2:ncol(decomp)){
    account[i]=sum(decomp[,i])
    npv[i]=sum(decomp[,i])*clv
    contb[i]=sum(decomp[,i])/sum(decomp$actual)
  }
  contb_data=data.frame(var=decomp_name,contrbution=contb,account=account,npv=npv)
  contb_data=contb_data[-1,]
  
  # compute forecast
  #for (i in 1:length(market)){
  #  forecast[[i]]=dlmForecast(
  #    f[[i]],nAhead=nAhead)$a[,sum(coef.check.pre[,i])+1]*ymean[[i]]
  #}
  #forecast.all=do.call(cbind,forecast)
  ############################################################################
  # 3, Graph output
  ############################################################################
  if (is.graph){
    plot_level_range=c(0,max(decomp.agg$actual)*1.3)
    opar=par(no.readonly=TRUE)
    #dev.new()
    par(mfrow=c(3,1))
    plot(decomp.agg$date,decomp.agg$reg,type="l",lwd=2,main="Regresion")
    plot(decomp.agg$date,decomp.agg$season,type="l",lwd=2,main="Seasonality")
    plot(decomp.agg$date,decomp.agg$level,type="l",lwd=2,main="Level")
    #dev.new()
    par(mfrow=c(2,2))
    hist(decomp.agg$residual,freq=FALSE,col="light gray",main="Histogram of Residuals",xlab="Residual")
    lines(density(decomp.agg$residual),col="red",lwd=2)
    qqnorm(decomp.agg$residual,main="Q-Q Plot of Residuals")
    qqline(decomp.agg$residual)
    plot(x=decomp.agg$predict, y=scale(decomp.agg$residual), main="Residual Plot",
         xlab="Predict", ylab="Standardized Residual", pch=16)
    abline(h=2,lty=2,col="blue");abline(h=-2,lty=2,col="blue")
    acf(decomp.agg$residual)
    #dev.new()
    par(mfrow=c(3,1))
    dlevel_reg=decomp.agg$reg+decomp.agg$level
    plot(decomp.agg$date,decomp.agg$actual,type="l",lwd=2,main="Level+Season+Reg")
    lines(decomp.agg$date,decomp.agg$predict,col="red",lty=1,lwd=2)
    lines(decomp.agg$date,decomp.agg$upper,col="blue",lty=3,lwd=1)
    lines(decomp.agg$date,decomp.agg$lower,col="blue",lty=3,lwd=1)
    plot(decomp.agg$date,decomp.agg$actual,type="l",lwd=2,main="Level+Reg")
    lines(decomp.agg$date,dlevel_reg,col="green",lty=1,lwd=2)
    plot(decomp.agg$date,decomp.agg$actual,type="l",main="Level",lwd=2,ylim=plot_level_range)
    lines(decomp.agg$date,decomp.agg$level,col="dark blue",lty=1,lwd=2)
    par(opar)
    end=Sys.time()-start
    print(paste("modelling time: ",round(end[[1]],digit=2),attr(end,"units"),sep=""))
  }
  ############################################################################
  # 4, Result output
  ############################################################################
  if (is.output){
    write.csv(decomp.na,paste(model.name,"_DLM_decomp_DMA.csv",sep=""),row.names=F) # DMA level decomp
    write.csv(decomp.agg,paste(model.name,"_DLM_decomp_NAT.csv",sep=""),row.names=F) # National level decomp
    write.csv(contb_data,paste(model.name,"_DLM_con",contrb.date,".csv",sep=""),row.names=F) # Contribution of certain period
    if (length(varlist!=0)) write.csv(coef.table.output,paste(model.name,"_DLM_var.csv",sep=""),row.names=F) # Covariates coming in the model
    write.csv(diagnose,paste(model.name,"_DLM_dx.csv",sep=""),row.names=F) # Residual diagnose 
    #save.image(paste(model.name,"_DLM.RData",sep=""))
  }
  if (length(varlist!=0)) return(list(stat=diagnose,coef=coef.table.output,decomp=decomp.na)) else
    return(list(stat=diagnose,decomp=decomp.na))
}
xinzhou1023/dlmpanel documentation built on May 4, 2019, 1:07 p.m.