- Patient Age -> Check ICD/HCPCS for Age Conflicts
- Provider Lag -> Days between DOS and DOR
- Balance -> Charges - (Payments + Adjustments)
- Coinsurance -> Charges - Allowed
Example Data
example |>
dplyr::mutate(
# base_inspmt = allowed * 0.8,
# base_ptres = allowed * 0.2,
all_pmt = payments / allowed,
balance = charges - (payments + adjustments),
.after = adjustments)
#> # A tibble: 33,225 × 19
#> claim_id dos dor dob icd .id order hcpcs units mod
#> <glue> <date> <date> <date> <chr> <int> <int> <chr> <int> <chr>
#> 1 00068-01 2022-08-16 2022-08-17 1990-02-24 F43.… 1 1 90837 1 NA
#> 2 00318-01 2022-08-16 2022-08-22 2012-10-24 F43.… 2 1 90832 1 NA
#> 3 01908-01 2022-08-16 2022-09-12 1985-01-09 F43.… 3 1 90834 1 95
#> 4 02295-01 2022-08-16 2022-08-16 1977-09-30 F43.… 4 1 90837 1 95
#> 5 04305-01 2022-08-16 2022-08-16 2006-01-07 A69.… 5 1 90791 1 NA
#> 6 04367-01 2022-08-16 2022-08-16 1980-07-24 F43.… 6 1 90791 1 AH
#> 7 04367-01 2022-08-16 2022-08-16 1980-07-24 F43.… 7 2 96130 1 AH
#> 8 04367-01 2022-08-16 2022-08-16 1980-07-24 F43.… 8 3 96131 1 AH
#> 9 04367-01 2022-08-16 2022-08-16 1980-07-24 F43.… 9 4 96136 1 AH
#> 10 04367-01 2022-08-16 2022-08-16 1980-07-24 F43.… 10 5 96137 3 AH
#> 11 04386-01 2022-08-16 2022-08-22 2011-08-22 F90.2 11 1 90834 1 NA
#> 12 05014-01 2022-08-16 2022-08-17 2003-09-09 F40.… 12 1 90837 1 NA
#> 13 06641-01 2022-08-16 2022-08-16 1987-07-21 F43.… 13 1 90791 1 NA
#> 14 06641-01 2022-08-16 2022-08-16 1987-07-21 F43.… 14 2 96130 1 NA
#> 15 06641-01 2022-08-16 2022-08-16 1987-07-21 F43.… 15 3 96131 1 NA
#> 16 06641-01 2022-08-16 2022-08-16 1987-07-21 F43.… 16 4 96136 1 NA
#> 17 06641-01 2022-08-16 2022-08-16 1987-07-21 F43.… 17 5 96137 3 NA
#> 18 07395-01 2022-08-16 2022-08-16 1994-11-18 F43.… 18 1 90837 1 NA
#> 19 09495-01 2022-08-16 2022-08-17 1960-07-02 F44.4 19 1 90837 1 NA
#> 20 09829-01 2022-08-16 2022-08-16 2004-12-27 F43.… 20 1 90837 1 NA
#> # ℹ 33,205 more rows
#> # ℹ 9 more variables: pos <chr>, charges <dbl>, allowed <dbl>, payments <dbl>,
#> # adjustments <dbl>, all_pmt <dbl>, balance <dbl>, class <fct>, adj <chr>
Place of Service
pos_trie <- triebeard::trie(
keys = search_pos()$pos_code,
values = .as$chr(search_pos()$pos_type))
example <- example |>
dplyr::mutate(
pos_type = triebeard::longest_match(pos_trie, pos),
.after = pos)
example |>
dplyr::summarise(
claim_lines = dplyr::n(),
pmt_mean = mean(payments, na.rm = TRUE),
pmt_sum = sum(payments, na.rm = TRUE),
.by = c(class, pos_type)) |>
dplyr::arrange(class, dplyr::desc(pos_type)) |>
gt::gt(
groupname_col = "class",
rowname_col = "pos_type",
row_group_as_column = TRUE
) |>
gt::fmt_currency(
columns = c(pmt_sum, pmt_mean),
decimals = 0)
claim_lines | pmt_mean | pmt_sum | ||
---|---|---|---|---|
BCBS | Non-Facility | 6035 | $114 | $685,291 |
Facility | 3580 | $85 | $304,899 | |
Commercial | Non-Facility | 3051 | $99 | $301,644 |
Facility | 505 | $87 | $44,172 | |
Cigna | Non-Facility | 2655 | $87 | $231,590 |
Facility | 859 | $76 | $65,283 | |
Medicaid | Non-Facility | 3656 | $113 | $412,056 |
Facility | 836 | $99 | $82,562 | |
Aetna | Non-Facility | 2071 | $98 | $203,674 |
Facility | 748 | $84 | $62,787 | |
Medicare | Non-Facility | 2717 | $103 | $280,001 |
Facility | 147 | $86 | $12,630 | |
UBH | Non-Facility | 2083 | $96 | $199,739 |
Facility | 483 | $83 | $40,300 | |
EAP | Non-Facility | 802 | $68 | $54,192 |
Facility | 89 | $60 | $5,297 | |
Med. Advantage | Non-Facility | 1511 | $88 | $132,343 |
Facility | 353 | $88 | $31,095 | |
Medicaid CMO | Non-Facility | 28 | $117 | $3,288 |
Facility | 185 | $109 | $20,205 | |
Tricare | Non-Facility | 534 | $102 | $54,251 |
Facility | 174 | $90 | $15,735 | |
VA | Non-Facility | 35 | $115 | $4,011 |
Facility | 74 | $88 | $6,486 | |
Beacon Health | Non-Facility | 3 | $204 | $613 |
Workers' Comp | Non-Facility | 6 | $252 | $1,512 |
Facility | 5 | $276 | $1,382 |
Categorize HCPCS
hcpcs_unq <- collapse::funique(example$hcpcs)
search_rbcs(hcpcs_code = hcpcs_unq) |>
dplyr::select(hcpcs_code:rbcs_family) |>
dplyr::left_join(
search_descriptions(hcpcs_code = hcpcs_unq,
hcpcs_desc_type = "Short") |>
dplyr::select(hcpcs_code, hcpcs_description),
by = dplyr::join_by(hcpcs_code)) |>
dplyr::select(hcpcs_code, rbcs_family, hcpcs_description) |>
gt::gt()
hcpcs_code | rbcs_family | hcpcs_description |
---|---|---|
90791 | Psychotherapy - Nongroup | PSYCH DIAGNOSTIC EVALUATION |
90792 | Psychotherapy - Nongroup | PSYCH DIAG EVAL W/MED SRVCS |
90832 | Psychotherapy - Nongroup | PSYTX W PT 30 MINUTES |
90834 | Psychotherapy - Nongroup | PSYTX W PT 45 MINUTES |
90837 | Psychotherapy - Nongroup | PSYTX W PT 60 MINUTES |
90839 | Psychotherapy - Nongroup | PSYTX CRISIS INITIAL 60 MIN |
90840 | Psychotherapy - Nongroup | PSYTX CRISIS EA ADDL 30 MIN |
90846 | Psychotherapy - Nongroup | FAMILY PSYTX W/O PT 50 MIN |
90847 | Psychotherapy - Nongroup | FAMILY PSYTX W/PT 50 MIN |
90853 | Psychotherapy - Group | GROUP PSYCHOTHERAPY |
96101 | No RBCS Family | NA |
96116 | No RBCS Family | NUBHVL XM PHYS/QHP 1ST HR |
96121 | No RBCS Family | NUBHVL XM PHY/QHP EA ADDL HR |
96130 | No RBCS Family | PSYCL TST EVAL PHYS/QHP 1ST |
96131 | No RBCS Family | PSYCL TST EVAL PHYS/QHP EA |
96132 | No RBCS Family | NRPSYC TST EVAL PHYS/QHP 1ST |
96133 | No RBCS Family | NRPSYC TST EVAL PHYS/QHP EA |
96136 | No RBCS Family | PSYCL/NRPSYC TST PHY/QHP 1ST |
96137 | No RBCS Family | PSYCL/NRPSYC TST PHY/QHP EA |
96138 | No RBCS Family | PSYCL/NRPSYC TECH 1ST |
96139 | No RBCS Family | PSYCL/NRPSYC TST TECH EA |
99203 | Office E&M - New | OFFICE O/P NEW LOW 30 MIN |
99203 | Office E&M - New | OFFICE O/P NEW LOW 30-44 MIN |
99204 | Office E&M - New | OFFICE O/P NEW MOD 45 MIN |
99204 | Office E&M - New | OFFICE O/P NEW MOD 45-59 MIN |
99205 | Office E&M - New | OFFICE O/P NEW HI 60 MIN |
99205 | Office E&M - New | OFFICE O/P NEW HI 60-74 MIN |
99213 | Office E&M - Established | OFFICE O/P EST LOW 20 MIN |
99213 | Office E&M - Established | OFFICE O/P EST LOW 20-29 MIN |
99214 | Office E&M - Established | OFFICE O/P EST MOD 30 MIN |
99214 | Office E&M - Established | OFFICE O/P EST MOD 30-39 MIN |
99215 | Office E&M - Established | OFFICE O/P EST HI 40 MIN |
99215 | Office E&M - Established | OFFICE O/P EST HI 40-54 MIN |
99404 | No RBCS Family | PREV MED CNSL INDIV APPRX 60 |
99404 | No RBCS Family | PREVENTIVE COUNSELING INDIV |
99441 | No RBCS Family | PHONE E/M PHYS/QHP 5-10 MIN |
99441 | Telephone Services | PHONE E/M PHYS/QHP 5-10 MIN |
Define Modifiers
mod_unq <- strsplit(toupper(example$mod[!is.na(example$mod)]), "-") |>
purrr::list_c() |>
collapse::funique()
search_modifiers(mod_code = mod_unq) |>
dplyr::select(mod_code, mod_description) |>
gt::gt()
mod_code | mod_description |
---|---|
25 | Significant, Separately Identifiable Evaluation and Management Service by the Same Physician or Other Qualified Health Care Professional on the Same Day of the Procedure or Other Service |
59 | Distinct Procedural Service |
95 | Synchronous Telemedicine Service Rendered Via a Real-Time Interactive Audio and Video Telecommunications System |
AH | Clinical psychologist |
AJ | Clinical social worker |
GT | Via interactive audio and video telecommunication systems |
HJ | Employee assistance program |
U8 | Medicaid level of care 8, as defined by each state |
UD | Medicaid level of care 13, as defined by each state |
example |>
dplyr::select(claim_id, dos, .id, order, hcpcs) |>
dplyr::group_by(claim_id) |>
dplyr::filter(dplyr::n() > 1) |>
dplyr::ungroup()
#> # A tibble: 9,160 × 5
#> claim_id dos .id order hcpcs
#> <glue> <date> <int> <int> <chr>
#> 1 04367-01 2022-08-16 6 1 90791
#> 2 04367-01 2022-08-16 7 2 96130
#> 3 04367-01 2022-08-16 8 3 96131
#> 4 04367-01 2022-08-16 9 4 96136
#> 5 04367-01 2022-08-16 10 5 96137
#> 6 06641-01 2022-08-16 13 1 90791
#> 7 06641-01 2022-08-16 14 2 96130
#> 8 06641-01 2022-08-16 15 3 96131
#> 9 06641-01 2022-08-16 16 4 96136
#> 10 06641-01 2022-08-16 17 5 96137
#> # ℹ 9,150 more rows
aocs <- search_aocs(hcpcs_code = hcpcs_unq) |>
tidyr::unnest(cols = aoc_complements)
aoc_pairs <- aocs |>
dplyr::filter(aoc_type == "Primary") |>
dplyr::select(
hcpcs_primary = hcpcs_code,
hcpcs_addon = aoc_complement)
ex_aoc <- example |>
dplyr::select(claim_id, dos, order, hcpcs) |>
dplyr::group_by(claim_id) |>
dplyr::filter(dplyr::n() > 1) |>
dplyr::ungroup()
prim <- ex_aoc |>
dplyr::filter(order == 1) |>
dplyr::select(claim_id, dos, hcpcs_primary = hcpcs)
addon <- ex_aoc |>
dplyr::filter(order != 1) |>
dplyr::select(claim_id, dos, order_addon = order, hcpcs_addon = hcpcs)
addon |>
dplyr::left_join(prim, by = dplyr::join_by(claim_id, dos)) |>
dplyr::filter(claim_id %in% c('46440-13', '16057-35', '57128-01'))
#> # A tibble: 2 × 5
#> claim_id dos order_addon hcpcs_addon hcpcs_primary
#> <glue> <date> <int> <chr> <chr>
#> 1 46440-13 2023-03-31 2 90840 90839
#> 2 57128-01 2023-12-18 2 96121 96116