Repository: scikit-learn/scikit-learn
Pull request: Updated error message to remove deprecated n_values
<!--
Thanks for contributing a pull request! Please ensure you have taken a look at
the contribution guidelines: https://github.com/scikit-learn/scikit-learn/blob/master/CONTRIBUTING.md#pull-request-checklist
-->

#### Reference Issues/PRs
<!--
Example: Fixes #1234. See also #3456.
Please use keywords (e.g., Fixes) to create link to the issues or pull requests
you resolved, so that they will automatically be closed when your pull request
is merged. See https://github.com/blog/1506-closing-issues-via-pull-requests
-->
Fixes #13446

#### What does this implement/fix? Explain your changes.
Updated error message to use categories in place of the deprecated n_values

#### Any other comments?


<!--
Please be aware that we are a loose team of volunteers so patience is
necessary; assistance handling other issues is very welcome. We value
all user contributions, no matter how minor they are. If we are slow to
review, either the pull request needs some benchmarking, tinkering,
convincing, etc. or more likely the reviewers are simply busy. In either
case, we ask for your understanding during the review process.
For more information, see our FAQ on this topic:
http://scikit-learn.org/dev/faq.html#why-is-my-pull-request-not-getting-any-attention.

Thanks for contributing!
-->


Problem statement:
Confusing error message in OrdinalEncoder when passing single list of categories
Small example:

```py
In [38]: from sklearn.preprocessing import OrdinalEncoder 

In [39]: X = np.array([['L', 'M', 'S', 'M', 'L']], dtype=object).T

In [40]: ohe = OrdinalEncoder(categories=['S', 'M', 'L'])

In [41]: ohe.fit(X)
...
ValueError: Shape mismatch: if n_values is an array, it has to be of shape (n_features,).
```

The error message is still using the old `n_values`, which makes it very confusing.

(another issue is that we might be able to actually detect this case)

#### Versions
```
System:
    python: 3.7.1 | packaged by conda-forge | (default, Feb 18 2019, 01:42:00)  [GCC 7.3.0]
executable: /home/joris/miniconda3/bin/python
   machine: Linux-4.4.0-142-generic-x86_64-with-debian-stretch-sid

BLAS:
    macros: HAVE_CBLAS=None
  lib_dirs: /home/joris/miniconda3/lib
cblas_libs: openblas, openblas

Python deps:
       pip: 19.0.2
setuptools: 40.8.0
   sklearn: 0.20.2
     numpy: 1.16.1
     scipy: 1.2.1
    Cython: None
    pandas: 0.23.4
```

Hints from issue discussion:
Just out of curiosity. First timer here! Are you looking for a fix just on writing up an error message similar to the more recently updated error messages in other parts of the same file? 
Hi, I'd like to take this one up. This is my first time contributing. Will make the change and submit a PR.

Commit message: Added test for error message on OrdinalEncoder

Patch to review:
diff --git a/sklearn/preprocessing/_encoders.py b/sklearn/preprocessing/_encoders.py
index 6c3df0f22178e..7c4b056c9b855 100644
--- a/sklearn/preprocessing/_encoders.py
+++ b/sklearn/preprocessing/_encoders.py
@@ -81,7 +81,7 @@ def _fit(self, X, handle_unknown='error'):
 
         if self._categories != 'auto':
             if len(self._categories) != n_features:
-                raise ValueError("Shape mismatch: if n_values is an array,"
+                raise ValueError("Shape mismatch: if categories is an array,"
                                  " it has to be of shape (n_features,).")
 
         self.categories_ = []
@@ -571,7 +571,7 @@ def _legacy_fit_transform(self, X):
                                 " 'auto', int or array of ints, got %r"
                                 % type(self._n_values))
             if n_values.ndim < 1 or n_values.shape[0] != X.shape[1]:
-                raise ValueError("Shape mismatch: if n_values is an array,"
+                raise ValueError("Shape mismatch: if categories is an array,"
                                  " it has to be of shape (n_features,).")
 
         self._n_values_ = n_values
diff --git a/sklearn/preprocessing/tests/test_encoders.py b/sklearn/preprocessing/tests/test_encoders.py
index 850efe22b5d11..573d5576bbde1 100644
--- a/sklearn/preprocessing/tests/test_encoders.py
+++ b/sklearn/preprocessing/tests/test_encoders.py
@@ -692,6 +692,13 @@ def test_ordinal_encoder_raise_missing(X):
     with pytest.raises(ValueError, match="Input contains NaN"):
         ohe.transform(X)
 
+def test_ordinal_encoder_raise_categories_shape():
+
+    X = np.array([['Low', 'Medium', 'High', 'Medium', 'Low']], dtype=object).T
+    cats = ['Low','Medium', 'High']
+    enc = OrdinalEncoder(categories=cats)
+    with pytest.raises(ValueError, match="Shape mismatch: if categories is an array,"):
+        enc.fit(X)
 
 def test_encoder_dtypes():
     # check that dtypes are preserved when determining categories


Code review comments:
diff_hunk: @@ -571,7 +571,7 @@ def _legacy_fit_transform(self, X):
                                 " 'auto', int or array of ints, got %r"
                                 % type(self._n_values))
             if n_values.ndim < 1 or n_values.shape[0] != X.shape[1]:
-                raise ValueError("Shape mismatch: if n_values is an array,"
+                raise ValueError("Shape mismatch: if categories is an array,"
path: sklearn/preprocessing/_encoders.py
text: @user1:
I don't think the change is applicable here. This condition applies only when the user is working with the deprecated parameter.

@author:
will revert the change for the _legacy_fit_transform.