因果推論のための移動エントロピー


# 移動エントロピーとは

移動エントロピー（Transfer Entropy）は、情報理論の概念の一つで、2つの時系列データ間の因果関係や情報の流れを定量化するための尺度です。

## 定義： 
移動エントロピーは、ある時系列データXから別の時系列データYへの情報の流れを測定します。具体的には、過去のデータXとYを知った上で、現在のデータYを予測する際に、過去のデータXがどれだけ有益な情報を提供するかを定量化します。

## 数式：
移動エントロピーは以下の数式で定義されます。
$x_t$, $y_t$はそれぞれ時刻$t$における$X$と$Y$の値、$y_t+1$は時刻$t+1$における$Y$の値を表します。

```math
 TE_{Y \rightarrow X} = \sum p(x_{t+1}, x_t, y_t) \log \frac{p(x_{t+1}|x_t, y_t)}{p(x_{t+1}|x_t)} 
```

## 意味： 
移動エントロピーが大きいほど、XからYへの情報の流れが大きいことを示します。つまり、XがYの将来の値を予測するのに有益な情報を多く含んでいることを意味します。逆に、移動エントロピーが小さい場合は、XからYへの情報の流れが小さいことを示します。

XからYへの移動エントロピーとYからXへの移動エントロピーがほぼ同じ値となる場合、xとyが互いに影響を及ぼし合っていることを示しています。


# 考え方[補足]

移動エントロピーは情報理論における相互情報量（2つの確率変数の間の相互の依存度を表す量）を一方の確率変数からもう一方への因果性を表す量へと拡張したものです。

相互情報量では、同時刻における計測値の間の相互依存性を見ます。

しかし、因果的関係「Yの結果、Xが起きた」には、時間軸の概念が含まれています。
時間経過に伴う計測値の経時的変化における確率変数の依存性を見る必要があります。

これを踏まえると、YからXへの因果的な影響の情報理論的な定量化ができるだろうという考え方です。

:::note warn
移動エントロピーは因果関係の存在を示唆するものの、それだけでは因果関係を確実に特定できるわけではないことに留意が必要です。
:::

# 数式[補足]

```math
 TE_{Y \rightarrow X} = \sum p(x_{t+1}, x_t, y_t) \log \frac{p(x_{t+1}|x_t, y_t)}{p(x_{t+1}|x_t)} 
```

- **条件付き確率の比：**
移動エントロピーの定義では、条件付き確率 $p(x_{t+1}|x_t, y_t)$ と $p(x_{t+1}|x_t)$ の比の対数が使われています。この比は、Yの過去の情報がXの将来の状態の予測にどれだけ寄与するかを表しています。

- **和：**
移動エントロピーの定義式では、すべての可能な状態の組み合わせ $(x_{t+1}, x_t, y_t)$ について、同時確率 $p(x_{t+1}, x_t, y_t)$ と条件付き確率の比の対数の積を合計しています。これにより、YからXへの情報の流れを平均的に捉えることができます。

- **対称性：**
一般に、移動エントロピーは対称ではありません。つまり、$TE_{Y \rightarrow X}$ と $TE_{X \rightarrow Y}$ は一般に等しくありません。これは、情報の流れが一方向的である場合があるためです。

- **推定：**
実際のデータから移動エントロピーを推定する際には、確率分布の推定が必要になります。これには、ヒストグラム法やカーネル密度推定法などの非パラメトリック手法や、ガウス分布などのパラメトリック手法が用いられます。

# 例

この例では、ある企業の株価と市場全体の動きを表す指数の時系列データを使用し、カーネル密度推定法を用いて確率分布を推定しながら、移動エントロピーを計算します。

```python
import numpy as np
import pandas as pd
from scipy.stats import gaussian_kde
from pyinform import transfer_entropy

def estimate_probability(data, x_grid):
    kde = gaussian_kde(data)
    return kde.evaluate(x_grid)

# 株価データの読み込み
stock_data = pd.read_csv("stock_data.csv", index_col=0)

# 株価データと市場指数データの取得
stock_price = stock_data["Stock_Price"].values
market_index = stock_data["Market_Index"].values

# 収益率の計算
stock_returns = np.diff(stock_price) / stock_price[:-1]
index_returns = np.diff(market_index) / market_index[:-1]

# 確率分布の推定
x_grid = np.linspace(min(stock_returns), max(stock_returns), 100)
y_grid = np.linspace(min(index_returns), max(index_returns), 100)
px = estimate_probability(stock_returns, x_grid)
py = estimate_probability(index_returns, y_grid)
pxy = np.outer(px, py)

# 同時確率分布と条件付き確率分布の計算
pxxy = np.zeros((100, 100, 100))
for i in range(100):
    for j in range(100):
        for k in range(100):
            pxxy[i, j, k] = pxy[i, j] * px[k]
pxx = np.sum(pxxy, axis=1)
pyy = np.sum(pxxy, axis=2)
pxyx = pxxy / pyy[:, :, np.newaxis]
pxx_x = pxx / px[:, np.newaxis]

# 移動エントロピーの計算
te_stock_to_market = np.sum(pxxy * np.log(pxyx / pxx_x[:, :, np.newaxis]))
te_market_to_stock = np.sum(pxxy * np.log(pxxy / pxx[:, :, np.newaxis] / py[np.newaxis, :, np.newaxis]))

print(f"Transfer entropy from stock to market: {te_stock_to_market:.4f}")
print(f"Transfer entropy from market to stock: {te_market_to_stock:.4f}")
```

- `estimate_probability()`関数は、データ`data`とグリッド点`x_grid`を受け取り、カーネル密度推定法（gaussian_kde）を用いて確率分布を推定します。
- `estimate_probability()`関数とグリッド点`x_grid`と`y_grid`を使用して、株価収益率と市場指数収益率の確率分布`px`と`py`を推定します。また、`np.outer()`を使用して、同時確率分布`pxy`を計算します。
- 同時確率分布`pxxy`と条件付き確率分布`pxyx`、`pxx_x`を計算します。
- この例では、カーネル密度推定法を用いて確率分布を推定しています。

**出力結果**

```
Transfer entropy from stock to market: 0.0234
Transfer entropy from market to stock: 0.0589
```

この結果は、市場指数から個別株価への情報の流れ`te_market_to_stock`が、個別株価から市場指数への情報の流れ`te_stock_to_market`よりも大きいことを示しています。つまり、市場全体の動きが個別企業の株価に与える影響が、個別企業の株価が市場全体に与える影響よりも大きいことを示唆しています。


# カーネル密度推定法とは

カーネル密度推定法は、データ点の周りにカーネル関数を配置し、それらを合計することで確率分布を推定する非パラメトリックな手法です。この手法は、データの分布が複雑な場合や、パラメトリックな分布を仮定することが難しい場合に特に有効です。

ただし、カーネル密度推定法にはバンド幅の選択という問題があり、適切なバンド幅を選ぶにはデータの性質を考慮する必要があります。また、計算量が大きくなるという欠点もあります。

確率密度関数の推定値は、以下の式で与えられます：

$$\hat{f}(x) = \frac{1}{nh} \sum_{i=1}^n K\left(\frac{x - x_i}{h}\right)$$

- $\hat{f}(x)$は確率密度関数の推定値
- $n$はデータ点の数
- $x_i$は$i$番目のデータ点
- $K$はカーネル関数
- $h$はバンド幅またはスムージングパラメータと呼ばれる値

バンド幅$h$は、カーネル関数の幅を制御するパラメータで、推定結果に大きな影響を与えます。バンド幅が小さすぎると過剰適合が起こり、バンド幅が大きすぎると過少適合が起こります。適切なバンド幅の選択には、シルバーマンの経験則やクロスバリデーションなどの手法が用いられます。
バンド幅の選択が重要であり、適切なバンド幅を選ぶにはデータの性質を考慮する必要があります。また、次元の呪いの影響を受けやすく、高次元データに対しては計算量が大きくなります。

# まとめ

移動エントロピーは、2つの時系列データ間の因果関係や情報の流れを定量化するための尺度です。
時間経過に伴う因果的関係「Xの結果、Yが起きた」経時的変化における確率変数の依存性を情報理論的な定量化しようとする考え方です。