<h3 dir="auto">Describe the bug</h3>
<p dir="auto">If you fit an <code class="notranslate">IsolationForest</code> using a <code class="notranslate">pd.DataFrame</code> it generates a warning</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="X does not have valid feature names, but IsolationForest was fitted with feature names"><pre class="notranslate"><span class="pl-v">X</span> <span class="pl-s1">does</span> <span class="pl-c1">not</span> <span class="pl-s1">have</span> <span class="pl-s1">valid</span> <span class="pl-s1">feature</span> <span class="pl-s1">names</span>, <span class="pl-s1">but</span> <span class="pl-v">IsolationForest</span> <span class="pl-s1">was</span> <span class="pl-s1">fitted</span> <span class="pl-s1">with</span> <span class="pl-s1">feature</span> <span class="pl-s1">names</span></pre></div>
<p dir="auto">This only seems to occur if you supply a non-default value (i.e. not "auto") for the <code class="notranslate">contamination</code> parameter. This warning is unexpected as a) X does have valid feature names and b) it is being raised by the <code class="notranslate">fit()</code> method but in general is supposed to indicate that predict has been called with ie. an ndarray but the model was fitted using a dataframe.</p>
<p dir="auto">The reason is most likely when you pass contamination != "auto" the estimator essentially calls predict on the training data in order to determine the <code class="notranslate">offset_</code> parameters:</p>
<p dir="auto"></p><div class="Box Box--condensed my-2">
  <div class="Box-header f6">
    <p class="mb-0 text-bold">
      <a href="https://github.com/scikit-learn/scikit-learn/blob/9aaed498795f68e5956ea762fef9c440ca9eb239/sklearn/ensemble/_iforest.py#L337">scikit-learn/sklearn/ensemble/_iforest.py</a>
    </p>
    <p class="mb-0 color-fg-muted">
         Line 337
      in
      <a data-pjax="true" class="commit-tease-sha" href="/scikit-learn/scikit-learn/commit/9aaed498795f68e5956ea762fef9c440ca9eb239">9aaed49</a>
    </p>
  </div>
  <div itemprop="text" class="Box-body p-0 blob-wrapper blob-wrapper-embedded data">
    <table class="highlight tab-size mb-0 js-file-line-container" data-tab-size="8" data-paste-markdown-skip="">

        <tbody><tr class="border-0">
          <td id="L337" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="337"></td>
          <td id="LC337" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> <span class="pl-s1">self</span>.<span class="pl-s1">offset_</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">percentile</span>(<span class="pl-s1">self</span>.<span class="pl-en">score_samples</span>(<span class="pl-v">X</span>), <span class="pl-c1">100.0</span> <span class="pl-c1">*</span> <span class="pl-s1">self</span>.<span class="pl-s1">contamination</span>) </td>
        </tr>
    </tbody></table>
  </div>
</div>
<p></p>
<h3 dir="auto">Steps/Code to Reproduce</h3>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from sklearn.ensemble import IsolationForest
import pandas as pd

X = pd.DataFrame({&quot;a&quot;: [-1.1, 0.3, 0.5, 100]})
clf = IsolationForest(random_state=0, contamination=0.05).fit(X)"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">sklearn</span>.<span class="pl-s1">ensemble</span> <span class="pl-k">import</span> <span class="pl-v">IsolationForest</span>
<span class="pl-k">import</span> <span class="pl-s1">pandas</span> <span class="pl-k">as</span> <span class="pl-s1">pd</span>

<span class="pl-v">X</span> <span class="pl-c1">=</span> <span class="pl-s1">pd</span>.<span class="pl-v">DataFrame</span>({<span class="pl-s">"a"</span>: [<span class="pl-c1">-</span><span class="pl-c1">1.1</span>, <span class="pl-c1">0.3</span>, <span class="pl-c1">0.5</span>, <span class="pl-c1">100</span>]})
<span class="pl-s1">clf</span> <span class="pl-c1">=</span> <span class="pl-v">IsolationForest</span>(<span class="pl-s1">random_state</span><span class="pl-c1">=</span><span class="pl-c1">0</span>, <span class="pl-s1">contamination</span><span class="pl-c1">=</span><span class="pl-c1">0.05</span>).<span class="pl-en">fit</span>(<span class="pl-v">X</span>)</pre></div>
<h3 dir="auto">Expected Results</h3>
<p dir="auto">Does not raise "X does not have valid feature names, but IsolationForest was fitted with feature names"</p>
<h3 dir="auto">Actual Results</h3>
<p dir="auto">raises "X does not have valid feature names, but IsolationForest was fitted with feature names"</p>
<h3 dir="auto">Versions</h3>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="System:
    python: 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0]
executable: /home/david/dev/warpspeed-timeseries/.venv/bin/python
   machine: Linux-5.15.0-67-generic-x86_64-with-glibc2.35

Python dependencies:
      sklearn: 1.2.1
          pip: 23.0.1
   setuptools: 67.1.0
        numpy: 1.23.5
        scipy: 1.10.0
       Cython: 0.29.33
       pandas: 1.5.3
   matplotlib: 3.7.1
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /home/david/dev/warpspeed-timeseries/.venv/lib/python3.10/site-packages/numpy.libs/libopenblas64_p-r0-742d56dc.3.20.so
        version: 0.3.20
threading_layer: pthreads
   architecture: Haswell
    num_threads: 12

       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /home/david/dev/warpspeed-timeseries/.venv/lib/python3.10/site-packages/scipy.libs/libopenblasp-r0-41284840.3.18.so
        version: 0.3.18
threading_layer: pthreads
   architecture: Haswell
    num_threads: 12

       user_api: openmp
   internal_api: openmp
         prefix: libgomp
       filepath: /home/david/dev/warpspeed-timeseries/.venv/lib/python3.10/site-packages/scikit_learn.libs/libgomp-a34b3233.so.1.0.0
        version: None
    num_threads: 12"><pre class="notranslate">System:
    python: 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0]
executable: /home/david/dev/warpspeed-timeseries/.venv/bin/python
   machine: Linux-5.15.0-67-generic-x86_64-with-glibc2.35

Python dependencies:
      sklearn: 1.2.1
          pip: 23.0.1
   setuptools: 67.1.0
        numpy: 1.23.5
        scipy: 1.10.0
       Cython: 0.29.33
       pandas: 1.5.3
   matplotlib: 3.7.1
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /home/david/dev/warpspeed-timeseries/.venv/lib/python3.10/site-packages/numpy.libs/libopenblas64_p-r0-742d56dc.3.20.so
        version: 0.3.20
threading_layer: pthreads
   architecture: Haswell
    num_threads: 12

       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /home/david/dev/warpspeed-timeseries/.venv/lib/python3.10/site-packages/scipy.libs/libopenblasp-r0-41284840.3.18.so
        version: 0.3.18
threading_layer: pthreads
   architecture: Haswell
    num_threads: 12

       user_api: openmp
   internal_api: openmp
         prefix: libgomp
       filepath: /home/david/dev/warpspeed-timeseries/.venv/lib/python3.10/site-packages/scikit_learn.libs/libgomp-a34b3233.so.1.0.0
        version: None
    num_threads: 12</pre></div>
<p dir="auto">This post is to follow up a discussion on the mailing list with <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/pprett/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/pprett">@pprett</a> .</p>
<p dir="auto"><strong>This issue is not about a general monitoring API, just about the ability to add trees</strong><br>
The motivation for this feature request is monitoring (see below), but <em>let's avoid discussion of a general monitoring API here</em> (which should be the same API as used for monitoring other estimators).  It might take a long time for us to all agree on a monitoring API, but in the meantime if someone implements a way to add more trees (or use a <code class="notranslate">warm_start</code> option in the fit method), then we'll have made some progress in the right direction.</p>
<p dir="auto"><strong>Motivation: monitoring and early termination</strong><br>
Two of the most important parameters for the boosting estimators are learn_rate and n_estimators.  In  <a href="http://cran.r-project.org/web/packages/gbm/vignettes/gbm.pdf" rel="nofollow">this document</a>, Greg Ridgeway provides advice for settings these:</p>
<blockquote>
<p dir="auto">My rule of thumb is to set shrinkage as small as possible while still being able to fit the model in a reasonable amount of time and storage. I usually aim for 3,000 to 10,000 iterations with shrinkage rates between 0.01 and 0.001.</p>
</blockquote>
<p dir="auto">Often such a large number of iterations will be an overkill, and this will be clear if one monitors the accuracy on the out-of-bag estimate.  In this situation (which is perhaps the usual situation), one should set the learning rate to be small, add some number of trees, check to see if the accuracy is still improving, and if so, keep adding trees.  This requires the ability to add more estimators (perhaps using a warm_start option in the fit function, or a more() method).</p>
<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/pprett/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/pprett">@pprett</a> mentioned</p>
<blockquote>
<p dir="auto">The original pull-request supported an additional parameter <code class="notranslate">monitor</code> which was called after each iteration using the current state of the model and allowed proper early stopping, however, we removed the parameter because we could not agree on the API.</p>
</blockquote>