Conditional Logit and Loglinear Models on Toy Matching Data
matching
loglinear models
conditional logit
A small worked example comparing conditional logit and loglinear formulations for the same toy contingency table.
Author
Benjamin F. Jarvis
Published
July 3, 2026
Question
How close are the conditional logit and loglinear views of a small matching table? This note starts from a toy table of pairings between three male categories and three female categories, then fits parallel models that describe the same pattern from two different directions.
The goal is not to make a substantive claim from the toy data. The goal is to make the bookkeeping visible: counts in a contingency table can be represented as matched choices, and the model formulas then become easier to compare.
Toy Data
library(survival)library(dplyr)
Attaching package: 'dplyr'
The following objects are masked from 'package:stats':
filter, lag
The following objects are masked from 'package:base':
intersect, setdiff, setequal, union
The loglinear models work directly with the cell counts. The conditional logit models need the same information represented as individual choices. The next steps expand the table into male and female records, then recover the observed pairings implied by the cell counts.
The expanded choice-set data have one row for every possible pairing. The observed unions are the rows where choice is TRUE.
cset |>count(choice)
# A tibble: 2 × 2
choice n
<lgl> <int>
1 FALSE 9900
2 TRUE 100
Model Fits
These four loglinear specifications and their conditional-logit counterparts are deliberately paired. The first loglinear model is saturated. There is no direct conditional-logit counterpart in this setup because conditioning on the male identifier absorbs the male-side total and leaves no comparable saturated choice model.
loglin_models <-list("1a"=glm(n ~ m * f, family = poisson, data = dt),"1b"=glm(n ~ m * f +offset(log(n_f)), family = poisson, data = dt),"1c"=glm(n ~ m + f + homogamy, family = poisson, data = dt),"2a"=glm(n ~ m +offset(log(n_f)) + homogamy, family = poisson, data = dt))clogit_models <-list("1a"=NULL,"1b"=clogit(choice ~ m * f +strata(m_id), data = cset),"1c"=clogit(choice ~ f + homogamy +strata(m_id), data = cset),"2a"=clogit(choice ~ homogamy +strata(m_id), data = cset))
Predicted Counts
For the loglinear models, predicted counts are obtained directly from the fitted Poisson mean. For the conditional logit models, the linear predictors are converted into probabilities within each male choice set and then summed back to the original table cells.
# A tibble: 9 × 5
m f loglinear conditional_logit difference
<chr> <chr> <dbl> <dbl> <dbl>
1 a a 40.0 40.0 7.36e-11
2 a b 8.00 8.00 3.29e-12
3 a c 2.00 2.00 -7.39e-11
4 b a 8.00 8.00 1.15e-11
5 b b 14.0 14.0 1.01e-12
6 b c 8.00 8.00 -1.26e-11
7 c a 2.00 2.00 -6.04e-11
8 c b 8.00 8.00 3.28e-11
9 c c 10.00 10.00 2.82e-11
Interpretation
The comparison is useful because the two model families emphasize different parts of the same setup. The loglinear model treats the table cells as the observations. The conditional logit model treats each observed male case as a choice among possible female cases. With the right conditioning and offsets, the fitted implications can line up closely, but the route to those fitted counts is different.
For this toy table, the most interesting comparisons are not the saturated model, but the reduced specifications that keep the broad marginal structure and then ask how much is added by category-specific homogamy terms.