Talip7/scikit-learn-issues-multilabel huggingface dataset:
Array API support with lazy evaluation

At the moment, our Array API integration can implicitly assume eager evaluation semantics.

Furthermore we did not test our code to see how it would behave with candidate Array API implementations with lazy evaluation semantics (e.g. dask, jax, ...).

The purpose of this issue is to track what would be needed to make our Array API estimator work with lazy evaluation.

I think we should first investigate where this breaks, then decide whether or not we would like to support lazy evaluation semantics in scikit-learn via the Array API support and if so open a meta-issue to add common test with an estimator tag and progressively fix the Array API estimators to deal with lazy evaluation.

Note that are particular point about lazy vs eager evaluation for Array API consuming libraries is being discussed here:

- https://github.com/data-apis/array-api/issues/642

COMMENT:
I think explaining to users that a `dask.array` array won't work and that they have to rewrite their code to use a `dask.array.array_api` array is difficult. I think this means I am also in support of the `array_api_compat` route.

Labels: RFC, Array API
Array API support with lazy evaluation

At the moment, our Array API integration can implicitly assume eager evaluation semantics.

Furthermore we did not test our code to see how it would behave with candidate Array API implementations with lazy evaluation semantics (e.g. dask, jax, ...).

The purpose of this issue is to track what would be needed to make our Array API estimator work with lazy evaluation.

I think we should first investigate where this breaks, then decide whether or not we would like to support lazy evaluation semantics in scikit-learn via the Array API support and if so open a meta-issue to add common test with an estimator tag and progressively fix the Array API estimators to deal with lazy evaluation.

Note that are particular point about lazy vs eager evaluation for Array API consuming libraries is being discussed here:

- https://github.com/data-apis/array-api/issues/642

COMMENT:
Which estimator depend on data dependent shapes?

Labels: RFC, Array API
Array API support with lazy evaluation

At the moment, our Array API integration can implicitly assume eager evaluation semantics.

Furthermore we did not test our code to see how it would behave with candidate Array API implementations with lazy evaluation semantics (e.g. dask, jax, ...).

The purpose of this issue is to track what would be needed to make our Array API estimator work with lazy evaluation.

I think we should first investigate where this breaks, then decide whether or not we would like to support lazy evaluation semantics in scikit-learn via the Array API support and if so open a meta-issue to add common test with an estimator tag and progressively fix the Array API estimators to deal with lazy evaluation.

Note that are particular point about lazy vs eager evaluation for Array API consuming libraries is being discussed here:

- https://github.com/data-apis/array-api/issues/642

COMMENT:
LDA does at the very least, there's a call to unique.

This was removed from #28588, since there's another dask bug that would prevent it from working.

Labels: RFC, Array API
Array API support with lazy evaluation

At the moment, our Array API integration can implicitly assume eager evaluation semantics.

Furthermore we did not test our code to see how it would behave with candidate Array API implementations with lazy evaluation semantics (e.g. dask, jax, ...).

The purpose of this issue is to track what would be needed to make our Array API estimator work with lazy evaluation.

I think we should first investigate where this breaks, then decide whether or not we would like to support lazy evaluation semantics in scikit-learn via the Array API support and if so open a meta-issue to add common test with an estimator tag and progressively fix the Array API estimators to deal with lazy evaluation.

Note that are particular point about lazy vs eager evaluation for Array API consuming libraries is being discussed here:

- https://github.com/data-apis/array-api/issues/642

COMMENT:
How does it result in silent correctness problems? Is it because dask uses nan instead of None?

Labels: RFC, Array API
Array API support with lazy evaluation

At the moment, our Array API integration can implicitly assume eager evaluation semantics.

Furthermore we did not test our code to see how it would behave with candidate Array API implementations with lazy evaluation semantics (e.g. dask, jax, ...).

The purpose of this issue is to track what would be needed to make our Array API estimator work with lazy evaluation.

I think we should first investigate where this breaks, then decide whether or not we would like to support lazy evaluation semantics in scikit-learn via the Array API support and if so open a meta-issue to add common test with an estimator tag and progressively fix the Array API estimators to deal with lazy evaluation.

Note that are particular point about lazy vs eager evaluation for Array API consuming libraries is being discussed here:

- https://github.com/data-apis/array-api/issues/642

COMMENT:
Yeah, e.g.

``return x.shape < 3``

or smth like that from ``is_multilabel``

Labels: RFC, Array API
Array API support with lazy evaluation

At the moment, our Array API integration can implicitly assume eager evaluation semantics.

Furthermore we did not test our code to see how it would behave with candidate Array API implementations with lazy evaluation semantics (e.g. dask, jax, ...).

The purpose of this issue is to track what would be needed to make our Array API estimator work with lazy evaluation.

I think we should first investigate where this breaks, then decide whether or not we would like to support lazy evaluation semantics in scikit-learn via the Array API support and if so open a meta-issue to add common test with an estimator tag and progressively fix the Array API estimators to deal with lazy evaluation.

Note that are particular point about lazy vs eager evaluation for Array API consuming libraries is being discussed here:

- https://github.com/data-apis/array-api/issues/642

COMMENT:
All classifiers use `xp.unique_*` methods to compute `self.classes_` and `self.n_classes_` which are data-dependent values. The latter is typically used to shape the fitted attribute (e.g. `coef_` for linear models) for downstream computation.

Labels: RFC, Array API
Array API support with lazy evaluation

At the moment, our Array API integration can implicitly assume eager evaluation semantics.

Furthermore we did not test our code to see how it would behave with candidate Array API implementations with lazy evaluation semantics (e.g. dask, jax, ...).

The purpose of this issue is to track what would be needed to make our Array API estimator work with lazy evaluation.

I think we should first investigate where this breaks, then decide whether or not we would like to support lazy evaluation semantics in scikit-learn via the Array API support and if so open a meta-issue to add common test with an estimator tag and progressively fix the Array API estimators to deal with lazy evaluation.

Note that are particular point about lazy vs eager evaluation for Array API consuming libraries is being discussed here:

- https://github.com/data-apis/array-api/issues/642

COMMENT:
> Calls compute if necessary on the array before returning a non-null shape.
> (Although compute is not part of the array API, array-api-compat can call the library specific version of compute for the lazy array implementations that it knows)

Note that dask also exposes an alternative to compute: `.persist` this triggers a compute but does not collect the result back as a numpy array in the driver program. Unfortunately, calling `persist` does not resolve the shape values.

Anyways, before make a decision, we should have a look at how other array api candidate libraries with lazy evaluation semantics behave on those patterns (shape of unique and masked assignment with a data dependent boolean mask). Here are libraries to investigate:

- pytorch expressions in a function decorated with `@torch.compile`
- jax
- tensorflow?
- maybe MLX from Apple.

Labels: RFC, Array API
Array API support with lazy evaluation

At the moment, our Array API integration can implicitly assume eager evaluation semantics.

Furthermore we did not test our code to see how it would behave with candidate Array API implementations with lazy evaluation semantics (e.g. dask, jax, ...).

The purpose of this issue is to track what would be needed to make our Array API estimator work with lazy evaluation.

I think we should first investigate where this breaks, then decide whether or not we would like to support lazy evaluation semantics in scikit-learn via the Array API support and if so open a meta-issue to add common test with an estimator tag and progressively fix the Array API estimators to deal with lazy evaluation.

Note that are particular point about lazy vs eager evaluation for Array API consuming libraries is being discussed here:

- https://github.com/data-apis/array-api/issues/642

COMMENT:
I just wanted to note that I have [a PoC lazy array API library](https://github.com/egraphs-good/egglog-python/blob/main/python/egglog/exp/array_api.py) building on top of [egglog](https://github.com/egraphs-good/egglog-python) that I have [made to work on the LDA example](https://egglog-python.readthedocs.io/latest/tutorials/sklearn.html). 

The technique I used is that whenever a real value is required, through an if statement on like `__bool__`, I will automatically materialize that value only. I have had to handle the isfinite and unique values special cases. You can see in the example that it is able to spit out the symbolic representation of the result, given some assumptions on the inputs, like their shapes, dtypes, whether their are finite, and their unique values.

Labels: RFC, Array API
Array API support with lazy evaluation

At the moment, our Array API integration can implicitly assume eager evaluation semantics.

Furthermore we did not test our code to see how it would behave with candidate Array API implementations with lazy evaluation semantics (e.g. dask, jax, ...).

The purpose of this issue is to track what would be needed to make our Array API estimator work with lazy evaluation.

I think we should first investigate where this breaks, then decide whether or not we would like to support lazy evaluation semantics in scikit-learn via the Array API support and if so open a meta-issue to add common test with an estimator tag and progressively fix the Array API estimators to deal with lazy evaluation.

Note that are particular point about lazy vs eager evaluation for Array API consuming libraries is being discussed here:

- https://github.com/data-apis/array-api/issues/642

COMMENT:
For the record, dask support in SciPy via array API is being deprioritized (at least in the short term):

- https://github.com/scipy/scipy/issues/24205

Support for lazy evaluated JAX expression is still being worked on, in particular via the `array-api-extra` package.

Labels: RFC, Array API
StandardScaler `mean_` is not None when `with_mean=False`

### Describe the bug

In the documentation, it is stated that

> **mean_**
ndarray of shape (n_features,) or None
The mean value for each feature in the training set. Equal to None when with_mean=False.

But the actual mean values are returned for `mean_` attribute.





### Steps/Code to Reproduce

```python
from sklearn.preprocessing import StandardScaler
data = [[0, 0], [0, 0], [1, 1], [1, 1]]
scaler = StandardScaler(with_mean=False)
print(scaler.fit(data))
print(scaler.mean_)
```

### Expected Results

StandardScaler(with_mean=False)
None

### Actual Results

StandardScaler(with_mean=False)
[0.5 0.5]

### Versions

```shell
System:
    python: 3.10.10 | packaged by conda-forge | (main, Mar 24 2023, 20:12:31) [Clang 14.0.6 ]
executable: /opt/homebrew/Caskroom/miniforge/base/envs/rim/bin/python3.10
   machine: macOS-13.4.1-arm64-arm-64bit

Python dependencies:
      sklearn: 1.1.3
          pip: 23.1.2
   setuptools: 67.7.2
        numpy: 1.23.3
        scipy: 1.9.1
       Cython: None
       pandas: 2.0.1
   matplotlib: 3.6.0
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /opt/homebrew/Caskroom/miniforge/base/envs/xxx/lib/libopenblas.0.dylib
        version: 0.3.21
threading_layer: openmp
   architecture: VORTEX
    num_threads: 10

       user_api: openmp
   internal_api: openmp
         prefix: libomp
       filepath: /opt/homebrew/Caskroom/miniforge/base/envs/xxx/lib/libomp.dylib
        version: None
    num_threads: 10
```

COMMENT:
Good work spotting this and thanks for reporting it. Do you want to try and make a Pull Request that fixes this?

Labels: Bug
StandardScaler `mean_` is not None when `with_mean=False`

### Describe the bug

In the documentation, it is stated that

> **mean_**
ndarray of shape (n_features,) or None
The mean value for each feature in the training set. Equal to None when with_mean=False.

But the actual mean values are returned for `mean_` attribute.





### Steps/Code to Reproduce

```python
from sklearn.preprocessing import StandardScaler
data = [[0, 0], [0, 0], [1, 1], [1, 1]]
scaler = StandardScaler(with_mean=False)
print(scaler.fit(data))
print(scaler.mean_)
```

### Expected Results

StandardScaler(with_mean=False)
None

### Actual Results

StandardScaler(with_mean=False)
[0.5 0.5]

### Versions

```shell
System:
    python: 3.10.10 | packaged by conda-forge | (main, Mar 24 2023, 20:12:31) [Clang 14.0.6 ]
executable: /opt/homebrew/Caskroom/miniforge/base/envs/rim/bin/python3.10
   machine: macOS-13.4.1-arm64-arm-64bit

Python dependencies:
      sklearn: 1.1.3
          pip: 23.1.2
   setuptools: 67.7.2
        numpy: 1.23.3
        scipy: 1.9.1
       Cython: None
       pandas: 2.0.1
   matplotlib: 3.6.0
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /opt/homebrew/Caskroom/miniforge/base/envs/xxx/lib/libopenblas.0.dylib
        version: 0.3.21
threading_layer: openmp
   architecture: VORTEX
    num_threads: 10

       user_api: openmp
   internal_api: openmp
         prefix: libomp
       filepath: /opt/homebrew/Caskroom/miniforge/base/envs/xxx/lib/libomp.dylib
        version: None
    num_threads: 10
```

COMMENT:
sure, I will make a PR for it. Thanks

Labels: Bug
StandardScaler `mean_` is not None when `with_mean=False`

### Describe the bug

In the documentation, it is stated that

> **mean_**
ndarray of shape (n_features,) or None
The mean value for each feature in the training set. Equal to None when with_mean=False.

But the actual mean values are returned for `mean_` attribute.





### Steps/Code to Reproduce

```python
from sklearn.preprocessing import StandardScaler
data = [[0, 0], [0, 0], [1, 1], [1, 1]]
scaler = StandardScaler(with_mean=False)
print(scaler.fit(data))
print(scaler.mean_)
```

### Expected Results

StandardScaler(with_mean=False)
None

### Actual Results

StandardScaler(with_mean=False)
[0.5 0.5]

### Versions

```shell
System:
    python: 3.10.10 | packaged by conda-forge | (main, Mar 24 2023, 20:12:31) [Clang 14.0.6 ]
executable: /opt/homebrew/Caskroom/miniforge/base/envs/rim/bin/python3.10
   machine: macOS-13.4.1-arm64-arm-64bit

Python dependencies:
      sklearn: 1.1.3
          pip: 23.1.2
   setuptools: 67.7.2
        numpy: 1.23.3
        scipy: 1.9.1
       Cython: None
       pandas: 2.0.1
   matplotlib: 3.6.0
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /opt/homebrew/Caskroom/miniforge/base/envs/xxx/lib/libopenblas.0.dylib
        version: 0.3.21
threading_layer: openmp
   architecture: VORTEX
    num_threads: 10

       user_api: openmp
   internal_api: openmp
         prefix: libomp
       filepath: /opt/homebrew/Caskroom/miniforge/base/envs/xxx/lib/libomp.dylib
        version: None
    num_threads: 10
```

COMMENT:
Just to add,
Current behaviour for non sparse matrix is, if both `with_mean` and `with_std `is set to `False`, only then `scaler.mean_`  will be set to `None`.

https://github.com/scikit-learn/scikit-learn/blob/d2b9c802844a5bbd81687fbe6b43fc80a79c8ffa/sklearn/preprocessing/_data.py#L944-L964

```
from sklearn.preprocessing import StandardScaler
data = [[0, 0], [0, 0], [1, 1], [1, 1]]
scaler = StandardScaler(with_mean=False, with_std=False)
print(scaler.fit(data))
print(scaler.mean_)
print(scaler.transform(data))
print(scaler.mean_)

Output

StandardScaler(with_mean=False, with_std=False)
None
[[0. 0.]
 [0. 0.]
 [1. 1.]
 [1. 1.]]
None
```

Labels: Bug
StandardScaler `mean_` is not None when `with_mean=False`

### Describe the bug

In the documentation, it is stated that

> **mean_**
ndarray of shape (n_features,) or None
The mean value for each feature in the training set. Equal to None when with_mean=False.

But the actual mean values are returned for `mean_` attribute.





### Steps/Code to Reproduce

```python
from sklearn.preprocessing import StandardScaler
data = [[0, 0], [0, 0], [1, 1], [1, 1]]
scaler = StandardScaler(with_mean=False)
print(scaler.fit(data))
print(scaler.mean_)
```

### Expected Results

StandardScaler(with_mean=False)
None

### Actual Results

StandardScaler(with_mean=False)
[0.5 0.5]

### Versions

```shell
System:
    python: 3.10.10 | packaged by conda-forge | (main, Mar 24 2023, 20:12:31) [Clang 14.0.6 ]
executable: /opt/homebrew/Caskroom/miniforge/base/envs/rim/bin/python3.10
   machine: macOS-13.4.1-arm64-arm-64bit

Python dependencies:
      sklearn: 1.1.3
          pip: 23.1.2
   setuptools: 67.7.2
        numpy: 1.23.3
        scipy: 1.9.1
       Cython: None
       pandas: 2.0.1
   matplotlib: 3.6.0
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /opt/homebrew/Caskroom/miniforge/base/envs/xxx/lib/libopenblas.0.dylib
        version: 0.3.21
threading_layer: openmp
   architecture: VORTEX
    num_threads: 10

       user_api: openmp
   internal_api: openmp
         prefix: libomp
       filepath: /opt/homebrew/Caskroom/miniforge/base/envs/xxx/lib/libomp.dylib
        version: None
    num_threads: 10
```

COMMENT:
Looks like we are computing the mean and std, even when one of them is ON. Hence, would it make sense to return these values and change the documentation accordingly?

https://github.com/scikit-learn/scikit-learn/blob/364c77e047ca08a95862becf40a04fe9d4cd2c98/sklearn/preprocessing/_data.py#L940-L952

Labels: Bug
StandardScaler `mean_` is not None when `with_mean=False`

### Describe the bug

In the documentation, it is stated that

> **mean_**
ndarray of shape (n_features,) or None
The mean value for each feature in the training set. Equal to None when with_mean=False.

But the actual mean values are returned for `mean_` attribute.





### Steps/Code to Reproduce

```python
from sklearn.preprocessing import StandardScaler
data = [[0, 0], [0, 0], [1, 1], [1, 1]]
scaler = StandardScaler(with_mean=False)
print(scaler.fit(data))
print(scaler.mean_)
```

### Expected Results

StandardScaler(with_mean=False)
None

### Actual Results

StandardScaler(with_mean=False)
[0.5 0.5]

### Versions

```shell
System:
    python: 3.10.10 | packaged by conda-forge | (main, Mar 24 2023, 20:12:31) [Clang 14.0.6 ]
executable: /opt/homebrew/Caskroom/miniforge/base/envs/rim/bin/python3.10
   machine: macOS-13.4.1-arm64-arm-64bit

Python dependencies:
      sklearn: 1.1.3
          pip: 23.1.2
   setuptools: 67.7.2
        numpy: 1.23.3
        scipy: 1.9.1
       Cython: None
       pandas: 2.0.1
   matplotlib: 3.6.0
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /opt/homebrew/Caskroom/miniforge/base/envs/xxx/lib/libopenblas.0.dylib
        version: 0.3.21
threading_layer: openmp
   architecture: VORTEX
    num_threads: 10

       user_api: openmp
   internal_api: openmp
         prefix: libomp
       filepath: /opt/homebrew/Caskroom/miniforge/base/envs/xxx/lib/libomp.dylib
        version: None
    num_threads: 10
```

COMMENT:
cc @betatim

Labels: Bug
StandardScaler `mean_` is not None when `with_mean=False`

### Describe the bug

In the documentation, it is stated that

> **mean_**
ndarray of shape (n_features,) or None
The mean value for each feature in the training set. Equal to None when with_mean=False.

But the actual mean values are returned for `mean_` attribute.





### Steps/Code to Reproduce

```python
from sklearn.preprocessing import StandardScaler
data = [[0, 0], [0, 0], [1, 1], [1, 1]]
scaler = StandardScaler(with_mean=False)
print(scaler.fit(data))
print(scaler.mean_)
```

### Expected Results

StandardScaler(with_mean=False)
None

### Actual Results

StandardScaler(with_mean=False)
[0.5 0.5]

### Versions

```shell
System:
    python: 3.10.10 | packaged by conda-forge | (main, Mar 24 2023, 20:12:31) [Clang 14.0.6 ]
executable: /opt/homebrew/Caskroom/miniforge/base/envs/rim/bin/python3.10
   machine: macOS-13.4.1-arm64-arm-64bit

Python dependencies:
      sklearn: 1.1.3
          pip: 23.1.2
   setuptools: 67.7.2
        numpy: 1.23.3
        scipy: 1.9.1
       Cython: None
       pandas: 2.0.1
   matplotlib: 3.6.0
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /opt/homebrew/Caskroom/miniforge/base/envs/xxx/lib/libopenblas.0.dylib
        version: 0.3.21
threading_layer: openmp
   architecture: VORTEX
    num_threads: 10

       user_api: openmp
   internal_api: openmp
         prefix: libomp
       filepath: /opt/homebrew/Caskroom/miniforge/base/envs/xxx/lib/libomp.dylib
        version: None
    num_threads: 10
```

COMMENT:
Let's adjust the documentation for the attributes.

Labels: Bug