GLM.jl
repository·master·Indexed 20 days ago
https://github.com/juliastats/glm.jlA Julia package for fitting linear and generalized linear models (GLM). It provides tools for regression analysis, including the `lm` function for Ordinary Least Squares and the `glm` function for models with various distributions (e.g., Poisson, Binomial) and link functions (e.g., LogitLink, ProbitLink). The library supports formula and matrix interfaces, categorical variable dummy coding, weighted estimation via StatsBase.jl, and specialized functions like `negbin` for negative binomial regression.
What's inside GLM.jl
- GLM.jl provides implementations for linear and generalized linear models in Julia. It is a core part of the JuliaStats ecosystem used for statistical modeling.
Choose between Cholesky and QR methods in `lm`
masterThe
lmfunction uses Cholesky factorization by default, which is fast but can be numerically unstable for ill-conditioned design matrices or aggressive in detecting multicollinearity.To improve numerical stability or handle multicollinearity, use the
methodkeyword argument:method=:cholesky(Default): Fast, but sensitive to ill-conditioned matrices and multicollinearity.method=:qr: More stable for ill-conditioned design matrices and less aggressive in dropping collinear columns.
If you encounter models where coefficients appear as
NaNor parameters are not estimated due to multicollinearity detection, try switching tomethod=:qr.# Using QR decomposition for better stability ols = lm(@formula(Y ~ X), data; method=:qr) # Using Cholesky decomposition (default) ols = lm(@formula(Y ~ X), data; method=:cholesky)Handle Categorical Variables in GLM
masterGLM.jl automatically handles categorical variables via dummy coding. You can trigger this in two ways:
- Using
CategoricalVectors: If a column in your table is aCategoricalVector(created viacategorical()orcategorical!()), it will be dummy coded by default. - Using the
contrastsargument: You can pass an explicitcontrastsargument to theglm(orlm) function to specify a different coding system (e.g.,DummyCoding()).
Note: The response (dependent) variable must be numeric and cannot be categorical.
using CategoricalArrays, DataFrames, GLM, StableRNGs # Method 1: Using CategoricalVectors rng = StableRNG(1) data = DataFrame(y = rand(rng, 100), x = categorical(repeat([1, 2, 3, 4], 25))) model = lm(@formula(y ~ x), data) # Method 2: Using explicit contrasts data_numeric = DataFrame(y = rand(StableRNG(1), 100), x = repeat([1, 2, 3, 4], 25)) model = lm(@formula(y ~ x), data_numeric, contrasts = Dict(:x => DummyCoding()))- Using
How response and predictor objects are separated
masterGLM.jl uses a design pattern that separates functionality related to the response (
ModResp) from functionality related to the linear predictor (LinPred). This allows the package to mix and match different statistical distributions with different types of model matrices.LinPred (Linear Predictor)
- Incorporates the parameter vector and the model matrix.
- The parameter vector is a dense numeric vector; the model matrix can be dense or sparse.
- Must implement a decomposition of the weighted model matrix to solve the system
X'W * X * delta = X'wres. - Common dense types include
DensePredQR(more accurate) andDensePredChol(faster).
ModResp (Model Response)
- Provides methods for
wtresandsqrtxwtsgenerics. - These values are used by
LinPredtypes during the fitting process (viaupdatebeta). - The
updatedeltamethod returns the convergence criterion. - The
updatemumethod (which takes thelinpredresult) returns the updated deviance.
Apply weights to `lm` and `glm` models
masterBoth
lmandglmsupport weighted estimation. To use weights, you must wrap your weight vector in one of the specific weight types defined inStatsBase.jland pass it to theweightskeyword argument.Important: Passing a raw
AbstractVectoras weights is deprecated. It will be coerced toFrequencyWeightsand trigger a warning. Always use the explicit weight constructors.Weight Types:
AnalyticWeights(viaaweights): Used for non-random relative importance (e.g., reliability or precision weights). Often used for aggregate values with differing variances.FrequencyWeights(viafweights): Used when weights represent the number of times an observation was seen (case weights).ProbabilityWeights(viapweights): Used to correct for sampling probabilities (sampling weights).UnitWeights: The default (unweighted) behavior.
Note that the weight type affects the variance of estimated coefficients and related quantities (like standard errors and log-likelihood), but the coefficient point estimates themselves remain the same regardless of the weight type used.
using StableRNGs, DataFrames, StatsBase, GLM data = DataFrame(y = rand(StableRNG(1), 100), x = randn(StableRNG(2), 100), weights = repeat([1, 2, 3, 4], 25)); # Using Analytic Weights m_aweights = lm(@formula(y ~ x), data, weights=aweights(data.weights)) # Using Frequency Weights m_fweights = lm(@formula(y ~ x), data, weights=fweights(data.weights)) # Using Probability Weights m_pweights = lm(@formula(y ~ x), data, weights=pweights(data.weights))Install GLM.jl
masterTo install GLM.jl and its dependencies (including the
Distributionspackage), use the Julia package manager:Pkg.add("GLM")Debug failed GLM fits
masterIf a generalized linear model fit fails, you can enable detailed iteration output by setting the
JULIA_DEBUGenvironment variable toGLM. This will output the deviance and the change in deviance for each iteration of the fitting process.# Run this in your terminal before starting Julia, or set it within your environment ENV["JULIA_DEBUG"] = "GLM"Perform Negative binomial regression
masterNegative binomial regression can be performed in two ways using the
GLM.jlpackage:- Using
glm: PassNegativeBinomial(theta)as the family argument toglm, wherethetais the dispersion parameter. - Using
negbin: A specialized convenience functionnegbinthat estimates the dispersion parameter automatically.
Both methods require a link function, such as
LogLink().using GLM, RDatasets quine = dataset("MASS", "quine") # Method 1: Using glm with a specified theta nbrmodel = glm(@formula(Days ~ Eth+Sex+Age+Lrn), quine, NegativeBinomial(2.0), LogLink()) # Method 2: Using the negbin convenience function (estimates theta) nbrmodel = negbin(@formula(Days ~ Eth+Sex+Age+Lrn), quine, LogLink()) # Accessing the estimated theta from the model println("Estimated theta = ", round(nbrmodel.rr.d.r, digits=5))- Using
Perform Probit regression
masterTo perform a Probit regression, use the
glmfunction with aBinomial()family and aProbitLink()link function. This is typically used when the response variable is binary (0 or 1).using GLM, DataFrames data = DataFrame(X=[1,2,2], Y=[1,0,1]) probit = glm(@formula(Y ~ X), data, Binomial(), ProbitLink())Use column names for weights in DataFrames
masterFor convenience, you can store pre-constructed weight objects directly in a
DataFramecolumn. You can then pass the column name as a symbol to theweightskeyword argument inlmorglm.# Pre-construct the weights in the DataFrame data.weights = aweights(data.weights); # Pass the column name as a symbol m_aweights = lm(@formula(y ~ x), data, weights=:weights)Perform linear regression with PowerLink
masterYou can use
PowerLink(λ)as a link function in aglmcall to model data where the relationship between the mean and the linear predictor follows a power law. To find the optimal power parameterλ, you can wrap thebic_glmcalculation (using thebicfunction) in an optimization routine likeOptim.optimizeto minimize the Bayesian Information Criterion (BIC).using GLM, RDatasets, StatsBase, DataFrames, Optim # Load dataset trees = DataFrame(dataset("datasets", "trees")); # Define a function to calculate BIC for a given λ bic_glm(λ) = bic(glm(@formula(Volume ~ Height + Girth), trees, Normal(), PowerLink(λ))); # Optimize λ to minimize BIC optimal_bic = optimize(bic_glm, -1.0, 1.0); # Use the optimal λ to fit the best model optimal_λ = round(optimal_bic.minimizer, digits = 5) model = glm(@formula(Volume ~ Height + Girth), trees, Normal(), PowerLink(optimal_λ))Extract statistics and predictions from a model
masterOnce a model is fitted, you can use several methods to inspect the results, perform predictions, or check model fit:
StatsBase.predict(model, X): Predict response values for new dataX.StatsBase.nobs(model): Returns the number of observations.StatsBase.deviance(model): Returns the deviance.StatsBase.nulldeviance(model): Returns the null deviance.GLM.ftest(model): Performs an F-test.GLM.dispersion(model): Returns the dispersion parameter.cooksdistance(model): Calculates Cook's distance for each observation.