Pythonではじめる因果推論と気を付けるべきバイアスについて

## はじめに

こんにちは！このブログでは、Pythonを使用して因果推論の基本的な手法を具体的な医療の例で解説し、データの可視化を通じて理解を深めます。また、因果推論において注意すべきバイアスについても説明します。

## 因果推論の基本

因果推論は、ある処置や介入が他の結果にどのように影響を与えるかを明らかにする方法です。単なる相関関係ではなく、因果関係を明示的に評価することが目的です。

### 因果推論の手法

1. **ランダム化実験（RCT）**:
   - 最も強力な因果推論の手法。
   - 被験者をランダムに処置群と対照群に分けることで、交絡因子の影響を排除します。

2. **観察データからの因果推論**:
   - RCTが困難な場合に使用されます。
   - 因果推論のモデルを構築し、交絡因子を調整することで因果効果を推定します。

## 交絡因子とは？

交絡因子（Confounding Variables）とは、処置（薬の服用など）と結果（回復など）の両方に影響を与える変数です。交絡因子の影響を考慮せずに因果関係を評価すると、誤った結論を導く可能性があります。例えば、年齢や既往症が交絡因子として考えられます。

## Pythonでの因果推論

### 分析テーマ

今回の分析のテーマは、新しい薬が患者の回復に与える影響を評価することです。他の要因として、年齢や既往症も考慮します。この問題を因果推論で解くことができます。

### 必要なライブラリのインストール

以下のコマンドで必要なライブラリをインストールします。

```bash
pip install dowhy plotly
```

### サンプルデータの準備

今回は、架空の医療データを使用します。ここでは、新しい薬が患者の回復に与える影響を評価します。

```python
import numpy as np
import pandas as pd
import plotly.express as px
from dowhy import CausalModel

# サンプルデータの作成
np.random.seed(42)
data = pd.DataFrame({
    'medication': np.random.binomial(1, 0.5, 1000),  # 薬の服用の有無
    'recovery': np.random.normal(50, 10, 1000),  # 回復度合い
    'age': np.random.randint(20, 80, 1000),  # 年齢（交絡因子）
    'preexisting_conditions': np.random.binomial(1, 0.3, 1000)  # 既往症の有無
})

# 薬の服用と他の要因が回復度合いに及ぼす影響を導入
data['recovery'] += data['medication'] * 10 - data['age'] * 0.5 + data['preexisting_conditions'] * -2
```

### データの可視化

データを可視化して、変数間の関係を理解します。Plotlyを使用して、薬の服用の有無による回復度合いの違いを比較します。

```python
# 薬の服用の有無による回復度合いの違いを可視化
fig = px.box(data, x='medication', y='recovery', title="薬の服用の有無による回復度合いの違い")
fig.show()

# 年齢による回復度合いの違いを可視化
fig = px.scatter(data, x='age', y='recovery', color='medication', title="年齢による回復度合いの違い")
fig.show()

# 既往症の有無による回復度合いの違いを可視化
fig = px.box(data, x='preexisting_conditions', y='recovery', title="既往症の有無による回復度合いの違い")
fig.show()
```
![スクリーンショット 2024-07-19 005422.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/8f8a01a7-c85b-721e-638c-55cb05662660.png)
![スクリーンショット 2024-07-19 005454.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/0cde5b90-9d9d-8609-cdc9-9febfdf05825.png)
![スクリーンショット 2024-07-19 005511.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/081cade5-f357-ebed-5ee6-e036e6f7ff5b.png)



### 因果モデルの構築

次に、因果モデルを構築し、因果効果を推定します。ここでは、`dowhy`ライブラリを使用して因果モデルを構築します。

1. `CausalModel`クラスを使って因果モデルを定義します。
2. 処置（treatment）、結果（outcome）、交絡因子（common_causes）を指定します。

```python
# 因果モデルの構築
model = CausalModel(
    data=data,
    treatment='medication',
    outcome='recovery',
    common_causes=['age', 'preexisting_conditions']
)

# 因果モデルの描画
model.view_model()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/23789320-b860-cf77-e0dd-c142bbf4921e.png)

`CausalModel`クラスは、因果モデルを構築するためのクラスです。`data`にはデータフレームを、`treatment`には処置を、`outcome`には結果を、`common_causes`には交絡因子を指定します。

### 因果効果の推定

因果効果を推定し、結果を表示します。因果効果の推定には、`identify_effect`メソッドと`estimate_effect`メソッドを使用します。

```python
# 因果効果の推定
identified_estimand = model.identify_effect()
estimate = model.estimate_effect(identified_estimand, method_name="backdoor.linear_regression")
print(estimate)
```

1. `identify_effect`メソッドを使用して、因果効果を識別します。
2. `estimate_effect`メソッドを使用して、識別された因果効果を推定します。ここでは、線形回帰を使用しています。


![スクリーンショット 2024-07-19 005730.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/8ddaf24a-d50c-7bff-0124-7eac827472b2.png)


### 結果の解釈と寄与のパーセンテージ計算

薬の服用と他の要因が回復度合いにどれだけ寄与したかをパーセンテージで示します。

```python
# 年齢の効果を因果推論で評価
model_age = CausalModel(
    data=data,
    treatment='age',
    outcome='recovery',
    common_causes=['medication', 'preexisting_conditions']
)

# 因果効果の推定
identified_estimand_age = model_age.identify_effect()
estimate_age = model_age.estimate_effect(identified_estimand_age, method_name="backdoor.linear_regression")
print(estimate_age)

# 既往症の効果を因果推論で評価
model_preexisting = CausalModel(
    data=data,
    treatment='preexisting_conditions',
    outcome='recovery',
    common_causes=['medication', 'age']
)

# 因果効果の推定
identified_estimand_preexisting = model_preexisting.identify_effect()
estimate_preexisting = model_preexisting.estimate_effect(identified_estimand_preexisting, method_name="backdoor.linear_regression")
print(estimate_preexisting)

# 各要因の効果の取り出し
medication_effect = estimate.value
age_effect = estimate_age.value
preexisting_effect = estimate_preexisting.value

# 全体の影響を合計
total_effect = abs(medication_effect) + abs(age_effect) + abs(preexisting_effect)

# パーセンテージ計算
medication_percentage = (abs(medication_effect) / total_effect) * 100
age_percentage = (abs(age_effect) / total_effect) * 100
preexisting_percentage = (abs(preexisting_effect) / total_effect) * 100

print(f"薬の回復度合いへの寄与: {medication_percentage:.2f}%")
print(f"年齢の回復度合いへの寄与: {age_percentage:.2f}%")
print(f"既往症の回復度合いへの寄与: {preexisting_percentage:.2f}%")
```
![スクリーンショット 2024-07-19 005750.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/625edbc8-33f9-8f13-93e8-9d6b83383b76.png)


### 結果の解釈

この分析では、新しい薬と他の要因（年齢、既往症の有無）が回復度合いに与える影響を評価しました。結果として、新しい薬の回復度合いへの寄与が約79%、年齢の寄与が約4%、既往症の寄与が約17%であることが示されました。この結果に基づいて、新しい薬が患者の回復を促進する有効な手段であることがわかります。

## 因果推論で注意すべきバイアス

因果推論においては、以下のバイアスに注意する必要があります。

### 1. 脱落バイアス（Attrition Bias）

脱落バイアスは、研究対象者がデータ収集中に脱落することで発生します。これにより、サンプルが偏り、結果が歪む可能性があります。

#### 例

臨床試験で、治療の副作用を理由に参加者が試験を中断する場合、残ったデータが治療の効果を正しく反映しない可能性があります。

#### 対策

脱落バイアスを軽減するためには、試験の設計段階で脱落リスクを最小限に抑える方法を検討し、可能な限り全データを収集するようにします。また、脱落データに対して適切な補完手法を使用します。

### 2. 自己選択バイアス（Self-Selection Bias）

自己選択バイアスは、サンプルが自分で選ばれる場合に発生します。特定の属性を持つ人がサンプルに選ばれやすくなり、結果が歪む可能性があります。

#### 例

健康に関心が高い人が健康に関する調査に参加し、健康への関心が低い人が参加しない場合、調査結果が健康に関する過大評価をする可能性があります。

#### 対策

自己選択バイアスを軽減するためには、無作為抽出や傾向スコアマッチングを使用して、サンプルが全体を代表するようにします。

## まとめ

この記事では、Pythonを使った因果推論の具体的な手法を詳しく解説し、新しい薬と他の要因が患者の回復に与える影響を評価しました。また、因果推論における重要なバイアスについても説明しました。因果推論を適切に行うためには、これらのバイアスに注意し、データの前処理やモデルの構築において適切な対策を講じることが重要です。

データの可視化やバイアスの理解を通じて、因果推論の結果をより正確に解釈し、より信頼性の高い意思決定を行いましょう。