Source code for finite_selection.features
"""Covariate transformations for balancing beyond the means."""
from __future__ import annotations
from itertools import combinations
import pandas as pd
[docs]
def make_sq_inter(
data: pd.DataFrame,
*,
is_square: bool = True,
is_inter: bool = True,
keep_marginal: bool = True,
) -> pd.DataFrame:
"""Add squares and pairwise products of the columns of ``data``.
Feeding these to :func:`~finite_selection.fsm` balances second moments
and interactions, which balancing the raw columns does not guarantee.
Args:
data: Covariates.
is_square: Add ``col^2`` for each column.
is_inter: Add ``a.b`` for each pair of columns.
keep_marginal: Keep the original columns first.
Returns:
Marginal columns, then interactions, then squares, each in input
column order.
Raises:
ValueError: If every option is off, leaving nothing to return.
"""
if not (is_square or is_inter or keep_marginal):
raise ValueError("nothing to return: enable at least one option")
parts = []
if keep_marginal:
parts.append(data)
if is_inter:
parts.append(
pd.DataFrame(
{
f"{a}.{b}": data[a] * data[b]
for a, b in combinations(data.columns, 2)
},
index=data.index,
)
)
if is_square:
parts.append(
pd.DataFrame(
{f"{a}^2": data[a] ** 2 for a in data.columns}, index=data.index
)
)
return pd.concat(parts, axis=1)