When a Pipeline step is changed via set_params, the set_output state is cleared

### Describe the bug

When a Pipeline step is set via `set_params`, the subsequent output of `fit_transform` is a numpy ndarray even if previously the pipeline's output was set to be of type pandas.DataFrame via a call to `set_output(transform= 'pandas')`.

This only happens when the entire step is set: `set_params(step= some_value)`, not when only a step's parameters are set: `set_params(step__some_param= some_value)`.

The issue doesn't occur if, instead of calling `set_output(transform= 'pandas')` on the Pipeline object, the option is set globally with `sklearn.set_config(transform_output= 'pandas')`.

The same problem may or may not occur with ColumnTransformer, I haven't checked.

### Steps/Code to Reproduce

```
from pandas import DataFrame
from numpy import NaN
from sklearn.preprocessing import MinMaxScaler
from sklearn.pipeline import Pipeline

X = DataFrame({'N': [1, 2]})
pipe = Pipeline([('scale', MinMaxScaler())]).set_output(transform='pandas')
pipe.set_params(scale= MinMaxScaler())
pipe.fit_transform(X)
```

### Expected Results

A pandas DataFrame

### Actual Results

A numpy ndarray

### Versions

```shell
System:
    python: 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]
executable: /usr/bin/python3
   machine: Linux-6.1.85+-x86_64-with-glibc2.35

Python dependencies:
      sklearn: 1.2.2
          pip: 23.1.2
   setuptools: 67.7.2
        numpy: 1.25.2
        scipy: 1.11.4
       Cython: 3.0.10
       pandas: 2.0.3
   matplotlib: 3.7.1
       joblib: 1.4.2
threadpoolctl: 3.5.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
    num_threads: 2
         prefix: libopenblas
       filepath: /usr/local/lib/python3.10/dist-packages/numpy.libs/libopenblas64_p-r0-5007b62f.3.23.dev.so
        version: 0.3.23.dev
threading_layer: pthreads
   architecture: Haswell

       user_api: openmp
   internal_api: openmp
    num_threads: 2
         prefix: libgomp
       filepath: /usr/local/lib/python3.10/dist-packages/scikit_learn.libs/libgomp-a34b3233.so.1.0.0
        version: None

       user_api: blas
   internal_api: openblas
    num_threads: 2
         prefix: libopenblas
       filepath: /usr/local/lib/python3.10/dist-packages/scipy.libs/libopenblasp-r0-23e5df77.3.21.dev.so
        version: 0.3.21.dev
threading_layer: pthreads
   architecture: Haswell
```

COMMENT:
I think this happens because `pipe.set_output` will call `.set_output` to all its underlying estimators in particular `pipe['scale']` i.e. its `MinMaxScaler` estimator. When you do `pipe.set_params(scale=MinMaxScaler())` you replace `pipe['scale']` with an estimator that does not have `set_output` set.

The easiest work-arounds is probably to make sure to call `pipe.set_output` last:

```py
from pandas import DataFrame
from numpy import NaN
from sklearn.preprocessing import MinMaxScaler
from sklearn.pipeline import Pipeline

X = DataFrame({'N': [1, 2]})
pipe = Pipeline([('scale', MinMaxScaler())])
# Call pipe.set_output last
pipe.set_params(scale= MinMaxScaler()).set_output(transform='pandas')
pipe.fit_transform(X)
```

I would agree that this is slightly confusing. At the same time, fixing this would probably involve going over all the pipeline estimators and set their outputs at fit time, so not sure this is worth the additional complexity?

Labels: Documentation, Moderate, help wanted