<jupyter_start><jupyter_text>COVID-19 and ACE inhibitors**This example does not use actual COVID-19 data and does not offer medical advice.**This notebook shows how to test whether ACI inhibitors explain higher mortality from COVID-19 among hypertensive patients.Suppose we have a machine learning model which predicts COVID-19 mortality based on a patient's characteristics. We can use generalized SHAP values to ask what variables lead our model to predict higher mortality rates for hypertensive patients.<jupyter_code>import gshap
from gshap.datasets import load_recidivism
from gshap.intergroup import IntergroupDifference, absolute_mean_distance

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC

import multiprocessing as mp<jupyter_output><empty_output><jupyter_text>Without access to a COVID-19 dataset, I load a recidivism dataset and rename the variables.<jupyter_code>recidivism = load_recidivism()
X, y = recidivism.data, recidivism.target
X = X.rename(columns={'black': 'hypertensive', 'age': 'ACE_inhibitor'})
y = y.rename('mortality')
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1000)
clf = SVC()
clf.fit(X_train, y_train)
print('Test score: %.4f' % clf.score(X_test, y_test))<jupyter_output>Test score: 0.6750<jupyter_text>Our model predicts higher mortality rates for hypertensive patients.<jupyter_code>df = pd.concat((X_test, y_test), axis=1)
df['y_pred'] = clf.predict(X_test)
p_non_hyper, p_hyper = df.groupby('hypertensive')['y_pred'].mean()
print('Predicted mortality rate for non-hypertensive patients: {0:.0f}%'.format(100*p_non_hyper))
print('Predicted mortality rate for hypertensive patients: {0:.0f}%'.format(100*p_hyper))
print('Absolute difference: {0:.0f} percentage points'.format(100*(p_hyper - p_non_hyper)))<jupyter_output>Predicted mortality rate for non-hypertensive patients: 40%
Predicted mortality rate for hypertensive patients: 61%
Absolute difference: 21 percentage points<jupyter_text>We now ask how many percentage points of the difference in mortality rates is explained by ACE inhibitors.<jupyter_code>g = IntergroupDifference(group=X_test['hypertensive'], distance=absolute_mean_distance)
explainer = gshap.KernelExplainer(clf.predict, X_train, g)
gshap_value = explainer.gshap_value('ACE_inhibitor', X_test, nsamples=32)
print('Difference in mortality rates explained by ACE inhibitors: {0:.0f} percentage points'.format(100*gshap_value))<jupyter_output>Difference in mortality rates explained by ACE inhibitors: 5 percentage points<jupyter_text>Additionally, we can use bootstrapping to run hypothesis tests and obtain confidence bounds.<jupyter_code>bootstrap_samples = 200

def bootstrap_gshap_values(output):
    sample = X_test.sample(len(X_test), replace=True)
    g = IntergroupDifference(group=sample['hypertensive'], distance=absolute_mean_distance)
    explainer = gshap.KernelExplainer(clf.predict, X_train, g)
    output.put(explainer.gshap_value('ACE_inhibitor', sample, nsamples=10))

output = mp.Queue()
processes = [
    mp.Process(target=bootstrap_gshap_values, args=(output,)) 
    for i in range(bootstrap_samples)
]
[p.start() for p in processes]
[p.join() for p in processes]
gshap_values = np.array([output.get() for p in processes])<jupyter_output><empty_output><jupyter_text>In this example, we ask how likely it is that ACE inhibitors explain more than 5 percentage points of the difference in mortality rates between hypertensive and non-hypertensive patients.<jupyter_code>threshold = .05
p_val = (gshap_values>threshold).mean()
print('Probability that ACE inhibitors explain more than {0:.1f} percentage points of the difference in mortality rates: {1:.1f}%'.format(100*threshold, 100*p_val))<jupyter_output>Probability that ACE inhibitors explain more than 5 percentage points of the difference in mortality rates: 93.5%
{'fraction_non_alphanumeric': 0.093196405648267, 'fraction_numerical': 0.01848523748395379, 'mean_word_length': 7.133611691022964, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '25683', 'license': 'MIT', 'n_tokens_mistral': 1280, 'n_tokens_neox': 1160, 'n_words': 363, 'path': 'COVID-19.ipynb', 'repo_name': 'dsbowen/gshap', 'size': '3895'}