Up

スタチンの効果の多項分布によるベイズ分析

 

Spiegelhalter (2019)Table 4.1には、スタチン(statin)を処方された人と偽薬(placebo)を処方された人の心臓発作(heart attack)、脳卒中(Stroke)などの発症率が記載されている。発症率から発症数を算出して表1にまとめた。

 

表1 Frequencies calculated from Table 4.1 of Spiegelhalter (2019)

Event

Placebo

Statin

Heart attack

1,212

893

Stroke

585

442

Death from any cause

1,509

1,325

Others

6,961

7,609

 

発症数に対して多項分布(岡本、2009)を適用してベイズ分布を行ってみた。

Stanスクリプトは、リスト1のように作成した。

Placebo群とstatin群における心臓発作などの発症頻度をデータとしている。

 

    array[K] int placebo;    //   Placebo群のデータ

    array[K] int statin;     //   Statin群のデータ

 

上記、配列において、各群

Heart attackStrokeDeath from any causeOthers

の順である。これは、他の配列(多項分布のパラメータなど)においても同様である。

発症頻度が従う多項分布のパラメータをsimplex型の変数として、以下のように設定している。

 

    simplex[K] theta_p;    //     Placebo

    simplex[K] theta_s;    //     Statin

 

条件間のパラメータ値の差、および比をgenerated quantitiesにおいて以下のように算出している。

 

generated quantities {

    vector[K] diff_p;

    vector[K] ratio_p;

    diff_p = theta_s - theta_p;

    for (k in 1:K)

        ratio_p[k] = theta_s[k] / theta_p[k];

}

 

リスト1Stanスクリプトを用いてベイズ分析を行うPythonスクリプトをリスト2のように作成した。

表1のデータを次のコードで設定して、リスト1のStanスクリプトを実行している。

 

Data = {'K': 4,

        'placebo': [1212, 585, 1509, 6961],

        'statin':  [ 893, 442, 1325, 7609]}

 

リスト2を実行すると、MCMCサンプリング後、多項分布のパラメータの事後分布のグラフが表示される(図1)。

図1

 

タイトルに記されているplacebo:およびstain:の右側の数値は、それぞれの群の人数である。ほぼ、総計2万人のデータである。

図中のレジェンド中の(P)および(S)は、placebo群およびstatin群を表す。3つの発症確率において、statin群の事後分布がplacebo群より左側にあり、群間の重なりはほとんど認められない。すなわちstatin群の発症確率がplacebo群より小さいことが統計学的に明瞭に示されていると言える。

図1のグラフのWindowを閉じると図2のグラフが表示される。

図2

 

2つの群のパラメータの差

statin群のパラメータ) ― (placebo群のパラメータ)

の事後分布のグラフである。発症確率の差の事後分布は、いずれも負の領域にあり、差が負であることが統計学的に明確に示されていると言える。すなわち、statin群の発症確率がplacebo群より小さいということである。

図2のWindowを閉じると、図3のグラフが表示される。

図3

 

パラメータの比

Statin群のパラメータ値)/(Placebo群のパラメータ値)

の事後分布である。発症確率のstatin群のplacebo群に対する比の事後分布は統計学的に1より小さいことが明瞭に示されている。Heart attackおよびStrokeの発症率において、statin群のplacebo群に対する比の事後分布の中央値は約34である。

 

 

上の分析データは、サンプルサイズが約2万人である。これを、比率はそのままにして、10分の1のサイズに変えてみる。すなわち、リスト2における次のコード

 

Data = {'K': 4,

        'placebo': [1212, 585, 1509, 6961],

        'statin':  [ 893, 442, 1325, 7609]}

 

 

Data = {'K': 4,

        'placebo': [121, 59, 151, 696],

        'statin':  [ 89, 44, 133, 761]}

 

に変更して実行してみる。このとき、statin群とplacebo群を合わせたサンプルサイズは約2千人である。

まず、各パラメータの事後分布であるが、図4のようになる。

図4

 

各発症確率は線のスタイルによって区別されているが、それぞれのstatin群(緑)とplacebo群(赤)の事後分布の分離は図1の分布に比べると重なりがかなり認められる。

各発症パラメータの差の事後分布は、図5のようになる。

図5

 

図2のグラフと比べると、0を跨いでいるのが認められ、特にstrokeの発症確率の事後分布の0からの分離が明瞭ではない。

図3のWindowを閉じると、図6のグラフが表示される。

図6

 

比の事後分布も、サンプルサイズを小さくした場合は、事後分布と1との関係が図3と比べると明瞭ではない。

 

 

 

リスト1 多項分布のStanスクリプト(statin_model.stan

 

data {

    int K;

    array[K] int placebo;    //   Placebo群のデータ

    array[K] int statin;     //   Statin群のデータ

}

transformed data {

    //

    //      Dirichlet分布のパラメータ

    //          一様分布

    //

    vector[K] alpha_p;

    vector[K] alpha_s;

    for (i in 1:K) {

        alpha_p[i] = 1;

        alpha_s[i] = 1;

    }

}

parameters {

    //

    //      多項分布のパラメータ

    //

    simplex[K] theta_p;    //     Placebo

    simplex[K] theta_s;    //     Statin

}

model {

    theta_p ~ dirichlet(alpha_p);

    theta_s ~ dirichlet(alpha_s);

    placebo ~ multinomial(theta_p);

    statin ~ multinomial(theta_s);

}

generated quantities {

    vector[K] diff_p;

    vector[K] ratio_p;

    diff_p = theta_s - theta_p;

    for (k in 1:K)

        ratio_p[k] = theta_s[k] / theta_p[k];

}

 

 

 

リスト2 多項分布によるベイズ分析用PyStanスクリプト(statin_model.stan リスト1)を用いるPythonスクリプト

 

import stan

import pandas as pd

import arviz as az

import seaborn as sb

import matplotlib.pyplot as plt

import numpy as np

 

Data = {'K': 4,

        'placebo': [1212, 585, 1509, 6961],

        'statin':  [ 893, 442, 1325, 7609]}

 

n_placebo = np.sum(Data['placebo'])

n_statin = np.sum(Data['statin'])

print('n_placebo =', n_placebo)

print('n_statin =', n_statin)

 

with open('statin_model.stan') as f_stan:

    sm = stan.build(f_stan.read(), data=Data)

fit = sm.sample()

 

i_data = az.from_pystan(posterior=fit, posterior_model=sm)

print(az.summary(i_data))

 

d_fm = fit.to_frame()

#

#           多項分布のパラメータの事後分布

#

name_lst = ['Heart attack', 'Stroke', 'Any cause', 'Others']

line_lst = ['--', '-.', ':']

plt.title('Posterior distribution' +

          f'\nplacebo:{n_placebo},   statin:{n_statin}')

for i in range(3):

    med = np.median(d_fm[f'theta_p.{i+1}'])

    sb.kdeplot(d_fm[f'theta_p.{i+1}'], c='r', ls=line_lst[i],

               label='(P):'+ name_lst[i] + f'\nmed.={med:.3f}')

    med = np.median(d_fm[f'theta_s.{i+1}'])

    sb.kdeplot(d_fm[f'theta_s.{i+1}'], c='g', ls=line_lst[i],

               label='(S):' + name_lst[i] + f'\nmed.={med:.3f}')

plt.xlabel('Probability')

plt.legend(ncols=2)

plt.tight_layout()

plt.show()

#

#           パラメータの差(Statin - Placebo)の事後分布

#

plt.title('Posterior distribution' +

          f'\nplacebo:{n_placebo},   statin:{n_statin}')

for i in range(4):

    med = np.median(d_fm[f'diff_p.{i+1}'])

    sb.kdeplot(d_fm[f'diff_p.{i+1}'], label=name_lst[i] +

               f'\nmed.={med:.3f}')

plt.xlabel('Difference of probabilities: Statin - Placebo')

plt.legend()

plt.show()

#

#          パラメータの比(Statin / Placebo)の事後分布

#

plt.title('Posterior distribution' +

          f'\nplacebo:{n_placebo},   statin:{n_statin}')

for i in range(4):

    med = np.median(d_fm[f'ratio_p.{i+1}'])

    sb.kdeplot(d_fm[f'ratio_p.{i+1}'], label=name_lst[i] +

               f'\nmed.={med:.3f}')

plt.xlabel('Ratio of probabilities: Statin / Placebo')

plt.legend()

plt.show()

 

 

 

引用参考文献

岡本安晴(2009) 統計学を学ぶための数学入門[下].培風館

岡本安晴(2019) いまさら聞けないPythonでデータ分析.丸善出版

Spiegelhalter, D. (2019). The art of statistics: Learning from data. Pelican

 

 

 

Home