dask / dask/dask-ml

LogisticRegression's predict_proba(X) returns (n,) instead of (n,2) for binary class

Open
#386 7 comments 1 reaction 0 assignees View on GitHub
Dominant language
Python
Stars
951
Forks
262
PR merge metrics
No merged PRs in 30d

Description

Just like [sklearn's precit_proba(X)](http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html#sklearn.linear_model.LogisticRegression.predict_proba), [Dask's documentation](https://ml.dask.org/modules/generated/dask_ml.linear_model.LogisticRegression.html#dask_ml.linear_model.LogisticRegression.predict_proba) says it returns an "array-like, shape = [n_samples, n_classes]".
However, it returns an "array-like, shape = [n_samples, 1]", for a binary classifier.
E.g. run this:
```
import numpy as np
from sklearn.linear_model import LogisticRegression
from dask_ml.linear_model import LogisticRegression as DaskLogit

# Data
X = np.random.rand(200,20)
y = np.random.rand(200).round(0) # random binary labels

# Dask
lrdask = DaskLogit()
lrdask.fit(X, y)
print("Logit Reg 'predict_proba' shape Dask\t", lrdask.predict_proba(X).shape)

# SKLearn
lrsklr = LogisticRegression()
lrsklr.fit(X, y)
print("Logit Reg 'predict_proba' shape SKLearn\t", lrsklr.predict_proba(X).shape)
```

Of course, no information is lost, but this *does* break stuff when used in other code.
E.g. in GridSearchCV's scorer I get:
```
C:\ProgramData\Anaconda3\lib\site-packages\sklearn\metrics\scorer.py in __call__(self, clf, X, y, sample_weight)
184
185 if y_type == "binary":
--> 186 y_pred = y_pred[:, 1]
187 elif isinstance(y_pred, list):
188 y_pred = np.vstack([p[:, -1] for p in y_pred]).T

IndexError: too many indices for array
```

predict_proba(X)'s return value is indeed implemented differently in sklearn and dask-ml:
[sklearn](https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/linear_model/base.py):
```
def _predict_proba_lr(self, X):
...
return np.vstack([1 - prob, prob]).T
```

[dask-ml](https://github.com/dask/dask-ml/blob/master/dask_ml/linear_model/glm.py):
```
def predict_proba(self, X):
...
return sigmoid(dot(X_, self._coef))
```

Is this intentional and would changing this break code that currently expects Dask to return (n,) and *not* (n,2)? Or is this an oversight, and should it return (n,2) as per documentation?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.