RFC SLEP006: verbose vs non-verbose declaration in meta-estimator

As the proposal and the implementation of meta-estimator routing (SLEP006) stands, if the user wants to use `sample_weight`, they need to be quite verbose in how they declare the estimators. Taking `AdaBoostClassifier` as an example, and imagining if `AdaBoostClassifier` would use the sub-estimator's `score` method, the user would have to write:

``` python
est = (
    AdaBoostClassifier(LogisticRegression().set_fit_request(sample_weight=True)
    .set_score_request(sample_weight=True))
    .fit(X, y, sample_weight=sw)
)
```

which is quite more verbose than the current code users need to write:

``` python
est = AdaBoostClassifier(LogisticRegression()).fit(X, y, sample_weight=sw)
```

There have been concerns about making users write quite verbose code in cases where the current pattern seems quite reasonable.

Without changing everything related to SLEP006, there are three paths we can take:

#### Option 1: Helper function
We can introduce helper functions to make the above code simpler. For instance, a `weighted` function could request `sample_weight` on all methods which accept `sample_weight` for a given estimator. Then the above code would look like:

``` python
est = AdaBoostClassifier(weighted(LogisticRegression())).fit(X, y, sample_weight=sw)
```

and if the sub-estimator is a pipeline:

``` python
est = AdaBoostClassifier(
    make_pipeline(weighted(StandardScaler()), weighted(LogisticRegression())))
).fit(X, y, sample_weight=sw)
```

Implementing `weighted` for a `Pipeline` (or other meta-estimators) would be tricky since `set_fit_request` is only available for consumers and not non-consumer routers; therefore the user needs to repeat the `weighted` call for all sub-estimators.

#### Option 2: Different meta-estimators
Have two classes of meta-estimators (or routers to be specific).

In this scenario, we divide meta-estimators into two classes, _simple_ and _complex_. Simple routers are the ones which simply forward `**kwargs` to sub-estimators, and by default the assume sub-estimators have requested those metadata. This simplifies the users' code and makes the existing code for simple meta-estimators to keep working, but it raises a few issues.

First is that there will be two classes of meta-estimators, and the user would need to know which estimator is of which class. It's also not clear what we should do if the user explicitly sets request values for metadata (we can probably respect those if present).

Another issue is that if a meta-estimator changes behavior, it needs to become a _complex_ meta-estimator if we want to keep backward compatibility for it. This doesn't seem like a good pattern.

#### Option 3: Keep as is
Do nothing, things are as is.

I'm in favor or option 1 because:
- with the helper function the user code doesn't look too verbose
- using metadata is not a beginner kinda thing and therefore this API is not hampering beginners' experience with the library
- it keeps consistency among meta-estimators/consumers

xref: https://github.com/scikit-learn/scikit-learn/pull/22986#pullrequestreview-1005144559

COMMENT:
There are a few issues with the above example:

1. What if `LogisticRegression` doesn't support `sample_weight` in version `x`, and starts supporting it in version `x+1`? Then the same code, would have to different behaviors silently. That's now what we do in scikit-learn.

2. How is `AdaBoost` supposed to know `LogisticRegression` supports `sample_weight`? Is it because its `fit` accepts the argument? What if instead of `LogisticRegression`, I pass something which is not a simple consumer? Should there be a way for estimators to tell the router objects, whether they are consumers or not? If yes, that adds quite a bit more burden to third party developers. Also, that would mean we'll move from "almost all third party estimators work out of the box with the current change", to "none of them work out of the box, all devs have to do something to give us more info about their estimators", and also, that would mean we'd have to modify all our estimators and add the info, which we're not doing now.

3. What if I want to put the above `AdaBoost` in a `Pipeline`? The `Pipeline` now definitely is not going to know if `AdaBoost` supports `sample_weight`, and the user would now need to go and set request values. It would be simpler if the user needed to set request values from the beginning.

4. `AdaBoost` basically follows two strategies based on whether the sub-estimator supports `sample_weight` or not, and the user needs to know that. Otherwise we're not encouraging them to do good machine learning.

Labels: API, RFC