<h2 dir="auto">Description</h2>
<p dir="auto">When fitting a <code class="notranslate">LogisticRegression</code> on a sparse <code class="notranslate">csr</code> matrix with <code class="notranslate">dtype</code> set to <code class="notranslate">np.float32</code></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&lt;378019x13491 sparse matrix of type '&lt;class 'numpy.float32'&gt;'
    with 13405727 stored elements in Compressed Sparse Row format&gt;"><pre class="notranslate"><code class="notranslate">&lt;378019x13491 sparse matrix of type '&lt;class 'numpy.float32'&gt;'
    with 13405727 stored elements in Compressed Sparse Row format&gt;
</code></pre></div>
<p dir="auto">the call to <code class="notranslate">fit</code> fails, with the exception below, indicating we are trying to write to a read-only variable.</p>
<p dir="auto">I have read <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="68665973" data-permission-text="Title is private" data-url="https://github.com/scikit-learn/scikit-learn/issues/4597" data-hovercard-type="issue" data-hovercard-url="/scikit-learn/scikit-learn/issues/4597/hovercard" href="https://github.com/scikit-learn/scikit-learn/issues/4597">#4597</a>, and the issue seems similar here:</p>
<ul dir="auto">
<li><code class="notranslate">joblib</code> thinks data matrix is large enough to be exposed as a read-only memory-mapped file</li>
<li><code class="notranslate">logistic.py</code> runs the following check, which can lead to an implicit cast to <code class="notranslate">np.float64</code>:</li>
</ul>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="        if solver == 'lbfgs':
            _dtype = np.float64
        else:
            _dtype = [np.float64, np.float32]

        X, y = check_X_y(X, y, accept_sparse='csr', dtype=_dtype, order=&quot;C&quot;,
                         accept_large_sparse=solver != 'liblinear')"><pre class="notranslate">        <span class="pl-k">if</span> <span class="pl-s1">solver</span> <span class="pl-c1">==</span> <span class="pl-s">'lbfgs'</span>:
            <span class="pl-s1">_dtype</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-s1">float64</span>
        <span class="pl-k">else</span>:
            <span class="pl-s1">_dtype</span> <span class="pl-c1">=</span> [<span class="pl-s1">np</span>.<span class="pl-s1">float64</span>, <span class="pl-s1">np</span>.<span class="pl-s1">float32</span>]

        <span class="pl-v">X</span>, <span class="pl-s1">y</span> <span class="pl-c1">=</span> <span class="pl-en">check_X_y</span>(<span class="pl-v">X</span>, <span class="pl-s1">y</span>, <span class="pl-s1">accept_sparse</span><span class="pl-c1">=</span><span class="pl-s">'csr'</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s1">_dtype</span>, <span class="pl-s1">order</span><span class="pl-c1">=</span><span class="pl-s">"C"</span>,
                         <span class="pl-s1">accept_large_sparse</span><span class="pl-c1">=</span><span class="pl-s1">solver</span> <span class="pl-c1">!=</span> <span class="pl-s">'liblinear'</span>)</pre></div>
<p dir="auto">Here, <code class="notranslate">check_X_y</code> tries to convert <code class="notranslate">X</code> to <code class="notranslate">np.float64</code> which apparently cannot be done.</p>
<p dir="auto">Solutions appear to be either:</p>
<ul dir="auto">
<li>Pass in a matrix with <code class="notranslate">np.float64</code> type</li>
<li>Use a different solver than <code class="notranslate">lbfgs</code></li>
</ul>
<p dir="auto">which I guess is acceptable. I am not sure if <code class="notranslate">check_X_y</code> could also do the type conversion without having to write X (this seems to be done as part of sorting)&gt;</p>
<p dir="auto">The logistic regression API and documentation could also be improved to be more user-friendly:</p>
<ul dir="auto">
<li>
<p dir="auto">The documentation for <code class="notranslate">LogisticRegression</code> does not mention that <code class="notranslate">lbfgs</code> only supports <code class="notranslate">np.float64</code>. I think using <code class="notranslate">np.float32</code> is a relatively common use case to limit memory usage, but here, even when memory mapping is not used, it silently leads to a copy with a different type being made.</p>
</li>
<li>
<p dir="auto">Should <code class="notranslate">check_X_y</code> check whether <code class="notranslate">X</code> is read-only before attempting to do a type conversion? This could fail with a clearer exception, if we are not able to do the copy without touching the original matrix.</p>
</li>
</ul>
<h4 dir="auto">Code</h4>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from sklearn.model_selection import GridSearchCV, GroupKFold, StratifiedKFold
from sklearn.metrics import accuracy_score, balanced_accuracy_score, make_scorer
from sklearn.linear_model import LogisticRegression

parameters = {&quot;C&quot;: np.logspace(-4, 1, 6), &quot;penalty&quot;: [&quot;l2&quot;], &quot;max_iter&quot;: [800]}

clf = LogisticRegression(verbose=3, class_weight=&quot;balanced&quot;)
cv = StratifiedKFold(3)
grid_cv = GridSearchCV(
    clf,
    parameters,
    refit=False,
    cv=cv,
    scoring=make_scorer(balanced_accuracy_score),
    n_jobs=20,
)

clf_ovr = OneVsRestClassifier(grid_cv, n_jobs=20)
clf_ovr.fit(X_np32, y)"><pre class="notranslate"><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-v">GridSearchCV</span>, <span class="pl-v">GroupKFold</span>, <span class="pl-v">StratifiedKFold</span>
<span class="pl-k">from</span> <span class="pl-s1">sklearn</span>.<span class="pl-s1">metrics</span> <span class="pl-k">import</span> <span class="pl-s1">accuracy_score</span>, <span class="pl-s1">balanced_accuracy_score</span>, <span class="pl-s1">make_scorer</span>
<span class="pl-k">from</span> <span class="pl-s1">sklearn</span>.<span class="pl-s1">linear_model</span> <span class="pl-k">import</span> <span class="pl-v">LogisticRegression</span>

<span class="pl-s1">parameters</span> <span class="pl-c1">=</span> {<span class="pl-s">"C"</span>: <span class="pl-s1">np</span>.<span class="pl-en">logspace</span>(<span class="pl-c1">-</span><span class="pl-c1">4</span>, <span class="pl-c1">1</span>, <span class="pl-c1">6</span>), <span class="pl-s">"penalty"</span>: [<span class="pl-s">"l2"</span>], <span class="pl-s">"max_iter"</span>: [<span class="pl-c1">800</span>]}

<span class="pl-s1">clf</span> <span class="pl-c1">=</span> <span class="pl-v">LogisticRegression</span>(<span class="pl-s1">verbose</span><span class="pl-c1">=</span><span class="pl-c1">3</span>, <span class="pl-s1">class_weight</span><span class="pl-c1">=</span><span class="pl-s">"balanced"</span>)
<span class="pl-s1">cv</span> <span class="pl-c1">=</span> <span class="pl-v">StratifiedKFold</span>(<span class="pl-c1">3</span>)
<span class="pl-s1">grid_cv</span> <span class="pl-c1">=</span> <span class="pl-v">GridSearchCV</span>(
    <span class="pl-s1">clf</span>,
    <span class="pl-s1">parameters</span>,
    <span class="pl-s1">refit</span><span class="pl-c1">=</span><span class="pl-c1">False</span>,
    <span class="pl-s1">cv</span><span class="pl-c1">=</span><span class="pl-s1">cv</span>,
    <span class="pl-s1">scoring</span><span class="pl-c1">=</span><span class="pl-en">make_scorer</span>(<span class="pl-s1">balanced_accuracy_score</span>),
    <span class="pl-s1">n_jobs</span><span class="pl-c1">=</span><span class="pl-c1">20</span>,
)

<span class="pl-s1">clf_ovr</span> <span class="pl-c1">=</span> <span class="pl-v">OneVsRestClassifier</span>(<span class="pl-s1">grid_cv</span>, <span class="pl-s1">n_jobs</span><span class="pl-c1">=</span><span class="pl-c1">20</span>)
<span class="pl-s1">clf_ovr</span>.<span class="pl-en">fit</span>(<span class="pl-v">X_np32</span>, <span class="pl-s1">y</span>)</pre></div>
<h4 dir="auto">Expected Results</h4>
<p dir="auto">More user-friendly exception/warning</p>
<h4 dir="auto">Actual Results</h4>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Traceback (most recent call last):
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/joblib/externals/loky/process_executor.py&quot;, line 418, in _process_worker
    r = call_item()
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/joblib/externals/loky/process_executor.py&quot;, line 272, in __call__
    return self.fn(*self.args, **self.kwargs)
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/joblib/_parallel_backends.py&quot;, line 600, in __call__
    return self.func(*args, **kwargs)
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/joblib/parallel.py&quot;, line 256, in __call__
    for func, args, kwargs in self.items]
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/joblib/parallel.py&quot;, line 256, in &lt;listcomp&gt;
    for func, args, kwargs in self.items]
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/sklearn/multiclass.py&quot;, line 80, in _fit_binary
    estimator.fit(X, y)
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/sklearn/model_selection/_search.py&quot;, line 715, in fit
    self.best_estimator_.fit(X, y, **fit_params)
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/sklearn/linear_model/logistic.py&quot;, line 1532, in fit
    accept_large_sparse=solver != 'liblinear')
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/sklearn/utils/validation.py&quot;, line 719, in check_X_y
    estimator=estimator)
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/sklearn/utils/validation.py&quot;, line 486, in check_array
    accept_large_sparse=accept_large_sparse)
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/sklearn/utils/validation.py&quot;, line 309, in _ensure_sparse_format
    spmatrix = spmatrix.astype(dtype)
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/scipy/sparse/data.py&quot;, line 71, in astype
    self._deduped_data().astype(dtype, casting=casting, copy=copy),
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/scipy/sparse/data.py&quot;, line 34, in _deduped_data
    self.sum_duplicates()
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/scipy/sparse/compressed.py&quot;, line 1013, in sum_duplicates
    self.sort_indices()
  File &quot;/opt/venv/python3/lib/python3.6/site-packages/scipy/sparse/compressed.py&quot;, line 1059, in sort_indices
    self.indices, self.data)
ValueError: UPDATEIFCOPY base is read-only"><pre class="notranslate"><code class="notranslate">Traceback (most recent call last):
  File "/opt/venv/python3/lib/python3.6/site-packages/joblib/externals/loky/process_executor.py", line 418, in _process_worker
    r = call_item()
  File "/opt/venv/python3/lib/python3.6/site-packages/joblib/externals/loky/process_executor.py", line 272, in __call__
    return self.fn(*self.args, **self.kwargs)
  File "/opt/venv/python3/lib/python3.6/site-packages/joblib/_parallel_backends.py", line 600, in __call__
    return self.func(*args, **kwargs)
  File "/opt/venv/python3/lib/python3.6/site-packages/joblib/parallel.py", line 256, in __call__
    for func, args, kwargs in self.items]
  File "/opt/venv/python3/lib/python3.6/site-packages/joblib/parallel.py", line 256, in &lt;listcomp&gt;
    for func, args, kwargs in self.items]
  File "/opt/venv/python3/lib/python3.6/site-packages/sklearn/multiclass.py", line 80, in _fit_binary
    estimator.fit(X, y)
  File "/opt/venv/python3/lib/python3.6/site-packages/sklearn/model_selection/_search.py", line 715, in fit
    self.best_estimator_.fit(X, y, **fit_params)
  File "/opt/venv/python3/lib/python3.6/site-packages/sklearn/linear_model/logistic.py", line 1532, in fit
    accept_large_sparse=solver != 'liblinear')
  File "/opt/venv/python3/lib/python3.6/site-packages/sklearn/utils/validation.py", line 719, in check_X_y
    estimator=estimator)
  File "/opt/venv/python3/lib/python3.6/site-packages/sklearn/utils/validation.py", line 486, in check_array
    accept_large_sparse=accept_large_sparse)
  File "/opt/venv/python3/lib/python3.6/site-packages/sklearn/utils/validation.py", line 309, in _ensure_sparse_format
    spmatrix = spmatrix.astype(dtype)
  File "/opt/venv/python3/lib/python3.6/site-packages/scipy/sparse/data.py", line 71, in astype
    self._deduped_data().astype(dtype, casting=casting, copy=copy),
  File "/opt/venv/python3/lib/python3.6/site-packages/scipy/sparse/data.py", line 34, in _deduped_data
    self.sum_duplicates()
  File "/opt/venv/python3/lib/python3.6/site-packages/scipy/sparse/compressed.py", line 1013, in sum_duplicates
    self.sort_indices()
  File "/opt/venv/python3/lib/python3.6/site-packages/scipy/sparse/compressed.py", line 1059, in sort_indices
    self.indices, self.data)
ValueError: UPDATEIFCOPY base is read-only
</code></pre></div>
<h4 dir="auto">Versions</h4>
<p dir="auto">ystem:<br>
python: 3.6.1 |Continuum Analytics, Inc.| (default, May 11 2017, 13:09:58)  [GCC 4.4.7 20120313 (Red Hat 4.4.7-1)]<br>
executable: /opt/venv/python3/bin/python<br>
machine: Linux-4.14.146-93.123.amzn1.x86_64-x86_64-with-glibc2.2.5</p>
<p dir="auto">Python deps:<br>
pip: 19.3.1<br>
setuptools: 41.4.0<br>
sklearn: 0.21.3<br>
numpy: 1.13.1<br>
scipy: 1.1.0<br>
Cython: 0.26.1<br>
pandas: 0.23.4</p>
<p dir="auto">To reproduce:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import classification_report
from sklearn.multiclass import OneVsRestClassifier

from sklearn.pipeline import Pipeline
from sklearn.svm import SVC, LinearSVC
from sklearn.datasets import fetch_20newsgroups

data_train = fetch_20newsgroups(subset='train')
data_test = fetch_20newsgroups(subset='test')




clf=OneVsRestClassifier(estimator=SVC(),n_jobs=-1)  ##Error when calling fit
#clf=OneVsRestClassifier(estimator=SVC(),n_jobs=1) ##NO Error if set to 1



pipeLine=Pipeline([('tfidf',TfidfVectorizer(min_df=10)),
    ('clf',clf)])

trainx=data_train.data
trainy=data_train.target
evalx=data_test.data
evaly=data_test.target
pipeLine.fit(trainx,trainy)

predictValue=pipeLine.predict(evalx)

print classification_report(evaly,predictValue)"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">sklearn</span>.<span class="pl-s1">feature_extraction</span>.<span class="pl-s1">text</span> <span class="pl-k">import</span> <span class="pl-v">TfidfVectorizer</span>
<span class="pl-k">from</span> <span class="pl-s1">sklearn</span>.<span class="pl-s1">metrics</span> <span class="pl-k">import</span> <span class="pl-s1">classification_report</span>
<span class="pl-k">from</span> <span class="pl-s1">sklearn</span>.<span class="pl-s1">multiclass</span> <span class="pl-k">import</span> <span class="pl-v">OneVsRestClassifier</span>

<span class="pl-k">from</span> <span class="pl-s1">sklearn</span>.<span class="pl-s1">pipeline</span> <span class="pl-k">import</span> <span class="pl-v">Pipeline</span>
<span class="pl-k">from</span> <span class="pl-s1">sklearn</span>.<span class="pl-s1">svm</span> <span class="pl-k">import</span> <span class="pl-v">SVC</span>, <span class="pl-v">LinearSVC</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">fetch_20newsgroups</span>

<span class="pl-s1">data_train</span> <span class="pl-c1">=</span> <span class="pl-en">fetch_20newsgroups</span>(<span class="pl-s1">subset</span><span class="pl-c1">=</span><span class="pl-s">'train'</span>)
<span class="pl-s1">data_test</span> <span class="pl-c1">=</span> <span class="pl-en">fetch_20newsgroups</span>(<span class="pl-s1">subset</span><span class="pl-c1">=</span><span class="pl-s">'test'</span>)




<span class="pl-s1">clf</span><span class="pl-c1">=</span><span class="pl-v">OneVsRestClassifier</span>(<span class="pl-s1">estimator</span><span class="pl-c1">=</span><span class="pl-v">SVC</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-c">##Error when calling fit</span>
<span class="pl-c">#clf=OneVsRestClassifier(estimator=SVC(),n_jobs=1) ##NO Error if set to 1</span>



<span class="pl-s1">pipeLine</span><span class="pl-c1">=</span><span class="pl-v">Pipeline</span>([(<span class="pl-s">'tfidf'</span>,<span class="pl-v">TfidfVectorizer</span>(<span class="pl-s1">min_df</span><span class="pl-c1">=</span><span class="pl-c1">10</span>)),
    (<span class="pl-s">'clf'</span>,<span class="pl-s1">clf</span>)])

<span class="pl-s1">trainx</span><span class="pl-c1">=</span><span class="pl-s1">data_train</span>.<span class="pl-s1">data</span>
<span class="pl-s1">trainy</span><span class="pl-c1">=</span><span class="pl-s1">data_train</span>.<span class="pl-s1">target</span>
<span class="pl-s1">evalx</span><span class="pl-c1">=</span><span class="pl-s1">data_test</span>.<span class="pl-s1">data</span>
<span class="pl-s1">evaly</span><span class="pl-c1">=</span><span class="pl-s1">data_test</span>.<span class="pl-s1">target</span>
<span class="pl-s1">pipeLine</span>.<span class="pl-en">fit</span>(<span class="pl-s1">trainx</span>,<span class="pl-s1">trainy</span>)

<span class="pl-s1">predictValue</span><span class="pl-c1">=</span><span class="pl-s1">pipeLine</span>.<span class="pl-en">predict</span>(<span class="pl-s1">evalx</span>)

<span class="pl-k">print</span> <span class="pl-en">classification_report</span>(<span class="pl-s1">evaly</span>,<span class="pl-s1">predictValue</span>)</pre></div>
<p dir="auto">Output:</p>
<p dir="auto">ValueError: UPDATEIFCOPY base is read-only</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Linux-4.2.0-19-generic-x86_64-with-Ubuntu-15.10-wily
('Python', '2.7.10 (default, Oct 14 2015, 16:09:02) \n[GCC 5.2.1 20151010]')
('NumPy', '1.10.4')
('SciPy', '0.17.0')
('Scikit-Learn', '0.18.dev0')"><pre class="notranslate"><code class="notranslate">Linux-4.2.0-19-generic-x86_64-with-Ubuntu-15.10-wily
('Python', '2.7.10 (default, Oct 14 2015, 16:09:02) \n[GCC 5.2.1 20151010]')
('NumPy', '1.10.4')
('SciPy', '0.17.0')
('Scikit-Learn', '0.18.dev0')
</code></pre></div>