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