Primary Analysis

Mengyu

2025-04-25

0. Basic Info

Cohort: - Referred Patients between 18 and 80 years old who started dialysis in Network 6 from 2015 to 2021 - Preemptive listed patients were excluded - Preemptive referrals were excluded

Outcome: Referred to transplant center outside or inside state

yn_factor <- function(x) factor(x, levels = c(0, 1), labels = c("No", "Yes")) 

pt <- readRDS("../data/dialysis_cohort.rds") %>%
  filter(referral_date >= FIRSTDIAL) %>%
  mutate(referred_to_tx_outside_state = factor(ifelse(df_state != substr(CTR_CD, 1, 2), "Yes", "No"), levels = c("No", "Yes"))) %>%
  mutate_at(c("nearest_tx_outside_state", "adjacent_to_boundary", "nearest_state_boundary_within_10m", "tx_outside_state_driving_time"), yn_factor) %>%
  rowwise() %>%
  mutate(como_na = sum(is.na(COMO_CHF), is.na(COMO_ASHD), is.na(COMO_OTHCARD), is.na(COMO_CVATIA), is.na(COMO_PVD), is.na(COMO_HTN), is.na(COMO_DIABETES), is.na(COMO_COPD), is.na(COMO_CANC), is.na(COMO_TOBAC)),
         como_cnt = sum(COMO_CHF == "Y", COMO_ASHD == "Y", COMO_OTHCARD == "Y", COMO_CVATIA == "Y", COMO_PVD == "Y", COMO_HTN == "Y", COMO_DIABETES == "Y", COMO_COPD == "Y", COMO_CANC == "Y", COMO_TOBAC == "Y", na.rm = T),
         como_cnt = ifelse(como_na == 10, NA, como_cnt),
         ADI_NATRANK = ifelse(ADI_NATRANK %in% c("PH", "GQ", "PH-GQ", "QDI"), NA, as.numeric(ADI_NATRANK))) %>% 
  select(referred_to_tx_outside_state, insurance_medevid_first, adjacent_to_boundary, male, INC_AGE, RACE, HISPANIC, EMPCUR, NEPHCARE, TRCERT, COMO_INST, como_cnt, inambulate, median_household_income, public_transportation_pct, ADI_NATRANK) 

desc_pt <- pt %>% 
  filter(!is.na(referred_to_tx_outside_state)) %>%
  filter(!is.na(insurance_medevid_first)) %>%
  mutate(median_household_income = median_household_income / 10000)

1. Descriptive tables

var_label <- list(
  "referred_to_tx_outside_state" = "Referred to transplant outside state",
  "adjacent_to_boundary" = "Located in the county adjacent to state boundary",
  "insurance_medevid_first" = "Insurance type",
  "male" = "Sex",
  "INC_AGE" = "Age at Dialysis Start",
  "RACE" = "Race", 
  "HISPANIC" = "Ethnicity", 
  "EMPCUR" = "Employment Status", 
  "NEPHCARE" = "Prior Nephrology Care", 
  "TRCERT" = "Patient Completing Home Dialysis Training", 
  "COMO_INST" = "Institutionalized", 
  "como_cnt" = "Number of Comorbidities",
  "inambulate" = "Inability to Ambulate",
  "median_household_income" = "Median Household Income (×$10k)",
  "public_transportation_pct" = "Public transportation to Work (%)", 
  "ADI_NATRANK" = "ADI National Rank"
  )

desc_pt %>%
  tbl_summary(by = adjacent_to_boundary,
              type = list(all_continuous() ~ "continuous2",
                          all_dichotomous() ~ "categorical"),
              statistic = all_continuous() ~ c("{mean}±{sd}", "{median} ({p25}, {p75})"),
              label = var_label
              ) %>%
  modify_spanning_header(all_stat_cols() ~ "**Located in the county adjacent to state boundary**") %>%
  add_overall()
Characteristic Overall
N = 23,845
1
Located in the county adjacent to state boundary
No
N = 17,094
1
Yes
N = 6,751
1
Referred to transplant outside state


    No 21,542 (90%) 15,930 (93%) 5,612 (83%)
    Yes 2,303 (9.7%) 1,164 (6.8%) 1,139 (17%)
Insurance type


    TM w/o MDCD 6,834 (29%) 4,889 (29%) 1,945 (29%)
    TM w/ MDCD 1,783 (7.5%) 1,266 (7.4%) 517 (7.7%)
    MA w/o MDCD 2,017 (8.5%) 1,426 (8.3%) 591 (8.8%)
    MA w/ MDCD 387 (1.6%) 272 (1.6%) 115 (1.7%)
    Employer 4,547 (19%) 3,303 (19%) 1,244 (18%)
    Other 2,021 (8.5%) 1,451 (8.5%) 570 (8.4%)
    None 6,256 (26%) 4,487 (26%) 1,769 (26%)
Sex


    Male 14,037 (59%) 9,943 (58%) 4,094 (61%)
    Female 9,808 (41%) 7,151 (42%) 2,657 (39%)
Age at Dialysis Start


    Mean±SD 55±13 55±13 55±13
    Median (Q1, Q3) 56 (46, 65) 57 (46, 65) 56 (46, 65)
Race


    White 8,312 (35%) 5,710 (33%) 2,602 (39%)
    Black 14,833 (62%) 10,911 (64%) 3,922 (58%)
    AIAN 127 (0.5%) 34 (0.2%) 93 (1.4%)
    Asian 410 (1.7%) 324 (1.9%) 86 (1.3%)
    NHPI 105 (0.4%) 79 (0.5%) 26 (0.4%)
    Other 51 (0.2%) 32 (0.2%) 19 (0.3%)
    Unknown 7 4 3
Ethnicity


    Hispanic 936 (3.9%) 675 (3.9%) 261 (3.9%)
    Non-Hispanic 22,909 (96%) 16,419 (96%) 6,490 (96%)
Employment Status


    Employed 3,842 (16%) 2,797 (16%) 1,045 (15%)
    Other 20,003 (84%) 14,297 (84%) 5,706 (85%)
Prior Nephrology Care


    No 4,935 (21%) 3,712 (22%) 1,223 (18%)
    Yes 15,505 (65%) 10,718 (63%) 4,787 (71%)
    Unknown 3,405 (14%) 2,664 (16%) 741 (11%)
Patient Completing Home Dialysis Training


    No 40 (0.2%) 27 (0.2%) 13 (0.2%)
    Yes 3,164 (13%) 2,244 (13%) 920 (14%)
    Unknown 20,641 (87%) 14,823 (87%) 5,818 (86%)
Institutionalized


    No 23,444 (98%) 16,813 (98%) 6,631 (98%)
    Yes 401 (1.7%) 281 (1.6%) 120 (1.8%)
Number of Comorbidities


    Mean±SD 2±1 2±1 2±1
    Median (Q1, Q3) 2 (1, 3) 2 (1, 3) 2 (1, 3)
Inability to Ambulate


    No 23,305 (98%) 16,712 (98%) 6,593 (98%)
    Yes 540 (2.3%) 382 (2.2%) 158 (2.3%)
Median Household Income (×$10k)


    Mean±SD 6.27±2.10 6.43±2.16 5.87±1.88
    Median (Q1, Q3) 5.90 (4.84, 7.31) 5.97 (4.94, 7.56) 5.56 (4.62, 6.65)
    Unknown 336 227 109
Public transportation to Work (%)


    Mean±SD 1.37±3.10 1.59±3.43 0.82±1.95
    Median (Q1, Q3) 0.34 (0.01, 1.24) 0.41 (0.03, 1.57) 0.18 (0.00, 0.95)
    Unknown 288 201 87
ADI National Rank


    Mean±SD 67±22 65±22 70±21
    Median (Q1, Q3) 70 (51, 84) 69 (50, 82) 70 (56, 88)
    Unknown 630 481 149
1 n (%)
desc_pt %>%
  select(referred_to_tx_outside_state, insurance_medevid_first) %>%
  tbl_summary(by = referred_to_tx_outside_state,
              type = list(all_continuous() ~ "continuous2",
                          all_dichotomous() ~ "categorical"),
              percent = "row",
              digits = list(all_continuous() ~ 1),
              statistic = all_continuous() ~ c("{mean}±{sd}", "{median} ({p25}, {p75})"),
              label = var_label
              ) %>%
  modify_spanning_header(all_stat_cols() ~ "**Referred to transplant outside state**") 
Characteristic
Referred to transplant outside state
No
N = 21,542
1
Yes
N = 2,303
1
Insurance type

    TM w/o MDCD 6,114 (89%) 720 (11%)
    TM w/ MDCD 1,609 (90%) 174 (9.8%)
    MA w/o MDCD 1,834 (91%) 183 (9.1%)
    MA w/ MDCD 352 (91%) 35 (9.0%)
    Employer 4,080 (90%) 467 (10%)
    Other 1,819 (90%) 202 (10.0%)
    None 5,734 (92%) 522 (8.3%)
1 n (%)

2. Fit models

male, INC_AGE, RACE, HISPANIC, EMPCUR, NEPHCARE, TRCERT, COMO_INST, COMO_INAMB, the number of COMOs (CHF ASHD OTH_CARDIAC ASCVD PVD HYPER DIABETES COPD CANC SMOKING), census - % of public transportation, census - median household income

or_tbl <- function(m) {
  m2 <- m %>% 
    tbl_regression(exponentiate = T, 
                   label = var_label) %>% 
    bold_p() %>%
    modify_table_styling(columns = c(estimate),
                         rows = reference_row == TRUE, 
                         missing_symbol = "Ref.")
  return(m2)
}

clean_tbl <- function(tbl, varname) {
  varname2 <- str_to_title(str_replace_all(varname, "_", " "))
  tbl_clean <- tbl %>% 
    rename_with(~ "At", all_of(varname)) %>%
    mutate_at(vars(AME, lower, upper, p), ~ round(., 5)) %>%
    mutate(Insurance = paste0(substr(factor, nchar("insurance_medevid_first") + 1, nchar(factor)), " vs. TM w/o MDCD"), 
           Insurance = factor(Insurance, levels = paste0(c("TM w/ MDCD", "MA w/o MDCD", "MA w/ MDCD", "Employer", "Other", "None"), " vs. TM w/o MDCD")),
           At = factor(At, levels = c("No", "Yes"), labels = c(paste0(varname2, ": No"), paste0(varname2, ": Yes"))),
           CI = paste0("(", lower, ", ", upper, ")")) %>%
    select(At, Insurance, AME, CI, p) %>%
    arrange(Insurance)
  return(tbl_clean)
}

covars <- "ADI_NATRANK + male + INC_AGE + RACE + HISPANIC + EMPCUR + NEPHCARE + TRCERT + COMO_INST + como_cnt + inambulate + median_household_income + public_transportation_pct"
# whether the dialysis facility is located in the county adjacent to state boundary
m1_c <- glm(referred_to_tx_outside_state ~ adjacent_to_boundary + insurance_medevid_first, 
            data = desc_pt, family = binomial) 
m1_a <- glm(as.formula(paste("referred_to_tx_outside_state ~ adjacent_to_boundary + insurance_medevid_first + ", covars)), 
            data = desc_pt, family = binomial) 
m1_in_c <- glm(referred_to_tx_outside_state ~ adjacent_to_boundary * insurance_medevid_first, 
               data = desc_pt, family = binomial)
m1_in_a <- glm(as.formula(paste("referred_to_tx_outside_state ~ adjacent_to_boundary * insurance_medevid_first + ", covars)), , 
               data = desc_pt, family = binomial) 

2.1 w/o interaction

tbl_merge(
  tbls = list(or_tbl(m1_c), or_tbl(m1_a)),
  tab_spanner = c("**Crude**", "**Adjusted**")
)
Characteristic
Crude
Adjusted
OR 95% CI p-value OR 95% CI p-value
Located in the county adjacent to state boundary





    No Ref.
Ref.
    Yes 2.78 2.55, 3.04 <0.001 2.39 2.18, 2.62 <0.001
Insurance type





    TM w/o MDCD Ref.
Ref.
    TM w/ MDCD 0.91 0.76, 1.08 0.3 0.90 0.75, 1.08 0.3
    MA w/o MDCD 0.84 0.70, 0.99 0.041 0.88 0.74, 1.05 0.2
    MA w/ MDCD 0.83 0.57, 1.17 0.3 0.83 0.57, 1.19 0.3
    Employer 0.98 0.87, 1.11 0.8 1.00 0.86, 1.16 >0.9
    Other 0.94 0.80, 1.11 0.5 0.93 0.77, 1.11 0.4
    None 0.77 0.68, 0.87 <0.001 0.78 0.67, 0.90 <0.001
ADI National Rank


1.01 1.00, 1.01 <0.001
Sex





    Male


Ref.
    Female


1.01 0.93, 1.11 0.8
Age at Dialysis Start


1.00 1.00, 1.00 >0.9
Race





    White


Ref.
    Black


0.94 0.85, 1.04 0.2
    AIAN


0.84 0.48, 1.39 0.5
    Asian


0.44 0.25, 0.72 0.002
    NHPI


1.43 0.71, 2.62 0.3
    Other


1.35 0.55, 2.89 0.5
Ethnicity





    Hispanic


Ref.
    Non-Hispanic


1.52 1.16, 2.02 0.003
Employment Status





    Employed


Ref.
    Other


1.00 0.87, 1.15 >0.9
Prior Nephrology Care





    No


Ref.
    Yes


1.06 0.94, 1.19 0.4
    Unknown


1.10 0.94, 1.29 0.2
Patient Completing Home Dialysis Training





    No


Ref.
    Yes


1.34 0.47, 5.63 0.6
    Unknown


1.25 0.44, 5.23 0.7
Institutionalized





    No


Ref.
    Yes


0.92 0.61, 1.33 0.7
Number of Comorbidities


0.94 0.91, 0.98 0.003
Inability to Ambulate





    No


Ref.
    Yes


0.69 0.47, 0.98 0.046
Median Household Income (×$10k)


0.94 0.91, 0.96 <0.001
Public transportation to Work (%)


0.94 0.92, 0.96 <0.001
Abbreviations: CI = Confidence Interval, OR = Odds Ratio

2.2 w/ interaction

AME

cplot(m1_in_c, "insurance_medevid_first", main = "Crude Model") 

cplot(m1_in_a, "insurance_medevid_first", main = "Adjusted Model")

crude <- summary(margins(m1_in_c)) %>%
  mutate(variable = as.character(factor),
         cAME_CI = paste0(sprintf("%.4f", round(AME, 4)), " (", sprintf("%.4f", round(lower, 4)), ", ", sprintf("%.4f", round(upper, 4)), ")")) %>%
  select(variable, cAME_CI)

adjusted <- summary(margins(m1_in_a)) %>%
  mutate(variable = as.character(factor),
         aAME_CI = paste0(sprintf("%.4f", round(AME, 4)), " (", sprintf("%.4f", round(lower, 4)), ", ", sprintf("%.4f", round(upper, 4)), ")")) %>%
  select(variable, aAME_CI)

crude %>% 
  left_join(adjusted, by = "variable") %>% 
  mutate(Variable = case_when(startsWith(variable, "adjacent_to_boundary") ~ "Located in the county adjacent to state boundary",
                              startsWith(variable, "insurance_medevid_first") ~ "Insurance type"),
         Comparison = case_when(variable == "adjacent_to_boundaryYes" ~ "Yes vs. No",
                                variable == "insurance_medevid_firstEmployer" ~ "Employer vs. TM w/o MDCD",
                                variable == "insurance_medevid_firstMA w/ MDCD" ~ "MA w/ MDCD vs. TM w/o MDCD",
                                variable == "insurance_medevid_firstMA w/o MDCD" ~ "MA w/o MDCD vs. TM w/o MDCD",
                                variable == "insurance_medevid_firstNone" ~ "None vs. TM w/o MDCD",
                                variable == "insurance_medevid_firstOther" ~ "Other vs. TM w/o MDCD",
                                variable == "insurance_medevid_firstTM w/ MDCD" ~ "TM w/ MDCD vs. TM w/o MDCD"),
         id = row_number()) %>%
  arrange(Variable, id) %>%
  select(Variable, Comparison, cAME_CI, aAME_CI) %>%
  kable(col.names = c("Variable", "Comparison", "Crude AME (95% CI)", "Adjusted AME (95% CI)"), 
        caption = "Average Marginal Effects of Insurance Type on Referral to Transplant Center Outside State") 
Average Marginal Effects of Insurance Type on Referral to Transplant Center Outside State
Variable Comparison Crude AME (95% CI) Adjusted AME (95% CI)
Insurance type Employer vs. TM w/o MDCD -0.0015 (-0.0128, 0.0099) 0.0001 (-0.0137, 0.0138)
Insurance type MA w/ MDCD vs. TM w/o MDCD -0.0170 (-0.0450, 0.0111) -0.0163 (-0.0447, 0.0122)
Insurance type MA w/o MDCD vs. TM w/o MDCD -0.0161 (-0.0300, -0.0021) -0.0117 (-0.0261, 0.0028)
Insurance type None vs. TM w/o MDCD -0.0218 (-0.0317, -0.0119) -0.0208 (-0.0325, -0.0090)
Insurance type Other vs. TM w/o MDCD -0.0052 (-0.0200, 0.0096) -0.0065 (-0.0221, 0.0092)
Insurance type TM w/ MDCD vs. TM w/o MDCD -0.0084 (-0.0237, 0.0069) -0.0088 (-0.0245, 0.0070)
Located in the county adjacent to state boundary Yes vs. No 0.1006 (0.0909, 0.1103) 0.0829 (0.0732, 0.0925)

Insurance at Distance Status

summary(margins(m1_in_c, at = list(adjacent_to_boundary = c("No", "Yes")), variables = "insurance_medevid_first")) %>%
  clean_tbl("adjacent_to_boundary") %>%
  kable(caption = "Crude Model")
Crude Model
At Insurance AME CI p
Adjacent To Boundary: No TM w/ MDCD vs. TM w/o MDCD -0.01383 (-0.02951, 0.00185) 0.08391
Adjacent To Boundary: Yes TM w/ MDCD vs. TM w/o MDCD 0.00544 (-0.03123, 0.04212) 0.77113
Adjacent To Boundary: No MA w/o MDCD vs. TM w/o MDCD -0.03600 (-0.0491, -0.0229) 0.00000
Adjacent To Boundary: Yes MA w/o MDCD vs. TM w/o MDCD 0.03441 (-0.00204, 0.07086) 0.06430
Adjacent To Boundary: No MA w/ MDCD vs. TM w/o MDCD -0.03606 (-0.06162, -0.0105) 0.00569
Adjacent To Boundary: Yes MA w/ MDCD vs. TM w/o MDCD 0.03136 (-0.04361, 0.10634) 0.41231
Adjacent To Boundary: No Employer vs. TM w/o MDCD -0.00722 (-0.0189, 0.00447) 0.22627
Adjacent To Boundary: Yes Employer vs. TM w/o MDCD 0.01303 (-0.01409, 0.04016) 0.34635
Adjacent To Boundary: No Other vs. TM w/o MDCD -0.00919 (-0.02444, 0.00605) 0.23730
Adjacent To Boundary: Yes Other vs. TM w/o MDCD 0.00505 (-0.03023, 0.04032) 0.77915
Adjacent To Boundary: No None vs. TM w/o MDCD -0.02023 (-0.03053, -0.00992) 0.00012
Adjacent To Boundary: Yes None vs. TM w/o MDCD -0.02562 (-0.04892, -0.00232) 0.03119
summary(margins(m1_in_a, at = list(adjacent_to_boundary = c("No", "Yes")), variables = "insurance_medevid_first")) %>%
  clean_tbl("adjacent_to_boundary") %>%
  kable(caption = "Adjusted Model")
Adjusted Model
At Insurance AME CI p
Adjacent To Boundary: No TM w/ MDCD vs. TM w/o MDCD -0.01528 (-0.03167, 0.00112) 0.06782
Adjacent To Boundary: Yes TM w/ MDCD vs. TM w/o MDCD 0.00648 (-0.02872, 0.04168) 0.71839
Adjacent To Boundary: No MA w/o MDCD vs. TM w/o MDCD -0.03430 (-0.04846, -0.02014) 0.00000
Adjacent To Boundary: Yes MA w/o MDCD vs. TM w/o MDCD 0.04129 (0.00575, 0.07683) 0.02278
Adjacent To Boundary: No MA w/ MDCD vs. TM w/o MDCD -0.03667 (-0.06351, -0.00983) 0.00742
Adjacent To Boundary: Yes MA w/ MDCD vs. TM w/o MDCD 0.03139 (-0.04028, 0.10306) 0.39068
Adjacent To Boundary: No Employer vs. TM w/o MDCD -0.00612 (-0.0198, 0.00756) 0.38030
Adjacent To Boundary: Yes Employer vs. TM w/o MDCD 0.01455 (-0.01363, 0.04273) 0.31165
Adjacent To Boundary: No Other vs. TM w/o MDCD -0.00908 (-0.02555, 0.00739) 0.27985
Adjacent To Boundary: Yes Other vs. TM w/o MDCD -0.00047 (-0.03434, 0.0334) 0.97830
Adjacent To Boundary: No None vs. TM w/o MDCD -0.01944 (-0.03137, -0.00751) 0.00141
Adjacent To Boundary: Yes None vs. TM w/o MDCD -0.02406 (-0.04782, -3e-04) 0.04715
plt_dt <- rbind(
  summary(margins(m1_in_c, at = list(adjacent_to_boundary = c("No", "Yes")), variables = "insurance_medevid_first")) %>%
    mutate(type = "Crude Model"),
  summary(margins(m1_in_a, at = list(adjacent_to_boundary = c("No", "Yes")), variables = "insurance_medevid_first")) %>%
    mutate(type = "Adjusted Model")
) %>%
  rowwise() %>%
  mutate(Insurance = substr(factor, nchar("insurance_medevid_first") + 1, nchar(factor)), 
         Insurance = factor(Insurance, levels = c("TM w/ MDCD", "MA w/o MDCD", "MA w/ MDCD", "Employer", "Other", "None")),
         adjacent_to_boundary = factor(adjacent_to_boundary, levels = c("No", "Yes"), labels = c("Facility NOT located in a county adjacent to boundary", "Facility located in a county adjacent to boundary")),
         type = factor(type, levels = c("Crude Model", "Adjusted Model"))) %>%
  select(type, adjacent_to_boundary, Insurance, AME, lower, upper) 

plt <- ggplot(
  data = plt_dt, 
  aes(x = Insurance, 
      y = AME, 
      shape = type, 
      linetype = type,
      color = Insurance)
  ) + 
  geom_hline(yintercept = 0, linetype = "dashed") +
  geom_point(position = position_dodge(0.5)) +
  geom_errorbar(aes(ymin = lower, ymax = upper), 
                width = .2,
                position = position_dodge(0.5)) + 
  labs(x = "Insurance Group (Ref: TM w/o MDCD)", 
       y = "Average Marginal Effect (95% CI)",
       linetype = "",
       shape = "") +
  ggsci::scale_color_bmj() + 
  facet_wrap(~adjacent_to_boundary) + 
  theme_bw() + 
  theme(legend.position = "top", 
        strip.text = element_text(size = 13),
        axis.text.x = element_text(size = 11, face = "bold", angle = 90, hjust = 1, vjust = 0.5),
        axis.title = element_text(size = 12), 
        legend.text = element_text(size = 12),
        ) +
  guides(color = "none")

plt