web-dev-qa-db-ja.com

scipy.optimizeとloglikelihoodを使用してベータ二項分布のアルファとベータを見つける

p、成功の確率、二項分布が形状パラメーターα>およびβ> 0のベータ分布を持っている場合、分布はベータ二項です。。形状パラメータは、成功の確率を定義します。ベータ二項分布の観点から私のデータを最もよく表すαおよびβの値を見つけたいと思います。私のデータセットplayersは、ヒット数([〜#〜] h [〜#〜])、打席数([〜 #〜] ab [〜#〜])と多くの野球選手の変換(H/AB)。 Pythonのベータ二項関数 のJulienDの答えの助けを借りてPDFを推定します

from scipy.special import beta
from scipy.misc import comb

pdf = comb(n, k) * beta(k + a, n - k + b) / beta(a, b)

次に、最小化する対数尤度関数を記述します。

def loglike_betabinom(params, *args):
   """
   Negative log likelihood function for betabinomial distribution
   :param params: list for parameters to be fitted.
   :param args:  2-element array containing the sample data.
   :return: negative log-likelihood to be minimized.
   """

   a, b = params[0], params[1]
   k = args[0] # the conversion rate
   n = args[1] # the number of at-bats (AE)

   pdf = comb(n, k) * beta(k + a, n - k + b) / beta(a, b)

   return -1 * np.log(pdf).sum()   

ここで、最小化する関数を記述したいと思いますloglike_betabinom

 from scipy.optimize import minimize
 init_params = [1, 10]
 res = minimize(loglike_betabinom, x0=init_params,
                args=(players['H'] / players['AB'], players['AB']),
                bounds=bounds,
                method='L-BFGS-B',
                options={'disp': True, 'maxiter': 250})
 print(res.x)

結果は[-6.045441382.03984464]です。これは、αが負であることを意味しますが、これは不可能です。次のRスニペットに基づいてスクリプトを作成しました。彼らは[101.359、287.318]を取得します。

 ll <- function(alpha, beta) { 
    x <- career_filtered$H
    total <- career_filtered$AB
    -sum(VGAM::dbetabinom.ab(x, total, alpha, beta, log=True))
 }

 m <- mle(ll, start = list(alpha = 1, beta = 10), 
 method = "L-BFGS-B", lower = c(0.0001, 0.1))

 ab <- coef(m)

誰かが私が間違っていることを教えてもらえますか?助けていただければ幸いです!!

14
HJA24

注意すべき点の1つは、対数尤度のcomb(n, k)が、データセットのnkの値に対して数値的に適切に動作しない可能性があることです。これを確認するには、データにcombを適用し、infsが表示されるかどうかを確認します。

物事を修正する1つの方法は、 https://stackoverflow.com/a/32355701/424041 で提案されているように、つまり、ガンマ関数の対数の関数として、負の対数尤度を書き直すことです。

from scipy.special import gammaln
import numpy as np

def loglike_betabinom(params, *args):

    a, b = params[0], params[1]
    k = args[0] # the OVERALL conversions
    n = args[1] # the number of at-bats (AE)

    logpdf = gammaln(n+1) + gammaln(k+a) + gammaln(n-k+b) + gammaln(a+b) - \
     (gammaln(k+1) + gammaln(n-k+1) + gammaln(a) + gammaln(b) + gammaln(n+a+b))

    return -np.sum(logpdf) 

次に、次の方法で対数尤度を最小化できます。

from scipy.optimize import minimize

init_params = [1, 10]
# note that I am putting 'H' in the args
res = minimize(loglike_betabinom, x0=init_params,
            args=(players['H'], players['AB']),
            method='L-BFGS-B', options={'disp': True, 'maxiter': 250})
print(res)

そしてそれは合理的な結果を与えるはずです。

コードをさらに作り直したい場合は、 Pythonでベータ分布を適切に適合させる方法は? インスピレーションを確認できます。

7
Davide Fiocco