normalize

mcda.normalize

Rescale a tool by metric score matrix to [0, 1], respecting polarity.

The pipeline picks one strategy per metric column from the card field comparability.recommended_normalization. Each strategy answers a different failure mode of plain min-max scaling:

  • min_max: linear rescale between the declared bounds, or the column extrema when a bound is missing. Simple, but one outlier sets the scale and the metric’s meaningful zero is mapped to the column midpoint.
  • log_min_max: min-max on the natural log of the column. For ratio metrics whose values span orders of magnitude (runtime, peak memory) this keeps the multiplicative structure, so a single slow method no longer compresses the differences among the fast ones (Smith 1988). Requires strictly positive values.
  • rank: map the within-column position to [0, 1]. Scale-free and immune to outliers; it keeps the order of the methods but drops the size of the gaps between them.
  • zscore: standardize the column, then pass it through the logistic so the result is bounded in (0, 1). The mean method maps to 0.5 and an outlier is compressed smoothly instead of setting the scale.
  • baseline_relative: rescale relative to a declared reference score (the chance-level value of a corrected-for-chance metric), so a method no better than chance maps to 0 rather than to the column midpoint. Defined for higher-is-better metrics only.
  • target_relative: rescale closeness to a declared target value, for a metric whose ideal is neither the highest nor the lowest score but a fixed point (polarity target_value). The absolute deviation from the target is min-max scaled with inverted polarity, so the method nearest the target maps to 1 and the farthest to 0. This is the distance-to-a- reference normalization of the OECD composite-indicators handbook (2008). Requires the card to declare semantics.target.

normalization_warnings is the matching guard. It flags min-max columns that rest on an empirical bound (not comparable across method sets) or that are heavy-tailed (one outlier dominates the rescale).

Functions

Name Description
min_max_normalize Min-max normalize every column of scores to [0, 1].
normalization_warnings Flag min-max columns whose rescale is fragile.
normalize Rescale each column of scores to [0, 1] under a per-column strategy.

min_max_normalize

mcda.normalize.min_max_normalize(scores, polarity, bounds=None)

Min-max normalize every column of scores to [0, 1].

Thin wrapper over normalize with the min_max strategy on every column. Higher-is-better columns map to (x - lo) / (hi - lo); lower-is-better columns map to (hi - x) / (hi - lo); a zero-range column maps to 0.5. When bounds declares both ends, observations outside the range raise.

Parameters

Name Type Description Default
scores np.ndarray 2D array, shape (n_tools, n_metrics). required
polarity Sequence[str] One "higher_is_better" or "lower_is_better" per column. required
bounds Sequence[Bound] | None Optional per-column (lower, upper); either can be None to fall back to the empirical extremum for that side. None

Returns

Type Description
2D array of the same shape, every column in [0, 1].

normalization_warnings

mcda.normalize.normalization_warnings(scores, strategies, bounds=None, metric_ids=None, heavy_tail_ratio=_HEAVY_TAIL_RATIO)

Flag min-max columns whose rescale is fragile.

Two checks, applied only to columns using the min_max strategy:

  1. Empirical bound. If a declared bound is missing on either side, the column max or min sets the scale, so the normalized values change when the method set changes. This breaks comparability across runs and across an incrementally built leaderboard.
  2. Heavy tail. If the positive values span more than heavy_tail_ratio between their maximum and their median, one outlier compresses the rest toward a single value and erases real differences. The message points at log_min_max or rank.

Returns a list of human-readable strings, empty when nothing is flagged.

normalize

mcda.normalize.normalize(scores, polarity, strategies, bounds=None, baselines=None, targets=None)

Rescale each column of scores to [0, 1] under a per-column strategy.

Parameters

Name Type Description Default
scores np.ndarray 2D array, shape (n_tools, n_metrics). required
polarity Sequence[str] One "higher_is_better", "lower_is_better" or "target_value" per column. A target_value column must use the target_relative strategy and no other. required
strategies Sequence[str] One entry per column, each from STRATEGIES. required
bounds Sequence[Bound] | None Optional per-column (lower, upper) declared range. Used by min_max and baseline_relative and for the out-of-range check applied to every strategy. log_min_max, rank and zscore set their own anchors from the data. None
baselines Sequence[float | None] | None Optional per-column reference score required by baseline_relative. None
targets Sequence[float | None] | None Optional per-column ideal value required by target_relative. None

Returns

Type Description
2D array of the same shape, every column in [0, 1].