title: XGBoost - Poisson distribution with varying exposure / offset
body: <p>I am trying to use XGBoost to model claims frequency of data generated from unequal length exposure periods, but have been unable to get the model to treat the exposure correctly. I would normally do this by setting log(exposure) as an offset - are you able to do this in XGBoost?</p>
  
  <p>(A similar question was posted here: <a href="https://stackoverflow.com/questions/34896004/xgboost-offset-exposure">xgboost, offset exposure?</a>)</p>
  
  <p>To illustrate the issue, the R code below generates some data with the fields:</p>
  
  <ul>
  <li>x1, x2 - factors (either 0 or 1)</li>
  <li>exposure - length of policy period on observed data</li>
  <li>frequency - mean number of claims per unit exposure</li>
  <li>claims - number of observed claims ~Poisson(frequency*exposure)</li>
  </ul>
  
  <p>The goal is to predict frequency using x1 and x2 - the true model is: frequency = 2 if x1 = x2 = 1, frequency = 1 otherwise.</p>
  
  <p>Exposure can't be used to predict the frequency as it is not known at the outset of a policy. The only way we can use it is to say: expected number of claims = frequency * exposure.</p>
  
  <p>The code tries to predict this using XGBoost by:</p>
  
  <ol>
  <li>Setting exposure as a weight in the model matrix</li>
  <li>Setting log(exposure) as an offset</li>
  </ol>
  
  <p>Below these, I've shown how I would handle the situation for a tree (rpart) or gbm.</p>
  
  <pre><code>set.seed(1)
  size&lt;-10000
  d &lt;- data.frame(
    x1 = sample(c(0,1),size,replace=T,prob=c(0.5,0.5)),
    x2 = sample(c(0,1),size,replace=T,prob=c(0.5,0.5)),
    exposure = runif(size, 1, 10)*0.3
  )
  d$frequency &lt;- 2^(d$x1==1 &amp; d$x2==1)
  d$claims &lt;- rpois(size, lambda = d$frequency * d$exposure)
  
  #### Try to fit using XGBoost
  require(xgboost)
  param0 &lt;- list(
    "objective"  = "count:poisson"
    , "eval_metric" = "logloss"
    , "eta" = 1
    , "subsample" = 1
    , "colsample_bytree" = 1
    , "min_child_weight" = 1
    , "max_depth" = 2
  )
  
  ## 1 - set weight in xgb.Matrix
  
  xgtrain = xgb.DMatrix(as.matrix(d[,c("x1","x2")]), label = d$claims, weight = d$exposure)
  xgb = xgb.train(
    nrounds = 1
    , params = param0
    , data = xgtrain
  )
  
  d$XGB_P_1 &lt;- predict(xgb, xgtrain)
  
  ## 2 - set as offset in xgb.Matrix
  xgtrain.mf  &lt;- model.frame(as.formula("claims~x1+x2+offset(log(exposure))"),d)
  xgtrain.m  &lt;- model.matrix(attr(xgtrain.mf,"terms"),data = d)
  xgtrain  &lt;- xgb.DMatrix(xgtrain.m,label = d$claims)
  
  xgb = xgb.train(
    nrounds = 1
    , params = param0
    , data = xgtrain
  )
  
  d$XGB_P_2 &lt;- predict(model, xgtrain)
  
  #### Fit a tree
  require(rpart)
  d[,"tree_response"] &lt;- cbind(d$exposure,d$claims)
  tree &lt;- rpart(tree_response ~ x1 + x2,
                data = d,
                method = "poisson")
  
  d$Tree_F &lt;- predict(tree, newdata = d)
  
  #### Fit a GBM
  
  gbm &lt;- gbm(claims~x1+x2+offset(log(exposure)), 
             data = d,
             distribution = "poisson",
             n.trees = 1,
             shrinkage=1,
             interaction.depth=2,
             bag.fraction = 0.5)
  
  d$GBM_F &lt;- predict(gbm, newdata = d, n.trees = 1, type="response")
  </code></pre>