项目文件夹

文件
2026-07-13 13:22:52 +08:00

208 行
6.1 KiB
Python

"""Tests for maskers through public explainer APIs.
These tests exercise masker functionality by using public explainers like
shap.Explainer, shap.KernelExplainer, etc., which internally use maskers.
"""
import numpy as np
import shap
def test_masker_with_kernel_explainer():
"""Test masker functionality through KernelExplainer (public API)."""
# Create simple model
def model(x):
return np.sum(x, axis=1)
# Create background data for masker
background = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]])
# KernelExplainer uses Independent masker internally
explainer = shap.KernelExplainer(model, background)
# Test data
test_data = np.array([[1, 2, 3]])
# This exercises masker's __call__ with various masks
shap_values = explainer.shap_values(test_data, nsamples=10)
assert shap_values is not None
assert shap_values.shape == (1, 3)
def test_independent_masker_with_kernel_explainer():
"""Test Independent masker through KernelExplainer."""
def model(x):
return np.sum(x, axis=1)
background = np.array([[0, 0, 0], [1, 1, 1]])
# KernelExplainer creates Independent masker internally from data
explainer = shap.KernelExplainer(model, background)
test_data = np.array([[1, 2, 3]])
shap_values = explainer.shap_values(test_data, nsamples=10)
assert shap_values is not None
assert shap_values.shape == (1, 3)
def test_independent_masker_basic():
"""Test Independent masker basic functionality."""
background = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]])
masker = shap.maskers.Independent(background)
# Test shape
assert masker.shape == (3, 3)
# Test with True mask (should select all features)
result = masker(True, background[0])
assert isinstance(result, tuple)
def test_independent_masker_with_false_mask():
"""Test Independent masker with False mask."""
background = np.array([[0, 0], [1, 1], [2, 2]])
masker = shap.maskers.Independent(background)
# False mask should select no features
result = masker(False, background[0])
assert isinstance(result, tuple)
def test_independent_masker_with_partial_mask():
"""Test Independent masker with partial mask array."""
background = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]])
masker = shap.maskers.Independent(background)
# Partial mask - select first two features
mask = np.array([True, True, False])
result = masker(mask, np.array([5, 6, 7]))
assert isinstance(result, tuple)
assert len(result) == 1
# Should return background samples with first two features from input
assert result[0].shape[0] == 3 # Same as background rows
def test_partition_masker_basic():
"""Test Partition masker basic functionality."""
background = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]])
masker = shap.maskers.Partition(background)
# Test with True mask
result = masker(True, background[0])
assert isinstance(result, tuple)
def test_partition_masker_with_false_mask():
"""Test Partition masker with False mask."""
background = np.array([[0, 0], [1, 1]])
masker = shap.maskers.Partition(background)
result = masker(False, background[0])
assert isinstance(result, tuple)
def test_masker_with_explainer_auto_detection():
"""Test that Explainer auto-detects and uses appropriate masker."""
def model(x):
return np.sum(x, axis=1)
background = np.array([[0, 0, 0], [1, 1, 1]])
# Explainer should auto-select masker based on model and data
explainer = shap.Explainer(model, background)
test_data = np.array([[1, 2, 3]])
# This internally uses maskers
shap_values = explainer(test_data)
assert shap_values is not None
assert isinstance(shap_values, shap.Explanation)
assert shap_values.values.shape == (1, 3)
def test_independent_masker_clustering():
"""Test that Independent masker has clustering attribute."""
background = np.array([[0, 0, 0], [1, 1, 1]])
masker = shap.maskers.Independent(background)
# Should have clustering attribute
assert hasattr(masker, "clustering")
def test_partition_masker_clustering():
"""Test that Partition masker has clustering attribute."""
background = np.array([[0, 0, 0], [1, 1, 1]])
masker = shap.maskers.Partition(background)
# Should have clustering attribute
assert hasattr(masker, "clustering")
def test_independent_masker_shape_property():
"""Test Independent masker shape property with different data sizes."""
# 5 samples, 4 features
background = np.random.rand(5, 4)
masker = shap.maskers.Independent(background)
assert masker.shape == (5, 4)
def test_partition_masker_with_clustering():
"""Test Partition masker with explicit clustering."""
background = np.array([[0, 0, 0, 0], [1, 1, 1, 1]])
# Partition masker can take clustering parameter
masker = shap.maskers.Partition(background, clustering="correlation")
assert hasattr(masker, "clustering")
def test_composite_masker_with_independent_maskers():
"""Test Composite masker combining Independent maskers."""
background1 = np.array([[0, 0], [1, 1]])
background2 = np.array([[2, 2, 2], [3, 3, 3]])
masker1 = shap.maskers.Independent(background1)
masker2 = shap.maskers.Independent(background2)
composite = shap.maskers.Composite(masker1, masker2)
# Shape should be sum of both
shape = composite.shape(background1[0], background2[0])
assert shape == (2, 5) # 2 rows (min), 2+3 = 5 cols
def test_independent_masker_with_varying_masks():
"""Test Independent masker with different mask patterns."""
background = np.array([[0, 0, 0, 0], [1, 1, 1, 1], [2, 2, 2, 2]])
masker = shap.maskers.Independent(background)
# All True
result = masker(np.ones(4, dtype=bool), np.array([5, 6, 7, 8]))
assert result[0].shape == (3, 4)
# All False
result = masker(np.zeros(4, dtype=bool), np.array([5, 6, 7, 8]))
assert result[0].shape == (3, 4)
# Alternating
result = masker(np.array([True, False, True, False]), np.array([5, 6, 7, 8]))
assert result[0].shape == (3, 4)