R Markdown Setup

To show all code please click “Show All Code” using the code button at the top right of the file.

Set Wrapping

knitr::opts_chunk$set(
  comment = "",
  tidy = TRUE,
  tidy.opts = list(width.cutoff = 80),
  width = 80
)

Set Encoding

# Set encoding: UTF-8
options(encoding = "UTF-8")
try(Sys.setlocale("LC_CTYPE", "en_US.UTF-8"), silent = TRUE)

[1] “en_US.UTF-8”

# Ensure chunk output is UTF-8
knitr::knit_hooks$set(output = function(x, options) enc2utf8(x))

Set Working Directory

# Set working directory to a filepath on computer
setwd('/Users/akthiersch/Desktop/Professional Applications/Job Interview Prep/The Joint Commission/Senior Healthcare Data Analyst/Assessment/Final')
# getwd()

Install Packages

# # Install packages to load necessary libraries
# # If needed, comment out to imporve R knitting performance
# options(repos = c(CRAN = "https://cloud.r-project.org/"))
# # Install Packages
# install.packages("tidyverse")
# install.packages("lubridate")
# install.packages("curl")
# install.packages("expss")
# install.packages("gt")
# install.packages("gtsummary")
# install.packages("maps")
# install.packages("usmap")
# install.packages("viridis")
# install.packages("ggrepel")
# # install.packages("cowplot")
# install.packages("statebins)
# install.packages("rmarkdown)

Install Libraries

# Install Libraries
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   4.0.0     ✔ tibble    3.2.1
✔ lubridate 1.9.4     ✔ tidyr     1.3.1
✔ purrr     1.0.4     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(lubridate)
library(curl)
Using libcurl 8.14.1 with LibreSSL/3.3.6 

Attaching package: 'curl'

The following object is masked from 'package:readr':

    parse_date
library(expss)
Loading required package: maditr

To select columns from data: columns(mtcars, mpg, vs:carb)


Attaching package: 'maditr'

The following objects are masked from 'package:dplyr':

    between, coalesce, first, last

The following object is masked from 'package:purrr':

    transpose

The following object is masked from 'package:readr':

    cols


Attaching package: 'expss'

The following objects are masked from 'package:stringr':

    fixed, regex

The following objects are masked from 'package:dplyr':

    compute, contains, na_if, recode, vars, where

The following objects are masked from 'package:purrr':

    keep, modify, modify_if, when

The following objects are masked from 'package:tidyr':

    contains, nest

The following object is masked from 'package:ggplot2':

    vars
library(gt)

Attaching package: 'gt'

The following objects are masked from 'package:expss':

    contains, gt, tab_caption, vars, where
library(gtsummary)

Attaching package: 'gtsummary'

The following objects are masked from 'package:expss':

    contains, vars, where
library(maps)

Attaching package: 'maps'

The following object is masked from 'package:purrr':

    map
library(usmap)
library(viridis)
Loading required package: viridisLite

Attaching package: 'viridis'

The following object is masked from 'package:maps':

    unemp
library(ggrepel)
# library(cowplot)
library(grid)
library(gridExtra)

Attaching package: 'gridExtra'

The following object is masked from 'package:dplyr':

    combine
library(statebins)
library(rmarkdown)

Exercise Questions

Question 1

Import FY24 Medicare Advantage (MA) Penetration Data

Create data import function

# ---- CMS Medicare Advantage (MA) Penetration Data Import Function ----

# ---- Function: download_with_retry ----
# Purpose: Allow multiple url download attempts
# Parameters:
#   url: website address of file to download
#   dest: destination file path
#   tries: number of download tries
 download_with_retry <- function(url, dest, tries = 5) {
  # Create connection handle
   h <- curl::new_handle()
  # Configure handle set to HTTP version 1.1 (1L) and user agent string
  curl::handle_setopt(h, http_version = 1L, useragent = "R curl/MA-pen-fetcher")
  # Set loop tp run through number of tries
  for (i in seq_len(tries)) {
    # Download attempt
    ok <- try({
      curl::curl_download(
                          # File website url
                          url, 
                          # File path destination
                          destfile = dest,
                          # Handle configuration
                          handle = h, 
                          # Suppress messages
                          quiet = TRUE)
      # TRUE if file successfully downloads
      TRUE
    }, silent = TRUE)
    # Checks if download worked
    if (isTRUE(ok)) return(invisible(dest))
    # Download cool down time, wait before retrying
    Sys.sleep(1.5 * i)
  }
  # Download fail error message
  stop("Failed to download after ", tries, " attempts: ", url)
}

# ---- Function: cms_ma_penetration_import ----
# Purpose: Import CSM Medicare Advantage (MA) Penetration files give a date range
# Parameters:
#   start_date = "YYYY-MM-DD"
#   end_date = "YYYY-MM-DD"
cms_ma_penetration_import <- function(start_date, end_date) {
  # Parse and normalize dates 
  .parse_ym <- function(x) {
    # Force dates to be character datatype
    x <- as.character(x)
    # Keep only "YYYY-MM"
    ym <- sub("^([0-9]{4}-[0-9]{2}).*$", "\\1", x)
    # Convert date to "YYYY-MM-01"
    ymd(paste0(ym, "-01"), quiet = TRUE)
  }
  # Set first month to download
  start <- .parse_ym(start_date)
  # Set last month to download
  end <- .parse_ym(end_date)
  # Error message if could not parse date formatting
  if (any(is.na(c(start, end)))) stop("Could not parse dates; use 'YYYY-MM' or 'YYYY-MM-DD'.")
  # Error message if start_data is large than end_date
  if (start > end) stop("start_date must be <= end_date.")
  
  # Generate monthly sequence based on first and last month
  months_seq <- seq.Date(floor_date(start, "month"), floor_date(end, "month"), by = "month")
  # Create temp directory for downloaded files
  td  <- tempdir()
  # Create list to hold dataframe for each month 
  out <- vector("list", length(months_seq))
  # Generate list of month abbreviations
  abbr <- c("jan","feb","mar","apr","may","jun","jul","aug","sept","oct","nov","dec")

  # Set loop to iterate through month sequence
  for (i in seq_along(months_seq)) {
    # Current month
    d <- months_seq[i]
    # Month number
    m <- lubridate::month(d)
    # Current year
    y <- lubridate::year(d)
    # Lowercase month name
    m_full <- tolower(month.name[m])
    # Month abbreviation
    m_abbr <- abbr[m]
    # Month number
    mm <- sprintf("%02d", m)

    # ---- List of possible CMS MA Penetration URL Formats ----
    # More url formats could be added for older formats
    urls <- c(
      # 1. Numeric month name year format (september-2025 etc.)
      sprintf("https://www.cms.gov/files/zip/ma-state/county-penetration-%s-%d.zip",
              m_full, y),
      # 2. Abbreviated month format (apr, aug, sept, etc.)
      sprintf(paste0("https://www.cms.gov/research-statistics-data-and-systems/",
                     "statistics-trends-and-reports/mcradvpartdenroldata/downloads/",
                     "%d/%s/state-county-penetration-ma-%d-%s.zip"),
              y, m_abbr, y, mm),
      # 3. Numeric month year format (01–12 etc.)
      sprintf(paste0("https://www.cms.gov/research-statistics-data-and-systems/",
                     "statistics-trends-and-reports/mcradvpartdenroldata/downloads/",
                     "%d/%02d/state-county-penetration-ma-%d-%s.zip"),
              y, m, y, mm),
      # 4. Full-month name format (august, december, etc.)
      sprintf(paste0("https://www.cms.gov/research-statistics-data-and-systems/",
                     "statistics-trends-and-reports/mcradvpartdenroldata/downloads/",
                     "%d/%s/state-county-penetration-ma-%d-%s.zip"),
              y, m_full, y, mm)
    )
    
    # Set filepath to save downloaded zipfile
    zf <- file.path(td, sprintf("ma_%d_%02d.zip", y, m))
    # Message to print when trying downloads
    message("Trying downloads for ", format(d, "%B %Y"), "...")
    # Set loop to try downloads for each url format
    success <- FALSE
    for (u in urls) {
      message("  ", u)
      ok <- tryCatch({
        # download_with_retry function for multiple download attempts
        download_with_retry(u, zf)
        TRUE
      }, error = function(e) FALSE)
      # Check zipfile size > 5 KB
      if (ok && file.exists(zf) && file.info(zf)$size > 5000) {
        # Message print when file successfully downloaded
        success <- TRUE
        message(" Success: ", basename(zf))
        break
      }
    }
    # Message print if no file is downloaded
    if (!success) {
      message("  No valid file found for ", format(d, "%B %Y"))
      next
    }

    # Extract and read data file data
    # List file contents
    listing <- try(utils::unzip(zf, list = TRUE), silent = TRUE)
    if (inherits(listing, "try-error")) next
    # Select file extension type
    pick <- listing$Name[grepl("\\.(csv|xlsx?)$", tolower(listing$Name))][1]
    if (is.na(pick)) next
    # Extract data from zip file and send to tempdir
    f <- utils::unzip(zf, files = pick, exdir = td, overwrite = TRUE)[1]
    ext <- tools::file_ext(f)
    
    # Read file into dataframe
    df <- if (tolower(ext) == "csv") {
      # Ensure propr encoding: UTF-8
      readr::read_csv(f, locale = locale(encoding = "UTF-8"), show_col_types = FALSE)
      # xlxs option
    } else {
      readxl::read_excel(f)
    }
    # Insert report year into dataframe
    df$report_year <- y
    # Insert report month into dataframe
    df$report_month <- m
    # Store output list
    out[[i]] <- df
  }
  # Bind rows together
  dplyr::bind_rows(Filter(Negate(is.null), out))
}

Import FY24 MA Penetration Data

# Import CMS Medicare Advantage (MA) penetration data for Fiscal Year 2024 (FY24)
# If needed, comment out import function to improve R Markdown knitting performance
# Last Import: 10/30/2025
df.ma_penetration_FY24_RAW <- data.frame(cms_ma_penetration_import('2023-10-01', '2024-09-30'))
Trying downloads for October 2023...
  https://www.cms.gov/files/zip/ma-state/county-penetration-october-2023.zip
 Success: ma_2023_10.zip
Trying downloads for November 2023...
  https://www.cms.gov/files/zip/ma-state/county-penetration-november-2023.zip
 Success: ma_2023_11.zip
Trying downloads for December 2023...
  https://www.cms.gov/files/zip/ma-state/county-penetration-december-2023.zip
 Success: ma_2023_12.zip
Trying downloads for January 2024...
  https://www.cms.gov/files/zip/ma-state/county-penetration-january-2024.zip
 Success: ma_2024_01.zip
Trying downloads for February 2024...
  https://www.cms.gov/files/zip/ma-state/county-penetration-february-2024.zip
 Success: ma_2024_02.zip
Trying downloads for March 2024...
  https://www.cms.gov/files/zip/ma-state/county-penetration-march-2024.zip
 Success: ma_2024_03.zip
Trying downloads for April 2024...
  https://www.cms.gov/files/zip/ma-state/county-penetration-april-2024.zip
 Success: ma_2024_04.zip
Trying downloads for May 2024...
  https://www.cms.gov/files/zip/ma-state/county-penetration-may-2024.zip
 Success: ma_2024_05.zip
Trying downloads for June 2024...
  https://www.cms.gov/files/zip/ma-state/county-penetration-june-2024.zip
 Success: ma_2024_06.zip
Trying downloads for July 2024...
  https://www.cms.gov/files/zip/ma-state/county-penetration-july-2024.zip
 Success: ma_2024_07.zip
Trying downloads for August 2024...
  https://www.cms.gov/files/zip/ma-state/county-penetration-august-2024.zip
 Success: ma_2024_08.zip
Trying downloads for September 2024...
  https://www.cms.gov/files/zip/ma-state/county-penetration-september-2024.zip
 Success: ma_2024_09.zip
# Export dataframe
write_csv(df.ma_penetration_FY24_RAW, "df.ma_penetration_FY24_RAW.csv")

# Read in dataframe
# df.ma_penetration_FY24_RAW <- read_csv("df.ma_penetration_FY24_RAW.csv")

# View characteristics of dataframe
# glimpse(df.ma_penetration_FY24_RAW)
paged_table(df.ma_penetration_FY24_RAW)
# head(df.ma_penetration_FY24_RAW)

Question 2

Calculate FY16 Average Percent Penetration per State by Month

Import FY16 MA Penetration Data

# Import CMS Medicare Advantage (MA) penetration data for Fiscal Year 2016 (FY16)
# If needed, comment out import function to improve R Markdown knitting performace
# Last Import: 10/30/2025
df.ma_penetration_FY16_RAW <- data.frame(cms_ma_penetration_import('2015-10-01', '2016-09-30'))
Trying downloads for October 2015...
  https://www.cms.gov/files/zip/ma-state/county-penetration-october-2015.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2015/oct/state-county-penetration-ma-2015-10.zip
 Success: ma_2015_10.zip
Trying downloads for November 2015...
  https://www.cms.gov/files/zip/ma-state/county-penetration-november-2015.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2015/nov/state-county-penetration-ma-2015-11.zip
 Success: ma_2015_11.zip
Trying downloads for December 2015...
  https://www.cms.gov/files/zip/ma-state/county-penetration-december-2015.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2015/dec/state-county-penetration-ma-2015-12.zip
 Success: ma_2015_12.zip
Trying downloads for January 2016...
  https://www.cms.gov/files/zip/ma-state/county-penetration-january-2016.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/jan/state-county-penetration-ma-2016-01.zip
 Success: ma_2016_01.zip
Trying downloads for February 2016...
  https://www.cms.gov/files/zip/ma-state/county-penetration-february-2016.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/feb/state-county-penetration-ma-2016-02.zip
 Success: ma_2016_02.zip
Trying downloads for March 2016...
  https://www.cms.gov/files/zip/ma-state/county-penetration-march-2016.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/mar/state-county-penetration-ma-2016-03.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/03/state-county-penetration-ma-2016-03.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/march/state-county-penetration-ma-2016-03.zip
 Success: ma_2016_03.zip
Trying downloads for April 2016...
  https://www.cms.gov/files/zip/ma-state/county-penetration-april-2016.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/apr/state-county-penetration-ma-2016-04.zip
 Success: ma_2016_04.zip
Trying downloads for May 2016...
  https://www.cms.gov/files/zip/ma-state/county-penetration-may-2016.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/may/state-county-penetration-ma-2016-05.zip
 Success: ma_2016_05.zip
Trying downloads for June 2016...
  https://www.cms.gov/files/zip/ma-state/county-penetration-june-2016.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/jun/state-county-penetration-ma-2016-06.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/06/state-county-penetration-ma-2016-06.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/june/state-county-penetration-ma-2016-06.zip
 Success: ma_2016_06.zip
Trying downloads for July 2016...
  https://www.cms.gov/files/zip/ma-state/county-penetration-july-2016.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/jul/state-county-penetration-ma-2016-07.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/07/state-county-penetration-ma-2016-07.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/july/state-county-penetration-ma-2016-07.zip
 Success: ma_2016_07.zip
Trying downloads for August 2016...
  https://www.cms.gov/files/zip/ma-state/county-penetration-august-2016.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/aug/state-county-penetration-ma-2016-08.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/08/state-county-penetration-ma-2016-08.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/august/state-county-penetration-ma-2016-08.zip
 Success: ma_2016_08.zip
Trying downloads for September 2016...
  https://www.cms.gov/files/zip/ma-state/county-penetration-september-2016.zip
  https://www.cms.gov/research-statistics-data-and-systems/statistics-trends-and-reports/mcradvpartdenroldata/downloads/2016/sept/state-county-penetration-ma-2016-09.zip
 Success: ma_2016_09.zip
# Export dataframe
write_csv(df.ma_penetration_FY16_RAW, "df.ma_penetration_FY16_RAW.csv")

# Read in dataframe
# df.ma_penetration_FY16_RAW <- read_csv("df.ma_penetration_FY16_RAW.csv")

# View dataframe
# glimpse(df.ma_penetration_FY16_RAW)
paged_table(df.ma_penetration_FY16_RAW)
# head(df.ma_penetration_FY16_RAW)

Clean FY16 Percent Penetration Data

# Modify RAW data
df.ma_penetration_FY16_mod <- df.ma_penetration_FY16_RAW |>
  # Remove % symbol and convert Penetration to numeric
  mutate(
    Penetration = as.numeric(gsub("[^0-9\\.]", "", Penetration))
  ) |>
  # Create month abbreviations variable
  mutate(
    report_month_text = month.abb[report_month], 
  # Create factored month text variable
    report_month_text = factor(report_month_text,                   
                               levels = month.abb, ordered = TRUE)
  ) |>
  # Factor State and County names
  mutate(across(c(State.Name, County.Name), as.factor)) |>
  # Standardize District of Columbia name format for State.Name
  mutate(State.Name = case_when(State.Name == "Washington D.C." ~ "District of Columbia",
                                State.Name == "District Of Columbia" ~ "District of Columbia",
                                TRUE ~ State.Name))

Calculate Average Percent Penetration

# TABLE 1: Mean penetration (%) by month per State (FY16)
# Subset for relevant variables
df.ma_penetration_FY16_tbl1 <- df.ma_penetration_FY16_mod |>
  filter(!State.Name %in% c("Pending State Designation", "American Samoa", "Guam", "Northern Mariana Islands", "Puerto Rico", "Virgin Islands", "Wake Island")) |>
  filter(!County.Name %in% c("Pending County Designation")) |>
  subset(select = c(State.Name, Penetration, report_month_text))

# Calculate mean penetration (%) by per State by Month
tbl1_ma_penetration <- df.ma_penetration_FY16_tbl1 |>
  group_by(State.Name, report_month_text) |>
  summarize(
    mean_pen = mean(Penetration, na.rm = TRUE),
    .groups  = "drop"
  ) |>
  # Pivot data long to wide
  select(State.Name, report_month_text, mean_pen) |>
  pivot_wider(names_from = report_month_text, values_from = mean_pen)|>
  arrange(State.Name)

# View characteristics of dataframe
# glimpse(tbl1_ma_penetration)

# Calculate total month means for all states
month_means <- df.ma_penetration_FY16_tbl1 |>
  group_by(report_month_text) |>
  summarize(
    mean_pen = mean(Penetration, na.rm = TRUE),
    .groups  = "drop"
  ) |> 
  mutate(State.Name = "All States") |>
  # Pivot data long to wind
  pivot_wider(names_from = report_month_text, values_from = mean_pen)|>
  arrange(State.Name)

# View characteristics of dataframe
# glimpse(month_means)

# Bind rows to create combined dataframe
tbl1_ma_penetration_all <- bind_rows(tbl1_ma_penetration, month_means)

# glimpse(tbl1_ma_penetration_all)
paged_table(tbl1_ma_penetration_all)
# If needed, mean calculations per state
# state_means <- df.ma_penetration_FY16_tbl1 |>
#   group_by(State.Name) |>
#   summarize(
#     mean_pen = mean(Penetration, na.rm = TRUE),
#     .groups  = "drop"
#   )
# 
# glimpse(state_means)

Table 1. Mean MA Percent Penetration (FY16)

# Construct gt table
gt_tbl1 <- gt::gt(tbl1_ma_penetration_all, rowname_col = "State.Name") |>
  tab_stubhead(label = "State") |>
    # Format table numbers
    gt::fmt_number(
    decimals = 1,
    pattern = "{x}%"
  ) |>
  # Format missing numbers
  gt::sub_missing(columns = everything(), missing_text = "-") |>
  # Set titles
  gt::tab_header(title = gt::md("**Table 1. Mean MA Percent Penetration (%) per State by Month (FY16)**"),
                 subtitle = gt::md("October 1<sup>st</sup>, 2014 - September 30<sup>th</sup>, 2016")) |>
  # Format column spanner title
    gt::tab_spanner(
    label = "Months",
    columns = 2:13) |>
  # Format rows
  gt::cols_label(State.Name = gt::md("**State**")) |>
  gt::tab_options(
    table.font.size = "small",
    data_row.padding = gt::px(3),
    heading.align = "left"
  ) |>
  # Format table body
  gt::tab_options(
    table.font.size = gt::px(11),
    data_row.padding = gt::px(2),
    table.font.color = "black",
    table.border.top.color = "black",
    table.border.top.width = gt::px(1),
    table.border.bottom.color = "black",
    table.border.bottom.width = gt::px(1),
    column_labels.font.weight = "bold",
    column_labels.border.bottom.color = "black",
    column_labels.border.bottom.width = gt::px(1),
    column_labels.border.top.color = "black",
    column_labels.border.top.width = gt::px(1),
    heading.align = "center",
    heading.background.color = "white",
    heading.title.font.weight = "bold",
    table.align = "center"
  ) |>
  # Format font
  gt::opt_table_font(
    font = list(
      gt::system_fonts(name = "old-style"),
      gt::default_fonts()
    )
  )|>
  # Format lines - thin gray lines between rows (no shading)
  gt::tab_style(
    style = list(gt::cell_borders(sides = "bottom", color = "#bfbfbf", weight = gt::px(0.5))),
    locations = gt::cells_body(rows = everything())) |>
  # Format final row
   gt::tab_style(
    style = gt::cell_text(weight = "bold"),
    locations = gt::cells_body(rows = State.Name == "All States")
  ) |>
  gt::tab_style(
    style = list(gt::cell_text(weight = "bold")),
    locations = gt::cells_stub(rows = State.Name == "All States")) |>
  # Format alignment
  gt::cols_align(align = "left", columns = State.Name) |>
  gt::cols_align(align = "center", columns = -State.Name) |>
  # Format Notes and Source
  gt::tab_source_note(
    gt::md("**_Note:_** The calculations above do not contain data from American Samoa, Guam, Northern Mariana Islands, Puerto Rico, Virgin Islands, Wake Island, Pending State Designation, or Pending County Designation.<br> 
            **_Source:_** Centers for Medicare & Medicaid Services, *Medicare Advantage/Part D Contract and Enrollment Data: MA State/County Penetration*, https://www.cms.gov/data-research/statistics-trends-and-reports/medicare-advantagepart-d-contract-and-enrollment-data/ma-state/county-penetration (accessed October 26, 2025).")
  )

gt_tbl1
Table 1. Mean MA Percent Penetration (%) per State by Month (FY16)
October 1st, 2014 - September 30th, 2016
State
Months
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Alabama 20.0% 20.4% 20.2% 20.3% 20.2% 20.3% 20.4% 20.3% 20.3% 19.4% 19.4% 19.5%
Alaska 0.5% 0.5% 0.5% 0.5% 0.4% 0.4% 0.4% 0.4% 0.5% 0.5% 0.5% 0.5%
Arizona 26.7% 26.9% 26.8% 26.9% 26.8% 26.7% 26.8% 26.7% 26.7% 26.6% 26.6% 26.5%
Arkansas 19.2% 19.3% 19.1% 19.1% 19.1% 19.1% 19.1% 19.1% 19.1% 18.6% 18.6% 18.6%
California 21.6% 21.8% 21.9% 22.0% 21.9% 21.9% 21.7% 21.6% 21.5% 20.8% 20.8% 20.8%
Colorado 19.1% 19.2% 18.9% 18.7% 18.6% 18.6% 18.7% 18.5% 18.5% 19.6% 19.5% 19.5%
Connecticut 24.8% 25.0% 25.0% 25.2% 25.1% 25.2% 25.4% 25.4% 25.4% 24.5% 24.5% 24.5%
Delaware 8.6% 9.1% 9.0% 9.0% 8.9% 8.9% 8.9% 8.9% 8.9% 7.6% 7.6% 7.6%
District of Columbia 13.7% 13.9% 13.8% 14.0% 14.1% 14.2% 14.3% 14.4% 14.5% 13.3% 13.4% 13.4%
Florida 31.6% 31.8% 31.5% 31.7% 31.6% 31.7% 31.8% 31.7% 31.8% 30.8% 30.8% 30.8%
Georgia 31.6% 31.9% 31.5% 31.7% 31.6% 31.6% 31.8% 31.7% 31.8% 30.5% 30.5% 30.5%
Hawaii 42.8% 43.0% 42.9% 43.2% 42.9% 42.9% 43.0% 42.8% 42.8% 43.6% 43.5% 43.5%
Idaho 20.0% 20.4% 20.3% 20.3% 20.2% 20.2% 20.2% 20.1% 20.1% 22.2% 22.3% 22.2%
Illinois 18.7% 19.3% 19.1% 19.2% 19.1% 19.0% 19.0% 19.0% 18.9% 18.3% 18.3% 18.2%
Indiana 21.7% 22.5% 22.3% 22.4% 22.3% 22.3% 22.4% 22.5% 22.5% 21.9% 21.9% 21.9%
Iowa 10.6% 12.3% 12.1% 12.1% 12.0% 12.0% 12.1% 12.0% 12.0% 10.5% 10.5% 10.3%
Kansas 5.8% 6.1% 6.1% 6.1% 6.1% 6.1% 6.2% 6.1% 6.1% 5.5% 5.5% 5.5%
Kentucky 25.2% 25.6% 25.4% 25.5% 25.4% 25.4% 25.6% 25.5% 25.5% 24.6% 24.6% 24.6%
Louisiana 24.9% 25.1% 24.9% 25.0% 24.9% 24.9% 25.1% 25.0% 25.0% 24.0% 24.1% 24.1%
Maine 22.2% 22.6% 22.6% 22.8% 22.8% 23.0% 23.2% 23.2% 23.4% 21.6% 21.7% 21.7%
Maryland 6.0% 6.4% 6.4% 6.4% 6.4% 6.4% 6.5% 6.5% 6.5% 5.2% 5.2% 5.2%
Massachusetts 16.7% 16.8% 16.7% 16.7% 16.7% 16.7% 16.8% 16.8% 16.8% 16.3% 16.3% 16.2%
Michigan 30.4% 30.8% 30.5% 30.6% 30.5% 30.7% 30.9% 30.8% 30.9% 30.1% 30.1% 30.0%
Minnesota 52.8% 53.3% 52.7% 52.9% 52.8% 52.8% 53.2% 53.0% 53.1% 51.6% 51.7% 51.7%
Mississippi 12.8% 12.9% 12.8% 12.9% 12.9% 13.0% 13.0% 13.0% 13.0% 12.2% 12.2% 12.2%
Missouri 19.4% 20.0% 19.8% 19.9% 19.8% 19.9% 20.0% 20.0% 20.0% 18.9% 18.9% 18.9%
Montana 14.1% 14.4% 14.4% 14.4% 14.3% 14.3% 14.4% 14.4% 14.4% 13.6% 13.6% 13.6%
Nebraska 8.6% 8.7% 8.4% 8.4% 8.4% 8.3% 8.3% 8.3% 8.2% 8.4% 8.4% 8.3%
Nevada 15.1% 14.4% 14.4% 14.4% 14.4% 14.3% 15.2% 15.1% 15.2% 14.5% 13.5% 14.5%
New Hampshire 6.3% 6.5% 6.5% 6.5% 6.5% 6.5% 6.6% 6.6% 6.7% 5.7% 5.7% 5.8%
New Jersey 14.9% 15.1% 14.9% 15.0% 15.0% 15.0% 15.1% 15.1% 15.2% 13.9% 14.0% 13.9%
New Mexico 19.7% 20.0% 19.9% 20.0% 20.0% 20.0% 20.1% 20.0% 20.1% 20.4% 20.4% 20.3%
New York 35.6% 36.1% 35.9% 36.1% 36.0% 36.1% 36.2% 36.1% 36.2% 35.4% 35.5% 35.4%
North Carolina 25.7% 26.1% 26.0% 26.1% 26.0% 26.0% 26.1% 26.0% 26.0% 25.4% 25.4% 25.4%
North Dakota 16.6% 17.2% 17.4% 17.6% 17.6% 17.6% 17.9% 17.8% 18.1% 16.7% 16.7% 16.8%
Ohio 32.4% 31.4% 31.1% 31.2% 31.1% 31.0% 31.2% 31.1% 31.0% 35.7% 35.6% 35.5%
Oklahoma 9.8% 9.9% 9.7% 9.7% 9.6% 9.7% 9.6% 9.7% 9.5% 9.3% 9.3% 9.3%
Oregon 27.6% 28.0% 27.6% 27.7% 27.5% 27.5% 27.6% 27.4% 27.4% 27.8% 27.7% 27.7%
Pennsylvania 37.7% 37.8% 37.4% 37.5% 37.4% 37.4% 37.5% 37.4% 37.4% 37.4% 37.4% 37.4%
Rhode Island 34.3% 34.4% 34.2% 34.3% 34.2% 34.1% 34.3% 34.2% 34.3% 33.8% 33.8% 33.8%
South Carolina 24.9% 25.0% 24.8% 25.5% 25.3% 25.3% 26.5% 26.0% 25.9% 24.2% 24.2% 24.2%
South Dakota 19.3% 17.7% 17.3% 17.7% 17.8% 17.9% 18.1% 18.1% 18.2% 15.6% 18.6% 18.5%
Tennessee 31.9% 32.4% 32.1% 32.2% 32.1% 32.1% 32.3% 32.3% 32.3% 31.0% 31.0% 31.0%
Texas 23.0% 23.3% 23.0% 23.1% 23.0% 23.0% 23.1% 23.1% 23.1% 22.2% 22.2% 22.2%
Utah 19.0% 19.3% 19.1% 19.2% 19.2% 19.2% 19.2% 19.2% 19.1% 19.4% 19.4% 19.4%
Vermont 7.4% 7.5% 7.5% 7.5% 7.5% 7.5% 7.5% 7.4% 7.4% 7.2% 7.2% 7.2%
Virginia 18.0% 45.0% 17.9% 17.9% 17.8% 17.8% 17.9% 17.8% 17.8% 17.8% 17.7% 17.7%
Washington 17.0% 17.2% 17.1% 17.2% 17.1% 17.1% 17.2% 17.1% 17.1% 18.4% 18.4% 18.4%
West Virginia 27.2% 27.3% 26.9% 27.0% 26.8% 26.7% 26.8% 26.7% 26.7% 26.2% 26.1% 26.1%
Wisconsin 36.3% 37.0% 36.5% 36.7% 36.5% 36.4% 36.6% 36.4% 36.4% 36.3% 36.3% 36.2%
Wyoming 3.2% 3.2% 3.2% 3.2% 3.2% 3.2% 3.2% 3.1% 3.1% 3.2% 3.2% 3.2%
All States 22.9% 24.4% 23.0% 23.1% 23.0% 23.0% 23.1% 23.1% 23.1% 22.5% 22.6% 22.6%
Note: The calculations above do not contain data from American Samoa, Guam, Northern Mariana Islands, Puerto Rico, Virgin Islands, Wake Island, Pending State Designation, or Pending County Designation.
Source: Centers for Medicare & Medicaid Services, Medicare Advantage/Part D Contract and Enrollment Data: MA State/County Penetration, https://www.cms.gov/data-research/statistics-trends-and-reports/medicare-advantagepart-d-contract-and-enrollment-data/ma-state/county-penetration (accessed October 26, 2025).
# Export table
gt::gtsave(gt_tbl1, filename = "gt_tbl1.png")
file:////var/folders/kz/p2v973zn3tvby5f6_bzbrk9m0000gn/T//RtmpF7yEH3/file31471a284d4e.html screenshot completed

Question 3

FY16 Percent Penetration Summary Statistics

Calculate Summary Statistics

# TABLE 2: Summary Statistics 
# Subset for relevant variables
df.ma_penetration_FY16_tbl2 <- df.ma_penetration_FY16_mod |>
  # Remove non-states
  filter(!State.Name %in% c("Pending State Designation", "American Samoa", "Guam", "Northern Mariana Islands", "Puerto Rico", "Virgin Islands", "Wake Island")) |>
  # Remove non-counties
  filter(!County.Name %in% c("Pending County Designation")) |>
  subset(select = c(State.Name, Penetration, report_month_text))


# TABLE 2: Summary Statistics of Medicare Advantage Penetration by State
# Calculate summary statistics
tbl2_ma_penetration <- df.ma_penetration_FY16_tbl2 |>
  group_by(State.Name) |>
  summarize(
    N = n(),  
    missing = sum(is.na(Penetration)),
    mean_pen = mean(Penetration, na.rm = TRUE),
    sd_pen = sd(Penetration, na.rm = TRUE),
    min_pen = min(Penetration, na.rm = TRUE),
    p25_pen = quantile(Penetration, 0.25, na.rm = TRUE),
    p50_pen = quantile(Penetration, 0.50, na.rm = TRUE),
    p75_pen = quantile(Penetration, 0.75, na.rm = TRUE),
    max_pen = max(Penetration, na.rm = TRUE),
    .groups = "drop"
  ) |>
  # Remove -inf errors
  mutate(across(where(is.numeric), ~ ifelse(!is.finite(.x), NA, .x))) 

# Calculate summary statistics for all states
tbl2_allstates <- df.ma_penetration_FY16_mod %>%
  summarize(
    State.Name = "All States",
    N = n(),
    missing = sum(is.na(Penetration)),
    mean_pen = mean(Penetration, na.rm = TRUE),
    sd_pen = sd(Penetration, na.rm = TRUE),
    min_pen = min(Penetration, na.rm = TRUE),
    p25_pen = quantile(Penetration, 0.25, na.rm = TRUE),
    p50_pen = quantile(Penetration, 0.50, na.rm = TRUE),
    p75_pen = quantile(Penetration, 0.75, na.rm = TRUE),
    max_pen = max(Penetration, na.rm = TRUE)
  )

# Combine dataframes
tbl2_ma_penatration_allstates <- bind_rows(tbl2_ma_penetration, tbl2_allstates)

# View characteristic of dataframe
# glimpse(tbl2_ma_penatration_allstates)
paged_table(tbl2_ma_penatration_allstates)

Table 2. MA Percent Penetration Summary Statistics (FY16)

# Construct gt table
gt_tbl2 <- gt::gt(tbl2_ma_penatration_allstates, rowname_col = "State.Name") |>
  tab_stubhead(label = "State") |>
  # Format numbers
  gt::fmt_number(
    columns = c(mean_pen, sd_pen, min_pen, p25_pen, p50_pen, p75_pen, max_pen),
    decimals = 2,
    use_seps = TRUE,
    pattern = "{x}%"
  ) |>
  # Format numbers
  gt::fmt_number(
    columns = c(N, missing),
    decimals = 0,
    use_seps = TRUE) |>
  # Format missing numbers
  gt::sub_missing(columns = everything(), missing_text = "-") |>
  # Format titles
  gt::tab_header(
    title = gt::md("**Table 2. Summary Statistics of MA Percent Penetration (%) by State (FY16)**"),
    subtitle = gt::md("October 1<sup>st</sup>, 2014 - September 30<sup>th</sup>, 2016")) |>
  # Format column spanner label
  gt::tab_spanner(
    label = "Summary Statistics",
    columns = 2:10) |>
  # Format columns
  gt::cols_label(
    State.Name = gt::md("**State**"),
    N = gt::md("**N**"),
    missing = gt::md("**Missing**"),
    mean_pen = gt::md("**Mean**"),
    sd_pen = gt::md("**SD**"),
    min_pen = gt::md("**Min**"),
    p25_pen = gt::md("**P25**"),
    p50_pen = gt::md("**P50**"),
    p75_pen = gt::md("**P75**"),
    max_pen = gt::md("**Max**")
  ) |>
  # Format table body
  gt::tab_options(
    table.font.size = gt::px(11),
    data_row.padding = gt::px(2),
    table.font.color = "black",
    table.border.top.color = "black",
    table.border.top.width = gt::px(1),
    table.border.bottom.color = "black",
    table.border.bottom.width = gt::px(1),
    column_labels.font.weight = "bold",
    column_labels.border.bottom.color = "black",
    column_labels.border.bottom.width = gt::px(1),
    column_labels.border.top.color = "black",
    column_labels.border.top.width = gt::px(1),
    heading.align = "center",
    heading.background.color = "white",
    heading.title.font.weight = "bold",
    table.align = "center"
  ) |>
  # Format Font
  gt::opt_table_font(
    font = list(
      gt::system_fonts(name = "old-style"),
      gt::default_fonts()
    )
  ) |>
  # Format lines - thin gray lines between rows (no shading)
  gt::tab_style(
    style = list(gt::cell_borders(sides = "bottom", color = "#bfbfbf", weight = gt::px(0.5))),
    locations = gt::cells_body(rows = everything())
  ) |>
  # Format final row
   gt::tab_style(
    style = gt::cell_text(weight = "bold"),
    locations = gt::cells_body(rows = State.Name == "All States")
  ) |>
  gt::tab_style(
    style = list(gt::cell_text(weight = "bold")),
    locations = gt::cells_stub(rows = State.Name == "All States")) |>
  # Format alignment
  gt::cols_align(align = "left", columns = State.Name) |>
  gt::cols_align(align = "center", columns = -State.Name) |>
  # Caption below (economics style)
  gt::tab_source_note(
    gt::md("**_Note:_** The calculations above do not contain data from American Samoa, Guam, Northern Mariana Islands, Puerto Rico, Virgin Islands, Wake Island, Pending State Designation, or Pending County Designation.<br> 
            **_Source:_** Centers for Medicare & Medicaid Services, *Medicare Advantage/Part D Contract and Enrollment Data: MA State/County Penetration*, https://www.cms.gov/data-research/statistics-trends-and-reports/medicare-advantagepart-d-contract-and-enrollment-data/ma-state/county-penetration (accessed October 26, 2025).")
  )

gt_tbl2
Table 2. Summary Statistics of MA Percent Penetration (%) by State (FY16)
October 1st, 2014 - September 30th, 2016
State
Summary Statistics
N Missing Mean SD Min P25 P50 P75 Max
Alabama 804 0 20.06% 10.54% 6.49% 12.35% 16.02% 25.08% 47.42%
Alaska 303 242 0.47% 0.09% 0.28% 0.44% 0.47% 0.51% 0.83%
Arizona 180 0 26.72% 12.98% 5.90% 15.74% 27.75% 36.92% 51.02%
Arkansas 900 0 19.00% 5.95% 8.83% 13.94% 18.84% 22.55% 38.42%
California 696 4 21.51% 18.10% 0.82% 5.11% 12.88% 40.75% 58.14%
Colorado 768 30 18.96% 13.82% 1.66% 7.95% 14.54% 29.41% 54.15%
Connecticut 96 0 25.01% 3.79% 18.47% 22.27% 24.24% 28.55% 31.20%
Delaware 36 0 8.59% 2.09% 5.41% 6.26% 9.36% 10.07% 11.30%
District of Columbia 12 0 13.92% 0.40% 13.33% 13.65% 13.96% 14.21% 14.48%
Florida 804 0 31.47% 11.65% 9.54% 22.73% 28.48% 39.16% 64.26%
Georgia 1,908 0 31.39% 5.28% 15.89% 27.98% 31.26% 34.95% 45.04%
Hawaii 59 11 43.08% 5.51% 35.48% 38.46% 43.84% 48.34% 49.19%
Idaho 528 0 20.72% 13.08% 1.02% 9.54% 21.15% 29.72% 50.96%
Illinois 1,224 0 18.84% 8.25% 6.38% 12.40% 17.11% 22.75% 45.65%
Indiana 1,104 0 22.22% 8.92% 8.65% 16.14% 20.21% 26.22% 50.59%
Iowa 1,188 6 11.53% 7.68% 0.30% 6.12% 10.34% 15.33% 53.50%
Kansas 1,260 175 5.94% 5.91% 0.82% 2.47% 3.63% 6.98% 33.65%
Kentucky 1,440 0 25.25% 5.53% 13.83% 20.69% 24.80% 28.81% 39.38%
Louisiana 768 0 24.74% 14.64% 6.47% 14.50% 18.18% 32.29% 57.87%
Maine 192 0 22.56% 6.26% 10.25% 17.31% 23.00% 28.15% 31.68%
Maryland 288 0 6.08% 3.66% 0.71% 3.48% 4.62% 8.16% 15.17%
Massachusetts 168 0 16.63% 8.91% 1.28% 11.90% 18.01% 22.82% 33.32%
Michigan 996 0 30.52% 6.53% 18.01% 26.26% 28.95% 33.14% 58.73%
Minnesota 1,044 0 52.64% 7.55% 31.48% 48.16% 53.62% 58.05% 69.88%
Mississippi 984 0 12.74% 5.80% 2.54% 8.63% 12.07% 17.00% 30.66%
Missouri 1,380 0 19.62% 11.96% 3.43% 10.21% 15.53% 26.86% 49.96%
Montana 672 48 14.17% 7.60% 1.81% 7.60% 14.69% 20.47% 32.54%
Nebraska 1,116 446 8.40% 5.74% 0.38% 4.10% 7.52% 11.48% 24.01%
Nevada 204 30 14.57% 14.01% 0.66% 1.83% 10.16% 20.92% 48.57%
New Hampshire 120 0 6.34% 2.85% 0.76% 5.70% 7.43% 8.07% 10.43%
New Jersey 252 0 14.76% 4.61% 7.63% 10.66% 14.35% 17.93% 24.98%
New Mexico 396 0 20.08% 13.53% 2.05% 8.61% 17.53% 27.15% 51.01%
New York 744 0 35.88% 12.54% 11.34% 25.58% 36.18% 44.01% 64.58%
North Carolina 1,200 0 25.84% 12.01% 9.29% 16.43% 24.24% 31.38% 61.23%
North Dakota 636 93 17.34% 8.79% 0.57% 12.09% 16.79% 22.49% 40.72%
Ohio 1,056 0 32.37% 9.18% 16.52% 24.29% 31.95% 39.91% 52.85%
Oklahoma 924 14 9.57% 6.84% 1.66% 5.17% 7.53% 10.59% 31.04%
Oregon 432 0 27.63% 18.15% 3.61% 13.34% 22.66% 47.38% 61.38%
Pennsylvania 804 0 37.48% 13.49% 10.97% 26.99% 35.18% 46.60% 65.64%
Rhode Island 60 0 34.14% 5.55% 24.58% 30.32% 37.05% 38.87% 39.57%
South Carolina 552 0 25.16% 5.96% 12.98% 20.34% 24.98% 29.93% 40.39%
South Dakota 785 36 17.90% 13.03% 1.04% 11.55% 16.66% 21.62% 185.71%
Tennessee 1,140 0 31.89% 10.66% 10.03% 22.41% 29.84% 41.11% 57.86%
Texas 3,048 31 22.85% 8.19% 4.49% 17.05% 21.57% 26.89% 54.37%
Utah 348 15 19.21% 14.47% 0.77% 3.31% 21.77% 33.54% 44.68%
Vermont 168 0 7.40% 1.56% 4.58% 6.37% 7.20% 8.40% 10.86%
Virginia 1,608 0 20.10% 89.61% 6.20% 12.95% 16.16% 21.32% 3,600.00%
Washington 468 12 17.46% 14.06% 0.81% 4.10% 14.96% 27.11% 54.91%
West Virginia 660 0 26.71% 5.60% 13.89% 22.27% 27.16% 31.01% 40.97%
Wisconsin 864 0 36.48% 10.56% 12.01% 29.94% 36.50% 43.02% 64.30%
Wyoming 276 36 3.19% 2.29% 0.29% 1.15% 3.31% 4.62% 9.39%
All States 38,659 1,634 23.76% 23.78% 0.17% 13.01% 21.55% 31.48% 3,600.00%
Note: The calculations above do not contain data from American Samoa, Guam, Northern Mariana Islands, Puerto Rico, Virgin Islands, Wake Island, Pending State Designation, or Pending County Designation.
Source: Centers for Medicare & Medicaid Services, Medicare Advantage/Part D Contract and Enrollment Data: MA State/County Penetration, https://www.cms.gov/data-research/statistics-trends-and-reports/medicare-advantagepart-d-contract-and-enrollment-data/ma-state/county-penetration (accessed October 26, 2025).
# Export table
gt::gtsave(gt_tbl2, filename = "gt_tbl2.png")
file:////var/folders/kz/p2v973zn3tvby5f6_bzbrk9m0000gn/T//RtmpF7yEH3/file31473cde1e21.html screenshot completed

Question 4

Merge State Percent Penetration with CSV

Import JCRC VA Facilities.csv

# Import JCRC VA Facilities data
df.JCRC_VA_Facilities_RAW <- data.frame(read_csv("JCRC VA Facilities.csv"))
Rows: 50 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (1): StateAbbrev
dbl (3): ID, latitude, longitude

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Add period to StateAbbrev
df.JCRC_VA_Facilities_mod <- df.JCRC_VA_Facilities_RAW |> 
  rename(State.Abbrev = StateAbbrev)

# View characteristics of the dataset
# glimpse(df.JCRC_VA_Facilities_mod)
# paged_table(df.JCRC_VA_Facilities_mod)

Add State Abbreviation

# Add state abbreviations
tbl2_ma_penetration_stateabbrev <- tbl2_ma_penetration |> 
  mutate(State.Abbrev = state.abb[match(State.Name, state.name)]) |>
  # Insert District of Columbia abbreviation
  mutate(State.Abbrev = case_when(State.Name == "District of Columbia" ~ "DC",
                                TRUE ~ State.Abbrev)) |>
  filter(!is.na(State.Abbrev))

# View characteristics of dataframe
# glimpse(tbl2_ma_penetration_stateabbrev)

Merge State Percent Penetration with VA Facilities

# Merge State Percent Penetration with VA Facilities by State.Abbrec
df.merged_ma_pen_va_fac <- inner_join(tbl2_ma_penetration_stateabbrev, df.JCRC_VA_Facilities_mod, by = "State.Abbrev" )

state_fips <- df.ma_penetration_FY16_mod|>
  distinct(State.Name, FIPSST)

# Join FIPS codes by State.Name
df.merged_ma_pen_va_fac_fips <- left_join(df.merged_ma_pen_va_fac, state_fips, by = "State.Name")

# View charateristics of dataframe
# glimpse(df.merged_ma_pen_va_fac_fips)
paged_table(df.merged_ma_pen_va_fac_fips)

Question 5

Medicare Advanatage Percent Penetration by Location

Figure 1. State Mean MA Percent Penetration (%) per VA Facility Coordinates

# Construct coordinate scatterplot
plt1 <- ggplot(df.merged_ma_pen_va_fac_fips, aes(x = longitude, y = latitude)) +
  # Set to scatterplot
  geom_point(aes(color = mean_pen, size = mean_pen), alpha = 0.8) +
  ggrepel::geom_text_repel(
    aes(label = State.Abbrev),
    size = 3, max.overlaps = 15, segment.color = "gray70"
  ) +
  # Format color scale legend
  scale_color_viridis_c(
    option = "viridis",
    name = "Mean MA Percent Penetration (%)"
  ) +
  # Format size legend
  scale_size_continuous(
    name = "Mean MA Percent Penetration (%)",
    range = c(2, 8),
    guide = guide_legend(reverse = TRUE)
  ) +
  # Set titles and axis labels
  labs(
    title = "Figure 1. State Mean MA Percent Penetration (%) per VA Facility Coordinates",
    subtitle = "Each point labeled by state; color and size indicate % penetration.",
    x = "Longitude",
    y = "Latitude",
    caption = paste0(
      "Note: Data from Kansas (KS) and Iowa (IA) were omitted because they did not have VA facility coordinate data.\n",
      "Source: CMS MA/Part D Penetration Data (Accessed Oct 26 2025)."
    )
  ) +
  # Format theme
  theme_minimal(base_family = "Times") +
  theme(
    # Format titles, legend, and caption
    legend.position = "right",
    plot.title = element_text(face = "bold"),
    plot.subtitle = element_text(margin = margin(b = 6)),
    plot.caption = element_text(
      hjust = 0,
      size = 9,
      color = "gray35",
      lineheight = 1.1,
      face = "italic" 
    )
  )

plt1

# Export figure
ggsave(
  filename = "plt1.jpeg",
  plot = plt1,
  width = 15, height = 10, dpi = 300
)

Figure 2. Mean MA Percent Penetration (%) by State

# Create state tile dataframe base on state abbreviation
df.tiles <- df.merged_ma_pen_va_fac_fips |>
  distinct(State.Abbrev, mean_pen)

# Construct state grid plot
plt2 <- ggplot(df.tiles, aes(state = State.Abbrev, fill = mean_pen)) +
  geom_statebins(border_col = "white") +
  scale_fill_viridis_c(name = "Mean MA Percent Penetration (%)", option = "viridis") +
  labs(
    title = "Figure 2. Mean MA Percent Penetration (%) by State",
    subtitle = "Each tile represents a state; color indicates mean MA percent penetration (%).",
    caption = paste0(
      "Note: Data from Kansas (KS) and Iowa (IA) were omitted because they did not have VA facility coordinate data.\n",
      "Source: CMS MA/Part D Penetration Data (Accessed Oct 26 2025)."
    )
  ) +
  # Format bin theme
  theme_statebins(base_size = 12) +
  theme(
    legend.position = "right",
    plot.title = element_text(face = "bold", family = "Times"),
    plot.subtitle = element_text(margin = margin(b = 6), family = "Times")
  ) +
  # Format theme and captions
  theme_minimal(base_family = "Times") +
  theme(
    # Remove grid lines and axis lines
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background = element_blank(),
    plot.background = element_blank(),
    axis.line = element_blank(),
    # Format titles,legend, caption
    legend.position = "right",
    plot.title = element_text(face = "bold"),
    plot.subtitle = element_text(margin = margin(b = 6)),
    plot.caption = element_text(
      hjust = 0,
      size = 9,
      color = "gray35",
      lineheight = 1.1,
      face = "italic" 
    )
  )

plt2

# Export figure
ggsave(
  filename = "plt2.jpeg",
  plot = plt2,
  width = 15, height = 10, dpi = 300
)

Question 6

Data Aggregation Scenario

Calculating Medicare Advantage (MA) Penetration by VA Facility

To calculate the percent (%) penetration of Medicare Advantage (MA) by VA facility, the following data would be needed:

  • VA facility address and location information, including county, ZIP code, FIPS code, and geographic coordinates (latitude and longitude).
  • VA facility service area, such as the counties or regions that the facility serves.
  • County-level enrollment data, i.e., the number of MA enrollees in each county.
  • County-level eligibility data, i.e., the number of Medicare-eligible individuals in each county.

Calculation Process

To calculate the percent penetration by VA facilities, I would:

  1. Aggregate the MA enrollee counts and Medicare-eligible counts for all counties within each VA facility’s service area.

  2. Compute the penetration rate as:

    \[ \text{Percent Penetration} = \left( \frac{\text{MA Enrollees}}{\text{Medicare Eligibles}} \right) \times 100 \]

    This represents the ratio of enrollees to eligibles expressed as a percentage.

  3. Repeat this calculation for the service area of each VA facility.


Additional Notes

Question 7

VA Patient Population Demographics

Import VA Vet Pop Demographic data

# The following files were formatted in Excel for proper import
# Import VA Patient Population Demographics files
df.va_vetpop_race_ethnicity_RAW <- readxl::read_xlsx("VetPop2023_Race_Ethnicity_State_NCVAS.xlsx")

# glimpse(df.va_vetpop_race_ethnicity_RAW)

df.va_vetpop_age_group_RAW <- readxl::read_xlsx("VetPop2023_State_AgeGroup_Sex_NCVAS.xlsx")

# View dataframe
# glimpse(df.va_vetpop_age_group_RAW)
# Calculate state-level demographic percentages for Sex, Race/Ethnicity, and Age Groups
# Factor levels: Sex
sex_levels <- c("Female", "Male")

# Sex Percentage Calculations per State
df.va_vetpop_sex <- df.va_vetpop_race_ethnicity_RAW |>
  subset(select = -c(Race_Ethnicity)) |>
  group_by(State, Sex) |>
  summarize(state_sex_pop = sum(Veterans, na.rm = TRUE), .groups = "drop") |>
  group_by(State) |>
  mutate(
    perc_state_sex = round((state_sex_pop / sum(state_sex_pop)) * 100, 2)
  ) |>
  ungroup() |>
  mutate(Sex = factor(Sex, levels = sex_levels, ordered = TRUE))

# Sex Percentage Calculations for All States
total_va_vetpop_sex <- df.va_vetpop_race_ethnicity_RAW |>
  subset(select = -c(Race_Ethnicity)) |>
  group_by(Sex) |>
  summarize(state_sex_pop = sum(Veterans, na.rm = TRUE), .groups = "drop")|>
  mutate(
    perc_state_sex = round((state_sex_pop / sum(state_sex_pop)) * 100, 2)
  ) |>
  ungroup() |>
  mutate(Sex = factor(Sex, levels = sex_levels, ordered = TRUE)) |>
  mutate(State = "All States")

# Combine dataframes
df.va_vetpop_sex_all <- bind_rows(df.va_vetpop_sex, total_va_vetpop_sex)

# View dataframe
# glimpse(df.va_vetpop_sex_all)

# Factor levels: Race/Ethnicity
race_levels <- c("White, alone",    "Black or African American, alone", "American Indian and Alaska Native, alone", "Asian, alone", "Native Hawaiian and Other Pacific Islander, alone",    "Some othe race, alone",    "Two or more races",    "Hispanic or Latino (of any race)", "White alone, Not Hispanic or Latino")

# Race/Ethnicity Percentage Calculations per State
df.va_vetpop_race_ethnic <- df.va_vetpop_race_ethnicity_RAW |>
  subset(select = -c(Sex)) |>
  group_by(State, Race_Ethnicity) |>
  summarize(state_race_ethnic_pop = sum(Veterans, na.rm = TRUE), .groups = "drop") |>
  group_by(State) |>
  mutate(
    perc_state_race_ethnic = round((state_race_ethnic_pop / sum(state_race_ethnic_pop)) * 100, 2)
  ) |>
  ungroup() |> 
  mutate(Race_Ethnicity = factor(Race_Ethnicity, levels = race_levels, ordered = TRUE))

# Race/Ethnicity Percentage Calculations for All States
total_va_vetpop_race_ethnicity <- df.va_vetpop_race_ethnicity_RAW |>
  subset(select = -c(Sex)) |>
  group_by(Race_Ethnicity) |>
  summarize(state_race_ethnic_pop = sum(Veterans, na.rm = TRUE), .groups = "drop")|>
  mutate(
    perc_state_race_ethnic = round((state_race_ethnic_pop / sum(state_race_ethnic_pop)) * 100, 2)
  ) |>
  ungroup() |>
  mutate(Race_Ethnicity = factor(Race_Ethnicity, levels = race_levels, ordered = TRUE)) |>
  mutate(State = "All States")

# Combine dataframes
df.va_vetpop_race_ethnic_all <- bind_rows(df.va_vetpop_race_ethnic, total_va_vetpop_race_ethnicity)

# View dataframe
# glimpse(df.va_vetpop_race_ethnic_all)

# Factor level: Age groups
age_levels <- c("< 20", "20-24", "25-29", "30-34", "35-39", "40-44", "45-49", "50-54", "55-59", "60-64", "65-69", "70-74", "75-79", "80-84", "85+")

# Age Group Percentage Calculations per State
df.va_vetpop_age_group <- df.va_vetpop_age_group_RAW |>
  subset(select = -c(Sex)) |>
  group_by(State, Age_Group) |>
  summarize(state_age_group_pop = sum(Veterans, na.rm = TRUE), .groups = "drop") |>
  group_by(State) |>
  mutate(
    perc_state_age_group = round((state_age_group_pop / sum(state_age_group_pop)) * 100, 2)
  ) |>
  ungroup() |>
  mutate(Age_Group = factor(Age_Group, levels = age_levels, ordered = TRUE))

# Age Group Percentage Calculations for All States
total_va_vetpop_age_group <- df.va_vetpop_age_group_RAW |>
  subset(select = -c(Sex)) |>
  group_by(Age_Group) |>
  summarize(state_age_group_pop = sum(Veterans, na.rm = TRUE), .groups = "drop")|>
  mutate(
    perc_state_age_group = round((state_age_group_pop / sum(state_age_group_pop)) * 100, 2)
  ) |>
  ungroup() |>
  mutate(Age_Group = factor(Age_Group, levels = age_levels, ordered = TRUE)) |>
  mutate(State = "All States")

# Combine dataframes
df.va_vetpop_age_group_all <- bind_rows(df.va_vetpop_age_group, total_va_vetpop_age_group)

# View dataframe
# glimpse(df.va_vetpop_age_group_all)
# paged_table(df.va_vetpop_age_group_all)
# Convert data frames from long to wide
# Sex
sex_wide <- df.va_vetpop_sex_all |>
  select(State, category = Sex, pct = perc_state_sex) |>
  pivot_wider(names_from = category, values_from = pct, names_prefix = "Sex: ")

# Race/Ethnicity
race_wide <- df.va_vetpop_race_ethnic_all |>
  select(State, category = Race_Ethnicity, pct = perc_state_race_ethnic) |>
  pivot_wider(names_from = category, values_from = pct, names_prefix = "Race: ")

# Age Groups
age_wide <- df.va_vetpop_age_group_all |>
  select(State, category = Age_Group, pct = perc_state_age_group) |>
  pivot_wider(names_from = category, values_from = pct, names_prefix = "Age: ")

# Combine all dataframes by State
df.state_perc_demographics <- sex_wide |>
  full_join(race_wide, by = "State") |>
  full_join(age_wide,  by = "State") |>
  arrange(State) |>
  select(State, all_of(paste0("Sex: ", sex_levels)), all_of(paste0("Race: ", race_levels)), all_of(paste0("Age: ", age_levels)))

# Format row and column order
tbl3_state_perc_demographics <- df.state_perc_demographics |>
      filter(!State %in% c("Island Areas & Foreign", "Puerto Rico")) |>
      rename_with(~ gsub("^(Sex: |Race: |Age: )", "", .x), -State) |>
      arrange(State == "All States")

# glimpse(tbl3_state_perc_demographics)
paged_table(tbl3_state_perc_demographics)

Table 3. State-Level Demographic Percentages (2023)

# Construct gt table
gt_tbl3 <- gt::gt(tbl3_state_perc_demographics, rowname_col = "State") |>
  tab_stubhead(label = "State") |>
  # Format title
  tab_header(
    title = md("**Table 3. State-Level Veteran Population Demographic Percentages (2023)**"),
    subtitle = md("Percent distribution of veterans by sex, race/ethnicity, and age group")
  ) |>
  # Format column spanned titles
  tab_spanner(
    label = "Sex",
    columns = 2:3
  ) |>
  tab_spanner(
    label = "Race / Ethnicity",
    columns = 4:12
  ) |>
  tab_spanner(
    label = "Age Group (years)",
    columns = 13:27
  ) |>
  # Format numbers
  fmt_number(columns = where(is.numeric), 
             decimals = 2, 
             pattern = "{x}%") |>
  # Format table body
  gt::tab_options(
    table.font.size = gt::px(11),
    data_row.padding = gt::px(2),
    table.font.color = "black",
    table.border.top.color = "black",
    table.border.top.width = gt::px(1),
    table.border.bottom.color = "black",
    table.border.bottom.width = gt::px(1),
    column_labels.font.weight = "bold",
    column_labels.border.bottom.color = "black",
    column_labels.border.bottom.width = gt::px(1),
    column_labels.border.top.color = "black",
    column_labels.border.top.width = gt::px(1),
    heading.align = "center",
    heading.background.color = "white",
    heading.title.font.weight = "bold",
    table.align = "center"
  ) |>
  gt::opt_table_font(
    font = list(
      gt::system_fonts(name = "old-style"),
      gt::default_fonts()
    )
  ) |>
  # Thin gray lines between rows (no shading)
  gt::tab_style(
    style = list(gt::cell_borders(sides = "bottom", color = "#bfbfbf", weight = gt::px(0.5))),
    locations = gt::cells_body(rows = everything())) |>
  # Format last row
   gt::tab_style(
    style = gt::cell_text(weight = "bold"),
    locations = gt::cells_body(rows = State == "All States")
  ) |>
  gt::tab_style(
    style = list(gt::cell_text(weight = "bold")),
    locations = gt::cells_stub(rows = State == "All States")) |>
  # Format alignment
  gt::cols_align(align = "left", columns = State) |>
  gt::cols_align(align = "center", columns = -State) |>
  # Format note and source caption
  gt::tab_source_note(
    gt::md("**_Note:_** The calculations above do not contain data from Island Areas & Foreign or Puerto Rico. All data is from September 30<sup>th</sup>, 2023 VA state-level population tables<br> 
            **_Source:_** U.S. Department of Veterans Affairs, *National Center for Veterans Analysis & Statistics.* Veteran Population - Population Tables: The States. Last updated March 26 2025. https://www.va.gov/vetdata/veteran_population.asp (accessed October 26, 2025).")
  )

gt_tbl3
Table 3. State-Level Veteran Population Demographic Percentages (2023)
Percent distribution of veterans by sex, race/ethnicity, and age group
State
Sex
Race / Ethnicity
Age Group (years)
Female Male White, alone Black or African American, alone American Indian and Alaska Native, alone Asian, alone Native Hawaiian and Other Pacific Islander, alone Some othe race, alone Two or more races Hispanic or Latino (of any race) White alone, Not Hispanic or Latino < 20 20-24 25-29 30-34 35-39 40-44 45-49 50-54 55-59 60-64 65-69 70-74 75-79 80-84 85+
Alabama 11.40% 88.60% 40.96% 14.40% 0.19% 0.31% 0.02% 0.51% 1.77% 1.48% 40.36% 0.02% 0.90% 3.09% 4.72% 5.60% 6.32% 6.34% 8.77% 9.91% 11.19% 10.52% 9.90% 11.67% 5.87% 5.17%
Alaska 14.97% 85.03% 43.33% 2.37% 3.52% 1.41% 0.61% 0.82% 3.57% 2.92% 41.46% 0.01% 1.72% 4.82% 6.84% 8.03% 8.74% 7.49% 8.39% 9.23% 10.69% 9.51% 8.23% 9.15% 4.37% 2.77%
Arizona 10.88% 89.12% 42.80% 2.79% 1.19% 0.54% 0.08% 1.78% 3.76% 7.72% 39.34% 0.03% 0.93% 3.27% 4.66% 5.32% 5.83% 5.39% 6.78% 7.98% 9.26% 9.26% 10.38% 15.17% 8.45% 7.28%
Arkansas 10.61% 89.39% 44.33% 6.53% 0.35% 0.23% 0.14% 0.60% 2.54% 1.47% 43.81% 0.02% 0.73% 3.06% 4.74% 5.54% 6.16% 5.86% 8.22% 9.22% 10.35% 9.95% 11.24% 11.97% 6.24% 6.71%
California 9.83% 90.17% 37.00% 5.55% 0.57% 4.31% 0.26% 3.46% 5.09% 10.99% 32.77% 0.04% 1.22% 3.81% 5.28% 6.14% 6.80% 6.16% 6.88% 7.95% 9.15% 9.14% 9.26% 12.19% 7.33% 8.66%
Colorado 12.48% 87.52% 42.99% 3.35% 0.51% 0.85% 0.13% 1.65% 3.74% 6.72% 40.06% 0.05% 1.47% 4.42% 6.39% 7.12% 7.07% 6.44% 8.05% 8.89% 9.44% 8.96% 9.17% 11.15% 5.34% 6.06%
Connecticut 8.33% 91.67% 44.83% 4.07% 0.17% 0.50% 0.01% 1.31% 2.06% 3.88% 43.17% 0.01% 0.86% 2.83% 4.28% 5.04% 5.72% 5.42% 6.55% 8.18% 10.32% 9.29% 8.10% 14.24% 8.81% 10.35%
Delaware 11.73% 88.27% 41.39% 12.58% 0.13% 0.46% 0.02% 0.86% 1.77% 2.71% 40.09% 0.01% 0.69% 2.44% 3.69% 4.22% 5.20% 4.95% 6.47% 9.07% 11.93% 10.44% 12.05% 14.25% 7.82% 6.76%
District of Columbia 14.72% 85.28% 28.02% 34.39% 0.32% 1.49% 0.01% 1.20% 3.51% 4.99% 26.07% 0.01% 0.43% 2.72% 5.67% 7.28% 8.70% 7.13% 7.81% 9.13% 11.71% 11.04% 8.08% 7.07% 5.80% 7.43%
Florida 11.14% 88.86% 42.39% 6.67% 0.19% 0.59% 0.04% 1.18% 3.33% 5.80% 39.82% 0.02% 0.78% 2.68% 4.01% 4.84% 5.71% 5.67% 7.17% 8.68% 10.63% 9.77% 9.64% 13.59% 8.19% 8.63%
Georgia 13.45% 86.55% 36.69% 20.95% 0.13% 0.66% 0.06% 0.90% 2.21% 2.63% 35.77% 0.03% 1.21% 3.88% 5.55% 6.07% 6.62% 6.58% 8.79% 10.16% 11.14% 9.75% 8.89% 10.48% 5.76% 5.07%
Hawaii 13.58% 86.42% 26.23% 3.87% 0.21% 19.96% 5.32% 1.81% 12.19% 6.16% 24.26% 0.02% 1.44% 4.70% 6.00% 7.14% 8.51% 6.95% 7.26% 8.50% 9.37% 8.27% 7.98% 10.39% 5.61% 7.85%
Idaho 9.77% 90.23% 46.75% 0.38% 0.45% 0.32% 0.07% 1.09% 2.42% 2.78% 45.74% 0.02% 0.91% 3.12% 5.09% 5.90% 6.45% 5.87% 7.34% 8.75% 9.40% 9.12% 10.11% 13.38% 7.35% 7.19%
Illinois 11.31% 88.69% 42.21% 7.77% 0.22% 0.98% 0.03% 1.22% 2.65% 4.60% 40.32% 0.08% 3.87% 8.47% 7.58% 5.56% 6.10% 5.29% 6.79% 7.93% 8.21% 7.25% 8.20% 11.53% 6.06% 7.11%
Indiana 9.40% 90.60% 46.09% 4.09% 0.15% 0.26% 0.03% 0.58% 1.70% 1.62% 45.49% 0.03% 0.83% 3.08% 4.78% 5.51% 5.49% 5.14% 7.91% 9.99% 11.12% 9.79% 10.56% 13.20% 6.52% 6.05%
Iowa 9.10% 90.90% 48.00% 1.15% 0.20% 0.17% 0.06% 0.33% 1.39% 1.29% 47.41% 0.02% 0.89% 2.99% 4.39% 5.32% 5.53% 5.28% 7.18% 9.32% 9.81% 8.58% 12.15% 13.25% 7.70% 7.59%
Kansas 10.75% 89.25% 45.20% 3.71% 0.37% 0.44% 0.14% 0.65% 2.79% 2.96% 43.73% 0.02% 1.43% 3.99% 5.31% 6.33% 6.74% 6.36% 7.75% 8.60% 9.24% 8.79% 10.12% 11.66% 7.10% 6.57%
Kentucky 9.76% 90.24% 46.09% 4.97% 0.14% 0.29% 0.07% 0.28% 1.47% 1.02% 45.68% 0.02% 1.06% 3.40% 4.51% 5.60% 6.18% 6.27% 8.55% 10.19% 10.98% 9.81% 10.27% 11.49% 5.99% 5.68%
Louisiana 11.27% 88.73% 39.64% 16.33% 0.24% 0.39% 0.02% 0.57% 2.10% 1.76% 38.95% 0.02% 1.12% 3.37% 4.60% 5.69% 7.57% 7.30% 9.49% 9.53% 8.82% 9.04% 9.92% 11.71% 6.43% 5.39%
Maine 9.11% 90.89% 48.40% 0.48% 0.19% 0.10% 0.01% 0.20% 1.79% 0.75% 48.08% 0.02% 0.56% 2.12% 3.69% 4.65% 4.80% 5.23% 7.01% 8.93% 11.55% 10.59% 10.47% 15.06% 7.90% 7.42%
Maryland 14.55% 85.45% 36.76% 19.15% 0.15% 1.36% 0.05% 1.06% 2.70% 3.16% 35.62% 0.02% 0.82% 2.67% 4.44% 5.63% 7.12% 6.98% 8.41% 10.05% 11.57% 9.57% 9.34% 10.45% 6.20% 6.72%
Massachusetts 8.16% 91.84% 46.14% 2.37% 0.18% 0.61% 0.01% 0.95% 1.95% 2.58% 45.21% 0.01% 0.58% 2.60% 4.26% 4.91% 4.96% 4.88% 6.62% 8.58% 10.83% 9.64% 9.63% 14.45% 7.68% 10.36%
Michigan 8.46% 91.54% 45.47% 5.58% 0.25% 0.33% 0.01% 0.49% 1.61% 1.41% 44.85% 0.02% 0.59% 2.29% 3.76% 4.64% 4.67% 4.67% 7.41% 9.57% 10.65% 9.58% 11.21% 15.10% 7.81% 8.03%
Minnesota 8.64% 91.36% 47.57% 1.23% 0.41% 0.62% 0.02% 0.39% 1.64% 1.12% 47.00% 0.01% 0.77% 2.89% 4.17% 5.12% 5.16% 4.54% 6.41% 8.64% 9.64% 9.17% 11.18% 15.96% 7.75% 8.59%
Mississippi 12.50% 87.50% 39.91% 16.73% 0.26% 0.44% 0.07% 0.39% 1.63% 1.10% 39.45% 0.02% 1.04% 3.52% 5.22% 6.02% 7.10% 6.91% 8.81% 9.74% 10.99% 9.84% 9.74% 10.24% 5.28% 5.52%
Missouri 9.73% 90.27% 45.58% 5.12% 0.24% 0.32% 0.08% 0.42% 1.97% 1.30% 44.96% 0.02% 0.87% 3.61% 4.76% 5.62% 6.10% 5.64% 7.58% 8.94% 10.49% 9.78% 10.40% 12.72% 6.54% 6.95%
Montana 11.05% 88.95% 46.67% 0.40% 1.88% 0.13% 0.01% 0.73% 2.50% 1.84% 45.84% 0.02% 0.88% 3.04% 4.73% 6.11% 6.65% 5.98% 7.49% 8.64% 9.22% 8.98% 11.97% 11.35% 7.38% 7.58%
Nebraska 11.04% 88.96% 46.49% 2.04% 0.31% 0.58% 0.00% 0.50% 2.21% 2.30% 45.57% 0.02% 0.86% 2.94% 4.84% 6.04% 6.61% 6.10% 8.08% 9.55% 10.15% 8.49% 9.47% 13.51% 5.74% 7.60%
Nevada 10.67% 89.33% 40.44% 5.89% 0.67% 2.75% 0.34% 1.72% 4.17% 5.81% 38.20% 0.03% 0.87% 3.45% 5.01% 5.78% 6.37% 5.73% 6.98% 8.67% 10.03% 9.77% 10.01% 14.04% 7.44% 5.82%
New Hampshire 9.39% 90.61% 48.31% 0.32% 0.13% 0.18% 0.04% 0.42% 1.45% 1.41% 47.74% 0.01% 0.66% 2.76% 4.36% 5.15% 5.01% 4.96% 6.91% 8.89% 11.58% 10.91% 10.23% 13.48% 7.77% 7.32%
New Jersey 8.13% 91.87% 40.92% 7.94% 0.16% 1.49% 0.07% 1.74% 3.06% 6.02% 38.59% 0.03% 1.04% 3.09% 4.36% 5.12% 5.52% 5.05% 6.29% 7.80% 9.41% 8.43% 8.51% 16.22% 7.98% 11.14%
New Mexico 12.50% 87.50% 37.63% 2.04% 3.05% 0.36% 0.06% 3.57% 6.78% 16.79% 29.73% 0.02% 0.88% 2.92% 4.41% 5.32% 6.58% 6.18% 7.67% 8.75% 10.79% 10.20% 10.70% 11.98% 7.33% 6.29%
New York 8.52% 91.48% 41.90% 6.67% 0.28% 1.07% 0.02% 1.77% 2.80% 5.24% 40.25% 0.03% 0.88% 2.74% 4.17% 5.07% 5.58% 5.23% 6.53% 8.99% 10.65% 9.47% 8.87% 14.37% 7.32% 10.10%
North Carolina 12.46% 87.54% 40.99% 12.81% 0.49% 0.43% 0.10% 0.80% 1.96% 2.35% 40.08% 0.02% 1.27% 4.28% 5.53% 6.10% 6.46% 6.37% 8.13% 9.11% 10.08% 9.42% 9.80% 11.88% 6.04% 5.53%
North Dakota 11.00% 89.00% 47.32% 1.03% 1.60% 0.24% 0.03% 0.24% 1.56% 1.16% 46.82% 0.01% 1.13% 3.96% 6.17% 7.35% 8.03% 6.67% 8.15% 9.83% 9.83% 8.79% 8.93% 10.23% 5.18% 5.73%
Ohio 9.00% 91.00% 45.53% 5.81% 0.09% 0.25% 0.03% 0.48% 1.59% 1.23% 44.99% 0.02% 0.80% 2.88% 4.17% 5.07% 5.35% 5.22% 7.73% 9.82% 10.85% 9.81% 10.87% 13.68% 6.63% 7.09%
Oklahoma 11.18% 88.82% 43.28% 4.23% 2.70% 0.42% 0.05% 0.88% 3.59% 2.69% 42.15% 0.05% 1.29% 3.65% 5.50% 6.61% 7.57% 6.79% 8.07% 8.53% 8.83% 9.19% 10.72% 10.52% 7.24% 5.46%
Oregon 9.72% 90.28% 46.60% 0.78% 0.53% 0.62% 0.09% 0.62% 2.75% 2.45% 45.56% 0.02% 0.66% 2.41% 4.11% 5.20% 5.54% 5.15% 6.96% 8.57% 9.59% 9.93% 11.66% 15.10% 7.39% 7.71%
Pennsylvania 8.75% 91.25% 45.65% 4.95% 0.08% 0.38% 0.03% 0.67% 1.50% 1.87% 44.87% 0.01% 0.61% 2.51% 3.81% 4.63% 5.10% 5.02% 6.90% 9.30% 10.28% 9.27% 10.27% 15.05% 8.12% 9.14%
Rhode Island 8.72% 91.28% 45.98% 2.34% 0.41% 0.65% 0.00% 1.25% 1.59% 2.58% 45.19% 0.04% 1.19% 3.10% 5.03% 5.39% 5.30% 5.26% 6.29% 8.56% 11.31% 9.39% 8.22% 15.50% 5.48% 9.95%
South Carolina 12.15% 87.85% 40.57% 14.47% 0.18% 0.40% 0.06% 0.66% 1.95% 1.92% 39.79% 0.19% 1.86% 3.97% 4.98% 5.69% 6.24% 6.23% 7.94% 9.05% 10.46% 9.28% 9.29% 12.75% 5.81% 6.26%
South Dakota 11.71% 88.29% 47.40% 0.61% 2.18% 0.22% 0.03% 0.25% 1.41% 1.08% 46.83% 0.02% 0.83% 3.13% 4.63% 5.95% 6.85% 6.34% 8.08% 9.82% 11.09% 9.72% 10.30% 13.04% 5.59% 4.61%
Tennessee 10.47% 89.53% 44.38% 7.92% 0.16% 0.28% 0.03% 0.44% 1.57% 1.47% 43.75% 0.03% 0.91% 3.34% 4.98% 5.58% 5.80% 5.62% 8.02% 9.51% 10.60% 9.84% 10.54% 12.53% 6.62% 6.09%
Texas 12.43% 87.57% 38.41% 8.38% 0.37% 0.84% 0.12% 2.00% 5.37% 11.68% 32.83% 0.04% 1.43% 4.39% 5.98% 7.31% 8.23% 7.45% 8.94% 8.94% 8.93% 8.79% 8.69% 10.43% 5.39% 5.04%
Utah 9.15% 90.85% 46.13% 0.98% 0.37% 0.66% 0.39% 0.94% 2.47% 3.28% 44.77% 0.04% 1.06% 4.00% 6.04% 6.89% 7.63% 6.89% 7.47% 7.96% 8.40% 8.08% 9.36% 12.52% 6.36% 7.30%
Vermont 9.27% 90.73% 48.35% 0.24% 0.06% 0.29% 0.02% 0.37% 1.98% 0.55% 48.12% 0.00% 0.70% 2.30% 3.95% 4.67% 4.55% 4.80% 6.69% 9.14% 12.24% 11.12% 10.36% 12.58% 8.65% 8.25%
Virginia 15.24% 84.76% 39.85% 12.46% 0.17% 1.42% 0.06% 1.10% 2.86% 3.48% 38.59% 0.02% 0.90% 3.36% 5.23% 6.64% 8.17% 7.97% 9.42% 10.12% 10.76% 9.36% 8.58% 9.58% 4.65% 5.26%
Washington 11.32% 88.68% 44.31% 2.81% 0.48% 1.59% 0.40% 1.03% 3.24% 2.92% 43.22% 0.01% 0.83% 3.20% 5.09% 6.16% 6.79% 6.23% 7.61% 9.08% 9.81% 9.85% 9.88% 13.12% 6.43% 5.91%
West Virginia 8.54% 91.46% 48.25% 1.72% 0.05% 0.20% 0.01% 0.28% 0.99% 0.55% 47.95% 0.02% 0.71% 2.53% 3.74% 4.78% 5.85% 6.29% 8.70% 9.77% 9.74% 9.22% 11.47% 12.10% 8.33% 6.73%
Wisconsin 9.49% 90.51% 47.35% 1.68% 0.45% 0.39% 0.01% 0.46% 1.54% 1.33% 46.79% 0.03% 0.76% 2.79% 4.17% 5.18% 5.17% 4.75% 6.89% 9.38% 10.08% 9.51% 11.11% 14.82% 7.46% 7.91%
Wyoming 11.05% 88.95% 47.09% 0.88% 0.66% 0.24% 0.01% 0.94% 1.79% 2.40% 46.00% 0.03% 1.01% 3.15% 5.24% 6.17% 7.34% 6.67% 8.28% 9.18% 9.30% 9.44% 10.81% 13.67% 5.98% 3.72%
All States 10.80% 89.20% 42.17% 7.05% 0.41% 1.07% 0.14% 1.26% 2.97% 4.80% 40.13% 0.03% 1.10% 3.52% 4.95% 5.77% 6.40% 6.04% 7.68% 9.01% 10.05% 9.34% 9.70% 12.58% 6.75% 7.08%
Note: The calculations above do not contain data from Island Areas & Foreign or Puerto Rico. All data is from September 30th, 2023 VA state-level population tables
Source: U.S. Department of Veterans Affairs, National Center for Veterans Analysis & Statistics. Veteran Population - Population Tables: The States. Last updated March 26 2025. https://www.va.gov/vetdata/veteran_population.asp (accessed October 26, 2025).
# Export table
gt::gtsave(gt_tbl3, filename = "gt_tbl3.png")
file:////var/folders/kz/p2v973zn3tvby5f6_bzbrk9m0000gn/T//RtmpF7yEH3/file314739ecdfcb.html screenshot completed

Completion Time

This assessment took me approximately 25 hours to complete. A lot of time was spent on constructing the functions to import the MA penetration files, formatting each of the tables and figures, and troubleshooting error messages.

Challenges

The two challenges I faced during this task were constructing the functions to import the MA penetration files and creating a figure to showcase the lat and long data for VA facilities. The functions took many trial and error attempts to create. The VA facilities coordinates figure would have been more clear if I was able to overlay a map of the United States, Alaska, and Hawaii. Unfortunately, I was having challenges importing and formatting polygons of the United States, Alaska, and Hawaii into the same figure. R does have the capability to do maps, but I could not figure it out in time before this assessment’s deadline.