Chapter 6 — Practice Demo Lab: Reference Solution

Lab: Clean the air-quality file together

Note

Reference solution for the Chapter 6 Practice Demo Lab (Tasks 1–6 of Lab: Clean the air-quality file together). Check your own attempt against it. The graded Canvas lab has its own private answer key.

Task 1 — Inspect together (the six moves)

air <- read_csv(here("data", "airdata3.csv"), show_col_types = FALSE)

dim(air)                       # rows x columns
[1] 11904    27
n_all_na <- sum(map_lgl(air, ~ all(is.na(.))))
n_with_data <- ncol(air) - n_all_na
c(columns = ncol(air), all_NA_columns = n_all_na, columns_with_data = n_with_data)
          columns    all_NA_columns columns_with_data 
               27                14                13 

The file has 11904 rows × 27 columns; 14 columns are 100 % missing and 13 carry data. glimpse(air) shows the key columns: location (the monitoring station), Date, Time, and pollutant columns including O3.

Task 2 — Drop the redundant columns

Drop the two spreadsheet index columns and every 100 %-missing column:

air2 <- air |>
  select(-`...1`, -`Unnamed: 0`) |>       # drop the spreadsheet index columns
  select(where(~ !all(is.na(.))))         # drop columns that are entirely NA
ncol(air2)                                 # columns remaining
[1] 11
names(air2)
 [1] "PM10"     "SO2"      "CO"       "NO"       "NO2"      "PM25"    
 [7] "O3"       "location" "Date"     "Time"     "TRS"     

That leaves the 11 columns that actually contain datalocation, Date, Time, O3, and the other measured pollutants.

Task 3 — Parse the date

air3 <- air2 |> mutate(date = mdy(Date))
sum(is.na(air3$date))          # how many dates failed to parse?
[1] 0

mdy(Date) parses every row — the failure count is 0 — because the file stores dates as month/day/year (e.g., 1/1/2000). If any had failed, they would show up as NA in this count.

Task 4 — Filter and group: mean O₃ per station (sorted)

by_station <- air3 |>
  filter(!is.na(O3)) |>
  group_by(location) |>
  summarise(mean_o3 = round(mean(O3), 1),
            n_hours = n(),
            .groups = "drop") |>
  arrange(desc(mean_o3))
kable(by_station, caption = "Mean hourly ozone (O3, ppb) by station, January 2000, highest first.")
Mean hourly ozone (O3, ppb) by station, January 2000, highest first.
location mean_o3 n_hours
Langley Central 17.7 732
Maple Ridge Golden Ears School 11.3 564
Richmond South 10.5 732
North Delta 10.3 731
Vancouver International Airport #2 10.2 727
Burnaby South 9.1 732
Vancouver Kitsilano 7.5 731
Port Moody Rocky Point Park 6.1 728

Task 5 — Discuss the result

Langley Central has the highest mean O₃ (17.7 ppb) for the month. That is consistent with Metro Vancouver geography: ozone is a secondary pollutant that forms downwind of traffic emissions, so cleaner-air / more suburban or elevated sites often record higher ozone than the busiest downtown stations — the opposite of what many students expect.

Task 6 — Submit

Each group submits: the final pipeline (Tasks 2–4 as one Quarto chunk), the station-ranked table from Task 4, and a one-sentence interpretation (Task 5), with all members’ names. (For the graded Canvas lab, follow the Canvas instructions.)