ChatGPTに言われるがままにLiNGAMを勉強してみた

# はじめに
先日、ChatGPTにハンズオンを作ってもらって、その通りに因果推論探索の手法の**LiNGAM**と**VAR-LiNGAM**を勉強しました。

https://x.com/uki_datascience/status/1890394229672677741

# LiNGAM
因果推論探索の手法の一つで、非ガウス性を利用して因果関係を推定する。

### 使用データ
Scikit-learnの組み込みデータセットの1つである、カリフォルニアの住宅価格データを使用しました。各変数の説明は以下の通りです。PRICEに対する因果関係を見ていきます。

| 項目        | 説明                           |
|------------|------------------------------|
| MedInc     | 地区の住民の収入の中央値       |
| HouseAge   | 住宅の平均年数               |
| AveRooms   | 1戸あたりの平均部屋数         |
| AveBedrms  | 1戸あたりの平均寝室数         |
| Population | 地区の総人口                 |
| AveOccup   | 1戸あたりの平均居住者数       |
| Latitude   | 地区の緯度                   |
| Longitude  | 地区の経度                   |
| PRICE      | 地区の住宅価格の中央値        |

### 使用コード
```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from lingam import DirectLiNGAM
```

```python
from sklearn.datasets import fetch_california_housing

# データセットの取得（Bostonは非推奨なのでCalifornia Housingを使用）
data = fetch_california_housing()
df = pd.DataFrame(data.data, columns=data.feature_names)

# 住宅価格を追加
df["PRICE"] = data.target

# 特徴量を標準化
scaler = StandardScaler()
df_scaled = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)
df_scaled
```

```python
# LiNGAMモデルの実行
model = DirectLiNGAM()
model.fit(df_scaled)

# 係数行列を取得
causal_matrix = model.adjacency_matrix_

# 結果の可視化
plt.figure(figsize=(10, 8))
plt.imshow(causal_matrix, cmap="coolwarm", interpolation="nearest")
plt.colorbar()
plt.xticks(ticks=np.arange(len(df_scaled.columns)), labels=df_scaled.columns, rotation=90)
plt.yticks(ticks=np.arange(len(df_scaled.columns)), labels=df_scaled.columns)
plt.title("LiNGAM Causal Matrix")

# 係数行列の値を表示
for (i, j), val in np.ndenumerate(causal_matrix):
    plt.text(j, i, f'{val:.2f}', ha='center', va='center', color='black')
    
plt.show()
```

### 分析結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457746/406cc46a-7da0-4d54-8d7d-a4a38fb6d698.png)

- **MedInc**（中央値の収入）:0.63
    - プラスの影響（収入が高いほど価格が高くなる）
    - これは直感的にも納得できる関係
- **HouseAge**（築年数）:0.11
    - ややプラスの影響（築年数が高いほど価格がやや高くなる）
    - これはエリアの歴史的価値などが影響している可能性
- **Latitude**（緯度）:-0.86、**Longitude**（経度）:-0.82
    - 大きな負の影響
    - 地域的な要因が住宅価格に強く影響を与えている
    - 例えば、緯度・経度が住宅地の価値を決める重要な要素となっている（地理的な高級住宅地 vs 低価格エリア）
    - 南西の価格が高く、北東の価格が安い？

# VAR-LiNGAM
VARモデルとLiNGAMを組み合わせることで、時系列データに対応した因果推論探索の手法で、非ガウス性を利用して因果関係を推定する。

### 使用データ
FRED (Federal Reserve Economic Data, 連邦準備制度経済データ) から米国の経済データを取得しました。各変数の説明は以下の通りです。

| 指標                 | 説明                           |
|----------------------|------------------------------|
| **GDP**             | GDP（景気の成長を示す）       |
| **Unemployment Rate** | 失業率（労働市場の状態を示す） |
| **Inflation Rate**   | インフレ率（物価の上昇を示す） |
| **Interest Rate**    | 政策金利（中央銀行の金利政策） |
| **Stock Market Index** | 株価指数（経済の期待を示す）  |

### 使用コード
```python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pandas_datareader import data as pdr
import statsmodels.api as sm
from statsmodels.tsa.api import VAR
from lingam import VARLiNGAM
from sklearn.preprocessing import StandardScaler
```

```python
# 経済データ取得（FRED）
start_date = '2000-01-01'
end_date = '2024-01-01'
symbols = {
    'GDP': 'GDP',
    'Unemployment Rate': 'UNRATE',
    'Inflation Rate': 'CPIAUCSL',
    'Interest Rate': 'FEDFUNDS',
    'Stock Market Index': 'SP500'
}

df = pdr.get_data_fred(symbols.values(), start=start_date, end=end_date)
df.columns = symbols.keys()

# データの月次変化率を計算
df = df.pct_change().dropna()

# 標準化
scaler = StandardScaler()
df_scaled = pd.DataFrame(scaler.fit_transform(df), columns=df.columns, index=df.index)
df_scaled
```

```python
# VARモデルのラグ選択
model = VAR(df_scaled)
lag_selection = model.select_order(maxlags=12)
print(lag_selection.summary())

# 最適なラグを取得
selected_lag = lag_selection.aic
print(f"Selected lag: {selected_lag}")
```

```python
# VAR-LiNGAMの適用
var_lingam = VARLiNGAM(lags=selected_lag)
var_lingam.fit(df_scaled)

# 因果関係の推定結果を取得
causal_matrix = var_lingam.adjacency_matrices_

# 結果の可視化
plt.figure(figsize=(10, 8))
plt.imshow(causal_matrix.sum(axis=0), cmap="coolwarm", interpolation="nearest")
plt.colorbar()
plt.xticks(ticks=np.arange(len(df_scaled.columns)), labels=df_scaled.columns, rotation=90)
plt.yticks(ticks=np.arange(len(df_scaled.columns)), labels=df_scaled.columns)
plt.title("VAR-LiNGAM Causal Matrix")

# 係数行列の値を表示
for (i, j), val in np.ndenumerate(causal_matrix.sum(axis=0)):
    plt.text(j, i, f'{val:.2f}', ha='center', va='center', color='black')

plt.show()
```

### 分析結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457746/5c04b980-1e14-456a-9e4a-80a1964be167.png)


- GDP → 失業率（-0.57）
    - 負の影響：GDPが成長すると、失業率が下がる
    - これは経済の基本的な関係で、GDP成長によって雇用が増えるため、失業率が減ることを示唆
- インフレ率 → GDP（0.37）
    - 正の影響：インフレ率が上がると、GDPが成長
    - これは、インフレが発生すると短期的には企業の収益が増え、経済が活発になる可能性を示す
- インフレ率 → 金利（0.41）
    - 強い正の影響：インフレが上昇すると、金利も上がる
    - これは中央銀行がインフレ抑制のために金利を引き上げる典型的なパターンを示している
- 金利 → 失業率（-0.29）
    - 負の影響：金利が上がると、失業率が減る
    - これは直感に反する結果だが、特定の時期（例えば金融緩和の影響）では成り立つ可能性もあるため、さらなる分析が必要
- 株式市場 → 自身（-0.14）
    - 自己相関的な要素があり、時系列の影響が強い

# 参考資料
https://qiita.com/itsuki_m/items/3fe9b1154e6e98b182e4