#' fit a GLM with lasso or elasticnet regularization #' #' Fit a generalized linear model via penalized maximum likelihood. The #' regularization path is computed for the lasso or elasticnet penalty at a #' grid of values for the regularization parameter lambda. Can deal with all #' shapes of data, including very large sparse data matrices. Fits linear, #' logistic and multinomial, poisson, and Cox regression models. #' #' The sequence of models implied by \code{lambda} is fit by coordinate #' descent. For \code{family="gaussian"} this is the lasso sequence if #' \code{alpha=1}, else it is the elasticnet sequence. #' #' The objective function for \code{"gaussian"} is \deqn{1/2 RSS/nobs + #' \lambda*penalty,} and for the other models it is \deqn{-loglik/nobs + #' \lambda*penalty.} Note also that for \code{"gaussian"}, \code{glmnet} #' standardizes y to have unit variance (using 1/n rather than 1/(n-1) formula) #' before computing its lambda sequence (and then unstandardizes the resulting #' coefficients); if you wish to reproduce/compare results with other software, #' best to supply a standardized y. The coefficients for any predictor #' variables with zero variance are set to zero for all values of lambda. #' #' ## Details on `family` option #' #' From version 4.0 onwards, glmnet supports both the original built-in families, #' as well as \emph{any} family object as used by `stats:glm()`. #' This opens the door to a wide variety of additional models. For example #' `family=binomial(link=cloglog)` or `family=negative.binomial(theta=1.5)` (from the MASS library). #' Note that the code runs faster for the built-in families. #' #' The built in families are specifed via a character string. For all families, #' the object produced is a lasso or elasticnet regularization path for fitting the #' generalized linear regression paths, by maximizing the appropriate penalized #' log-likelihood (partial likelihood for the "cox" model). Sometimes the #' sequence is truncated before \code{nlambda} values of \code{lambda} have #' been used, because of instabilities in the inverse link functions near a #' saturated fit. \code{glmnet(...,family="binomial")} fits a traditional #' logistic regression model for the log-odds. #' \code{glmnet(...,family="multinomial")} fits a symmetric multinomial model, #' where each class is represented by a linear model (on the log-scale). The #' penalties take care of redundancies. A two-class \code{"multinomial"} model #' will produce the same fit as the corresponding \code{"binomial"} model, #' except the pair of coefficient matrices will be equal in magnitude and #' opposite in sign, and half the \code{"binomial"} values. #' Two useful additional families are the \code{family="mgaussian"} family and #' the \code{type.multinomial="grouped"} option for multinomial fitting. The #' former allows a multi-response gaussian model to be fit, using a "group #' -lasso" penalty on the coefficients for each variable. Tying the responses #' together like this is called "multi-task" learning in some domains. The #' grouped multinomial allows the same penalty for the #' \code{family="multinomial"} model, which is also multi-responsed. For both #' of these the penalty on the coefficient vector for variable j is #' \deqn{(1-\alpha)/2||\beta_j||_2^2+\alpha||\beta_j||_2.} When \code{alpha=1} #' this is a group-lasso penalty, and otherwise it mixes with quadratic just #' like elasticnet. A small detail in the Cox model: if death times are tied #' with censored times, we assume the censored times occurred just #' \emph{before} the death times in computing the Breslow approximation; if #' users prefer the usual convention of \emph{after}, they can add a small #' number to all censoring times to achieve this effect. #' #' ## Details on response for `family="cox"` #' #' For Cox models, the response should preferably be a \code{Surv} object, #' created by the \code{Surv()} function in \pkg{survival} package. For #' right-censored data, this object should have type "right", and for #' (start, stop] data, it should have type "counting". To fit stratified Cox #' models, strata should be added to the response via the \code{stratifySurv()} #' function before passing the response to \code{glmnet()}. (For backward #' compatibility, right-censored data can also be passed as a #' two-column matrix with columns named 'time' and 'status'. The #' latter is a binary variable, with '1' indicating death, and '0' indicating #' right censored.) #' #' ## Details on `relax` option #' #' If \code{relax=TRUE} #' a duplicate sequence of models is produced, where each active set in the #' elastic-net path is refit without regularization. The result of this is a #' matching \code{"glmnet"} object which is stored on the original object in a #' component named \code{"relaxed"}, and is part of the glmnet output. #' Generally users will not call \code{relax.glmnet} directly, unless the #' original 'glmnet' object took a long time to fit. But if they do, they must #' supply the fit, and all the original arguments used to create that fit. They #' can limit the length of the relaxed path via 'maxp'. #' #' @param x input matrix, of dimension nobs x nvars; each row is an observation #' vector. Can be in sparse matrix format (inherit from class #' \code{"sparseMatrix"} as in package \code{Matrix}) #' @param y response variable. Quantitative for \code{family="gaussian"}, or #' \code{family="poisson"} (non-negative counts). For \code{family="binomial"} #' should be either a factor with two levels, or a two-column matrix of counts #' or proportions (the second column is treated as the target class; for a #' factor, the last level in alphabetical order is the target class). For #' \code{family="multinomial"}, can be a \code{nc>=2} level factor, or a matrix #' with \code{nc} columns of counts or proportions. For either #' \code{"binomial"} or \code{"multinomial"}, if \code{y} is presented as a #' vector, it will be coerced into a factor. For \code{family="cox"}, preferably #' a \code{Surv} object from the survival package: see Details section for #' more information. For \code{family="mgaussian"}, \code{y} is a matrix #' of quantitative responses. #' @param family Either a character string representing #' one of the built-in families, or else a `glm()` family object. For more #' information, see Details section below or the documentation for response #' type (above). #' @param weights observation weights. Can be total counts if responses are #' proportion matrices. Default is 1 for each observation #' @param offset A vector of length \code{nobs} that is included in the linear #' predictor (a \code{nobs x nc} matrix for the \code{"multinomial"} family). #' Useful for the \code{"poisson"} family (e.g. log of exposure time), or for #' refining a model by starting at a current fit. Default is \code{NULL}. If #' supplied, then values must also be supplied to the \code{predict} function. #' @param alpha The elasticnet mixing parameter, with \eqn{0\le\alpha\le 1}. #' The penalty is defined as #' \deqn{(1-\alpha)/2||\beta||_2^2+\alpha||\beta||_1.} \code{alpha=1} is the #' lasso penalty, and \code{alpha=0} the ridge penalty. #' @param nlambda The number of \code{lambda} values - default is 100. #' @param lambda.min.ratio Smallest value for \code{lambda}, as a fraction of #' \code{lambda.max}, the (data derived) entry value (i.e. the smallest value #' for which all coefficients are zero). The default depends on the sample size #' \code{nobs} relative to the number of variables \code{nvars}. If \code{nobs #' > nvars}, the default is \code{0.0001}, close to zero. If \code{nobs < #' nvars}, the default is \code{0.01}. A very small value of #' \code{lambda.min.ratio} will lead to a saturated fit in the \code{nobs < #' nvars} case. This is undefined for \code{"binomial"} and #' \code{"multinomial"} models, and \code{glmnet} will exit gracefully when the #' percentage deviance explained is almost 1. #' @param lambda A user supplied \code{lambda} sequence. Typical usage is to #' have the program compute its own \code{lambda} sequence based on #' \code{nlambda} and \code{lambda.min.ratio}. Supplying a value of #' \code{lambda} overrides this. WARNING: use with care. Avoid supplying a #' single value for \code{lambda} (for predictions after CV use #' \code{predict()} instead). Supply instead a decreasing sequence of #' \code{lambda} values. \code{glmnet} relies on its warms starts for speed, #' and its often faster to fit a whole path than compute a single fit. #' @param standardize Logical flag for x variable standardization, prior to #' fitting the model sequence. The coefficients are always returned on the #' original scale. Default is \code{standardize=TRUE}. If variables are in the #' same units already, you might not wish to standardize. See details below for #' y standardization with \code{family="gaussian"}. #' @param intercept Should intercept(s) be fitted (default=TRUE) or set to zero #' (FALSE) #' @param thresh Convergence threshold for coordinate descent. Each inner #' coordinate-descent loop continues until the maximum change in the objective #' after any coefficient update is less than \code{thresh} times the null #' deviance. Defaults value is \code{1E-7}. #' @param dfmax Limit the maximum number of variables in the model. Useful for #' very large \code{nvars}, if a partial path is desired. #' @param pmax Limit the maximum number of variables ever to be nonzero #' @param exclude Indices of variables to be excluded from the model. Default #' is none. Equivalent to an infinite penalty factor for the variables excluded (next item). #' Users can supply instead an \code{exclude} function that generates the list of indices. #' This function is most generally defined as \code{function(x, y, weights, ...)}, #' and is called inside \code{glmnet} to generate the indices for excluded variables. #' The \code{...} argument is required, the others are optional. #' This is useful for filtering wide data, and works correctly with \code{cv.glmnet}. #' See the vignette 'Introduction' for examples. #' @param penalty.factor Separate penalty factors can be applied to each #' coefficient. This is a number that multiplies \code{lambda} to allow #' differential shrinkage. Can be 0 for some variables, which implies no #' shrinkage, and that variable is always included in the model. Default is 1 #' for all variables (and implicitly infinity for variables listed in #' \code{exclude}). Note: the penalty factors are internally rescaled to sum to #' nvars, and the lambda sequence will reflect this change. #' @param lower.limits Vector of lower limits for each coefficient; default #' \code{-Inf}. Each of these must be non-positive. Can be presented as a #' single value (which will then be replicated), else a vector of length #' \code{nvars} #' @param upper.limits Vector of upper limits for each coefficient; default #' \code{Inf}. See \code{lower.limits} #' @param maxit Maximum number of passes over the data for all lambda values; #' default is 10^5. #' @param type.gaussian Two algorithm types are supported for (only) #' \code{family="gaussian"}. The default when \code{nvar<500} is #' \code{type.gaussian="covariance"}, and saves all inner-products ever #' computed. This can be much faster than \code{type.gaussian="naive"}, which #' loops through \code{nobs} every time an inner-product is computed. The #' latter can be far more efficient for \code{nvar >> nobs} situations, or when #' \code{nvar > 500}. #' @param type.logistic If \code{"Newton"} then the exact hessian is used #' (default), while \code{"modified.Newton"} uses an upper-bound on the #' hessian, and can be faster. #' @param standardize.response This is for the \code{family="mgaussian"} #' family, and allows the user to standardize the response variables #' @param type.multinomial If \code{"grouped"} then a grouped lasso penalty is #' used on the multinomial coefficients for a variable. This ensures they are #' all in our out together. The default is \code{"ungrouped"} #' @param relax If \code{TRUE} then for each \emph{active set} in the path of #' solutions, the model is refit without any regularization. See \code{details} #' for more information. This argument is new, and users may experience convergence issues #' with small datasets, especially with non-gaussian families. Limiting the #' value of 'maxp' can alleviate these issues in some cases. #' @param trace.it If \code{trace.it=1}, then a progress bar is displayed; #' useful for big models that take a long time to fit. #' @param ... Additional argument used in \code{relax.glmnet}. These include #' some of the original arguments to 'glmnet', and each must be named if used. #' @return An object with S3 class \code{"glmnet","*" }, where \code{"*"} is #' \code{"elnet"}, \code{"lognet"}, \code{"multnet"}, \code{"fishnet"} #' (poisson), \code{"coxnet"} or \code{"mrelnet"} for the various types of #' models. If the model was created with \code{relax=TRUE} then this class has #' a prefix class of \code{"relaxed"}. \item{call}{the call that produced this #' object} \item{a0}{Intercept sequence of length \code{length(lambda)}} #' \item{beta}{For \code{"elnet"}, \code{"lognet"}, \code{"fishnet"} and #' \code{"coxnet"} models, a \code{nvars x length(lambda)} matrix of #' coefficients, stored in sparse column format (\code{"CsparseMatrix"}). For #' \code{"multnet"} and \code{"mgaussian"}, a list of \code{nc} such matrices, #' one for each class.} \item{lambda}{The actual sequence of \code{lambda} #' values used. When \code{alpha=0}, the largest lambda reported does not quite #' give the zero coefficients reported (\code{lambda=inf} would in principle). #' Instead, the largest \code{lambda} for \code{alpha=0.001} is used, and the #' sequence of \code{lambda} values is derived from this.} \item{dev.ratio}{The #' fraction of (null) deviance explained (for \code{"elnet"}, this is the #' R-square). The deviance calculations incorporate weights if present in the #' model. The deviance is defined to be 2*(loglike_sat - loglike), where #' loglike_sat is the log-likelihood for the saturated model (a model with a #' free parameter per observation). Hence dev.ratio=1-dev/nulldev.} #' \item{nulldev}{Null deviance (per observation). This is defined to be #' 2*(loglike_sat -loglike(Null)); The NULL model refers to the intercept #' model, except for the Cox, where it is the 0 model.} \item{df}{The number of #' nonzero coefficients for each value of \code{lambda}. For \code{"multnet"}, #' this is the number of variables with a nonzero coefficient for \emph{any} #' class.} \item{dfmat}{For \code{"multnet"} and \code{"mrelnet"} only. A #' matrix consisting of the number of nonzero coefficients per class} #' \item{dim}{dimension of coefficient matrix (ices)} \item{nobs}{number of #' observations} \item{npasses}{total passes over the data summed over all #' lambda values} \item{offset}{a logical variable indicating whether an offset #' was included in the model} \item{jerr}{error flag, for warnings and errors #' (largely for internal debugging).} \item{relaxed}{If \code{relax=TRUE}, this #' additional item is another glmnet object with different values for #' \code{beta} and \code{dev.ratio}} #' @author Jerome Friedman, Trevor Hastie, Balasubramanian Narasimhan, Noah #' Simon, Kenneth Tay and Rob Tibshirani\cr Maintainer: Trevor Hastie #' \email{hastie@@stanford.edu} #' @seealso \code{print}, \code{predict}, \code{coef} and \code{plot} methods, #' and the \code{cv.glmnet} function. #' @references Friedman, J., Hastie, T. and Tibshirani, R. (2008) #' \emph{Regularization Paths for Generalized Linear Models via Coordinate #' Descent (2010), Journal of Statistical Software, Vol. 33(1), 1-22}, #' \url{https://web.stanford.edu/~hastie/Papers/glmnet.pdf}.\cr #' Simon, N., Friedman, J., Hastie, T. and Tibshirani, R. (2011) #' \emph{Regularization Paths for Cox's Proportional #' Hazards Model via Coordinate Descent, Journal of Statistical Software, Vol. #' 39(5), 1-13}, \url{https://www.jstatsoft.org/v39/i05/}.\cr Tibshirani, #' Robert, Bien, J., Friedman, J., Hastie, T.,Simon, N.,Taylor, J. and #' Tibshirani, Ryan. (2012) \emph{Strong Rules for Discarding Predictors in #' Lasso-type Problems, JRSSB, Vol. 74(2), 245-266}, #' \url{https://statweb.stanford.edu/~tibs/ftp/strong.pdf}.\cr #' Hastie, T., Tibshirani, Robert and Tibshirani, Ryan. \emph{Extended #' Comparisons of Best Subset Selection, Forward Stepwise Selection, and the #' Lasso (2017), Stanford Statistics Technical Report}, #' \url{https://arxiv.org/abs/1707.08692}.\cr #' Glmnet webpage with four vignettes, \url{https://glmnet.stanford.edu}. #' @keywords models regression #' @examples #' #' # Gaussian #' x = matrix(rnorm(100 * 20), 100, 20) #' y = rnorm(100) #' fit1 = glmnet(x, y) #' print(fit1) #' coef(fit1, s = 0.01) # extract coefficients at a single value of lambda #' predict(fit1, newx = x[1:10, ], s = c(0.01, 0.005)) # make predictions #' #' # Relaxed #' fit1r = glmnet(x, y, relax = TRUE) # can be used with any model #' #' # multivariate gaussian #' y = matrix(rnorm(100 * 3), 100, 3) #' fit1m = glmnet(x, y, family = "mgaussian") #' plot(fit1m, type.coef = "2norm") #' #' # binomial #' g2 = sample(c(0,1), 100, replace = TRUE) #' fit2 = glmnet(x, g2, family = "binomial") #' fit2n = glmnet(x, g2, family = binomial(link=cloglog)) #' fit2r = glmnet(x,g2, family = "binomial", relax=TRUE) #' fit2rp = glmnet(x,g2, family = "binomial", relax=TRUE, path=TRUE) #' #' # multinomial #' g4 = sample(1:4, 100, replace = TRUE) #' fit3 = glmnet(x, g4, family = "multinomial") #' fit3a = glmnet(x, g4, family = "multinomial", type.multinomial = "grouped") #' # poisson #' N = 500 #' p = 20 #' nzc = 5 #' x = matrix(rnorm(N * p), N, p) #' beta = rnorm(nzc) #' f = x[, seq(nzc)] %*% beta #' mu = exp(f) #' y = rpois(N, mu) #' fit = glmnet(x, y, family = "poisson") #' plot(fit) #' pfit = predict(fit, x, s = 0.001, type = "response") #' plot(pfit, y) #' #' # Cox #' set.seed(10101) #' N = 1000 #' p = 30 #' nzc = p/3 #' x = matrix(rnorm(N * p), N, p) #' beta = rnorm(nzc) #' fx = x[, seq(nzc)] %*% beta/3 #' hx = exp(fx) #' ty = rexp(N, hx) #' tcens = rbinom(n = N, prob = 0.3, size = 1) # censoring indicator #' y = cbind(time = ty, status = 1 - tcens) # y=Surv(ty,1-tcens) with library(survival) #' fit = glmnet(x, y, family = "cox") #' plot(fit) #' #' # Cox example with (start, stop] data #' set.seed(2) #' nobs <- 100; nvars <- 15 #' xvec <- rnorm(nobs * nvars) #' xvec[sample.int(nobs * nvars, size = 0.4 * nobs * nvars)] <- 0 #' x <- matrix(xvec, nrow = nobs) #' start_time <- runif(100, min = 0, max = 5) #' stop_time <- start_time + runif(100, min = 0.1, max = 3) #' status <- rbinom(n = nobs, prob = 0.3, size = 1) #' jsurv_ss <- survival::Surv(start_time, stop_time, status) #' fit <- glmnet(x, jsurv_ss, family = "cox") #' #' # Cox example with strata #' jsurv_ss2 <- stratifySurv(jsurv_ss, rep(1:2, each = 50)) #' fit <- glmnet(x, jsurv_ss2, family = "cox") #' #' # Sparse #' n = 10000 #' p = 200 #' nzc = trunc(p/10) #' x = matrix(rnorm(n * p), n, p) #' iz = sample(1:(n * p), size = n * p * 0.85, replace = FALSE) #' x[iz] = 0 #' sx = Matrix(x, sparse = TRUE) #' inherits(sx, "sparseMatrix") #confirm that it is sparse #' beta = rnorm(nzc) #' fx = x[, seq(nzc)] %*% beta #' eps = rnorm(n) #' y = fx + eps #' px = exp(fx) #' px = px/(1 + px) #' ly = rbinom(n = length(px), prob = px, size = 1) #' system.time(fit1 <- glmnet(sx, y)) #' system.time(fit2n <- glmnet(x, y)) #' #' @export glmnet glmnet=function(x,y,family=c("gaussian","binomial","poisson","multinomial","cox","mgaussian"),weights=NULL,offset=NULL,alpha=1.0,nlambda=100,lambda.min.ratio=ifelse(nobs1){ warning("alpha >1; set to 1") alpha=1 } if(alpha<0){ warning("alpha<0; set to 0") alpha=0 } alpha=as.double(alpha) nlam=as.integer(nlambda) y=drop(y) # we dont like matrix responses unless we need them dimy=dim(y) nrowy=ifelse(is.null(dimy),length(y),dimy[1]) if(nrowy!=nobs)stop(paste("number of observations in y (",nrowy,") not equal to the number of rows of x (",nobs,")",sep="")) vnames=colnames(x) if(is.null(vnames))vnames=paste("V",seq(nvars),sep="") ne=as.integer(dfmax) nx=as.integer(pmax) if(is.null(exclude))exclude=integer(0) if(any(penalty.factor==Inf)){ exclude=c(exclude,seq(nvars)[penalty.factor==Inf]) exclude=sort(unique(exclude)) } if(length(exclude)>0){ jd=match(exclude,seq(nvars),0) if(!all(jd>0))stop("Some excluded variables out of range") penalty.factor[jd]=1 #ow can change lambda sequence jd=as.integer(c(length(jd),jd)) }else jd=as.integer(0) vp=as.double(penalty.factor) internal.parms=glmnet.control() if(internal.parms$itrace)trace.it=1 else{ if(trace.it){ glmnet.control(itrace=1) on.exit(glmnet.control(itrace=0)) } } ###check on limits if(any(lower.limits>0)){stop("Lower limits should be non-positive")} if(any(upper.limits<0)){stop("Upper limits should be non-negative")} lower.limits[lower.limits==-Inf]=-internal.parms$big upper.limits[upper.limits==Inf]=internal.parms$big if(length(lower.limits)=1)stop("lambda.min.ratio should be less than 1") flmin=as.double(lambda.min.ratio) ulam=double(1) } else{ flmin=as.double(1) if(any(lambda<0))stop("lambdas should be non-negative") ulam=as.double(rev(sort(lambda))) nlam=as.integer(length(lambda)) } is.sparse=FALSE ix=jx=NULL if(inherits(x,"sparseMatrix")){##Sparse case is.sparse=TRUE x=as(x,"CsparseMatrix") x=as(x,"dgCMatrix") ix=as.integer(x@p+1) jx=as.integer(x@i+1) # TODO: currently only changed gaussian family to C++ implementation. # We need gaussian to take xd as the dgCMatrix itself. # Other methods still require xd to be the compressed data vector. if (family == "gaussian") { xd <- x } else { xd <- x@x } } else if (!inherits(x, "matrix")) { xd <- data.matrix(x) } else { xd <- x } # TODO: only coerce to vector of double if family is not supported by C++. if (family != "gaussian") { storage.mode(xd) <- "double" } if (trace.it) { if (relax) cat("Training Fit\n") pb <- createPB(min = 0, max = nlam, initial = 0, style = 3) } else { pb <- NULL # dummy initialize (won't be used, but still need to pass) } kopt=switch(match.arg(type.logistic), "Newton"=0,#This means to use the exact Hessian "modified.Newton"=1 # Use the upper bound ) if(family=="multinomial"){ type.multinomial=match.arg(type.multinomial) if(type.multinomial=="grouped")kopt=2 #overrules previous kopt } kopt=as.integer(kopt) fit=switch(family, "gaussian"=elnet(xd,is.sparse,y,weights,offset,type.gaussian,alpha,nobs,nvars,jd,vp,cl,ne,nx,nlam,flmin,ulam,thresh,isd,intr,vnames,maxit,pb), "poisson"=fishnet(xd,is.sparse,ix,jx,y,weights,offset,alpha,nobs,nvars,jd,vp,cl,ne,nx,nlam,flmin,ulam,thresh,isd,intr,vnames,maxit), "binomial"=lognet(xd,is.sparse,ix,jx,y,weights,offset,alpha,nobs,nvars,jd,vp,cl,ne,nx,nlam,flmin,ulam,thresh,isd,intr,vnames,maxit,kopt,family), "multinomial"=lognet(xd,is.sparse,ix,jx,y,weights,offset,alpha,nobs,nvars,jd,vp,cl,ne,nx,nlam,flmin,ulam,thresh,isd,intr,vnames,maxit,kopt,family), "cox"=coxnet(xd,is.sparse,ix,jx,y,weights,offset,alpha,nobs,nvars,jd,vp,cl,ne,nx,nlam,flmin,ulam,thresh,isd,vnames,maxit), "mgaussian"=mrelnet(xd,is.sparse,ix,jx,y,weights,offset,alpha,nobs,nvars,jd,vp,cl,ne,nx,nlam,flmin,ulam,thresh,isd,jsd,intr,vnames,maxit) ) if (trace.it) { utils::setTxtProgressBar(pb, nlam) close(pb) } if(is.null(lambda))fit$lambda=fix.lam(fit$lambda)##first lambda is infinity; changed to entry point fit$call=this.call fit$nobs=nobs class(fit)=c(class(fit),"glmnet") } } if(relax) relax.glmnet(fit, x=x,y=y,weights=weights,offset=offset, lower.limits=lower.limits,upper.limits=upper.limits,penalty.factor=penalty.factor, check.args=FALSE,...) else fit }