causalis.shared.confounder_clustering

Correlation-based clustering of observed confounders.

Module Contents

Functions

cluster_confounders

Cluster confounders using their absolute pairwise correlations.

rank_confounder_clusters

Cluster confounders and rank them by joint and treatment importance.

Data

CorrelationMethod

LinkageMethod

OutcomeImportanceMethod

__all__

API

causalis.shared.confounder_clustering.CorrelationMethod

None

causalis.shared.confounder_clustering.LinkageMethod

None

causalis.shared.confounder_clustering.OutcomeImportanceMethod

None

causalis.shared.confounder_clustering.cluster_confounders(data: causalis.dgp.causaldata.CausalData | causalis.dgp.multicausaldata.MultiCausalData, *, min_abs_correlation: float = 0.7, correlation_method: causalis.shared.confounder_clustering.CorrelationMethod = 'pearson', linkage_method: causalis.shared.confounder_clustering.LinkageMethod = 'complete', max_samples: Optional[int] = 200000, random_state: Optional[int] = 42) list[list[str]]

Cluster confounders using their absolute pairwise correlations.

The clustering distance is

.. math::

d(X_i, X_j) = 1 - |\operatorname{corr}(X_i, X_j)|.

Hierarchical clustering is cut at 1 - min_abs_correlation. Negative and positive correlations of the same magnitude are therefore treated as equally similar. By default, complete linkage is used, so every pair of features in a non-singleton cluster has an absolute correlation at least as large as min_abs_correlation on the sampled data.

Parameters

data : CausalData or MultiCausalData Causal data contract exposing numeric df and confounders attributes. min_abs_correlation : float, default 0.7 Correlation cut-off in the closed interval [0, 1]. Larger values form smaller, more strongly related clusters. correlation_method : {“pearson”, “spearman”}, default “pearson” Pairwise correlation measure. Spearman correlation is useful for monotonic non-linear relationships but requires more work and memory. linkage_method : {“average”, “complete”, “single”}, default “complete” Hierarchical-linkage rule. Only complete linkage guarantees the pairwise threshold interpretation described above. max_samples : int or None, default 200000 Maximum number of rows used to estimate correlations. If the dataset is larger, rows are sampled without replacement. Pass None to use all rows. random_state : int or None, default 42 Seed used for row sampling.

Returns

list[list[str]] Clusters in the original confounder order. Features within each cluster also preserve their original order. Singleton clusters are retained.

Examples

clusters = cluster_confounders(data, min_abs_correlation=0.8) strongest_group = clusters[0] strongest_group # doctest: +SKIP [‘income’, ‘salary’, ‘credit_limit’]

Notes

Missing correlations can occur when a rare feature is constant in the sampled rows. They are treated as zero correlation, leaving that feature separate unless it is linked to another feature by valid correlations.

causalis.shared.confounder_clustering.rank_confounder_clusters(data: causalis.dgp.causaldata.CausalData | causalis.dgp.multicausaldata.MultiCausalData, effect_estimation: Any, *, min_abs_correlation: float = 0.7, correlation_method: causalis.shared.confounder_clustering.CorrelationMethod = 'pearson', linkage_method: causalis.shared.confounder_clustering.LinkageMethod = 'complete', max_samples: Optional[int] = 200000, random_state: Optional[int] = 42, outcome_importance: causalis.shared.confounder_clustering.OutcomeImportanceMethod = 'mean', ranking_method: Literal[mixed, joint] = 'mixed') pandas.DataFrame

Cluster confounders and rank them by joint and treatment importance.

For each correlation cluster :math:C_g, the treatment and outcome importances are aggregated as

.. math::

I_{D,g} = \sum_{j \in C_g} I_{m,j},

and, by default,

.. math::

I_{Y,g} = \frac{1}{2}\left(
    \sum_{j \in C_g} I_{g0,j}
    + \sum_{j \in C_g} I_{g1,j}
\right).

The joint score is score = importance_d * importance_y. By default, the first two clusters have the highest joint scores, and the third has the highest treatment importance among the remaining clusters. All other clusters retain descending joint-score order. Native importance vectors are normalized separately for m, g0, and g1 before aggregation.

Parameters

data : CausalData or MultiCausalData Data containing the confounders to cluster. effect_estimation : Any Fitted IRM, causal estimate with diagnostic data, or dictionary containing one of them. Feature importance must have been collected. min_abs_correlation, correlation_method, linkage_method, max_samples, random_state Forwarded to :func:cluster_confounders. outcome_importance : {“mean”, “max”}, default “mean” Combine the cluster-level g0 and g1 importance by their mean or maximum. "max" is more conservative for features important in only one treatment arm. ranking_method : {“mixed”, “joint”}, default “mixed” "mixed" selects two clusters by joint score, then the strongest remaining treatment cluster, followed by the rest in joint-score order. Treatment-importance ties favor higher joint score, then original cluster order. With fewer than three clusters, all are returned in joint-score order. "joint" preserves the legacy descending joint-score ordering for every cluster. The initial joint-score sort preserves original cluster order for tied scores.

Returns

pandas.DataFrame Cluster ranking with columns cluster_id, features, n_features, importance_d, importance_g0, importance_g1, importance_y, and score. Row zero is the highest-ranked cluster; features can be passed directly to sensitivity_benchmark_group. Every cluster appears once, and scores are unchanged by the ranking method. Mixed ordering is not necessarily globally descending by score.

Notes

Ranking reuses native feature importances without fitting additional models. These importances are screening heuristics, not calibrated sensitivity strengths; mixed ranking does not guarantee higher benchmark r2_d.

Examples

ranking = rank_confounder_clusters(data, estimate) top3 = ranking.head(3) # Two by joint score, one by treatment importance. joint_ranking = rank_confounder_clusters(data, estimate, ranking_method=”joint”)

causalis.shared.confounder_clustering.__all__

[‘cluster_confounders’, ‘rank_confounder_clusters’]