私はPythonが初めてです。私のコードがぎこちなく感じる場合は、事前にお詫び申し上げます。ここ数週間、私は控除可能なモデリングと呼ばれる難しい統計上の課題に取り組んできました。私が理解しているように、私の問題はプログラミング/最適化の問題であり、統計の問題ではありません。
必要に応じて、このスレッドをより適切なスタック交換サイトに移動してください。
8 つのパラメーターがあり、そのうちの 2 つは制約されており、正 (phi_freq
およびphi_sev
) である必要があります。基本的に、これらすべてのパラメーターの非凸、マルチモーダル、連続、実数値、非微分 (AFAIK) 関数である対数尤度関数を最大化しようとしています。うわぁ!
このような問題は、検索アルゴリズムに提供されるシード値が、収束するローカル/グローバル最適値に多大な影響を与えることを意味しますが、私の知る限り、私の開始値はしっかりしており、ハードコーディングされています (提供されたサンプルでは)以下)、単なる主観的な直感ではなく、補助的な最適化の結果でした。
Nelder-Mead
ライブラリのandSLSQP
メソッド (SLSQP
はコメントアウトされています) を使用してみましscipy.optimize.minimize
たが、返される値はぎこちなく、無意味です。
以下は MWE です。
from scipy.stats import gamma
from scipy import special
import pandas as pd
import numpy as np
import scipy as s
def freq_mean(intercept_freq, beta_veh_age_log, beta_dr_section_b):
return np.exp(intercept_freq + beta_veh_age_log * freq_data['veh_age_log'] + beta_dr_section_b * freq_data['dr_section_b'])
def sev_mean(intercept_sev, alpha_veh_age_log, alpha_acv_log, df):
return np.exp(intercept_sev + alpha_veh_age_log * df['veh_age_log'] + alpha_acv_log * df['acv_log'])
def freq_dist(x, mu, phi):
return (sp.special.gamma(phi + x) / sp.special.gamma(phi) / sp.special.factorial(x)) * ((phi / (phi + mu)) ** phi) * ((mu / (phi + mu)) ** x)
def sev_dist(x, mu, phi, ded):
gamma_pdf = (((phi / mu) ** phi) / sp.special.gamma(phi)) * (x ** (phi - 1.0)) * np.exp(-phi * x / mu)
gamma_sdf = 1.0 - sp.stats.gamma.cdf(x = phi * ded / mu, a = phi, scale = 1.0)
if gamma_sdf == 0.0:
return 0.0
else:
return gamma_pdf / gamma_sdf
def sev_loglik(intercept_sev, alpha_veh_age_log, alpha_acv_log, phi_sev):
sev_data['mu_sev'] = sev_mean(intercept_sev, alpha_veh_age_log, alpha_acv_log, sev_data)
return sev_data.apply(lambda x : np.log(sev_dist(x['claim_amount'], x['mu_sev'], phi_sev, x['deductible'])), axis = 1).sum()
def freq_loglik(intercept_freq, beta_veh_age_log, beta_dr_section_b, phi_freq, intercept_sev, alpha_veh_age_log, alpha_acv_log, phi_sev):
freq_data['mu_sev'] = sev_mean(intercept_sev, alpha_veh_age_log, alpha_acv_log, freq_data)
freq_data['claim_prob'] = 1.0 - sp.stats.gamma.cdf(x = phi_sev * freq_data['deductible'] / freq_data['mu_sev'], a = phi_sev, scale = 1.0)
freq_data['mu_freq'] = freq_mean(intercept_sev, beta_veh_age_log, beta_dr_section_b)
return freq_data.apply(lambda x : np.log(freq_dist(x['claim_count'], x['exposure'] * x['claim_prob'] * x['mu_freq'], x['exposure'] * phi_freq)), axis = 1).sum()
def obj_func(param):
intercept_freq, beta_veh_age_log, beta_dr_section_b, phi_freq, intercept_sev, alpha_veh_age_log, alpha_acv_log, phi_sev = param
ll_sev = sev_loglik(intercept_sev, alpha_veh_age_log, alpha_acv_log, phi_sev)
ll_freq = freq_loglik(intercept_freq, beta_veh_age_log, beta_dr_section_b, phi_freq, intercept_sev, alpha_veh_age_log, alpha_acv_log, phi_sev)
return -(ll_freq + ll_sev)
def mle(nfev = 100):
intercept_freq, beta_veh_age_log, beta_dr_section_b, phi_freq, intercept_sev, alpha_veh_age_log, alpha_acv_log, phi_sev = (-1.87515443, -0.5675389200, -0.0216802900, 23.78568667, 10.42040743, 0.00465891, 0.00072216, 0.69497075)
seeds = np.array([intercept_freq, beta_veh_age_log, beta_dr_section_b, phi_freq, intercept_sev, alpha_veh_age_log, alpha_acv_log, phi_sev])
return sp.optimize.minimize(fun = obj_func, x0 = seeds, method = 'Nelder-Mead', options = {'maxfev' : nfev})
#cons = ({'type': 'ineq', 'fun' : lambda x : x[3]}, {'type': 'ineq', 'fun' : lambda x : x[7]})
#return sp.optimize.minimize(fun = obj_func, x0 = seeds, method = 'SLSQP', constraints = cons)
policies = pd.read_csv('C:/policies.txt', sep = '\t')
claims = pd.read_csv('C:/claims.txt', sep = '\t')
freq_data = pd.merge(left = policies, right = claims.groupby('ID').agg(claim_count = ('claim_amount', 'count')), how = 'left', on = 'ID')
freq_data['claim_count'].fillna(0, inplace = True)
sev_data = pd.merge(left = claims[['ID', 'claim_amount']], right = policies.drop(['dr_section_b', 'exposure'], axis = 1), how = 'left', on = 'ID')
opt = mle(4000)
現時点でデータを提供する必要があるかどうか、またどのように提供する必要があるかはわかりません (サンプル コードで参照されているpolicies
およびclaims
フラット ファイル)。私はそうする準備ができていますが、最初にそれらを匿名化する必要があります.
ですから、私は壁にぶつかりそうになっているので、この時点でどんな指針も歓迎されると思います. グローバルなソリューションが存在する必要があります。つまり、mle
(最尤推定量) が存在する必要があります。私のシード値は、モーメント マッチング (いわゆるmethod of moments
推定値) によって取得されたため、非常に現実的です。私が間違っていることが他にあるに違いないと感じています。また、不自由に聞こえるかもしれませんが、Excel
のソルバーを使用してまったく同じ問題を再現し、同様の数値収束の問題に遭遇しました。この問題に関して、技術的かどうかにかかわらず、補足的な詳細を提供させていただきます。