<div dir="ltr">Dear Wolfgang,<div><br></div><div>Thank you very much for confirming the calculations!! Tha's great that they are correct! Actually, by "miscalculation", I have rather meant the order, not the numbers. </div><div><br></div><div>The thing that confuses me a lot is that according to forest plot examination and standardized (deleted) residuals, the 1st experiment is an outlier. But according to Cook’s distance plot, the 2nd experiment is influential. Looking at the forest plot, it is really hard to believe that the removal of the 2nd experiment can affect the pooled estimate (its mean is close to the overall effect estimate and CI does overlap (almost included) with CI of the overall effect).</div><div><img src="cid:ii_kz9lhpgi0" alt="image.png" width="562" height="384" style="margin-right: 0px;"><br></div><img src="cid:ii_kz9liz8t1" alt="image.png" width="562" height="424"><br><div><br></div><div><br></div><div>Sincerely,</div><div>Antonina</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Feb 4, 2022 at 7:17 PM Viechtbauer, Wolfgang (SP) <<a href="mailto:wolfgang.viechtbauer@maastrichtuniversity.nl" target="_blank">wolfgang.viechtbauer@maastrichtuniversity.nl</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Just as a brief follow-up with respect to the calculations: They are correct. Continuing with your code, Antonina, we can easily manually compute the Cook's distances here:<br>
<br>
cooksd[1:2]<br>
<br>
sub <- <a href="http://rma.mv" rel="noreferrer" target="_blank">rma.mv</a>(yi, vi,<br>
              random = ~ 1 | study/experiment,<br>
              data=dat, subset=-1)<br>
<br>
(coef(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>) - coef(sub))^2 / vcov(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>)<br>
<br>
sub <- <a href="http://rma.mv" rel="noreferrer" target="_blank">rma.mv</a>(yi, vi,<br>
              random = ~ 1 | study/experiment,<br>
              data=dat, subset=-2)<br>
<br>
(coef(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>) - coef(sub))^2 / vcov(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>)<br>
<br>
As you will see, these match up.<br>
<br>
With these data, removal of a single row can have a large impact on the variance components, which can lead to considerable changes in the pooled estimate.<br>
<br>
Best,<br>
Wolfgang<br>
<br>
>-----Original Message-----<br>
>From: R-sig-meta-analysis [mailto:<a href="mailto:r-sig-meta-analysis-bounces@r-project.org" target="_blank">r-sig-meta-analysis-bounces@r-project.org</a>] On<br>
>Behalf Of Reza Norouzian<br>
>Sent: Friday, 04 February, 2022 8:01<br>
>To: Antonina Dolgorukova<br>
>Cc: R meta<br>
>Subject: Re: [R-meta] possible miscalculation of Cook’s distances<br>
><br>
>Dear Antonina,<br>
><br>
>There was no rationale, I just wanted to indicate that there is no bug<br>
>in the function (and save myself a tiny bit of time). The default<br>
>reestimate = TRUE is certainly to be preferred given that your model<br>
>does include random-effects and, as the documentation correctly<br>
>mentions, the influence of each effect estimate on the estimates of<br>
>heterogeneity and correlation can only be examined, if you set<br>
>reestimate = TRUE.<br>
><br>
>For instance, if you remove the random-effects from your initial model<br>
>(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>), then, you'll see that the use of reestimate = TRUE or FALSE<br>
>has no effect. In both cases, only the effect estimate associated with<br>
>study 1, experiment 1 is influential. Thus, this shows that the use of<br>
>reestimate = FALSE in your initial model essentially ignored the<br>
>influence of each effect estimate on the estimates of heterogeneity.<br>
><br>
>In models with complex random-effects structure esp. fit to large<br>
>datasets, setting reestimate = TRUE would take a good chunk of time.<br>
>In such cases, some (myself included) may be tempted to set reestimate<br>
>= FALSE hoping that the approximation will be close enough.<br>
><br>
>Kind regards,<br>
>Reza<br>
><br>
>res.ml2 <- update.rma(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>, random = NULL)<br>
><br>
>cook_with_reest2 <- <a href="http://cooks.distance.rma.mv" rel="noreferrer" target="_blank">cooks.distance.rma.mv</a>(res.ml2)<br>
>cook_without_reest2 <- <a href="http://cooks.distance.rma.mv" rel="noreferrer" target="_blank">cooks.distance.rma.mv</a>(res.ml2, reestimate = FALSE)<br>
><br>
>plot(cook_with_reest2,type="b")<br>
>plot(cook_without_reest2,type="b")<br>
><br>
>On Fri, Feb 4, 2022 at 12:19 AM Antonina Dolgorukova<br>
><<a href="mailto:an.dolgorukova@gmail.com" target="_blank">an.dolgorukova@gmail.com</a>> wrote:<br>
>><br>
>> Dear Reza,<br>
>><br>
>> Thank you very much for your reply. I do understand that not all outliers have<br>
>to be influential and that not all influential cases have to be outliers. But<br>
>thank you for mentioning this and for the code provided. I did notice you set the<br>
>reestimate = FALSE. This raises two questions, actually. It would be great if you<br>
>help with them.<br>
>><br>
>> 1) Is there any explanation why <a href="http://cooks.distance.rma.mv" rel="noreferrer" target="_blank">cooks.distance.rma.mv</a>(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>) and<br>
><a href="http://cooks.distance.rma.mv" rel="noreferrer" target="_blank">cooks.distance.rma.mv</a>(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a> , reestimate = FALSE) give completely different<br>
>results about the experiments 1 and 2 (and very similar for the remaining<br>
>experiments)?<br>
>><br>
>> According to <a href="http://cooks.distance.rma.mv" rel="noreferrer" target="_blank">cooks.distance.rma.mv</a>(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>), the Study 1, Experiment 2 is<br>
>influential, but<br>
>> according to  <a href="http://cooks.distance.rma.mv" rel="noreferrer" target="_blank">cooks.distance.rma.mv</a>(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a> , reestimate = FALSE), Study 1,<br>
>Experiment 1 is influential<br>
>><br>
>><br>
>> #the code illustrating my question<br>
>><br>
>> dat <- data.frame(study=c(1,1,2,3,3,3), experiment=c(1:6),<br>
>>                   yi=c( 68, 18, 31,20,10,26),<br>
>>                   vi=c(60,32, 15, 19, 41, 82))<br>
>><br>
>> <a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a> <- <a href="http://rma.mv" rel="noreferrer" target="_blank">rma.mv</a>(yi, vi,<br>
>>                  random = ~ 1 | study/experiment,<br>
>>                  data=dat,<br>
>>                  slab = paste("Study ", study,", ", "Experiment ", experiment,<br>
>sep = ""))<br>
>><br>
>> cook_with_reest <- <a href="http://cooks.distance.rma.mv" rel="noreferrer" target="_blank">cooks.distance.rma.mv</a>(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>)<br>
>> cook_without_reest <- <a href="http://cooks.distance.rma.mv" rel="noreferrer" target="_blank">cooks.distance.rma.mv</a>(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>, reestimate = FALSE)<br>
>><br>
>> plot(1:length(cook_with_reest), cook_with_reest, ylim=c(0,2), type="o", pch=19,<br>
>las=1, xaxt="n",<br>
>>      xlab="Study and Experiment ID", ylab="Cook's Distance")<br>
>> points(cook_without_reest, type="o", pch=19, col = "red")<br>
>> axis(1, 1:length(cook_with_reest), labels=names(cook_with_reest))<br>
>> abline(h=4/length(cook_with_reest), lty="dotted", lwd=2)<br>
>> legend("top", pch=19, col=c("black","red"), lty="solid",<br>
>>        legend=c("reestimate = TRUE","reestimate = FALSE"), bty="n")<br>
>><br>
>> 2) And could you please explain what is the rationale to set reestimate =<br>
>FALSE? According to the metafor documentation:<br>
>> "Doing so only yields an approximation to the Cook’s distances that ignores the<br>
>influence of the ith case on the variance/correlation components"<br>
>><br>
>> Sincerely,<br>
>> Antonina<br>
>><br>
>> On Fri, Feb 4, 2022 at 3:29 AM Reza Norouzian <<a href="mailto:rnorouzian@gmail.com" target="_blank">rnorouzian@gmail.com</a>> wrote:<br>
>>><br>
>>> Dear Antonina,<br>
>>><br>
>>> An effect estimate whose standardized deleted residual falls beyond<br>
>>> +/-1.96 doesn't necessarily need to have a cook's distance<br>
>>> (influence), and/or a hat value (if additional moderators are used)<br>
>>> that are likewise extreme.<br>
>>><br>
>>> As a general proposition, it may be methodologically more reasonable<br>
>>> to simultaneously consult all these indices to flag an extreme effect<br>
>>> estimate.<br>
>>><br>
>>> That said, in your case, it does seem that the estimate from study 1,<br>
>>> experiment 1 has a large standardized deleted residual as well as a<br>
>>> large Cook's distance relative to that of other effect estimates. So,<br>
>>> I don't think there is any bug in any of the metafor functions you<br>
>>> used.<br>
>>><br>
>>> Below is a bit of code to catch that outlying effect estimate.<br>
>>><br>
>>> Kind regards,<br>
>>> Reza<br>
>>><br>
>>> dat <- data.frame(study=c(1,1,2,3,3,3), experiment=c(1:6),<br>
>>>                   yi=c( 68, 18, 31,20,10,26),<br>
>>>                   vi=c(60,32, 15, 19, 41, 82))<br>
>>><br>
>>> <a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a> <- <a href="http://rma.mv" rel="noreferrer" target="_blank">rma.mv</a>(yi, vi,<br>
>>>                  random = ~ 1 | study/experiment,<br>
>>>                  data=dat,<br>
>>>                  slab = paste("Study ", study,", ", "Experiment ",<br>
>>>                               experiment, sep = ""))<br>
>>><br>
>>> dat <- transform(dat, obs = <a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>$slab)<br>
>>><br>
>>> outlier_limit <- qnorm(.975)<br>
>>><br>
>>> cook <- <a href="http://cooks.distance.rma.mv" rel="noreferrer" target="_blank">cooks.distance.rma.mv</a>(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>,<br>
>>>                               reestimate = FALSE)<br>
>>><br>
>>> st_del_res_z <- <a href="http://rstudent.rma.mv" rel="noreferrer" target="_blank">rstudent.rma.mv</a>(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>,<br>
>>>                                 reestimate = FALSE)$z<br>
>>><br>
>>> cook_limit <- max(mean(range(cook)), boxplot.stats(cook, coef = 1.5)$stats[5])<br>
>>><br>
>>> i <- abs(st_del_res_z) > outlier_limit<br>
>>> k <- cook > cook_limit<br>
>>> oo <- which(i & k)<br>
>>><br>
>>> LL <- names(oo)<br>
>>><br>
>>> removed <- subset(dat, obs %in% LL)<br>
>>> new_dat <- subset(dat, !obs %in% LL)<br>
>>><br>
>>> On Thu, Feb 3, 2022 at 3:36 PM Antonina Dolgorukova<br>
>>> <<a href="mailto:an.dolgorukova@gmail.com" target="_blank">an.dolgorukova@gmail.com</a>> wrote:<br>
>>> ><br>
>>> > Dear Dr. Viechtbauer and all,<br>
>>> ><br>
>>> > I have a multilevel data structure (experiments nested within studies) are<br>
>>> > use <a href="http://rma.mv" rel="noreferrer" target="_blank">rma.mv</a> to calculate an overall effect estimate. The next step requires<br>
>>> > sensitivity analysis on the experiment-level data. For detecting outliers<br>
>>> > I've used standardized (deleted) residuals and for detecting influential<br>
>>> > experiments I've used Cook’s distance. However, the last test provides<br>
>>> > contradictory results.<br>
>>> ><br>
>>> > The forest plot indicates that the 1st experiment may be an outlier, and<br>
>>> > standardized (deleted) residuals confirm this. But according to Cook’s<br>
>>> > distance plot, the 2nd experiment is influential. It seems that there may<br>
>>> > be a miscalculation of Cook’s distance since I can easily reproduce this<br>
>>> > issue (in one study one of the experiments have to provide a much larger ES<br>
>>> > than the other) also if use the model with random = ~ 1 | experiment, the<br>
>>> > 1st experiment is influential, not the second.<br>
>>> ><br>
>>> > Could you please clarify is this a bug or a feature of the cooks.distance()<br>
>>> > function? Maybe it does not work properly with <a href="http://rma.mv" rel="noreferrer" target="_blank">rma.mv</a> objects?<br>
>>> ><br>
>>> >   ## Reproducible Example<br>
>>> ><br>
>>> > # data frame<br>
>>> >   dat <- data.frame(study=c(1,1,2,3,3,3), experiment=c(1:6),<br>
>>> >                     yi=c( 68, 18, 31,20,10,26),<br>
>>> >                     vi=c(60,32, 15, 19, 41, 82))<br>
>>> ><br>
>>> > # multilevel model<br>
>>> > <a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a> <- <a href="http://rma.mv" rel="noreferrer" target="_blank">rma.mv</a>(yi, vi,<br>
>>> >                  random = ~ 1 | study/experiment,<br>
>>> >                  data=dat,<br>
>>> >                  slab = paste("Study ", study,", ", "Experiment ",<br>
>>> > experiment, sep = ""))<br>
>>> ><br>
>>> > # forest plot examination  indicates that the 1st experiment may be an<br>
>>> > outlier<br>
>>> > forest(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>,<br>
>>> >        header = "Study and Experiment ID")<br>
>>> ><br>
>>> > # standardized (deleted) residuals confirm this<br>
>>> > rst <- rstudent(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>)<br>
>>> > plot(NA, NA, xlim=c(1, <a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>$k), ylim=c(-3,5),<br>
>>> >      xlab="Study and Experiment ID", ylab="Standardized (Deleted) Residual",<br>
>>> >      xaxt="n", las=1)<br>
>>> > axis(side=1, at=1:<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>$k, labels=rst$slab)<br>
>>> > abline(h=c(-1.96,1.96), lty="dotted")<br>
>>> > abline(h=0)<br>
>>> > points(1:<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>$k, rst$z, type="o", pch=19)<br>
>>> ><br>
>>> > # according to Cook’s distance plot, the 2nd experiment is influential<br>
>>> > cooksd <- cooks.distance(<a href="http://res.ml" rel="noreferrer" target="_blank">res.ml</a>)<br>
>>> > plot(1:length(cooksd), cooksd, ylim=c(0,2), type="o", pch=19, las=1,<br>
>>> > xaxt="n",<br>
>>> >      xlab="Experiment ID", ylab="Cook's Distance")<br>
>>> > axis(1, 1:length(cooksd), labels=names(cooksd))<br>
>>> > abline(h=4/length(cooksd), lty="dotted", lwd=2)<br>
>>> ><br>
>>> > sessionInfo()<br>
>>> > R version 4.1.2 (2021-11-01)<br>
>>> > Platform: x86_64-w64-mingw32/x64 (64-bit)<br>
>>> > Running under: Windows 10 x64 (build 19042)<br>
>>> > [1] metafor_3.1-43 metadat_1.0-0  Matrix_1.3-4<br>
>>> ><br>
>>> > --<br>
>>> > Antonina Dolgorukova, M.D.<br>
>>> > Pavlov First Saint Petersburg State Medical University<br>
>>> > Lev Tolstoy str., 6-8, 197022<br>
>>> > Saint Petersburg, Russia<br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr"><div dir="ltr"><div><div dir="ltr"><div>Antonina Dolgorukova, M.D.</div><div>Pavlov First Saint Petersburg State Medical University</div><div>Lev Tolstoy str., 6-8, <span style="font-family:arial,sans-serif">197022</span></div><div>Saint Petersburg, Russia<br></div></div></div></div></div>