Skip to content

Commit

Permalink
commit
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewallenbruce committed Oct 8, 2023
1 parent 4443827 commit 3ed6fa0
Show file tree
Hide file tree
Showing 10 changed files with 615 additions and 399 deletions.
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
export(affiliations)
export(bene_years)
export(beneficiaries)
export(betos_classification)
export(betos)
export(by_geography)
export(by_provider)
export(by_service)
Expand Down
135 changes: 135 additions & 0 deletions R/betos.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#' Restructured BETOS Classification System
#'
#' @description
#'
#' `betos_classification()` allows the user to group HCPCS codes into clinically
#' meaningful categories based on the original Berenson-Eggers Type of Service
#' (BETOS) classification. Users may use the RBCS to analyze trends and perform
#' other types of health services analytic work.
#'
#' ## BETOS
#' The Restructured BETOS Classification System (RBCS) is a taxonomy that allows
#' researchers to group healthcare service codes for Medicare Part B services
#' into clinically meaningful categories and subcategories. It is based on the
#' original Berenson-Eggers Type of Service (BETOS) classification created in
#' the 1980s, and includes notable updates such as Part B non-physician services.
#' The RBCS will undergo annual updates by a technical expert panel of
#' researchers and clinicians.
#'
#' The general framework for grouping service codes into the new RBCS taxonomy
#' largely follows the same structure of BETOS. Like BETOS, the RBCS groups
#' HCPCS codes into categories, subcategories, and families – with categories
#' as the most aggregate level and families as the more granular level.
#'
#' All Medicare Part B service codes, including non-physician services, are
#' assigned to a 6-character RBCS taxonomy code.
#'
#' Links:
#'
#' - [Restructured BETOS Classification System](https://data.cms.gov/provider-summary-by-type-of-service/provider-service-classifications/restructured-betos-classification-system)
#' - [Restructured BETOS Classification System Data Dictionary](https://data.cms.gov/resources/restructured-betos-classification-system-data-dictionary)
#'
#' *Update Frequency:* **Annually**
#'
#' @param hcpcs_code < *character* > HCPCS or CPT code
#' @param category < *character* > RBCS Category Description
#' @param subcategory < *character* > RBCS Subcategory Description
#' @param family < *character* > RBCS Family Description
#' @param procedure < *character* > Whether the HCPCS code is a Major (`"M"`),
#' Other (`"O"`), or Non-Procedure code (`"N"`).
#' @param tidy < *boolean* > Tidy output; default is `TRUE`
#'
#' @return A [tibble][tibble::tibble-package] with the columns:
#'
#' |**Field** |**Description** |
#' |:------------------|:--------------------------------------------|
#' |`hcpcs_code` |HCPCS or CPT code |
#' |`rbcs_id` |RBCS Identifier |
#' |`category` |RBCS Category |
#' |`subcategory` |RBCS Subcategory |
#' |`family` |RBCS Family |
#' |`procedure` |RBCS Major Procedure Indicator |
#' |`hcpcs_start_date` |Date HCPCS Code was added |
#' |`hcpcs_end_date` |Date HCPCS Code was no longer effective |
#' |`rbcs_start_date` |Earliest Date that the RBCS ID was effective |
#' |`rbcs_end_date` |Latest Date that the RBCS ID can be applied |
#'
#' @examplesIf interactive()
#' betos(hcpcs_code = "0001U")
#' betos(category = "Test")
#' betos(subcategory = "General Laboratory")
#' betos(family = "Immunoassay")
#' betos(procedure = "M")
#' @autoglobal
#' @export
betos <- function(hcpcs_code = NULL,
category = NULL,
subcategory = NULL,
family = NULL,
procedure = NULL,
tidy = TRUE) {

args <- dplyr::tribble(
~param, ~arg,
"HCPCS_Cd", hcpcs_code,
"RBCS_Cat_Desc", category,
"RBCS_Subcat_Desc", subcategory,
"RBCS_Family_Desc", family,
"RBCS_Major_Ind", procedure)

response <- httr2::request(build_url("bet", args)) |> httr2::req_perform()

if (isTRUE(vctrs::vec_is_empty(response$body))) {

cli_args <- dplyr::tribble(
~x, ~y,
"hcpcs_code", hcpcs_code,
"category", category,
"subcategory", subcategory,
"family", family,
"procedure", procedure) |>
tidyr::unnest(cols = c(y))

format_cli(cli_args)

return(invisible(NULL))

}

results <- httr2::resp_body_json(response, simplifyVector = TRUE)

if (tidy) {
results <- tidyup(results) |>
dplyr::mutate(dplyr::across(dplyr::everything(), stringr::str_squish),
dplyr::across(dplyr::contains("dt"), anytime::anydate),
rbcs_major_ind = dplyr::case_match(rbcs_major_ind,
"N" ~ "Non-procedure",
"M" ~ "Major",
"O" ~ "Other")) |>
betos_cols()
}
return(results)
}

#' @param df data frame
#' @autoglobal
#' @noRd
betos_cols <- function(df) {

cols <- c('hcpcs_code' = 'hcpcs_cd',
'rbcs_id',
# 'rbcs_cat',
'category' = 'rbcs_cat_desc',
# 'rbcs_cat_subcat',
'subcategory' = 'rbcs_subcat_desc',
# 'rbcs_fam_numb',
'family' = 'rbcs_family_desc',
'procedure' = 'rbcs_major_ind',
'hcpcs_start_date' = 'hcpcs_cd_add_dt',
'hcpcs_end_date' = 'hcpcs_cd_end_dt',
'rbcs_start_date' = 'rbcs_assignment_eff_dt',
'rbcs_end_date' = 'rbcs_assignment_end_dt')

df |> dplyr::select(dplyr::all_of(cols))

}
5 changes: 3 additions & 2 deletions R/globals.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ utils::globalVariables(c(
"state.name", # <beneficiaries>
"y", # <beneficiaries>
"bene_fips_cd", # <beneficiaries>
"y", # <betos>
"rbcs_major_ind", # <betos>
"year", # <change_year>
":=", # <change_year>
"state.abb", # <cc_specific>
Expand Down Expand Up @@ -281,8 +283,6 @@ utils::globalVariables(c(
"classification", # <download_nucc_csv>
"specialization", # <download_nucc_csv>
"code", # <download_nucc_csv>
"y", # <betos_classification>
"rbcs_major_ind", # <betos_classification>
"distro", # <by_provider>
"y", # <by_provider>
"rndrng_prvdr_crdntls", # <by_provider>
Expand All @@ -306,6 +306,7 @@ utils::globalVariables(c(
"x", # <by_geography>
"y", # <by_geography>
"distro", # <by_geography>
"hcpcs_desc", # <by_geography>
"hcpcs_drug_ind", # <by_geography>
"place_of_srvc", # <by_geography>
"category", # <by_geography>
Expand Down
12 changes: 6 additions & 6 deletions R/hospitals.R
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#' enrollment identifier; begins with capital "O"
#' @param enroll_state < *character* > Hospital’s enrollment state
#' @param specialty_code < *character* > Enrollment specialty type code
#' @param pac_id_org < *integer* > 10-digit organizational/group provider
#' @param pac_org < *integer* > 10-digit organizational/group provider
#' associate-level control identifier
#' @param organization < *character* > Hospital’s legal business name
#' @param doing_business_as < *character* > Hospital’s doing-business-as name
Expand Down Expand Up @@ -63,7 +63,7 @@
#' @seealso [clinicians()], [providers()], [affiliations()]
#'
#' @examples
#' hospitals(pac_id_org = 6103733050)
#' hospitals(pac_org = 6103733050)
#'
#' hospitals(state = "GA", reh_conversion = TRUE)
#' @autoglobal
Expand All @@ -73,7 +73,7 @@ hospitals <- function(npi = NULL,
enroll_id_org = NULL,
enroll_state = NULL,
specialty_code = NULL,
pac_id_org = NULL,
pac_org = NULL,
organization = NULL,
doing_business_as = NULL,
city = NULL,
Expand All @@ -99,7 +99,7 @@ hospitals <- function(npi = NULL,
na.rm = TRUE) {

if (!is.null(npi)) {npi <- npi_check(npi)}
if (!is.null(pac_id_org)) {pac_id_org <- pac_check(pac_id_org)}
if (!is.null(pac_org)) {pac_org <- pac_check(pac_org)}
if (!is.null(zip)) {zip <- as.character(zip)}
if (!is.null(facility_ccn)) {facility_ccn <- as.character(facility_ccn)}
if (!is.null(enroll_id_org)) {enroll_check(enroll_id_org)}
Expand Down Expand Up @@ -129,7 +129,7 @@ hospitals <- function(npi = NULL,
"ENROLLMENT ID", enroll_id_org,
"ENROLLMENT STATE", enroll_state,
"PROVIDER TYPE CODE", specialty_code,
"ASSOCIATE ID", pac_id_org,
"ASSOCIATE ID", pac_org,
"ORGANIZATION NAME", organization,
"DOING BUSINESS AS NAME", doing_business_as,
"CITY", city,
Expand Down Expand Up @@ -163,7 +163,7 @@ hospitals <- function(npi = NULL,
"enroll_id_org", enroll_id_org,
"enroll_state", enroll_state,
"specialty_code", specialty_code,
"pac_id_org", pac_id_org,
"pac_org", pac_org,
"organization", organization,
"doing_business_as", doing_business_as,
"city", city,
Expand Down
129 changes: 0 additions & 129 deletions R/taxonomy_crosswalk.R
Original file line number Diff line number Diff line change
Expand Up @@ -262,132 +262,3 @@ download_nucc_csv <- function() {
taxonomy = code)
return(x)
}

#' Restructured BETOS Classification System
#'
#' @description
#'
#' `betos_classification()` allows the user to group HCPCS codes into clinically
#' meaningful categories based on the original Berenson-Eggers Type of Service
#' (BETOS) classification. Users may use the RBCS to analyze trends and perform
#' other types of health services analytic work.
#'
#' ## BETOS
#' The Restructured BETOS Classification System (RBCS) is a taxonomy that allows
#' researchers to group healthcare service codes for Medicare Part B services
#' into clinically meaningful categories and subcategories. It is based on the
#' original Berenson-Eggers Type of Service (BETOS) classification created in
#' the 1980s, and includes notable updates such as Part B non-physician services.
#' The RBCS will undergo annual updates by a technical expert panel of
#' researchers and clinicians.
#'
#' The general framework for grouping service codes into the new RBCS taxonomy
#' largely follows the same structure of BETOS. Like BETOS, the RBCS groups
#' HCPCS codes into categories, subcategories, and families – with categories
#' as the most aggregate level and families as the more granular level.
#'
#' All Medicare Part B service codes, including non-physician services, are
#' assigned to a 6-character RBCS taxonomy code.
#'
#' Links:
#' - [Restructured BETOS Classification System](https://data.cms.gov/provider-summary-by-type-of-service/provider-service-classifications/restructured-betos-classification-system)
#' - [Restructured BETOS Classification System Data Dictionary](https://data.cms.gov/resources/restructured-betos-classification-system-data-dictionary)
#'
#' *Update Frequency:* **Annually**
#'
#' @param hcpcs_code < *character* > HCPCS or CPT code
#' @param category < *character* > RBCS Category Description
#' @param subcategory < *character* > RBCS Subcategory Description
#' @param family < *character* > RBCS Family Description
#' @param procedure < *character* > Whether the HCPCS code is a Major (`"M"`),
#' Other (`"O"`), or non-procedure code (`"N"`).
#' @param tidy < *boolean* > Tidy output; default is `TRUE`
#'
#' @return A [tibble][tibble::tibble-package] with the columns:
#'
#' |**Field** |**Description** |
#' |:----------------------|:--------------------------------------------------|
#' |`specialty_code` |Code that corresponds to the Medicare specialty |
#' |`specialty_description`|Description of the Medicare provider/Supplier Type |
#' |`taxonomy_code` |Provider's taxonomy code |
#' |`taxonomy_description` |Description of the taxonomy code |
#'
#' @examplesIf interactive()
#' betos_classification(hcpcs_code = "0001U")
#' betos_classification(category = "Test")
#' betos_classification(subcategory = "General Laboratory")
#' betos_classification(family = "Immunoassay")
#' betos_classification(procedure = "M")
#' @autoglobal
#' @export
betos_classification <- function(hcpcs_code = NULL,
category = NULL,
subcategory = NULL,
family = NULL,
procedure = NULL,
tidy = TRUE) {

args <- dplyr::tribble(
~param, ~arg,
"HCPCS_Cd", hcpcs_code,
"RBCS_Cat_Desc", category,
"RBCS_Subcat_Desc", subcategory,
"RBCS_Family_Desc", family,
"RBCS_Major_Ind", procedure)

response <- httr2::request(build_url("bet", args)) |> httr2::req_perform()

if (isTRUE(vctrs::vec_is_empty(response$body))) {

cli_args <- dplyr::tribble(
~x, ~y,
"hcpcs_code", hcpcs_code,
"category", category,
"subcategory", subcategory,
"family", family,
"procedure", procedure) |>
tidyr::unnest(cols = c(y))

format_cli(cli_args)

return(invisible(NULL))

}

results <- httr2::resp_body_json(response, simplifyVector = TRUE)

if (tidy) {
results <- tidyup(results) |>
dplyr::mutate(dplyr::across(dplyr::everything(), stringr::str_squish),
dplyr::across(dplyr::contains("dt"), anytime::anydate),
rbcs_major_ind = dplyr::case_match(rbcs_major_ind,
"N" ~ "Non-procedure",
"M" ~ "Major",
"O" ~ "Other")) |>
betos_cols()
}
return(results)
}

#' @param df data frame
#' @autoglobal
#' @noRd
betos_cols <- function(df) {

cols <- c('hcpcs_code' = 'hcpcs_cd',
'rbcs_id',
# 'rbcs_cat',
'category' = 'rbcs_cat_desc',
# 'rbcs_cat_subcat',
'subcategory' = 'rbcs_subcat_desc',
# 'rbcs_fam_numb',
'family' = 'rbcs_family_desc',
'procedure' = 'rbcs_major_ind',
'hcpcs_effective_date' = 'hcpcs_cd_add_dt',
'hcpcs_end_date' = 'hcpcs_cd_end_dt',
'rbcs_effective_date' = 'rbcs_assignment_eff_dt',
'rbcs_end_date' = 'rbcs_assignment_end_dt')

df |> dplyr::select(dplyr::all_of(cols))

}
Loading

0 comments on commit 3ed6fa0

Please sign in to comment.