<p dir="auto">It would be nice if the HistGradientBoostingClassifier works takes the same input as the GradientBoostingClassifier.<br>
The following script on sklearn 0.23.0 raises:<br>
<code class="notranslate">TypeError: A sparse matrix was passed, but dense data is required. Use X.toarray() to convert to a dense numpy array.</code></p>
<p dir="auto">Switching to GradientBoostingClassifier makes the script work.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="from sklearn.experimental import enable_hist_gradient_boosting  # noqa
from sklearn.ensemble import HistGradientBoostingClassifier, GradientBoostingClassifier
import numpy as np
from scipy import sparse
arr = np.array([[0, 1, 0, 1],
               [1, 0, 1, 0]])
labels = [0, 1]
clf = HistGradientBoostingClassifier()
# clf = GradientBoostingClassifier()

arr = sparse.csr_matrix(arr)
clf.fit(arr,labels)"><pre class="notranslate"><code class="notranslate">from sklearn.experimental import enable_hist_gradient_boosting  # noqa
from sklearn.ensemble import HistGradientBoostingClassifier, GradientBoostingClassifier
import numpy as np
from scipy import sparse
arr = np.array([[0, 1, 0, 1],
               [1, 0, 1, 0]])
labels = [0, 1]
clf = HistGradientBoostingClassifier()
# clf = GradientBoostingClassifier()

arr = sparse.csr_matrix(arr)
clf.fit(arr,labels)
</code></pre></div>
<p dir="auto">This is a placeholder issue for sparse matrices support in the Histogram-based GBDT estimators.</p>
<p dir="auto">I guess <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="518378130" data-permission-text="Title is private" data-url="https://github.com/scikit-learn/scikit-learn/issues/15550" data-hovercard-type="issue" data-hovercard-url="/scikit-learn/scikit-learn/issues/15550/hovercard" href="https://github.com/scikit-learn/scikit-learn/issues/15550">#15550</a> should be tackled first.</p>
<hr>
<p dir="auto">Below are my thoughts and potential plan on the matter, feel free to ignore.</p>
<p dir="auto">Binning:</p>
<p dir="auto">We need a utility to compute quantiles on sparse data, and we need to map a float sparse matrix to a binned sparse matrix given those quantiles.  To avoid having to densify <code class="notranslate">X_binned</code>, the zeros in <code class="notranslate">X</code> should be mapped to bin 0, even if that's not their actual bin (called <code class="notranslate">actual_bin_zeros</code>). I guess that means all the bins in <code class="notranslate">range(0, actual_bin_zeros)</code> have an offset of 1, i.e. now they're actually mapped to <code class="notranslate">range(1, actual_bin_zeros + 1)</code>.  Though maybe we can avoid the offset by distinguishing between explicit and implicit zeros, IDK.</p>
<p dir="auto">Histograms:</p>
<p dir="auto">We need a histogram builder that can handle sparse data <em>and</em> that is aware of <code class="notranslate">actual_bin_zeros</code> in some way. We can't just build the histograms as usual, because that would mean that the zeros would be treated as the lowest value in the splitter.  In the histogram, the zeros should be placed in their proper bin, i.e. at index <code class="notranslate">actual_bin_zeros</code>. This way, the splitter can be left unchanged. The offset of the bins in <code class="notranslate">range(1, actual_bin_zeros)</code> should also be canceled here.</p>
<p dir="auto">When building a histogram, we can focus only on the non-zeros entries. We already know the totals <code class="notranslate">sum_gradients</code>, <code class="notranslate">sum_hessians</code>, and <code class="notranslate">count</code> at any given node. So we can just go through the samples that have non-zero values and fill-in the histogram at their respective bins, and then set <code class="notranslate">hist[actual_bin_zeros]['grad'] = total_sum_gradients - hist[:]['grad'].sum()</code>.</p>