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,8451 |
Located in the county adjacent to state boundary
|
|
|---|---|---|---|
| No N = 17,0941 |
Yes N = 6,7511 |
||
| 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,5421 |
Yes N = 2,3031 |
|
| 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
| 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
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") | 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")| 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")| 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