0
$\begingroup$

I have a propensity score weighted population (using IPTW) and I want to compute risk ratios on my weighted population. For this, I am using a weighted Poisson regression.

Let's suppose that "married" is the outcome and I want to see the risk ratio of treated vs non treated considering married as outcome.

library(WeightIt)
library(survey)
W.out <- weightit(treat ~ age + educ + race + nodegree + re74 + re75,
                  data = lalonde, estimand = "ATE", method = "ps")

d.w <- svydesign(~1, weights = W.out$weights, data = lalonde)
fit <- svyglm(married ~ treat , design = d.w, family="poisson") 
exp(coefficients(fit))
exp(confint.default(fit))

For instance, in this case the weighted rate of "married" for each group is:

married_treated <- with(lalonde, weighted.mean(married[treat == 1], W.out$weights[treat == 1]))
married_nontreated <- with(lalonde, weighted.mean(married[treat == 0], W.out$weights[treat == 0]))

The result of the Poisson regression is basically equal to the ratio between married_treated / married_nontreated. This should be correct because RR is risk of outcome in exposed people / risk of outcome in unexposed.

The risk of outcome in exposed patients is equal to the frequency of married people in the total exposed group divided by the total n° of people in the exposed group (married/total n° exposed). Subsequently, the weighted rate of married in the treated group should be the weighted risk in the exposed while the weighted rate of married in the non treated group should be the weighted risk in the non exposed. Therefore, RR = weighted risk treated / weighted risk non treated. However, I would like a confirmation.

Is this the correct way of computing risk ratios in a population balanced through IPTW?

$\endgroup$

1 Answer 1

2
$\begingroup$

That's one way to do it. But if you include covariates in the outcome model or if you want to generalize the effect to a subset of your population (e.g., for the average treatment effect in the treated), you should use weighted g-computation instead. This is explained in the WeightIt vignette on estimating effects.

Weighted g-computation involves fitting an outcome model with the IPW weights applied, then generating predicted values of the outcome under treatment and under control for each unit. Then, you computed the IPW-weighted mean of the predicted outcomes under treatment and under control, which are the marginal risks. Finally, you can take the ratio of the marginal risks and that is your IPW- and covariate-adjusted estimate of the marginal risk ratio. A benefit of this method is that you can use whatever model you want to fit the outcome model because the risk ratio does not correspond to a coefficient in the outcome model but rather is a function of the covariates, the model parameters, and the weights. This is important when including covariates in the outcome model because a Poisson model is rarely if ever the right model for a binary outcome. It is useful as a convenience because the coefficient on treatment is equal to the log risk ratio, but that is only true when no covariates are present in the model. In contrast, a logistic regression model is more likely to fit the data well and generate valid predictions.

Below is how to do weighted g-computation manually. Getting standard errors is hard unless you bootstrap.

library(WeightIt)

data("lalonde", package = "cobalt")

W.out <- weightit(treat ~ age + educ + race + nodegree + re74 + re75,
                  data = lalonde, estimand = "ATE", method = "ps")

library(survey)
d.w <- svydesign(~1, weights = W.out$weights, data = lalonde)
fit <- svyglm(married ~ treat * (age + educ + race + nodegree + re74 + re75),
              design = d.w,  family = "quasibinomial")

# Predicted outcomes under treatment
pred_1 <- predict(fit, newdata = transform(lalonde, treat = 1),
                  type = "response")

# Predicted outcomes under control
pred_0 <- predict(fit, newdata = transform(lalonde, treat = 0),
                  type = "response")

# Marignal risks udner treatment and control
Epred_1 <- weighted.mean(pred_1, W.out$weights)
Epred_0 <- weighted.mean(pred_0, W.out$weights)

# Marginal risk ratio
(RR <- Epred_1 / Epred_0)
#> [1] 0.6167727

Below is how you do it using marginaleffects as explained in the WeightIt vignette.

# Using marginaleffects
library(marginaleffects)
avg_comparisons(fit, variables = "treat",
                comparison = "lnratioavg",
                transform = "exp",
                wts = "(weights)")
#> 
#>   Term              Contrast Estimate Pr(>|z|) 2.5 % 97.5 %
#>  treat ln(mean(1) / mean(0))    0.617    0.048 0.382  0.996
#> 
#> Columns: term, contrast, estimate, p.value, conf.low, conf.high, predicted, predicted_hi, predicted_lo

You should always use the marginaleffects strategy because it produces the right answer no matter what outcome model you use or whether you have covariates in the outcome model or not. When there are no covariates in the outcome model, it produces the same estimate as the exponentiated coefficient on treatment in a Poisson regression model.

$\endgroup$
8
  • $\begingroup$ Thank you so much as always! :) $\endgroup$ Commented Apr 15, 2023 at 22:00
  • $\begingroup$ What is the difference between for example writing like 'fit <- svyglm(married ~ treat + age + educ + race + nodegree + re74 + re75, design = d.w)' and 'fit <- svyglm(married ~ treat * (age + educ + race + nodegree + re74 + re75), design = d.w, family = "quasibinomial")' . Is there a difference due to the presence of * ? $\endgroup$ Commented Apr 15, 2023 at 22:03
  • $\begingroup$ Since you are an expert of IPTW I wanted to ask you something. I have to perform a weighted chi square test and since I am not so good with using svydesign I found this function from weights package: wtd.chi.sq . I just want to compare the difference in the weighted rates of my outcome stratified by treatment thus it is like a normal chi square but taking into account weights. Do you think it is the correct function? Also considering this post which I found and confused me a bit. stackoverflow.com/questions/50396708/… $\endgroup$ Commented Apr 15, 2023 at 23:40
  • $\begingroup$ (My double is whether to set mean1=FALSE or not because I dont quite understand rdocumentation.org/packages/weights/versions/1.0.4/topics/…) $\endgroup$ Commented Apr 15, 2023 at 23:45
  • $\begingroup$ The model I wrote includes interactions between treatment and all the covariates. This is generally a good idea because it makes the model more plausible and doesn't cost much in terms of precision even if those interactions don't exist in reality. I always include such interactions when possible. If you have many covariates, you can omit the ones that are well-balanced and are thought to be less associated with the outcome. $\endgroup$
    – Noah
    Commented Apr 16, 2023 at 5:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.