chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from shap.utils import hclust
|
||||
from shap.utils._exceptions import DimensionError
|
||||
|
||||
|
||||
@pytest.mark.parametrize("linkage", ["single", "complete", "average"])
|
||||
def test_hclust_runs(linkage):
|
||||
# GH #3290
|
||||
pytest.importorskip("xgboost")
|
||||
X = np.column_stack((np.arange(1, 10), np.arange(100, 1000, step=100)))
|
||||
y = np.where(X[:, 0] > 5, 1, 0)
|
||||
|
||||
# just check if clustered ran successfully (using xgboost_distances_r2)
|
||||
clustered = hclust(X, y, linkage=linkage, random_state=0)
|
||||
assert isinstance(clustered, np.ndarray)
|
||||
assert clustered.shape == (1, 4)
|
||||
|
||||
# Check clustering runs if y=None (using scipy metrics)
|
||||
clustered = hclust(X, linkage=linkage, random_state=0)
|
||||
assert isinstance(clustered, np.ndarray)
|
||||
assert clustered.shape == (1, 4)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"X",
|
||||
[
|
||||
np.arange(1, 10),
|
||||
list(range(1, 10)),
|
||||
],
|
||||
)
|
||||
def test_hclust_errors_on_input_shapes(X):
|
||||
# hclust only accepts 2-d arrays for X
|
||||
with pytest.raises(DimensionError):
|
||||
hclust(X, random_state=0)
|
||||
|
||||
|
||||
def test_hclust_errors_on_unknown_linkages():
|
||||
X = np.column_stack((np.arange(1, 10), np.arange(100, 1000, step=100)))
|
||||
with pytest.raises(ValueError, match=r"Unknown linkage type:"):
|
||||
hclust(X, linkage="random-string", random_state=0) # type: ignore
|
||||
@@ -0,0 +1,124 @@
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pytest
|
||||
import scipy.sparse as ssp
|
||||
|
||||
import shap
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"arr",
|
||||
[
|
||||
np.arange(100),
|
||||
["zz"] * 100,
|
||||
pd.Series(range(100), name="test"),
|
||||
pd.DataFrame(np.random.RandomState(0).randn(100, 2), columns=["a", "b"]),
|
||||
],
|
||||
)
|
||||
def test_sample_basic(arr):
|
||||
"""Tests the basic functionality of `sample()` on a variety of array-like objects."""
|
||||
new_arr = shap.utils.sample(arr, 30, random_state=42)
|
||||
assert len(new_arr) == 30
|
||||
|
||||
|
||||
def test_sample_basic_sparse():
|
||||
"""Tests the basic functionality of `sample()` on sparse objects."""
|
||||
arr = ssp.csr_matrix((100, 3), dtype=np.int8)
|
||||
new_arr = shap.utils.sample(arr, 30, random_state=42)
|
||||
assert new_arr.shape[0] == 30
|
||||
|
||||
|
||||
def test_sample_no_op():
|
||||
"""Ensures that `sample()` is a no-op when numsamples is larger
|
||||
than the size of X.
|
||||
"""
|
||||
arr = np.arange(50)
|
||||
new_arr = shap.utils.sample(arr, 100, random_state=42)
|
||||
|
||||
assert len(arr) == len(new_arr)
|
||||
|
||||
|
||||
def test_sample_sampling_without_replacement():
|
||||
"""Ensures that `sample()` is performing sampling without replacement.
|
||||
|
||||
See GH dsgibbons#36.
|
||||
"""
|
||||
arr = np.arange(100)
|
||||
new_arr = shap.utils.sample(arr, 99, random_state=0)
|
||||
|
||||
assert len(new_arr) == 99
|
||||
assert len(np.unique(new_arr)) == 99
|
||||
|
||||
|
||||
def test_sample_can_be_zipped():
|
||||
"""Ensures that the sampling is done via indexing.
|
||||
|
||||
That is, sampling X and y separately would give the same result as sampling
|
||||
concat(X, y), up to a random state. Our `datasets` module relies on
|
||||
this behaviour.
|
||||
"""
|
||||
arr1 = pd.Series(np.arange(100))
|
||||
arr2 = pd.Series(np.repeat(np.arange(25), 4))
|
||||
combined = pd.DataFrame(
|
||||
{
|
||||
"arr1": arr1,
|
||||
"arr2": arr2,
|
||||
}
|
||||
)
|
||||
|
||||
new_arr1 = shap.utils.sample(arr1, 75, random_state=42)
|
||||
new_arr2 = shap.utils.sample(arr2, 75, random_state=42)
|
||||
new_combined = shap.utils.sample(combined, 75, random_state=42)
|
||||
|
||||
assert (new_arr1 == new_combined["arr1"]).all()
|
||||
assert (new_arr2 == new_combined["arr2"]).all()
|
||||
|
||||
|
||||
def test_opchain_repr():
|
||||
"""Ensures OpChain repr is working properly"""
|
||||
opchain = (
|
||||
shap.utils.OpChain("shap.DummyExplanation")
|
||||
.foo.foo(0, "big_blue_bear")
|
||||
.foo(0, v1=10)
|
||||
.foo(k1="alpha", k2="beta")
|
||||
.baz
|
||||
)
|
||||
expected_repr = "shap.DummyExplanation.foo.foo(0, 'big_blue_bear').foo(0, v1=10).foo(k1='alpha', k2='beta').baz"
|
||||
|
||||
assert repr(opchain) == expected_repr
|
||||
|
||||
|
||||
def test_format_value_empty_string():
|
||||
"""Tests that format_value() handles empty strings without raising IndexError."""
|
||||
# Test with empty string
|
||||
result = shap.utils._general.format_value("", "%0.03f")
|
||||
assert result == ""
|
||||
|
||||
|
||||
def test_format_value_negative_number():
|
||||
"""Tests that format_value() correctly formats negative numbers with unicode minus sign."""
|
||||
result = shap.utils._general.format_value(-1.5, "%0.03f")
|
||||
assert result == "\u2212" + "1.5"
|
||||
|
||||
|
||||
def test_format_value_positive_number():
|
||||
"""Tests that format_value() correctly formats positive numbers."""
|
||||
result = shap.utils._general.format_value(1.5, "%0.03f")
|
||||
assert result == "1.5"
|
||||
|
||||
|
||||
def test_format_value_trailing_zeros():
|
||||
"""Tests that format_value() removes trailing zeros."""
|
||||
result = shap.utils._general.format_value(1.5000, "%0.03f")
|
||||
assert result == "1.5"
|
||||
|
||||
|
||||
def test_format_value_string_input():
|
||||
"""Tests that format_value() handles string inputs correctly."""
|
||||
# Test with non-empty string
|
||||
result = shap.utils._general.format_value("test_string", "%0.03f")
|
||||
assert result == "test_string"
|
||||
|
||||
# Test with string that starts with minus
|
||||
result = shap.utils._general.format_value("-123", "%0.03f")
|
||||
assert result == "\u2212" + "123"
|
||||
@@ -0,0 +1,18 @@
|
||||
import numpy as np
|
||||
|
||||
from shap.links import identity
|
||||
from shap.utils._masked_model import _build_fixed_output
|
||||
|
||||
|
||||
def test__build_fixed_output():
|
||||
"""GH3651"""
|
||||
num_varying_rows = np.array([1])
|
||||
varying_rows = np.array([[True]])
|
||||
batch_positions = np.array([0, 1])
|
||||
averaged_outs = np.zeros((1, 10), dtype=np.float32)
|
||||
last_outs = np.zeros((1, 10), dtype=np.float32)
|
||||
outputs = np.random.rand(1, 10).astype(np.float16)
|
||||
_build_fixed_output(
|
||||
averaged_outs, last_outs, outputs, batch_positions, varying_rows, num_varying_rows, identity, None
|
||||
)
|
||||
assert np.allclose(averaged_outs, outputs, 1e-2)
|
||||
Reference in New Issue
Block a user