ukbdf0 <- read.csv("C:/Users/19832/Desktop/data_5000.csv")
library(survival)
library(survminer)
library(dplyr)
library(table1)
OUTCOME <- "outcome_status"
TIMESCALE <- "age2"
ID <- "f.eid"
varConfig <- list(
"outcome_status" = list(
label = "AR cases",
trans = "factor",
levels = c(0, 1),
labels = c("no", "yes")
),
"age" = list(
label = "age",
unit = "y",
render = c("mean ± SD" = "MEAN ± SD")
),
"sex" = list(
label = "sex",
unit = "N",
trans = "factor",
labels = c("male", "female")
),
"Ethnicity" = list(
label = "ethnicity",
unit = "N",
trans = "factor",
levels = c(1:4),
labels = c("white", "asia", "black", "mixed")
),
"BMI" = list(
label = "BMI",
unit = "kg/m2",
render = c("mean ± SD" = "MEAN ± SD")
),
"BMI_4" = list(
label = "BMI",
unit = "N",
trans = "factor",
levels = 1:4,
labels = c(
"BMI < 18.5",
"18.5 <= BMI <25",
"25 <= BMI < 30",
"BMI >= 30"
)
),
"education" = list(
label = "education level",
unit = "N",
trans = "factor",
levels = 1:3,
labels = c(
"high education level",
"medium education level",
"others"
)
),
"smoking_status" = list(
label = "smoking status",
unit = "N",
trans = "factor",
levels = 0:2,
labels = c(
"never smoker",
"previous smoker",
"current smoker"
)
),
"physical.bio" = list(
label = "physical activity",
unit = "N",
trans = "factor",
labels = c("no", "yes")
),
"drink_status" = list(
label = "alcohol drinking status",
unit = "N",
trans = "factor",
labels = c(
"never drinking",
"previous drinking",
"current drinking"
)
),
"diet" = list(
label = "healthy diet score",
render = c("mean ± SD" = "MEAN ± SD")
),
"householdincome" = list(
label = "household income",
unit = "N",
trans = "factor",
labels = c(
"<18,000",
"18,000-30,999",
"31,000-51,999",
"52,000-100,000",
">100,000"
)
),
"discoast" = list(
label = "residence location distance to the coast",
unit = "km",
render = c("mean ± SD" = "MEAN ± SD")
),
"PM2.5" = list(
label = "PM2.5",
unit = "μg/m3",
render = c("median (IQR)" = "MEDIAN (IQR)")
),
"PM_c" = list(
label = "PM_coarse",
unit = "μg/m3",
render = c("median (IQR)" = "MEDIAN (IQR)")
),
"PM10" = list(
label = "PM10",
unit = "μg/m3",
render = c("median (IQR)" = "MEDIAN (IQR)")
),
"NO2" = list(
label = "NO2",
unit = "μg/m3",
render = c("median (IQR)" = "MEDIAN (IQR)")
),
"NOx" = list(
label = "NOx",
unit = "μg/m3",
render = c("median (IQR)" = "MEDIAN (IQR)")
),
"PM2.5_5" = list(
label = "PM2.5",
unit = "5 μg/m3",
render = c("median (IQR)" = "MEDIAN (IQR)")
),
"PM_c_5" = list(
label = "PM_coarse",
unit = "5 μg/m3",
render = c("median (IQR)" = "MEDIAN (IQR)")
),
"PM10_10" = list(
label = "PM10",
unit = "10 μg/m3",
render = c("median (IQR)" = "MEDIAN (IQR)")
),
"NO2_10" = list(
label = "NO2",
unit = "10 μg/m3",
render = c("median (IQR)" = "MEDIAN (IQR)")
),
"NOx_20" = list(
label = "NOx",
unit = "20 μg/m3",
render = c("median (IQR)" = "MEDIAN (IQR)")
),
"PM2.5_IQR" = list(
label = "PM2.5",
unit = "N",
trans = "factor",
labels = c("Q1", "Q2", "Q3", "Q4")
),
"PM_c_IQR" = list(
label = "PM_coarse",
unit = "N",
trans = "factor",
labels = c("Q1", "Q2", "Q3", "Q4")
),
"PM10_IQR" = list(
label = "PM10",
unit = "N",
trans = "factor",
labels = c("Q1", "Q2", "Q3", "Q4")
),
"NO2_IQR" = list(
label = "NO2",
unit = "N",
trans = "factor",
labels = c("Q1", "Q2", "Q3", "Q4")
),
"NOx_IQR" = list(
label = "NOx",
unit = "N",
trans = "factor",
labels = c("Q1", "Q2", "Q3", "Q4")
)
)
dfRaw <- ukbdf0 %>%
mutate(
across(
everything(),
function(x) {
nameCurCol <- cur_column()
if (!is.null(varConfig[[nameCurCol]][["trans"]])) {
trans <- varConfig[[nameCurCol]][["trans"]]
paramProtect <- c("label", "unit", "trans", "render")
if (trans == "factor") {
paramAcc <- c("levels", "labels")
paramAvail <- intersect(
names(varConfig[[nameCurCol]]),
paramAcc
)
return(
do.call(
trans,
c(
list(x),
varConfig[[nameCurCol]][paramAvail]
)
)
)
}
paramAvail <- setdiff(
names(varConfig[[nameCurCol]]),
paramProtect
)
return(
do.call(
trans,
c(
list(x),
varConfig[[nameCurCol]][paramAvail]
)
)
)
}
return(x)
}
)
)
varAll <- c(
"age",
"sex",
"Ethnicity",
"BMI",
"BMI_4",
"education",
"smoking_status",
"physical.bio",
"drink_status",
"diet",
"householdincome",
"discoast",
"PM2.5",
"PM_c",
"PM10",
"NO2",
"NOx"
)
varStrata <- OUTCOME
dfBaseline <- dfRaw %>%
select(
c(
all_of(varAll),
all_of(varStrata)
)
)
for (nameVar in varAll) {
if (!is.null(varConfig[[nameVar]][["label"]])) {
labelVarTmp <- varConfig[[nameVar]][["label"]]
label(dfBaseline[, nameVar]) <- labelVarTmp
}
}
for (nameVar in varAll) {
if (!is.null(varConfig[[nameVar]][["unit"]])) {
unitVarTmp <- varConfig[[nameVar]][["unit"]]
units(dfBaseline[, nameVar]) <- unitVarTmp
}
}
rndr <- function(x, name, ...) {
if (!is.numeric(x)) {
return(render.categorical.default(x))
}
if (is.null(varConfig[[name]][["render"]])) {
return(render.continuous.default(x))
} else {
return(
parse.abbrev.render.code(
varConfig[[name]][["render"]],
2
)(x)
)
}
}
table1(
formula(
paste(
"~ ",
paste(varAll, collapse = " + "),
" | ",
varStrata
)
),
data = dfBaseline,
render = rndr
)
| no (N=4963) |
yes (N=37) |
Overall (N=5000) |
|
|---|---|---|---|
| age (y) | |||
| mean ± SD | 56.1 ± 8.09 | 55.1 ± 7.93 | 56.0 ± 8.08 |
| sex (N) | |||
| male | 2611 (52.6%) | 22 (59.5%) | 2633 (52.7%) |
| female | 2352 (47.4%) | 15 (40.5%) | 2367 (47.3%) |
| ethnicity (N) | |||
| white | 4720 (95.1%) | 35 (94.6%) | 4755 (95.1%) |
| asia | 90 (1.8%) | 0 (0%) | 90 (1.8%) |
| black | 80 (1.6%) | 2 (5.4%) | 82 (1.6%) |
| mixed | 73 (1.5%) | 0 (0%) | 73 (1.5%) |
| BMI (kg/m2) | |||
| mean ± SD | 27.4 ± 4.81 | 26.6 ± 5.55 | 27.4 ± 4.81 |
| BMI (N) | |||
| BMI < 18.5 | 26 (0.5%) | 0 (0%) | 26 (0.5%) |
| 18.5 <= BMI <25 | 1615 (32.5%) | 17 (45.9%) | 1632 (32.6%) |
| 25 <= BMI < 30 | 2098 (42.3%) | 14 (37.8%) | 2112 (42.2%) |
| BMI >= 30 | 1224 (24.7%) | 6 (16.2%) | 1230 (24.6%) |
| education level (N) | |||
| high education level | 714 (14.4%) | 4 (10.8%) | 718 (14.4%) |
| medium education level | 2282 (46.0%) | 18 (48.6%) | 2300 (46.0%) |
| others | 1967 (39.6%) | 15 (40.5%) | 1982 (39.6%) |
| smoking status (N) | |||
| never smoker | 2691 (54.2%) | 23 (62.2%) | 2714 (54.3%) |
| previous smoker | 1772 (35.7%) | 12 (32.4%) | 1784 (35.7%) |
| current smoker | 500 (10.1%) | 2 (5.4%) | 502 (10.0%) |
| physical activity (N) | |||
| no | 1380 (27.8%) | 7 (18.9%) | 1387 (27.7%) |
| yes | 3583 (72.2%) | 30 (81.1%) | 3613 (72.3%) |
| alcohol drinking status (N) | |||
| never drinking | 190 (3.8%) | 0 (0%) | 190 (3.8%) |
| previous drinking | 156 (3.1%) | 0 (0%) | 156 (3.1%) |
| current drinking | 4617 (93.0%) | 37 (100%) | 4654 (93.1%) |
| healthy diet score | |||
| mean ± SD | 3.37 ± 1.32 | 3.46 ± 1.12 | 3.37 ± 1.31 |
| household income (N) | |||
| <18,000 | 1111 (22.4%) | 4 (10.8%) | 1115 (22.3%) |
| 18,000-30,999 | 1333 (26.9%) | 10 (27.0%) | 1343 (26.9%) |
| 31,000-51,999 | 1249 (25.2%) | 11 (29.7%) | 1260 (25.2%) |
| 52,000-100,000 | 1000 (20.1%) | 10 (27.0%) | 1010 (20.2%) |
| >100,000 | 270 (5.4%) | 2 (5.4%) | 272 (5.4%) |
| residence location distance to the coast (km) | |||
| mean ± SD | 43.5 ± 27.7 | 50.8 ± 22.0 | 43.5 ± 27.7 |
| PM2.5 (μg/m3) | |||
| median (IQR) | 9.90 (1.24) | 9.87 (1.42) | 9.90 (1.24) |
| PM_coarse (μg/m3) | |||
| median (IQR) | 6.08 (0.770) | 6.17 (0.680) | 6.09 (0.770) |
| PM10 (μg/m3) | |||
| median (IQR) | 16.0 (1.76) | 16.2 (1.26) | 16.0 (1.76) |
| NO2 (μg/m3) | |||
| median (IQR) | 25.8 (9.81) | 28.9 (6.75) | 25.8 (9.79) |
| NOx (μg/m3) | |||
| median (IQR) | 41.6 (16.0) | 44.2 (16.1) | 41.7 (16.0) |
varExposure <- c(
"PM2.5_5",
"PM_c_5",
"PM10_10",
"NO2_10",
"NOx_20"
)
varModela <- c("sex")
varModelb <- c(
"sex",
"Ethnicity",
"education",
"BMI",
"householdincome",
"smoking_status",
"drink_status",
"diet",
"physical.bio",
"discoast"
)
fitModela <- coxph(
reformulate(
c(varExposure, varModela),
response = call(
"Surv",
str2lang(TIMESCALE),
call("as.numeric", str2lang(OUTCOME))
)
),
data = dfRaw
)
fitModela
## Call:
## coxph(formula = reformulate(c(varExposure, varModela), response = call("Surv",
## str2lang(TIMESCALE), call("as.numeric", str2lang(OUTCOME)))),
## data = dfRaw)
##
## coef exp(coef) se(coef) z p
## PM2.5_5 -1.3373 0.2626 1.7088 -0.783 0.4339
## PM_c_5 -0.6251 0.5352 1.9275 -0.324 0.7457
## PM10_10 1.6834 5.3838 2.0983 0.802 0.4224
## NO2_10 1.2237 3.3997 0.6151 1.989 0.0467
## NOx_20 -0.8626 0.4221 0.6089 -1.417 0.1566
## sexfemale -0.3071 0.7356 0.3353 -0.916 0.3597
##
## Likelihood ratio test=6.74 on 6 df, p=0.3456
## n= 5000, number of events= 37
fitModelb <- coxph(
reformulate(
c(varExposure, varModelb),
response = call(
"Surv",
str2lang(TIMESCALE),
call("as.numeric", str2lang(OUTCOME))
)
),
data = dfRaw
)
fitModelb
## Call:
## coxph(formula = reformulate(c(varExposure, varModelb), response = call("Surv",
## str2lang(TIMESCALE), call("as.numeric", str2lang(OUTCOME)))),
## data = dfRaw)
##
## coef exp(coef) se(coef) z p
## PM2.5_5 1.547e-02 1.016e+00 1.760e+00 0.009 0.9930
## PM_c_5 -3.457e-01 7.077e-01 1.906e+00 -0.181 0.8561
## PM10_10 1.238e+00 3.450e+00 2.057e+00 0.602 0.5471
## NO2_10 9.904e-01 2.692e+00 6.394e-01 1.549 0.1214
## NOx_20 -7.801e-01 4.584e-01 6.145e-01 -1.269 0.2043
## sexfemale -3.970e-01 6.723e-01 3.503e-01 -1.133 0.2571
## Ethnicityasia -1.805e+01 1.450e-08 1.247e+04 -0.001 0.9988
## Ethnicityblack 1.436e+00 4.203e+00 7.814e-01 1.837 0.0662
## Ethnicitymixed -1.828e+01 1.148e-08 1.570e+04 -0.001 0.9991
## educationmedium education level 2.897e-01 1.336e+00 5.740e-01 0.505 0.6138
## educationothers -1.900e-02 9.812e-01 6.061e-01 -0.031 0.9750
## BMI -2.905e-02 9.714e-01 4.070e-02 -0.714 0.4754
## householdincome18,000-30,999 8.186e-01 2.267e+00 6.029e-01 1.358 0.1746
## householdincome31,000-51,999 1.291e+00 3.636e+00 6.129e-01 2.106 0.0352
## householdincome52,000-100,000 1.639e+00 5.149e+00 6.422e-01 2.552 0.0107
## householdincome>100,000 1.401e+00 4.060e+00 9.075e-01 1.544 0.1226
## smoking_statusprevious smoker -3.550e-01 7.011e-01 3.646e-01 -0.974 0.3302
## smoking_statuscurrent smoker -4.981e-01 6.077e-01 7.472e-01 -0.667 0.5050
## drink_statusprevious drinking -5.746e-01 5.629e-01 9.605e+03 0.000 1.0000
## drink_statuscurrent drinking 1.745e+01 3.793e+07 4.949e+03 0.004 0.9972
## diet -5.440e-02 9.471e-01 1.320e-01 -0.412 0.6802
## physical.bioyes 4.327e-01 1.541e+00 4.262e-01 1.015 0.3100
## discoast 1.009e-02 1.010e+00 6.500e-03 1.552 0.1206
##
## Likelihood ratio test=32.92 on 23 df, p=0.08241
## n= 5000, number of events= 37
varExposureIQR <- c(
"PM2.5_IQR",
"PM_c_IQR",
"PM10_IQR",
"NO2_IQR",
"NOx_IQR"
)
fitModelIQRa <- coxph(
reformulate(
c(varExposureIQR, varModela),
response = call(
"Surv",
str2lang(TIMESCALE),
call("as.numeric", str2lang(OUTCOME))
)
),
data = dfRaw
)
fitModelIQRa
## Call:
## coxph(formula = reformulate(c(varExposureIQR, varModela), response = call("Surv",
## str2lang(TIMESCALE), call("as.numeric", str2lang(OUTCOME)))),
## data = dfRaw)
##
## coef exp(coef) se(coef) z p
## PM2.5_IQRQ2 0.2523 1.2870 0.6283 0.402 0.688
## PM2.5_IQRQ3 -1.4444 0.2359 0.8934 -1.617 0.106
## PM2.5_IQRQ4 0.2561 1.2919 0.8192 0.313 0.755
## PM_c_IQRQ2 -0.1342 0.8744 0.5435 -0.247 0.805
## PM_c_IQRQ3 -0.3265 0.7214 0.6058 -0.539 0.590
## PM_c_IQRQ4 -0.7159 0.4888 0.8008 -0.894 0.371
## PM10_IQRQ2 0.3162 1.3718 0.6054 0.522 0.602
## PM10_IQRQ3 1.0594 2.8848 0.6757 1.568 0.117
## PM10_IQRQ4 1.0988 3.0006 0.8738 1.257 0.209
## NO2_IQRQ2 0.3923 1.4805 0.6520 0.602 0.547
## NO2_IQRQ3 0.7795 2.1804 0.7633 1.021 0.307
## NO2_IQRQ4 -0.4935 0.6105 0.9392 -0.525 0.599
## NOx_IQRQ2 -0.5476 0.5784 0.6522 -0.840 0.401
## NOx_IQRQ3 -0.2889 0.7491 0.7900 -0.366 0.715
## NOx_IQRQ4 0.3998 1.4915 0.9160 0.436 0.663
## sexfemale -0.2872 0.7504 0.3359 -0.855 0.393
##
## Likelihood ratio test=22.42 on 16 df, p=0.1303
## n= 5000, number of events= 37
fitModelIQRb <- coxph(
reformulate(
c(varExposureIQR, varModelb),
response = call(
"Surv",
str2lang(TIMESCALE),
call("as.numeric", str2lang(OUTCOME))
)
),
data = dfRaw
)
fitModelIQRb
## Call:
## coxph(formula = reformulate(c(varExposureIQR, varModelb), response = call("Surv",
## str2lang(TIMESCALE), call("as.numeric", str2lang(OUTCOME)))),
## data = dfRaw)
##
## coef exp(coef) se(coef) z p
## PM2.5_IQRQ2 3.669e-01 1.443e+00 6.557e-01 0.559 0.57583
## PM2.5_IQRQ3 -1.190e+00 3.042e-01 9.170e-01 -1.298 0.19430
## PM2.5_IQRQ4 8.553e-01 2.352e+00 8.577e-01 0.997 0.31870
## PM_c_IQRQ2 -4.242e-02 9.585e-01 5.465e-01 -0.078 0.93813
## PM_c_IQRQ3 -3.194e-01 7.266e-01 6.226e-01 -0.513 0.60789
## PM_c_IQRQ4 -7.923e-01 4.528e-01 8.453e-01 -0.937 0.34862
## PM10_IQRQ2 2.810e-01 1.325e+00 6.188e-01 0.454 0.64972
## PM10_IQRQ3 1.008e+00 2.739e+00 7.006e-01 1.438 0.15038
## PM10_IQRQ4 1.117e+00 3.056e+00 9.210e-01 1.213 0.22521
## NO2_IQRQ2 2.777e-01 1.320e+00 6.768e-01 0.410 0.68160
## NO2_IQRQ3 6.101e-01 1.841e+00 8.135e-01 0.750 0.45327
## NO2_IQRQ4 -9.006e-01 4.063e-01 9.985e-01 -0.902 0.36707
## NOx_IQRQ2 -4.537e-01 6.353e-01 6.830e-01 -0.664 0.50650
## NOx_IQRQ3 -1.044e-01 9.008e-01 8.439e-01 -0.124 0.90153
## NOx_IQRQ4 6.120e-01 1.844e+00 9.779e-01 0.626 0.53146
## sexfemale -4.160e-01 6.597e-01 3.528e-01 -1.179 0.23837
## Ethnicityasia -1.778e+01 1.898e-08 1.083e+04 -0.002 0.99869
## Ethnicityblack 1.873e+00 6.510e+00 7.948e-01 2.357 0.01842
## Ethnicitymixed -1.827e+01 1.163e-08 1.571e+04 -0.001 0.99907
## educationmedium education level 2.651e-01 1.304e+00 5.752e-01 0.461 0.64488
## educationothers 2.196e-02 1.022e+00 6.056e-01 0.036 0.97107
## BMI -3.349e-02 9.671e-01 4.076e-02 -0.822 0.41126
## householdincome18,000-30,999 9.153e-01 2.497e+00 6.036e-01 1.516 0.12944
## householdincome31,000-51,999 1.356e+00 3.881e+00 6.163e-01 2.200 0.02779
## householdincome52,000-100,000 1.829e+00 6.230e+00 6.432e-01 2.844 0.00445
## householdincome>100,000 1.684e+00 5.389e+00 9.153e-01 1.840 0.06571
## smoking_statusprevious smoker -3.747e-01 6.875e-01 3.637e-01 -1.030 0.30297
## smoking_statuscurrent smoker -4.193e-01 6.575e-01 7.479e-01 -0.561 0.57499
## drink_statusprevious drinking -5.591e-01 5.717e-01 1.019e+04 0.000 0.99996
## drink_statuscurrent drinking 1.751e+01 4.017e+07 4.887e+03 0.004 0.99714
## diet -5.358e-02 9.478e-01 1.312e-01 -0.408 0.68303
## physical.bioyes 4.726e-01 1.604e+00 4.291e-01 1.101 0.27079
## discoast 1.220e-02 1.012e+00 6.481e-03 1.882 0.05984
##
## Likelihood ratio test=53.69 on 33 df, p=0.01288
## n= 5000, number of events= 37
nameTestCovariates <- c(
"PM2.5",
"PM_c",
"PM10",
"NO2",
"NOx"
)
formulaTest <- reformulate(
nameTestCovariates,
response = call(
"Surv",
str2lang(TIMESCALE),
call("as.numeric", str2lang(OUTCOME))
)
)
fitCoxzph <- cox.zph(
coxph(
formulaTest,
data = dfRaw
)
)
fitCoxzph
## chisq df p
## PM2.5 0.00777 1 0.93
## PM_c 0.55798 1 0.46
## PM10 0.04448 1 0.83
## NO2 0.17346 1 0.68
## NOx 0.40619 1 0.52
## GLOBAL 2.74815 5 0.74
ggcoxzph(fitCoxzph)
logit_model <- glm(
outcome_status ~ PM2.5 + PM10 + PM_c + NO2 + NOx +
age + sex + BMI_4 + smoking_status + Ethnicity,
data = dfRaw,
family = binomial
)
summary(logit_model)
##
## Call:
## glm(formula = outcome_status ~ PM2.5 + PM10 + PM_c + NO2 + NOx +
## age + sex + BMI_4 + smoking_status + Ethnicity, family = binomial,
## data = dfRaw)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.955e+01 2.081e+03 -0.009 0.9925
## PM2.5 -2.268e-01 3.542e-01 -0.640 0.5219
## PM10 1.790e-01 1.982e-01 0.903 0.3665
## PM_c -1.531e-01 3.674e-01 -0.417 0.6769
## NO2 1.057e-01 6.267e-02 1.687 0.0916 .
## NOx -4.083e-02 3.182e-02 -1.283 0.1994
## age -9.978e-03 2.053e-02 -0.486 0.6269
## sexfemale -1.444e-01 3.428e-01 -0.421 0.6737
## BMI_418.5 <= BMI <25 1.498e+01 2.081e+03 0.007 0.9943
## BMI_425 <= BMI < 30 1.456e+01 2.081e+03 0.007 0.9944
## BMI_4BMI >= 30 1.424e+01 2.081e+03 0.007 0.9945
## smoking_statusprevious smoker -1.564e-01 3.638e-01 -0.430 0.6672
## smoking_statuscurrent smoker -7.631e-01 7.443e-01 -1.025 0.3052
## Ethnicityasia -1.487e+01 1.118e+03 -0.013 0.9894
## Ethnicityblack 9.402e-01 7.748e-01 1.213 0.2249
## Ethnicitymixed -1.482e+01 1.239e+03 -0.012 0.9905
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 436.79 on 4999 degrees of freedom
## Residual deviance: 422.30 on 4984 degrees of freedom
## AIC: 454.3
##
## Number of Fisher Scoring iterations: 18
OR_result <- exp(
cbind(
OR = coef(logit_model),
confint(logit_model)
)
)
knitr::kable(
OR_result,
digits = 3,
caption = "Odds Ratios and 95% Confidence Intervals"
)
| OR | 2.5 % | 97.5 % | |
|---|---|---|---|
| (Intercept) | 0.000 | 0.000 | 1.016200e+27 |
| PM2.5 | 0.797 | 0.398 | 1.596000e+00 |
| PM10 | 1.196 | 0.806 | 1.699000e+00 |
| PM_c | 0.858 | 0.429 | 1.758000e+00 |
| NO2 | 1.112 | 0.983 | 1.257000e+00 |
| NOx | 0.960 | 0.898 | 1.018000e+00 |
| age | 0.990 | 0.951 | 1.031000e+00 |
| sexfemale | 0.866 | 0.434 | 1.682000e+00 |
| BMI_418.5 <= BMI <25 | 3192975.947 | 0.000 | 1.893292e+283 |
| BMI_425 <= BMI < 30 | 2100269.395 | 0.000 | 2.870029e+272 |
| BMI_4BMI >= 30 | 1530975.440 | 0.000 | 2.092100e+272 |
| smoking_statusprevious smoker | 0.855 | 0.406 | 1.715000e+00 |
| smoking_statuscurrent smoker | 0.466 | 0.074 | 1.605000e+00 |
| Ethnicityasia | 0.000 | 0.000 | 2.412080e+17 |
| Ethnicityblack | 2.560 | 0.392 | 9.556000e+00 |
| Ethnicitymixed | 0.000 | 0.000 | 9.750962e+19 |
library(broom)
library(forestplot)
# 过滤掉样本量过少的组
dfFiltered <- dfRaw %>%
group_by(BMI_4) %>%
filter(n() >= 30) %>%
ungroup()
results <- dfFiltered %>%
group_by(BMI_4) %>%
do({
model <- glm(
outcome_status ~ PM2.5 + age + sex +
smoking_status + Ethnicity,
data = .,
family = binomial
)
tidy(
model,
exponentiate = TRUE,
conf.int = TRUE
) %>%
filter(term == "PM2.5") %>%
select(
term,
estimate,
conf.low,
conf.high,
p.value
)
}) %>%
ungroup()
knitr::kable(
results,
digits = 3,
caption = "BMI-Stratified Association Between PM2.5 and AR"
)
| BMI_4 | term | estimate | conf.low | conf.high | p.value |
|---|---|---|---|---|---|
| 18.5 <= BMI <25 | PM2.5 | 0.995 | 0.600 | 1.574 | 0.985 |
| 25 <= BMI < 30 | PM2.5 | 1.221 | 0.734 | 1.926 | 0.417 |
| BMI >= 30 | PM2.5 | 1.132 | 0.491 | 2.347 | 0.755 |
tabletext <- cbind(
as.character(results$BMI_4),
sprintf(
"%.2f (%.2f–%.2f)",
results$estimate,
results$conf.low,
results$conf.high
),
sprintf(
"p=%.3f",
results$p.value
)
)
forestplot(
labeltext = tabletext,
mean = results$estimate,
lower = results$conf.low,
upper = results$conf.high,
zero = 1,
xlog = TRUE,
col = fpColors(
box = "royalblue",
line = "darkblue",
summary = "royalblue"
)
)
library(survival)
library(survminer)
df_surv <- dfRaw
df_surv$outcome_status <- ifelse(
df_surv$outcome_status == "yes",
1,
0
)
df_surv$outcome_status <- as.numeric(
df_surv$outcome_status
)
fit <- survfit(
Surv(
time_followup_ICD,
outcome_status
) ~ PM2.5_cate,
data = df_surv
)
km_plot <- ggsurvplot(
fit,
data = df_surv,
pval = TRUE,
conf.int = TRUE,
risk.table = TRUE,
legend.title = "PM2.5 group",
xlab = "Follow-up time (years)",
ylab = "Cumulative incidence of AR"
)
print(km_plot)
library(cmprsk)
df_gray <- df_surv
# 将分类变量转换为数值型
df_gray$sex <- as.numeric(df_gray$sex)
df_gray$BMI_4 <- as.numeric(df_gray$BMI_4)
df_gray$smoking_status <- as.numeric(df_gray$smoking_status)
df_gray$Ethnicity <- as.numeric(df_gray$Ethnicity)
# 确保状态变量为数值型
df_gray$outcome_status <- as.numeric(
df_gray$outcome_status
)
crr_model <- crr(
ftime = df_gray$time_followup_ICD,
fstatus = df_gray$outcome_status,
cov1 = df_gray[
,
c(
"PM2.5",
"PM10",
"PM_c",
"NO2",
"NOx",
"age",
"sex",
"BMI_4",
"smoking_status",
"Ethnicity"
)
]
)
summary(crr_model)
## Competing Risks Regression
##
## Call:
## crr(ftime = df_gray$time_followup_ICD, fstatus = df_gray$outcome_status,
## cov1 = df_gray[, c("PM2.5", "PM10", "PM_c", "NO2", "NOx",
## "age", "sex", "BMI_4", "smoking_status", "Ethnicity")])
##
## coef exp(coef) se(coef) z p-value
## PM2.5 -0.24814 0.780 0.3779 -0.657 0.510
## PM10 0.17010 1.185 0.1773 0.959 0.340
## PM_c -0.12837 0.880 0.3570 -0.360 0.720
## NO2 0.11469 1.122 0.0631 1.817 0.069
## NOx -0.04283 0.958 0.0261 -1.644 0.100
## age -0.00647 0.994 0.0197 -0.329 0.740
## sex -0.14552 0.865 0.3437 -0.423 0.670
## BMI_4 -0.31306 0.731 0.2217 -1.412 0.160
## smoking_status -0.26413 0.768 0.2619 -1.009 0.310
## Ethnicity -0.05030 0.951 0.3130 -0.161 0.870
##
## exp(coef) exp(-coef) 2.5% 97.5%
## PM2.5 0.780 1.282 0.372 1.64
## PM10 1.185 0.844 0.837 1.68
## PM_c 0.880 1.137 0.437 1.77
## NO2 1.122 0.892 0.991 1.27
## NOx 0.958 1.044 0.910 1.01
## age 0.994 1.006 0.956 1.03
## sex 0.865 1.157 0.441 1.70
## BMI_4 0.731 1.368 0.473 1.13
## smoking_status 0.768 1.302 0.460 1.28
## Ethnicity 0.951 1.052 0.515 1.76
##
## Num. cases = 5000
## Pseudo Log-likelihood = -308
## Pseudo likelihood ratio test = 8.98 on 10 df,
sessionInfo()
## R version 4.5.2 (2025-10-31 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26100)
##
## Matrix products: default
## LAPACK version 3.12.1
##
## locale:
## [1] LC_COLLATE=Chinese (Simplified)_China.utf8
## [2] LC_CTYPE=Chinese (Simplified)_China.utf8
## [3] LC_MONETARY=Chinese (Simplified)_China.utf8
## [4] LC_NUMERIC=C
## [5] LC_TIME=Chinese (Simplified)_China.utf8
##
## time zone: Asia/Shanghai
## tzcode source: internal
##
## attached base packages:
## [1] grid stats graphics grDevices utils datasets methods
## [8] base
##
## other attached packages:
## [1] cmprsk_2.2-12 forestplot_3.2.0 abind_1.4-8 checkmate_2.3.4
## [5] broom_1.0.13 table1_1.5.1 dplyr_1.2.0 survminer_0.5.2
## [9] ggpubr_1.0.0 ggplot2_4.0.3 survival_3.8-3
##
## loaded via a namespace (and not attached):
## [1] sass_0.4.10 generics_0.1.4 tidyr_1.3.2 xml2_1.5.2
## [5] rstatix_1.1.0 stringi_1.8.7 lattice_0.22-7 digest_0.6.39
## [9] magrittr_2.0.4 evaluate_1.0.5 RColorBrewer_1.1-3 fastmap_1.2.0
## [13] jsonlite_2.0.0 Matrix_1.7-4 backports_1.5.1 Formula_1.2-6
## [17] ggtext_0.2.0 gridExtra_2.3 purrr_1.2.1 scales_1.4.0
## [21] jquerylib_0.1.4 cli_3.6.5 rlang_1.1.7 litedown_0.11
## [25] commonmark_2.0.0 splines_4.5.2 withr_3.0.2 cachem_1.1.0
## [29] yaml_2.3.12 otel_0.2.0 tools_4.5.2 ggsignif_0.6.4
## [33] vctrs_0.7.1 R6_2.6.1 lifecycle_1.0.5 stringr_1.6.0
## [37] car_3.1-5 pkgconfig_2.0.3 pillar_1.11.1 bslib_0.10.0
## [41] gtable_0.3.6 Rcpp_1.1.2 glue_1.8.0 xfun_0.57
## [45] tibble_3.3.1 tidyselect_1.2.1 rstudioapi_0.18.0 knitr_1.51
## [49] farver_2.1.2 htmltools_0.5.9 rmarkdown_2.30 carData_3.0-6
## [53] labeling_0.4.3 compiler_4.5.2 S7_0.2.1 markdown_2.0
## [57] gridtext_0.1.6