Skip to contents
  • 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