Skip to contents

logistic_regression() performs binary logistic regression with SPSS-compatible output. Wraps stats::glm(family = binomial) and adds odds ratios, pseudo R-squared measures, classification table, and model tests matching SPSS LOGISTIC REGRESSION output.

Supports two interface styles:

  • Formula interface: logistic_regression(data, high_satisfaction ~ age + income)

  • SPSS-style: logistic_regression(data, dependent = high_satisfaction, predictors = c(age, income))

Usage

logistic_regression(
  data,
  formula = NULL,
  dependent = NULL,
  predictors = NULL,
  weights = NULL,
  conf.level = 0.95,
  factors = c("dummy", "numeric")
)

Arguments

data

Your survey data (a data frame or tibble). If grouped (via dplyr::group_by()), separate regressions are run for each group.

formula

A formula specifying the model (e.g., y ~ x1 + x2). If provided, dependent and predictors are ignored.

dependent

The dependent variable (unquoted). Used with predictors when no formula is given. Must have exactly two distinct values (e.g. 0/1, 1/2, a two-level factor); see Technical Details.

predictors

Predictor variable(s) (unquoted, supports tidyselect). Used with dependent when no formula is given. The dependent, weights and grouping variables are never used as predictors (a selection such as where(is.numeric) drops them with a message). Character predictors are entered as factors.

weights

Optional survey weights. When specified, weighted maximum likelihood estimation is used, matching SPSS WEIGHT BY behavior. Give a column name (unquoted or as a string), an expression such as sampling_weight * 2, or a numeric vector with one weight per row.

conf.level

Confidence level for odds ratio intervals (default 0.95).

factors

How factor predictors are entered into the model: "dummy" (default, matches base R glm()) expands a factor with L levels into L - 1 contrasts; "numeric" silently coerces factor levels to their integer codes, matching SPSS LOGISTIC REGRESSION default behavior when no /CATEGORICAL subcommand is given. The "numeric" mode emits a one-line cli::cli_inform() listing the coerced variables. Note that for ordered factors, "dummy" applies R's default polynomial contrasts (terms suffixed .L, .Q, .C), not treatment dummies; convert with factor(x, ordered = FALSE) first if you want dummy coding. factors applies to factors only: labelled predictors from SPSS files (haven_labelled) are numeric and enter with their numeric codes, as in SPSS LOGISTIC REGRESSION without /CATEGORICAL; summary() notes them. Convert them with to_label first to get dummy coding.

Value

For ungrouped data, an object of class c("logistic_regression", "glm", "lm") — the fitted glm itself, with mariposa-specific slots attached:

coef_table

Tibble with B, S.E., Wald, df, Sig., Exp(B), CI_lower, CI_upper

model_summary

List with minus2LL, cox_snell_r2, nagelkerke_r2, mcfadden_r2

omnibus_test

List with chi_sq, df, p for overall model test

classification

List with table, overall_pct, pct_correct_0, pct_correct_1

hosmer_lemeshow

List with chi_sq, df, p (goodness-of-fit test)

dv_encoding

Tibble Original -> Internal (0/1) of the outcome categories (SPSS "Dependent Variable Encoding")

n

Sample size (listwise complete cases; weighted N when weighted)

formula, dependent, predictor_names, weighted, weight_name, is_grouped, conf.level

Call metadata.

Because the object inherits from "glm", all standard generics (predict(), anova(), vcov(), confint(), residuals(), fitted(), coef(), broom::tidy(), broom::glance(), broom::augment()) dispatch natively without unwrapping. summary() returns the SPSS-style mariposa summary; for the raw glm summary use stats::summary.glm() on the same object. confint() returns Wald intervals on the log-odds scale (the SPSS method; exp(confint(model)) gives the "C.I. for EXP(B)" of the summary), profile-likelihood intervals via confint(model, method = "profile"); see confint.logistic_regression.

For grouped data, returns a list of class "logistic_regression" with $groups holding one fitted glm-inheriting result per group.

Details

Understanding the Results

The output includes five sections matching SPSS LOGISTIC REGRESSION output:

  • Omnibus Test: Tests whether the model as a whole is significant. A significant chi-square means the model predicts better than chance.

  • Model Summary: -2 Log Likelihood and pseudo R-squared values. Lower -2LL = better fit. Higher R-squared = more variance explained.

  • Hosmer-Lemeshow Test: Goodness-of-fit test. A non-significant result (p > 0.05) means the model fits the data well.

  • Classification Table: How well the model classifies cases. Shows percentage correctly predicted for each group and overall.

  • Coefficients: B, Wald test, odds ratios (Exp(B)), and CIs.

Interpreting odds ratios (Exp(B)):

  • Exp(B) > 1: Predictor increases the odds of the outcome

  • Exp(B) < 1: Predictor decreases the odds of the outcome

  • Exp(B) = 1: Predictor has no effect on the odds

When to Use This

Use logistic_regression() when:

  • Your dependent variable is binary (yes/no, 0/1, pass/fail)

  • You want to predict group membership from one or more predictors

  • You need odds ratios to interpret predictor effects

For continuous outcomes, use linear_regression instead.

Technical Details

Dependent Variable: Any variable with exactly two distinct observed values, coded internally as 0/1 like SPSS LOGISTIC REGRESSION does: for numeric and labelled variables the lower value becomes 0 and the higher 1 (so 1/2 and 0/1 codings give the same model); for factors unused levels are dropped and the first remaining level becomes 0; character values are ordered alphabetically; logicals code FALSE = 0, TRUE = 1. The model predicts the probability of the category coded 1 - the compact print names it ([P(y = category)]), and summary() shows the SPSS "Dependent Variable Encoding" table (also stored as $dv_encoding). A grouped analysis uses one encoding for all groups.

Missing Data: Listwise deletion is used (matching SPSS LOGISTIC REGRESSION default behavior).

Weights: When weights are specified, they are treated as frequency weights (matching SPSS WEIGHT BY behavior).

Pseudo R-squared: Three measures are reported:

  • Cox & Snell R-squared (bounded below 1)

  • Nagelkerke R-squared (adjusted to reach 1)

  • McFadden R-squared (1 - LL_model/LL_null)

Factor Predictors: By default (factors = "dummy"), factor predictors are expanded into L - 1 contrasts via R's stats::model.matrix(), matching base R glm(): unordered factors get treatment (dummy) contrasts against the first level, while ordered factors get R's default polynomial contrasts (.L/.Q/.C terms). Pass factors = "numeric" to silently coerce factor levels to their integer codes (SPSS LOGISTIC REGRESSION default without an explicit /CATEGORICAL subcommand).

Grouped Analysis: When data is grouped via dplyr::group_by(), a separate regression is run for each group (matching SPSS SPLIT FILE BY).

See also

linear_regression for continuous outcome variables.

chi_square for testing associations between categorical variables.

summary.logistic_regression for detailed output with toggleable sections.

Other regression: linear_regression(), marginal_effects()

Examples

library(dplyr)
data(survey_data)

# Create binary DV
survey_data$high_satisfaction <- ifelse(survey_data$life_satisfaction >= 4, 1, 0)

# Bivariate logistic regression
logistic_regression(survey_data, high_satisfaction ~ age)
#> Logistic Regression: high_satisfaction ~ age [P(high_satisfaction = 1)]
#>   Nagelkerke R2 = 0.000, chi2(1) = 0.28, p = 0.595, Accuracy = 57.7%, N = 2421
#> Use summary() for detailed output.

# Multiple logistic regression
logistic_regression(survey_data, high_satisfaction ~ age + income + education)
#> Logistic Regression: high_satisfaction ~ age + income + education [P(high_satisfaction = 1)]
#>   Nagelkerke R2 = 0.213, chi2(5) = 364.62, p < 0.001 ***, Accuracy = 68.3%, N = 2115
#> Use summary() for detailed output.

# SPSS-style interface
logistic_regression(survey_data,
                    dependent = high_satisfaction,
                    predictors = c(age, income))
#> Logistic Regression: high_satisfaction ~ age + income [P(high_satisfaction = 1)]
#>   Nagelkerke R2 = 0.209, chi2(2) = 357.43, p < 0.001 ***, Accuracy = 68.4%, N = 2115
#> Use summary() for detailed output.

# Weighted logistic regression
logistic_regression(survey_data, high_satisfaction ~ age,
                    weights = sampling_weight)
#> Logistic Regression: high_satisfaction ~ age [P(high_satisfaction = 1)] [Weighted]
#>   Nagelkerke R2 = 0.000, chi2(1) = 0.30, p = 0.586, Accuracy = 57.6%, N = 2437
#> Use summary() for detailed output.

# Grouped by region
survey_data |>
  dplyr::group_by(region) |>
  logistic_regression(high_satisfaction ~ age)
#> Logistic Regression: high_satisfaction ~ age [P(high_satisfaction = 1)] [Grouped: region]
#> [region = East]
#>   Nagelkerke R2 = 0.002, chi2(1) = 0.74, p = 0.390, Accuracy = 58.3%, N = 465
#> [region = West]
#>   Nagelkerke R2 = 0.000, chi2(1) = 0.03, p = 0.860, Accuracy = 57.6%, N = 1956
#> Use summary() for detailed output.

# Factor predictors: dummy-coding (default, matches base R glm())
logistic_regression(survey_data, high_satisfaction ~ age + education)
#> Logistic Regression: high_satisfaction ~ age + education [P(high_satisfaction = 1)]
#>   Nagelkerke R2 = 0.084, chi2(4) = 156.25, p < 0.001 ***, Accuracy = 63.4%, N = 2421
#> Use summary() for detailed output.

# Factor predictors: SPSS-style ordinal-as-scale
logistic_regression(survey_data, high_satisfaction ~ age + education,
                    factors = "numeric")
#> ℹ Factor predictor(s) coerced to numeric (SPSS-style ordinal scaling):
#> • `education`
#> Logistic Regression: high_satisfaction ~ age + education [P(high_satisfaction = 1)]
#>   Nagelkerke R2 = 0.078, chi2(2) = 144.84, p < 0.001 ***, Accuracy = 63.4%, N = 2421
#> Use summary() for detailed output.

# --- Three-layer output ---
result <- logistic_regression(survey_data, high_satisfaction ~ age + income)
result                                    # compact one-line overview
#> Logistic Regression: high_satisfaction ~ age + income [P(high_satisfaction = 1)]
#>   Nagelkerke R2 = 0.209, chi2(2) = 357.43, p < 0.001 ***, Accuracy = 68.4%, N = 2115
#> Use summary() for detailed output.
summary(result)                           # full detailed SPSS-style output
#> 
#> Logistic Regression Results
#> ---------------------------
#> - Formula: high_satisfaction ~ age + income
#> - Method: ENTER
#> - N: 2115
#> 
#>   Dependent Variable Encoding
#>   ------------------------------
#>   Original Value  Internal Value
#>   ------------------------------
#>   0                            0
#>   1                            1
#>   ------------------------------
#> 
#>   Omnibus Tests of Model Coefficients
#>   ---------------------------------
#>          Chi-square  df   Sig.     
#>   ---------------------------------
#>   Model     357.432   2  <.001  ***
#>   ---------------------------------
#> 
#>   Model Summary
#>   -------------------------------
#>   -2 Log Likelihood      2520.010
#>   Cox & Snell R Square      0.155
#>   Nagelkerke R Square       0.209
#>   McFadden R Square         0.124
#>   -------------------------------
#> 
#>   Hosmer and Lemeshow Test
#>   ------------------------
#>      Chi-square  df   Sig.
#>   ------------------------
#>         150.764   8  <.001
#>   ------------------------
#> 
#>   Classification Table (cutoff = 0.50; rows: observed, columns: predicted)
#>   ---------------------------------------
#>   Observed              0    1  % Correct
#>   ---------------------------------------
#>   0                   508  380       57.2
#>   1                   289  938       76.4
#>   Overall Percentage                 68.4
#>   ---------------------------------------
#> 
#>   Variables in the Equation
#>   ------------------------------------------------------------------------------------------
#>   Term              B      S.E.     Wald  df   Sig.  Exp(B)  95% CI Lower  95% CI Upper     
#>   ------------------------------------------------------------------------------------------
#>   (Intercept)  -2.252     0.212  112.868   1  <.001   0.105                              ***
#>   age           0.001     0.003    0.174   1   .677   1.001         0.996         1.007     
#>   income        0.001  4.26e-05  268.118   1  <.001  1.0007        1.0006        1.0008  ***
#>   ------------------------------------------------------------------------------------------
#> 
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05
summary(result, classification = FALSE)   # hide classification table
#> 
#> Logistic Regression Results
#> ---------------------------
#> - Formula: high_satisfaction ~ age + income
#> - Method: ENTER
#> - N: 2115
#> 
#>   Dependent Variable Encoding
#>   ------------------------------
#>   Original Value  Internal Value
#>   ------------------------------
#>   0                            0
#>   1                            1
#>   ------------------------------
#> 
#>   Omnibus Tests of Model Coefficients
#>   ---------------------------------
#>          Chi-square  df   Sig.     
#>   ---------------------------------
#>   Model     357.432   2  <.001  ***
#>   ---------------------------------
#> 
#>   Model Summary
#>   -------------------------------
#>   -2 Log Likelihood      2520.010
#>   Cox & Snell R Square      0.155
#>   Nagelkerke R Square       0.209
#>   McFadden R Square         0.124
#>   -------------------------------
#> 
#>   Hosmer and Lemeshow Test
#>   ------------------------
#>      Chi-square  df   Sig.
#>   ------------------------
#>         150.764   8  <.001
#>   ------------------------
#> 
#>   Variables in the Equation
#>   ------------------------------------------------------------------------------------------
#>   Term              B      S.E.     Wald  df   Sig.  Exp(B)  95% CI Lower  95% CI Upper     
#>   ------------------------------------------------------------------------------------------
#>   (Intercept)  -2.252     0.212  112.868   1  <.001   0.105                              ***
#>   age           0.001     0.003    0.174   1   .677   1.001         0.996         1.007     
#>   income        0.001  4.26e-05  268.118   1  <.001  1.0007        1.0006        1.0008  ***
#>   ------------------------------------------------------------------------------------------
#> 
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05