Why Explicit GLM Specifications Matter
A GLM call can run successfully and still represent the wrong model. The response distribution and the link function are separate choices: the distribution describes the response’s stochastic behaviour, while the link connects its mean to the linear predictor. In R, a default link may be used if one is not stated. That convenience is a risk when the intended model requires a particular link, or when code is reviewed later by someone who must establish what was fitted.
This tutorial focuses on writing those choices explicitly and checking the fitted object before using its predictions. It assumes the response and predictors have already been prepared appropriately. The aim is not to compare candidate models, but to confirm that the model R fitted is the model the analyst intended. The practices here are aligned with the SOA Exam PA (Predictive Analytics) syllabus.
binomial() or Gamma() returns an object that specifies both the family and a link.
Separating the Family From the Link
The family and link answer different questions. For example, a Poisson family describes a count response with conditional mean \(\mu_i\) and conditional variance \(\mu_i\). A log link specifies how that mean relates to predictors: \( \log(\mu_i)=\eta_i\). Choosing a Poisson family does not, by itself, mean that every possible link choice is appropriate for a particular application.
The link also determines how the linear predictor maps back to the mean. If \(g\) is invertible over the relevant range, then \(\mu_i=g^{-1}(\eta_i)\). For a log link, the inverse is the exponential function, so \(\mu_i=\exp(\eta_i)\), which is positive. For a logit link, the inverse is \(1/(1+\exp(-\eta_i))\), which lies between zero and one. This is why confirming only the family is not enough before interpreting a prediction.
In R, write the link inside the family constructor. Common specifications include the following. The quoted family and link names are the values ordinarily found in the fitted object’s family component.
| Target | Explicit R family specification | Stored family and link |
|---|---|---|
| Binary response with logit link | binomial(link = "logit") | "binomial", "logit" |
| Counts with log link | poisson(link = "log") | "poisson", "log" |
| Continuous response with identity link | gaussian(link = "identity") | "gaussian", "identity" |
| Positive response with log link | Gamma(link = "log") | "Gamma", "log" |
| Positive response with inverse-square link | inverse.gaussian(link = "1/mu^2") | "inverse.gaussian", "1/mu^2" |
These are examples, not rules that every application must follow. The earlier material on GLM families and links establishes how to match a distribution and link to a target. Here, the practical requirement is that the chosen pair be stated deliberately. Also note that the Tweedie family is not one of the standard base R family constructors. A Tweedie model generally requires an appropriate package and an explicitly constructed family object; it should not be assumed that tweedie() is available from base R.
Why the Inverse Link Governs the Mean
The prediction rule follows directly from the definition of a GLM. Let \(\boldsymbol{x}_i\) be the predictor vector, \(\boldsymbol{\beta}\) the coefficient vector, and \(\eta_i=\boldsymbol{x}_i^\mathsf{T}\boldsymbol{\beta}\). The link states that \(g(\mu_i)=\eta_i\). Applying the inverse function to both sides gives the mean on the response scale.
This justification depends on the link having an inverse over the relevant domain. If the link or family is mis-specified, the resulting response-scale interpretation can be wrong even if the fitting routine returns an object. For example, a logit-link prediction is a probability; a log-link prediction is a positive mean. They are not interchangeable.
Inspecting a Fitted GLM Object
A fitted object stores information about what was fitted. The key checks for this tutorial are the fitted family and link, the model formula, and the response used to fit the model. The expression fit$family$family returns the family name, and fit$family$link returns the link name. Use formula(fit) to inspect the fitted formula. To inspect the response as used in the model frame, use model.response(model.frame(fit)).
The model frame matters because it contains the observations used for fitting. If rows were excluded, for example because of missing values, the response in the model frame need not have the same length as the original response column. Check the retained observations and compare their responses with the intended data, rather than assuming the model used every original row. The examples below use complete toy data so the expected response can be checked directly.
Name the response, predictor formula, family, and link before writing the R call.
For example, use
poisson(link = "log"), rather than relying on an implicit default.Check
fit$family$family, fit$family$link, formula(fit), and the response in model.frame(fit).Choose the prediction scale with the model’s confirmed family and link in mind.
Worked Specifications
Worked Example: Binary Outcome With a Logit Link
A hypothetical insurer has one record for each of ten policyholders. The response event is already prepared as zero or one, and score is a numeric predictor. Specify a binomial GLM with a logit link, then verify the fitted object’s family, link, formula, and response. The intended response vector is c(0, 0, 1, 0, 1, 1, 0, 1, 1, 1).
Method. State the target first: a binary response calls for the binomial family, and this specification requires the logit link. The formula is event ~ score. Using a data frame named policy, fit the model with fit <- glm(event ~ score, data = policy, family = binomial(link = "logit")).
Check the family and link. Evaluate fit$family$family and fit$family$link. For this call, the expected values are "binomial" and "logit", respectively. A different value would mean the fitted specification does not match the target.
Check the formula. Inspect formula(fit). It should show event ~ score, so the response is event and the stated predictor is score.
Check the response. Extract it with model.response(model.frame(fit)). With all ten records present, the expected response has length 10 and values 0, 0, 1, 0, 1, 1, 0, 1, 1, 1. Their sum is 6, so the observed event proportion is \(6/10=0.6\). This is a useful basic consistency check; it does not replace checking each recorded response.
The result is a binomial GLM with a logit link and the intended response and formula. The common mistake avoided is assuming that a fitted object is correct merely because glm() returned it.
Worked Example: Count Response With a Log Link
A hypothetical service team records the number of repair requests received during each of eight equal-length observation periods. The response vector is c(0, 1, 2, 1, 3, 2, 4, 2). A predictor named temperature is available for each period. Specify and check a Poisson GLM with a log link.
Method. The target is a count response, so specify the Poisson family. The desired link is log, so write family = poisson(link = "log") explicitly. The complete call, using a data frame named service, is fit <- glm(requests ~ temperature, data = service, family = poisson(link = "log")).
Check the fitted family and link. The expected values of fit$family$family and fit$family$link are "poisson" and "log". The log link means that the model relates the log of the conditional mean request count to the linear predictor; it does not mean that the observed counts were logged before fitting.
Check the formula and response. formula(fit) should show requests ~ temperature. The response extracted by model.response(model.frame(fit)) should have eight values matching the stated vector. Their total is \(0+1+2+1+3+2+4+2=15\), and their mean is \(15/8=1.875\). These calculations provide a second check on the response that was intended, not a substitute for confirming its order and values.
The model specification is appropriate to the stated count target, subject to the assumptions of the Poisson model and the suitability of the predictors. The common mistake avoided is treating numeric values as sufficient reason to use a Gaussian family: the response’s meaning and distributional model, not its storage type alone, guide the family choice.
Worked Example: Positive Severity With a Log Link
For a hypothetical portfolio, eight positive claim amounts, in thousands of dollars, are stored as c(1.2, 1.5, 1.7, 2.0, 2.4, 2.8, 3.1, 3.6). The predictor age_band_score is numeric. Specify a Gamma GLM with a log link and check that the fitted response and formula match the intended analysis.
Method. Given a positive, right-skewed severity target, the stated model uses the Gamma family with the log link. With a data frame named claims, write fit <- glm(amount_thousands ~ age_band_score, data = claims, family = Gamma(link = "log")). The capitalization in Gamma is part of the R family constructor.
Check the family and link. The fitted object should report fit$family$family as "Gamma" and fit$family$link as "log". The Gamma family requires positive responses; the eight stated amounts are all positive. For a quick range check, the minimum is 1.2 and the maximum is 3.6, both in thousands of dollars.
Check the formula and response. Confirm that formula(fit) is amount_thousands ~ age_band_score. The model-frame response should have length eight, with values from 1.2 through 3.6 in the stated order. Their sum is \(1.2+1.5+1.7+2.0+2.4+2.8+3.1+3.6=18.3\), giving a mean of \(18.3/8=2.2875\) thousand dollars. These checks catch a wrong response column or an unintended change of scale.
The intended family, link, formula, and positive response have been checked before prediction. The common mistake avoided is checking only that the selected family is Gamma: a different link would change how the fitted mean is related to the linear predictor.
Common Specification Traps
A common trap is to specify a family but leave the link implicit. For example, family = binomial uses the family’s default link, which is logit. That is not a safe way to request a probit model. Likewise, placing link = "probit" as a separate argument to glm() does not specify the link in the family constructor and is not the proper way to write the model.
Wrong: glm(event ~ score, data = policy, family = binomial, link = "probit"). This does not put the probit link in the binomial family specification. Correction: glm(event ~ score, data = policy, family = binomial(link = "probit")). Then check that fit$family$link is "probit".
Other checks prevent related errors. Inspecting the formula can reveal that the wrong response or predictor was named. Inspecting the model-frame response can reveal that the model used an unexpected variable or fewer rows than expected. Inspecting the family and link together can reveal a valid but unintended default. These checks are especially valuable in scripts where the call is separated from the later prediction code.
glm() call. Before using predictions, verify the fitted family, fitted link, fitted formula, and response actually used. A successful fit is not, by itself, evidence that the intended model was fitted.
Check Your Understanding
For each problem, identify the specification or object checks needed. Answers are provided at the end of each question.
- A positive, right-skewed response named
costis modelled using predictordurationand a log link. Write the family argument and state the expected stored family and link names. (Answer:Gamma(link = "log"); stored family"Gamma", link"log".) - A model was intended to use a Poisson family with a log link and formula
calls ~ workload. Name the two fitted-object fields to check for family and link, and the function to inspect the formula. (Answer:fit$family$family,fit$family$link, andformula(fit); expected values are"poisson","log", andcalls ~ workload.) - A colleague fits a binary response with
family = binomialbut intended a probit link. Explain the error and write the correction. (Answer: the family default is logit, not the intended probit; usefamily = binomial(link = "probit")and verifyfit$family$linkis"probit".) - A fitted model reports the expected family and link, but its formula is
paid ~ tenurewhen the intended formula wasfrequency ~ tenure. Is the model ready for prediction of frequency? State the next check. (Answer: no; the response is wrong. Inspectformula(fit)andmodel.response(model.frame(fit)), then refit with the intended response.) - A Poisson model used the intended formula and reports family
"poisson"and link"log". The original data had 40 rows, but the model frame has 36. What should be checked before using predictions, and why? (Answer: inspect the model-frame response and retained rows to establish which observations were used; the fitted response may exclude four original records, so the fit may not reflect the intended analysis population.)