反復重み付き最小二乗法で遊ぶ
1.はじめに
積読が増えてきてしまった*1ので、最近はDobson本を読み始めたのですが、反復重み付き最小二乗法(IRLS)なるとても興味深いものを見つけました。面白そうだったからとりあえず実装してみたというのが今回の記事です。本記事は、IRLSを実装するために最低限必要な数式しか載せていないので、文章や式の展開がだいぶ飛躍しています。これに関連して、記事中で出てくる記号について先に述べておくと、は推定したいパラメータであり、はの推定値となります。
2.指数型分布族と一般化線形モデル
指数型分布族から述べます。指数型分布族は次の式で表されます。
独立な確率変数が従う分布を、指数型分布族に属する分布であると仮定します。さらに、以下に示す関係を仮定します。
ここで、は番目のデータに対する説明変数(p×1ベクトル)であり、は推定したいパラメータです。一般化線形モデルでは、連結関数が非常に重要なパーツとなります。
3.パラメータの推定(IRLS)
3.1 とりあえず結論
IRLSの本題に移りますが、冒頭にも述べた通り実装に不要な数式は一気にすっ飛ばしていくので、とりあえずIRLSの反復式を示します。反復式は次のようになります。
ここで、は説明変数の行列でありN×p行列です。はパラメータの推定値ベクトルでp×1ベクトルです。はN×Nの対角行列であり、成分は次の式で表されます(式中の偏微分の箇所は後で説明します)。
最後に、はN×1ベクトルであり、番目の要素は次の式で表されます。
IRLSを実装する時は、とを逐一計算していきます。次に、この反復式を導出するに当たって必要な流れを述べていきます。
3.2 導出
最尤推定の流れから導出していきます。指数型分布族と一般化線形モデルの部分で述べた仮定に基づいて、まずは対数尤度関数を求めていきます。番目のデータに対する対数尤度関数は次の式で表されます。
がとなっているのは、一般化線形モデルの場合は正準形を持つ分布が前提となっているからです。ここからパラメータの最尤推定値を求めていくわけですが、さっくり流れだけ追っていきます。パラメータの最尤推定値を得るために、対数尤度関数を微分します。とりあえず簡単のために、番目のデータに対する対数尤度関数を微分します。
対数尤度関数は合成関数になっている*2ため、微分の連鎖法則を用いて微分していきます。さらに、右辺の3つ目の偏微分は次のように微分の連鎖法則で微分できます。
一番最後の式の偏微分はとりあえず結論で述べた所にも現れています。この偏微分は(記事には載せませんが)スコアや情報行列にも現れてきており、解析的に反復の式を導出する際はこれを計算する必要があります。
あとは偏微分から良い感じになんやかんやしてなんやかんやする*3と、IRLSの反復計算式を求める事が出来ます。途中経過は省略です。
3.3 例.ロジスティック回帰
実験ではロジスティック回帰で遊んでいきます。Dobson本では第7章で触れられています*4が、スコアと情報行列を出して終わっているので、IRLSで計算すべきとまでは述べてくれていません。従って、自力で導出していきます。計算が間違えている可能性もあるので、あらかじめごめんなさいしておきます。
ひとまず重要なのは、次の2つです。
ここで、であり、ロジスティック回帰では期待値と連結関数は次のようになります。
中のはなのでとりあえずOKです。次に、どちらにも共通して現れる偏微分を求めていきます。偏微分の結果は次のようになります。
第3式から第4式は逆関数の微分を利用しました。これで、とは次のようにすっきり求める事が出来ました。
これで完成で、あとは反復式に入れるだけです。
4.実験
4.1 IRLSの実装
さて、長々と述べてきたわけですが、IRLSの実装に重要なポイントをまとめていきます。
反復式
反復式では、とを計算する必要があります。
ロジスティック回帰のIRLS
ロジスティック回帰では、とは次の式で表す事が出来ました。
あとは上手く反復の手順を考えるだけです。
反復の手順
パラメータが多いと可視化に困るので、とを次のように決めておきます。
ステップ目の推定したパラメータをとした時、反復の手順を次に示します。
手順1:初期値を決める→パラメータの初期値を、確率の最尤推定値の初期値をとして与えます。
手順2:とを計算
手順3:反復式を次のように変形して、パラメータを推定
手順4:パラメータの推定後、を次の式で計算
手順5:手順1のをに変更して、手順2から繰り返す
これをパラメータが収束するまで繰り返していきます。
5.まとめ
ちゃんとうごかすことができてとてもたのしかったです
プログラム
こっそりあとがきですが、実はこの記事を書いた段階ではDobson本は第4章までしか読めておらず、収束の判定まではプログラムに実装できませんでした*6。安直にfor文で回しただけのプログラムになってしまいましたが、IRLSのコアとなる部分はfor文の中の4行です。もう少し上手い事プログラムを組めばより短くなるかもしれません。
# seibisi import numpy as np import pandas as pd import matplotlib.pyplot as plt from numpy.random import * from matplotlib import animation def make_p(beta1, beta2, x): return np.exp(beta1 + beta2 * x) / (1 + np.exp(beta1 + beta2 * x)) def main(): # パラメータ beta = [2.0, 3.0] x = np.linspace(-5, 5, 20) pi = make_p(beta[0], beta[1], x) # データセットの作成 n = [round(normal(50, 5)) for i in range(len(x))] y = [round(nn * pp) for nn, pp in zip(n, pi)] # 初期値 beta_hat = [0, 0] pi_hat = [0.5 for i in range(len(y))] X = np.array([np.ones(len(y)), x]).T # IRLS for i in range(10): # 1. zとWの計算 z = [beta_hat[0] + beta_hat[1] * xx + (yy - nn * pp)/(nn * pp * (1-pp)) for xx, yy, nn, pp in zip(x, y, n, pi_hat)] W = np.diag([nn * pp * (1-pp) for nn, pp in zip(n, pi_hat)]) # 2. パラメータの計算 beta_hat = np.dot(np.linalg.inv(np.dot(np.dot(X.T, W), X)), np.dot(np.dot(X.T, W), z)) # 3. 予測 pi_hat = make_p(beta_hat[0], beta_hat[1], x)