Source code for nlp_shap.estimation.normalizers
"""Post-aggregation attribution normalizers."""
from collections.abc import Sequence
import numpy as np
[docs]
class IdentityNormalizer:
"""Return attributions unchanged."""
@property
def name(self) -> str:
"""Return the registered normalizer identifier."""
return "identity"
[docs]
def normalize(self, values: Sequence[float]) -> list[float]:
"""Return a copy of ``values``."""
return list(values)
[docs]
class AbsSumNormalizer:
"""Scale attributions by the sum of absolute values."""
@property
def name(self) -> str:
"""Return the registered normalizer identifier."""
return "abs_sum"
[docs]
def normalize(self, values: Sequence[float]) -> list[float]:
"""Return ``values`` divided by the sum of absolute entries."""
array = np.asarray(values, dtype=np.float64)
abs_sum = float(np.abs(array).sum())
if abs_sum == 0.0:
return list(values)
normalized = array / abs_sum
return [float(value) for value in normalized]
[docs]
class PowerShiftNormalizer:
"""Shift to non-negative values, apply a power, then scale to sum one."""
def __init__(self, power: float = 1.0) -> None:
if power <= 0.0:
msg = "power must be a positive float"
raise ValueError(msg)
self.power = power
@property
def name(self) -> str:
"""Return the registered normalizer identifier."""
return "power_shift"
[docs]
def normalize(self, values: Sequence[float]) -> list[float]:
"""Return power-shift normalized attributions."""
array = np.asarray(values, dtype=np.float64)
shifted = array - array.min()
powered = np.power(shifted, self.power)
total = float(powered.sum())
if total == 0.0:
return list(values)
normalized = powered / total
return [float(value) for value in normalized]
[docs]
class MinMaxNormalizer:
"""Min-max scale to ``[0, 1]`` then normalize to sum one."""
@property
def name(self) -> str:
"""Return the registered normalizer identifier."""
return "min_max"
[docs]
def normalize(self, values: Sequence[float]) -> list[float]:
"""Return min-max scaled attributions that sum to one."""
array = np.asarray(values, dtype=np.float64)
min_val = float(array.min())
max_val = float(array.max())
if max_val - min_val == 0.0:
uniform = np.ones_like(array) / len(array)
return [float(value) for value in uniform]
scaled = (array - min_val) / (max_val - min_val)
total = float(scaled.sum())
normalized = scaled / total
return [float(value) for value in normalized]