R/pamls.R

Defines functions BIC4PAMLS SoftThreshold Innerpamls2 Innerpamls ComputeParameter pamlsreg pamls

pamls= function(x, y, penalty1 = c("L1"), penalty2 = c("L1"), lambda1 = NULL, 
    lambda2 = NULL, nlambda1 = 50, nlambda2 = 100, 
    lambda1.min=1e-03, 
    lambda2.min=0.05, 
    beta0 = NULL, gam0 = NULL, startBeta = NULL, startGam = NULL, initial = "uniform", delta = 1e-06, maxIter = 1000, intercept = TRUE, standardize = TRUE, updateInitialTimes = 0, 
    criterion = c("BIC", "AIC"), initCrit=c("BIC", "AIC"), search = c("cross", "all"), ...) {
    ## error checking
    if (class(x) != "matrix") {
        tmp <- try(x <- as.matrix(x), silent = TRUE)
        if (class(tmp)[1] == "try-error") 
            stop("x must be a matrix or able to be coerced to a matrix")
    }
    if (class(y) != "numeric") {
        tmp <- try(y <- as.numeric(y), silent = TRUE)
        if (class(tmp)[1] == "try-error") 
            stop("y must numeric or able to be coerced to numeric")
    }
    
    criterion <- match.arg(criterion)
    initCrit <- match.arg(initCrit)
    search <- match.arg(search)
    
    
    # if (nlambda1 < 2||nlambda2<2) stop('nlambda must be at least 2')
    if (!is.null(lambda1)) 
        nlambda1 = length(lambda1)
    if (!is.null(lambda2)) 
        nlambda2 = length(lambda2)
    
    if (any(is.na(y)) | any(is.na(x))) 
        stop("Missing data (NA's) detected.Take actions to eliminate missing data before passing X and y to pamls.")
    
    # initial
    n = length(y)
    p = dim(x)[2]
    if (initial == "PAMLS") {
      init = pamls(x, y, intercept = intercept,criterion = initCrit, search = "all")
      beta0 = init$beta
      gam0 = init$gam
    } else if (initial == "uniform") {
        if (is.null(beta0)) {
            beta0 = rep(1, p)
            if (intercept) 
                beta0 = c(1, beta0)
        }
        if (is.null(gam0)) {
            gam0 = rep(1, n)
        }
    }
    b = 1e-6  
    beta0 = ifelse(abs(beta0) < b, b, beta0)
    gam0 = ifelse(abs(gam0) < b, b, gam0)
    
    
    # intercept
    if (intercept) {
        x = cbind(rep(1,n), x)
    }
    
    # sandardize
    std = 0
    scale = 0
    if (standardize) {
        std <- .Call("Standardize", x, y)
        XX <- std[[1]]
        yy <- std[[2]]
        scale <- std[[3]]
    } else {
        XX = x
        yy = y
    }
    
    ## setup parameter
    if (missing(lambda1) || missing(lambda2)||is.null(lambda1)||is.null(lambda2)) {
        lambda = ComputeParameter(XX, yy, nlambda1, nlambda2, lambda1.min=lambda1.min, lambda2.min=lambda2.min, beta0, gam0)
        if (is.null(lambda1)) 
            lambda1 = lambda$lambda1
        if (is.null(lambda2)) 
            lambda2 = lambda$lambda2
    }
    
    ## Fit
    
    if (criterion == "BIC" || criterion == "AIC") {
        # search for the whole grid
        if (search == "all") {
            res = Innerpamls(XX, yy, lambda1, lambda2, beta0, gam0, delta, 
                maxIter, intercept = intercept)
            res = BIC4PAMLS(res$loss, res$beta, res$gam, lambda1, lambda2, criterion = criterion)
        } else {
            # (search=='cross')
            res = pamlsreg(XX, yy, lambda1, lambda2, beta0, gam0, delta, maxIter, 
                intercept = intercept, criterion = criterion, startBeta = startBeta, startGam = startGam)
        }
        
    } 
    ## unstandardize
    if (standardize) {
        scale = ifelse(scale == 0, 0, 1/scale)
        res$beta = res$beta * scale
    }
    res
}
# without search the whole grid of lambda
pamlsreg= function(x, y,lambda1, lambda2, beta0, gam0, delta, maxIter, intercept = TRUE,
                   criterion = "BIC", startBeta = NULL, startGam = NULL) {
  L1 = length(lambda1)
  L2 = length(lambda2)
  m = dim(x)[2]
  n = length(y)
  pre1 = pre2 = 0
  lmaxIter = 50
  
  # initial lambda
  index2 = round(L2/2)
  res = Innerpamls(x, y, lambda1, lambda2[index2], beta0, gam0, delta, maxIter, 
                 intercept = intercept, startBeta = startBeta, startGam = startGam)  #fix lambda2
  bic1 = BIC4PAWLS(as.vector(res$loss), apply(matrix(res$gam, L1, n) != 0 + 0, 1, sum), 
                   apply(matrix(res$beta, L1, m) != 0 + 0, 1, sum), n, m, criterion = criterion) 
  index1 =bic1$index  #find best lambda1
  crit1 = bic1$crit
  
  res = Innerpamls(x, y,lambda1[index1], lambda2, beta0, gam0, delta, maxIter, 
                 intercept = intercept, startBeta = startBeta, startGam = startGam)  #fix lambda1
  bic2 = BIC4PAWLS(as.vector(res$loss), apply(matrix(res$gam, L2, n) != 0 + 0, 1, sum),
                   apply(matrix(res$beta,L2, m) != 0 + 0, 1, sum), n, m, 
                   criterion = criterion)
  index2 = bic2$index  #find best lambda2
  crit2 = bic2$crit
  ## loop to estimate and find the best
  iter = 0
  
  while ((pre1 != index1 || pre2 != index2) && (iter < lmaxIter)) {
    iter = iter + 1
    pre1 = index1
    pre2 = index2
    
    resg = Innerpamls(x, y, lambda1, lambda2[index2], beta0, gam0, delta, 
                    maxIter, intercept = intercept, startBeta = startBeta, startGam = startGam)  #fix lambda2
    bic1 = BIC4PAWLS(as.vector(resg$loss), apply(matrix(resg$gam, L1, n) != 0 + 0, 1, sum), 
                     apply(matrix(resg$beta, L1, m) != 0 + 0, 1, sum), n, m, criterion = criterion) 
    index1 =bic1$index  #find best lambda1
    crit1 = bic1$crit
    
    res = Innerpamls(x, y,lambda1[index1], lambda2, beta0, gam0, delta, 
                   maxIter, intercept = intercept, startBeta = startBeta, startGam = startGam)  #fix lambda1
    bic2 = BIC4PAWLS(as.vector(res$loss), apply(matrix(res$gam, L2, n) != 0 + 0, 1, sum),
                     apply(matrix(res$beta,L2, m) != 0 + 0, 1, sum), n, m, 
                     criterion = criterion)
    index2 = bic2$index  #find best lambda2
    crit2 = bic2$crit
    if (pre2 == index2 && pre1 == index1) 
    {
      break
    }
    
  }
  
  list(lambda1 = lambda1[index1], lambda2 = lambda2[index2], beta = as.vector(res$beta[1, index2, ]), 
       gam = as.vector(res$gam[1,index2, ]), loss = res$loss[1,index2], bdf = sum(res$beta[1, index2, ] != 0), 
       gdf = sum(res$gam[1, index2,] != 0), index1 = index1, index2 = index2, iter = iter, gam0 = gam0, 
       beta0 = beta0, lambda1s = lambda1, lambda2s = lambda2, 
       betas = matrix(res$beta, L2, m), gams = matrix(resg$gam, L1, n), crit1=crit1, crit2=crit2)
  
}

ComputeParameter = function(x, y, nlambda1, nlambda2,lambda1.min=1e-03, lambda2.min=0.05, beta0, gam0) {
  n = length(y)
  p =dim(x)[2]
  lambda1Max = max(abs(y * gam0 / n))
  lambda2Max = max(abs(t(x) %*% y/n) * abs(beta0))  # max |betaj|*|xj'y/n|
  lambda1 = logSeq2(lambda1Max, lambda1Max * lambda1.min, nlambda1)
  lambda2 = logSeq2(lambda2Max, lambda2Max * lambda2.min, nlambda2)
  return(list(lambda1 = lambda1, lambda2 = lambda2))
}

Innerpamls = function(x, y,lambda1, lambda2, beta0, gam0, delta, maxIter, intercept = TRUE, 
                      startBeta = NULL, startGam = NULL) {
   #return (res2=Innerpamls2(x, y,lambda1,lambda2,beta0,gam0,delta,maxIter,intercept,startBeta=startBeta,startGam = startGam))
  L1 = length(lambda1)
  L2 = length(lambda2)
  m = dim(x)[2]
  n = dim(x)[1]
  if (is.null(startBeta)) {
    startBeta = rep(0, m)
  }
  if (is.null(startGam)) {
    startGam = rep(0, n)
  }
  res <- .Call("INNERPAMLS", x, y,lambda1, lambda2, beta0, gam0, delta, maxIter, ifelse(intercept,1, 0), startBeta = startBeta, startGam = startGam)
  
  res = list(beta = array(res[[1]], dim = c(L1, L2, m)), gam = array(res[[2]], dim = c(L1, L2, n)),
             loss = array(res[[3]], dim = c(L1, L2)), iter = array(res[[4]], dim = c(L1, L2)))
  
  res
  
}

Innerpamls2 = function(x, y,lambda1, lambda2, beta0, gam0, delta, maxIter, intercept = TRUE, 
                     startBeta = NULL, startGam = NULL) {
  
  ## declaration
  n = length(y)
  m = dim(x)[2]
  p = m
  L1 = length(lambda1)
  L2 = length(lambda2)
  lstart1 = 1  ##should be 1
  lstart2 = 1
  
  ## reslut to be returned
  beta = array(0, dim = c(L1, L2, m))
  gam = array(0, dim = c(L1, L2, n))
  loss = matrix(ncol = L2, nrow = L1, 0)
  iter = matrix(ncol = L2, nrow = L1, 0)
  
  betaPre = rep(0, m)
  gamPre = rep(0, n)
  if (!is.null(startBeta)) {
    betaPre = startBeta
  }
  if (!is.null(startGam)) {
    gamPre = startGam
  }
  r = y - x %*% betaPre
  ## iteration for each lamda1
  for (l1 in lstart1:L1) {
    ## initial
    
    shift = rep(0, m + n)
    loss[l1, 1] = t(r - gamPre) %*% (r - gamPre)  ##initial loss[l1,1]
    lam1 = (lambda1[l1]/abs(gam0)) * n
    
    ## iteration for each lamda2
    for (l2 in lstart2:L2) {
      lam2 = lambda2[l2]/abs(beta0)
      if (intercept) {
        lam2[1] = 0
      }
      ## iteration for all covariates
      while (iter[l1, l2] < maxIter) {
        iter[l1, l2] = iter[l1, l2] + 1
        
        ## iteration for each beta
        for (j in 1:m) {
          ## (1)calculate zj
          zj = t(x[, j]) %*% (r - gamPre)/n + betaPre[j]
          ## (2)update betaj
          beta[l1, l2, j] = SoftThreshold(zj, lam2[j])

          ## (3)update r
          shift[j] = beta[l1, l2, j] - betaPre[j]
          r = r - x[, j] * shift[j]
        }
        
        ## update gamma
        gam[l1, l2, ]=SoftThreshold(r,lam1)
        shift[(m + 1):(m + n)] = gam[l1, l2, ] - gamPre
        
        ## update betaPre and gamPre for next iteration
        betaPre = beta[l1, l2, ]
        gamPre = gam[l1, l2, ]
        ## Check for convergence
        if (t(shift) %*% shift < delta) {
          break
        }
        
      }  #end for the inner loop
      
      ## compute square of loss
      loss[l1, l2] = t(r - gamPre) %*% (r - gamPre)
      
      ## reset betaPre and gamPre for next lambda if(!is.null(startBeta)) { betaPre=startBeta r=starRes }
      ## if(!is.null(startGam)) { gamPre=startGam }
      
    }  #end iteration for each lambda2 fixed lambda1
    
  }  #end iteration for each lambda1
  list(beta = beta, loss = loss, iter = iter, gam = gam)
}

SoftThreshold <- function(z,lambda){
  ifelse(abs(z) <= lambda, 0, ifelse(z >lambda,z-lambda,z+lambda))
}

BIC4PAMLS = function(loss, beta, gam, lambda1, lambda2,criterion = "BIC") {
  # declare and initial
  l1 = length(lambda1)
  l2 = length(lambda2)
  index1 = index2 = 1
  BIC.max= 1e+08
  bicPre = BIC.max
  bicTemp = matrix(0, l1, l2)
  gdf = matrix(0, l1, l2)
  bdf = matrix(0, l1, l2)
  start1 = 1
  end1 = l1
  start2 = 1
  end2 = l2
  n = length(gam[1, 1, ])
  bicTemp2=matrix(0, l1, l2)
  pro=0.5
  for (i in start1:end1) {
    for (j in start2:end2) {
      gdf[i, j] = sum(gam[i, j, ] != 0)
      bdf[i, j] = sum(beta[i, j, ] != 0)
      if (criterion == "AIC") {
        bicTemp[i, j] = log(loss[i, j]/(n)) + (bdf[i, j] + gdf[i, j]) * 2/(n)
      } else {
        # (log(loss/n+a)+log(n)*df/(n))
        bicTemp[i, j] = log(loss[i, j]/(n)) + (bdf[i, j] + gdf[i, j]) * log(n)/(n)
      }
      #compute limit of lambda1 & lambda2
      if(gdf[i,j] >= n * pro || bdf[i,j] + gdf[i,j] >= n){
        bicTemp2[i,j]=-BIC.max
      }else{
        bicTemp2[i,j]=bicTemp[i,j]
        if (bicTemp[i, j] <= bicPre) {
          index1 = i
          index2 = j
          bicPre = bicTemp[i, j]
        }
      }
    }
  }
  bicTemp2 <- ifelse(bicTemp2==-BIC.max,max(bicTemp),bicTemp2)
  res = list(lambda1 = lambda1, lambda2 = lambda2, bdf = bdf, gdf = gdf, bic = bicTemp, bic2=bicTemp2,gam = gam, beta = beta)
  i = index1
  j = index2
  list(lambda1s = lambda1, lambda2s = lambda2, beta = beta[i, j, ], gam = gam[i, j, ], loss = loss[i, j], 
       bdf = bdf[i, j], gdf = gdf[i, j], index1 = i, index2 = j, iter=0,crit1=bicTemp[,j], crit2=bicTemp[i,],res = res)
}
r08in/RobustCD documentation built on Oct. 17, 2023, 7:42 p.m.