Talip7/scikit-learn-issues-multilabel huggingface dataset:
Cloned estimators have identical randomness but different RNG instances

### Describe the bug

Cloned estimators have identical randomness but different RNG instances. According to documentation, it should be the other way around: different randomness but identical RNG instances.

Related #25395 

The User Guide [says](https://scikit-learn.org/stable/common_pitfalls.html#controlling-randomness):
> For an optimal robustness of cross-validation (CV) results, pass RandomState instances when creating estimators

> ```python
> rf_inst = RandomForestClassifier(random_state=np.random.RandomState(0))
> cross_val_score(rf_inst, X, y)
> ```
> ...
> Since `rf_inst` was passed a `RandomState` instance, each call to `fit` starts from a different RNG. As a result, the random subset of features will be different for each folds

In regards to cloning, the same reference says:
> ```python
> rng = np.random.RandomState(0)
> a = RandomForestClassifier(random_state=rng)
> b = clone(a)
> ```
> Moreover, `a` and `b` will influence each-other since they share the same internal RNG: calling `a.fit` will consume `b`’s RNG, and calling `b.fit` will consume `a`’s RNG, since they are the same. 

The actual behaviour does not follow this description. 

### Steps/Code to Reproduce

```python
import numpy as np
from sklearn import clone
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier

rng = np.random.RandomState(0)
X, y = make_classification(random_state=rng)
rf = RandomForestClassifier(random_state=rng)

d = cross_validate(rf, X, y, return_estimator=True, cv=2)
rngs = [e.random_state for e in d['estimator']]
# estimators corresponding to different CV runs have different but identical RNGs:
print(rngs[0] is rngs[1]) # False
print(all(rngs[0].randint(10, size=10) == rngs[1].randint(10, size=10))) # True

rf_clone = clone(rf)
rngs = [rf.random_state, rf_clone.random_state]
print(rngs[0] is rngs[1]) # False
print(all(rngs[0].randint(10, size=10) == rngs[1].randint(10, size=10))) # True
```

### Expected Results

True False True False

### Actual Results

False True False True

### Versions

```shell
Tested on a two-week-old dev build and also on the following version (Kaggle)

System:
    python: 3.7.12 | packaged by conda-forge | (default, Oct 26 2021, 06:08:53)  [GCC 9.4.0]
executable: /opt/conda/bin/python3.7
   machine: Linux-5.15.90+-x86_64-with-debian-bullseye-sid

Python dependencies:
          pip: 22.3.1
   setuptools: 59.8.0
      sklearn: 1.0.2
        numpy: 1.21.6
        scipy: 1.7.3
       Cython: 0.29.34
       pandas: 1.3.5
   matplotlib: 3.5.3
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True
```

COMMENT:
And because I've forgotten twice already: thanks for digging into this, reading the docs and reporting this @avm19. This is a topic with many subtleties where we need to get what should happen, what does happen and what the docs say in alignment.

Labels: Bug, Documentation, Needs Decision
Cloned estimators have identical randomness but different RNG instances

### Describe the bug

Cloned estimators have identical randomness but different RNG instances. According to documentation, it should be the other way around: different randomness but identical RNG instances.

Related #25395 

The User Guide [says](https://scikit-learn.org/stable/common_pitfalls.html#controlling-randomness):
> For an optimal robustness of cross-validation (CV) results, pass RandomState instances when creating estimators

> ```python
> rf_inst = RandomForestClassifier(random_state=np.random.RandomState(0))
> cross_val_score(rf_inst, X, y)
> ```
> ...
> Since `rf_inst` was passed a `RandomState` instance, each call to `fit` starts from a different RNG. As a result, the random subset of features will be different for each folds

In regards to cloning, the same reference says:
> ```python
> rng = np.random.RandomState(0)
> a = RandomForestClassifier(random_state=rng)
> b = clone(a)
> ```
> Moreover, `a` and `b` will influence each-other since they share the same internal RNG: calling `a.fit` will consume `b`’s RNG, and calling `b.fit` will consume `a`’s RNG, since they are the same. 

The actual behaviour does not follow this description. 

### Steps/Code to Reproduce

```python
import numpy as np
from sklearn import clone
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier

rng = np.random.RandomState(0)
X, y = make_classification(random_state=rng)
rf = RandomForestClassifier(random_state=rng)

d = cross_validate(rf, X, y, return_estimator=True, cv=2)
rngs = [e.random_state for e in d['estimator']]
# estimators corresponding to different CV runs have different but identical RNGs:
print(rngs[0] is rngs[1]) # False
print(all(rngs[0].randint(10, size=10) == rngs[1].randint(10, size=10))) # True

rf_clone = clone(rf)
rngs = [rf.random_state, rf_clone.random_state]
print(rngs[0] is rngs[1]) # False
print(all(rngs[0].randint(10, size=10) == rngs[1].randint(10, size=10))) # True
```

### Expected Results

True False True False

### Actual Results

False True False True

### Versions

```shell
Tested on a two-week-old dev build and also on the following version (Kaggle)

System:
    python: 3.7.12 | packaged by conda-forge | (default, Oct 26 2021, 06:08:53)  [GCC 9.4.0]
executable: /opt/conda/bin/python3.7
   machine: Linux-5.15.90+-x86_64-with-debian-bullseye-sid

Python dependencies:
          pip: 22.3.1
   setuptools: 59.8.0
      sklearn: 1.0.2
        numpy: 1.21.6
        scipy: 1.7.3
       Cython: 0.29.34
       pandas: 1.3.5
   matplotlib: 3.5.3
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True
```

COMMENT:
> As a result I don't think the docs need improving, instead we need to improve the code.

For that we'd need to revive the SLEP.

Labels: Bug, Documentation, Needs Decision
Cloned estimators have identical randomness but different RNG instances

### Describe the bug

Cloned estimators have identical randomness but different RNG instances. According to documentation, it should be the other way around: different randomness but identical RNG instances.

Related #25395 

The User Guide [says](https://scikit-learn.org/stable/common_pitfalls.html#controlling-randomness):
> For an optimal robustness of cross-validation (CV) results, pass RandomState instances when creating estimators

> ```python
> rf_inst = RandomForestClassifier(random_state=np.random.RandomState(0))
> cross_val_score(rf_inst, X, y)
> ```
> ...
> Since `rf_inst` was passed a `RandomState` instance, each call to `fit` starts from a different RNG. As a result, the random subset of features will be different for each folds

In regards to cloning, the same reference says:
> ```python
> rng = np.random.RandomState(0)
> a = RandomForestClassifier(random_state=rng)
> b = clone(a)
> ```
> Moreover, `a` and `b` will influence each-other since they share the same internal RNG: calling `a.fit` will consume `b`’s RNG, and calling `b.fit` will consume `a`’s RNG, since they are the same. 

The actual behaviour does not follow this description. 

### Steps/Code to Reproduce

```python
import numpy as np
from sklearn import clone
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier

rng = np.random.RandomState(0)
X, y = make_classification(random_state=rng)
rf = RandomForestClassifier(random_state=rng)

d = cross_validate(rf, X, y, return_estimator=True, cv=2)
rngs = [e.random_state for e in d['estimator']]
# estimators corresponding to different CV runs have different but identical RNGs:
print(rngs[0] is rngs[1]) # False
print(all(rngs[0].randint(10, size=10) == rngs[1].randint(10, size=10))) # True

rf_clone = clone(rf)
rngs = [rf.random_state, rf_clone.random_state]
print(rngs[0] is rngs[1]) # False
print(all(rngs[0].randint(10, size=10) == rngs[1].randint(10, size=10))) # True
```

### Expected Results

True False True False

### Actual Results

False True False True

### Versions

```shell
Tested on a two-week-old dev build and also on the following version (Kaggle)

System:
    python: 3.7.12 | packaged by conda-forge | (default, Oct 26 2021, 06:08:53)  [GCC 9.4.0]
executable: /opt/conda/bin/python3.7
   machine: Linux-5.15.90+-x86_64-with-debian-bullseye-sid

Python dependencies:
          pip: 22.3.1
   setuptools: 59.8.0
      sklearn: 1.0.2
        numpy: 1.21.6
        scipy: 1.7.3
       Cython: 0.29.34
       pandas: 1.3.5
   matplotlib: 3.5.3
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True
```

COMMENT:
I've added this to the agenda for the next monthly meeting (24th April). I think having a short sync discussion would be helpful, even if it won't answer all questions "once and for all".

Labels: Bug, Documentation, Needs Decision
Cloned estimators have identical randomness but different RNG instances

### Describe the bug

Cloned estimators have identical randomness but different RNG instances. According to documentation, it should be the other way around: different randomness but identical RNG instances.

Related #25395 

The User Guide [says](https://scikit-learn.org/stable/common_pitfalls.html#controlling-randomness):
> For an optimal robustness of cross-validation (CV) results, pass RandomState instances when creating estimators

> ```python
> rf_inst = RandomForestClassifier(random_state=np.random.RandomState(0))
> cross_val_score(rf_inst, X, y)
> ```
> ...
> Since `rf_inst` was passed a `RandomState` instance, each call to `fit` starts from a different RNG. As a result, the random subset of features will be different for each folds

In regards to cloning, the same reference says:
> ```python
> rng = np.random.RandomState(0)
> a = RandomForestClassifier(random_state=rng)
> b = clone(a)
> ```
> Moreover, `a` and `b` will influence each-other since they share the same internal RNG: calling `a.fit` will consume `b`’s RNG, and calling `b.fit` will consume `a`’s RNG, since they are the same. 

The actual behaviour does not follow this description. 

### Steps/Code to Reproduce

```python
import numpy as np
from sklearn import clone
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier

rng = np.random.RandomState(0)
X, y = make_classification(random_state=rng)
rf = RandomForestClassifier(random_state=rng)

d = cross_validate(rf, X, y, return_estimator=True, cv=2)
rngs = [e.random_state for e in d['estimator']]
# estimators corresponding to different CV runs have different but identical RNGs:
print(rngs[0] is rngs[1]) # False
print(all(rngs[0].randint(10, size=10) == rngs[1].randint(10, size=10))) # True

rf_clone = clone(rf)
rngs = [rf.random_state, rf_clone.random_state]
print(rngs[0] is rngs[1]) # False
print(all(rngs[0].randint(10, size=10) == rngs[1].randint(10, size=10))) # True
```

### Expected Results

True False True False

### Actual Results

False True False True

### Versions

```shell
Tested on a two-week-old dev build and also on the following version (Kaggle)

System:
    python: 3.7.12 | packaged by conda-forge | (default, Oct 26 2021, 06:08:53)  [GCC 9.4.0]
executable: /opt/conda/bin/python3.7
   machine: Linux-5.15.90+-x86_64-with-debian-bullseye-sid

Python dependencies:
          pip: 22.3.1
   setuptools: 59.8.0
      sklearn: 1.0.2
        numpy: 1.21.6
        scipy: 1.7.3
       Cython: 0.29.34
       pandas: 1.3.5
   matplotlib: 3.5.3
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True
```

COMMENT:
The point we made, which is lost in the summary, is that people should be able to have randomized predict, but they should also be able to control that randomness if needed.

Labels: Bug, Documentation, Needs Decision
RandomForest not passing feature names to trees and creating warnings.

### Describe the bug

I fit a decision forest with training data that includes feature names. When I call predict_proba on the forest everything is fine. When I call rf.estimators_[0].predict_proba it will warn that it was not trained with feature names.


### Steps/Code to Reproduce
```python
import numpy as np
from sklearn.ensemble import RandomForestClassifier

print(sklearn.__version__)

data = np.random.normal([1,2,3,4,5,6,7,8,9,10], size=(1000, 10))
feature_names = [f'F{i}' for i in range(10)]
df = pd.DataFrame(data=data, columns=feature_names)
y = np.ones(1000)
y[500:] = 0

rf = RandomForestClassifier()
rf.fit(df, y)

print(f"Feature names in Forest: {rf.feature_names_in_} ")

print('Classing pred proba on forest')
rf.predict_proba(df)
print('Done calling pred proba on forest')

# THIS GIVES A WARNING
rf.estimators_[0].predict_proba(df)
```

### Expected Results

No warnings

### Actual Results
```
Feature names in Forest: ['F0' 'F1' 'F2' 'F3' 'F4' 'F5' 'F6' 'F7' 'F8' 'F9'] 
Classing pred proba on forest
Done calling pred proba on forest
.....lib/python3.8/site-packages/sklearn/base.py:432: UserWarning: X has feature names, but DecisionTreeClassifier was fitted without feature names
  warnings.warn(
```
### Versions

```shell
sk>>> sklearn.show_versions()

System:
    python: 3.8.16 (default, Mar  2 2023, 03:21:46)  [GCC 11.2.0]
executable: ....../bin/python
   machine: Linux-5.15.0-60-generic-x86_64-with-glibc2.17

Python dependencies:
      sklearn: 1.2.2
          pip: 23.0.1
   setuptools: 65.6.3
        numpy: 1.23.1
        scipy: 1.9.0
       Cython: None
       pandas: 1.5.3
   matplotlib: None
       joblib: 1.1.1
threadpoolctl: 2.2.0
```

COMMENT:
Thanks for reporting this. What happens is that the `df` you pass in to the random forest has feature names, but these aren't passed on to the individual trees that make up the forest. This means when you directly access a tree and pass it the `df` it warns about this.

I think this happens because a lot of the scikit-learn data input validation that goes on in an estimator converts from a dataframe to a numpy array, which is then passed to the individual trees.

I think it would make sense to pass the feature name along as well so that use cases like your work. It would also mean that errors in the individual trees could make use of the feature names, etc. However, I am not sure how complex it would be to do this.

Labels: Bug, Moderate, module:ensemble
RandomForest not passing feature names to trees and creating warnings.

### Describe the bug

I fit a decision forest with training data that includes feature names. When I call predict_proba on the forest everything is fine. When I call rf.estimators_[0].predict_proba it will warn that it was not trained with feature names.


### Steps/Code to Reproduce
```python
import numpy as np
from sklearn.ensemble import RandomForestClassifier

print(sklearn.__version__)

data = np.random.normal([1,2,3,4,5,6,7,8,9,10], size=(1000, 10))
feature_names = [f'F{i}' for i in range(10)]
df = pd.DataFrame(data=data, columns=feature_names)
y = np.ones(1000)
y[500:] = 0

rf = RandomForestClassifier()
rf.fit(df, y)

print(f"Feature names in Forest: {rf.feature_names_in_} ")

print('Classing pred proba on forest')
rf.predict_proba(df)
print('Done calling pred proba on forest')

# THIS GIVES A WARNING
rf.estimators_[0].predict_proba(df)
```

### Expected Results

No warnings

### Actual Results
```
Feature names in Forest: ['F0' 'F1' 'F2' 'F3' 'F4' 'F5' 'F6' 'F7' 'F8' 'F9'] 
Classing pred proba on forest
Done calling pred proba on forest
.....lib/python3.8/site-packages/sklearn/base.py:432: UserWarning: X has feature names, but DecisionTreeClassifier was fitted without feature names
  warnings.warn(
```
### Versions

```shell
sk>>> sklearn.show_versions()

System:
    python: 3.8.16 (default, Mar  2 2023, 03:21:46)  [GCC 11.2.0]
executable: ....../bin/python
   machine: Linux-5.15.0-60-generic-x86_64-with-glibc2.17

Python dependencies:
      sklearn: 1.2.2
          pip: 23.0.1
   setuptools: 65.6.3
        numpy: 1.23.1
        scipy: 1.9.0
       Cython: None
       pandas: 1.5.3
   matplotlib: None
       joblib: 1.1.1
threadpoolctl: 2.2.0
```

COMMENT:
A simple fix, that I didn't expect to work, would be to set `feature_names_in_` for the trees in the fitted forest. Something like the following:
```python
for est in rf.estimators:
  est.feature_names_in_ = rf.feature_names_in_
```

I was expecting this to lead to a warning when the estimators are used from `rf.predict_proba` but it turns out that input validation is turned off when the trees are used from within the forest. This means this code works.

Would be good to hear what others think about this, just because there is no warning/exception doesn't mean it is a good idea ;)

Labels: Bug, Moderate, module:ensemble
RandomForest not passing feature names to trees and creating warnings.

### Describe the bug

I fit a decision forest with training data that includes feature names. When I call predict_proba on the forest everything is fine. When I call rf.estimators_[0].predict_proba it will warn that it was not trained with feature names.


### Steps/Code to Reproduce
```python
import numpy as np
from sklearn.ensemble import RandomForestClassifier

print(sklearn.__version__)

data = np.random.normal([1,2,3,4,5,6,7,8,9,10], size=(1000, 10))
feature_names = [f'F{i}' for i in range(10)]
df = pd.DataFrame(data=data, columns=feature_names)
y = np.ones(1000)
y[500:] = 0

rf = RandomForestClassifier()
rf.fit(df, y)

print(f"Feature names in Forest: {rf.feature_names_in_} ")

print('Classing pred proba on forest')
rf.predict_proba(df)
print('Done calling pred proba on forest')

# THIS GIVES A WARNING
rf.estimators_[0].predict_proba(df)
```

### Expected Results

No warnings

### Actual Results
```
Feature names in Forest: ['F0' 'F1' 'F2' 'F3' 'F4' 'F5' 'F6' 'F7' 'F8' 'F9'] 
Classing pred proba on forest
Done calling pred proba on forest
.....lib/python3.8/site-packages/sklearn/base.py:432: UserWarning: X has feature names, but DecisionTreeClassifier was fitted without feature names
  warnings.warn(
```
### Versions

```shell
sk>>> sklearn.show_versions()

System:
    python: 3.8.16 (default, Mar  2 2023, 03:21:46)  [GCC 11.2.0]
executable: ....../bin/python
   machine: Linux-5.15.0-60-generic-x86_64-with-glibc2.17

Python dependencies:
      sklearn: 1.2.2
          pip: 23.0.1
   setuptools: 65.6.3
        numpy: 1.23.1
        scipy: 1.9.0
       Cython: None
       pandas: 1.5.3
   matplotlib: None
       joblib: 1.1.1
threadpoolctl: 2.2.0
```

COMMENT:
As mentioned in https://github.com/scikit-learn/scikit-learn/issues/26140#issuecomment-1502905523, `RandomForest*` is configured to not validate in `predict`, so we can get away with setting the feature names directly. I'm okay with adjusting `RandomForest*` to do this.

For linking purposes, there was a related issue with `Bagging*` (https://github.com/scikit-learn/scikit-learn/issues/21599) that I tried to resolve in https://github.com/scikit-learn/scikit-learn/pull/21811. `Bagging*` is harder because we can not turn off validation in the inner estimator and so we are forced to pass in the DataFrame. Passing in DataFrames lead to issues with the common test: https://github.com/scikit-learn/scikit-learn/pull/21811#issuecomment-1091869844.

Labels: Bug, Moderate, module:ensemble
RandomForest not passing feature names to trees and creating warnings.

### Describe the bug

I fit a decision forest with training data that includes feature names. When I call predict_proba on the forest everything is fine. When I call rf.estimators_[0].predict_proba it will warn that it was not trained with feature names.


### Steps/Code to Reproduce
```python
import numpy as np
from sklearn.ensemble import RandomForestClassifier

print(sklearn.__version__)

data = np.random.normal([1,2,3,4,5,6,7,8,9,10], size=(1000, 10))
feature_names = [f'F{i}' for i in range(10)]
df = pd.DataFrame(data=data, columns=feature_names)
y = np.ones(1000)
y[500:] = 0

rf = RandomForestClassifier()
rf.fit(df, y)

print(f"Feature names in Forest: {rf.feature_names_in_} ")

print('Classing pred proba on forest')
rf.predict_proba(df)
print('Done calling pred proba on forest')

# THIS GIVES A WARNING
rf.estimators_[0].predict_proba(df)
```

### Expected Results

No warnings

### Actual Results
```
Feature names in Forest: ['F0' 'F1' 'F2' 'F3' 'F4' 'F5' 'F6' 'F7' 'F8' 'F9'] 
Classing pred proba on forest
Done calling pred proba on forest
.....lib/python3.8/site-packages/sklearn/base.py:432: UserWarning: X has feature names, but DecisionTreeClassifier was fitted without feature names
  warnings.warn(
```
### Versions

```shell
sk>>> sklearn.show_versions()

System:
    python: 3.8.16 (default, Mar  2 2023, 03:21:46)  [GCC 11.2.0]
executable: ....../bin/python
   machine: Linux-5.15.0-60-generic-x86_64-with-glibc2.17

Python dependencies:
      sklearn: 1.2.2
          pip: 23.0.1
   setuptools: 65.6.3
        numpy: 1.23.1
        scipy: 1.9.0
       Cython: None
       pandas: 1.5.3
   matplotlib: None
       joblib: 1.1.1
threadpoolctl: 2.2.0
```

COMMENT:
@howarth would you like to open a Pull Request that implements the idea from [my previous comment](https://github.com/scikit-learn/scikit-learn/issues/26140#issuecomment-1502905523) for `RandomForest*` estimators? Together with a non regression test based on your reproducer code.

Labels: Bug, Moderate, module:ensemble
RandomForest not passing feature names to trees and creating warnings.

### Describe the bug

I fit a decision forest with training data that includes feature names. When I call predict_proba on the forest everything is fine. When I call rf.estimators_[0].predict_proba it will warn that it was not trained with feature names.


### Steps/Code to Reproduce
```python
import numpy as np
from sklearn.ensemble import RandomForestClassifier

print(sklearn.__version__)

data = np.random.normal([1,2,3,4,5,6,7,8,9,10], size=(1000, 10))
feature_names = [f'F{i}' for i in range(10)]
df = pd.DataFrame(data=data, columns=feature_names)
y = np.ones(1000)
y[500:] = 0

rf = RandomForestClassifier()
rf.fit(df, y)

print(f"Feature names in Forest: {rf.feature_names_in_} ")

print('Classing pred proba on forest')
rf.predict_proba(df)
print('Done calling pred proba on forest')

# THIS GIVES A WARNING
rf.estimators_[0].predict_proba(df)
```

### Expected Results

No warnings

### Actual Results
```
Feature names in Forest: ['F0' 'F1' 'F2' 'F3' 'F4' 'F5' 'F6' 'F7' 'F8' 'F9'] 
Classing pred proba on forest
Done calling pred proba on forest
.....lib/python3.8/site-packages/sklearn/base.py:432: UserWarning: X has feature names, but DecisionTreeClassifier was fitted without feature names
  warnings.warn(
```
### Versions

```shell
sk>>> sklearn.show_versions()

System:
    python: 3.8.16 (default, Mar  2 2023, 03:21:46)  [GCC 11.2.0]
executable: ....../bin/python
   machine: Linux-5.15.0-60-generic-x86_64-with-glibc2.17

Python dependencies:
      sklearn: 1.2.2
          pip: 23.0.1
   setuptools: 65.6.3
        numpy: 1.23.1
        scipy: 1.9.0
       Cython: None
       pandas: 1.5.3
   matplotlib: None
       joblib: 1.1.1
threadpoolctl: 2.2.0
```

COMMENT:
@betatim Sure, but I won't be able to get to that for at least two weeks.

Labels: Bug, Moderate, module:ensemble