Low SHAP values when applying SHAP model explanation on time series classification using ROCKET

138 views Asked by At

I´m using a ROCKET transformer + RidgeClassifierCV (https://www.sktime.net/en/stable/api_reference/auto_generated/sktime.classification.kernel_based.RocketClassifier.html) for multivariate time series classification. The model works quit well on my data (predictions are precise and as expected). Additionally, in order to make the model decisions explainable, I want to use SHAP (https://shap-lrjball.readthedocs.io/en/latest/examples.html#general) for model explanation.

As I found in the docs of the sktime module, there is no direct SHAP implementation for ROCKET but a workaround (https://gist.github.com/varelasaraiva/fd16a3108a5bb1ae47b27443ca20933f) which works so far. However, when applying this workaround to my data, I get very low SHAP values in general (max. of around 0.015). To check if this problem was due to my specific data, I applied this approach to two example datasets from sktime as shown below:

Import first example dataset (basic_motions):

# Example Datset basic_motions
from sktime.datasets import load_basic_motions
X, y = load_basic_motions(return_X_y=True)

# Select train and test by hand
X_train = X[0:55]
y_train = y[0:55]

X_test = X[56:89]
y_test = y[56:89]

Import second example dataset (unit_test):

# Example Dataset unit_test
from sktime.datasets import load_unit_test
X_train, y_train = load_unit_test(split="train", return_X_y=True)
X_test, y_test = load_unit_test(split="test", return_X_y=True)

Then I transformed X_train and X_test into a 3D-numpy array (3D-array format is needed as input format for the SHAP- workaround):

# Transform X_train etc. into 3D numpy array
from sktime.datatypes import convert_to
X_train_3d = convert_to(X_train, to_type="numpy3D")
X_test_3d = convert_to(X_test, to_type="numpy3D")

After that the workaround is defined (regarding to https://gist.github.com/varelasaraiva/fd16a3108a5bb1ae47b27443ca20933f) as following:

# Define Explanation Function
def mvts_shap(X_train, X_test, y_train, y_test):
    
    # Encode string labels to integers
    label_encoder = LabelEncoder()
    y_train_encoded = label_encoder.fit_transform(y_train)
    y_test_encoded = label_encoder.transform(y_test)
    
    i, j, k = X_train.shape
    u, v, w = X_test.shape
    
    X_train_flat = X_train.reshape(i, j*k)
    
    def reshaper(inner_tensor):
        return inner_tensor.reshape(inner_tensor.shape[0], j, k)

    def inv_reshaper(inner_tensor):
        return inner_tensor.reshape(inner_tensor.shape[0], j*k)

    param = {
            'objective': 'binary:logistic',
            'tree_method': 'hist',
            'eval_metric': 'logloss',
            'seed': 888,
            'n_estimators': 500
           }

    pipe = Pipeline([
        ('reshaper_t', FunctionTransformer(reshaper, inverse_func=inv_reshaper)),
        ('tabulariser', MiniRocketMultivariate(num_kernels=588, n_jobs=-1, random_state=1837)),
        ('bst', xgb.XGBClassifier(**param))
    ])
    
    pipe.fit(X_train_flat, y_train_encoded)
    
    # Take only n random samples from training data
    masker = shap.maskers.Independent(X_train_flat, 55) #10 
    
    # Define Explainer
    explainer = shap.KernelExplainer(pipe.predict_proba, masker.data)   
    
    # Explanation on Full test data
    shap_output = explainer.shap_values(X_test.reshape(u, v*w))

    shap_tensor = shap_output[1].reshape(u, v, w)        
    
    return shap_tensor

I then applied the mvts_shap function to both datasets:

# apply mvts_shap function to data
shap_values = mvts_shap(X_train_3d, X_test_3d, y_train, y_test)

When applying to the basic_motions dataset, I get roughly the same low shap values (max = 0.062) like for my data. When I apply the same approach to the unit_test dataset, the SHAP values are significantly higher (max = 0.286).

Does anyone have an idea if the problem is due to the workaround of applying SHAP to ROCKET or if it is due to the specific data (and ROCKET in combination with SHAP is somehow limited to certain data characteristics)?

The main difference between the unit_test and basic_motions datasets is that the unit_test dataset contains only one variable. To check for this difference, I additionally tried the basic_motions with only one feature column, but got the same low SHAP values.

0

There are 0 answers