Talip7/scikit-learn-issues-multilabel huggingface dataset:
Add MultiHorizonTimeSeriesSplit for Multi-Horizon Time Series Cross-Validation

### Describe the workflow you want to enable

The current `TimeSeriesSplit` in scikit-learn supports cross-validation for time series data with a single prediction horizon per split, which limits its use for scenarios requiring forecasts over multiple future steps (e.g., predicting 1, 3, and 5 days ahead). I propose adding a new class, `MultiHorizonTimeSeriesSplit`, to enable cross-validation with multiple prediction horizons in a single split.

This would allow users to:
- Specify a list of horizons (e.g., `[1, 3, 5]`) to generate train-test splits where the test set includes indices for multiple future steps.
- Evaluate time series models for short, medium, and long-term forecasts simultaneously.
- Simplify workflows for applications like demand forecasting, financial modeling, or weather prediction, avoiding manual splitting.

Example usage with daily temperatures:
```
from sklearn.model_selection import MultiHorizonTimeSeriesSplit
import numpy as np

# Daily temperatures for 10 days (in °C)
X = np.array([20, 21, 22, 23, 24, 25, 26, 27, 28, 29])
cv = MultiHorizonTimeSeriesSplit(n_splits=2, horizons=[1, 2])
for train_idx, test_idx in cv.split(X):
    print(f"Train indices: {train_idx}, Test indices: {test_idx}")
```
Expected output:
```
Train indices: [0 1 2 3 4], Test indices: [5 6]
Train indices: [0 1 2 3 4 5 6], Test indices: [7 8]
```

### Describe your proposed solution

I propose implementing a new class, `MultiHorizonTimeSeriesSplit`, inheriting from `TimeSeriesSplit`. The class will:
- Add a `horizons` parameter (list of integers) to specify prediction steps.
- Modify the `split` method to generate test indices for each horizon while preserving temporal order.
- Include input validation to ensure valid horizons and splits.

To ensure the correctness of MultiHorizonTimeSeriesSplit, we will develop unit tests covering various configurations and edge cases. For benchmarking, we will assess the computational efficiency and correctness of the new class compared to manual splitting. We will use synthetic time series to evaluate scalability and measure split generation time and memory usage, running tests on a personal laptop.


### Describe alternatives you've considered, if relevant

_No response_

### Additional context

_No response_

COMMENT:
@ogrisel @glemaitre you seem to know things about time series, what do you think about this?

Labels: New Feature
Add MultiHorizonTimeSeriesSplit for Multi-Horizon Time Series Cross-Validation

### Describe the workflow you want to enable

The current `TimeSeriesSplit` in scikit-learn supports cross-validation for time series data with a single prediction horizon per split, which limits its use for scenarios requiring forecasts over multiple future steps (e.g., predicting 1, 3, and 5 days ahead). I propose adding a new class, `MultiHorizonTimeSeriesSplit`, to enable cross-validation with multiple prediction horizons in a single split.

This would allow users to:
- Specify a list of horizons (e.g., `[1, 3, 5]`) to generate train-test splits where the test set includes indices for multiple future steps.
- Evaluate time series models for short, medium, and long-term forecasts simultaneously.
- Simplify workflows for applications like demand forecasting, financial modeling, or weather prediction, avoiding manual splitting.

Example usage with daily temperatures:
```
from sklearn.model_selection import MultiHorizonTimeSeriesSplit
import numpy as np

# Daily temperatures for 10 days (in °C)
X = np.array([20, 21, 22, 23, 24, 25, 26, 27, 28, 29])
cv = MultiHorizonTimeSeriesSplit(n_splits=2, horizons=[1, 2])
for train_idx, test_idx in cv.split(X):
    print(f"Train indices: {train_idx}, Test indices: {test_idx}")
```
Expected output:
```
Train indices: [0 1 2 3 4], Test indices: [5 6]
Train indices: [0 1 2 3 4 5 6], Test indices: [7 8]
```

### Describe your proposed solution

I propose implementing a new class, `MultiHorizonTimeSeriesSplit`, inheriting from `TimeSeriesSplit`. The class will:
- Add a `horizons` parameter (list of integers) to specify prediction steps.
- Modify the `split` method to generate test indices for each horizon while preserving temporal order.
- Include input validation to ensure valid horizons and splits.

To ensure the correctness of MultiHorizonTimeSeriesSplit, we will develop unit tests covering various configurations and edge cases. For benchmarking, we will assess the computational efficiency and correctness of the new class compared to manual splitting. We will use synthetic time series to evaluate scalability and measure split generation time and memory usage, running tests on a personal laptop.


### Describe alternatives you've considered, if relevant

_No response_

### Additional context

_No response_

COMMENT:
With @ogrisel we are going to explore shortly a bit of time-series forecasting. I think that it will be a good opportunity to assess whether such CV splitter should be in the scope of scikit-learn or if it is preferable to contribute it to a specialized time-series third-party library.

Basically, if we are already able to do many forecast case solely with scikit-learn, I think that having the tool to evaluate then is really useful.

Labels: New Feature
Add MultiHorizonTimeSeriesSplit for Multi-Horizon Time Series Cross-Validation

### Describe the workflow you want to enable

The current `TimeSeriesSplit` in scikit-learn supports cross-validation for time series data with a single prediction horizon per split, which limits its use for scenarios requiring forecasts over multiple future steps (e.g., predicting 1, 3, and 5 days ahead). I propose adding a new class, `MultiHorizonTimeSeriesSplit`, to enable cross-validation with multiple prediction horizons in a single split.

This would allow users to:
- Specify a list of horizons (e.g., `[1, 3, 5]`) to generate train-test splits where the test set includes indices for multiple future steps.
- Evaluate time series models for short, medium, and long-term forecasts simultaneously.
- Simplify workflows for applications like demand forecasting, financial modeling, or weather prediction, avoiding manual splitting.

Example usage with daily temperatures:
```
from sklearn.model_selection import MultiHorizonTimeSeriesSplit
import numpy as np

# Daily temperatures for 10 days (in °C)
X = np.array([20, 21, 22, 23, 24, 25, 26, 27, 28, 29])
cv = MultiHorizonTimeSeriesSplit(n_splits=2, horizons=[1, 2])
for train_idx, test_idx in cv.split(X):
    print(f"Train indices: {train_idx}, Test indices: {test_idx}")
```
Expected output:
```
Train indices: [0 1 2 3 4], Test indices: [5 6]
Train indices: [0 1 2 3 4 5 6], Test indices: [7 8]
```

### Describe your proposed solution

I propose implementing a new class, `MultiHorizonTimeSeriesSplit`, inheriting from `TimeSeriesSplit`. The class will:
- Add a `horizons` parameter (list of integers) to specify prediction steps.
- Modify the `split` method to generate test indices for each horizon while preserving temporal order.
- Include input validation to ensure valid horizons and splits.

To ensure the correctness of MultiHorizonTimeSeriesSplit, we will develop unit tests covering various configurations and edge cases. For benchmarking, we will assess the computational efficiency and correctness of the new class compared to manual splitting. We will use synthetic time series to evaluate scalability and measure split generation time and memory usage, running tests on a personal laptop.


### Describe alternatives you've considered, if relevant

_No response_

### Additional context

_No response_

COMMENT:
@glemaitre did you get some insights for this issue?

Labels: New Feature
⚠️ CI failed on Wheel builder (last failure: May 07, 2025) ⚠️

**CI failed on [Wheel builder](https://github.com/scikit-learn/scikit-learn/actions/runs/14874735765)** (May 07, 2025)

COMMENT:
## CI is no longer failing! ✅

[Successful run](https://github.com/scikit-learn/scikit-learn/actions/runs/14874735765) on May 07, 2025

Labels: Needs Triage
⚠️ CI failed on Linux_free_threaded.pylatest_free_threaded (last failure: May 07, 2025) ⚠️

**CI failed on [Linux_free_threaded.pylatest_free_threaded](https://dev.azure.com/scikit-learn/scikit-learn/_build/results?buildId=76323&view=logs&j=c10228e9-6cf7-5c29-593f-d74f893ca1bd)** (May 07, 2025)
Unable to find junit file. Please see link for details.

COMMENT:
## CI is no longer failing! ✅

[Successful run](https://dev.azure.com/scikit-learn/scikit-learn/_build/results?buildId=76391&view=logs&j=c10228e9-6cf7-5c29-593f-d74f893ca1bd) on May 08, 2025

Labels: Needs Triage
Add train_validation_test_split for three-way dataset splits

### Describe the workflow you want to enable

Enable the user to divide the dataset into 3 parts (train, validation and test) instead of only two (train and test) using only one method. This would present a more elegant solution than using the method train_test_split twice.

```python 
from sklearn.model_selection import train_val_test_split
X_train, X_val, X_test, y_train, y_val, y_test = train_validation_test_split(
    X, y,
    train_size=0.6,
    val_size=0.2,
    test_size=0.2,
    random_state=42,
    shuffle=True,
    stratify=y
)
```

### Describe your proposed solution

Add a new method called train_test_validation_split where the dataset is divided into train, validation and test set. The arguments would be the same as the train_test_split method with the additional  val_size, similar to test_size and train_size but for the validation set.

### Describe alternatives you've considered, if relevant

Using train_test_split twice works, but having a dedicated train_validation_test_split function would be cleaner and more concise.

### Additional context

Using a validation set helps avoiding both overfitting aswell as underfitting.

COMMENT:
We got such request in the past (cf. https://github.com/scikit-learn/scikit-learn/issues/13990#issuecomment-1534763718) and we advise against adding new parameters and instead used the `train_test_split` functions twice.

Labels: New Feature, Needs Triage
Argument order in haversine_distances for latitude/longitude

### Describe the issue linked to the documentation

Hello! I frequently use [sklearn.metrics.pairwise.haversine_distances](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.haversine_distances.html) to estimate distances on the globe. The example on the linked page uses a geographic example, but it does not specify whether geographic coordinates are in (latitude, longitude) or (longitude, latitude) form. From context, one can infer that the correct order is (latitude,longitude); however, it would be useful to explicitly state the order.

This is my first issue submission; please let me know if there is something more that might be useful for resolution!

### Suggest a potential alternative/fix

There are two ways that this could be resolved:
1. Include a short note stating that geographic coordinates should be input as (latitude,longitude)
2. Include a comment in the example code describing the coordinate order.

COMMENT:
I think it is specified in the documentation that you mentioned:

![Image](https://github.com/user-attachments/assets/9cf985fa-0a4d-4ad1-9902-fe147c2a286b)

The first column is the latitude and the second is the longitude from what I'm reading now, isn't it?

Labels: Documentation
Argument order in haversine_distances for latitude/longitude

### Describe the issue linked to the documentation

Hello! I frequently use [sklearn.metrics.pairwise.haversine_distances](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.haversine_distances.html) to estimate distances on the globe. The example on the linked page uses a geographic example, but it does not specify whether geographic coordinates are in (latitude, longitude) or (longitude, latitude) form. From context, one can infer that the correct order is (latitude,longitude); however, it would be useful to explicitly state the order.

This is my first issue submission; please let me know if there is something more that might be useful for resolution!

### Suggest a potential alternative/fix

There are two ways that this could be resolved:
1. Include a short note stating that geographic coordinates should be input as (latitude,longitude)
2. Include a comment in the example code describing the coordinate order.

COMMENT:
You are correct, I wasn't reading it closely enough! Thank you!!

Labels: Documentation
SGDRegressor is not inheriting from LinearModel

### Describe the bug

I wanted to rely on the base class [LinearModel](https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/linear_model/_base.py#L267) to identify linear models, but I found out that [SGDRegressor](https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/linear_model/_stochastic_gradient.py#L1757) (nor any of its sub classes) is not inheriting this class. However, SGDClassifier is (through LinearClassifierMixin).

Is there any reason for [BaseSGDRegressor](https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/linear_model/_stochastic_gradient.py#L1383) to not inherit [LinearModel](https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/linear_model/_base.py#L267)? Is it because it overloads all of LinearModel's methods?

### Steps/Code to Reproduce

from sklearn.linear_model import SGDRegressor
from sklearn.linear_model._base import LinearModel

issubclass(SGDRegressor, LinearModel)

### Expected Results

from sklearn.linear_model import SGDRegressor
from sklearn.linear_model._base import LinearModel

issubclass(SGDRegressor, LinearModel)
# True

### Actual Results

from sklearn.linear_model import SGDRegressor
from sklearn.linear_model._base import LinearModel

issubclass(SGDRegressor, LinearModel)
# False

### Versions

```shell
System:
    python: 3.10.11 (v3.10.11:7d4cc5aa85, Apr  4 2023, 19:05:19) [Clang 13.0.0 (clang-1300.0.29.30)]
executable: /usr/local/bin/python3.10
   machine: macOS-14.4.1-arm64-arm-64bit

Python dependencies:
      sklearn: 1.5.0
          pip: 24.2
   setuptools: 74.0.0
        numpy: 1.26.4
        scipy: 1.13.1
       Cython: 3.0.12
       pandas: 1.5.3
   matplotlib: 3.8.4
       joblib: 1.2.0
threadpoolctl: 3.5.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
    num_threads: 8
         prefix: libopenblas
       filepath: /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/numpy/.dylibs/libopenblas64_.0.dylib
        version: 0.3.23.dev
threading_layer: pthreads
   architecture: armv8

       user_api: blas
   internal_api: openblas
    num_threads: 8
         prefix: libopenblas
       filepath: /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/.dylibs/libopenblas.0.dylib
        version: 0.3.27
threading_layer: pthreads
   architecture: neoversen1

       user_api: openmp
   internal_api: openmp
    num_threads: 8
         prefix: libomp
       filepath: /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/sklearn/.dylibs/libomp.dylib
        version: None
```

COMMENT:
If subclassing can help remove redundant code, then I am not opposed to a PR. But if subclassing does not help reduce code complexity, I see little benefit to doing so. Extra indirections introduced by inheritance make it harder to navigate the code base and (slightly) hurt code readability as a result.

Labels: Enhancement
SGDRegressor is not inheriting from LinearModel

### Describe the bug

I wanted to rely on the base class [LinearModel](https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/linear_model/_base.py#L267) to identify linear models, but I found out that [SGDRegressor](https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/linear_model/_stochastic_gradient.py#L1757) (nor any of its sub classes) is not inheriting this class. However, SGDClassifier is (through LinearClassifierMixin).

Is there any reason for [BaseSGDRegressor](https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/linear_model/_stochastic_gradient.py#L1383) to not inherit [LinearModel](https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/linear_model/_base.py#L267)? Is it because it overloads all of LinearModel's methods?

### Steps/Code to Reproduce

from sklearn.linear_model import SGDRegressor
from sklearn.linear_model._base import LinearModel

issubclass(SGDRegressor, LinearModel)

### Expected Results

from sklearn.linear_model import SGDRegressor
from sklearn.linear_model._base import LinearModel

issubclass(SGDRegressor, LinearModel)
# True

### Actual Results

from sklearn.linear_model import SGDRegressor
from sklearn.linear_model._base import LinearModel

issubclass(SGDRegressor, LinearModel)
# False

### Versions

```shell
System:
    python: 3.10.11 (v3.10.11:7d4cc5aa85, Apr  4 2023, 19:05:19) [Clang 13.0.0 (clang-1300.0.29.30)]
executable: /usr/local/bin/python3.10
   machine: macOS-14.4.1-arm64-arm-64bit

Python dependencies:
      sklearn: 1.5.0
          pip: 24.2
   setuptools: 74.0.0
        numpy: 1.26.4
        scipy: 1.13.1
       Cython: 3.0.12
       pandas: 1.5.3
   matplotlib: 3.8.4
       joblib: 1.2.0
threadpoolctl: 3.5.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
    num_threads: 8
         prefix: libopenblas
       filepath: /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/numpy/.dylibs/libopenblas64_.0.dylib
        version: 0.3.23.dev
threading_layer: pthreads
   architecture: armv8

       user_api: blas
   internal_api: openblas
    num_threads: 8
         prefix: libopenblas
       filepath: /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/.dylibs/libopenblas.0.dylib
        version: 0.3.27
threading_layer: pthreads
   architecture: neoversen1

       user_api: openmp
   internal_api: openmp
    num_threads: 8
         prefix: libomp
       filepath: /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/sklearn/.dylibs/libomp.dylib
        version: None
```

COMMENT:
I looked a bit at the code and I think that we can clean-up something. In addition of the inheritance, I think we should look at the code of `LinearModel` and `LinearClassifierMixin`:

https://github.com/scikit-learn/scikit-learn/blob/81bb708dc4c218f801b11fa2751c51e2ba3715b8/sklearn/linear_model/_base.py#L322-L324

I think there is room to improve the clarity of those classes and it should remove some redundant code, notably when it comes to the `_decision_function` call.

Labels: Enhancement
SGDRegressor is not inheriting from LinearModel

### Describe the bug

I wanted to rely on the base class [LinearModel](https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/linear_model/_base.py#L267) to identify linear models, but I found out that [SGDRegressor](https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/linear_model/_stochastic_gradient.py#L1757) (nor any of its sub classes) is not inheriting this class. However, SGDClassifier is (through LinearClassifierMixin).

Is there any reason for [BaseSGDRegressor](https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/linear_model/_stochastic_gradient.py#L1383) to not inherit [LinearModel](https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/linear_model/_base.py#L267)? Is it because it overloads all of LinearModel's methods?

### Steps/Code to Reproduce

from sklearn.linear_model import SGDRegressor
from sklearn.linear_model._base import LinearModel

issubclass(SGDRegressor, LinearModel)

### Expected Results

from sklearn.linear_model import SGDRegressor
from sklearn.linear_model._base import LinearModel

issubclass(SGDRegressor, LinearModel)
# True

### Actual Results

from sklearn.linear_model import SGDRegressor
from sklearn.linear_model._base import LinearModel

issubclass(SGDRegressor, LinearModel)
# False

### Versions

```shell
System:
    python: 3.10.11 (v3.10.11:7d4cc5aa85, Apr  4 2023, 19:05:19) [Clang 13.0.0 (clang-1300.0.29.30)]
executable: /usr/local/bin/python3.10
   machine: macOS-14.4.1-arm64-arm-64bit

Python dependencies:
      sklearn: 1.5.0
          pip: 24.2
   setuptools: 74.0.0
        numpy: 1.26.4
        scipy: 1.13.1
       Cython: 3.0.12
       pandas: 1.5.3
   matplotlib: 3.8.4
       joblib: 1.2.0
threadpoolctl: 3.5.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
    num_threads: 8
         prefix: libopenblas
       filepath: /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/numpy/.dylibs/libopenblas64_.0.dylib
        version: 0.3.23.dev
threading_layer: pthreads
   architecture: armv8

       user_api: blas
   internal_api: openblas
    num_threads: 8
         prefix: libopenblas
       filepath: /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/.dylibs/libopenblas.0.dylib
        version: 0.3.27
threading_layer: pthreads
   architecture: neoversen1

       user_api: openmp
   internal_api: openmp
    num_threads: 8
         prefix: libomp
       filepath: /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/sklearn/.dylibs/libomp.dylib
        version: None
```

COMMENT:
Is this issue open for contributions? If yes then I'd love to give it a try.
cc @ogrisel @glemaitre

Labels: Enhancement
Reference CalibrationDisplay from calibration_curve's docstring in a "See also section"

### Describe the issue linked to the documentation

Enrich documentation like proposed in #31302 for calibration_curve's

### Suggest a potential alternative/fix

_No response_

COMMENT:
hi @metlouf 

I'd like to work on this documentation improvement. Adding a reference to CalibrationDisplay in the "See also" section of the calibration_curve docstring makes perfect sense, as it helps users connect the computation function with the visualization utility.

I plan to:

Add CalibrationDisplay to the "See also" section of calibration_curve.

Ensure the formatting is consistent with other references.

Run the doc build to verify everything renders correctly.

Let me know if there's anything else you'd like me to include. I'd be happy to open a PR for this.

Labels: Documentation