Fit models for women’s labor force participation

library(car)
library(nnet)   # for `multinom()`
library(dplyr)
data(Womenlf, package = "carData")

make not.work the reference category

Womenlf <- within (Womenlf, {
  partic <- ordered(partic, levels=c('not.work', 'parttime', 'fulltime'))})

Fit model with main effects

wlf.multinom <- multinom(partic ~ hincome + children, 
                         data=Womenlf, Hess=TRUE)
## # weights:  12 (6 variable)
## initial  value 288.935032 
## iter  10 value 211.454772
## final  value 211.440963 
## converged
summary(wlf.multinom, Wald=TRUE)
## Call:
## multinom(formula = partic ~ hincome + children, data = Womenlf, 
##     Hess = TRUE)
## 
## Coefficients:
##          (Intercept)      hincome childrenpresent
## parttime   -1.432321  0.006893838      0.02145558
## fulltime    1.982842 -0.097232073     -2.55860537
## 
## Std. Errors:
##          (Intercept)    hincome childrenpresent
## parttime   0.5924627 0.02345484       0.4690352
## fulltime   0.4841789 0.02809599       0.3621999
## 
## Value/SE (Wald statistics):
##          (Intercept)    hincome childrenpresent
## parttime   -2.417573  0.2939197      0.04574407
## fulltime    4.095266 -3.4607098     -7.06407045
## 
## Residual Deviance: 422.8819 
## AIC: 434.8819
Anova(wlf.multinom)
## Analysis of Deviance Table (Type II tests)
## 
## Response: partic
##          LR Chisq Df Pr(>Chisq)    
## hincome    15.153  2  0.0005123 ***
## children   63.559  2  1.579e-14 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# overall test?
#car::linearHypothesis(wlf.multinom, "parttime, fulltime")

Examine coefficients

coef(wlf.multinom)
##          (Intercept)      hincome childrenpresent
## parttime   -1.432321  0.006893838      0.02145558
## fulltime    1.982842 -0.097232073     -2.55860537
exp(coef(wlf.multinom))
##          (Intercept)   hincome childrenpresent
## parttime    0.238754 1.0069177      1.02168740
## fulltime    7.263353 0.9073454      0.07741263

Wald tests & p-values

stats <- summary(wlf.multinom, Wald=TRUE)
z <- stats$Wald.ratios
p <- 2 * (1 - pnorm(abs(z)))
zapsmall(p)
##          (Intercept)   hincome childrenpresent
## parttime   0.0156244 0.7688193       0.9635142
## fulltime   0.0000422 0.0005388       0.0000000

Plot fitted values in two panels

op <- par(mfrow=c(1,2))

predictors <- expand.grid(hincome=1:45, children=c('absent', 'present'))
p.fit <- predict(wlf.multinom, predictors, type='probs')
Hinc <- 1:max(predictors$hincome)
for ( kids in c("absent", "present") ) {
    data <- subset(data.frame(predictors, p.fit), children==kids)
    plot( range(Hinc), c(0,1), type="n",
        xlab="Husband's Income", ylab='Fitted Probability',
        main = paste("Children", kids))
    lines(Hinc, data[, 'not.work'], lwd=3, col="black", lty=1)
    lines(Hinc, data[, 'parttime'], lwd=3, col="blue",  lty=2)
    lines(Hinc, data[, 'fulltime'], lwd=3, col="red",   lty=3)
  if (kids=="absent") {
  legend(5, 0.97, lty=1:3, lwd=3, col=c("black", "blue", "red"),
    legend=c('not working', 'part-time', 'full-time'))
    }
}

par(op)

Effect plots

wlf.effects <- allEffects(wlf.multinom)
plot(wlf.effects, style='stacked')

plot(Effect(c("hincome", "children"), wlf.multinom), 
     style = "stacked", key.args=list(x=.75, y=.25),
     colors = c(grey(.85), "pink", "lightblue")
     )

plotting probabilities

get fitted probabilities

options(digits=3)
predictors <- expand.grid(hincome=1:50, children=c('absent', 'present'))
fit <- data.frame(predictors, 
                  predict(wlf.multinom, predictors, type='probs'))

Re-shape for plotting

library(tidyr)

tidyr::gather()

plotdat <- fit |>
  gather(key="Level", value="Probability", not.work:fulltime) 


plotdat <- fit |>
  pivot_longer(not.work:fulltime, 
               names_to = "Level",
               values_to = "Probability") 
head(plotdat)
## # A tibble: 6 x 4
##   hincome children Level    Probability
##     <int> <fct>    <chr>          <dbl>
## 1       1 absent   not.work      0.128 
## 2       1 absent   parttime      0.0307
## 3       1 absent   fulltime      0.842 
## 4       2 absent   not.work      0.138 
## 5       2 absent   parttime      0.0335
## 6       2 absent   fulltime      0.828
library(directlabels)
gg <-
ggplot(plotdat, aes(x = hincome, y = Probability, colour = Level)) + 
  geom_line(size=1.5) + theme_bw() + 
  facet_grid(~ children, labeller = label_both) +
  theme_bw(base_size = 14)
direct.label(gg, list("top.bumptwice", dl.trans(y = y + 0.2)))

IycgLS0tDQojJyB0aXRsZTogIk11bHRpbm9taWFsIGxvZ2lzdGljIHJlZ3Jlc3Npb24iDQojJyBhdXRob3I6ICJNaWNoYWVsIEZyaWVuZGx5Ig0KIycgZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpKWAiDQojJyBvdXRwdXQ6DQojJyAgIGh0bWxfZG9jdW1lbnQ6DQojJyAgICAgdGhlbWU6IHJlYWRhYmxlDQojJyAgICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KIycgLS0tDQoNCiMnICMjIEZpdCBtb2RlbHMgZm9yIHdvbWVuJ3MgbGFib3IgZm9yY2UgcGFydGljaXBhdGlvbg0KDQpsaWJyYXJ5KGNhcikNCmxpYnJhcnkobm5ldCkgICAjIGZvciBgbXVsdGlub20oKWANCmxpYnJhcnkoZHBseXIpDQpkYXRhKFdvbWVubGYsIHBhY2thZ2UgPSAiY2FyRGF0YSIpDQoNCiMnICMjIyMgbWFrZSBgbm90LndvcmtgIHRoZSByZWZlcmVuY2UgY2F0ZWdvcnkNCg0KV29tZW5sZiA8LSB3aXRoaW4gKFdvbWVubGYsIHsNCiAgcGFydGljIDwtIG9yZGVyZWQocGFydGljLCBsZXZlbHM9Yygnbm90LndvcmsnLCAncGFydHRpbWUnLCAnZnVsbHRpbWUnKSl9KQ0KDQojJyAjIyBGaXQgbW9kZWwgd2l0aCBtYWluIGVmZmVjdHMNCndsZi5tdWx0aW5vbSA8LSBtdWx0aW5vbShwYXJ0aWMgfiBoaW5jb21lICsgY2hpbGRyZW4sIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9V29tZW5sZiwgSGVzcz1UUlVFKQ0Kc3VtbWFyeSh3bGYubXVsdGlub20sIFdhbGQ9VFJVRSkNCkFub3ZhKHdsZi5tdWx0aW5vbSkNCg0KIyBvdmVyYWxsIHRlc3Q/DQojY2FyOjpsaW5lYXJIeXBvdGhlc2lzKHdsZi5tdWx0aW5vbSwgInBhcnR0aW1lLCBmdWxsdGltZSIpDQoNCiMnICMjIEV4YW1pbmUgY29lZmZpY2llbnRzDQpjb2VmKHdsZi5tdWx0aW5vbSkNCmV4cChjb2VmKHdsZi5tdWx0aW5vbSkpDQoNCg0KIycgIyMgV2FsZCB0ZXN0cyAmIHAtdmFsdWVzDQpzdGF0cyA8LSBzdW1tYXJ5KHdsZi5tdWx0aW5vbSwgV2FsZD1UUlVFKQ0KeiA8LSBzdGF0cyRXYWxkLnJhdGlvcw0KcCA8LSAyICogKDEgLSBwbm9ybShhYnMoeikpKQ0KemFwc21hbGwocCkNCg0KDQojJyAjIyBQbG90IGZpdHRlZCB2YWx1ZXMgaW4gdHdvIHBhbmVscw0Kb3AgPC0gcGFyKG1mcm93PWMoMSwyKSkNCg0KcHJlZGljdG9ycyA8LSBleHBhbmQuZ3JpZChoaW5jb21lPTE6NDUsIGNoaWxkcmVuPWMoJ2Fic2VudCcsICdwcmVzZW50JykpDQpwLmZpdCA8LSBwcmVkaWN0KHdsZi5tdWx0aW5vbSwgcHJlZGljdG9ycywgdHlwZT0ncHJvYnMnKQ0KSGluYyA8LSAxOm1heChwcmVkaWN0b3JzJGhpbmNvbWUpDQpmb3IgKCBraWRzIGluIGMoImFic2VudCIsICJwcmVzZW50IikgKSB7DQoJZGF0YSA8LSBzdWJzZXQoZGF0YS5mcmFtZShwcmVkaWN0b3JzLCBwLmZpdCksIGNoaWxkcmVuPT1raWRzKQ0KCXBsb3QoIHJhbmdlKEhpbmMpLCBjKDAsMSksIHR5cGU9Im4iLA0KCQl4bGFiPSJIdXNiYW5kJ3MgSW5jb21lIiwgeWxhYj0nRml0dGVkIFByb2JhYmlsaXR5JywNCgkJbWFpbiA9IHBhc3RlKCJDaGlsZHJlbiIsIGtpZHMpKQ0KCWxpbmVzKEhpbmMsIGRhdGFbLCAnbm90LndvcmsnXSwgbHdkPTMsIGNvbD0iYmxhY2siLCBsdHk9MSkNCglsaW5lcyhIaW5jLCBkYXRhWywgJ3BhcnR0aW1lJ10sIGx3ZD0zLCBjb2w9ImJsdWUiLCAgbHR5PTIpDQoJbGluZXMoSGluYywgZGF0YVssICdmdWxsdGltZSddLCBsd2Q9MywgY29sPSJyZWQiLCAgIGx0eT0zKQ0KICBpZiAoa2lkcz09ImFic2VudCIpIHsNCiAgbGVnZW5kKDUsIDAuOTcsIGx0eT0xOjMsIGx3ZD0zLCBjb2w9YygiYmxhY2siLCAiYmx1ZSIsICJyZWQiKSwNCiAgICBsZWdlbmQ9Yygnbm90IHdvcmtpbmcnLCAncGFydC10aW1lJywgJ2Z1bGwtdGltZScpKQ0KICAgIH0NCn0NCnBhcihvcCkNCg0KDQoNCiMnICMjIEVmZmVjdCBwbG90cw0KIycgDQp3bGYuZWZmZWN0cyA8LSBhbGxFZmZlY3RzKHdsZi5tdWx0aW5vbSkNCnBsb3Qod2xmLmVmZmVjdHMsIHN0eWxlPSdzdGFja2VkJykNCg0KcGxvdChFZmZlY3QoYygiaGluY29tZSIsICJjaGlsZHJlbiIpLCB3bGYubXVsdGlub20pLCANCiAgICAgc3R5bGUgPSAic3RhY2tlZCIsIGtleS5hcmdzPWxpc3QoeD0uNzUsIHk9LjI1KSwNCiAgICAgY29sb3JzID0gYyhncmV5KC44NSksICJwaW5rIiwgImxpZ2h0Ymx1ZSIpDQogICAgICkNCg0KDQojJyAjIyBwbG90dGluZyBwcm9iYWJpbGl0aWVzDQoNCiMnIGdldCBmaXR0ZWQgcHJvYmFiaWxpdGllcw0Kb3B0aW9ucyhkaWdpdHM9MykNCnByZWRpY3RvcnMgPC0gZXhwYW5kLmdyaWQoaGluY29tZT0xOjUwLCBjaGlsZHJlbj1jKCdhYnNlbnQnLCAncHJlc2VudCcpKQ0KZml0IDwtIGRhdGEuZnJhbWUocHJlZGljdG9ycywgDQogICAgICAgICAgICAgICAgICBwcmVkaWN0KHdsZi5tdWx0aW5vbSwgcHJlZGljdG9ycywgdHlwZT0ncHJvYnMnKSkNCg0KDQojJyAjIyBSZS1zaGFwZSBmb3IgcGxvdHRpbmcNCmxpYnJhcnkodGlkeXIpDQoNCiMnIHRpZHlyOjpnYXRoZXIoKQ0KcGxvdGRhdCA8LSBmaXQgfD4NCiAgZ2F0aGVyKGtleT0iTGV2ZWwiLCB2YWx1ZT0iUHJvYmFiaWxpdHkiLCBub3Qud29yazpmdWxsdGltZSkgDQoNCg0KcGxvdGRhdCA8LSBmaXQgfD4NCiAgcGl2b3RfbG9uZ2VyKG5vdC53b3JrOmZ1bGx0aW1lLCANCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIkxldmVsIiwNCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJQcm9iYWJpbGl0eSIpIA0KaGVhZChwbG90ZGF0KQ0KDQpsaWJyYXJ5KGRpcmVjdGxhYmVscykNCmdnIDwtDQpnZ3Bsb3QocGxvdGRhdCwgYWVzKHggPSBoaW5jb21lLCB5ID0gUHJvYmFiaWxpdHksIGNvbG91ciA9IExldmVsKSkgKyANCiAgZ2VvbV9saW5lKHNpemU9MS41KSArIHRoZW1lX2J3KCkgKyANCiAgZmFjZXRfZ3JpZCh+IGNoaWxkcmVuLCBsYWJlbGxlciA9IGxhYmVsX2JvdGgpICsNCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpDQpkaXJlY3QubGFiZWwoZ2csIGxpc3QoInRvcC5idW1wdHdpY2UiLCBkbC50cmFucyh5ID0geSArIDAuMikpKQ0KDQoNCg==