Getting started¶
This page gets you from zero to a working Shapley vs Banzhaf comparison in a few minutes.
Installation¶
Install from PyPI:
pip install nlp-shap
From a local clone (requires uv):
git clone https://github.com/Pawlo77/nlp-shap
cd nlp-shap
make install
Your first aggregation¶
The estimand aggregators take boolean coalition masks and aligned payoffs \(v(S)\). On a three-player majority game, Shapley and Banzhaf disagree:
from itertools import product
from nlp_shap import BanzhafAggregator, 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]
Explain a short prompt¶
For end-to-end token attributions, build a
ConversationSnapshot, load an
ExplainConfig, and call ExplainRunner:
from nlp_shap import ExplainConfig, ExplainRunner
from nlp_shap.domain.conversation import ConversationSnapshot, Message, Turn
from nlp_shap.domain.enums import Role
snapshot = ConversationSnapshot.from_turns((
Turn(messages=(Message(role=Role.USER, text="refund my order"),)),
))
config = ExplainConfig.model_validate({
"backend": {"kind": "mock", "model_id": "stub"},
"explanation": {
"estimator": "exact",
"value_fn": "tfidf_cosine",
"absence_policy": "pad",
},
})
output = ExplainRunner(config).explain_sync(snapshot)
print(output.result.values)
Output
(-0.3201357760454475, -0.06610412816763576, -0.12182339154254021)
Label results for archives¶
When you persist explain outputs, record which estimand was used:
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")
restored = parse_manifest(manifest.to_dict())
print("estimand:", restored.estimand.value)
print("run_id:", restored.run_id)
Output
estimand: shapley
run_id: run-42
Next steps¶
Using estimand aggregators — coalition weights, manifests, and wire types
Shapley values and axioms — Shapley axioms and uniqueness
Estimands: Shapley vs Banzhaf — why Shapley and Banzhaf differ
Business and compliance applications — business and compliance use cases
Examples — estimands_toy_game.ipynb, masking_views.ipynb, runtime_core.ipynb, and exact_estimation.ipynb
End-to-end explain pipeline —
ExplainRunnerend-to-end explain flowExtending nlp-shap — optional extras and plugin entry points
Masking views — coalition masking and absence policies
Runtime core — archive persistence, dedup, and async scheduling
Using the exact estimator — exact coalition enumeration and estimand wiring
API reference — module reference