2次元確率分布の変数変換(計算してPythonで確認)
この記事では2次元確率分布の変数変換を紹介します。
ヤコビアンを使うやつです。
はじめに公式を確認してから例題で実際に計算し、最後にPythonで確認してみます。
自分が学習した備忘録ですが、2次元確率分布の変数変換の勉強をしているけどよく分からない、イメージが湧かない、という方に助けになれば嬉しいです。
変数変換とは?
2次元確率分布の変数変換とは、確率変数
そして大抵は 変換後の
この記事ではそれを知るための計算方法を紹介します。
(1次元の場合ですが)変数変換の具体例として下記のようなものがあります。
-
データの標準化
正規分布 に従う確率変数{\it N}(\mu, \sigma^2) にX Z=(X - \mu)/\sigma なる変数変換を施すと、確率変数
は標準正規分布Z に従います。{\it N}(0, 1)
データの標準化と言われるやつですね。 -
時間の単位の変換
もっと単純な例ですが、分単位で取られた何かの計測時間データに60を掛けて秒単位のデータに変えるのも変数変換です。
この場合は、分単位データを とすると、X の変数変換となります。Y = X \times 60
もちろんこの変換では分布の形状は変わりません。
このような変換を2次元で行い、変換後の分布を知りたいというのがモチベーションです。
変数変換の公式
2次元確率分布の変数変換の公式は下記です。
確率変数
の同時確率(密度)関数を \ (X, Y) とし、 \ f_{X,Y}(x, y)
と表されるとき、 X = h_1(S, T), Y = h_2(S, T) の同時確率(密度)関数 (S, T) は f_{S,T}(s, t) f_{S,T}(s,t) = f_{X,Y}(h_1(s, t), h_2(s, t)) |J(s,t)| となる。
式中の
で求めます。ただし、行列
となります。
この記事では上記公式やヤコビアンについて詳しく説明しませんが、以降で例題を解いてみます。
変数変換の例
確率変数
であるとき、(ただし、
という変数変換をすると、
先に結論を書いてしまうと、
は独立に分布し、それぞれガンマ分布とベータ分布に従い S, T S \sim {\it Ga}(a+b,1) \\ T \sim {\it Beta}(a, b) となります。
は独立なので S,T となります。 f_{S,T}(s,t) = f_S(s)f_T(t)
実際に計算してこうなることを確認してみましょう。
ガンマ分布とベータ分布
まずこの例題に登場するガンマ分布とベータ分布について確認します。
ガンマ分布
ガンマ分布の確率密度関数は下記です。
ただし、
式中の
です。
Pythonでどんな分布か確認してみましょう。
import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate
plt.style.use("seaborn")
def gamma_func(a):
"""ガンマ関数"""
y, abserr = integrate.quad(lambda x: x**(a - 1) * np.exp(-x), 0, np.inf)
return y
def gamma_pdf(x, a, b):
"""ガンマ分布の確率密度関数"""
return 1 / (gamma_func(a) * b**a) * x**(a-1) * np.exp(-x / b)
X = np.linspace(0, 10, 1000)
fig, ax = plt.subplots(figsize=(10, 8))
for a, b in zip([1, 2, 4], [1, 1, 1]):
ax.plot(X, gamma_pdf(X, a, b), label=f"$Ga({a}, {b})$")
ax.set(xlabel="X")
ax.legend(fontsize=15)
plt.show()
ちなみに指数分布
ベータ分布
ベータ分布の確率密度関数は下記です。
ただし、
式中の
です。
ベータ分布もPythonで確認してみましょう。
import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate
plt.style.use("seaborn")
def beta_func(a, b):
"""ベータ関数"""
y, abserr = integrate.quad(lambda x: x**(a-1) * (1 - x)**(b-1), 0, 1)
return y
def beta_pdf(x, a, b):
"""ベータ分布の確率密度関数"""
return (1 / beta_func(a, b)) * x**(a-1) * (1 - x)**(b-1)
X = np.linspace(0, 1, 1000)
fig, ax = plt.subplots(figsize=(10, 8))
for a, b in zip([0.1, 1, 3], [0.5, 1, 2]):
ax.plot(X, beta_pdf(X, a, b), label=f"$Beta({a}, {b})$")
ax.set(xlabel="X", ylim=(-0.1, 4))
ax.legend(fontsize=15)
plt.show()
なかなか面白い形をしていますね。
ベータ分布は
ガンマ関数とベータ関数の関係
ガンマ関数とベータ関数の間には下記の関係があり、今回の例題を解くのに必要となってきます。
計算してみる
ガンマ分布とベータ分布の確認でやや脱線しましたが、例題を実際に計算して解いてみましょう。
まずヤコビアンを求めます。
なので
となります。
よってヤコビアンは
となります。
これを変数変換の公式に入れると
と書けます。ただし
info:
式の3行目はが独立なので X,Y と変形しています。 f_{X,Y}(x,y) = f_X(x)f_Y(y)
7行目は6行目の式にを掛けて並べ替えています。 \ \Gamma(a+b) / \Gamma(a+b)
さて、式の最後の行をよく見ると「
また「
したがって、求めたかった
と書けます。これはガンマ分布とベータ分布の単純な積なので
まとめると、
確率変数
が独立に分布していてそれぞれガンマ分布に従い、 \ X,Y X \sim {\it Ga(a, 1)}\\ Y \sim {\it Ga(b, 1)} であるとき、(ただし、
) a > 0, b > 0 S = X + Y \\ T = X / (X + Y) という変数変換をすると、
は独立に分布し、それぞれガンマ分布とベータ分布 S, T S \sim {\it Ga}(a+b,1) \\ T \sim {\it Beta}(a, b) に従う。
ということです!
Pythonで確認してみる
最後に上記の変数変換が本当にそうなるのか確認してみましょう。
今回は
まず、
# 変数変換前の確率変数X,Yの生成
a = 3
b = 2
X = np.linspace(0, 20, 1000)
Y = np.linspace(0, 20, 1000)
# 乱数生成
x = np.random.gamma(a, 1, 100_000)
y = np.random.gamma(b, 1, 100_000)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6), dpi=80)
# 上で作成した関数 gamma_pdf()を使っているのでエラーに注意.
ax1.hist(x, bins=50, density=True)
ax1.plot(X, gamma_pdf(X, a, 1), label=f"$Ga({a}, 1)$", c="r")
ax2.hist(y, bins=50, density=True)
ax2.plot(Y, gamma_pdf(Y, b, 1), label=f"$Ga({b}, 1)$", c="r")
ax1.set_xlabel("X", fontsize=13)
ax2.set_xlabel("Y", fontsize=13)
ax1.legend(fontsize=15)
ax2.legend(fontsize=15);
続いて変数変換
を行います。
先ほどの計算が正しければ
# 変数変換後の乱数が本当に上記のようになっているか確認
S = np.linspace(0, 20, 100_000)
T = np.linspace(0, 1, 100_000)
# 変数変換
s = x + y
t = x / (x + y)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 12), dpi=80)
# 上で作成した関数 gamma_pdf(), beta_pdf()を使っているのでエラーに注意.
ax1.hist(s, bins=50, density=True)
ax1.plot(S, gamma_pdf(S, a + b, 1), label=f"$Ga({a + b}, 1)$", color="r")
ax2.hist(t, bins=50, density=True)
ax2.plot(T, beta_pdf(T, a, b), label=f"$Beta({a}, {b})$", color="r")
ax1.set_title("S", fontsize=15)
ax2.set_title("T", fontsize=15)
ax1.legend(fontsize=15)
ax2.legend(fontsize=15);
というわけでここまで2次元確率分布の変数変換を見てきました。
実際に手を動かして計算してみるとそれほど大変ではないかなと思いますが、ただ計算しているだけだとイメージが湧きづらいので今回はPythonで確認まで行ってみました。
こういった記事は初めて書くので、分かりづらい点や間違い等あるかもしれませんが、何かありましたらコメント等でご教授いただけると幸いです!
Discussion