ngreifer / WeightIt

WeightIt: an R package for propensity score weighting
https://ngreifer.github.io/WeightIt/
102 stars 12 forks source link

Estimation of weights in case of effect modification #52

Closed lorenzoFabbri closed 10 months ago

lorenzoFabbri commented 1 year ago

I would like to explore the possibility of effect modification (between exposure and one or more covariates) in my models. VanderWeele provides the following formula for the weights of a Marginal Structural Model (for effect modification rather than interaction) [1]:

$$ w_i^E = \frac{P(E = e_i | Q = q_i)}{P(E = e_i | Q = q_i, X = x_i)}, $$

with $E$ being the treatment/exposure, $Q$ the effect modifier, and $X$ the confounders. In my case, the exposure $E$ is continuous, while $Q$ can be either continuous or categorical (up to 6 levels).

I would like to know whether this is possible with the WeightIt package (right now I am using the energy method). I thought about estimating the weights passing $Q$ to the by argument.

[1] On the Distinction Between Interaction and Effect Modification. DOI: 10.1097/EDE.0b013e3181ba333c.

ngreifer commented 1 year ago

The recommended approach is to estimate weights separately in each group of the effect modifier. You can do this using the by argument as you mentioned. This method is agnostic to how the weights are created, and so is compatible with energy balancing or any other method.

The expression you found is correct only when the propensity score model is correct. Notice that the denominator of the weights is identical to what it would be if $Q$ was just a covariate. There is no special formula for propensity scores in the context of effect modification. Using a stabilization factor in the numerator is optional as described in the paper, and is in accordance with the general advice given in Cole & Hernán (2008) that if you are adjusting for a covariate in the outcome model, you can include it in the stabilization factor at no cost, where it is also optional.

So, what I mean to communicate is that this is not a special formula for weights under effect modification; this is a general formula for propensity score weights, and the stabilization factor is optional and consistent with its use in standard analysis of weighted treatment effect estimates. I also want to say that the empirical application of this formula may not yield the least bias or most precise estimates of the subgroup treatment effects; a method that fully achieves balance within each subgroup will do that, and such a method typically involves estimating weights separately within each subgroup, which you can do using the by argument. Rather than thinking about the formula for a propensity score model, think about weights that achieve balance; energy balancing weights do not estimate propensity scores and don't involve a model (except in an abstract, implicit way), and so do not correspond to the formula you included.

lorenzoFabbri commented 11 months ago

I am trying to explore covariates balance after estimating the weights. I am using the data d used in the vignette for continuous treatments, and adding by = "X5". I then proceed to generate a love plot, by passing the cluster argument set to X5. I get the following error message:

Error in UseMethod("as.cluster") : 
  no applicable method for 'as.cluster' applied to an object of class "logical"

Am I missing something?

ngreifer commented 11 months ago

Can you paste the code you are using? That suggests some other package is interfering with cobalt because as.cluster() is not called by either cobalt or WeightIt.

lorenzoFabbri commented 11 months ago

You are right. In a new session I do not get that error. But I am not loading any library when I run my analyses (with library(...))...

ngreifer commented 11 months ago

Again, without seeing what code you're actually running I have no idea why you could be getting this error. as.cluster() seems to only exist in the parallelly package, which may be loaded by another package you are using in your pipeline. Still, it shouldn't affect cobalt operations unless you have something specific in your code, which is why I would need to see your code to diagnose and fix the problem.

lorenzoFabbri commented 10 months ago

I am still facing this issue although I have nothing special in my code. I just found out that parallelly might be loaded by the targets R package, which I am using for the analysis pipeline. A temporary fix is to use subset with love.plot.

ngreifer commented 10 months ago

If you are using targets for your analysis pipeline, then there is something special in your code. This package seems to automatically open parallel processing units. Please send me your code if you want any chance of this being fixed. Otherwise I am completely in the dark and can't fix this.