MENU

【無料プレゼント付き】学会発表・論文投稿に必要な統計を最短で学ぶことができる無料メルマガ

metaとmetaforでメタ回帰の結果が違う?原因は設定にあった【R】

研究者: 同じBCGワクチンのデータで、metafor と meta の両方でメタ回帰をしてみたんです。そうしたら、異質性 $\tau^2$ が 0.0504 と 0.3378 で全然違う結果になって……。meta のメタ回帰は $\tau^2$ を推定し直していない、ということでしょうか?

統計ER: 実はそれ、メタ回帰が実行されていないんです。metabin() に mods を書いても、エラーも警告も出ずに無視されてしまいます。metareg() で正しく実行すると、metafor と小数点以下まで同じ結果になりますよ。

メタアナリシスを行うRパッケージとして、meta と metafor は広く使われている。両方を試した人の中には、メタ回帰の結果(標準誤差や $\tau^2$)が食い違って戸惑った経験がある人もいるだろう。

先に結論を述べる。meta の metareg() は、内部で metafor の rma.uni() を呼び出している。したがって、効果量の定義・$\tau^2$ の推定法・検定法の3つが揃っていれば、両者の結果は完全に一致する。結果が違うときは「計算方法の違い」ではなく「設定(またはコード)の違い」を疑えばよい。

本記事はやや細かい話題であるが、両パッケージを行き来する人がつまずきやすい点を、実際にRで答え合わせしながら整理する。


>>もう統計で悩むのは終わりにしませんか? 

↑1万人以上の医療従事者が購読中

目次

メタ回帰と「2種類の $\tau^2$」

メタ回帰(meta-regression)は、研究ごとの効果量が研究の特性(共変量)によってどう変わるかを調べる手法である。例えば、BCGワクチンの効果が、研究が行われた地域の緯度によって違うかを調べたい、というような場合に用いる。変量効果メタ回帰(混合効果モデル)は次の式で表される。

$$y_i = \beta_0 + \beta_1 x_i + u_i + \varepsilon_i, \qquad u_i \sim N(0, \tau^2), \quad \varepsilon_i \sim N(0, v_i)$$

  • $y_i$:研究 $i$ の効果量(ここでは対数オッズ比)、$v_i$:その分散(研究内のばらつき)
  • $x_i$:研究の特性(共変量)。ここでは緯度の絶対値 ablat
  • $\tau^2$:共変量で説明しきれずに残った研究間のばらつき(残差の異質性)

ポイントは、共変量を入れる前と後で $\tau^2$ の意味が変わることである。共変量なしの変量効果モデルの $\tau^2$ は「研究間のばらつき全体」、メタ回帰の $\tau^2$ は「共変量で説明できなかった残りのばらつき」を表す。メタ回帰では、回帰係数とこの残差 $\tau^2$ が同時に推定される。これは metafor でも meta でも同じである。

※コラム:$\tau^2$ が 0.3378 から 0.0504 に減るということ
研究間のばらつきを「教室の騒がしさ」に喩えると、共変量なしの $\tau^2$ は教室全体の騒がしさである。緯度という共変量を入れるのは「窓際の席ほど騒がしい」という法則を見つけるようなもので、その法則で説明できる分を差し引いた残りの騒がしさが残差 $\tau^2$ になる。BCGデータでは $\tau^2$ が 0.3378 から 0.0504 に減り、$(0.3378 – 0.0504)/0.3378 \approx 85\%$ が緯度で説明された。これが metafor の出力にある $R^2 = 85.06\%$ である。


Step 1:metafor でメタ回帰(rma.uni())

例として、metafor に付属する(正確には metadat パッケージに収録された)BCGワクチンの13研究のデータ dat.bcg を使う(Colditz et al., 1994)。tpos/tneg はワクチン群の結核発症あり/なし、cpos/cneg は対照群の発症あり/なし、ablat は研究地域の緯度の絶対値である。

metafor では、まず escalc() で研究ごとの効果量(対数オッズ比 yi)とその分散(vi)を計算し、rma.uni()(rma() でも同じ)の mods 引数に共変量を指定する。

library(metafor)   # metadat(dat.bcg を含む)も自動で読み込まれる
library(meta)

data(dat.bcg)

dat4metafor <- escalc(measure = "OR", ai = tpos, bi = tneg,
                      ci = cpos, di = cneg, data = dat.bcg,
                      slab = paste0(author, ", ", year))

res_metafor <- rma.uni(yi = yi, vi = vi, data = dat4metafor)
print(res_metafor)
forest(res_metafor, transf = exp)

res_metafor_ablat <- rma.uni(yi = yi, vi = vi, mods = ~ ablat,
                             data = dat4metafor)
print(res_metafor_ablat)

共変量なしのメタアナリシス(フォレストプロット):

メタ回帰の結果:

Mixed-Effects Model (k = 13; tau^2 estimator: REML)

tau^2 (estimated amount of residual heterogeneity):     0.0504 (SE = 0.0449)
tau (square root of estimated tau^2 value):             0.2246
I^2 (residual heterogeneity / unaccounted variability): 57.39%
H^2 (unaccounted variability / sampling variability):   2.35
R^2 (amount of heterogeneity accounted for):            85.06%

Test for Residual Heterogeneity:
QE(df = 11) = 25.0954, p-val = 0.0088

Test of Moderators (coefficient 2):
QM(df = 1) = 25.2424, p-val < .0001

Model Results:

         estimate      se     zval    pval    ci.lb    ci.ub
intrcpt    0.3010  0.2146   1.4025  0.1608  -0.1197   0.7217
ablat     -0.0315  0.0063  -5.0242  <.0001  -0.0438  -0.0192  ***

---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

緯度が1度高くなるごとに対数オッズ比が 0.0315 小さくなる(オッズ比にすると $\exp(-0.0315) \approx 0.97$ 倍)、つまり高緯度の地域ほどワクチンの効果が大きいという結果である。残差の $\tau^2$ は 0.0504 で、共変量なしのモデルの 0.3378 から大きく減っている。


>>もう統計で悩むのは終わりにしませんか? 

↑1万人以上の医療従事者が購読中

Step 2:meta でメタ回帰(metabin() → metareg())

meta では、まず metabin() などでメタアナリシスを行い、その結果オブジェクトを metareg() に渡してメタ回帰を行う。ここに、冒頭の研究者がはまった落とし穴がある。

落とし穴:metabin() に mods を書いても無視される

metafor の感覚で、metabin() に mods = ~ ablat を書いてみる。

res_meta <- metabin(event.e = tpos, n.e = tpos + tneg,
                    event.c = cpos, n.c = cpos + cneg,
                    data = dat.bcg, sm = "OR",
                    common = FALSE, random = TRUE,
                    studlab = paste0(author, ", ", year))
print(res_meta)
forest(res_meta)

# 落とし穴:metabin() に mods を渡しても、エラーも警告も出ずに無視される
res_meta_mods <- metabin(event.e = tpos, n.e = tpos + tneg,
                         event.c = cpos, n.c = cpos + cneg,
                         data = dat.bcg, sm = "OR", mods = ~ ablat,
                         common = FALSE, random = TRUE,
                         studlab = paste0(author, ", ", year))
all.equal(res_meta_mods$TE.random, res_meta$TE.random)  # TRUE:中身は同じ

res_meta_mods を表示すると、次のように共変量なしの変量効果モデルの結果がそのまま表示される。

Number of studies: k = 13
Number of observations: o = 357347 (o.e = 191064, o.c = 166283)
Number of events: e = 2575

                         OR           95% CI     z  p-value
Random effects model 0.4746 [0.3296; 0.6835] -4.01 < 0.0001

Quantifying heterogeneity (with 95% CIs):
 tau^2 = 0.3378 [0.1302; 1.1812]; tau = 0.5812 [0.3608; 1.0868]
 I^2 = 92.6% [89.2%; 95.0%]; H = 3.69 [3.04; 4.47]

Test of heterogeneity:
      Q d.f.  p-value
 163.16   12 < 0.0001

Details of meta-analysis methods:
- Inverse variance method
- Restricted maximum-likelihood estimator for tau^2
- Q-Profile method for confidence interval of tau^2 and tau
- Calculation of I^2 based on Q

ここに表示されている $\tau^2 = 0.3378$ は、共変量なしの「研究間のばらつき全体」である。これを metafor のメタ回帰の残差 $\tau^2 = 0.0504$ と比べると、「meta は $\tau^2$ を推定し直していない」ように見えてしまう。しかし実際には、比べているものが「メタ回帰前」と「メタ回帰後」で違うだけである。

※コラム:なぜエラーにならないのか
metabin() には、古い引数名を受け止めるための ... 引数がある。知らない引数(ここでは mods)はこの「何でも入る受け皿」に吸い込まれ、使われないまま捨てられる。宛名の書き間違いの郵便物が、差し戻されずに保管庫へ回されるようなものだ。Rの関数では珍しくない挙動なので、「エラーが出なかった=意図どおり動いた」とは限らないことを覚えておきたい。

正しくは metareg() を使う

res_meta_ablat <- metareg(res_meta, ~ ablat)
print(res_meta_ablat)
Mixed-Effects Model (k = 13; tau^2 estimator: REML)

tau^2 (estimated amount of residual heterogeneity):     0.0504 (SE = 0.0449)
tau (square root of estimated tau^2 value):             0.2246
I^2 (residual heterogeneity / unaccounted variability): 57.39%
H^2 (unaccounted variability / sampling variability):   2.35
R^2 (amount of heterogeneity accounted for):            85.06%

Test for Residual Heterogeneity:
QE(df = 11) = 25.0954, p-val = 0.0088

Test of Moderators (coefficient 2):
QM(df = 1) = 25.2424, p-val < .0001

Model Results:

         estimate      se     zval    pval    ci.lb    ci.ub
intrcpt    0.3010  0.2146   1.4025  0.1608  -0.1197   0.7217
ablat     -0.0315  0.0063  -5.0242  <.0001  -0.0438  -0.0192  ***

---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Step 1 の metafor の出力と見比べてほしい。回帰係数、標準誤差、残差 $\tau^2$、$R^2$ まですべて同じである。出力の見た目まで同じなのには理由がある。


Step 3:metareg() の中身は metafor だった

class(res_meta_ablat)

# 研究ごとの効果量(対数OR)と分散は escalc() と同じ
all.equal(res_meta$TE, as.numeric(dat4metafor$yi))
all.equal(res_meta$seTE^2, as.numeric(dat4metafor$vi))

# 2つのモデルを並べて比べる関数
compare_fit <- function(fit_meta, fit_metafor) {
  data.frame(term        = names(coef(fit_metafor)),
             est_meta    = round(coef(fit_meta), 4),
             est_metafor = round(coef(fit_metafor), 4),
             se_meta     = round(fit_meta$se, 4),
             se_metafor  = round(fit_metafor$se, 4),
             tau2_meta   = round(fit_meta$tau2, 4),
             tau2_metafor = round(fit_metafor$tau2, 4),
             row.names = NULL)
}
compare_fit(res_meta_ablat, res_metafor_ablat)
> class(res_meta_ablat)
[1] "metareg" "rma.uni" "rma"
> all.equal(res_meta$TE, as.numeric(dat4metafor$yi))
[1] TRUE
> all.equal(res_meta$seTE^2, as.numeric(dat4metafor$vi))
[1] TRUE
> compare_fit(res_meta_ablat, res_metafor_ablat)
     term est_meta est_metafor se_meta se_metafor tau2_meta tau2_metafor
1 intrcpt   0.3010      0.3010  0.2146     0.2146    0.0504       0.0504
2   ablat  -0.0315     -0.0315  0.0063     0.0063    0.0504       0.0504

metareg() の結果のクラスは "metareg" "rma.uni" "rma"、つまり metafor の rma.uni オブジェクトそのものである。metareg() は、metabin() が計算した研究ごとの効果量 TE と標準誤差 seTE を取り出し、次の設定で metafor::rma.uni() を呼び出している。

  • 効果量:yi = TE、sei = seTE(metabin() で計算したもの)
  • $\tau^2$ の推定法:method = メタアナリシスで使った method.tau(既定値は REML)
  • 検定法:メタアナリシスで Hartung-Knapp 法(method.random.ci = "HK")を使っていれば test = "knha"、そうでなければ test = "z"

喩えるなら、meta と metafor は同じエンジンを積んだ2台の車である。meta はダッシュボード(フォレストプロットや出力の見やすさ)を整えた車で、メタ回帰の場面ではボンネットの中で metafor のエンジンが回っている。エンジンが同じなので、同じ燃料(効果量)を入れ、同じ走行モード($\tau^2$ の推定法と検定法)を選べば、走りは完全に同じになる。


Step 4:それでも標準誤差が違うときのチェックリスト

逆に言えば、両者の結果が違うときは、燃料か走行モードのどこかがずれている。よくある「ずれ」は次のとおりである。

チェック項目meta 側の設定metafor 側の設定ずれると変わるもの
$\tau^2$ の推定法method.tau(version 5.0以降の既定値は REML、4.x以前は DL)method(既定値は REML)$\tau^2$、係数、SE
検定法method.random.ci = "HK" なら Knapp-Hartungtest = "knha"(既定値は "z")SE、検定統計量(z か t か)、CI
効果量の定義sm、method("Peto" など)escalc() の measure効果量そのもの → すべて
ゼロセルの連続補正incr、method.increscalc() の add、toゼロセルを含む研究の効果量(既定値どうしなら同じ)
モデルの種類method = "GLMM" なら内部で rma.glmm()rma.uni() と rma.glmm() は別モデルすべて(比べる相手を rma.glmm() にする)
meta(version 8.5-0)と metafor(version 5.0-1)で確認

上の3つを実際に確かめてみる。いずれも、片方だけ設定を変えると結果がずれ、両方を揃えると一致する。

(a) $\tau^2$ の推定法:DL と REML

res_meta_dl <- update(res_meta, method.tau = "DL")
metareg(res_meta_dl, ~ ablat)$se        # meta (DL)
res_metafor_ablat$se                    # metafor (REML) … ずれる
compare_fit(metareg(res_meta_dl, ~ ablat),
            rma.uni(yi, vi, mods = ~ ablat, data = dat4metafor,
                    method = "DL"))     # 揃えれば一致
> metareg(res_meta_dl, ~ ablat)$se        # meta (DL)
[1] 0.210875146 0.006172559
> res_metafor_ablat$se                    # metafor (REML) … ずれる
[1] 0.214648582 0.006276366
> compare_fit(metareg(res_meta_dl, ~ ablat), ...
     term est_meta est_metafor se_meta se_metafor tau2_meta tau2_metafor
1 intrcpt   0.3030      0.3030  0.2109     0.2109     0.048        0.048
2   ablat  -0.0316     -0.0316  0.0062     0.0062     0.048        0.048

meta は version 5.0(2021年)で $\tau^2$ の既定の推定法を DerSimonian-Laird(DL)法から REML に変更した。古い meta を使っている場合や、settings.meta("RevMan5") のように DL を使う設定を読み込んでいる場合は、metafor(既定値は REML)と結果がずれる。

(b) 検定法:Knapp-Hartung 法

res_meta_hk <- update(res_meta, method.random.ci = "HK")
metareg(res_meta_hk, ~ ablat)
compare_fit(metareg(res_meta_hk, ~ ablat),
            rma.uni(yi, vi, mods = ~ ablat, data = dat4metafor,
                    test = "knha"))     # 揃えれば一致
Test of Moderators (coefficient 2):
F(df1 = 1, df2 = 11) = 17.5958, p-val = 0.0015

Model Results:

         estimate      se     tval  df    pval    ci.lb    ci.ub
intrcpt    0.3010  0.2571   1.1709  11  0.2664  -0.2648   0.8669
ablat     -0.0315  0.0075  -4.1947  11  0.0015  -0.0481  -0.0150  **

     term est_meta est_metafor se_meta se_metafor tau2_meta tau2_metafor
1 intrcpt   0.3010      0.3010  0.2571     0.2571    0.0504       0.0504
2   ablat  -0.0315     -0.0315  0.0075     0.0075    0.0504       0.0504

Knapp-Hartung 法では、$\tau^2$ も係数も変わらないが、標準誤差が残差のばらつきに応じて調整され(ここでは 0.0063 → 0.0075)、z分布の代わりに自由度 $k – p = 11$ のt分布で検定・信頼区間を計算する。研究数が少ないメタ回帰で、通常の z 検定が有意になりすぎる問題への対処として提案された方法である(Knapp & Hartung, 2003)。meta でメタアナリシスを HK 法で行っていると、metareg() も自動で HK 法になる点に注意したい(metareg(..., hakn = FALSE) で z 検定に戻せる)。

(c) 効果量の定義:Peto 法のオッズ比

res_meta_peto <- update(res_meta, method = "Peto")
dat4peto <- escalc(measure = "PETO", ai = tpos, n1i = tpos + tneg,
                   ci = cpos, n2i = cpos + cneg, data = dat.bcg)
compare_fit(metareg(res_meta_peto, ~ ablat),
            rma.uni(yi, vi, mods = ~ ablat, data = dat4peto))
     term est_meta est_metafor se_meta se_metafor tau2_meta tau2_metafor
1 intrcpt   0.2769      0.2769  0.1494     0.1494    0.0173       0.0173
2   ablat  -0.0289     -0.0289  0.0043     0.0043    0.0173       0.0173

metabin() で method = "Peto" を指定すると、研究ごとの効果量が Peto 法の対数オッズ比になる。これは escalc(measure = "OR") の通常の対数オッズ比とは別物なので、ablat の係数(−0.0289)も標準誤差(0.0043)も Step 1 とは違う値になる。metafor 側も measure = "PETO" にすれば一致する。料理に喩えれば、同じレシピでも計量カップが違えば味が変わる、ということである。

※コラム:settings.meta() のプリセットにも注意
meta には、ガイドラインや雑誌に合わせて既定値をまとめて切り替える settings.meta() がある。例えば settings.meta("RevMan5") は $\tau^2$ に DL 法、settings.meta("IQWiG6") は Paule-Mandel 法と HK 法を使う設定になる(meta 8.5-0 で確認)。スクリプトの冒頭やプロファイルでプリセットを読み込んでいると、本人が意識しないうちに metafor と設定がずれることがある。settings.meta("reset") で既定値に戻せる。


細かい違い:$I^2$ が 92.6% と 92.07% になる理由

メタ回帰ではないが、共変量なしのモデルでも両者の出力には小さな違いがある。$\tau^2 = 0.3378$ は同じなのに、$I^2$ は meta で 92.6%、metafor で 92.07% と表示される。これは $I^2$ の計算式が違うためである。

  • meta:$Q$ 統計量から計算する $I^2 = (Q – \mathrm{df})/Q = (163.16 – 12)/163.16 \approx 92.6\%$(出力の “Calculation of I^2 based on Q”)
  • metafor:推定した $\tau^2$ から計算する $I^2 = \hat{\tau}^2 / (\hat{\tau}^2 + \tilde{v})$($\tilde{v}$ は研究内分散の「典型値」)

2つの式は DL 法では一致するが、REML などほかの推定法では少しずれる(Higgins & Thompson, 2002)。なお、metareg() の出力に出る残差の $I^2$(57.39%)は metafor が計算したものなので、メタ回帰の部分では両者は一致する。


Step 5:結果を図で確認する(バブルプロット)

メタ回帰の結果は、横軸に共変量、縦軸に効果量をとり、各研究を重みに比例した大きさの円で描くバブルプロットで確認するとよい。meta では bubble()、metafor では regplot() で描ける。

bubble(res_meta_ablat)                  # meta
regplot(res_metafor_ablat, transf = exp, # metafor
        xlab = "Absolute latitude", ylab = "Odds ratio")
meta のバブルプロット
metafor のバブルプロット

緯度が高い研究ほどオッズ比が小さい(ワクチンの効果が大きい)傾向が見て取れる。一方で、研究数は13しかなく、同じ緯度の研究も少ない。直線の当てはまりを鵜呑みにせず、個々の研究の位置も合わせて確認したい。

2つの図の回帰線は、見た目は違うが同じ結果である。meta の bubble() は縦軸を対数目盛りで描くため、対数オッズ比の回帰式がそのまま直線になる。metafor の regplot(transf = exp) は推定値をオッズ比に戻して通常の目盛りで描くため、同じ回帰式が曲線(指数関数)になる。灰色の帯は回帰線の95%信頼区間である。円の大きさはどちらも研究の重みを表すが、大きさの決め方が違うため、図同士で円の大きさは比べられない。なお、metafor の transf = exp を削除すれば、Y軸が meta と同じく対数オッズ比となり、回帰線も直線になる。


どちらを使うべきか?

ここまで見てきたとおり、標準的な変量効果メタ回帰であれば、meta と metafor のどちらを使っても結果は同じである。したがって、「どちらが正しいか」ではなく、作業の流れに合うほうを選べばよい。

  • meta:metabin() → forest() → metareg() → bubble() と、メタアナリシスの流れの中でそのままメタ回帰まで進められる。論文用のフォレストプロットを細かく整えたい場合にも便利である
  • metafor:rma.mv() による多変量・多階層モデル、permutest() による並べ替え検定、anova() による係数の検定など、メタ回帰を深掘りする道具がそろっている。metareg() の結果は rma.uni オブジェクトなので、これらの多くは meta で作った結果にもそのまま使える

どちらを使う場合も、論文の Methods には「$\tau^2$ の推定法」と「検定法(z 検定か Knapp-Hartung 法か)」を明記しておくと、読者が結果を再現しやすい。また、メタ回帰そのものの注意点として、研究数が少ないと検出力が低く偶然の関連も出やすいこと、研究単位の関連は個々の患者レベルの関連を意味しないこと(生態学的バイアス)、共変量は事前に決めておくべきことも押さえておきたい(Thompson & Higgins, 2002)。


論文でそのまま使える英文テンプレート

以下の数値は、本記事の BCG データで実際にRを実行して得た結果である。自分のデータに使う場合は、推定法・検定法と数値を差し替えること。

Methods:

To explore sources of between-study heterogeneity, we performed a random-effects meta-regression with absolute latitude as a study-level covariate. Log odds ratios and their sampling variances were calculated for each study, and the residual between-study variance (τ²) was estimated using the restricted maximum likelihood method. Analyses were conducted with the meta (version 8.5-0) and metafor (version 5.0-1) packages in R (version 4.5.3).

(日本語訳)研究間の異質性の要因を探索するため、緯度の絶対値を研究レベルの共変量とする変量効果メタ回帰を行った。各研究の対数オッズ比とその標本分散を算出し、残差の研究間分散(τ²)は制限付き最尤法で推定した。解析には R(version 4.5.3)の meta パッケージ(version 8.5-0)および metafor パッケージ(version 5.0-1)を用いた。

Knapp-Hartung 法を使った場合は、次の一文を加える:“The Knapp–Hartung method was used to calculate standard errors, confidence intervals, and P values of the regression coefficients.”(回帰係数の標準誤差・信頼区間・P値の計算には Knapp-Hartung 法を用いた。)

Results:

In the meta-regression, higher absolute latitude was associated with a lower odds ratio for tuberculosis (regression coefficient for log odds ratio, −0.032 per degree; 95% CI, −0.044 to −0.019; P < 0.001). Absolute latitude accounted for 85% of the between-study heterogeneity (residual τ² = 0.050, compared with τ² = 0.338 without the covariate).

(日本語訳)メタ回帰では、緯度の絶対値が高いほど結核のオッズ比が低かった(対数オッズ比に対する回帰係数:1度あたり −0.032、95%信頼区間 −0.044〜−0.019、P < 0.001)。緯度の絶対値は研究間の異質性の85%を説明した(残差 τ² = 0.050、共変量なしでは τ² = 0.338)。


まとめ

  • meta の metareg() は、内部で metafor の rma.uni() を呼び出している。残差 $\tau^2$ もメタ回帰の中で推定し直される
  • 効果量の定義・$\tau^2$ の推定法・検定法が揃っていれば、両者の結果は完全に一致する
  • metabin() に mods を書いても、エラーも警告も出ずに無視される。メタ回帰は必ず metareg() で行う
  • 結果がずれたら、method.tau(DL か REML か)、method.random.ci(HK か)、sm・method(Peto など)、settings.meta() のプリセットを確認する

2つのパッケージの結果が食い違うと、つい「計算方法が根本的に違うのでは」と考えたくなる。しかし多くの場合、原因はもっと手前の設定にある。同じエンジンの車なら、まず走行モードのスイッチを確認する、という順番で考えるとよい。

一括コピペ用Rスクリプト

動作確認環境:R 4.5.3、meta 8.5-0、metafor 5.0-1、metadat 1.6-0

# ============================================================
# meta と metafor のメタ回帰を比較する(BCGワクチンデータ)
# ============================================================
library(metafor)   # metadat(dat.bcg を含む)も自動で読み込まれる
library(meta)

data(dat.bcg)

# ---- Step 1:metafor でメタ回帰 ----------------------------
dat4metafor <- escalc(measure = "OR", ai = tpos, bi = tneg,
                      ci = cpos, di = cneg, data = dat.bcg,
                      slab = paste0(author, ", ", year))

res_metafor <- rma.uni(yi = yi, vi = vi, data = dat4metafor)
print(res_metafor)
forest(res_metafor, transf = exp)

res_metafor_ablat <- rma.uni(yi = yi, vi = vi, mods = ~ ablat,
                             data = dat4metafor)
print(res_metafor_ablat)

# ---- Step 2:meta でメタ回帰(metabin → metareg) ----------
res_meta <- metabin(event.e = tpos, n.e = tpos + tneg,
                    event.c = cpos, n.c = cpos + cneg,
                    data = dat.bcg, sm = "OR",
                    common = FALSE, random = TRUE,
                    studlab = paste0(author, ", ", year))
print(res_meta)
forest(res_meta)

# 落とし穴:metabin() に mods を渡しても、エラーも警告も出ずに無視される
res_meta_mods <- metabin(event.e = tpos, n.e = tpos + tneg,
                         event.c = cpos, n.c = cpos + cneg,
                         data = dat.bcg, sm = "OR", mods = ~ ablat,
                         common = FALSE, random = TRUE,
                         studlab = paste0(author, ", ", year))
all.equal(res_meta_mods$TE.random, res_meta$TE.random)  # TRUE:中身は同じ

# 正しくは metareg() を使う
res_meta_ablat <- metareg(res_meta, ~ ablat)
print(res_meta_ablat)

# ---- Step 3:中身を確かめる --------------------------------
class(res_meta_ablat)   # "metareg" "rma.uni" "rma"

# 研究ごとの効果量(対数OR)と分散は escalc() と同じ
all.equal(res_meta$TE, as.numeric(dat4metafor$yi))
all.equal(res_meta$seTE^2, as.numeric(dat4metafor$vi))

# 2つのモデルを並べて比べる関数
compare_fit <- function(fit_meta, fit_metafor) {
  data.frame(term        = names(coef(fit_metafor)),
             est_meta    = round(coef(fit_meta), 4),
             est_metafor = round(coef(fit_metafor), 4),
             se_meta     = round(fit_meta$se, 4),
             se_metafor  = round(fit_metafor$se, 4),
             tau2_meta   = round(fit_meta$tau2, 4),
             tau2_metafor = round(fit_metafor$tau2, 4),
             row.names = NULL)
}
compare_fit(res_meta_ablat, res_metafor_ablat)

# ---- Step 4:設定がずれると SE がずれる --------------------
# (a) tau^2 の推定法:meta 4.x 以前の既定値は DerSimonian-Laird
res_meta_dl <- update(res_meta, method.tau = "DL")
metareg(res_meta_dl, ~ ablat)$se        # meta (DL)
res_metafor_ablat$se                    # metafor (REML) … ずれる
compare_fit(metareg(res_meta_dl, ~ ablat),
            rma.uni(yi, vi, mods = ~ ablat, data = dat4metafor,
                    method = "DL"))     # 揃えれば一致

# (b) Knapp-Hartung 法:meta 側で HK を選ぶと metareg も test = "knha" になる
res_meta_hk <- update(res_meta, method.random.ci = "HK")
compare_fit(metareg(res_meta_hk, ~ ablat),
            rma.uni(yi, vi, mods = ~ ablat, data = dat4metafor,
                    test = "knha"))     # 揃えれば一致

# (c) 効果量の定義:Peto 法のオッズ比は escalc(measure = "OR") と別物
res_meta_peto <- update(res_meta, method = "Peto")
dat4peto <- escalc(measure = "PETO", ai = tpos, n1i = tpos + tneg,
                   ci = cpos, n2i = cpos + cneg, data = dat.bcg)
compare_fit(metareg(res_meta_peto, ~ ablat),
            rma.uni(yi, vi, mods = ~ ablat, data = dat4peto))

# ---- Step 5:結果を図で確認する ----------------------------
bubble(res_meta_ablat)                  # meta
regplot(res_metafor_ablat, transf = exp, # metafor
        xlab = "Absolute latitude", ylab = "Odds ratio")

おすすめ書籍

  • 丹後俊郎『新版 メタ・アナリシス入門―エビデンスの統合をめざす統計手法―』(医学統計学シリーズ)朝倉書店, 2016. 変量効果モデル、異質性、メタ回帰の考え方を医学統計の立場から体系的に学べる日本語の定番書。 Amazonで見る
  • 山田剛史・井上俊哉『メタ分析入門―心理・教育研究の系統的レビューのために―』東京大学出版会, 2012. 効果量の考え方から異質性、調整変数の分析まで、心理・教育研究の文脈で丁寧に解説した入門書。医療以外の分野でメタ分析を行う人にもすすめやすい。 Amazonで見る
  • Schwarzer G, Carpenter JR, Rücker G. Meta-Analysis with R (Use R!). Springer; 2015. meta パッケージの開発者による解説書。刊行時点の meta(version 4.x)は $\tau^2$ の既定値が DL 法なので、本記事の「設定のずれ」を意識しながら読むとよい。 Amazonで見る
  • Harrer M, Cuijpers P, Furukawa TA, Ebert DD. Doing Meta-Analysis with R: A Hands-On Guide. Chapman & Hall/CRC; 2021. meta と metafor の両方を使い、メタ回帰まで手を動かしながら学べる実践書。Web版(bookdown)も公開されている。 Amazonで見る

参考文献

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

リサーチクエスチョン探し?データ分析?論文投稿?、、、で、もう悩まない!

第1章:臨床研究ではなぜ統計が必要なのか?計画することの重要性
  • 推定ってどんなことをしているの?
  • 臨床研究を計画するってどういうこと?
  • どうにかして標本平均を母平均に近づけられないか?
第2章:研究目的をどれだけ明確にできるのかが重要
  • データさえあれば解析でどうにかなる、という考え方は間違い
  • 何を明らかにしたいのか? という研究目的が重要
  • 研究目的は4種類に分けられる
  • 統計専門家に相談する上でも研究目的とPICOを明確化しておく
第3章:p値で結果が左右される時代は終わりました
  • アメリカ統計協会(ASA)のp値に関する声明で指摘されていること
  • そうは言っても、本当に有意差がなくてもいいの…?
  • なぜ統計専門家はp値を重要視していないのか
  • 有意差がない時に「有意な傾向があった」といってもいい?
  • 統計を放置してしまうと非常にまずい
第4章:多くの人が統計を苦手にする理由
  • 残念ながら、セミナー受講だけで統計は使えません。
  • インプットだけで統計が使えない理由
  • どうやったら統計の判断力が鍛えられるか?
  • 統計は手段なので正解がないため、最適解を判断する力が必要
第5章:統計を使えるようになるために今日から何をすれば良いか?
  • 論文を読んで統計が使えるようになるための5ステップ
第6章:統計を学ぶために重要な環境
  • 統計の3つの力をバランスよく構築する環境

以下のボタンをクリックして、画面に出てくる指示に従って、必要事項を記入してください。

この記事を書いた人

医師、医学博士(専門は疫学および統計学)。10年以上の研究歴を有し、筆頭著者として10本の英文原著論文を執筆した実績を持つ。現在、外資系製薬企業にて15年以上にわたり、臨床開発やデータ解析、承認審査、薬価交渉戦略といった実務の最前線に従事。

「統計に悩むあなたを救いたい」をコンセプトに、ブログ「統計ER」やYouTube、SNSを通じて、医療従事者や研究者向けに「実務直結の統計ノウハウ」を配信。

学術的な厳密さと、製薬業界での高度な実務経験を融合させた独自の視点から、ブラックボックス化しない統計解析の普及を目指す。オンラインショップ「TKER SHOP」での計算ツール提供や、クラウドワークス等を通じた統計コンサルティング・解析代行(主にRを使用)も幅広く展開中。

コメント

コメントする

目次