--- title: "Regression Models" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Regression Models} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r knitr-opts, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(deli) ``` ## Overview deli provides estimating equations for a wide range of regression models. Every model in this vignette is fitted the same way: pass a formula, a data frame, and the estimating equation to `m_estimate()`, which builds the design matrix, constructs the estimator, and solves it in one call. Arguments belonging to the estimating equation, such as `model` or `penalty`, go in the same call and are forwarded to it, while `init`, `subset`, `solver`, and the other solver controls are arguments of `m_estimate()` itself. The sandwich variance estimator automatically provides robust standard errors. The parameters are labeled from the first of three sources that names every one of them: the names on `init`, the columns of the design matrix, and the row names the estimating equation writes on its own return. A default `init` carries no names, so the design columns label the fit, together with any parameter the equation estimates on top of the coefficients; an explicit `init` is labeled the same way when its length accounts for one of those two shapes. Where it accounts for neither, the equation's row names label the fit instead, and where nothing labels every parameter they are numbered `theta_1` through `theta_p`. Name the elements of `init` yourself to label the parameters any other way. `init` defaults to a zero vector with one element per design matrix column. That is the right length for most estimating equations, but not for the few that estimate a parameter of their own on top of the coefficients; the gamma and negative binomial GLMs below are the cases you are likely to meet. Every model shown here can also be fitted through the function interface, where you write a `psi` function that supplies the design matrix and response yourself. That form is what you need for a design the formula notation cannot express, for a response that is not a vector (`ee_mlogit()`), and for custom or stacked equations; see `vignette("custom-estimating-equations")`. ## Linear regression The most basic regression model uses `ee_regression()` with `model = "linear"`: ```{r linear} set.seed(42) n <- 300 x1 <- rnorm(n) x2 <- rbinom(n, 1, 0.5) y <- 1 + 2 * x1 - 0.5 * x2 + rnorm(n) d <- data.frame(x1, x2, y) m <- m_estimate(y ~ x1 + x2, data = d, .ee = ee_regression, model = "linear") summary(m) ``` ## Logistic regression For binary outcomes, use `model = "logistic"`: ```{r logistic} set.seed(42) n <- 500 x <- rnorm(n) y <- rbinom(n, 1, plogis(0.5 + x)) d <- data.frame(x, y) m <- m_estimate(y ~ x, data = d, .ee = ee_regression, model = "logistic") summary(m) ``` ## Poisson regression For count data, use `model = "poisson"`: ```{r poisson} set.seed(42) n <- 500 x <- rnorm(n) y <- rpois(n, lambda = exp(0.5 + 0.3 * x)) d <- data.frame(x, y) m <- m_estimate(y ~ x, data = d, .ee = ee_regression, model = "poisson") summary(m) ``` ## GLM: generalized linear models `ee_glm()` provides a more flexible interface where you specify the distribution and link function separately: ```{r glm-poisson} set.seed(42) n <- 500 x <- rnorm(n) y <- rpois(n, lambda = exp(0.5 + 0.3 * x)) d <- data.frame(x, y) m <- m_estimate( y ~ x, data = d, .ee = ee_glm, distribution = "poisson", link = "log" ) m@theta ``` Available distributions: `"normal"`, `"binomial"`, `"poisson"`, `"gamma"`, `"negative_binomial"`, `"inverse_gaussian"`, and `"tweedie"`. `"tweedie"` takes a variance-power `hyperparameter`; see `?ee_glm` for the details. Available links: `"identity"`, `"log"`, `"logit"`, `"probit"`, `"cauchy"` (alias `"cauchit"`), `"loglog"`, `"cloglog"`, `"inverse"`, and `"sqrt"`. `"gamma"` and `"negative_binomial"` estimate one parameter beyond the regression coefficients: the log of the gamma shape, or the log of the negative binomial dispersion. The automatic `init` has one element per design matrix column and so is one element short for these two, which makes an explicit `init` necessary. It needs no names of its own: the formula interface labels an unnamed `init` of that length from the model matrix columns and the extra parameter. ```{r glm-gamma} set.seed(42) n <- 500 x <- rnorm(n) mu <- exp(0.5 + 0.3 * x) y <- rgamma(n, shape = 2, scale = mu / 2) d <- data.frame(x, y) m <- m_estimate( y ~ x, data = d, .ee = ee_glm, distribution = "gamma", link = "log", init = c(0, 0, 0) ) m@theta ``` The extra parameter is on the log scale, so `exp(m@theta[["log_shape"]])` recovers the shape, here close to the value of 2 used in the simulation. ## Penalized regression deli supports several penalized regression methods. These add a penalty term to the estimating equations. ### Ridge regression L2 penalty shrinks coefficients toward zero: ```{r ridge} set.seed(42) n <- 200 x1 <- rnorm(n) x2 <- rnorm(n) y <- 1 + 0.5 * x1 + 0.3 * x2 + rnorm(n) d <- data.frame(x1, x2, y) m <- m_estimate( y ~ x1 + x2, data = d, .ee = ee_ridge_regression, model = "linear", penalty = 0.5 ) summary(m) ``` ### LASSO regression L1 penalty produces sparse solutions: ```{r lasso} # Not differentiable, so the sandwich variance should not be trusted here m <- m_estimate( y ~ x1 + x2, data = d, .ee = ee_lasso_regression, model = "linear", penalty = 0.1 ) m@theta ``` ### Elastic net Combines L1 and L2 penalties: ```{r elasticnet} # The L1 half is not differentiable, so again distrust the sandwich variance m <- m_estimate( y ~ x1 + x2, data = d, .ee = ee_elasticnet_regression, model = "linear", penalty = 0.1, ratio = 0.5 ) m@theta ``` ## Robust regression `ee_robust_regression()` replaces the squared loss with a robust loss function, providing resistance to outliers: ```{r robust} set.seed(42) n <- 200 x <- rnorm(n) y <- 1 + 2 * x + rnorm(n) # Add some outliers y[1:5] <- y[1:5] + 20 d <- data.frame(x, y) # The Huber loss is convex, so its estimating function has a single root. What # makes the seed necessary is that the Huber psi is bounded: far from the # solution every residual is past the tuning constant k, every contribution # saturates at k, and the estimating function is constant with a Jacobian of # exactly zero. Starting from zero lands in that flat region, where the solver # has no slope to follow, so start from a least-squares fit. start <- coef(lm(y ~ x, data = d)) # Huber loss with k = 1.345 m <- m_estimate( y ~ x, data = d, .ee = ee_robust_regression, model = "linear", loss = "huber", k = 1.345, init = start ) # Compare with OLS (affected by outliers) m_ols <- m_estimate(y ~ x, data = d, .ee = ee_regression, model = "linear") rbind(robust = m@theta, ols = m_ols@theta) ``` Available loss functions: `"huber"`, `"tukey"`, `"andrew"`, `"hampel"`. ## Weighted regression All regression EEs support observation weights via the `weights` argument. Arguments passed through `m_estimate()` are evaluated in the data frame, so the column name is enough: ```{r weighted} set.seed(42) n <- 200 x <- rnorm(n) y <- 1 + 2 * x + rnorm(n) w <- runif(n, 0.5, 1.5) d <- data.frame(x, y, w) m <- m_estimate( y ~ x, data = d, .ee = ee_regression, model = "linear", weights = w ) m@theta ``` ## Predictions after regression After fitting any regression model, use `augment()` for predicted values with confidence intervals. Give it a data frame of new covariate values as `newdata`, with one column for each covariate the formula names, and it returns that frame with `.fitted`, `.se.fit`, `.lower`, and `.upper` beside it: ```{r predictions} set.seed(42) n <- 300 x <- rnorm(n) y <- 1 + 2 * x + rnorm(n) d <- data.frame(x, y) m <- m_estimate(y ~ x, data = d, .ee = ee_regression, model = "linear") # Predict at new covariate values augment(m, newdata = data.frame(x = seq(-2, 2, length.out = 5))) ``` Called without `newdata`, `augment()` reports the rows the model was fitted to and adds a `.resid` column as well. For a model with a non-identity link, `type.predict = "response"` moves `.fitted` and its interval from the linear predictor to the scale of the response.