//  [python]
def validate_ood_group(
    id_data: np.array,
    ood_data: np.array,
    feature_names: List[str],
    test: str = "welch",
    p_thresh: float = 0.05,
) -> Dict[str, float]:
    """
    Perform an experiment on an in-domain and out-of-domain group to see whether the latter constitutes a form of
    covariate shift. This is done by checking whether p(x) = q(x) using a significance test. It is also tested whether
    the results change after / imputing and scaling by checking how many more features become significant afterwards
    ('#feat_ood') and a sanity check how many features of the imputed in-domain data are significantly different after
    the imputing process compared to its raw form ('#feats same').

    Parameters
    ----------
    id_data: np.array
        In-domain data.
    ood_data: np.array
        Out-of-domain data.
    feature_names: List[str]
        The names of the features as a list.
    test: str
        Name of the significance test that should be used. Either 'welch' or 'kolmogorov-smirnov'.
    p_thresh: float
        p-value treshold. Default is 0.05.

    Returns
    -------
    results: pd.DataFrame
        Return the result of the test
    """

    pipe = pipeline.Pipeline(
        [("scaler", StandardScaler()), ("imputer", Imputer())]
    )

    results = {}

    print("Raw data")

    ks_values_raw, sig_raw = ood_utils.validate_ood_data(
        id_data, ood_data, feature_names=feature_names, test=test, p_thresh=p_thresh
    )
    results["raw"] = f"{sig_raw * 100:.2f}"

    print("\nImputed & scaled data")

    pipe.fit(id_data)
    scaled_imputed_id = pipe.transform(id_data)

    scaled_imputed_ood = pipe.transform(ood_data)

    ks_values_scaled_imputed, sig_scaled_imputed = ood_utils.validate_ood_data(
        scaled_imputed_id,
        scaled_imputed_ood,
        feature_names=feature_names,
        test=test,
        p_thresh=p_thresh,
    )
    results["imputed"] = f"{sig_scaled_imputed * 100:.2f}"

    # Calculate how many new features became stat. sig. after imputing
    ks_sig_raw = (ks_values_raw <= p_thresh).astype(int)
    ks_sig_scaled_imputed = (ks_values_scaled_imputed <= p_thresh).astype(int)

    num_diff_feats = ks_sig_scaled_imputed.sum() - ks_sig_raw.sum()
    results["#feats ood"] = num_diff_feats

    # Do the same computing the original data set to its original variant
    ks_values_same, _ = ood_utils.validate_ood_data(
        pipe.named_steps["scaler"].transform(id_data),  # Only scale, don't impute
        scaled_imputed_id,
        feature_names=feature_names,
        test=test,
        p_thresh=p_thresh,
        verbose=False,
    )
    num_diff_same = (ks_values_same <= p_thresh).astype(int).sum()
    results["#feats same"] = num_diff_same

    if num_diff_feats > 0:
        # Retrieve the names of those features
        newly_sig_feats = [
            feat_name
            for i, feat_name in enumerate(feature_names)
            if ks_sig_raw[i] == 0 and ks_sig_scaled_imputed[i] == 1
        ]

        print(
            f"\nIn total {num_diff_feats} new stat. sig. features ({num_diff_same} new for the same dataset after "
            f"imputing):\n{', '.join(newly_sig_feats)}"
        )

    return results