Using estimand aggregators

The nlp_shap.estimation.estimands package provides estimand aggregators that turn coalition masks and payoffs \(v(S)\) into per-player attributions. Each aggregator reports which estimand it implements.

Quick start

from itertools import product

from nlp_shap import BanzhafAggregator, Estimand, ShapleyAggregator

num_players = 3
masks = [tuple(bits) for bits in product([False, True], repeat=num_players)]

def majority_payoff(mask: tuple[bool, ...]) -> float:
    return 1.0 if sum(mask) >= 2 else 0.0

payoffs = [majority_payoff(mask) for mask in masks]

shapley = ShapleyAggregator().aggregate(masks, payoffs)
banzhaf = BanzhafAggregator().aggregate(masks, payoffs)

print("Shapley:", shapley)
print("Banzhaf:", banzhaf)

Output

Shapley: [0.3333333333333333, 0.3333333333333333, 0.3333333333333333]
Banzhaf: [0.5, 0.5, 0.5]

Coalition weights

Inspect weights without full aggregation:

from nlp_shap import ShapleyAggregator, BanzhafAggregator

shapley = ShapleyAggregator()
banzhaf = BanzhafAggregator()

n = 4
for k in range(n):
    print(f"k={k}", shapley.coalition_weight(k, n), banzhaf.coalition_weight(k, n))

Output

k=0 0.25 0.125
k=1 0.083333 0.125
k=2 0.083333 0.125
k=3 0.25 0.125

Explain results and manifests

Label outputs explicitly for archives and papers:

from nlp_shap import Estimand, ExplainResult, RunManifest, parse_manifest

result = ExplainResult(
    estimand=Estimand.SHAPLEY,
    values=(0.333, 0.333, 0.333),
)

manifest = RunManifest(estimand=result.estimand, run_id="run-42")
payload = manifest.to_dict()
restored = parse_manifest(payload)
print("estimand:", restored.estimand.value)
print("run_id:", restored.run_id)

Output

estimand: shapley
run_id: run-42

Wire values for JSON manifests use EstimandWire ("shapley" | "banzhaf").

Notebook

See the runnable walkthrough in Examplesexamples/estimands_toy_game.ipynb.

Further reading