title: Why calling fit resets custom objective function in XGBClassifier?
body: <p>I have tried to setup XGBoost sklearn API <code>XGBClassifier</code> to use custom objective function (<code>brier</code>) according to the documentation:</p>
  
  <pre><code>    .. note::  Custom objective function
  
          A custom objective function can be provided for the ``objective``
          parameter. In this case, it should have the signature
          ``objective(y_true, y_pred) -&gt; grad, hess``:
  
          y_true: array_like of shape [n_samples]
              The target values
          y_pred: array_like of shape [n_samples]
              The predicted values
  
          grad: array_like of shape [n_samples]
              The value of the gradient for each sample point.
          hess: array_like of shape [n_samples]
              The value of the second derivative for each sample point
  </code></pre>
  
  <p>Here's my attempt:</p>
  
  <pre><code>import numpy as np
  from xgboost import XGBClassifier
  from sklearn.datasets import load_svmlight_file
  train_data = load_svmlight_file('~/agaricus.txt.train')
  X = train_data[0].toarray()
  y = train_data[1]
  
  def brier(y_true, y_pred):
      y_pred = 1.0 / (1.0 + np.exp(-y_pred))
      grad = 2 * y_pred * (y_true - y_pred) * (y_pred - 1)
      hess = 2 * y_pred ** (1 - y_pred) * (2 * y_pred * (y_true + 1) - y_true - 3 * y_pred ** 2)
      return grad, hess
  
  m = XGBClassifier(objective=brier, seed=42)
  </code></pre>
  
  <p>It seemingly results in correct object:</p>
  
  <pre><code>XGBClassifier(base_score=None, booster=None, colsample_bylevel=None,
                colsample_bynode=None, colsample_bytree=None, gamma=None,
                gpu_id=None, importance_type='gain', interaction_constraints=None,
                learning_rate=None, max_delta_step=None, max_depth=None,
                min_child_weight=None, missing=nan, monotone_constraints=None,
                n_estimators=100, n_jobs=None, num_parallel_tree=None,
                objective=&lt;function brier at 0x7fe7ac418290&gt;, random_state=None,
                reg_alpha=None, reg_lambda=None, scale_pos_weight=None, seed=42,
                subsample=None, tree_method=None, validate_parameters=False,
                verbosity=None)
  </code></pre>
  
  <p>However, calling <code>.fit</code> method seems to reset <code>m</code> object to default setup:</p>
  
  <pre><code>m.fit(X, y)
  m
  XGBClassifier(base_score=0.5, booster=None, colsample_bylevel=1,
                colsample_bynode=1, colsample_bytree=1, gamma=0, gpu_id=-1,
                importance_type='gain', interaction_constraints=None,
                learning_rate=0.300000012, max_delta_step=0, max_depth=6,
                min_child_weight=1, missing=nan, monotone_constraints=None,
                n_estimators=100, n_jobs=0, num_parallel_tree=1,
                objective='binary:logistic', random_state=42, reg_alpha=0,
                reg_lambda=1, scale_pos_weight=1, seed=42, subsample=1,
                tree_method=None, validate_parameters=False, verbosity=None)
  </code></pre>
  
  <p>with <code>objective='binary:logistic'</code>. I have noticed that while investigating why I am getting worse brier score when optimising directly for <code>brier</code> than when I use default <code>binary:logistic</code>, as described <a href="https://datascience.stackexchange.com/q/71823/88076">here</a>. </p>
  
  <p>So, how can I properly setup <code>XGBClassifier</code> to use my function <code>brier</code> as custom objective?</p>