Skip to content

Api space partitioning

The finder protocol

A region finder is any object exposing

find_regions(feature, data, score_fn, *, axis_limits, feature_types, cat_limit,
             candidate_conditioning_features, feature_names, target_name) -> Partition

where score_fn(mask) -> float scores a boolean subregion (the effect passes heter_score(feature, mask)). The finder owns the min-points / degeneracy guard; the effect never sees the BIG_M vocabulary (design contract R12). Best and BestLevelWise below implement this protocol; a new finder (ICE clustering, subgroup discovery, a user groupby) plugs into find_regions with no changes elsewhere.

Both built-in finders enumerate candidate splits through the proposer seam (parent rule → child conditions) and build the rule-primary Partition directly — there is no tree intermediate. The proposers are picked per feature type from the constructor kwargs categorical_proposer= ("one_vs_rest" | "subsets" | "ordered" | "multiway") and continuous_proposer= ("threshold" | "quantiles"), each also accepting a proposer instance.

API

effector.space_partitioning.Best(min_heterogeneity_decrease_pcg=0.05, heter_small_enough=0.03, max_depth=2, min_samples_leaf=10, numerical_features_grid_size=20, search_partitions_when_categorical=True, categorical_proposer='one_vs_rest', continuous_proposer='threshold')

Bases: Base

Node-wise recursive partitioning: the best split for each node, CART-style.

At every node, scan all candidate splits over all conditioning features, keep the one that minimizes the (population-weighted) heterogeneity of the children, and recurse into each child independently — so different branches may split on different features. A split is accepted only if it drops the node's heterogeneity by at least min_heterogeneity_decrease_pcg.

finder = effector.space_partitioning.Best(max_depth=3)
partition = rhale.find_regions("hr", finder=finder)

Configure the finder.

Parameters:

Name Type Description Default
min_heterogeneity_decrease_pcg float

Minimum relative heterogeneity drop to accept a split, as a fraction of the pre-split value.

Default is 0.05

With heterogeneity 1.0 at a node, the weighted heterogeneity of the children must be at most 0.95 — otherwise the node stays unsplit. heter_score is a std-type quantity (output units), where drops read smaller than on a variance scale: 0.05 ≈ 1 − √0.9, the equivalent of the historical variance-scale 0.1.

0.05
heter_small_enough float

A node with heterogeneity below this value is considered homogeneous and is not split further.

Default is 0.03

In output units (std scale). Small enough for most cases. If you know a priori what "homogeneous enough" means for your effect scores, raise it to stop earlier.

0.03
max_depth int

Maximum number of split levels.

Default is 2

Two levels of binary splits already yield up to 4 subregions — 4 regional plots per feature; deeper partitions are rarely digestible.

2
min_samples_leaf int

Minimum number of instances per subregion; candidate children below it score worst-possible, so they are never selected.

10
numerical_features_grid_size int

Threshold-grid resolution for continuous conditioning features: the axis range is divided into this many equal segments and the interior boundaries are the candidate thresholds (grid_size - 1 candidates).

20
search_partitions_when_categorical bool

Whether to search for subregions when the feature of interest is categorical.

Refers to a categorical feature of interest

Categorical features are always considered for conditioning, regardless of this flag. It is honored by BestLevelWise; Best currently always searches.

True
categorical_proposer

How candidate splits on categorical conditioning features are enumerated.

Options
  • "one_vs_rest" (default): one level vs. all others, per observed level
  • "subsets": every binary subset-vs-complement split
  • "ordered": contiguous cuts after ordering the levels (natural for ordinal, similarity seriation for nominal)
  • "multiway": one k-way candidate with one child per level
  • a proposer instance (anything exposing propose(ctx, foc)), e.g. effector.proposers.CategoricalOrdered(order=[...])
'one_vs_rest'
continuous_proposer

How candidate splits on continuous conditioning features are enumerated.

Options
  • "threshold" (default): binary splits on an interior grid of numerical_features_grid_size positions
  • "quantiles": one k-way candidate per child count, split at the marginal quantiles
  • a proposer instance, e.g. effector.proposers.ContinuousQuantiles(max_children=3)
'threshold'
Source code in effector/space_partitioning.py
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
def __init__(
    self,
    min_heterogeneity_decrease_pcg: float = 0.05,
    heter_small_enough: float = 0.03,
    max_depth: int = 2,
    min_samples_leaf: int = 10,
    numerical_features_grid_size: int = 20,
    search_partitions_when_categorical: bool = True,
    categorical_proposer="one_vs_rest",
    continuous_proposer="threshold",
):
    """Configure the finder.

    Args:
        min_heterogeneity_decrease_pcg: Minimum relative heterogeneity drop
            to accept a split, as a fraction of the pre-split value.

            ??? example "Default is `0.05`"
                With heterogeneity 1.0 at a node, the weighted
                heterogeneity of the children must be at most 0.95 —
                otherwise the node stays unsplit. `heter_score` is a
                std-type quantity (output units), where drops read
                smaller than on a variance scale: 0.05 ≈ 1 − √0.9, the
                equivalent of the historical variance-scale 0.1.

        heter_small_enough: A node with heterogeneity below this value is
            considered homogeneous and is not split further.

            ??? note "Default is `0.03`"
                In output units (std scale). Small enough for most cases.
                If you know a priori what "homogeneous enough" means for
                your effect scores, raise it to stop earlier.

        max_depth: Maximum number of split levels.

            ??? note "Default is `2`"
                Two levels of binary splits already yield up to 4
                subregions — 4 regional plots per feature; deeper
                partitions are rarely digestible.

        min_samples_leaf: Minimum number of instances per subregion;
            candidate children below it score worst-possible, so they are
            never selected.

        numerical_features_grid_size: Threshold-grid resolution for
            continuous conditioning features: the axis range is divided
            into this many equal segments and the interior boundaries are
            the candidate thresholds (`grid_size - 1` candidates).

        search_partitions_when_categorical: Whether to search for
            subregions when the *feature of interest* is categorical.

            !!! warning "Refers to a categorical feature of interest"
                Categorical features are always considered for
                *conditioning*, regardless of this flag. It is honored by
                `BestLevelWise`; `Best` currently always searches.

        categorical_proposer: How candidate splits on categorical
            conditioning features are enumerated.

            ??? note "Options"
                - `"one_vs_rest"` (default): one level vs. all others, per observed level
                - `"subsets"`: every binary subset-vs-complement split
                - `"ordered"`: contiguous cuts after ordering the levels (natural for ordinal, similarity seriation for nominal)
                - `"multiway"`: one k-way candidate with one child per level
                - a proposer instance (anything exposing `propose(ctx, foc)`), e.g. `effector.proposers.CategoricalOrdered(order=[...])`

        continuous_proposer: How candidate splits on continuous conditioning
            features are enumerated.

            ??? note "Options"
                - `"threshold"` (default): binary splits on an interior grid of `numerical_features_grid_size` positions
                - `"quantiles"`: one k-way candidate per child count, split at the marginal quantiles
                - a proposer instance, e.g. `effector.proposers.ContinuousQuantiles(max_children=3)`
    """
    super().__init__(
        "Best",
        min_heterogeneity_decrease_pcg,
        heter_small_enough,
        max_depth,
        min_samples_leaf,
        numerical_features_grid_size,
        search_partitions_when_categorical,
        categorical_proposer,
        continuous_proposer,
    )

effector.space_partitioning.BestLevelWise(min_heterogeneity_decrease_pcg=0.05, heter_small_enough=0.03, max_depth=2, min_samples_leaf=10, numerical_features_grid_size=20, search_partitions_when_categorical=True, categorical_proposer='one_vs_rest', continuous_proposer='threshold')

Bases: Base

Level-wise partitioning: one shared split per level (the REPID-style search).

At every level, find the single split that — applied to all nodes of that level at once — minimizes the weighted heterogeneity of the resulting children, then keep the prefix of levels whose relative heterogeneity drop exceeds min_heterogeneity_decrease_pcg. All siblings therefore split on the same feature at the same position, which yields symmetric, easy-to-read partitions; Best is the more flexible node-wise alternative.

finder = effector.space_partitioning.BestLevelWise(max_depth=2)
partition = rhale.find_regions("hr", finder=finder)

Configure the finder — same knobs as Best (see there for the extended notes).

Parameters:

Name Type Description Default
min_heterogeneity_decrease_pcg float

Minimum relative heterogeneity drop for a level to be kept (default 0.1 = 10%).

0.05
heter_small_enough float

Stop once a level's weighted heterogeneity is below this value (default 0.001).

0.03
max_depth int

Maximum number of split levels (default 2).

2
min_samples_leaf int

Minimum number of instances per subregion; candidate children below it score worst-possible.

10
numerical_features_grid_size int

Threshold-grid resolution for continuous conditioning features (grid_size - 1 candidates).

20
search_partitions_when_categorical bool

Whether to search when the feature of interest is categorical; if False, a root-only partition is returned for categorical features.

True
categorical_proposer

"one_vs_rest" (default), "subsets", "ordered", "multiway", or a proposer instance.

'one_vs_rest'
continuous_proposer

"threshold" (default), "quantiles", or a proposer instance.

'threshold'
Source code in effector/space_partitioning.py
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
def __init__(
    self,
    min_heterogeneity_decrease_pcg: float = 0.05,
    heter_small_enough: float = 0.03,
    max_depth: int = 2,
    min_samples_leaf: int = 10,
    numerical_features_grid_size: int = 20,
    search_partitions_when_categorical: bool = True,
    categorical_proposer="one_vs_rest",
    continuous_proposer="threshold",
):
    """Configure the finder — same knobs as `Best` (see there for the
    extended notes).

    Args:
        min_heterogeneity_decrease_pcg: Minimum relative heterogeneity drop
            for a level to be kept (default `0.1` = 10%).
        heter_small_enough: Stop once a level's weighted heterogeneity is
            below this value (default `0.001`).
        max_depth: Maximum number of split levels (default `2`).
        min_samples_leaf: Minimum number of instances per subregion;
            candidate children below it score worst-possible.
        numerical_features_grid_size: Threshold-grid resolution for
            continuous conditioning features (`grid_size - 1` candidates).
        search_partitions_when_categorical: Whether to search when the
            *feature of interest* is categorical; if `False`, a root-only
            partition is returned for categorical features.
        categorical_proposer: `"one_vs_rest"` (default), `"subsets"`,
            `"ordered"`, `"multiway"`, or a proposer instance.
        continuous_proposer: `"threshold"` (default), `"quantiles"`, or a
            proposer instance.
    """
    super().__init__(
        "best_level_wise",
        min_heterogeneity_decrease_pcg,
        heter_small_enough,
        max_depth,
        min_samples_leaf,
        numerical_features_grid_size,
        search_partitions_when_categorical,
        categorical_proposer,
        continuous_proposer,
    )

    # init splits
    self.splits: list = []
    self.important_splits: list = []

    # state variable
    self.split_found: bool = False
    self.important_splits_selected: bool = False