Skip to content

Api axis partitioning

effector.axis_partitioning.Fixed(nof_bins=20, min_points_per_bin=0)

Bases: Base

Uniform grid: exactly nof_bins equal-width bins — ALE's default ("fixed").

Ignores y, so it is deterministic and the cheapest option (O(N)). It is also the only binner ALE accepts: a shared fixed grid is part of ALE's definition. It honors the requested bin count exactly — it never collapses to fewer bins; if some bin ends up under min_points_per_bin it reports failure instead.

Initialize the fixed binner.

Parameters:

Name Type Description Default
nof_bins int

Number of equal-width bins over the axis range.

20
min_points_per_bin int

If any bin of the grid holds fewer points, find_limits returns False. 0 disables the check.

0
Source code in effector/axis_partitioning.py
509
510
511
512
513
514
515
516
517
518
519
def __init__(self, nof_bins: int = 20, min_points_per_bin: int = 0):
    """Initialize the fixed binner.

    Args:
        nof_bins: Number of equal-width bins over the axis range.
        min_points_per_bin: If any bin of the grid holds fewer points,
            `find_limits` returns `False`. `0` disables the check.
    """
    constraints = Constraints(min_points_per_bin=min_points_per_bin)
    params = {"nof_bins": nof_bins}
    super(Fixed, self).__init__("fixed", constraints, params)

effector.axis_partitioning.Agglomerative(init_nof_bins=20, min_points_per_bin=2, discount=0.3)

Bases: Base

Bottom-up greedy binning: near-optimal adaptive bins at a fraction of DP's cost.

Start from a fine uniform grid of init_nof_bins cells and repeatedly remove the interior boundary whose removal reduces the total cost the most, stopping when no removal helps (under-filled bins are merged away first). Driven by the same variance-based objective DynamicProgramming optimizes exactly, but only locally optimal — O(N + K^2) instead of O(N + K^3). Pick it when "dp" is too slow.

Replaces the old Greedy

The old left-to-right Greedy sweep was replaced by this order-independent agglomerative merge; Greedy and the "greedy" alias still work and resolve here.

Initialize the agglomerative binner.

Parameters:

Name Type Description Default
init_nof_bins int

Number of cells in the starting uniform grid; the final bins are unions of these cells, so it caps the resolution.

20
min_points_per_bin int

Bins with fewer points are penalized and merged away. Must be at least 2 (variance needs two points).

2
discount float

How much to reward well-populated bins. A bin holding a fraction p of the points has its cost scaled by 1 - discount * p; higher values favor fewer, fuller bins.

0.3
Source code in effector/axis_partitioning.py
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
def __init__(
    self,
    init_nof_bins: int = 20,
    min_points_per_bin: int = 2,
    discount: float = 0.3,
):
    """Initialize the agglomerative binner.

    Args:
        init_nof_bins: Number of cells in the starting uniform grid; the
            final bins are unions of these cells, so it caps the resolution.
        min_points_per_bin: Bins with fewer points are penalized and merged
            away. Must be at least 2 (variance needs two points).
        discount: How much to reward well-populated bins. A bin holding a
            fraction `p` of the points has its cost scaled by
            `1 - discount * p`; higher values favor fewer, fuller bins.
    """
    assert min_points_per_bin >= 2, "min_points_per_bin should be at least 2"
    constraints = Constraints(min_points_per_bin=min_points_per_bin)
    params = {"init_nof_bins": init_nof_bins, "discount": discount}
    super(Agglomerative, self).__init__("agglomerative", constraints, params)

effector.axis_partitioning.Quantile(nof_bins=20, min_points_per_bin=0)

Bases: Base

Equal-frequency binning: edges at data quantiles ("quantile").

Every bin holds roughly the same number of points. Like Fixed it ignores y, but it adapts the edge positions to the x distribution — pick it for skewed features, where a uniform grid wastes bins on empty stretches. O(N log N). Tied quantiles collapse (so discrete-ish data yields fewer bins), and under-filled bins are merged into a neighbor to honor min_points_per_bin.

Initialize the quantile binner.

Parameters:

Name Type Description Default
nof_bins int

Number of equal-frequency bins (edges at the i/nof_bins quantiles); duplicates collapse, so ties may yield fewer.

20
min_points_per_bin int

Bins with fewer points are merged into a neighbor. 0 disables the check.

0
Source code in effector/axis_partitioning.py
554
555
556
557
558
559
560
561
562
563
564
565
def __init__(self, nof_bins: int = 20, min_points_per_bin: int = 0):
    """Initialize the quantile binner.

    Args:
        nof_bins: Number of equal-frequency bins (edges at the `i/nof_bins`
            quantiles); duplicates collapse, so ties may yield fewer.
        min_points_per_bin: Bins with fewer points are merged into a
            neighbor. `0` disables the check.
    """
    constraints = Constraints(min_points_per_bin=min_points_per_bin)
    params = {"nof_bins": nof_bins}
    super(Quantile, self).__init__("quantile", constraints, params)

effector.axis_partitioning.DynamicProgramming(max_nof_bins=20, min_points_per_bin=2, discount=0.3)

Bases: Base

Optimal variance-based binning — RHALE's default ("dp").

Among all partitions of a uniform max_nof_bins-cell grid, dynamic programming finds the one that exactly minimizes the total cost Var[y] * width * (1 - discount * n/N) summed over bins: bin edges land where the local effects change behavior. The most accurate binner and the most expensive — O(N + K^3) in max_nof_bins; for large grids consider Agglomerative, which chases the same objective greedily.

Initialize the dynamic-programming binner.

Parameters:

Name Type Description Default
max_nof_bins int

Number of cells in the candidate grid and an upper bound on the number of bins; the optimum may use fewer.

20
min_points_per_bin int

Bins with fewer points are penalized and avoided. Must be at least 2 (variance needs two points).

2
discount float

How much to reward well-populated bins. A bin holding a fraction p of the points has its cost scaled by 1 - discount * p; higher values favor fewer, fuller bins.

0.3
Source code in effector/axis_partitioning.py
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
def __init__(
    self,
    max_nof_bins: int = 20,
    min_points_per_bin: int = 2,
    discount: float = 0.3,
):
    """Initialize the dynamic-programming binner.

    Args:
        max_nof_bins: Number of cells in the candidate grid and an upper
            bound on the number of bins; the optimum may use fewer.
        min_points_per_bin: Bins with fewer points are penalized and
            avoided. Must be at least 2 (variance needs two points).
        discount: How much to reward well-populated bins. A bin holding a
            fraction `p` of the points has its cost scaled by
            `1 - discount * p`; higher values favor fewer, fuller bins.
    """
    assert min_points_per_bin >= 2, "min_points_per_bin should be at least 2"
    constraints = Constraints(
        min_points_per_bin=min_points_per_bin, max_nof_bins=max_nof_bins
    )
    params = {"discount": discount}
    super(DynamicProgramming, self).__init__(
        "dynamic_programming", constraints, params
    )