今回は機械学習の重要なトピックである「潜在変数モデル」と「EMアルゴリズム」について、実装例を交えながら丁寧に解説していきます。
潜在変数モデルとは?
潜在変数モデルでは、観測できる変数(データ)と観測できない潜在変数(隠れた要因)の間に何らかの関係があると仮定します。例えば、以下のようなモデルが考えられます。
- 人の収入(観測変数)は、能力や努力度合い(潜在変数)に影響を受ける
- 天気予報の適切さ(観測変数)は、予報士の能力(潜在変数)に左右される
- 製品の品質(観測変数)は、工場の設備状況(潜在変数)による
このように、潜在変数モデルでは観測できないが重要な要因(潜在変数)が、観測できるデータ(観測変数)に影響を与えていると考えられています。しかし、潜在変数は直接観測できないため、その値を推定するのは難しい問題となります。
EMアルゴリズムによる潜在変数モデルの解析
そこで登場するのが、EMアルゴリズム(Expectation-Maximization algorithm)です。EMアルゴリズムは、潜在変数を含むモデルのパラメータを推定するための一般的なアルゴリズムです。 具体例として、ある集団にはハッピー層とアンハッピー層の2つの潜在的なグループ(潜在変数)が存在すると考えられます。しかし、我々は個人の幸福度(観測変数)しか観測できません。EMアルゴリズムを使うことで、観測された幸福度からグループ分けのパラメータ(平均や分散など)を推定することができます。 EMアルゴリズムは以下の2ステップを繰り返し行うことで、パラメータを推定します。
- E-step (Expectation step): 現在のパラメータを使って、潜在変数の事後確率分布を計算する。
- M-step (Maximization step): 事後確率分布を使って、対数尤度を最大化するようにパラメータを更新する。
この2ステップを交互に繰り返すことで、潜在変数を含むモデルのパラメータを徐々に良い値に近づけていきます。 次に、Pythonでの実装例を見ていきましょう。
import numpy as np # データ生成過程 # zは潜在変数、xは観測変数 # P(z=0) = 0.5、P(z=1) = 0.5 # z = 0の時、x ~ N(0, 1) # z = 1の時、x ~ N(5, 1) def sample_data(n_samples): z = np.random.binomial(1, 0.5, n_samples) # 潜在変数zをサンプリング x = np.zeros(n_samples) x[z == 0] = np.random.normal(0, 1, np.sum(z == 0)) # z=0の時、x ~ N(0, 1) x[z == 1] = np.random.normal(5, 1, np.sum(z == 1)) # z=1の時、x ~ N(5, 1) return x, z # EMアルゴリズム def em(x: np.ndarray, n_iter: int = 100) -> tuple[float, float]: """EMアルゴリズムを実行し、最終的な平均と分散を返す""" n_samples = len(x) # 初期値 mu0 = 0.0 # 平均の初期値 mu1 = 5.0 sigma0 = 1.0 sigma1 = 1.0 pi = 0.5 # 事前確率の初期値 for _ in range(n_iter): # E-step: 事後確率を計算 p0 = pi * np.exp(-0.5 * ((x - mu0) / sigma0) ** 2) / (np.sqrt(2 * np.pi * sigma0)) p1 = (1 - pi) * np.exp(-0.5 * ((x - mu1) / sigma1) ** 2) / (np.sqrt(2 * np.pi * sigma1)) gamma = p0 / (p0 + p1) # M-step: パラメータを更新 mu0 = np.sum(x * (1 - gamma)) / np.sum(1 - gamma) mu1 = np.sum(x * gamma) / np.sum(gamma) sigma0 = np.sqrt(np.sum((x - mu0) ** 2 * (1 - gamma)) / np.sum(1 - gamma)) sigma1 = np.sqrt(np.sum((x - mu1) ** 2 * gamma) / np.sum(gamma)) pi = np.mean(gamma) return mu0, sigma0, mu1, sigma1 # サンプルデータを生成 x, z = sample_data(1000) # EMアルゴリズムを実行し、推定された平均と分散を出力 mu0, sigma0, mu1, sigma1 = em(x) print(f"z=0の時の推定平均: {mu0:.2f}, 推定分散: {sigma0:.2f}") print(f"z=1の時の推定平均: {mu1:.2f}, 推定分散: {sigma1:.2f}")
このコードでは、潜在変数zと観測変数xのデータ生成過程が定義されています。EMアルゴリズムの関数emでは、以下の処理が行われています。
平均、分散、事前確率の初期値を設定します。 E-stepで、現在のパラメータから潜在変数の事後確率gammaを計算します。 M-stepで、事後確率gammaを使って平均、分散、事前確率を更新します。 2と3を指定された反復回数(n_iter)分繰り返します。 最終的な平均と分散を返します。
実行すると、潜在変数zが0と1の2つの値を取る場合の、推定された平均と分散が出力されます。 このように、EMアルゴリズムを使うことで、潜在変数を含むモデルのパラメータを推定することができます。機械学習の分野をはじめ、様々な分野で幅広く利用されているアルゴリズムです。