Skip to contents

Many user measures start at the task level: a researcher labels tasks, a model scores task text, or a team codes task exposure manually. Occupation-level analysis needs one score per occupation. onet_task_to_occupation() performs that mechanical rollup using O*NET task ratings.

Read Task Statements and Ratings

tasks <- onet_archive_read(
  "30.3",
  "Task Statements",
  path = archive_dir,
  release_date = "2026-05-01"
)
ratings <- onet_archive_read(
  "30.3",
  "Task Ratings",
  path = archive_dir,
  release_date = "2026-05-01"
)

tasks |>
  select(onet_soc_code, task_id, task_type, task) |>
  knitr::kable(digits = 3, align = "l")
onet_soc_code task_id task_type task
15-1252.00 1001 Core Analyze user needs and software requirements.
15-1252.00 1002 Supplemental Prepare reports on software testing status.
29-1141.00 2001 Core Monitor patient health and record signs.

ratings |>
  select(onet_soc_code, task_id, scale_id, scale_name, data_value) |>
  head(8) |>
  knitr::kable(digits = 3, align = "l")
onet_soc_code task_id scale_id scale_name data_value
15-1252.00 1001 RT Relevance of Task 95.0
15-1252.00 1001 IM Importance 4.5
15-1252.00 1002 RT Relevance of Task 45.0
29-1141.00 2001 RT Relevance of Task 98.0
29-1141.00 2001 IM Importance 4.8

Validate Task Scores

task_scores <- tibble::tibble(
  task_id = c("1001", "1002", "2001"),
  score = c(0.80, 0.40, 0.20)
)

measure <- onet_measure(
  task_scores,
  key = "task_id",
  score = "score",
  key_type = "task",
  universe = tasks$task_id,
  measure_id = "stylized_task_score",
  release_version = "30.3"
)

onet_coverage(measure) |>
  knitr::kable(digits = 3, align = "l")
key_type n_input n_universe n_matched coverage_share employment_coverage_share
task 3 3 3 1 NA

Roll Up with Relevance Weights

core_only <- onet_task_to_occupation(
  measure,
  task_ratings = ratings,
  task_metadata = tasks,
  weight_scale = "RT",
  include_supplemental = FALSE
)

core_plus_supplemental <- onet_task_to_occupation(
  measure,
  task_ratings = ratings,
  task_metadata = tasks,
  weight_scale = "RT",
  include_supplemental = TRUE
)

core_only |>
  select(onet_soc_code, soc_code, n_tasks, total_task_weight, measure_score) |>
  knitr::kable(digits = 3, align = "l")
onet_soc_code soc_code n_tasks total_task_weight measure_score
15-1252.00 15-1252 1 95 0.8
29-1141.00 29-1141 1 98 0.2
core_plus_supplemental |>
  select(onet_soc_code, soc_code, n_tasks, total_task_weight, measure_score) |>
  knitr::kable(digits = 3, align = "l")
onet_soc_code soc_code n_tasks total_task_weight measure_score
15-1252.00 15-1252 2 140 0.671
29-1141.00 29-1141 1 98 0.200

Interpret the Plumbing Choice

comparison <- bind_rows(
  core_only |> mutate(rule = "Core tasks only"),
  core_plus_supplemental |> mutate(rule = "Core plus Supplemental")
) |>
  select(rule, onet_soc_code, n_tasks, total_task_weight, measure_score)

comparison |>
  knitr::kable(digits = 3, align = "l")
rule onet_soc_code n_tasks total_task_weight measure_score
Core tasks only 15-1252.00 1 95 0.800
Core tasks only 29-1141.00 1 98 0.200
Core plus Supplemental 15-1252.00 2 140 0.671
Core plus Supplemental 29-1141.00 1 98 0.200

The task score did not change; only the rollup rule did. A clear write-up keeps the scoring choice separate from the package mechanics.