InteractionTransformer

### Describe the workflow you want to enable

The latest 1.2 release is full of great features, e.g., full column name support. This brings me to one of my most desired features regarding building strong and realistic linear models: Interactions!

It is currently very hard to add interaction terms between two feature groups, especially if they involve 1 to m transforms like OHE or SplineTransformers.

### Describe your proposed solution

An idea of @lorentzenchr that I try to summarize: Create the transforms like a ColumnTransformer,  but also adding interaction terms between columns generated by each transformer. The resulting columns could be glued to an other ColumnTransformer using `FeatureUnion`.

## Sketch of the API

```
InteractionTransformer(
    transformers,
    interaction_only=False
    include_bias=True,
    verbose_feature_names_out=True
)

# transformers: list of tuples
#     List of (name, transformer, columns) tuples specifying the transformer objects to be applied to subsets of the data.
#     Each transformer would specify a feature (group) that would interact with other transformers.
# interaction_only: If False, also return main effects
```

## Example 1: Interactions between two 1-m transforms

Here, we would let each dummy variable of "f1" interact with each spline basis of "f2":

```
InteractionTransformer(
    transformers=[
        ("f1_ohe", OneHotEncoder(drop="first"), ["f1"]),
        ("f2_spline", SplineTransformer(), ["f2"]),
    ]
)
```

## Example 2: Interaction between OHE and other features

Each column generated by OHE "f1" would interact with numeric feature "f2" and also with numeric feature "f3".

```
InteractionTransformer(
    transformers=[
        ("f1_ohe", OneHotEncoder(drop="first"), ["f1"]),
        ("f2_others", "passthrough", ["f2", "f3"]),
    ]
)
```

## Example 3: Interaction between two OHE, further features linear

```
interactor = InteractionTransformer(
    transformers=[
        ("f1_ohe", OneHotEncoder(drop="first"), ["f1"]),
        ("f2_ohe", OneHotEncoder(drop="first"), ["f2"]),
    ]
)

preprocessor = FeatureUnion(
  interactor,
  ColumnTransformer("other", "passthrough", ["f3", "f4"])
)

```


### Describe alternatives you've considered, if relevant

_No response_

### Additional context

_No response_

COMMENT:
@ogrisel Thanks for your consideration! 

Regarding the tuning logic: We could use an argument `kind="pairwise"` that would specify which feature groups would interact:

- `"pairwise"`: All pairwise interactions
- `None`: Only main effects (?)
- A tuple of pairs of names. In Example 3 above, `"pairwise"` would be equivalent to `(("f1_ohe", "f2_ohe"),)`.

## Alternative API

We *could* pack the interaction functionality also directly into into the existing `columnTransformer()` :

```
columnTransformer(
    transformers=[
        ("f1_ohe", OneHotEncoder(drop="first"), ["f1"]),
        ("f2_others", "passthrough", ["f2", "f3"]),
    ],
    interactions="pairwise"  # or (("f1_ohe", "f2_others"),)
)
```

Maybe you got an even more bold idea?

Labels: New Feature, module:preprocessing