The new challenge: split, reshape, and recombine mixed data
The table mixes two levels of detail. Full-time employment is divided into occupation rows, while every other employment status is already a single total. We must separate these structures, aggregate them to the same level, recombine them, and only then construct a denominator.
13.1 Learning objectives
By the end of this case, you should be able to:
recognize a table that mixes different levels of detail;
split rows with different structures;
recombine detailed occupation rows into comparable status totals;
reshape the status totals into columns;
build a denominator from mutually exclusive categories; and
calculate a weighted rate.
13.2 Why the familiar workflow is not enough
The Norway holdings have a relatively simple row structure. The Hong Kong graduate employment data are more complicated. A single group_by() can produce a result, but first separating the two row structures makes the aggregation rule visible and easier to check.
Continue in the same project
Open djr.Rproj and create 11-employment.Rmd. Download employment.csv and save it in data/. The familiar folder structure lets you concentrate on the more complicated row structure.
13.3 Set up the case
library(tidyverse)employment <-read_csv("data/employment.csv") |>rename(academic_year =`Academic Year`,university = University,level =`Level of study`,status =`Employment Situation`,occupation = Occupation,headcount =`Number of Graduates (Headcount)` )glimpse(employment)
Rows: 5,669
Columns: 6
$ academic_year <chr> "2009/10", "2009/10", "2009/10", "2009/10", "2009/10", "…
$ university <chr> "City University of Hong Kong", "City University of Hong…
$ level <chr> "Research postgraduate", "Research postgraduate", "Resea…
$ status <chr> "FT employment", "FT employment", "FT employment", "FT e…
$ occupation <chr> "Authors, Journalists and Related Writers", "Business Pr…
$ headcount <dbl> 1, 2, 2, 1, 3, 1, 3, 1, 15, 2, 18, 8, 5, 1, 1, 97, 1, 6,…
For full-time employment, the occupation column contains many detailed categories. For other statuses, it contains “Not in Full-time Employment.”
One raw row therefore represents one headcount cell for an academic year, university, study level, employment status, and—only for full-time employment—occupation.
flowchart TD
A["Year × university × level"] --> B["Full-time employment"]
A --> C["Other employment status"]
B --> D["Several occupation rows"]
C --> E["One row"]
Counting raw rows would count categories, not graduates.
13.5 The strategy
We will solve the mixed structure in six steps:
split full-time and other-status rows;
aggregate the detailed occupation rows;
recombine comparable status totals;
reshape statuses into columns;
construct a denominator; and
add headcounts before calculating a combined rate.
Each step changes what one row represents. State that unit after every major transformation.
13.6 Strategy 1: split the two row structures
Use filter() to create one table for detailed full-time records and another for the already aggregated statuses:
The split is based on data structure, not on which outcome is more important. It prevents the occupation rows from being treated as if they were already comparable with unemployment or further-study totals.
13.7 Strategy 2: aggregate the detailed rows
Within the full-time table, add occupation headcounts for each cohort:
One row now represents one employment status within one cohort. Recombining before the full-time rows were aggregated would recreate the original problem.
Do not simply average the study-level rates. That would give a small cohort the same influence as a large cohort. Adding the headcounts first weights the result by the number of graduates.
A descriptive comparison is not a league table
Universities differ in subjects, study levels, student populations, and career paths. The rates describe reported outcomes. They do not prove that attending one university caused a better or worse outcome.
13.12 Optional extension: examine one occupation
Suppose the question concerns authors, journalists, and related writers. First stay within full-time employment, then create an indicator column before grouping. if_else() assigns one value when a condition is true and another when it is false: