From 7f6383a2b158893b59e58380515b99f7c7e29bf9 Mon Sep 17 00:00:00 2001 From: Andrew Bruce Date: Tue, 28 Nov 2023 21:56:58 -0500 Subject: [PATCH] `quality_eligibility` nested boolean output (#61) --- R/globals.R | 6 ++ R/quality_eligibility.R | 175 +++++++++++++++++++++++++++++++++++-- README.Rmd | 12 ++- README.md | 14 ++- man/quality_eligibility.Rd | 4 +- vignettes/articles/qpp.Rmd | 151 +------------------------------- 6 files changed, 200 insertions(+), 162 deletions(-) diff --git a/R/globals.R b/R/globals.R index b8be76ea..502a5710 100644 --- a/R/globals.R +++ b/R/globals.R @@ -195,6 +195,12 @@ utils::globalVariables(c( "grp", # "npi_type", # "org_state", # + "results", # + "year", # + "npi", # + "org_name", # + "value", # + "name", # "distro", # "y", # "set", # diff --git a/R/quality_eligibility.R b/R/quality_eligibility.R index e65c3d3e..a9c07ffa 100644 --- a/R/quality_eligibility.R +++ b/R/quality_eligibility.R @@ -88,8 +88,8 @@ quality_eligibility <- function(year, npi, tidy = TRUE, unnest = TRUE, - pivot = FALSE, - na.rm = FALSE, + pivot = TRUE, + na.rm = TRUE, ...) { rlang::check_required(year) @@ -169,12 +169,13 @@ quality_eligibility <- function(year, unnest_if_name('grp.lowVolumeStatusReasons', wide = TRUE) |> unnest_if_name('grp.isEligible') |> unnest_if_name('error') |> - cols_qelig() + cols_qelig('tidyup') results <- tidyup(results, dtype = 'ymd', int = c('year', 'years_in_medicare', + 'ind_hosp_vbp_score', # 'apms_lvt_patients', # 'apms_lvt_year' 'pecos_year'), @@ -204,6 +205,7 @@ quality_eligibility <- function(year, 'ind_hospital_based', 'ind_hpsa', 'ind_ia_study', + 'ind_opted_in', 'ind_opt_in_eligible', 'ind_mips_switch', 'ind_non_patient', @@ -228,6 +230,7 @@ quality_eligibility <- function(year, 'grp_hospital_based', 'grp_hpsa', 'grp_ia_study', + 'grp_opted_in', 'grp_opt_in_eligible', 'grp_mips_switch', 'grp_non_patient', @@ -238,7 +241,14 @@ quality_eligibility <- function(year, dplyr::mutate(npi_type = fct_entype(npi_type), org_state = fct_stabb(org_state)) } - if (pivot) {} + if (pivot) { + + results <- cols_qelig(results, 'top') |> + dplyr::left_join(cols_qelig(results, 'apms')) |> + dplyr::left_join(cols_qelig(results, 'ind')) |> + dplyr::left_join(cols_qelig(results, 'grp')) + + } if (na.rm) results <- narm(results) } return(results) @@ -265,9 +275,12 @@ unnest_if_name <- function(df, name, unpack = TRUE, wide = FALSE) { } #' @param df data frame +#' @param type description #' @autoglobal #' @noRd -cols_qelig <- function(df) { +cols_qelig <- function(df, type = c('tidyup', 'top', 'apms', 'ind', 'grp')) { + + if (type == 'tidyup') { cols <- c('year' = 'year', 'npi' = 'npi', @@ -281,7 +294,7 @@ cols_qelig <- function(df) { 'newly_enrolled' = 'newlyEnrolled', 'specialty_desc' = 'specialty.specialtyDescription', 'specialty_type' = 'specialty.typeDescription', - 'specialty_category' = 'specialty.categoryReference', + 'specialty_cat' = 'specialty.categoryReference', 'is_maqi' = 'isMaqi', 'org_name' = 'organizations_prvdrOrgName', 'org_hosp_vbp_name' = 'organizations_hospitalVbpName', @@ -364,7 +377,7 @@ cols_qelig <- function(df) { # 'ind_scenario' = 'ind.eligibilityScenario', 'grp_hardship_pi' = 'grp.aciHardship', - 'grp_hardship_reweight' = 'grp.aciReweighting', + 'grp_reweight_pi' = 'grp.aciReweighting', 'grp_asc' = 'grp.ambulatorySurgicalCenter', 'grp_ext_hardship' = 'grp.extremeHardship', 'grp_ext_hardship_quality' = 'grp.extremeHardshipReasons.quality', @@ -388,8 +401,154 @@ cols_qelig <- function(df) { 'grp_eligible' = 'grp.isEligible.group' # 'grp_agg_level' = 'grp.aggregationLevel', ) + return(df |> dplyr::select(dplyr::any_of(cols))) + } + + if (type == 'top') { + + cols <- c('year', + 'npi', + 'npi_type', + 'first', + 'middle', + 'last', + 'first_approved_date', + 'years_in_medicare', + 'pecos_year', + 'newly_enrolled', + 'specialty_desc', + 'specialty_type', + 'specialty_cat', + 'is_maqi', + 'org_name', + 'org_hosp_vbp_name', + 'org_facility_based', + 'org_address', + 'org_city', + 'org_state', + 'org_zip', + 'qp_status', + 'ams_mips_eligible', + 'qp_score_type', + 'error_message', + 'error_type') + + return(df |> dplyr::select(dplyr::any_of(cols))) + + } - df |> dplyr::select(dplyr::any_of(cols)) + if (type == 'apms') { + + apm_flags <- c( + 'Advanced APM' = 'apms_advanced', + 'Below Low Volume Threshold' ='apms_lvt', + 'Small Practice Status' = 'apms_lvt_small', + 'MIPS APM' = 'apms_mips_apm', + 'Extreme Hardship' = 'apms_ext_hardship', + 'Extreme Hardship (Performance Improvement)' = 'apms_ext_hardship_pi', + 'Extreme Hardship (Cost)' = 'apms_ext_hardship_cost', + 'Extreme Hardship (Improvement Activities)' = 'apms_ext_hardship_ia', + 'Extreme Hardship (Quality)' = 'apms_ext_hardship_quality' + ) + + return(results |> + dplyr::select(year, + npi, + org_name, + dplyr::contains('apms_')) |> + dplyr::rename(dplyr::any_of(apm_flags)) |> + tidyr::pivot_longer(cols = dplyr::any_of(names(apm_flags))) |> + dplyr::filter(!is.na(value)) |> + dplyr::filter(value == TRUE) |> + dplyr::mutate(value = NULL) |> + tidyr::nest(apms_status = name) |> + janitor::remove_empty(which = c("rows", "cols"))) + + } + + if (type == 'ind') { + + ind_flags <- c( + 'Hardship (Performance Improvement)' = 'ind_hardship_pi', + 'Reweighting (Performance Improvement)' = 'ind_reweight_pi', + 'Ambulatory Surgical Center' = 'ind_asc', + 'Extreme Hardship' = 'ind_ext_hardship', + 'Extreme Hardship (Quality)' = 'ind_ext_hardship_quality', + 'Extreme Hardship (Improvement Activities)' = 'ind_ext_hardship_ia', + 'Extreme Hardship (Performance Improvement)' = 'ind_ext_hardship_pi', + 'Extreme Hardship (Cost)' = 'ind_ext_hardship_cost', + 'Hospital-based Clinician' = 'ind_hospital_based', + 'HPSA Clinician' = 'ind_hpsa', + 'Improvement Activities Study' = 'ind_ia_study', + 'Has Opted In' = 'ind_opted_in', + 'Is Opt-In Eligible' = 'ind_opt_in_eligible', + 'MIPS Eligible Clinician' = 'ind_mips_switch', + 'Non-Patient Facing' = 'ind_non_patient', + 'Rural Clinician' = 'ind_rural', + 'Small Group Practitioner' = 'ind_small', + 'Below Low Volume Threshold' = 'ind_lvt_switch', + 'Has Payment Adjustment CCN' = 'ind_has_payment_adjustment_ccn', + 'Has Hospital Value-Based CCN' = 'ind_has_hospital_vbp_ccn', + 'Facility-based Clinician' = 'ind_facility', + 'Eligible: Individual' = 'ind_eligible_ind', + 'Eligible: Group' = 'ind_eligible_group', + 'Eligible: APM' = 'ind_eligible_apm', + 'Eligible: Virtual Group' = 'ind_eligible_virtual' + ) + + return(results |> + dplyr::select(year, + npi, + org_name, + dplyr::contains('ind_')) |> + dplyr::rename(dplyr::any_of(ind_flags)) |> + tidyr::pivot_longer(cols = dplyr::any_of(names(ind_flags))) |> + dplyr::filter(!is.na(value)) |> + dplyr::filter(value == TRUE) |> + dplyr::mutate(value = NULL) |> + tidyr::nest(ind_status = name) |> + janitor::remove_empty(which = c("rows", "cols"))) + + } + + if (type == 'grp') { + + grp_flags <- c( + 'Hardship (Performance Improvement)' = 'grp_hardship_pi', + 'Reweighting (Performance Improvement)' = 'grp_reweight_pi', + 'Ambulatory Surgical Center' = 'grp_asc', + 'Extreme Hardship' = 'grp_ext_hardship', + 'Extreme Hardship (Quality)' = 'grp_ext_hardship_quality', + 'Extreme Hardship (Improvement Activities)' = 'grp_ext_hardship_ia', + 'Extreme Hardship (Performance Improvement)' = 'grp_ext_hardship_pi', + 'Extreme Hardship (Cost)' = 'grp_ext_hardship_cost', + 'Hospital-based Clinician' = 'grp_hospital_based', + 'HPSA Clinician' = 'grp_hpsa', + 'Improvement Activities Study' = 'grp_ia_study', + 'Has Opted In' = 'grp_opted_in', + 'Is Opt-In Eligible' = 'grp_opt_in_eligible', + 'MIPS Eligible Clinician' = 'grp_mips_switch', + 'Non-Patient Facing' = 'grp_non_patient', + 'Rural Clinician' = 'grp_rural', + 'Small Group Practitioner' = 'grp_small', + 'Below Low Volume Threshold' = 'grp_lvt_switch', + 'Eligible: Group' = 'grp_eligible' + ) + + return(results |> + dplyr::select(year, + npi, + org_name, + dplyr::contains('grp_')) |> + dplyr::rename(dplyr::any_of(grp_flags)) |> + tidyr::pivot_longer(cols = dplyr::any_of(names(grp_flags))) |> + dplyr::filter(!is.na(value)) |> + dplyr::filter(value == TRUE) |> + dplyr::mutate(value = NULL) |> + tidyr::nest(grp_status = name) |> + janitor::remove_empty(which = c("rows", "cols"))) + + } } diff --git a/README.Rmd b/README.Rmd index d1276bcf..cc157c59 100644 --- a/README.Rmd +++ b/README.Rmd @@ -31,7 +31,7 @@ knitr::opts_chunk$set( > Providing easy access to [healthcare provider](https://en.wikipedia.org/wiki/Health_care_provider) data through publicly available APIs. -# :arrow_double_down: Installation +## :arrow_double_down: Installation You can install __`provider`__ from [GitHub](https://github.com/) with: @@ -40,7 +40,7 @@ You can install __`provider`__ from [GitHub](https://github.com/) with: pak::pak("andrewallenbruce/provider") ``` -# :beginner: Usage +## :beginner: Usage ```{r echo=TRUE, message=FALSE, warning=FALSE} library(provider) @@ -191,6 +191,14 @@ select(q, year, measures) |> unnest(measures) ``` +### `quality_eligibility()` + +```{r} +quality_eligibility(year = 2021, + npi = 1932365699) |> + dplyr::glimpse() +``` + ### `reassignments()` ```{r} diff --git a/README.md b/README.md index 0eff50f1..42ece90a 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ milestone](https://img.shields.io/github/milestones/progress/andrewallenbruce/pr > provider](https://en.wikipedia.org/wiki/Health_care_provider) data > through publicly available APIs. -# :arrow_double_down: Installation +## :arrow_double_down: Installation You can install **`provider`** from [GitHub](https://github.com/) with: @@ -32,7 +32,7 @@ You can install **`provider`** from [GitHub](https://github.com/) with: pak::pak("andrewallenbruce/provider") ``` -# :beginner: Usage +## :beginner: Usage ``` r library(provider) @@ -501,6 +501,16 @@ select(q, year, measures) |> #> 5 2021 Quality 1 0 #> 6 2021 Quality 117 0 +### `quality_eligibility()` + +``` r +quality_eligibility(year = 2021, + npi = 1932365699) |> + dplyr::glimpse() +``` + + #> Error in dplyr::select(results, year, npi, org_name, dplyr::contains("apms_")): object 'results' not found + ### `reassignments()` ``` r diff --git a/man/quality_eligibility.Rd b/man/quality_eligibility.Rd index 8bbc6a2b..0e94e55b 100644 --- a/man/quality_eligibility.Rd +++ b/man/quality_eligibility.Rd @@ -9,8 +9,8 @@ quality_eligibility( npi, tidy = TRUE, unnest = TRUE, - pivot = FALSE, - na.rm = FALSE, + pivot = TRUE, + na.rm = TRUE, ... ) } diff --git a/vignettes/articles/qpp.Rmd b/vignettes/articles/qpp.Rmd index d92594aa..b8233676 100644 --- a/vignettes/articles/qpp.Rmd +++ b/vignettes/articles/qpp.Rmd @@ -89,164 +89,19 @@ n ```{r} -s <- 2017:2023 |> +results <- 2017:2023 |> purrr::map(\(x) quality_eligibility(year = x, npi = 1043477615, na.rm = FALSE)) |> purrr::list_rbind() -``` - - -```{r} -apm_flags <- c( - 'Advanced APM' = 'apms_advanced', - 'Below Low Volume Threshold' ='apms_lvt', - 'Small Practice Status' = 'apms_lvt_small', - 'MIPS APM' = 'apms_mips_apm', - 'Extreme Hardship' = 'apms_ext_hardship', - 'Extreme Hardship (Performance Improvement)' = 'apms_ext_hardship_pi', - 'Extreme Hardship (Cost)' = 'apms_ext_hardship_cost', - 'Extreme Hardship (Improvement Activities)' = 'apms_ext_hardship_ia', - 'Extreme Hardship (Quality)' = 'apms_ext_hardship_quality' -) -apms <- s |> - dplyr::select(year, - npi, - org_name, - dplyr::contains('apms_')) |> - dplyr::rename(dplyr::any_of(apm_flags)) |> - tidyr::pivot_longer(cols = dplyr::any_of(names(apm_flags))) |> - dplyr::filter(!is.na(value)) |> - dplyr::filter(value == TRUE) |> - dplyr::mutate(value = NULL) |> - tidyr::nest(apms_status = name) |> - janitor::remove_empty(which = c("rows", "cols")) - -apms +results ``` -```{r} -# ind <- s |> -# dplyr::select(year, -# npi, -# org_name, -# dplyr::starts_with("ind.")) |> -# tidyr::pivot_longer(cols = c(ind.pi_hardship, -# ind.pi_reweighting, -# ind.ambulatory_surgical_center, -# ind.extreme_hardship, -# ind.extreme_hardship_reasons.quality, -# ind.extreme_hardship_reasons.ia, -# ind.extreme_hardship_reasons.pi, -# ind.extreme_hardship_reasons.cost, -# ind.hospital_based_clinician, -# ind.hpsa_clinician, -# ind.ia_study, -# ind.is_opted_in, -# ind.is_opt_in_eligible, -# ind.mips_eligible_switch, -# ind.non_patient_facing, -# ind.rural_clinician, -# ind.small_group_practitioner, -# ind.low_volume_switch, -# ind.has_payment_adjustment_ccn, -# ind.has_hospital_vbp_ccn, -# ind.facility_based, -# ind.eligible.individual, -# ind.eligible.group, -# ind.eligible.mips_apm, -# ind.eligible.virtual_group)) |> -# dplyr::filter(!is.na(value)) |> -# dplyr::filter(value == TRUE) |> -# dplyr::mutate(name = stringr::str_replace(name, "ind.pi_reweighting", "PI Reweighting"), -# name = stringr::str_replace(name, "ind.hospital_based_clinician", "Hospital-based Clinician"), -# name = stringr::str_replace(name, "ind.mips_eligible_switch", "MIPS Eligible Switch"), -# name = stringr::str_replace(name, "ind.eligible.individual", "Eligible: Individual"), -# name = stringr::str_replace(name, "ind.eligible.group", "Eligible: Group"), -# name = stringr::str_replace(name, "ind.eligible.mips_apm", "Eligible: MIPS APM"), -# name = stringr::str_replace(name, "ind.extreme_hardship", "Extreme Hardship"), -# name = stringr::str_replace(name, "ind.is_opt_in_eligible", "Opt-In Eligible"), -# name = stringr::str_replace(name, "ind.low_volume_switch", "Low Volume Switch"), -# value = NULL) |> -# dplyr::select(year, -# npi, -# org_name, -# ind.extreme_hardship_event = ind.extreme_hardship_event.type, -# ind.opt_in_date = ind.opt_in_decision_date, -# ind.hospital_vbp_name, -# ind.hospital_vbp_score, -# specialty_code = ind.specialty.code, -# specialty_description = ind.specialty.description, -# specialty_type = ind.specialty.type, -# specialty_category = ind.specialty.category, -# ind.extreme_hardship_sources, -# ind.lvt_code = ind.low_volume_status_reasons.code, -# ind.lvt_reasons = ind.low_volume_status_reasons.description, -# ind.status = name) |> -# tidyr::nest(ind.statuses = ind.status) |> -# janitor::remove_empty() -# -# ind -``` -```{r} -# grp <- s |> -# dplyr::select(year, -# npi, -# org_name, -# dplyr::starts_with("grp.")) |> -# tidyr::pivot_longer(cols = c(grp.pi_hardship, -# grp.pi_reweighting, -# grp.ambulatory_surgical_center, -# grp.extreme_hardship, -# grp.extreme_hardship_reasons.quality, -# grp.extreme_hardship_reasons.ia, -# grp.extreme_hardship_reasons.pi, -# grp.extreme_hardship_reasons.cost, -# grp.hospital_based_clinician, -# grp.hpsa_clinician, -# grp.ia_study, -# grp.is_opted_in, -# grp.is_opt_in_eligible, -# grp.mips_eligible_switch, -# grp.non_patient_facing, -# grp.rural_clinician, -# grp.small_group_practitioner, -# grp.low_volume_switch, -# grp.eligible)) |> -# dplyr::filter(!is.na(value)) |> -# dplyr::filter(value == TRUE) |> -# dplyr::mutate(name = stringr::str_replace(name, "grp.pi_hardship", "PI Hardship"), -# name = stringr::str_replace(name, "grp.pi_reweighting", "PI Reweighting"), -# name = stringr::str_replace(name, "grp.hospital_based_clinician", "Hospital-based Clinician"), -# name = stringr::str_replace(name, "grp.mips_eligible_switch", "MIPS Eligible Switch"), -# name = stringr::str_replace(name, "grp.eligible", "Eligible: Group"), -# value = NULL) |> -# dplyr::select(year, -# npi, -# org_name, -# grp.extreme_hardship_event = grp.extreme_hardship_event_type, -# grp.opt_in_date = grp.opt_in_decision_date, -# grp.status = name) |> -# tidyr::nest(grp.statuses = grp.status) |> -# janitor::remove_empty() -# -# grp -``` -```{r} -# nests <- dplyr::full_join(ind, grp) |> -# dplyr::full_join(apms) -# -# qpp_e <- top |> -# dplyr::left_join(nests) -# -# n |> -# dplyr::full_join(qpp_e) |> -# dplyr::glimpse() -``` +