ChatGPT と Python で学ぶ semopy PyMC3 lingam causal-learn DoWhy

# **user**:

SEMを用いた因果推論について、Pythonを使いながら詳細かつ厳密に教えてください。

# **assistant**:

### **Pythonを用いたSEMによる因果推論**

共分散構造分析（SEM: Structural Equation Modeling）は、観測変数と潜在変数を組み合わせた因果推論を行うための手法です。SEMは、以下の2つの側面を持ちます。

1. **測定モデル（Measurement Model）**  
   潜在変数（観測できない概念）と観測変数（測定されたデータ）の関係を定義する。
2. **構造モデル（Structural Model）**  
   変数間の因果関係を記述する。

Pythonでは、`semopy` や `lavaan`（R用のパッケージを`rpy2`経由で使用）、`PyMC3` を用いてSEMを実装できます。特にPyMC3を用いたベイズSEMは、柔軟なモデリングと不確実性の定量化が可能です。

---

## **1. SEMによる因果推論の理論**
SEMによる因果推論の核心は、観測データから因果構造を推定し、仮説モデルがデータをどの程度説明できるかを評価することにあります。

### **(1) SEMの数学的定式化**
SEMは、以下の行列方程式で表されます。

1. **測定モデル（確認的因子分析; CFA）**
   $$
   X = \Lambda_X \xi + \epsilon_X, \quad Y = \Lambda_Y \eta + \epsilon_Y
   $$
   - $ X $ は観測された指標変数（エクソジェナス）
   - $ Y $ は観測された指標変数（エンドジェナス）
   - $ \xi $ と $ \eta $ は潜在変数
   - $ \Lambda_X $ と $ \Lambda_Y $ は因子負荷行列
   - $ \epsilon_X $, $ \epsilon_Y $ は誤差項

2. **構造モデル**
   $$
   \eta = B \eta + \Gamma \xi + \zeta
   $$
   - $ B $ は潜在変数間の関係を表す係数行列
   - $ \Gamma $ は潜在変数から観測変数への影響
   - $ \zeta $ は構造誤差

---

## **2. Pythonを用いたSEMの実装**
### **(1) `semopy` を用いた基本的なSEM**
`semopy` はPythonでの共分散構造分析の主要ライブラリの一つです。まず、線形SEMの基本例を実装します。

#### **例：教育成果に対する自己効力感の影響**
```python
import pandas as pd
import semopy

# サンプルデータの作成
data_dict = {
    "self_efficacy1": [3, 4, 5, 3, 4],
    "self_efficacy2": [4, 5, 3, 4, 5],
    "self_efficacy3": [5, 4, 4, 3, 5],
    "academic_achievement1": [70, 85, 60, 75, 90],
    "academic_achievement2": [80, 88, 65, 78, 92],
}

df = pd.DataFrame(data_dict)

# SEMモデルの定義
model_desc = """
    # 測定モデル
    SelfEfficacy =~ self_efficacy1 + self_efficacy2 + self_efficacy3
    AcademicAchievement =~ academic_achievement1 + academic_achievement2
    
    # 構造モデル
    AcademicAchievement ~ SelfEfficacy
"""

# モデルの適合
model = semopy.Model(model_desc)
res = model.fit(df)

# 結果の確認
print(res)
print(model.inspect())
```
#### **解説**
- `SelfEfficacy`（自己効力感）と `AcademicAchievement`（学業成績）を潜在変数として定義。
- 潜在変数を観測変数で測定（因子分析）。
- `SelfEfficacy` から `AcademicAchievement` への影響を推定（因果関係の推定）。
- `model.fit(df)` でモデルを適合させ、結果を `model.inspect()` で確認。

---

### **(2) PyMC3を用いたベイズSEM**
ベイズSEMは、事前分布を指定してモデルの不確実性を評価できます。

```python
import pymc3 as pm
import numpy as np

# データ生成
np.random.seed(42)
N = 100
self_efficacy = np.random.normal(0, 1, N)
academic_achievement = 0.5 * self_efficacy + np.random.normal(0, 1, N)

# PyMC3でモデル定義
with pm.Model() as model:
    # 事前分布
    beta = pm.Normal("beta", mu=0, sigma=1)
    sigma = pm.HalfNormal("sigma", sigma=1)

    # 回帰モデル
    mu = beta * self_efficacy
    achievement_obs = pm.Normal("achievement_obs", mu=mu, sigma=sigma, observed=academic_achievement)

    # サンプリング
    trace = pm.sample(1000, return_inferencedata=True)

# 結果の可視化
import arviz as az
az.plot_posterior(trace)
```

#### **解説**
- `beta` は `SelfEfficacy` から `AcademicAchievement` への因果効果を表す係数。
- `sigma` は誤差項の標準偏差。
- `pm.sample(1000)` によりマルコフ連鎖モンテカルロ（MCMC）法で事後分布をサンプリング。
- `az.plot_posterior(trace)` で係数の分布を可視化し、不確実性を評価。

---

## **3. SEMを用いた因果推論のポイント**
### **(1) SEMとDAGの関係**
- DAG（有向非巡回グラフ）を構築し、それを基にSEMを定式化可能。
- SEMでは「共分散」を重視するが、DAGでは「条件付き独立性」に基づく。

### **(2) 交絡因子と因果推論**
- SEMの適用には「操作変数」や「条件付き独立性の検証」が重要。
- 交絡因子を考慮しないと、単なる相関分析と変わらなくなる。

### **(3) ベイズSEMの利点**
- **不確実性の推定**：各パラメータの信頼区間を明示できる。
- **柔軟なモデリング**：事前情報を取り入れることで、モデルの頑健性を向上。

---

## **まとめ**
Pythonを用いたSEMは、観測変数と潜在変数を組み合わせた因果推論を行うのに有効なツールです。  
- `semopy` を使うことで手軽に線形SEMを実装可能。
- `PyMC3` を用いることで、ベイズ統計の枠組みで不確実性を考慮したSEMが構築可能。

因果探索 (`lingam` や `causal-learn`) と組み合わせることで、階層的因果推論も可能になります。どのような因果構造を推定したいか、具体的なケースがあれば教えてください！

# **user**:

semopyやPyMC3と、lingam や causal-learn や DoWhy との違いを厳密かつ詳細に教えてください。


# **assistant**:


### **PythonライブラリにおけるSEM（共分散構造分析）と因果探索・因果推論の違い**

`semopy` や `PyMC3` を用いたSEMと、`lingam`・`causal-learn`・`DoWhy` などの因果探索・因果推論ライブラリは、目的・理論・手法が異なります。以下では、厳密に違いを整理し、それぞれの役割を明確にします。

---

## **1. SEM（共分散構造分析）と因果探索・因果推論の違い**
| 項目 | SEM (`semopy`, `PyMC3`) | 因果探索 (`lingam`, `causal-learn`) | 因果推論 (`DoWhy`) |
|------|-----------------|-----------------|----------------|
| **目的** | 事前に仮定した因果構造のパラメータ推定と適合度評価 | データから因果構造を自動推定 | 介入効果の推定・反実仮想の推定 |
| **アプローチ** | 統計モデル（共分散構造モデル） | 機械学習・統計的手法（DAG学習） | 介入推論（反実仮想） |
| **変数の扱い** | 潜在変数を扱える | 潜在変数を考慮しない（観測変数のみ） | 介入変数・媒介変数を明示的に考慮 |
| **入力データ** | 共分散行列またはデータフレーム | データフレーム（数値データ） | 因果グラフ＋データ |
| **適用可能なデータ** | 相関関係が強いデータ | 確率的・線形・非線形データ | 介入や時間的因果があるデータ |
| **因果推論の基準** | モデル適合度（CFI, RMSEAなど） | 条件付き独立性・スパース性 | 介入分析（Do-演算） |
| **ベイズ的推論** | `PyMC3` では可能 | `causal-learn` では部分的に可能 | `DoWhy` はベイズモデルと統合可能 |

---

## **2. `semopy` や `PyMC3`（SEM）**
### **SEM（共分散構造分析）の概要**
SEMは、観測データに基づいて事前に仮定した因果モデルのパラメータを推定し、モデルの適合度を評価します。  
潜在変数（直接観測できない概念）を扱える点が特徴です。

### **(1) `semopy`**
- **目的**: 仮説に基づく因果構造の評価と適合度の検証。
- **手法**:
  - 確認的因子分析（CFA）
  - パス解析（Path Analysis）
  - 潜在変数モデル（Latent Variable Model）
- **利点**:
  - 潜在変数を含むモデルを扱える。
  - `lavaan`（RのSEMライブラリ）に近い記法が使える。
- **制約**:
  - 事前に因果構造を仮定する必要がある（探索的因果推論には向かない）。

#### **例（`semopy`）**
```python
import semopy
import pandas as pd

# データフレーム作成
data = pd.DataFrame({
    "X1": [3, 4, 5, 3, 4],
    "X2": [4, 5, 3, 4, 5],
    "Y1": [70, 85, 60, 75, 90],
    "Y2": [80, 88, 65, 78, 92],
})

# SEMモデルの定義
model_desc = """
    FactorX =~ X1 + X2
    FactorY =~ Y1 + Y2
    FactorY ~ FactorX
"""
model = semopy.Model(model_desc)
model.fit(data)
print(model.inspect())
```
→ **仮定した因果モデルに基づくパラメータ推定**

---

### **(2) `PyMC3` によるベイズSEM**
- **目的**: SEMのベイズ推論版。事前分布を考慮し、不確実性を定量化できる。
- **手法**:
  - マルコフ連鎖モンテカルロ（MCMC）
  - 潜在変数モデリング
- **利点**:
  - 不確実性の推定が可能。
  - 潜在変数を扱える。
- **制約**:
  - 推定に時間がかかる。

#### **例（`PyMC3` でのSEM）**
```python
import pymc3 as pm
import numpy as np

N = 100
X = np.random.normal(0, 1, N)
Y = 0.5 * X + np.random.normal(0, 1, N)

with pm.Model() as model:
    beta = pm.Normal("beta", mu=0, sigma=1)
    sigma = pm.HalfNormal("sigma", sigma=1)
    mu = beta * X
    Y_obs = pm.Normal("Y_obs", mu=mu, sigma=sigma, observed=Y)
    trace = pm.sample(1000, return_inferencedata=True)

import arviz as az
az.plot_posterior(trace)
```
→ **事後分布を求めることで、SEMの因果推論をより確実にする**

---

## **3. `lingam` や `causal-learn`（因果探索）**
### **因果探索の概要**
因果探索（Causal Discovery）は、データから因果構造を推定する手法です。

### **(1) `lingam`**
- **目的**: 変数間の因果関係をデータから発見（主に線形因果モデル）。
- **手法**:
  - DirectLiNGAM（回帰分析を用いた因果探索）
  - ICA-LiNGAM（独立成分分析を用いた因果探索）
- **利点**:
  - 事前の因果モデルが不要。
  - 変数間の因果方向を特定できる。
- **制約**:
  - 外生変数が線形である前提。
  - ノイズが独立している必要がある。

```python
from lingam import DirectLiNGAM
import numpy as np

X = np.random.normal(size=(100, 3))
X[:, 1] += X[:, 0]
X[:, 2] += X[:, 1]

model = DirectLiNGAM()
model.fit(X)
print(model.causal_order_)
```
→ **データから因果順序を推定**

---

### **(2) `causal-learn`**
- **目的**: 確率モデルを用いた因果構造の学習。
- **手法**:
  - PCアルゴリズム（条件付き独立性に基づく）
  - GES（スコアベース探索）
- **利点**:
  - データ駆動で因果構造を推定。
- **制約**:
  - 時系列データには弱い。

```python
from causallearn.search.FCMBased import lingam
import numpy as np

X = np.random.normal(size=(100, 3))
model = lingam.ICALiNGAM()
model.fit(X)
print(model.adjacency_matrix_)
```
→ **確率的手法を用いた因果探索**

---

## **4. `DoWhy`（因果推論）**
- **目的**: 介入効果を推定（反実仮想の評価）。
- **手法**:
  - Do-演算（Pearlの因果推論）
  - 傾向スコアマッチング
- **利点**:
  - 因果推論の厳密な理論に基づく。
- **制約**:
  - DAGを事前に指定する必要がある。

```python
from dowhy import CausalModel

model = CausalModel(data=df, treatment="X", outcome="Y", common_causes=["Z"])
identified_estimand = model.identify_effect()
```
→ **介入の因果効果を推定**

---

## **結論**
- **SEM (`semopy`, `PyMC3`)**: 仮説モデルの適合度評価と因果推論
- **因果探索 (`lingam`, `causal-learn`)**: データ駆動で因果構造を学習
- **因果推論 (`DoWhy`)**: 介入効果を推定

**目的に応じて適切な手法を選ぶことが重要！**

# **user**:

ありがとうございました！大変勉強になりました！

# **assistant**:

どういたしまして！お役に立てて嬉しいです😊✨  
SEMや因果推論は奥が深いので、また何か疑問があれば気軽に聞いてください！Pythonのコード実装や具体的な解析の進め方についてもお手伝いできます💡📊

楽しいデータ分析ライフを！🚀