require(simcausal)
<- DAG.empty()
D <- D +
D node("age", distr = "rnorm",
mean = 2, sd = 4) +
node("gender", distr = "rbern",
prob = plogis(4)) +
node("education", distr = "rbern",
prob = plogis(3 + 5 * age)) +
node("diet", distr = "rbern",
prob = plogis(1 - 3 * education)) +
node("income", distr = "rbern",
prob = plogis(2 - 5 * education - 4 * age)) +
node("smoking", distr = "rbern",
prob = plogis(1 + 1.2 * gender + 2 * age)) +
node("hypertension", distr = "rbern",
prob = plogis(1 + log(3) * diet +
log(1.3) * age +
log(3.5) * smoking +
log(0.5) * gender))
<- set.DAG(D) Dset
4 Effect Modification Analysis within the Propensity score Framework
Observational comparative effectiveness studies often adopt propensity score analysis to adjust for confounding. Although this approach is relatively straightforward to implement, careful thought is needed when treatment effect heterogeneity is present. This chapter illustrates the estimation of subgroup-specific treatment effects using (traditional) covariate adjustment methods, propensity score matching, propensity score weighting, propensity score stratification, and covariate adjustment using propensity scores.
4.1 Simulation
We will use the following data-generation model:
Below is the diagram, with pink lines representing open backdoor path.
using the following vertex attributes:
NAdarkbluenone100.50
using the following edge attributes:
black0.210.60.5
We can now generate an example dataset:
<- sim(DAG = Dset, n = 50000, rndseed = 123)
Obs.Data $smoking <- as.character(Obs.Data$smoking)
Obs.Data$income <- as.factor(Obs.Data$income)
Obs.Data$income <- relevel(Obs.Data$income, ref = "1") Obs.Data
Sample data from the hypothetical example of association between hypertension and smoking, where other variables such as income, age [centered], gender, education and diet also plays a role in the data generation process.
age | gender | education | diet | income | smoking | hypertension | |
---|---|---|---|---|---|---|---|
34901 | 12.29 | 1 | 1 | 1 | 0 | 1 | 1 |
149 | 10.40 | 1 | 1 | 0 | 0 | 1 | 1 |
10060 | 2.99 | 1 | 1 | 0 | 0 | 1 | 0 |
22220 | -4.31 | 0 | 0 | 0 | 1 | 0 | 1 |
9979 | -6.44 | 0 | 0 | 0 | 1 | 0 | 1 |
4.2 Covariate adjustment
4.2.1 Interaction approach
Below, we estimate a logistic regression model to assess whether the effect of smoking (the exposure) on hypertension is modified by income levels. This model considers the following variables:
- Outcome:
hypertension
- Exposure variables:
smoking
andincome
- Confounders:
age
andgender
require(jtools)
<- glm(hypertension ~ smoking * income + age + gender,
fit.w.em family = binomial(link = "logit"),
data = Obs.Data)
<- summ(fit.w.em, exp = TRUE) results.model
exp(Est.) | 2.5% | 97.5% | z val. | p | |
---|---|---|---|---|---|
(Intercept) | 5.46 | 4.37 | 6.82 | 14.97 | 0.00 |
smoking1 | 2.93 | 2.60 | 3.30 | 17.69 | 0.00 |
income0 | 0.48 | 0.41 | 0.57 | -8.28 | 0.00 |
age | 1.29 | 1.27 | 1.31 | 36.77 | 0.00 |
gender | 0.54 | 0.43 | 0.67 | -5.55 | 0.00 |
smoking1:income0 | 1.27 | 1.04 | 1.56 | 2.33 | 0.02 |
Results indicate that the interaction between smoking status and income level is statistically significant (p = 0.02).
If we expand previous model to adjust for an additional confounder education
, we have:
<- glm(hypertension ~ smoking * income + age + gender + education,
fit.w.int family = binomial(link = "logit"),
data = Obs.Data)
<- summ(fit.w.int, exp = TRUE) results.int.model
exp(Est.) | 2.5% | 97.5% | z val. | p | |
---|---|---|---|---|---|
(Intercept) | 5.69 | 4.56 | 7.11 | 15.31 | 0.00 |
smoking1 | 3.35 | 2.95 | 3.79 | 18.85 | 0.00 |
income0 | 1.09 | 0.85 | 1.40 | 0.68 | 0.49 |
age | 1.30 | 1.28 | 1.32 | 37.32 | 0.00 |
gender | 0.54 | 0.43 | 0.67 | -5.58 | 0.00 |
education | 0.42 | 0.35 | 0.51 | -8.87 | 0.00 |
smoking1:income0 | 1.10 | 0.90 | 1.35 | 0.93 | 0.35 |
The interaction term between income and smoking is no longer statistically significant (p = 0.35).
We can generate a summary report from aforementioned effect modification analysis.
library(interactionR)
<- interactionR(fit.w.em,
em.object exposure_names = c("income0", "smoking1"),
ci.type = "mover", ci.level = 0.95,
em = TRUE, recode = FALSE)
The table below depicts the adjusted odds ratios for income levels (high = 0
, and low = 1
). The variables CI.ll
and CI.ul
depict the lower and upper limits of the 95 percent confidence intervals, OR11
= \(OR_{A = 1, M = 1}\) , OR10
= \(OR_{A = 1}\), OR01
= \(OR_{M = 1}\) and OR00
captures the reference.
Measures | Estimates | CI.ll | CI.ul |
---|---|---|---|
OR00 | 1.00 | NA | NA |
OR01 | 2.93 | 2.60 | 3.30 |
OR10 | 0.48 | 0.41 | 0.57 |
OR11 | 1.80 | 1.63 | 1.98 |
OR(smoking1 on outcome [income0==0] | 2.93 | 2.60 | 3.30 |
OR(smoking1 on outcome [income0==1] | 3.72 | 3.14 | 4.41 |
Multiplicative scale | 1.27 | 1.04 | 1.56 |
RERI | -0.61 | -0.98 | -0.29 |
Similarly, for the analysis adjusting for an additional confounder education
, we have:
Measures | Estimates | CI.ll | CI.ul |
---|---|---|---|
OR00 | 1.00 | NA | NA |
OR01 | 1.09 | 0.85 | 1.40 |
OR10 | 3.35 | 2.95 | 3.79 |
OR11 | 4.02 | 3.29 | 4.92 |
OR(income0 on outcome [smoking1==0] | 1.09 | 0.85 | 1.40 |
OR(income0 on outcome [smoking1==1] | 1.20 | 1.00 | 1.45 |
OR(smoking1 on outcome [income0==0] | 3.35 | 2.95 | 3.79 |
OR(smoking1 on outcome [income0==1] | 3.69 | 3.11 | 4.37 |
Multiplicative scale | 1.10 | 0.90 | 1.35 |
RERI | 0.59 | 0.03 | 1.27 |
AP | 0.15 | 0.00 | 0.26 |
SI | 1.24 | 1.01 | 1.53 |
# test run with additive model
$smoking <- as.numeric(as.character(Obs.Data$smoking))
Obs.Data$income <- as.numeric(as.character(Obs.Data$income))
Obs.Data<- glm(hypertension ~ smoking * income + age + gender + education,
fit.w.int.add family = gaussian(link = "identity"), data = Obs.Data)
::sim_slopes(fit.w.int.add,
interactionspred = smoking,
modx = income,
exp = TRUE,
robust = TRUE,
confint = TRUE,
data = Obs.Dat)
JOHNSON-NEYMAN INTERVAL
When income is INSIDE the interval [-3.27, 16.87], the slope of smoking is
p < .05.
Note: The range of observed values of income is [0.00, 1.00]
SIMPLE SLOPES ANALYSIS
Slope of smoking when income = 0.00 (0):
Est. S.E. 2.5% 97.5% t val. p
------ ------ ------ ------- -------- ------
0.25 0.02 1.24 1.34 12.76 0.00
Slope of smoking when income = 1.00 (1):
Est. S.E. 2.5% 97.5% t val. p
------ ------ ------ ------- -------- ------
0.28 0.01 1.30 1.34 34.53 0.00
4.2.2 Stratification
This approach involves estimating a regression model in different strata of the discrete effect modifier income
:
# Estimate the prognostic effect of smoking in low income individuals
<- glm(hypertension ~ smoking + age + gender,
fit.income1 family = binomial(link = "logit"),
data = subset(Obs.Data, income == 1))
# Estimate the prognostic effect of smoking in high income individuals
<- glm(hypertension ~ smoking + age + gender,
fit.income0 family = binomial(link = "logit"),
data = subset(Obs.Data, income == 0))
The table below summarizes the adjusted odds ratios for smoking across the different income levels (low = 1
, and high = 0
) as obtained using the stratified approach.
Value of income | Estimate | 2.5 % | 97.5 % | z value | p value |
---|---|---|---|---|---|
1 | 3.07 | 2.71 | 3.47 | 17.65 | 0 |
0 | 3.59 | 3.02 | 4.26 | 14.57 | 0 |
Note that we can obtain the same results by estimating a regression model with an interaction term between the modifier and all covariates:
<- glm(hypertension ~ income * (smoking + age + gender),
fit.all.int family = binomial(link = "logit"), data = Obs.Data)
# Odds ratio for smoking in individuals with low income
exp(coef(fit.all.int)["smoking"])
smoking
3.59026
# Odds ratio for smoking in individuals with high income
exp(coef(fit.all.int)["smoking"] + coef(fit.all.int)["income:smoking"])
smoking
3.066878
4.3 Propensity score matching
4.3.1 Stratification with exact matching within subgroups
We simulate another example dataset using aforementioned DAG, but restrict the sample size to 5000 individuals to reduce computational burden.
set.seed(123)
<- sim(DAG = Dset, n = 5000, rndseed = 123) Obs.Data
We first estimate the propensity of smoking in the high-income group (income == 0
):
require(MatchIt)
.0 <- matchit(smoking ~ age + gender,
match.incomedata = subset(Obs.Data, income == 0),
method = "full", distance = "glm", link = "logit")
.0 <- match.data(match.income.0) data.income
Below, we draw a sample from the high-income group based on the hypothetical example of an association between hypertension and smoking. Here age [centered], gender, education, and diet are covariates.
age gender education diet income smoking hypertension distance
657 6.0810120 0 1 1 0 1 1 0.9999874
4932 1.6109860 1 1 0 0 1 0 0.9943155
252 -0.2475055 1 1 1 0 0 1 0.8525107
2693 -0.2511048 1 1 0 0 1 1 0.8516785
1646 -0.2836155 1 0 1 0 1 1 0.8439843
weights subclass
657 1.00000000 33
4932 1.00000000 33
252 0.04944134 23
2693 1.00000000 23
1646 1.00000000 4
Now, we do the same for the low-income group (income == 1
):
.1 <- matchit(smoking ~ age + gender,
match.incomedata = subset(Obs.Data, income == 1),
method = "full", distance = "glm", link = "logit")
.1 <- match.data(match.income.1) data.income
We estimated the exposure effect from a weighted outcome model for the matched data. While the weights
are essential for estimating the point estimate from the outcome model, the subclass
variable assists in calculating the robust variance of the exposure effect estimate.
# Treatment effect estimation
.0 <- glm(hypertension ~ smoking + age + gender,
fit.incomedata = data.income.0, weights = weights,
family = quasibinomial("logit"))
.1 <- glm(hypertension ~ smoking + age + gender,
fit.incomedata = data.income.1, weights = weights,
family = quasibinomial("logit"))
# Robust variance calculation
<- summ(fit.income.1,
fit.nexp.adj.res1 robust = TRUE,
cluster = "subclass",
confint = TRUE)
<- summ(fit.income.0,
fit.nexp.adj.res0 robust = TRUE,
cluster = "subclass",
confint = TRUE)
Value of income | Est. | 2.5% | 97.5% | t val. | p |
---|---|---|---|---|---|
0 | 3.76 | -43.15 | 50.66 | 0.16 | 0.88 |
1 | 1.36 | 0.90 | 1.81 | 5.78 | 0.00 |
4.3.2 Joint approach without exact matching within subgroups
Here, entire cohort data is used to estimate the propensity scores, and the effect modifier income
is considered as a covariate in the propensity score model:
<- as.formula("smoking ~ age + gender + income")
ps.formula <- matchit(ps.formula, data = Obs.Data,
match.obj.j method = "full",
distance = "glm",
link = "logit")
<- match.data(match.obj.j) match.data.j
<- glm(hypertension ~ smoking*income + age + gender,
fit.joint.no.exact data = match.data.j,
weights = weights,
family = binomial("logit"))
<- interactions::sim_slopes(fit.joint.no.exact,
nem.nexp.adj.res pred = smoking,
modx = income,
robust = "HC1",
cluster = "subclass",
johnson_neyman = TRUE,
confint = TRUE,
data = match.data.j)
Value of income | Est. | S.E. | 2.5% | 97.5% | z val. | p |
---|---|---|---|---|---|---|
0 | 3.77 | 1.02 | 1.77 | 5.76 | 3.70 | 0 |
1 | 1.34 | 0.28 | 0.79 | 1.89 | 4.78 | 0 |
4.3.3 Joint approach with exact matching within subgroups
We specify the moderator variable’s name in the exact
argument of the matchit
function.
<- as.formula("smoking ~ age + gender")
ps.formula.no.mod <- matchit(ps.formula.no.mod, data = Obs.Data,
match.obj.js method = "full", distance = "glm",link = "logit",
exact = "income")
<- match.data(match.obj.js)
match.data.js <- glm(hypertension ~ smoking*income + age + gender,
fit.joint.exact data = match.data.js, weights = weights,
family = binomial("logit"))
<- interactions::sim_slopes(fit.joint.exact,
js.nexp.adj.res pred = smoking,
modx = income, # effect modifier
robust = "HC1",
cluster = "subclass",
johnson_neyman = FALSE,
confint = TRUE,
data = match.data.js)
Value of income | Est. | S.E. | 2.5% | 97.5% | z val. | p |
---|---|---|---|---|---|---|
0 | 3.81 | 1.02 | 1.81 | 5.80 | 3.74 | 0 |
1 | 1.34 | 0.28 | 0.79 | 1.89 | 4.76 | 0 |
4.3.4 Interaction approach without exact matching within subgroups
Analysts incorporate relevant moderator-covariate interactions into the propensity score model that align with biological plausibility. For instance, in the case study we considered an interaction between age (a covariate) and income (a moderator), but did not include other interactions terms.
<- formula("smoking ~ age*income + gender")
ps.formula.with.int <- matchit(ps.formula.with.int, data = Obs.Data,
match.obj.i method = "full", distance = "glm",link = "logit")
<- match.data(match.obj.i)
match.data.i <- glm(hypertension ~ smoking*income + age + gender,
fit.int.no.exact data = match.data.i, weights = weights,
family = binomial("logit"))
<- interactions::sim_slopes(fit.int.no.exact,
i.nexp.adj.res pred = smoking,
modx = income,
robust = "HC1",
cluster = "subclass",
johnson_neyman = FALSE,
confint = TRUE,
data = match.data.i)
Value of income | Est. | S.E. | 2.5% | 97.5% | z val. | p |
---|---|---|---|---|---|---|
0 | 3.77 | 1.02 | 1.77 | 5.77 | 3.70 | 0 |
1 | 1.35 | 0.28 | 0.80 | 1.91 | 4.77 | 0 |
4.3.5 Interaction approach with exact matching within subgroups
This method bears resemblance to the interaction approach for propensity score estimation. However, when it comes to matching, researchers match within each moderator subgroup.
<- matchit(ps.formula.with.int, data = Obs.Data,
match.obj.is method = "full", distance = "glm",link = "logit",
exact = "income")
<- match.data(match.obj.is)
match.data.is <- glm(hypertension ~ smoking*income + age + gender,
fit.int.exact data = match.data.is, weights = weights,
family = binomial("logit"))
<- interactions::sim_slopes(fit.int.exact,
is.nexp.adj.res pred = smoking,
modx = income,
robust = "HC1",
cluster = "subclass",
johnson_neyman = FALSE,
confint = TRUE,
data = match.data.is)
Value of income | Est. | S.E. | 2.5% | 97.5% | z val. | p |
---|---|---|---|---|---|---|
0 | 3.75 | 1.02 | 1.75 | 5.75 | 3.68 | 0 |
1 | 1.37 | 0.28 | 0.82 | 1.92 | 4.88 | 0 |
4.4 Propensity Score Weighting
4.4.1 Common model
This approach adds confounder-moderator interactions in the common weight model.
require(WeightIt)
library(survey)
library(interactions)
<- weightit(ps.formula.with.int,
W.out data = Obs.Data,
method = "ps",
estimand = "ATT")
<- svydesign(~1, weights = W.out$weights, data = Obs.Data)
d.w <- svyglm(hypertension ~ smoking*income, design = d.w,
fit2w family = quasibinomial("logit"))
<- interactions::sim_slopes(fit2w,
w.nexp.adj.res pred = smoking,
modx = income,
confint = TRUE)
Value of income | Est. | S.E. | 2.5% | 97.5% | t val. | p |
---|---|---|---|---|---|---|
0 | 2.66 | 0.63 | 1.42 | 3.89 | 4.23 | 0 |
1 | 1.32 | 0.25 | 0.83 | 1.82 | 5.24 | 0 |
We can adjust previous analysis model to adopt stabilized weights for the propensity score (stabilize = TRUE
):
<- weightit(ps.formula.with.int, data = Obs.Data,
W.out.st method = "ps",
estimand = "ATT",
stabilize = TRUE)
<- svydesign(~1, weights = W.out.st$weights, data = Obs.Data)
d.sw <- svyglm(hypertension ~ smoking*income + age + gender,
fit2sw design = d.sw,
family = binomial("logit"))
<- interactions::sim_slopes(fit2sw,
ws.nexp.adj.res pred = smoking,
modx = income,
confint = TRUE)
Value of income | Est. | S.E. | 2.5% | 97.5% | t val. | p |
---|---|---|---|---|---|---|
0 | 2.27 | 0.73 | 0.84 | 3.69 | 3.12 | 0 |
1 | 1.32 | 0.25 | 0.83 | 1.82 | 5.23 | 0 |
4.4.2 Separate models
Propensity score weighting approach with weights estimated separately from each subgroup:
<- formula("smoking ~ age + gender")
ps.formula.with.no.int <- weightit(ps.formula.with.no.int,
W.out1 data = subset(Obs.Data, income == 1),
method = "ps",
estimand = "ATT")
1.percent1 <- trim(W.out1$weights,
trimmed.weight.at = 1, lower = TRUE)
Weight | Min. | 1st Qu. | Median | Mean | 3rd Qu. | Max. |
---|---|---|---|---|---|---|
Raw weights | 0 | 0.01 | 0.11 | 0.45 | 1 | 11.69 |
1% truncated weights | 0 | 0.01 | 0.11 | 0.44 | 1 | 7.61 |
# Outcome model for income = 1
<- svydesign(~1, weights = trimmed.weight.1.percent1,
d.w1 data = subset(Obs.Data, income == 1))
<- svyglm(hypertension ~ smoking,
fit2unadj1 design = d.w1,
family = binomial("logit"))
# weight model for income = 0
<- weightit(ps.formula, data = subset(Obs.Data, income == 0),
W.out0 method = "ps", estimand = "ATT")
1.percent0 <- trim(W.out0$weights, at = 1, lower = TRUE)
trimmed.weight.
# Outcome model for income = 0
<- svydesign(~1, weights = trimmed.weight.1.percent0,
d.w0 data = subset(Obs.Data, income == 0))
<- svyglm(hypertension ~ smoking,
fit2unadj0 design = d.w0,
family = binomial("logit"))
<- summ(fit2unadj1, confint = TRUE)
fit.exp.adj.res1 <- summ(fit2unadj0, confint = TRUE) fit.exp.adj.res0
Value of income | Est. | 2.5% | 97.5% | t val. | p |
---|---|---|---|---|---|
0 | 2.21 | 1.27 | 3.15 | 4.60 | 0 |
1 | 1.34 | 0.85 | 1.83 | 5.36 | 0 |
4.4.3 Weights from the subgroup balancing propensity scores
Subgroup balancing propensity scores for propensity score weighting:
<- weightit(smoking ~ age + gender + income,
w.out data = Obs.Data,
method = "ps",
estimand = "ATT")
<- sbps(w.out, moderator = "income")
w.out.sb <- svydesign(~1, weights = w.out.sb$weights, data = Obs.Data)
d.w.sb
<- svyglm(hypertension ~ smoking*income,
fit2unadj.sb design = d.w.sb,
family = binomial("logit"))
<- interactions::sim_slopes(fit2unadj.sb,
sb.w.nexp.adj.res pred = smoking,
modx = income,
confint = TRUE,
johnson_neyman = FALSE)
Value of income | Est. | S.E. | 2.5% | 97.5% | t val. | p |
---|---|---|---|---|---|---|
0 | 2.68 | 0.64 | 1.44 | 3.92 | 4.22 | 0 |
1 | 1.32 | 0.25 | 0.82 | 1.82 | 5.22 | 0 |
4.5 Covariate adjustment for the propensity score
4.5.1 As continuous covariate
An implementation of propensity scores as a continuous covariate in the outcome model:
# Separate models for each subgroup
# For subgroup income = 1
$ps[Obs.Data$income == 1] <- glm(ps.formula,
Obs.Datadata = subset(Obs.Data, income == 1),
family = "binomial")$fitted.values
<- glm(hypertension ~ smoking + age + gender,
fit2adj1 family = binomial("logit"),
data = subset(Obs.Data, income == 1))
# For subgroup income = 0
$ps[Obs.Data$income == 0] <- glm(ps.formula,
Obs.Datadata = subset(Obs.Data, income == 0),
family = "binomial")$fitted.values
<- glm(hypertension ~ smoking + age + gender,
fit2adj0 family = binomial("logit"),
data = subset(Obs.Data, income == 0))
<- summ(fit2adj1, robust = TRUE, confint = TRUE)
fit.nexp.adj.res1 <- summ(fit2adj0, robust = TRUE, confint = TRUE) fit.nexp.adj.res0
Value of income | Est. | 2.5% | 97.5% | z val. | p |
---|---|---|---|---|---|
0 | 1.16 | 0.56 | 1.75 | 3.83 | 0 |
1 | 1.37 | 0.96 | 1.77 | 6.61 | 0 |
# Common model
$ps <- glm(ps.formula.with.int, data = Obs.Data,
Obs.Datafamily = "binomial")$fitted.values
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
<- glm(hypertension ~ smoking*income + age + gender + ps,
fit2adjc family = binomial("logit"),
data = Obs.Data)
<- interactions::sim_slopes(fit2adjc,
c.nexp.adj.res pred = smoking,
modx = income,
confint = TRUE,
data = Obs.Data)
Value of income | Est. | S.E. | 2.5% | 97.5% | z val. | p |
---|---|---|---|---|---|---|
0 | 1.17 | 0.29 | 0.61 | 1.74 | 4.07 | 0 |
1 | 1.43 | 0.23 | 0.98 | 1.87 | 6.30 | 0 |
4.5.2 As quantiles
The propensity scores as a categorical covariate, broken by quintiles, in the outcome model.
$ps <- glm(ps.formula.with.int,
Obs.Datadata = Obs.Data,
family = "binomial")$fitted.values
<- quantile(Obs.Data$ps,
quintiles prob = seq(from = 0, to = 1, by = 0.2),
na.rm = T)
$psq <- cut(Obs.Data$ps, breaks = quintiles,
Obs.Datalabels = seq(1,5), include.lowest = T)
$psq <- as.factor(Obs.Data$psq)
Obs.Data
<- glm(hypertension ~ (smoking*psq)*income,
fit2adjq family = binomial("logit"),
data = Obs.Data)
<- interactions::sim_slopes(fit2adjq,
cq.nexp.adj.res pred = smoking,
modx = income,
confint = TRUE,
data = Obs.Data)
Value of income | Est. | S.E. | 2.5% | 97.5% | z val. | p |
---|---|---|---|---|---|---|
0 | 3.08 | 0.63 | 1.85 | 4.32 | 4.91 | 0 |
1 | 2.60 | 0.47 | 1.68 | 3.51 | 5.56 | 0 |
4.6 Propensity Score Stratification
Here is an implementation of propensity score stratification approach by using the marginal mean weighting through stratification (MMWS):
<- matchit(ps.formula, data = Obs.Data,
match.obj method = "subclass", subclass = 3,
estimand = "ATT", min.n = 10)
<- match.data(match.obj)
data.subclass
<- glm(hypertension ~ smoking*income,
subclass.fit family = binomial("logit"),
data = data.subclass,
weights = weights)
<- interactions::sim_slopes(subclass.fit,
subclass.nexp.adj.res pred = smoking,
modx = income,
confint = TRUE,
robust = "HC3",
johnson_neyman = FALSE,
data = data.subclass)
Value of income | Est. | S.E. | 2.5% | 97.5% | z val. | p |
---|---|---|---|---|---|---|
0 | 2.21 | 0.47 | 1.29 | 3.13 | 4.71 | 0 |
1 | 1.89 | 0.19 | 1.51 | 2.26 | 9.78 | 0 |
4.7 Summary
The marginal odds ratios for smoking
are summarized below
Version info
This chapter was rendered using the following version of R and its packages:
R version 4.2.3 (2023-03-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 22.04.4 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so
locale:
[1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8
[4] LC_COLLATE=C.UTF-8 LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8
[7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C
[10] LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] grid stats graphics grDevices utils datasets methods
[8] base
other attached packages:
[1] interactions_1.1.5 survey_4.4-1 survival_3.5-3 Matrix_1.6-5
[5] interactionR_0.1.7 simcausal_0.5.6 scales_1.3.0 ggplot2_3.5.0
[9] xtable_1.8-4 dplyr_1.1.4 kableExtra_1.4.0 knitr_1.45
[13] cowplot_1.1.3 broom_1.0.5 MatchIt_4.5.5 jtools_2.2.2
[17] sandwich_3.1-0 lmtest_0.9-40 zoo_1.8-12 optmatch_0.10.7
[21] WeightIt_0.14.2 cobalt_4.5.4 table1_1.4.3
loaded via a namespace (and not attached):
[1] fontquiver_0.2.1 tools_4.2.3 backports_1.4.1
[4] utf8_1.2.4 R6_2.5.1 DBI_1.2.2
[7] colorspace_2.1-0 withr_3.0.0 tidyselect_1.2.1
[10] curl_5.2.1 compiler_4.2.3 textshaping_0.3.7
[13] cli_3.6.2 expm_0.999-9 flextable_0.9.5
[16] xml2_1.3.6 officer_0.6.5 fontBitstreamVera_0.1.1
[19] labeling_0.4.3 mvtnorm_1.2-4 askpass_1.2.0
[22] systemfonts_1.0.6 stringr_1.5.1 digest_0.6.35
[25] rmarkdown_2.26 svglite_2.1.3 gfonts_0.2.0
[28] pkgconfig_2.0.3 htmltools_0.5.7 highr_0.10
[31] fastmap_1.1.1 htmlwidgets_1.6.4 rlang_1.1.3
[34] rstudioapi_0.15.0 httpcode_0.3.0 shiny_1.8.0
[37] farver_2.1.1 generics_0.1.3 jsonlite_1.8.8
[40] car_3.1-2 zip_2.3.1 magrittr_2.0.3
[43] Formula_1.2-5 Rcpp_1.0.12 munsell_0.5.0
[46] fansi_1.0.6 abind_1.4-5 gdtools_0.3.7
[49] lifecycle_1.0.4 chk_0.9.1 stringi_1.8.3
[52] yaml_2.3.8 carData_3.0-5 promises_1.2.1
[55] crayon_1.5.2 lattice_0.20-45 splines_4.2.3
[58] pander_0.6.5 pillar_1.9.0 igraph_2.0.3
[61] uuid_1.2-0 codetools_0.2-19 crul_1.4.0
[64] glue_1.7.0 evaluate_0.23 msm_1.7.1
[67] mitools_2.4 fontLiberation_0.1.0 data.table_1.15.2
[70] vctrs_0.6.5 httpuv_1.6.14 gtable_0.3.4
[73] openssl_2.1.1 purrr_1.0.2 tidyr_1.3.1
[76] assertthat_0.2.1 xfun_0.42 mime_0.12
[79] later_1.3.2 ragg_1.3.0 viridisLite_0.4.2
[82] tibble_3.2.1 ellipsis_0.3.2 rlemon_0.2.1