Logistic Regression, Average Marginal Effects, and the Linear Probability Model - Part IV: How AMEs are affected by the distribution of omitted variables

In the previous post, we saw that an average marginal effect (AME) of an independent variable in a logistic regression model reflects not only the influence of the variable in focus (i.e., the variable for which the AME is computed), but also the impact of ommitted variables in a model. The perhaps desirable consequence of this is that AMEs change less strongly if an ommitted variable is added to the model (if it is uncorrelated to the variables to the variables already present in the model.)

fun2 <- function(a=0,b1=1,b2=1,mu.x1=0,mu.x2=0,n=5000) {
    x1 <- rnorm(n=n,mean=mu.x1)
    x2 <- rnorm(n=n,mean=mu.x2)
    p <- logistic(a+b1*x1+b2*x2)
    y <- rbinom(n=n,size=1,prob=p)
    glm1 <- glm(y~x1, family = binomial,maxit=6)
    lm1 <- lm(y~x1)
    glm2 <- glm(y~x1+x2, family = binomial,maxit=6)
    lm2 <- lm(y~x1+x2)
    
    c(
        b_glm1=coef(glm1)[-1],
        b_glm2=coef(glm2)[-1],
        AME_glm1=AME(glm1),
        AME_glm2=AME(glm2),
        b_lm1=coef(lm1)[-1],
        b_lm2=coef(lm2)[-1]
    )

}
Last executed at 1 February 2026 at 23:13:32 GMT+1 in 73ms
+ 
simres2 <- simsim(fun2,
                 conditions=list(
                     b2=c(0,0.1,.3,0.5,1,1.5,2,2.5,3),
                     mu.x2=c(0,0.1,.3,0.5,1,1.5,2,2.5,3)
                 ),
                 nsim=100)
Last executed at 1 February 2026 at 23:15:36 GMT+1 in 123617ms
There were 50 or more warnings (use warnings() to see the first 50)
fun2()
Last executed at 1 February 2026 at 23:17:20 GMT+1 in 38ms
  b_glm1.x1   b_glm2.x1   b_glm2.x2 AME_glm1.x1 AME_glm2.x1 AME_glm2.x2 
  0.8509133   0.9951201   0.9879956   0.1829449   0.1812240   0.1799266 
   b_lm1.x1    b_lm2.x1    b_lm2.x2 
  0.1832448   0.1818026   0.1786455 
simres2.df <- as.data.frame(simres2)
Last executed at 1 February 2026 at 23:17:20 GMT+1 in 25ms
ggplot(simres2.df) + 
  geom_boxplot(aes(mu.x2,b_glm1.x1,group=mu.x2)) +
  facet_wrap(~b2, labeller = label_both)
Last executed at 1 February 2026 at 23:17:22 GMT+1 in 891ms
ggplot(simres2.df) + 
  geom_boxplot(aes(mu.x2,AME_glm1.x1,group=mu.x2)) +
  facet_wrap(~b2, labeller = label_both,scales="free_y")
Last executed at 1 February 2026 at 23:17:23 GMT+1 in 887ms
ggplot(simres2.df) + 
  geom_boxplot(aes(mu.x2,b_glm2.x1,group=mu.x2)) +
  facet_wrap(~b2, labeller = label_both,scales="free_y")
Last executed at 1 February 2026 at 23:17:25 GMT+1 in 913ms
ggplot(simres2.df) + 
  geom_boxplot(aes(mu.x2,AME_glm2.x1,group=mu.x2)) +
  facet_wrap(~b2, labeller = label_both,scales="free_y")
Last executed at 1 February 2026 at 23:17:27 GMT+1 in 915ms

Discussion and conclusion