Skip to Main Content

Function Linear.R

  ###################################################
### Refit the model with the selected variables ###
###################################################

### Inputs:
        # x: design matrix
        # y: response vector
        # beta: original coeffecients
### Output:
        # updated coefficients

update.beta <- function(x, y, beta) {
        pos <- which(abs(beta[-1]) > 1e-10)
        beta.refit <- rep(0, length(beta))
        if (length(pos) >= 1) {
                refit <- lm(y ~ x[, pos])
                beta.refit[c(1, pos + 1)] <- refit$coef
                return(beta.refit)
        }
        else {
                # refit <- lm(y ~ 1)
                beta.refit[1] <- mean(y)
                return(beta.refit)
    }
}

########################################
### Calculate mean squared residuals ###
########################################

### Inputs:
        # as in update.beta
### Output:
        # mean squared residuals

MSR.function <- function(x, y, beta) {
        eta <- cbind(rep(1, nrow(x)), x) %*% beta
        res <- y - eta
        return(sum(res * res)/nrow(x))
}

#######################################################
### pLASSO in linear regression by cross validation ###
#######################################################

### This is the main function for linear regression with cross validation.
### It can find each unweighted penalization estimators: LASSO, p, pLASSO.
### It can find each weighted penalization estimators: LASSO-A, p-A, pLASSO-A.
### For details of the above terms, refer to the paper.

### Inputs:
        # x: design matrix
        # y: response vector
        # eta.seq: the sequence of eta, the parameter tuning the prior information [(6) in the paper]
                # for LASSO/p/pLASSO, use eta sequence
                # for LASSO-A/p-A/pLASSO-A, use 0
        # tau.seq: the sequence of tau, the parameter tuning the L1 penalty weights [(35) in the paper]
                # for LASSO/p/pLASSO, use 0
                # for LASSO-A/p-A/pLASSO-A, use tau sequence
        # beta.prior: either the prior estimator or the initial estimator
                # for LASSO/p: use a vector with all 0
                # for pLASSO: use prior estimator
                # for LASSO-A: use LASSO estimator
                # for p-A: use prior estimator
                # for pLASSO-A: use pLASSO estimator
        # penalty.factor: a vector of indicators of which predictors are penalized (yes/no: 1/0)
        # cv.group: the index of cross validation groups
        # is.refit: is the estimator refitted (yes/no: 1/0)?
### Output:
        # the optimal estimator with cross validation
        
find.beta <- function(x, y, eta.seq, tau.seq, beta.prior, penalty.factor, cv.group, is.refit)
{
        n.group <- length(unique(cv.group))
        y.prior <- cbind(1, x) %*% beta.prior
        log.liklhd.eta.tau <- matrix(0, length(eta.seq), length(tau.seq))
        betas.eta.tau <- array(0, dim = c(ncol(x) + 1, length(eta.seq), length(tau.seq)))
        
        for(k in 1 : length(eta.seq)) 
        {
                eta <- eta.seq[k]
                y.tilde <- (y + eta * y.prior)/(1 + eta)
                for(l in 1 : length(tau.seq))
                {
                        tau <- tau.seq[l]
                        Winv <- 1 + tau * abs(beta.prior[-1])
                        x.Winv <- x * (matrix(1, nrow = nrow(x)) %*% Winv)
                        fits <- glmnet(x.Winv, y.tilde, standardize = FALSE, penalty.factor = penalty.factor)
                        
                        lambda.seq <- fits$lambda
                        log.liklhd <- matrix(0, length(lambda.seq), n.group)
                        a0s <- fits$a0
                        betas <- fits$beta
                
                        for(j in 1 : n.group)
                        {
                                sel <- (cv.group != j)
                                x.Winv.train <- x.Winv[sel, ]
                                y.tilde.train <- y.tilde[sel]
                                x.tune <- x[!sel, ]
                                y.tune <- y[!sel]
                                fits <- glmnet(x.Winv.train, y.tilde.train, standardize = FALSE, penalty.factor = penalty.factor)
                                
                                for(i in 1 : length(lambda.seq))
                                {
                                        beta <- coef(fits, s = lambda.seq[i])
                                        beta.refit <- rep(0, length(beta))
                                        if(is.refit) {
                                                temp <- update.beta(x.Winv.train, y.tilde.train, beta)
                                        }
                                        else {
                                                temp <- beta
                                        }
                                        beta.refit[1] <- temp[1]
                                        beta.refit[-1] <- Winv * temp[-1]
                                        log.liklhd[i, j] <- MSR.function(x.tune, y.tune, beta.refit) * (-1)
                                }
                        }
                        
                        mean.log.liklhd <- apply(log.liklhd, 1, mean)
                        se.log.liklhd <- apply(log.liklhd, 1, sd)/sqrt(n.group)
                        pos.max <- which.max(mean.log.liklhd)
                        # cat("pos.max = ", pos.max, "\n")
                        # one standard error rule
                        temp <- which(mean.log.liklhd >= mean.log.liklhd[pos.max] - se.log.liklhd[pos.max])
                        pos.1se <- temp[1]
                        # cat("pos.1se = ", pos.1se, "\n")

                        log.liklhd.eta.tau[k, l] <- mean.log.liklhd[pos.1se]
                        betas.eta.tau[, k, l] <- c(a0s[pos.1se], betas[, pos.1se])
                }
        }
        
        pos.max.eta.tau <- which(log.liklhd.eta.tau == max(log.liklhd.eta.tau), arr.ind = TRUE)
        if(nrow(pos.max.eta.tau) > 1) {
                cat("pos.max.eta.tau has more than one row", "\n")
                pos.max.eta.tau <- pos.max.eta.tau[nrow(pos.max.eta.tau), ]
        }
        eta <- eta.seq[pos.max.eta.tau[1]]
        tau <- tau.seq[pos.max.eta.tau[2]]
        
        if(length(eta.seq) > 1 && length(tau.seq) == 1) {
                cat("plasso: selected eta is ", eta, "\n")
        }
        if(length(eta.seq) == 1 && length(tau.seq) > 1) {
                cat("alasso: selected tau is ", tau, "\n")
        }
        if(length(eta.seq) > 1 && length(tau.seq) > 1) {
                cat("plasso + alasso: selected eta is ", eta, " and selected tau is ", tau, "\n")
        }
        
        y.tilde <- (y + eta * y.prior)/(1 + eta)
        Winv <- 1 + tau * abs(beta.prior[-1])
        x.Winv <- x * (matrix(1, nrow = nrow(x)) %*% Winv)
        beta <- betas.eta.tau[, pos.max.eta.tau[1], pos.max.eta.tau[2]]
        beta.refit <- rep(0, length(beta))
        if(is.refit) {
                temp <- update.beta(x.Winv, y.tilde, beta)
        }
        else {
                temp <- beta
        }
        beta.refit[1] <- temp[1]
        beta.refit[-1] <- Winv * temp[-1]
        
        return(beta.refit = beta.refit)
}