EqualFrequencyBinning

class binlearn.methods.EqualFrequencyBinning(n_bins: int | str | None = None, quantile_range: tuple[float, float] | None = None, clip: bool | None = None, preserve_dataframe: bool | None = None, fit_jointly: bool | None = None, *, bin_edges: dict[Any, list[float]] | None = None, bin_representatives: dict[Any, list[float]] | None = None, class_: str | None = None, module_: str | None = None)[source]

Bases: IntervalBinningBase

Equal frequency binning implementation for creating balanced population bins.

This class implements equal frequency binning (also known as quantile binning), which creates bins containing approximately equal numbers of observations. Unlike equal width binning that creates uniform intervals, equal frequency binning adapts bin boundaries to the data distribution, ensuring each bin has roughly the same number of data points.

Equal frequency binning is particularly effective for: - Skewed distributions where equal width bins would create imbalanced populations - Creating bins with consistent statistical power for analysis - Preprocessing for algorithms that perform better with balanced bin sizes - Ordinal discretization that preserves ranking relationships

Key Features: - Creates bins with approximately equal observation counts - Handles duplicate values intelligently by adjusting bin boundaries - Supports custom quantile ranges for focusing on specific data portions - Automatic handling of edge cases (insufficient unique values, duplicates) - Inherits all interval binning capabilities (clipping, format preservation, etc.)

Algorithm: 1. Sort the data values for each column 2. Calculate quantile positions for n_bins equal-frequency intervals 3. Find actual data values at or near these quantile positions 4. Adjust bin boundaries to handle duplicate values properly 5. Create representative values (typically quantile midpoints)

Parameters:
  • n_bins – Number of bins to create, or string specification like ‘sqrt’, ‘log2’. Can be an integer for exact count or string for automatic calculation. Default value can be configured globally via binlearn.config.

  • quantile_range – Optional (min_quantile, max_quantile) tuple to focus binning on a specific portion of the data distribution. For example, (0.1, 0.9) creates bins only within the 10th-90th percentile range, ignoring outliers.

bin_edges_

Dictionary mapping column identifiers to lists of bin edges after fitting. Edges correspond to quantile boundaries in the data.

bin_representatives_

Dictionary mapping column identifiers to lists of bin representatives (typically quantile midpoints).

Example

>>> import numpy as np
>>> from binlearn.methods import EqualFrequencyBinning
>>>
>>> # Skewed data - exponential distribution
>>> X = np.random.exponential(2, (1000, 1))
>>> binner = EqualFrequencyBinning(n_bins=4)
>>> binner.fit(X)
>>> X_binned = binner.transform(X)
>>> # Each bin contains approximately 250 observations
>>>
>>> # Focus on middle 80% of data, ignoring extreme outliers
>>> binner_focused = EqualFrequencyBinning(n_bins=5, quantile_range=(0.1, 0.9))
>>> binner_focused.fit(X)

Note

  • Works best with continuous numeric data having many unique values

  • May create fewer bins than requested if data has insufficient unique values

  • Duplicate values at quantile boundaries are handled by boundary adjustment

  • Consider the trade-off between bin count and meaningful bin boundaries

  • Inherits clipping behavior and DataFrame preservation from IntervalBinningBase

__init__(n_bins: int | str | None = None, quantile_range: tuple[float, float] | None = None, clip: bool | None = None, preserve_dataframe: bool | None = None, fit_jointly: bool | None = None, *, bin_edges: dict[Any, list[float]] | None = None, bin_representatives: dict[Any, list[float]] | None = None, class_: str | None = None, module_: str | None = None)[source]

Initialize equal frequency binning with configuration and parameters.

Sets up the equal frequency binning method with user-specified parameters and configuration defaults. The method integrates with binlearn’s global configuration system and supports flexible bin count specification.

Parameters:
  • n_bins – Number of equal-frequency bins to create, or string specification for automatic calculation. Can be: - Integer: exact number of bins to create - ‘sqrt’: number of bins = sqrt(n_samples) - ‘log2’: number of bins = log2(n_samples) - ‘sturges’: Sturges’ rule for histogram bins If None, uses global configuration default for ‘equal_frequency’ method.

  • quantile_range – Optional (min_quantile, max_quantile) tuple to focus binning on a specific portion of the data distribution. Values should be between 0.0 and 1.0 with min_quantile < max_quantile. For example, (0.05, 0.95) creates bins within the 5th-95th percentile range, effectively ignoring extreme outliers.

  • clip – Whether to clip out-of-range values to the nearest bin boundary during transformation. If True, values outside the range are assigned to the nearest edge bin. If False, they receive special out-of-range indices. If None, uses global configuration default.

  • preserve_dataframe – Whether to preserve DataFrame format in outputs when input is a DataFrame. If None, uses global configuration default.

  • fit_jointly – Whether to fit all columns together (not applicable for equal frequency binning as it’s inherently per-column). If None, uses global configuration default.

  • bin_edges – Pre-computed bin edges for reconstruction/deserialization. If provided, no fitting is performed and these edges are used directly. Should be a dictionary mapping column identifiers to lists of edge values.

  • bin_representatives – Pre-computed bin representatives for reconstruction. Must be provided together with bin_edges. Should be a dictionary mapping column identifiers to lists of representative values.

  • class – Class name for reconstruction compatibility (ignored during normal initialization).

  • module – Module name for reconstruction compatibility (ignored during normal initialization).

Example

>>> # Basic initialization with automatic bin count
>>> binner = EqualFrequencyBinning(n_bins='sqrt')
>>>
>>> # Fixed number of bins with outlier handling
>>> binner = EqualFrequencyBinning(n_bins=10, quantile_range=(0.1, 0.9))
>>>
>>> # Reconstruction from saved parameters
>>> binner = EqualFrequencyBinning(
...     n_bins=4,
...     bin_edges={'col1': [0.1, 0.3, 0.6, 0.8, 0.95]},
...     bin_representatives={'col1': [0.2, 0.45, 0.7, 0.875]}
... )

Note

  • String n_bins values are resolved during fitting based on data size

  • quantile_range is useful for handling outliers and focusing analysis

  • Pre-computed edges and representatives enable object reconstruction

  • Parameters integrate with binlearn’s global configuration system

classmethod __init_subclass__(**kwargs)

Set the set_{method}_request methods.

This uses PEP-487 [1] to set the set_{method}_request methods. It looks for the information available in the set default values which are set using __metadata_request__* class attributes, or inferred from method signatures.

The __metadata_request__* class attributes are used when a method does not explicitly accept a metadata through its arguments or if the developer would like to specify a request value for those metadata which are different from the default None.

References

static check_data_quality(data: ndarray[Any, Any], name: str = 'data') None

Check data quality and issue warnings if needed.

property feature_names_in_: list[str] | None

Get feature names.

fit(X: Any, y: Any | None = None, **fit_params: Any) GeneralBinningBase

Fit the binning transformer with comprehensive orchestration.

This method orchestrates the complete fitting process, handling parameter validation, input preprocessing, column separation, and routing to the appropriate fitting strategy (joint vs independent).

Parameters:
  • X – Input data to fit the binning transformer on. Can be: - pandas.DataFrame: Column names are preserved - polars.DataFrame: Column names are preserved - numpy.ndarray: Numeric column indices are used - array-like: Converted to numpy array

  • y – Target values for supervised binning methods. Ignored by unsupervised methods. Can be array-like or None.

  • **fit_params – Additional fitting parameters passed to the specific binning algorithm implementation. Common parameters include: - guidance_data: Alternative guidance data (conflicts with fit_jointly=True)

Returns:

The fitted binning transformer instance.

Return type:

self

Raises:
  • ValueError – If parameter validation fails, inputs are invalid, or conflicting parameters are provided (e.g., fit_jointly=True with guidance_data).

  • BinningError – If the binning algorithm fails to fit the data.

  • RuntimeError – If an unexpected error occurs during fitting.

Example

>>> from binlearn import EqualWidthBinning
>>> import pandas as pd
>>> X = pd.DataFrame({'feature1': [1, 2, 3, 4, 5], 'feature2': [10, 20, 30, 40, 50]})
>>> binner = EqualWidthBinning(n_bins=3)
>>> binner.fit(X)
EqualWidthBinning(...)

Note

The method automatically handles column separation when guidance_columns is specified, routing guidance columns separately from binning columns. The fitting strategy (joint vs independent) is determined by the fit_jointly parameter.

fit_transform(X, y=None, **fit_params)

Fit to data, then transform it.

Fits transformer to X and y with optional parameters fit_params and returns a transformed version of X.

Parameters:
  • X (array-like of shape (n_samples, n_features)) – Input samples.

  • y (array-like of shape (n_samples,) or (n_samples, n_outputs), default=None) – Target values (None for unsupervised transformations).

  • **fit_params (dict) – Additional fit parameters.

Returns:

X_new – Transformed array.

Return type:

ndarray array of shape (n_samples, n_features_new)

get_input_columns() list[Any] | None

Get input columns for data preparation.

This method should be overridden by derived classes to provide appropriate column information without exposing binning-specific concepts.

Returns:

Column information or None if not available

get_metadata_routing()

Get metadata routing of this object.

Please check User Guide on how the routing mechanism works.

Returns:

routing – A MetadataRequest encapsulating routing information.

Return type:

MetadataRequest

get_params(deep: bool = True) dict[str, Any]

Get parameters for this estimator, including fitted parameters.

This method extends sklearn’s standard get_params to include fitted parameters when the estimator is fitted, enabling complete object reconstruction through the get_params/set_params interface. This is essential for pipeline persistence and model serialization.

Parameters:

deep – If True, returns parameters for sub-estimators (not applicable here but maintained for sklearn compatibility).

Returns:

  • Constructor parameters extracted from __init__ signature

  • Fitted parameters (if estimator is fitted) mapped from attributes

  • Class metadata (class_, module_) for automatic reconstruction

Return type:

Dictionary of parameter names mapped to their values, including

Example

>>> binner = EqualWidthBinning(n_bins=5)
>>> params = binner.get_params()
>>> print(params)
{'n_bins': 5, 'clip': None, ..., 'class_': 'EqualWidthBinning', 'module_': '...'}
>>>
>>> binner.fit(X)
>>> fitted_params = binner.get_params()
>>> # Now includes: {'bin_edges': {...}, 'bin_representatives': {...}, ...}

Note

  • Automatically extracts constructor parameters from __init__ signature

  • Includes fitted parameters only when estimator is fitted

  • Adds class metadata for reconstruction workflows

  • Excludes internal sklearn attributes like n_features_in_

  • class_ and module_ parameters are handled specially during set_params

inverse_transform(X: Any) Any

Inverse transform from bin indices back to representative values.

Converts discrete bin indices back to their representative values, effectively reversing the binning transformation. This is useful for interpreting results or reconstructing approximate original values.

Parameters:

X – Input data containing bin indices to inverse transform. Should contain only binning columns (no guidance columns). Can be: - pandas.DataFrame: Column names should match binning columns - polars.DataFrame: Column names should match binning columns - numpy.ndarray: Must have same number of binning columns - array-like: Converted to numpy array

Returns:

Inverse transformed data where bin indices are replaced with their representative values (typically bin centers). Output format matches the preserve_dataframe setting.

Raises:
  • RuntimeError – If the transformer has not been fitted yet.

  • ValueError – If input data has wrong number of columns or invalid format.

  • BinningError – If inverse transformation fails.

Example

>>> # After fitting and transforming
>>> X_binned = [[0, 1], [1, 0], [2, 2]]  # Bin indices
>>> X_reconstructed = binner.inverse_transform(X_binned)
>>> print(X_reconstructed)
[[0.5, 1.5], [1.5, 0.5], [2.5, 2.5]]  # Representative values

Note

For guided binning (when guidance_columns is specified), the input should only contain the binning columns, not the guidance columns. The number of input columns must match the number of binning columns.

property n_features_in_: int

Get number of features.

set_output(*, transform=None)

Set output container.

See Introducing the set_output API for an example on how to use the API.

Parameters:

transform ({"default", "pandas", "polars"}, default=None) –

Configure output of transform and fit_transform.

  • ”default”: Default output format of a transformer

  • ”pandas”: DataFrame output

  • ”polars”: Polars output

  • None: Transform configuration is unchanged

Added in version 1.4: “polars” option was added.

Returns:

self – Estimator instance.

Return type:

estimator instance

set_params(**params: Any) SklearnIntegrationBase

Set the parameters of this estimator.

This method supports reconstruction workflows by handling fitted parameters that come from get_params() output (without underscores) and setting them as fitted attributes (with underscores).

Parameters:

**params – Parameters to set. Can include: - Regular constructor parameters (n_bins, clip, etc.) - Fitted parameters from get_params (bin_edges, bin_representatives) - Class metadata (ignored during reconstruction)

Returns:

Returns the instance itself.

Return type:

self

transform(X: Any) Any

Transform input data using fitted binning parameters.

Applies the fitted binning transformation to new data, converting continuous values to discrete bin indices or representatives. Handles column separation when guidance columns are present.

Parameters:

X – Input data to transform. Must have the same structure as the data used during fitting (same number of columns). Can be: - pandas.DataFrame: Column names should match training data - polars.DataFrame: Column names should match training data - numpy.ndarray: Must have same number of columns as training - array-like: Converted to numpy array

Returns:

Transformed data where continuous values are replaced with bin indices or representative values. The output format depends on: - preserve_dataframe setting: DataFrame vs array format - binning method: indices vs representatives - guidance_columns: only binning columns are transformed

Raises:
  • RuntimeError – If the transformer has not been fitted yet.

  • ValueError – If the input data has incompatible structure or format.

  • BinningError – If transformation fails due to data issues.

Example

>>> # After fitting
>>> X_new = pd.DataFrame({'feature1': [1.5, 2.5], 'feature2': [15, 25]})
>>> X_binned = binner.transform(X_new)
>>> print(X_binned)
[[0, 0], [1, 1]]  # Bin indices

Note

When guidance_columns is specified, only the binning columns are transformed. Guidance columns are filtered out from the output. The method preserves the original data format when preserve_dataframe=True.

static validate_array_like(data: Any, name: str = 'data', allow_none: bool = False) ndarray[Any, Any] | None

Validate and convert array-like input to numpy array.

This method provides robust validation and conversion of various input formats to numpy arrays, with comprehensive error handling and helpful suggestions for common issues.

Parameters:
  • data – Input data to validate and convert. Can be: - numpy.ndarray: Used directly - pandas.DataFrame/Series: Converted to numpy array - polars.DataFrame: Converted to numpy array - list, tuple: Converted to numpy array - None: Allowed only if allow_none=True

  • name – Name of the data parameter for error messages. Used to provide context in error messages (e.g., “X”, “y”, “guidance_data”).

  • allow_none – Whether to allow None as a valid input. If True, None is returned unchanged; if False, None raises InvalidDataError.

Returns:

Validated numpy array, or None if data is None and allow_none=True. The returned array maintains the same data content but is guaranteed to be a numpy array.

Raises:

InvalidDataError – If validation fails: - data is None when allow_none=False - data cannot be converted to numpy array - Conversion process encounters errors

Example

>>> # Valid inputs
>>> arr = ValidationMixin.validate_array_like([1, 2, 3], "X")
>>> print(type(arr))
<class 'numpy.ndarray'>
>>>
>>> # Allow None
>>> result = ValidationMixin.validate_array_like(None, "y", allow_none=True)
>>> print(result)
None
>>>
>>> # Invalid input
>>> ValidationMixin.validate_array_like(None, "X", allow_none=False)
InvalidDataError: X cannot be None

Note

This method focuses on format validation and conversion. Content validation (like checking for NaN values) should be done separately using other validation methods.

static validate_column_specification(columns: Any, data_shape: tuple[int, ...]) list[Any]

Validate column specifications.

static validate_guidance_columns(guidance_cols: Any, binning_cols: list[Any], data_shape: tuple[int, ...]) list[Any]

Validate guidance column specifications.

Examples

Basic Usage

import numpy as np
from binlearn.methods import EqualFrequencyBinning

# Create skewed sample data
np.random.seed(42)
X = np.random.exponential(2, (1000, 3))  # Exponentially distributed data

# Create equal-frequency binner
binner = EqualFrequencyBinning(n_bins=4)
X_binned = binner.fit_transform(X)

print(f"Original shape: {X.shape}")
print(f"Binned shape: {X_binned.shape}")

# Check bin counts (should be approximately equal)
unique, counts = np.unique(X_binned[:, 0], return_counts=True)
print(f"Bin counts for feature 0: {counts}")

Comparison with Equal-Width

import matplotlib.pyplot as plt
from binlearn.methods import EqualWidthBinning, EqualFrequencyBinning

# Highly skewed data
X_skewed = np.random.lognormal(0, 2, (5000, 1))

# Equal-width binning
ew_binner = EqualWidthBinning(n_bins=5)
X_ew_binned = ew_binner.fit_transform(X_skewed)

# Equal-frequency binning
ef_binner = EqualFrequencyBinning(n_bins=5)
X_ef_binned = ef_binner.fit_transform(X_skewed)

# Compare bin distributions
ew_counts = np.bincount(X_ew_binned.astype(int).flatten())
ef_counts = np.bincount(X_ef_binned.astype(int).flatten())

print("Equal-width bin counts:", ew_counts)
print("Equal-frequency bin counts:", ef_counts)

# Visualize the difference
fig, axes = plt.subplots(1, 3, figsize=(15, 5))

axes[0].hist(X_skewed, bins=50, alpha=0.7)
axes[0].set_title('Original Data Distribution')

axes[1].hist(X_ew_binned, bins=5, alpha=0.7, color='red')
axes[1].set_title('Equal-Width Binning')

axes[2].hist(X_ef_binned, bins=5, alpha=0.7, color='green')
axes[2].set_title('Equal-Frequency Binning')

plt.tight_layout()
plt.show()

With DataFrame

import pandas as pd

# Create DataFrame with different distributions
df = pd.DataFrame({
    'normal': np.random.normal(50, 15, 1000),
    'exponential': np.random.exponential(5, 1000),
    'uniform': np.random.uniform(0, 100, 1000)
})

# Apply equal-frequency binning
binner = EqualFrequencyBinning(n_bins=4, preserve_dataframe=True)
df_binned = binner.fit_transform(df)

# Check that each bin has approximately equal frequency
for column in df.columns:
    counts = df_binned[column].value_counts().sort_index()
    print(f"\n{column} bin counts:")
    print(counts)