2017-10-11 22 views
1

私はxgboostでブーストされたポアソン回帰モデルを実装しようとしていますが、結果は低い周波数で偏っていることがわかります。低周波で予測が爆破するように見えることxgboostのポアソン回帰が低い周波数で失敗する

import numpy as np 
import pandas as pd 
import xgboost as xgb 

def get_preds(mult): 
    # generate toy dataset for illustration 
    # 4 observations with linearly increasing frequencies 
    # the frequencies are scaled by `mult` 
    dmat = xgb.DMatrix(data=np.array([[0, 0], [0, 1], [1, 0], [1, 1]]), 
         label=[i*mult for i in [1, 2, 3, 4]], 
         weight=[1000, 1000, 1000, 1000]) 

    # train a poisson booster on the toy data 
    bst = xgb.train(
     params={"objective": "count:poisson"}, 
     dtrain=dmat, 
     num_boost_round=100000, 
     early_stopping_rounds=5, 
     evals=[(dmat, "train")], 
     verbose_eval=False) 

    # return fitted frequencies after reversing scaling 
    return bst.predict(dmat)/mult 

# test multipliers in the range [10**(-8), 10**1] 
# display fitted frequencies 
mults = [10**i for i in range(-8, 1)] 
df = pd.DataFrame(np.round(np.vstack([get_preds(m) for m in mults]), 0)) 
df.index = mults 
df.columns = ["(0, 0)", "(0, 1)", "(1, 0)", "(1, 1)"] 
df 

# --- result --- 
#    (0, 0) (0, 1) (1, 0) (1, 1) 
#1.000000e-08 11598.0 11598.0 11598.0 11598.0 
#1.000000e-07 1161.0 1161.0 1161.0 1161.0 
#1.000000e-06 118.0 118.0 118.0 118.0 
#1.000000e-05  12.0  12.0  12.0  12.0 
#1.000000e-04  2.0  2.0  3.0  3.0 
#1.000000e-03  1.0  2.0  3.0  4.0 
#1.000000e-02  1.0  2.0  3.0  4.0 
#1.000000e-01  1.0  2.0  3.0  4.0 
#1.000000e+00  1.0  2.0  3.0  4.0 

注意:ここでは、説明するために、私は問題を複製だと思ういくつかの最小限のPythonコードです。これはポアソンラムダ*との関係があるかもしれませんが、体重が1を下回ると(実際には1000を超える体重が増すと周波数が低くなります)、私は予測が平均トレーニングに近づくと期待します周波数(2.5)。また、(上記の例では示されていない)、etaを減らすと、予測の偏りの量が増えるようです。

これは何が起こるのでしょうか?効果を軽減するパラメータが利用可能ですか?

答えて

0

一部の掘り出しの後、解決策が見つかりました。他の誰かが同じ問題に遭遇した場合のためにここに文書化する。それは平均周波数の(自然な)対数に等しいオフセット項を加える必要があることが判明しました。それが直ちに明らかでない場合は、最初の予測が頻度0.5で開始され、予測を平均頻度に再スケーリングするだけで多くの追加の反復が必要なためです。

おもちゃの例の更新については、次のコードを参照してください。私が最初の質問で示唆したように、予測はより低いスケールでの平均頻度(2.5)に近づいています。

import numpy as np 
import pandas as pd 
import xgboost as xgb 

def get_preds(mult): 
    # generate toy dataset for illustration 
    # 4 observations with linearly increasing frequencies 
    # the frequencies are scaled by `mult` 
    dmat = xgb.DMatrix(data=np.array([[0, 0], [0, 1], [1, 0], [1, 1]]), 
         label=[i*mult for i in [1, 2, 3, 4]], 
         weight=[1000, 1000, 1000, 1000]) 

    ## adding an offset term equal to the log of the mean frequency 
    offset = np.log(np.mean([i*mult for i in [1, 2, 3, 4]])) 
    dmat.set_base_margin(np.repeat(offset, 4)) 

    # train a poisson booster on the toy data 
    bst = xgb.train(
     params={"objective": "count:poisson"}, 
     dtrain=dmat, 
     num_boost_round=100000, 
     early_stopping_rounds=5, 
     evals=[(dmat, "train")], 
     verbose_eval=False) 

    # return fitted frequencies after reversing scaling 
    return bst.predict(dmat)/mult 

# test multipliers in the range [10**(-8), 10**1] 
# display fitted frequencies 
mults = [10**i for i in range(-8, 1)] 
## round to 1 decimal point to show the result approaches 2.5 
df = pd.DataFrame(np.round(np.vstack([get_preds(m) for m in mults]), 1)) 
df.index = mults 
df.columns = ["(0, 0)", "(0, 1)", "(1, 0)", "(1, 1)"] 
df 

# --- result --- 
#    (0, 0) (0, 1) (1, 0) (1, 1) 
#1.000000e-08  2.5  2.5  2.5  2.5 
#1.000000e-07  2.5  2.5  2.5  2.5 
#1.000000e-06  2.5  2.5  2.5  2.5 
#1.000000e-05  2.5  2.5  2.5  2.5 
#1.000000e-04  2.4  2.5  2.5  2.6 
#1.000000e-03  1.0  2.0  3.0  4.0 
#1.000000e-02  1.0  2.0  3.0  4.0 
#1.000000e-01  1.0  2.0  3.0  4.0 
#1.000000e+00  1.0  2.0  3.0  4.0