Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions data/abcs_gas/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# abcs_gas

This is a dcf data source project, initialized with `dcf::dcf_add_source`.

You can us the `dcf` package to check the project:

```R
dcf_check_source("abcs_gas", "..")
```

And process it:

```R
dcf_process("abcs_gas", "..")
```
193 changes: 193 additions & 0 deletions data/abcs_gas/ingest.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# =============================================================================
# ABCs Group A Streptococcus Data Ingestion
# Source: https://data.cdc.gov/Public-Health-Surveillance/Active-Bacterial-Core-surveillance-ABCs-Group-A-St/9y49-tura/about_data
# =============================================================================

library(dplyr)

process <- dcf::dcf_process_record()

raw_state <- dcf::dcf_download_cdc(
"9y49-tura",
"raw",
process$raw_state
)

if (!identical(process$raw_state, raw_state)) {

data_raw <- vroom::vroom("raw/9y49-tura.csv.xz", show_col_types = FALSE) %>%
rename(
year = Year,
value = Value,
units = Units,
bacteria = Bacteria,
topic = Topic,
viewby = ViewBy,
viewby2 = ViewBy2
) %>%
mutate(
# Normalize casing inconsistencies across years
topic = case_when(
tolower(trimws(topic)) == "case rates" ~ "Case rates",
tolower(trimws(topic)) == "death rates" ~ "Death rates",
tolower(trimws(topic)) == "number of cases and deaths" ~ "Number of cases and deaths",
tolower(trimws(topic)) == "syndromes" ~ "Syndromes",
tolower(trimws(topic)) == "antibiotic resistance" ~ "Antibiotic resistance",
tolower(trimws(topic)) %in% c("emm types", "emm types") ~ "Emm types",
TRUE ~ topic
),
time = as.Date(paste0(year, "-12-31")),
geography = "00"
)

# ---------------------------------------------------------------------------
# 1. Case rates and death rates (by age, sex, race, and overall)
# ---------------------------------------------------------------------------
rate_topics <- c("Case rates", "Death rates")

make_measure <- function(df) {
df %>% mutate(measure = if_else(topic == "Case rates", "case_rate", "death_rate"))
}

# Overall (one row per year/measure)
rates_overall <- data_raw %>%
filter(topic %in% rate_topics, viewby == "Overall") %>%
make_measure() %>%
mutate(age = "Overall", sex = "Overall", race_ethnicity = "Overall")

# Age-stratified (exclude the Overall row within Age viewby)
age_map <- c(
"<1 year old" = "<1 years",
"1 year old" = "1 year old",
"1 years old" = "1 year old",
"2-4 years old" = "2-4 years old",
"5-17 years old" = "5-17 years old",
"18-34 years old" = "18-34 years old",
"35-49 years old" = "35-49 years old",
"50-64 years old" = "50-64 years old",
"\u226565 years old" = "65+ years olds"
)
rates_age <- data_raw %>%
filter(topic %in% rate_topics, viewby == "Age", viewby2 %in% names(age_map)) %>%
make_measure() %>%
mutate(age = age_map[viewby2], sex = "Overall", race_ethnicity = "Overall")

# Sex-stratified (Male/Female only — Overall already covered above)
rates_sex <- data_raw %>%
filter(topic %in% rate_topics, viewby == "Sex", viewby2 %in% c("Male", "Female")) %>%
make_measure() %>%
mutate(age = "Overall", sex = viewby2, race_ethnicity = "Overall")

# Race-stratified (non-Overall values only)
race_map <- c("Black" = "Black", "White" = "White", "Other races" = "Other")
rates_race <- data_raw %>%
filter(topic %in% rate_topics, viewby == "Race", viewby2 %in% names(race_map)) %>%
make_measure() %>%
mutate(age = "Overall", sex = "Overall", race_ethnicity = race_map[viewby2])

data_rates <- bind_rows(rates_overall, rates_age, rates_sex, rates_race) %>%
mutate(measure = if_else(measure == "case_rate", "abcs_gas_rate_cases", "abcs_gas_rate_deaths")) %>%
select(geography, time, age, sex, race_ethnicity, measure, value)

# ---------------------------------------------------------------------------
# 2. Total case counts and deaths (national aggregate)
# ---------------------------------------------------------------------------
data_counts <- data_raw %>%
filter(
topic == "Number of cases and deaths",
viewby == "ALL"
) %>%
mutate(
measure = case_when(
viewby2 == "Total cases" ~ "abcs_gas_N_cases",
viewby2 == "Number of deaths" ~ "abcs_gas_N_deaths",
TRUE ~ NA_character_
),
age = "Overall",
sex = "Overall",
race_ethnicity = "Overall"
) %>%
filter(!is.na(measure)) %>%
# Source has duplicate 2023 "Total cases" entries; keep the larger (national estimate)
group_by(geography, time, measure) %>%
slice_max(value, n = 1, with_ties = FALSE) %>%
ungroup() %>%
select(geography, time, age, sex, race_ethnicity, measure, value)

data_main <- bind_rows(data_rates, data_counts) %>%
tidyr::pivot_wider(
id_cols = c(geography, time, age, sex, race_ethnicity),
names_from = measure,
values_from = value
)

vroom::vroom_write(data_main, "standard/data.csv.gz", delim = ",")

# ---------------------------------------------------------------------------
# 3. Syndromes (percent of cases by clinical presentation)
# ---------------------------------------------------------------------------
syndrome_name_map <- c(
"Cellulitis" = "cellulitis",
"Bacteremia without focus" = "bacteremia_without_focus",
"Pneumonia" = "pneumonia",
"Necrotizing fasciitis" = "necrotizing_fasciitis",
"Streptococcal toxic shock" = "strep_toxic_shock",
"Other" = "other"
)

data_syndromes <- data_raw %>%
filter(topic == "Syndromes", viewby %in% names(syndrome_name_map)) %>%
mutate(
measure = paste0("abcs_gas_pct_syndrome_", syndrome_name_map[viewby])
) %>%
select(geography, time, measure, value) %>%
tidyr::pivot_wider(names_from = measure, values_from = value)

vroom::vroom_write(data_syndromes, "standard/data_syndromes.csv.gz", delim = ",")

# ---------------------------------------------------------------------------
# 4. Antibiotic resistance (percent resistant / number of isolates)
# ---------------------------------------------------------------------------
antibiotics <- c(
"Penicillin", "Erythromycin", "Clindamycin**",
"Cefotaxime", "Tetracycline", "Vancomycin", "Number of isolates"
)

data_resistance <- data_raw %>%
filter(topic == "Antibiotic resistance", viewby %in% antibiotics) %>%
mutate(
drug = tolower(sub("\\*\\*$", "", viewby)),
measure = if_else(
viewby == "Number of isolates",
"abcs_gas_n_isolates",
paste0("abcs_gas_pct_resistant_", drug)
)
) %>%
select(geography, time, measure, value) %>%
tidyr::pivot_wider(names_from = measure, values_from = value)

vroom::vroom_write(data_resistance, "standard/data_resistance.csv.gz", delim = ",")

# ---------------------------------------------------------------------------
# 5. emm types (percent and counts of isolates by emm type)
# ---------------------------------------------------------------------------
data_emm <- data_raw %>%
filter(topic == "Emm types") %>%
mutate(
emm_clean = tolower(gsub("[^a-zA-Z0-9]", "_", viewby)),
measure = case_when(
units == "Percent" ~ paste0("abcs_gas_emm_pct_", emm_clean),
TRUE ~ paste0("abcs_gas_emm_count_", emm_clean)
)
) %>%
select(geography, time, measure, value) %>%
tidyr::pivot_wider(names_from = measure, values_from = value)

vroom::vroom_write(data_emm, "standard/data_emm.csv.gz", delim = ",")

# ---------------------------------------------------------------------------
# 6. Record processed state
# ---------------------------------------------------------------------------
process$raw_state <- raw_state
dcf::dcf_process_record(updated = process)
}
141 changes: 141 additions & 0 deletions data/abcs_gas/measure_info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
{
"case_rate": {
"id": "case_rate",
"short_name": "Invasive GAS case rate",
"long_name": "Invasive Group A Streptococcus case rate",
"category": "Bacterial diseases",
"short_description": "Incidence rate of invasive Group A Streptococcus disease per 100,000 population",
"long_description": "Annual incidence rate of invasive Group A Streptococcus (iGAS) disease per 100,000 population, from CDC Active Bacterial Core surveillance (ABCs). Rates are available by age group, sex, and race.",
"statement": "In {location}, the invasive GAS case rate was {value} per 100,000 population.",
"measure_type": "Rate",
"unit": "Per 100,000 population",
"time_resolution": "Year",
"sources": [{ "id": "abcs_gas" }],
"citations": []
},
"death_rate": {
"id": "death_rate",
"short_name": "Invasive GAS death rate",
"long_name": "Invasive Group A Streptococcus death rate",
"category": "Bacterial diseases",
"short_description": "Mortality rate from invasive Group A Streptococcus disease per 100,000 population",
"long_description": "Annual mortality rate from invasive Group A Streptococcus (iGAS) disease per 100,000 population, from CDC Active Bacterial Core surveillance (ABCs). Rates are available by age group, sex, and race.",
"statement": "In {location}, the invasive GAS death rate was {value} per 100,000 population.",
"measure_type": "Rate",
"unit": "Per 100,000 population",
"time_resolution": "Year",
"sources": [{ "id": "abcs_gas" }],
"citations": []
},
"n_cases": {
"id": "n_cases",
"short_name": "Invasive GAS case count",
"long_name": "Number of invasive Group A Streptococcus cases",
"category": "Bacterial diseases",
"short_description": "Total number of invasive Group A Streptococcus cases in the ABCs catchment area",
"long_description": "Annual count of invasive Group A Streptococcus (iGAS) disease cases in the CDC ABCs surveillance catchment area.",
"statement": "In {location}, {value} invasive GAS cases were reported.",
"measure_type": "Count",
"unit": "Count",
"time_resolution": "Year",
"sources": [{ "id": "abcs_gas" }],
"citations": []
},
"n_deaths": {
"id": "n_deaths",
"short_name": "Invasive GAS death count",
"long_name": "Number of deaths from invasive Group A Streptococcus",
"category": "Bacterial diseases",
"short_description": "Total number of deaths from invasive Group A Streptococcus in the ABCs catchment area",
"long_description": "Annual count of deaths from invasive Group A Streptococcus (iGAS) disease in the CDC ABCs surveillance catchment area.",
"statement": "In {location}, {value} deaths from invasive GAS were reported.",
"measure_type": "Count",
"unit": "Count",
"time_resolution": "Year",
"sources": [{ "id": "abcs_gas" }],
"citations": []
},
"n_survivals": {
"id": "n_survivals",
"short_name": "Invasive GAS survival count",
"long_name": "Number of survivors of invasive Group A Streptococcus",
"category": "Bacterial diseases",
"short_description": "Total number of survivors of invasive Group A Streptococcus in the ABCs catchment area",
"long_description": "Annual count of survivors of invasive Group A Streptococcus (iGAS) disease in the CDC ABCs surveillance catchment area.",
"statement": "In {location}, {value} people survived invasive GAS disease.",
"measure_type": "Count",
"unit": "Count",
"time_resolution": "Year",
"sources": [{ "id": "abcs_gas" }],
"citations": []
},
"syndrome": {
"id": "syndrome",
"short_name": "Clinical syndrome",
"long_name": "Clinical syndrome of invasive GAS case",
"category": "Bacterial diseases",
"short_description": "Percent of invasive GAS cases by clinical syndrome (cellulitis, STSS, necrotizing fasciitis, etc.)",
"long_description": "Annual distribution of clinical syndromes among invasive Group A Streptococcus cases. Syndromes include cellulitis, bacteremia without focus, pneumonia, necrotizing fasciitis, streptococcal toxic shock syndrome (STSS), and other.",
"statement": "",
"measure_type": "Percent",
"unit": "Percent",
"time_resolution": "Year",
"sources": [{ "id": "abcs_gas" }],
"citations": []
},
"pct_resistant": {
"id": "pct_resistant",
"short_name": "Antibiotic resistance (%)",
"long_name": "Percent of GAS isolates resistant to antibiotic",
"category": "Bacterial diseases",
"short_description": "Percent of invasive GAS isolates showing resistance to a given antibiotic",
"long_description": "Annual percent of invasive Group A Streptococcus isolates demonstrating non-susceptibility to antibiotics including penicillin, erythromycin, clindamycin, cefotaxime, tetracycline, and vancomycin. Data from CDC ABCs.",
"statement": "",
"measure_type": "Percent",
"unit": "Percent",
"time_resolution": "Year",
"sources": [{ "id": "abcs_gas" }],
"citations": []
},
"n_isolates": {
"id": "n_isolates",
"short_name": "Number of GAS isolates tested",
"long_name": "Number of invasive GAS isolates tested for antibiotic susceptibility",
"category": "Bacterial diseases",
"short_description": "Total number of invasive GAS isolates tested for antibiotic susceptibility",
"long_description": "Annual count of invasive Group A Streptococcus isolates submitted for antibiotic susceptibility testing in the CDC ABCs catchment area.",
"statement": "",
"measure_type": "Count",
"unit": "Count",
"time_resolution": "Year",
"sources": [{ "id": "abcs_gas" }],
"citations": []
},
"emm_type": {
"id": "emm_type",
"short_name": "emm type",
"long_name": "GAS emm type",
"category": "Bacterial diseases",
"short_description": "Distribution of GAS emm types among invasive isolates",
"long_description": "Annual distribution of emm types (surface protein gene sequence types) among invasive Group A Streptococcus isolates from the CDC ABCs catchment area. emm typing is used to track GAS strain diversity and vaccine coverage.",
"statement": "",
"measure_type": "Percent",
"unit": "Percent",
"time_resolution": "Year",
"sources": [{ "id": "abcs_gas" }],
"citations": []
},
"_sources": {
"abcs_gas": {
"name": "Active Bacterial Core surveillance (ABCs) - Group A Streptococcus",
"url": "https://data.cdc.gov/Public-Health-Surveillance/Active-Bacterial-Core-surveillance-ABCs-Group-A-St/9y49-tura/about_data",
"organization": "Centers for Disease Control and Prevention",
"organization_url": "https://www.cdc.gov",
"location": "Active Bacterial Core surveillance (ABCs) Group A Streptococcus data on data.cdc.gov",
"location_url": "https://data.cdc.gov/resource/9y49-tura/",
"date_accessed": 2025,
"description": "CDC monitors invasive bacterial infections through Active Bacterial Core surveillance (ABCs), a population-based surveillance program for invasive bacterial diseases in selected geographic areas of the United States. This dataset reports annual data on invasive Group A Streptococcus (iGAS) disease from 1997 onwards, including case and death rates by age group, sex, and race; clinical syndrome distribution (cellulitis, bacteremia without focus, pneumonia, necrotizing fasciitis, streptococcal toxic shock syndrome); antibiotic resistance patterns; and emm type distribution among isolates. ABCs catchment areas include California, Colorado, Connecticut, Georgia, Maryland, Minnesota, New York, Oregon, and Tennessee, representing approximately 10% of the US population. Incidence rates are calculated using U.S. Census Bureau population estimates for the respective catchment areas.",
"restrictions": "Public domain. CDC data is generally not subject to copyright restrictions."
}
}
}
33 changes: 33 additions & 0 deletions data/abcs_gas/process.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "abcs_gas",
"type": "source",
"scripts": [
{
"path": "ingest.R",
"manual": false,
"frequency": 0,
"last_run": "",
"run_time": "",
"last_status": {
"log": "",
"success": true
}
}
],
"checked": "2026-08-05 15:59:49",
"check_results": {
"data/abcs_gas/standard/data.csv.gz": {
"measures": ["missing_info: age", "missing_info: sex", "missing_info: race_ethnicity", "missing_info: abcs_gas_rate_cases", "missing_info: abcs_gas_rate_deaths", "missing_info: abcs_gas_N_cases", "missing_info: abcs_gas_N_deaths"]
},
"data/abcs_gas/standard/data_emm.csv.gz": {
"measures": ["missing_info: abcs_gas_emm_count_number_of_isolates", "missing_info: abcs_gas_emm_pct_other", "missing_info: abcs_gas_emm_pct_emm_1", "missing_info: abcs_gas_emm_pct_emm_11", "missing_info: abcs_gas_emm_pct_emm_12", "missing_info: abcs_gas_emm_pct_emm_28", "missing_info: abcs_gas_emm_pct_emm_43", "missing_info: abcs_gas_emm_pct_emm_59", "missing_info: abcs_gas_emm_pct_emm_77", "missing_info: abcs_gas_emm_pct_emm_82", "missing_info: abcs_gas_emm_pct_emm_83", "missing_info: abcs_gas_emm_pct_emm_89", "missing_info: abcs_gas_emm_pct_emm_92", "missing_info: abcs_gas_emm_pct_emm_49", "missing_info: abcs_gas_emm_pct_emm_81", "missing_info: abcs_gas_emm_pct_emm_60", "missing_info: abcs_gas_emm_pct_emm_91"]
},
"data/abcs_gas/standard/data_resistance.csv.gz": {
"measures": ["missing_info: abcs_gas_pct_resistant_cefotaxime", "missing_info: abcs_gas_pct_resistant_clindamycin", "missing_info: abcs_gas_pct_resistant_erythromycin", "missing_info: abcs_gas_pct_resistant_penicillin", "missing_info: abcs_gas_pct_resistant_tetracycline", "missing_info: abcs_gas_pct_resistant_vancomycin", "missing_info: abcs_gas_n_isolates"]
},
"data/abcs_gas/standard/data_syndromes.csv.gz": {
"measures": ["missing_info: abcs_gas_pct_syndrome_cellulitis", "missing_info: abcs_gas_pct_syndrome_bacteremia_without_focus", "missing_info: abcs_gas_pct_syndrome_pneumonia", "missing_info: abcs_gas_pct_syndrome_necrotizing_fasciitis", "missing_info: abcs_gas_pct_syndrome_strep_toxic_shock"]
}
},
"raw_state": 1747769158
}
Binary file added data/abcs_gas/raw/9y49-tura.csv.xz
Binary file not shown.
Loading