Talip7/scikit-learn-issues-multilabel huggingface dataset:
forced threading joblib backend in pairwise_distances

### Describe the bug

The function pairwise_distances in pairwise.py comes with a forced "threading" joblib backend.
This slows down the system if one uses a python callable as distance function, due to the global interpreter lock - in practice there is no parallelism.

Is there a reason for this choice?

In my opition the backend should be different if the metric is a custom callable, or at least, the user should be able to force a different one.

### Steps/Code to Reproduce

Invoke pairwise_distance with a callable as metric and n_jobs > 1

```
def myCustomDistanceWrittenInPython(p0, p1):
    return myhexoticmetric

with parallel_backend('loky', n_jobs=n_jobs):
    pairwise_distances(X, metric=myCustomDistanceWrittenInPython)
```

### Expected Results

joblib creates n_jobs processes and runs parallel

### Actual Results

the global interpreter lock of python prevents a correct parllelization

### Versions

```shell
sklearn main branch after commit e947074f63c6602ae15cd57b1fa4f6658040cff7 of Fri Nov 11 05:10:31 2022 -0500
```

COMMENT:
For a user provided metric, I agree that using `loky` is a better default.

My concern is if the user provided metric actually releases the gil, then using `threading` is preferred. If we change to loky immediately, then it can lead to a performance regression.

I think a quick improvement is to add `with parallel_backend("loky")` to the documentation for `metric`, so readers can learn about changing the backend.

Labels: Bug, module:metrics
forced threading joblib backend in pairwise_distances

### Describe the bug

The function pairwise_distances in pairwise.py comes with a forced "threading" joblib backend.
This slows down the system if one uses a python callable as distance function, due to the global interpreter lock - in practice there is no parallelism.

Is there a reason for this choice?

In my opition the backend should be different if the metric is a custom callable, or at least, the user should be able to force a different one.

### Steps/Code to Reproduce

Invoke pairwise_distance with a callable as metric and n_jobs > 1

```
def myCustomDistanceWrittenInPython(p0, p1):
    return myhexoticmetric

with parallel_backend('loky', n_jobs=n_jobs):
    pairwise_distances(X, metric=myCustomDistanceWrittenInPython)
```

### Expected Results

joblib creates n_jobs processes and runs parallel

### Actual Results

the global interpreter lock of python prevents a correct parllelization

### Versions

```shell
sklearn main branch after commit e947074f63c6602ae15cd57b1fa4f6658040cff7 of Fri Nov 11 05:10:31 2022 -0500
```

COMMENT:
Thank @thomasjpfan for your reply.
I'm no expert of joblib, but I see that since version 0.12 one can indicate a "preferred" backend when the Parallel instance is created. Which would be overridden by a call to parallel_backend. Maybe this could be a solution?

Labels: Bug, module:metrics
forced threading joblib backend in pairwise_distances

### Describe the bug

The function pairwise_distances in pairwise.py comes with a forced "threading" joblib backend.
This slows down the system if one uses a python callable as distance function, due to the global interpreter lock - in practice there is no parallelism.

Is there a reason for this choice?

In my opition the backend should be different if the metric is a custom callable, or at least, the user should be able to force a different one.

### Steps/Code to Reproduce

Invoke pairwise_distance with a callable as metric and n_jobs > 1

```
def myCustomDistanceWrittenInPython(p0, p1):
    return myhexoticmetric

with parallel_backend('loky', n_jobs=n_jobs):
    pairwise_distances(X, metric=myCustomDistanceWrittenInPython)
```

### Expected Results

joblib creates n_jobs processes and runs parallel

### Actual Results

the global interpreter lock of python prevents a correct parllelization

### Versions

```shell
sklearn main branch after commit e947074f63c6602ae15cd57b1fa4f6658040cff7 of Fri Nov 11 05:10:31 2022 -0500
```

COMMENT:
The trick that I suggested yesterday does not work.

Yesterday I suggested to substitute line 1578 in file pairwise.py
`Parallel(backend="threading", n_jobs=n_jobs)(`
with
`Parallel(n_jobs=n_jobs, prefer="threads")(`
but just doing so give different results if n_jobs=1 or n_jobs>1 if the beckend is not threads.

That's because the distance matrix is filled separately in each process and not shared.

Here an example:
```
import numpy as np
from joblib import parallel_backend
from sklearn.metrics.pairwise import pairwise_distances

def metric(x0, x1):
    return np.abs(x0-x1)

x = np.arange(0, 100, .1)
x = np.expand_dims(x, 1)

n_jobs = 6
#with parallel_backend('threading', n_jobs=n_jobs):
with parallel_backend('loky', n_jobs=n_jobs):
    Dpar = pairwise_distances(x, metric=metric, n_jobs=n_jobs)

Dser = pairwise_distances(x, metric=metric)
   
assert np.all(Dser == Dpar)
```

Labels: Bug, module:metrics
forced threading joblib backend in pairwise_distances

### Describe the bug

The function pairwise_distances in pairwise.py comes with a forced "threading" joblib backend.
This slows down the system if one uses a python callable as distance function, due to the global interpreter lock - in practice there is no parallelism.

Is there a reason for this choice?

In my opition the backend should be different if the metric is a custom callable, or at least, the user should be able to force a different one.

### Steps/Code to Reproduce

Invoke pairwise_distance with a callable as metric and n_jobs > 1

```
def myCustomDistanceWrittenInPython(p0, p1):
    return myhexoticmetric

with parallel_backend('loky', n_jobs=n_jobs):
    pairwise_distances(X, metric=myCustomDistanceWrittenInPython)
```

### Expected Results

joblib creates n_jobs processes and runs parallel

### Actual Results

the global interpreter lock of python prevents a correct parllelization

### Versions

```shell
sklearn main branch after commit e947074f63c6602ae15cd57b1fa4f6658040cff7 of Fri Nov 11 05:10:31 2022 -0500
```

COMMENT:
The fix above seems to work properly with both threads and processes. I also included a related part in the regression tests (file sklearn/metrics/tests/test_pairwise.py).

Labels: Bug, module:metrics
'OrdinalEncoder' object has no attribute '_missing_indices'

### Describe the bug

I have fitted an OrdinalEncoder and saved the `categories_` attribute as a numpy array. I want to load these categories in, in a new module so I do not have to re-fit the model. When trying to transform the prefitted model, I get this Attribute Error. I see that `_missing_indicies` is not initialized in `__init__`, but instead is created in the `fit` function, which I intend to never call.

### Steps/Code to Reproduce

```
from sklearn.preprocessing import OrdinalEncoder
import pandas as pd
import numpy as np

df = pd.DataFrame({'cat': ['Low', 'Low', 'Med', 'High', 'Med']})

encoder = OrdinalEncoder()
encoder.fit(df)

np.save('cats.npy', encoder.categories_)

new_encoder = OrdinalEncoder()
new_encoder.categories_ = np.load('cats.npy', allow_pickle=True)

new_encoder.transform(df)
```

The error with trace is below

```
AttributeError                            Traceback (most recent call last)
<ipython-input-9-78339e8cfce1> in <module>
----> 1 new_encoder.transform(df)

/opt/conda/lib/python3.7/site-packages/sklearn/preprocessing/_encoders.py in transform(self, X)
    933         X_trans = X_int.astype(self.dtype, copy=False)
    934 
--> 935         for cat_idx, missing_idx in self._missing_indices.items():
    936             X_missing_mask = X_int[:, cat_idx] == missing_idx
    937             X_trans[X_missing_mask, cat_idx] = np.nan

AttributeError: 'OrdinalEncoder' object has no attribute '_missing_indices'
```

### Expected Results

No error is thrown. Data is fitted with 
```
array([[1.],
       [1.],
       [2.],
       [0.],
       [2.]])
```

### Actual Results

```
AttributeError                            Traceback (most recent call last)
<ipython-input-9-78339e8cfce1> in <module>
----> 1 new_encoder.transform(df)

/opt/conda/lib/python3.7/site-packages/sklearn/preprocessing/_encoders.py in transform(self, X)
    933         X_trans = X_int.astype(self.dtype, copy=False)
    934 
--> 935         for cat_idx, missing_idx in self._missing_indices.items():
    936             X_missing_mask = X_int[:, cat_idx] == missing_idx
    937             X_trans[X_missing_mask, cat_idx] = np.nan

AttributeError: 'OrdinalEncoder' object has no attribute '_missing_indices'
```

### Versions

```shell
System:
    python: 3.7.4 (default, Aug 13 2019, 20:35:49)  [GCC 7.3.0]
executable: /opt/conda/bin/python
   machine: Linux-3.10.0-1160.76.1.el7.x86_64-x86_64-with-debian-buster-sid

Python dependencies:
          pip: 20.0.2
   setuptools: 39.1.0
      sklearn: 1.0.2
        numpy: 1.19.5
        scipy: 1.6.0
       Cython: 0.29.21
       pandas: 0.25.1
   matplotlib: 3.3.3
       joblib: 1.0.0
threadpoolctl: 2.1.0

Built with OpenMP: True
```

COMMENT:
Closing since this is not a bug.

Labels: Bug, Needs Triage
Extend `validate_params` to validate arguments which are type parameters (i.e. classes, built-in types, generic types, etc.)

### Describe the workflow you want to enable
Main idea is to add `issublcass` option somewhere in `_param_validation`. Working on #24862 makes me realize we need an `issubclass` checker to simplify parameter validation. For example when the parameter (argument to function) is itself a type parameter. 

Currently, if a function takes in a `Type` as a parameter, such as `dtype=int` or `return_as=sparse.coo_matrix`, then the type validator for this  

if the accepted contained DTypes are numeric, currently one would have to find out all the numeric dtypes and write a rather clunky:

```python
"dtype": [
   type(float),
   type(int),
   type(complex),
   type(...)
],
"return_as" : [type(np.ndarray), type(scipy.sparse.spmatrix)]
```
Since `type(Numeric)` (or other abstract classes from `numbers`) won't work., i.e. `isinstance(int, type(Numeric))` is `False`, one would have to enumerate all numeric like class types. This also won't work with `numpy dtypes` or third party dtypes.  

The workflow I want to enable is the following when writing the validators:

```python
"dtype": [
   SubClass(Number),
],
"return_as" : [SubClass(ArrayLike)]
```
The former will pass all manner of good generic conditions without being overly (or impossibly) wordy. 


### Describe your proposed solution

add the following to `_param_validation` (but also see the alternative, maybe both should be in?):

```python
class SubClass(_Condition):
   def __init__(self, type):
      self.type = type

   def is_satisfied_by(self, val):
       return issubclass(val, self.type)

```

also add the required code to `make_constraint` in the same script.


### Describe alternatives you've considered, if relevant

A possible alternative is to make a generic class which leverages the Typing methods made available by third parties like numpy. Something like

```python
class TypeChecker(_Constraint):
   def __init__(self, type_checker):
      self.type_checker = type_checker

   def is_satisfied_by(self, val):
       return type_checker(val)
  # or:
   def is_satisfied_by_alt(self, val):
       return isinstance(val, TypeChecker)

   # or:
   def is_satisfied_by_alt2(self, val):
       return issubclass(val, TypeChecker)
```
where `type_checker` could be `numpy.typing.DTypeLike`
or a custom `TypeGuard`


### Additional context

This will help write better validators.

COMMENT:
You can see my message here: https://github.com/scikit-learn/scikit-learn/pull/24886/files#r1019518476

Up to now, we are delegating. If we find the need, later on, we can reconsider.

Labels: New Feature, Needs Triage
Extend `validate_params` to validate arguments which are type parameters (i.e. classes, built-in types, generic types, etc.)

### Describe the workflow you want to enable
Main idea is to add `issublcass` option somewhere in `_param_validation`. Working on #24862 makes me realize we need an `issubclass` checker to simplify parameter validation. For example when the parameter (argument to function) is itself a type parameter. 

Currently, if a function takes in a `Type` as a parameter, such as `dtype=int` or `return_as=sparse.coo_matrix`, then the type validator for this  

if the accepted contained DTypes are numeric, currently one would have to find out all the numeric dtypes and write a rather clunky:

```python
"dtype": [
   type(float),
   type(int),
   type(complex),
   type(...)
],
"return_as" : [type(np.ndarray), type(scipy.sparse.spmatrix)]
```
Since `type(Numeric)` (or other abstract classes from `numbers`) won't work., i.e. `isinstance(int, type(Numeric))` is `False`, one would have to enumerate all numeric like class types. This also won't work with `numpy dtypes` or third party dtypes.  

The workflow I want to enable is the following when writing the validators:

```python
"dtype": [
   SubClass(Number),
],
"return_as" : [SubClass(ArrayLike)]
```
The former will pass all manner of good generic conditions without being overly (or impossibly) wordy. 


### Describe your proposed solution

add the following to `_param_validation` (but also see the alternative, maybe both should be in?):

```python
class SubClass(_Condition):
   def __init__(self, type):
      self.type = type

   def is_satisfied_by(self, val):
       return issubclass(val, self.type)

```

also add the required code to `make_constraint` in the same script.


### Describe alternatives you've considered, if relevant

A possible alternative is to make a generic class which leverages the Typing methods made available by third parties like numpy. Something like

```python
class TypeChecker(_Constraint):
   def __init__(self, type_checker):
      self.type_checker = type_checker

   def is_satisfied_by(self, val):
       return type_checker(val)
  # or:
   def is_satisfied_by_alt(self, val):
       return isinstance(val, TypeChecker)

   # or:
   def is_satisfied_by_alt2(self, val):
       return issubclass(val, TypeChecker)
```
where `type_checker` could be `numpy.typing.DTypeLike`
or a custom `TypeGuard`


### Additional context

This will help write better validators.

COMMENT:
Thanks @glemaitre, I understand delegating for the dtype case, I've fixed the PRs.

Maybe we could add to the docstring of `validate_params` using `[type(blah)]` instead of `issubclass`.

However, I believe there is still a use to have `issubclass` based validation for flexibility in validating arguments which are (non-numpy/pandas) type parameters. But I can re-open if I run into it..

Labels: New Feature, Needs Triage
Building interactive demos for examples

### Describe the issue linked to the documentation

This is not an issue but rather a good-to-have feature for documentation and this issue is more of a discussion.

It would be nice to have links to or embedding interactive demos made with Gradio inside documentation. 
I've built two apps that you might see how it looks like:
- Anomaly detection: https://huggingface.co/spaces/scikit-learn/anomaly-detection
- Classification: https://huggingface.co/spaces/scikit-learn/classification

We can have below demo (but more official version 😅) embedded in your documentation.
<img width="1155" alt="Ekran Resmi 2022-11-10 15 11 41" src="https://user-images.githubusercontent.com/53175384/201114005-5fd13d40-990a-412d-abe6-fdd01d0f87d9.png">

The current workflow for users is to download python code or run binder. This reduces amount of work in this workflow too!
If you think embedded demos is a bit overkill what we could do is to create these demos and host them on [Spaces](https://huggingface.co/spaces) and put link to Space instead (like it is with Keras examples or kornia examples, you can see them [here](https://huggingface.co/keras-io) and [here](https://huggingface.co/kornia), they're linked from their tutorials on both [Keras.io/examples](https://keras.io/examples/) and Kornia docs) We will also host the Spaces in better hardware (8 vCPU 32 GiB RAM) to make sure it's always running and all good. ✨ 

You can see how it's implemented in Kornia for rst docs [here](https://raw.githubusercontent.com/kornia/kornia/627ebcaaab1547c362908fc9ad9a68c6316c5993/docs/source/filters.rst). It looks like [this](https://kornia.readthedocs.io/en/latest/filters.html#interactive-demo) inside Kornia docs.

<img width="1353" alt="Ekran Resmi 2022-11-10 15 15 08" src="https://user-images.githubusercontent.com/53175384/201114865-d44b6af5-0b85-44d1-b490-0450d8ea05aa.png">

As for Keras, we just put a redirection link inside docs since their document generation is more layered.  
<img width="1309" alt="Ekran Resmi 2022-11-10 15 09 57" src="https://user-images.githubusercontent.com/53175384/201113694-a4c5b804-dce4-4e72-b23e-bbe449bbc150.png">

We definitely want to reduce the core maintainers' workflow so what would be cool is that we (team at [Gradio](https://gradio.app/) & community)  will be developing the demos and maintaining them through GitHub actions such that they will not break every time there's a breaking change in sklearn (this happens rarely, though 🙂)

Hoping to see how we could collaborate!

COMMENT:
@adrinjalali I think you're wrong in changing the title. Embedding demo itself is not about Hugging Face Hub but about having interactive demos within sklearn docs. (see Kornia docs for example)

I updated the issue for better clarity 🙂

Labels: Documentation, RFC
Building interactive demos for examples

### Describe the issue linked to the documentation

This is not an issue but rather a good-to-have feature for documentation and this issue is more of a discussion.

It would be nice to have links to or embedding interactive demos made with Gradio inside documentation. 
I've built two apps that you might see how it looks like:
- Anomaly detection: https://huggingface.co/spaces/scikit-learn/anomaly-detection
- Classification: https://huggingface.co/spaces/scikit-learn/classification

We can have below demo (but more official version 😅) embedded in your documentation.
<img width="1155" alt="Ekran Resmi 2022-11-10 15 11 41" src="https://user-images.githubusercontent.com/53175384/201114005-5fd13d40-990a-412d-abe6-fdd01d0f87d9.png">

The current workflow for users is to download python code or run binder. This reduces amount of work in this workflow too!
If you think embedded demos is a bit overkill what we could do is to create these demos and host them on [Spaces](https://huggingface.co/spaces) and put link to Space instead (like it is with Keras examples or kornia examples, you can see them [here](https://huggingface.co/keras-io) and [here](https://huggingface.co/kornia), they're linked from their tutorials on both [Keras.io/examples](https://keras.io/examples/) and Kornia docs) We will also host the Spaces in better hardware (8 vCPU 32 GiB RAM) to make sure it's always running and all good. ✨ 

You can see how it's implemented in Kornia for rst docs [here](https://raw.githubusercontent.com/kornia/kornia/627ebcaaab1547c362908fc9ad9a68c6316c5993/docs/source/filters.rst). It looks like [this](https://kornia.readthedocs.io/en/latest/filters.html#interactive-demo) inside Kornia docs.

<img width="1353" alt="Ekran Resmi 2022-11-10 15 15 08" src="https://user-images.githubusercontent.com/53175384/201114865-d44b6af5-0b85-44d1-b490-0450d8ea05aa.png">

As for Keras, we just put a redirection link inside docs since their document generation is more layered.  
<img width="1309" alt="Ekran Resmi 2022-11-10 15 09 57" src="https://user-images.githubusercontent.com/53175384/201113694-a4c5b804-dce4-4e72-b23e-bbe449bbc150.png">

We definitely want to reduce the core maintainers' workflow so what would be cool is that we (team at [Gradio](https://gradio.app/) & community)  will be developing the demos and maintaining them through GitHub actions such that they will not break every time there's a breaking change in sklearn (this happens rarely, though 🙂)

Hoping to see how we could collaborate!

COMMENT:
@merveenoyan where do these demos run? Don't they then run on a Space? If yes, then it's a Hub related issue. We don't have the compute backend to actually run the demos on our servers (which we don't have much of). We could think of having them as pyodide though.

What I'm saying: who's maintaining the demo code, and who's maintaining the compute servers/infra. If the answer to those questions are people at Hugging Face, then it's a Hub thing.

Labels: Documentation, RFC
Building interactive demos for examples

### Describe the issue linked to the documentation

This is not an issue but rather a good-to-have feature for documentation and this issue is more of a discussion.

It would be nice to have links to or embedding interactive demos made with Gradio inside documentation. 
I've built two apps that you might see how it looks like:
- Anomaly detection: https://huggingface.co/spaces/scikit-learn/anomaly-detection
- Classification: https://huggingface.co/spaces/scikit-learn/classification

We can have below demo (but more official version 😅) embedded in your documentation.
<img width="1155" alt="Ekran Resmi 2022-11-10 15 11 41" src="https://user-images.githubusercontent.com/53175384/201114005-5fd13d40-990a-412d-abe6-fdd01d0f87d9.png">

The current workflow for users is to download python code or run binder. This reduces amount of work in this workflow too!
If you think embedded demos is a bit overkill what we could do is to create these demos and host them on [Spaces](https://huggingface.co/spaces) and put link to Space instead (like it is with Keras examples or kornia examples, you can see them [here](https://huggingface.co/keras-io) and [here](https://huggingface.co/kornia), they're linked from their tutorials on both [Keras.io/examples](https://keras.io/examples/) and Kornia docs) We will also host the Spaces in better hardware (8 vCPU 32 GiB RAM) to make sure it's always running and all good. ✨ 

You can see how it's implemented in Kornia for rst docs [here](https://raw.githubusercontent.com/kornia/kornia/627ebcaaab1547c362908fc9ad9a68c6316c5993/docs/source/filters.rst). It looks like [this](https://kornia.readthedocs.io/en/latest/filters.html#interactive-demo) inside Kornia docs.

<img width="1353" alt="Ekran Resmi 2022-11-10 15 15 08" src="https://user-images.githubusercontent.com/53175384/201114865-d44b6af5-0b85-44d1-b490-0450d8ea05aa.png">

As for Keras, we just put a redirection link inside docs since their document generation is more layered.  
<img width="1309" alt="Ekran Resmi 2022-11-10 15 09 57" src="https://user-images.githubusercontent.com/53175384/201113694-a4c5b804-dce4-4e72-b23e-bbe449bbc150.png">

We definitely want to reduce the core maintainers' workflow so what would be cool is that we (team at [Gradio](https://gradio.app/) & community)  will be developing the demos and maintaining them through GitHub actions such that they will not break every time there's a breaking change in sklearn (this happens rarely, though 🙂)

Hoping to see how we could collaborate!

COMMENT:
@adrinjalali I see, but this is something done for sklearn docs in the end and that is what I mean 🙂

Wanted to ask @ArturoAmorQ their opinion 🙂

Labels: Documentation, RFC