統計学

ランダム化比較実験(RCT)とは?Pythonでの実装方法も見ていこう!

ランダム化比較実験
記事内に商品プロモーションを含む場合があります
ウマたん
ウマたん
本記事では、ビジネスシーンで因果関係を知りたい時に一番適切なアプローチがランダム化比較実験であり、非常に重要なので必ずおさえておきましょう!

こんにちは!データサイエンティストのウマたん(@statistics1012)です。

ビジネスシーンで因果関係を確かめたいときってよくありますよね。

例えば、この施策って本当に効果あったのー?みたいな。

そんな時に、まず知っておきたいのがランダム化比較実験というアプローチ。

この記事で学んで、しっかり理解しておきましょう!

相関関係と因果関係

さて、まずは相関関係と因果関係の違いについて見ていきましょう!

例えば、「年収と一日の平均摂取カロリーには負の相関関係がある
と聞いたらみなさんはどのように思いますか?

「よっしゃ!年収をあげるためにカロリーを抑えよう!」と思うでしょうか?

でも実際にはカロリーを低く抑えることによって年収が上がるということは期待されません。

なぜなら相関関係があったとしても因果関係があるとは限らないからです。

図1. 年収と摂取カロリーの散布図(仮想データ)

さて、先ほどの「年収と一日の摂取カロリー」には相関関係があることは間違いないです。

しかし、経験的に一日の摂取カロリーを低くしても年収が上がるという因果関係は認められないと思います。

それではなぜ「年収」を「摂取カロリー」の間に相関関係が見られたのでしょうか?
それは、「年収」と「摂取カロリー」の裏に「年齢」という隠れた因子が存在するからです。

図2. 交絡した因果グラフ

一般的に年齢が高くなると年収は上がります。そして年齢が高くなると摂取カロリーは低くなるでしょう。
そのため摂取カロリーが低い人ほど年収が高くなったのです。

このような変数間の構造のことを交絡と呼びます。
また、交絡しているときの相関を擬似相関(偽相関)と呼びます。

大事なのは相関関係があっても因果関係があるとは限らないということです。

相関関係 因果関係
相関関係と因果関係の違いについて例を挙げながら簡単に解説していく!当サイト【スタビジ】の本記事では、相関関係と因果関係の違いについて具体的な例を挙げながら分かりやすく簡単に解説していきます。相関関係と因果関係はビジネスシーンでつきまとう非常に重要な概念。違いについて明確に理解しておきましょう!...
ウマたん
ウマたん
相関と因果は別物だよ!

ランダム化比較実験とは?

ランダム化比較試験

さて、相関と因果の違いを理解できたところで、早速ランダム化比較実験とは何なのか?見ていきましょう!

例えば、ある新薬を飲んでもらう群と通常のビタミン剤を飲んでもらう群に分けて新薬の効果を見る実験をするとします。

この時、ある集団を新薬を飲んでもらう群(実験群・介入群・処置群などと呼ぶ)とビタミン剤を飲んでもらう群(対照群・統制群・コントロール群などと呼ぶ)に分けて、結果の差を見ます。

集団の中のそれぞれの対象が介入群と対照群のどちらになるかを決定させることを割り付けと呼びます。

では、集団をどのように割り付ければ良いでしょうか。

例えば、男性なら新薬を飲んでもらい、女性ならビタミン剤を飲んでもらうという割り付けをしてみます。

すると、確かに結果の差を得ることは出来ますが、果たしてそれは新薬の効果によるものなのでしょうか。性別に由来する影響かもしれません。

この場合、性別のことを交絡因子と呼びます。

このように割り付けを適切に行わないと交絡を引き起こしてしまいます。

結局、如何にして交絡に対処するかが重要ということです。

因果効果を測定するには交絡因子を調整する必要があります。

ここで登場する最も最適な方法が、割り付けを完全にランダムに行う方法でありランダム化比較実験(Randomized Controlled Trial;RCT)と呼ばれるのです。

RCTでは例えば、一人一人にコインを投げてもらい表なら介入群、裏なら対照群とします。

これによって、いろんな潜在的な交絡因子があっても二つの群の分布は平均的に等しくなることが期待されます。

したがって、介入群と対照群の結果の差は介入によるものであると結論づけることが出来ます。

ランダム化比較実験(RCT)をPythonで実装してみよう!

さて、それではこのRCTをPythonで実装してみましょう!

今回は血圧を下げるサプリの効果があるのかないのか確かめるケースを考えてみます。

まず、血圧を下げるサプリを試したい人を公募で募集し、彼らに血圧を下げるサプリを試して、それをサプリを接種していない一般人と比較しました。

ウマたん
ウマたん
この実験のどこに問題があるか分かるかな?

そう、そもそも年齢が高く血圧が高い人ほど血圧を下げるサプリを飲みたいと思い応募してきている可能性が高く、比較対象には年齢という交絡因子が存在することが考えられます。

この誤った実験設定をそのままPythonコードに落とし込んでいきましょう!

# --- データ生成 ---
N_obs = 1000

Age_obs = np.random.normal(50, 10, size=N_obs)

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# 年齢が高いほどサプリを飲みやすい
p_supp_obs = sigmoid(0.3 * (Age_obs - 50))
Supplement_obs = np.random.binomial(1, p_supp_obs)

BloodPressure_obs = 130 + 0.3*Age_obs - 4.0*Supplement_obs + np.random.normal(0, 5, size=N_obs)

df_obs = pd.DataFrame({
    'Age': Age_obs,
    'Supplement': Supplement_obs,
    'BloodPressure': BloodPressure_obs
})

# --- まずは「年齢を無視」して単純比較 ---
mean_bp_supp_obs = df_obs[df_obs['Supplement'] == 1]['BloodPressure'].mean()
mean_bp_nosupp_obs = df_obs[df_obs['Supplement'] == 0]['BloodPressure'].mean()
diff_obs_naive = mean_bp_supp_obs - mean_bp_nosupp_obs

print(f"サプリ群 平均血圧:    {mean_bp_supp_obs:.2f}")
print(f"非サプリ群 平均血圧:  {mean_bp_nosupp_obs:.2f}")
print(f"単純比較(サプリ - 非サプリ): {diff_obs_naive:.2f}  ")

このコードの流れを見ていきましょう!

課題設定に沿って、1000人を対象に年齢が高いほどサプリを飲みやすいというような条件設定にします。

まず、Age_obs = np.random.normal(50, 10, size=N_obs)の部分で、年齢を平均50・標準偏差10の正規分布に従う形でランダムに1000個生成しています。

続いて、sigmoidでシグモイド関数を定義しています。シグモイド関数はロジスティック回帰などに用いられる関数で、入力の値は0~1の範囲に変換します。

すなわち数値を確率に変換する時に役立ちます。

入力が0の場合は出力は0.5になり、それより小さくなればなるほど0に近づき、大きければ大きいほど1に近づくのです。

今回は年齢を入力にしてサプリを飲む確率値を出力したいので、シグモイド関数を用いているのです。

さて、この関数の入力には0.3 * (Age_obs – 50)を入れているので50歳の人はちょうど0.5の確率が出力されるようになっているわけですね。

ちなみに、たとえば被験者が60歳なら、Age_obs – 50 = 10 となり、計算は 0.3 * 10 = 3 となります。シグモイド関数に3 を入れると約 0.95程度。つまり「ほぼ 95% の確率でサプリを飲む」となるわけです。

逆に40歳なら、Age_obs – 50 = -10 → 0.3 * (-10) = -3となり、sigmoid(−3) は約 0.05。つまり「5% くらいの確率でしかサプリを飲まない」となるわけです。

続いて、Supplement_obs = np.random.binomial(1, p_supp_obs)の箇所では、二項分布に基づいて、確率値からサプリを飲むか飲まないかを0,1で出力しています。

続いて、以下の式では血圧の計測結果を出力しています。

BloodPressure_obs = 130 + 0.3*Age_obs - 4.0*Supplement_obs + np.random.normal(0, 5, size=N_obs)

年齢が高ければ高いほど血圧が高くなり、サプリを飲んでいれば血圧が下がるような式になっています。

また個体差を出すために、乱数も発生させて加えています。

この結果をデータフレームに格納し、サプリを接種した群としていない群の平均を比較してみると・・・結果は以下のようになりました。

サプリ群 平均血圧: 143.04
非サプリ群 平均血圧: 143.06
単純比較(サプリ – 非サプリ): -0.02

本来であればサプリの効果があるはずなのに、ほぼ差がないことが分かります(※今回サプリを飲んでいるか否かで4.0を足しているので、本来であれば単純比較の差が4近くなるはず)。

それでは続いて、ランダム化比較実験(RCT)を用いて割り付けをおこなっていきましょう!

Pythonコードは以下になります。

# --- データ生成 ---
N_rct = 1000

Age_rct = np.random.normal(50, 10, size=N_rct)

# サプリ割付:RCTなので年齢関係なく50%割付
Supplement_rct = np.random.binomial(1, 0.5, size=N_rct)

BloodPressure_rct = 130 + 0.3*Age_rct - 4.0*Supplement_rct + np.random.normal(0, 5, size=N_rct)

df_rct = pd.DataFrame({
    'Age': Age_rct,
    'Supplement': Supplement_rct,
    'BloodPressure': BloodPressure_rct
})

# --- 単純比較 ---
mean_bp_supp = df_rct[df_rct['Supplement'] == 1]['BloodPressure'].mean()
mean_bp_nosupp = df_rct[df_rct['Supplement'] == 0]['BloodPressure'].mean()
diff_rct = mean_bp_supp - mean_bp_nosupp

print(f"サプリ群 平均血圧:    {mean_bp_supp:.2f}")
print(f"非サプリ群 平均血圧:  {mean_bp_nosupp:.2f}")
print(f"単純比較(サプリ - 非サプリ): {diff_rct:.2f}  (ちゃんと効果が出る)")

今回は年齢の関係なくランダムに割り付けをおこなっています。血圧を求める式は同様。

結果は以下のようになりました。

サプリ群 平均血圧: 140.82
非サプリ群 平均血圧: 145.12
単純比較(サプリ – 非サプリ): -4.29 (ちゃんと効果が出る)

ちゃんとサプリ群の方が4近く血圧が小さくなっており、効果が出ていることが分かりますね!

ロボたん
ロボたん
それならどんな場合でもRCTをやればいいんじゃ、、、?

ただ割り付けをランダムにすれば良いRCTは使い勝手が良さそうに見えますが、デメリットもあります。

そもそもそのような実験ができれば良いが、ランダムな割り付けが出来ない場合も多いのです

例えば、タバコと肺がんの関係を調べるために、ランダムに割り付けた人々に一日10本のタバコを吸ってもらい肺がんになるまで実験するというのは倫理的に不可能です。

また、コストの問題もありますし、そもそもすでにデータが得られている場合にはどうしようもありません。

実験研究とは異なり割り付けがランダム化されていない方法は観察研究と呼ばれます。

現実問題では、観察データが多いこともあり、その場合は別のアプローチを試す必要があるのです。

ランダム化比較実験 まとめ

ここまでで、まずおさえておきたいランダム化比較実験(RCT)についてまとめてきました。

もしランダムに割り付けができる状況であれば、ランダム化比較実験を実行して確実に因果を見定めていきましょう!

実際にはランダム化比較実験が難しいことも多く、そういった場合は様々な統計的因果推論のアプローチを試していくことになります。

統計的因果推論の分野の様々な手法について知りたい方は以下の記事をチェックしてみてください!

統計的因果推論_アイキャッチ
【分かりやすく解説】統計的因果推論の手法7つを理解しPythonで実装していこう!当サイト【スタビジ】の本記事では、非常に奥が深い分野である統計的因果推論について見ていきたいと思います。相関関係と因果関係は違うということをしっかり理解し、どのように因果を見つけていけばよいか様々な方法を見ていきましょう!...

さらに詳しくAIやデータサイエンスの勉強がしたい!という方は当サイト「スタビジ」が提供するスタビジアカデミーというサービスで体系的に学ぶことが可能ですので是非参考にしてみてください!

AIデータサイエンス特化スクール「スタアカ」

スタアカトップ
【価格】ライトプラン:1280円/月
プレミアムプラン:149,800円
【オススメ度】
【サポート体制】
【受講形式】オンライン形式
【学習範囲】データサイエンスを網羅的に学ぶ
実践的なビジネスフレームワークを学ぶ
SQLとPythonを組み合わせて実データを使った様々なワークを行う
マーケティングの実行プラン策定
マーケティングとデータ分析の掛け合わせで集客マネタイズ

データサイエンティストとしての自分の経験をふまえてエッセンスを詰め込んだのがこちらのスタビジアカデミー、略して「スタアカ」!!

当メディアが運営するスクールです。

24時間以内の質問対応と現役データサイエンティストによる複数回のメンタリングを実施します!

カリキュラム自体は、他のスクールと比較して圧倒的に良い自信があるのでぜひ受講してみてください!

他のスクールのカリキュラムはPythonでの機械学習実装だけに焦点が当たっているものが多く、実務に即した内容になっていないものが多いです。

そんな課題感に対して、実務で使うことの多いSQLや機械学習のビジネス導入プロセスの理解なども合わせて学べるボリューム満点のコースになっています!

Pythonが初めての人でも学べるようなカリキュラムしておりますので是非チェックしてみてください!

ウォルマートのデータを使って商品の予測分析をしたり、実務で使うことの多いGoogleプロダクトのBigQueryを使って投球分析をしたり、データサイエンティストに必要なビジネス・マーケティングの基礎を学んでマーケティングプランを作ってもらったり・Webサイト構築してデータ基盤構築してWebマーケ×データ分析実践してもらったりする盛りだくさんの内容になってます!

・BigQuery上でSQL、Google Colab上でPythonを使い野球の投球分析
・世界最大手小売企業のウォルマートの実データを用いた需要予測
・ビジネス・マーケティングの基礎を学んで実際の企業を題材にしたマーケティングプランの策定
・Webサイト構築してデータ基盤構築してWebマーケ×データ分析実践して稼ぐ

スタビジアカデミーでデータサイエンスをさらに深く学ぼう!

スタアカサービスバナースタビジのコンテンツをさらに深堀りしたコンテンツが動画と一緒に学べるスクールです。

プレミアムプランでは私がマンツーマンで伴走させていただきます!ご受講お待ちしております!

スタビジアカデミーはこちら