スコア検定#
概要#
スコア関数#
分布\(f(x|\theta)\)からランダムに得られた\(n\)個のサンプルを\(X = (X_1, \cdots, X_n)\)とする。
\(X\)の同時確率関数(尤度)を\(\prod_{i=1}^n f(x_i|\theta)\)を\(f_n(x|\theta)\)と表す。
対数尤度\(l(\theta, X) = \log f_n(X|\theta)\)の導関数
を スコア関数 (score function)という。
フィッシャー情報量#
スコア関数の2乗の期待値
を フィッシャー情報量 という。
スコア関数の性質#
(\(I_1(\theta)\)はサンプル1つのフィッシャー情報量)
となるので、中心極限定理により、\(\theta\)が真値のとき
という漸近正規性があるので、これを使って検定ができる
TODO: 導出を追う
\(l'_1(\theta, X_i) = \{(d/d\theta) f(x|\theta)\} / f(x|\theta)\)と書けるらしいので(?)
スコア検定#
に対して、
を棄却域とする検定を スコア検定 (score test) という。
例#
参考:Julia and real estate statistics
ガンマ分布っぽいデータがあったとする。
ガンマ分布のshapeパラメータ\(\alpha\)は、\(\alpha=1\)のとき指数分布と一致する。
データが指数分布(\(\alpha=1\))に従っているのか、かガンマ分布(\(\alpha \neq 1\))なのか検定する(ガンマ分布のscaleパラメータは既知とする)
最尤推定量\(\alpha_{ML}\)について以下の仮説に対する検定を行う
最尤推定量\(\alpha_{ML}\)を求める
from scipy.stats import gamma
def log_likelihood(alpha):
return np.sum(gamma.logpdf(x, a=alpha, scale=scale))
def neg_log_likelihood(alpha, scale, data):
# scipyはminimize_scalar しかないので、対数尤度ではなく負の対数尤度にする
return -np.sum(gamma.logpdf(data, a=alpha, scale=scale))
from scipy.optimize import minimize_scalar
result = minimize_scalar(neg_log_likelihood, args=(scale, x), bounds=(0.01, 10), method='bounded')
alpha_hat = result.x
# 最尤推定量
print(f"{alpha_hat=:.3f}")
alpha_hat=1.075
\(E[-l''_n(\theta,X)]= I_n(\theta)\)という関係があるので、対数尤度の2階微分でフィッシャー情報量を求める
import numdifftools as nd
grad = nd.Derivative(log_likelihood, n=1)
hess = nd.Derivative(log_likelihood, n=2)
print(f"{grad(alpha_hat)=}, {hess(alpha_hat)=}")
grad(alpha_hat)=array(0.0002217), hess(alpha_hat)=array(-1480.84211289)
なぜフィッシャー情報量で割るのか → 対数尤度のピークが鋭ければ\(l''(\theta)\)は大きな値をとるためらしい
/usr/local/lib/python3.10/site-packages/numpy/lib/nanfunctions.py:1563: RuntimeWarning: All-NaN slice encountered
return function_base._ureduce(a,
/usr/local/lib/python3.10/site-packages/numdifftools/limits.py:150: UserWarning: All-NaN slice encountered
warnings.warn(str(msg))
\(\frac{|\ell'(\alpha)|}{ \sqrt{-\ell''(\alpha)}}\)の値が大きいので標準正規分布に従っているのか不安だが、概ねそれっぽい値になってる
\(\alpha = 1\)とする(\(\alpha_0=1\)とする)という帰無仮説のもとでの検定統計量を計算
# 検定統計量
alpha_0 = 1
I = -hess(alpha_0) # I = E[-l''(θ)]
score = abs(grad(alpha_0)) / np.sqrt(I)
print(f"|l'(α0)| / √I(α0) = {score:.3f}")
|l'(α0)| / √I(α0) = 2.894
これは標準正規分布上では次のような値になる
from scipy.stats import norm
pvalue = 2 * (1 - norm.cdf(score))
pvalue
0.0038054754122531786