---
title: "EC306 Assignment 1: Child Care and Mothers' Labour Supply"
subtitle: "Answer Key"
author: "Prof. Justin Smith"
date: today
format:
  pdf:
    fig-width: 6
    fig-height: 3.5
    include-in-header:
      text: |
        \usepackage{float}
        \floatplacement{table}{H}
        \floatplacement{figure}{H}
execute:
  message: false
  warning: false
---

<!--
  ANSWER KEY. Not for the course site until after the due date.

  Built from the student template: the question text is identical, with
  the code chunks filled in and an answer under each "Answer:". The test
  suite (tests/run_tests.R) checks that the question text still matches
  the template, so edit the template first and then carry the change here.

  This file is also the "perfect" test submission for the autograder.
-->

## Background

Since 1997, Quebec has offered regulated child care at a low fixed daily
fee: originally \$5 a day, and still under \$10 a day in 2019. Until
2021, parents in the rest of Canada mostly paid market prices that were
many times higher. In 2021 the federal government began signing
agreements with the other provinces and territories to bring average
fees down to \$10 a day by 2026. Because the rest of Canada has been
catching up since then, this assignment uses data from 2019.

In the labour supply model, child care is a cost of working: a parent
who takes a job has to pay for care during the hours they are away.
Cheaper child care raises the net return to working, so we would expect
it to draw parents of young children, and mothers especially, into the
labour force. In this assignment you will look at whether the data are
consistent with that prediction, and then think about whether the
comparison you make can be read as causal.

## The data

The data come from the Labour Force Survey public use microdata file for
March 2019. The sample is everyone aged 25 to 54.

| Variable   | Description                                                     |
|:-----------|:----------------------------------------------------------------|
| `id`       | Person identifier                                               |
| `province` | Province of residence                                           |
| `gender`   | "Women+" or "Men+"                                              |
| `agegroup` | Five-year age group                                             |
| `educ`     | Highest level of education                                      |
| `lfsstat`  | Labour force status: "Employed, at work", "Employed, absent from work", "Unemployed", or "Not in labour force" |
| `kidage`   | Age of youngest child living with the person: "Under 6", "6 to 12", "13 to 17", "18 to 24", or "None under 25" |
| `hours`    | Usual weekly hours at all jobs (missing if not employed)        |

## Instructions

-   Write your R code in the chunks provided. You can add more chunks if
    you need them.
-   When a question tells you to store a result under a particular name,
    such as `q2` or `gap_u6`, use exactly that name. Those objects are
    marked by computer, and a different name counts as missing.
-   Do not round the numbers you store. Round only when you display them.
-   Tables and graphs must be presentable: use `modelsummary()`,
    `datasummary()` or `datasummary_df()` for tables, and give every
    graph readable axis labels. Do not show a table by just printing a
    data frame.
-   The hints under each question point to sections of the R tutorial,
    the Introduction to R and Quarto page on the course website. Each
    section has a worked example of the step the hint describes, using
    different data.
-   Render the document after each question, not only at the end.
-   Every written answer goes under **Answer:**, and what it must cover is
    set out just above, under **Comment on the results**.
-   Each question is marked out of 5 from your PDF, using the rubric on
    the assignment page. The objects you are told to create are also
    checked by computer, for another 5 marks, so the assignment is out
    of 30.

## Setup

Do not change this chunk or the next one.

```{r}
#| label: setup
library(tidyverse)
library(modelsummary)
```

```{r}
#| label: load-data
lfs <- read_csv("ec306assign1.csv")

# Put the categories of kidage in their natural order, so tables and
# graphs list them from youngest to oldest instead of alphabetically.
lfs <- lfs |>
  mutate(kidage = factor(kidage, levels = c("Under 6", "6 to 12", "13 to 17",
                                            "18 to 24", "None under 25")))

glimpse(lfs)
```

```{r}
#| label: key-helpers
#| include: false
# Helpers for quoting numbers in the key's written answers. They are not
# part of the answer, and students are not expected to write functions.
pct <- function(x, digits = 1) sprintf(paste0("%.", digits, "f"), 100 * x)
```

## Question 1 (5 marks)

Create the following dummy variables and add them to `lfs`:

-   `lfp`: 1 if the person is in the labour force (employed and at work,
    employed but absent from work, or unemployed), 0 otherwise
-   `woman`: 1 if `gender` is "Women+", 0 otherwise
-   `quebec`: 1 if `province` is "Quebec", 0 otherwise
-   `kid_u6`: 1 if the person's youngest child is under 6 (`kidage` is
    "Under 6"), 0 otherwise

Then make a table showing the mean, standard deviation, minimum, and
maximum of the four dummy variables.

*Hints.*

-   Create the dummies with `mutate()`, and save the result back into
    `lfs`; otherwise the new variables are not kept. A comparison such
    as `province == "Ontario"` gives `TRUE` or `FALSE` for each person,
    and wrapping it in `as.numeric()` turns that into 1 or 0. See
    "Dummy variables" in the R tutorial.
-   Three of the four categories of `lfsstat` count as being in the
    labour force. You can join comparisons with `|` (or), or use `!=`
    (is not equal to) on the one category that does not count. See
    "Dummy variables" and "`filter()` — keep some rows" in the R
    tutorial.
-   Text has to match exactly, capitals and punctuation included. Run
    `count(lfs, lfsstat)` to see the exact spellings.
-   For the table, use `datasummary()` with the statistics `Mean`, `SD`,
    `Min` and `Max`. See "Tables" in the R tutorial.

```{r}
#| label: q1-dummies
lfs <- lfs |>
  mutate(
    lfp    = as.numeric(lfsstat != "Not in labour force"),
    woman  = as.numeric(gender == "Women+"),
    quebec = as.numeric(province == "Quebec"),
    kid_u6 = as.numeric(kidage == "Under 6")
  )
```

```{r}
#| label: q1-table
datasummary(
  (`In labour force` = lfp) + (`Woman` = woman) + (`Lives in Quebec` = quebec) +
    (`Youngest child under 6` = kid_u6) ~ Mean + SD + Min + Max,
  data = lfs,
  fmt = 3
)
```

**Comment on the results.** What does the table tell you about the
people in the sample? Before you write, review how to interpret the
mean of a dummy variable.

**Answer:**

The mean of a dummy variable is the share of the sample for whom it
equals 1. Among Canadians aged 25 to 54, `r pct(mean(lfs$lfp))`% are in
the labour force. The sample is almost evenly split by gender
(`r pct(mean(lfs$woman))`% women). `r pct(mean(lfs$quebec))`% of the
sample lives in Quebec, somewhat below Quebec's share of the population,
because the LFS oversamples the smaller provinces and these figures are
unweighted. `r pct(mean(lfs$kid_u6))`% have a youngest child under 6.
The minimum of 0 and maximum of 1 confirm that each variable is a dummy,
and for a dummy the standard deviation is determined by the mean,
$\sqrt{p(1-p)}$, so it carries no extra information.

## Question 2 (5 marks)

Keep only women. For each combination of `kidage` and `quebec`,
calculate the labour force participation rate. That gives 10 rates: five
child age groups, in Quebec and in the rest of Canada. Store the result
in a data frame called `q2`, with the rates in a column called
`lfp_rate`.

Then make a bar chart of the participation rates, with the age of the
youngest child on the horizontal axis and the Quebec and rest-of-Canada
bars side by side. You do not need a table for this question: the graph
presents the rates.

*Hints.*

-   Do not overwrite `lfs` with the women-only data, because later
    questions need everyone. Use `filter()` to save the women in a new
    data frame called `women`; you will use it again in Questions 3
    and 4. See "`filter()` — keep some rows" in the R tutorial.
-   The rates come from `group_by()` followed by `summarise()`, with
    both variables in `group_by()`. See "Grouping by two variables" in
    the R tutorial.
-   Give `q2` to `ggplot()`, not `women`. `geom_col()` draws the bars,
    `position = "dodge"` puts them side by side, and mapping
    `factor(quebec)` to `fill` colours them by province. Replace the 0
    and 1 in the legend with words. See "Bar charts of results you have
    calculated" in the R tutorial.

```{r}
#| label: q2-rates
women <- lfs |> filter(woman == 1)

q2 <- women |>
  group_by(kidage, quebec) |>
  summarise(lfp_rate = mean(lfp), n = n())
```

```{r}
#| label: q2-graph
#| fig-cap: "Labour force participation of women aged 25 to 54, by age of youngest child"
ggplot(q2, aes(x = kidage, y = lfp_rate, fill = factor(quebec))) +
  geom_col(position = "dodge") +
  scale_fill_discrete(labels = c("Rest of Canada", "Quebec")) +
  scale_y_continuous(labels = scales::percent) +
  coord_cartesian(ylim = c(0.5, 1)) +
  labs(x = "Age of youngest child", y = "Participation rate", fill = NULL)
```

```{r}
#| label: q2-numbers
#| include: false
# Helper for quoting numbers in the text (see key-helpers)
r <- function(k, q) q2$lfp_rate[q2$kidage == k & q2$quebec == q]
```

**Comment on the results.** What does the graph show? Describe how
participation changes as the youngest child gets older, and how the gap
between Quebec and the rest of Canada changes.

**Answer:**

In the rest of Canada, participation is lowest for women whose youngest
child is under 6 (`r pct(r("Under 6", 0))`%). It rises once the youngest
child reaches school age, to `r pct(r("6 to 12", 0))`% for a youngest
child aged 6 to 12 and `r pct(r("13 to 17", 0))`% for 13 to 17. In
Quebec the dip for mothers of young children almost disappears: their
participation rate is `r pct(r("Under 6", 1))`%, about the same as for
Quebec women with no children under 25.

Quebec women participate more than women elsewhere in every group, but
the gap is largest, at about
`r round(100 * (r("Under 6", 1) - r("Under 6", 0)))` percentage points,
for women whose youngest child is under 6, which is the group for whom
the cost of child care matters most. For women with no children under
25, the gap is only about
`r round(100 * (r("None under 25", 1) - r("None under 25", 0)))` points.
This pattern is what the labour supply model predicts if cheap child
care lowers the cost of working. (Note the vertical axis starts at 50%
so that the differences are visible.)

## Question 3 (5 marks)

Participation is only one way to adjust labour supply. The other is how
many hours to work. Keep only women who are employed (at work or absent
from work) and whose youngest child is under 6. Make a box plot of usual
weekly hours (`hours`) for Quebec and for the rest of Canada.

*Hints.*

-   Start from `women`, and save the filtered data as a new data frame
    to give to `ggplot()`. Conditions in `filter()` separated by commas
    must all hold, so you can write the condition on employment and the
    condition on the child separately. Two categories of `lfsstat` count
    as employed. See "`filter()` — keep some rows" in the R tutorial.
-   Put `factor(quebec)` on the horizontal axis and replace the 0 and 1
    on the axis with words. Adding `outliers = FALSE` to
    `geom_boxplot()` leaves out the individual points beyond the
    whiskers, which otherwise crowd the graph. See the boxplot of men's
    and women's wages under "Graphs" in the R tutorial.

```{r}
#| label: q3-graph
#| fig-cap: "Usual weekly hours of employed women whose youngest child is under 6"
q3_data <- women |>
  filter(kid_u6 == 1,
         lfsstat %in% c("Employed, at work", "Employed, absent from work"))

ggplot(q3_data, aes(x = factor(quebec), y = hours, fill = factor(quebec))) +
  geom_boxplot(outliers = FALSE, width = 0.5, show.legend = FALSE) +
  scale_x_discrete(labels = c("Rest of Canada", "Quebec")) +
  labs(x = NULL, y = "Usual weekly hours, all jobs")
```

```{r}
#| label: q3-numbers
#| include: false
h <- q3_data |>
  group_by(quebec) |>
  summarise(mean = mean(hours), med = median(hours),
            p25 = quantile(hours, 0.25), p75 = quantile(hours, 0.75))
# Helper for quoting numbers in the text (see key-helpers)
hq <- function(stat, q) h[[stat]][h$quebec == q]
```

**Comment on the results.** Do employed mothers of young children in
Quebec work more hours than those in the rest of Canada? How does the
difference compare with the difference in participation you found in
Question 2?

**Answer:**

Hours are similar. The median employed mother of a young child usually
works `r hq("med", 1)` hours a week in Quebec and `r hq("med", 0)` in the
rest of Canada, while the means are about an hour apart the other way
(`r round(hq("mean", 1), 1)` in Quebec and `r round(hq("mean", 0), 1)`
elsewhere). The Quebec distribution is more compressed: its 25th
percentile is higher (`r hq("p25", 1)` hours against `r hq("p25", 0)`)
and its 75th percentile lower (`r round(hq("p75", 1), 1)` against
`r hq("p75", 0)`). Fewer Quebec mothers work short part-time hours, and
fewer work long hours.

Compared with the participation gap of about
`r round(100 * (r("Under 6", 1) - r("Under 6", 0)))` percentage points, the
difference in hours is small. The Quebec difference is mainly at the
extensive margin (whether mothers work at all) rather than the intensive
margin (how much they work once employed). That fits the idea that child
care costs act largely like a fixed cost of working, which mainly
affects the decision to participate.

## Question 4 (5 marks)

The Quebec gap for mothers of young children in Question 2 may not all
be due to child care. Quebec could differ from the rest of Canada in
other ways, such as its labour market or attitudes toward women working,
that raise participation for *all* Quebec women. Women whose youngest
child is not under 6 rarely need daycare, so the Quebec gap for them
estimates that general difference. Subtracting it from the gap for
mothers of young children gives a **difference-in-differences** estimate
of the effect of child care. For example, with made-up numbers:

| Participation rate            | Quebec | Rest of Canada | Quebec minus rest of Canada |
|:------------------------------|-------:|---------------:|----------------------------:|
| Youngest child under 6        |    80% |            70% |                   10 points |
| All other women               |    85% |            81% |                    4 points |
| **Difference in differences** |        |                |               **6 points** |

**(a)** Using women only, calculate the four participation rates by
`quebec` and `kid_u6`, the same way as in Question 2, and present them
in a table. Then calculate the following, and store each as a single
number without rounding:

-   `gap_u6`: the Quebec minus rest-of-Canada participation gap for women
    whose youngest child is under 6
-   `gap_other`: the same gap for all other women (`kid_u6 == 0`)
-   `did`: `gap_u6 - gap_other`

*Hints.*

-   `datasummary_df()` turns a data frame of results, such as your four
    rates, into a presentable table. See "Tables" in the R tutorial.
-   For `gap_u6`, `gap_other` and `did`, store each of the four rates as
    its own object first, under a name of your choosing, then subtract.
-   Each rate is the mean of `lfp` for one group of women. Square
    brackets pick out a group: `women$lfp[women$quebec == 1]` is `lfp`
    for every Quebec woman, and `&` adds a second condition. See
    "Picking out elements" and "Functions" in the R tutorial.

```{r}
#| label: q4a-table
q4_table <- women |>
  group_by(quebec, kid_u6) |>
  summarise(lfp_rate = mean(lfp))

datasummary_df(q4_table, fmt = 3)
```

```{r}
#| label: q4a
qc_u6     <- mean(women$lfp[women$quebec == 1 & women$kid_u6 == 1])
roc_u6    <- mean(women$lfp[women$quebec == 0 & women$kid_u6 == 1])
qc_other  <- mean(women$lfp[women$quebec == 1 & women$kid_u6 == 0])
roc_other <- mean(women$lfp[women$quebec == 0 & women$kid_u6 == 0])

gap_u6    <- qc_u6 - roc_u6
gap_other <- qc_other - roc_other
did       <- gap_u6 - gap_other

round(c(gap_u6 = gap_u6, gap_other = gap_other, did = did), 3)
```

**Comment on the results.** Report the three numbers in percentage
points (0.05 is 5 percentage points) and explain what each one means.
What has to be true for `did` to measure the effect of Quebec's child
care policy?

**Answer:**

-   `gap_u6` = `r pct(gap_u6)` percentage points: among women whose
    youngest child is under 6, the participation rate is
    `r pct(gap_u6)` points higher in Quebec than in the rest of Canada
    (`r pct(qc_u6)`% against `r pct(roc_u6)`%).
-   `gap_other` = `r pct(gap_other)` percentage points: among all other
    women, who rarely need daycare, participation is `r pct(gap_other)`
    points higher in Quebec. This is the general Quebec difference.
-   `did` = `r pct(did)` percentage points: the extra Quebec advantage
    that is specific to mothers of young children.

So of the `r pct(gap_u6)`-point Quebec gap for mothers of young
children, about `r pct(gap_other)` points reflect the general Quebec
difference that shows up among all women, and about `r pct(did)` points
are specific to mothers of young children. That `r pct(did)` points is
the difference-in-differences estimate of the effect of Quebec's child
care policy.

For `did` to measure the effect of the policy, the general Quebec
difference has to be the same for both groups: without cheap child care,
Quebec mothers of young children would have had the same
`r pct(gap_other)`-point advantage as other Quebec women, no more and no
less. If something else sets Quebec mothers of young children apart,
such as more generous parental leave, `did` picks that up too.

**(b)** Using women only, estimate the regression

$$
lfp_i = \beta_0 + \beta_1 quebec_i + \beta_2 kid\_u6_i + \beta_3 (quebec_i \times kid\_u6_i) + \epsilon_i
$$

and store it as `q4_model`. Present the results in a table with
`modelsummary()`.

*Hint.* Estimate it with `lm()`, using `women` as the data. In an R
formula, `quebec * kid_u6` includes both variables and their product.
See "Interactions" in the R tutorial.

```{r}
#| label: q4b
q4_model <- lm(lfp ~ quebec * kid_u6, data = women)

modelsummary(
  list("Women" = q4_model),
  coef_rename = c("(Intercept)" = "Constant", "quebec" = "Quebec",
                  "kid_u6" = "Youngest child under 6",
                  "quebec:kid_u6" = "Quebec × child under 6"),
  gof_map = c("nobs", "r.squared"),
  stars = TRUE,
  fmt = 3
)
```

```{r}
#| label: q4-numbers
#| include: false
b <- coef(q4_model)
```

**Comment on the results.** Interpret each of the four coefficients.
How does $\beta_3$ compare with `did` from part (a)?

**Answer:**

-   $\beta_0$ = `r round(b[1], 3)`: the participation rate of women in
    the rest of Canada whose youngest child is not under 6.
-   $\beta_1$ = `r round(b[2], 3)`: among women whose youngest child is
    not under 6, Quebec women's participation is `r pct(b[2])` points
    higher. This equals `gap_other`.
-   $\beta_2$ = `r round(b[3], 3)`: in the rest of Canada, women whose
    youngest child is under 6 participate `r pct(-b[3])` points less
    than other women.
-   $\beta_3$ = `r round(b[4], 3)`: the Quebec gap is `r pct(b[4])`
    points larger for women whose youngest child is under 6 than for
    other women.

$\beta_3$ is exactly equal to `did`. With two dummies and their
interaction, the regression has one coefficient for each of the four
groups, so it reproduces the four group means exactly, and the
interaction is the difference in differences. What the regression adds
is a standard error: $\beta_3$ is statistically significant at the 1%
level.

## Question 5 (5 marks)

**(a)** Estimate the same regression for men, and store it as
`q5_model`. Present both regressions side by side in one table, with
the columns labelled "Women" and "Men". Part (a) needs no written
answer; you will use the results in part (b).

*Hints.*

-   You need a men-only data frame, made the same way as `women`.
-   `modelsummary()` accepts a list of models, and the names you give
    the elements of the list become the column headings. See
    "Presenting results" in the R tutorial.

```{r}
#| label: q5
men <- lfs |> filter(woman == 0)
q5_model <- lm(lfp ~ quebec * kid_u6, data = men)

modelsummary(
  list("Women" = q4_model, "Men" = q5_model),
  coef_rename = c("(Intercept)" = "Constant", "quebec" = "Quebec",
                  "kid_u6" = "Youngest child under 6",
                  "quebec:kid_u6" = "Quebec × child under 6"),
  gof_map = c("nobs", "r.squared"),
  stars = TRUE,
  fmt = 3
)
```

```{r}
#| label: q5-numbers
#| include: false
bm <- coef(q5_model)
absent <- women |>
  filter(kid_u6 == 1) |>
  group_by(quebec) |>
  summarise(absent = mean(lfsstat == "Employed, absent from work"))
```

**(b)** **Comment on the results.** Is `did` a causal estimate of the
effect of Quebec's child care policy on mothers' participation? In your
answer, consider:

-   what the result for men tells you;
-   other ways Quebec differs from the rest of Canada that could affect
    parents of young children. One example: the LFS counts a parent on
    parental leave, with a job to return to, as "employed, absent from
    work";
-   in 2021 the other provinces began cutting their child care fees
    toward \$10 a day. If you repeated this analysis with data from
    2025, what would you expect to happen to `did`, and why?

**Answer:**

It is suggestive, but not conclusive. The key assumption is that without
the policy, the Quebec gap for mothers of young children would have
matched the gap for other women. Several things could make that fail.

*Men.* For men the interaction is `r round(bm[4], 3)`, small and not
statistically significant. Whatever raises participation among Quebec
mothers of young children does not show up among Quebec fathers of young
children. That supports reading the women's result as something specific
to mothers, which is where child care costs are expected to bite, rather
than something that affects all Quebec parents. Men are an imperfect
comparison, though: almost all fathers of young children are in the
labour force (note the positive coefficient on the child dummy), so
there is little room for any policy to raise their participation.

*Other differences between Quebec and the rest of Canada.* Quebec
mothers of young children may differ from mothers elsewhere in age,
education, or when they have children, and Quebec has other family
policies. The most relevant is parental leave. Quebec runs its own, more
generous parental insurance plan, and because the LFS counts a parent on
leave with a job to return to as employed, more generous leave could
raise measured participation of mothers of infants without any role for
child care. In these data it can explain only a small part of the gap:
`r pct(absent$absent[absent$quebec == 1])`% of Quebec mothers of young
children are employed but absent from work, against
`r pct(absent$absent[absent$quebec == 0])`% elsewhere. That difference of
about `r round(100 * diff(absent$absent))` points is small next to
the participation gap; most of the Quebec advantage comes from more
mothers being at work.

*Fees elsewhere, then and now.* In March 2019 the rest of Canada had not
yet cut fees broadly, although BC and Alberta had started smaller
fee-reduction programs in 2017 and 2018, so some families outside Quebec
already had cheaper care. After 2021 the other provinces cut fees toward
\$10 a day, so data from 2025 would compare Quebec with provinces that
are partly treated themselves. If cheaper care raises mothers'
participation, mothers elsewhere should have gained ground, and `did`
should shrink. It does: the same calculation with the March 2025 LFS
gives about 5.9 points, against `r pct(did)` here. Other things changed
between 2019 and 2025, the pandemic above all, so that is suggestive
rather than proof. A convincing causal estimate would compare mothers
before and after a policy change, like the studies of Quebec's 1997
reform, rather than across provinces at a single point in time.

## Use of generative AI

If you used a generative AI tool for any part of this assignment, name
the tool and describe what you used it for. If you did not use one, say
so.

Not applicable (answer key).

## Before you submit

This chunk lists any required objects that are still missing. It should
say "All required objects found" before you submit.

```{r}
#| label: check
#| echo: false
required <- c("lfs", "q2", "gap_u6", "gap_other", "did", "q4_model", "q5_model")
missing  <- required[!sapply(required, exists)]
if (exists("lfs")) {
  missing_cols <- setdiff(c("lfp", "woman", "quebec", "kid_u6"), names(lfs))
  if (length(missing_cols) > 0) missing <- c(missing, paste0("lfs$", missing_cols))
}
if (length(missing) == 0) {
  cat("All required objects found\n")
} else {
  cat("Still missing:", missing, sep = "\n  ")
}
```
