<p dir="auto">Hi, I am a graduate student utilizing sklean for some data work.<br>
And when I handle the data using the Decision Trees library, I found there are some inconvenience:<br>
Neither the classificationTree nor the regressionTree supports categorical feature. <strong>That means the Decision trees model can only accept continuous feature</strong>.<br>
For example, the categorical feature like app name such as google, facebook can not be input into the model, because they can not be transformed to continuous value properly. And there don not exist a corresponding algorithm to divide discrete feature in the Decision Trees library.<br>
However, <strong>the CART algorithm itself has considered the use of categorical feature</strong>. So I have made some modification of Decision Trees library based on CART and apply the new model on my own work.  And it proves that the support for categorical feature indeed improves the performance, which is very necessary for decision tree, I think.<br>
I am very willing to contribute this to sklearn community, but I`m new to this community, not so familiar about the procedure.<br>
Could u give some suggestions or comments on this new feature? Or has anyone already processed on this feature? Thank you so much.</p>
<h3 dir="auto">Describe the bug</h3>
<p dir="auto">When calling <code class="notranslate">cross_val_score</code> with a sparse data matrix <code class="notranslate">X</code> and a <code class="notranslate">RandomForestClassifier</code> with <code class="notranslate">n_jobs=-1</code>, there is a weird interaction with joblib and memmapping that makes the buffer from <code class="notranslate">X</code> read-only, breaking the cython code for the tree construction but it is weird as it only appears with the <code class="notranslate">cross_validate</code> function, and not when calling the classifier alone, while <code class="notranslate">n_jobs=1</code> for the  cross val function so joblib should not enter the play here...</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 scipy.sparse import csr_matrix
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score

X, y = make_classification(10000, n_features=200)
X = csr_matrix(X, copy=True)

clf = RandomForestClassifier(n_jobs=-1)

cross_val_score(clf, X, y)"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">scipy</span>.<span class="pl-s1">sparse</span> <span class="pl-k">import</span> <span class="pl-s1">csr_matrix</span>
<span class="pl-k">from</span> <span class="pl-s1">sklearn</span>.<span class="pl-s1">datasets</span> <span class="pl-k">import</span> <span class="pl-s1">make_classification</span>
<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">RandomForestClassifier</span>
<span class="pl-k">from</span> <span class="pl-s1">sklearn</span>.<span class="pl-s1">model_selection</span> <span class="pl-k">import</span> <span class="pl-s1">cross_val_score</span>

<span class="pl-v">X</span>, <span class="pl-s1">y</span> <span class="pl-c1">=</span> <span class="pl-en">make_classification</span>(<span class="pl-c1">10000</span>, <span class="pl-s1">n_features</span><span class="pl-c1">=</span><span class="pl-c1">200</span>)
<span class="pl-v">X</span> <span class="pl-c1">=</span> <span class="pl-en">csr_matrix</span>(<span class="pl-v">X</span>, <span class="pl-s1">copy</span><span class="pl-c1">=</span><span class="pl-c1">True</span>)

<span class="pl-s1">clf</span> <span class="pl-c1">=</span> <span class="pl-v">RandomForestClassifier</span>(<span class="pl-s1">n_jobs</span><span class="pl-c1">=</span><span class="pl-c1">-</span><span class="pl-c1">1</span>)

<span class="pl-en">cross_val_score</span>(<span class="pl-s1">clf</span>, <span class="pl-v">X</span>, <span class="pl-s1">y</span>)</pre></div>
<h3 dir="auto">Expected Results</h3>
<p dir="auto">Working code</p>
<h3 dir="auto">Actual Results</h3>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="ValueError: 
All the 5 fits failed.
It is very likely that your model is misconfigured.
You can try to debug the error by setting error_score='raise'.

Below are more details about the failures:
--------------------------------------------------------------------------------
5 fits failed with the following error:
joblib.externals.loky.process_executor._RemoteTraceback: 
&quot;&quot;&quot;
Traceback (most recent call last):
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/externals/loky/process_executor.py&quot;, line 428, in _process_worker
    r = call_item()
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/externals/loky/process_executor.py&quot;, line 275, in __call__
    return self.fn(*self.args, **self.kwargs)
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/_parallel_backends.py&quot;, line 620, in __call__
    return self.func(*args, **kwargs)
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/parallel.py&quot;, line 288, in __call__
    return [func(*args, **kwargs)
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/parallel.py&quot;, line 288, in &lt;listcomp&gt;
    return [func(*args, **kwargs)
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/sklearn/utils/fixes.py&quot;, line 117, in __call__
    return self.function(*args, **kwargs)
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/sklearn/ensemble/_forest.py&quot;, line 185, in _parallel_build_trees
    tree.fit(X, y, sample_weight=curr_sample_weight, check_input=False)
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/sklearn/tree/_classes.py&quot;, line 889, in fit
    super().fit(
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/sklearn/tree/_classes.py&quot;, line 379, in fit
    builder.build(self.tree_, X, y, sample_weight)
  File &quot;sklearn/tree/_tree.pyx&quot;, line 147, in sklearn.tree._tree.DepthFirstTreeBuilder.build
  File &quot;sklearn/tree/_tree.pyx&quot;, line 173, in sklearn.tree._tree.DepthFirstTreeBuilder.build
  File &quot;sklearn/tree/_splitter.pyx&quot;, line 789, in sklearn.tree._splitter.BaseSparseSplitter.init
  File &quot;stringsource&quot;, line 660, in View.MemoryView.memoryview_cwrapper
  File &quot;stringsource&quot;, line 350, in View.MemoryView.memoryview.__cinit__
ValueError: buffer source array is read-only
&quot;&quot;&quot;

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/sklearn/model_selection/_validation.py&quot;, line 686, in _fit_and_score
    estimator.fit(X_train, y_train, **fit_params)
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/sklearn/ensemble/_forest.py&quot;, line 474, in fit
    trees = Parallel(
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/parallel.py&quot;, line 1098, in __call__
    self.retrieve()
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/parallel.py&quot;, line 975, in retrieve
    self._output.extend(job.get(timeout=self.timeout))
  File &quot;/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/_parallel_backends.py&quot;, line 567, in wrap_future_result
    return future.result(timeout=timeout)
  File &quot;/home/temp/.local/miniconda/lib/python3.10/concurrent/futures/_base.py&quot;, line 458, in result
    return self.__get_result()
  File &quot;/home/temp/.local/miniconda/lib/python3.10/concurrent/futures/_base.py&quot;, line 403, in __get_result
    raise self._exception
ValueError: buffer source array is read-only"><pre class="notranslate"><code class="notranslate">ValueError: 
All the 5 fits failed.
It is very likely that your model is misconfigured.
You can try to debug the error by setting error_score='raise'.

Below are more details about the failures:
--------------------------------------------------------------------------------
5 fits failed with the following error:
joblib.externals.loky.process_executor._RemoteTraceback: 
"""
Traceback (most recent call last):
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/externals/loky/process_executor.py", line 428, in _process_worker
    r = call_item()
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/externals/loky/process_executor.py", line 275, in __call__
    return self.fn(*self.args, **self.kwargs)
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/_parallel_backends.py", line 620, in __call__
    return self.func(*args, **kwargs)
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/parallel.py", line 288, in __call__
    return [func(*args, **kwargs)
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/parallel.py", line 288, in &lt;listcomp&gt;
    return [func(*args, **kwargs)
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/sklearn/utils/fixes.py", line 117, in __call__
    return self.function(*args, **kwargs)
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/sklearn/ensemble/_forest.py", line 185, in _parallel_build_trees
    tree.fit(X, y, sample_weight=curr_sample_weight, check_input=False)
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/sklearn/tree/_classes.py", line 889, in fit
    super().fit(
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/sklearn/tree/_classes.py", line 379, in fit
    builder.build(self.tree_, X, y, sample_weight)
  File "sklearn/tree/_tree.pyx", line 147, in sklearn.tree._tree.DepthFirstTreeBuilder.build
  File "sklearn/tree/_tree.pyx", line 173, in sklearn.tree._tree.DepthFirstTreeBuilder.build
  File "sklearn/tree/_splitter.pyx", line 789, in sklearn.tree._splitter.BaseSparseSplitter.init
  File "stringsource", line 660, in View.MemoryView.memoryview_cwrapper
  File "stringsource", line 350, in View.MemoryView.memoryview.__cinit__
ValueError: buffer source array is read-only
"""

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/sklearn/model_selection/_validation.py", line 686, in _fit_and_score
    estimator.fit(X_train, y_train, **fit_params)
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/sklearn/ensemble/_forest.py", line 474, in fit
    trees = Parallel(
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/parallel.py", line 1098, in __call__
    self.retrieve()
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/parallel.py", line 975, in retrieve
    self._output.extend(job.get(timeout=self.timeout))
  File "/home/temp/.local/miniconda/lib/python3.10/site-packages/joblib/_parallel_backends.py", line 567, in wrap_future_result
    return future.result(timeout=timeout)
  File "/home/temp/.local/miniconda/lib/python3.10/concurrent/futures/_base.py", line 458, in result
    return self.__get_result()
  File "/home/temp/.local/miniconda/lib/python3.10/concurrent/futures/_base.py", line 403, in __get_result
    raise self._exception
ValueError: buffer source array is read-only
</code></pre></div>
<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 | packaged by conda-forge | (main, Aug 22 2022, 20:36:39) [GCC 10.4.0]
executable: /home/temp/.local/miniconda/bin/python3.10
   machine: Linux-5.14.0-1054-oem-x86_64-with-glibc2.31

Python dependencies:
      sklearn: 1.2.0
          pip: 22.3
   setuptools: 65.5.0
        numpy: 1.23.5
        scipy: 1.9.3
       Cython: 0.29.32
       pandas: 1.5.2
   matplotlib: 3.6.2
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: mkl
         prefix: libmkl_rt
       filepath: /home/temp/.local/miniconda/lib/libmkl_rt.so.2
        version: 2022.1-Product
threading_layer: intel
    num_threads: 4

       user_api: openmp
   internal_api: openmp
         prefix: libomp
       filepath: /home/temp/.local/miniconda/lib/libomp.so
        version: None
    num_threads: 8"><pre class="notranslate">System:
    python: 3.10.6 <span class="pl-k">|</span> packaged by conda-forge <span class="pl-k">|</span> (main, Aug 22 2022, 20:36:39) [GCC 10.4.0]
executable: /home/temp/.local/miniconda/bin/python3.10
   machine: Linux-5.14.0-1054-oem-x86_64-with-glibc2.31

Python dependencies:
      sklearn: 1.2.0
          pip: 22.3
   setuptools: 65.5.0
        numpy: 1.23.5
        scipy: 1.9.3
       Cython: 0.29.32
       pandas: 1.5.2
   matplotlib: 3.6.2
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: mkl
         prefix: libmkl_rt
       filepath: /home/temp/.local/miniconda/lib/libmkl_rt.so.2
        version: 2022.1-Product
threading_layer: intel
    num_threads: 4

       user_api: openmp
   internal_api: openmp
         prefix: libomp
       filepath: /home/temp/.local/miniconda/lib/libomp.so
        version: None
    num_threads: 8</pre></div>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content=""><pre class="notranslate"><code class="notranslate"></code></pre></div>