Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Beispiel wird kernel SHAP verwendet, um ein tabellarisches Klassifikationsmodell zu erläutern, das aus dem Dataset "Erwachsenenzählung" erstellt wurde.
Importieren Sie die erforderlichen Pakete, und definieren Sie die UDFs, die wir später benötigen:
import pyspark
from synapse.ml.explainers import *
from pyspark.ml import Pipeline
from pyspark.ml.classification import LogisticRegression
from pyspark.ml.feature import StringIndexer, OneHotEncoder, VectorAssembler
from pyspark.sql.types import *
from pyspark.sql.functions import *
import pandas as pd
from pyspark.sql import SparkSession
# Bootstrap Spark Session
spark = SparkSession.builder.getOrCreate()
from synapse.ml.core.platform import *
vec_access = udf(lambda v, i: float(v[i]), FloatType())
vec2array = udf(lambda vec: vec.toArray().tolist(), ArrayType(FloatType()))
Lesen Sie die Daten, und trainieren Sie ein binäres Klassifizierungsmodell:
df = spark.read.parquet(
"wasbs://publicwasb@mmlspark.blob.core.windows.net/AdultCensusIncome.parquet"
)
labelIndexer = StringIndexer(
inputCol="income", outputCol="label", stringOrderType="alphabetAsc"
).fit(df)
print("Label index assigment: " + str(set(zip(labelIndexer.labels, [0, 1]))))
training = labelIndexer.transform(df).cache()
display(training)
categorical_features = [
"workclass",
"education",
"marital-status",
"occupation",
"relationship",
"race",
"sex",
"native-country",
]
categorical_features_idx = [col + "_idx" for col in categorical_features]
categorical_features_enc = [col + "_enc" for col in categorical_features]
numeric_features = [
"age",
"education-num",
"capital-gain",
"capital-loss",
"hours-per-week",
]
strIndexer = StringIndexer(
inputCols=categorical_features, outputCols=categorical_features_idx
)
onehotEnc = OneHotEncoder(
inputCols=categorical_features_idx, outputCols=categorical_features_enc
)
vectAssem = VectorAssembler(
inputCols=categorical_features_enc + numeric_features, outputCol="features"
)
lr = LogisticRegression(featuresCol="features", labelCol="label", weightCol="fnlwgt")
pipeline = Pipeline(stages=[strIndexer, onehotEnc, vectAssem, lr])
model = pipeline.fit(training)
Nachdem das Modell trainiert wurde, wählen Sie zufällig einige Beobachtungen aus, um zu erklären:
explain_instances = (
model.transform(training).orderBy(rand()).limit(5).repartition(200).cache()
)
display(explain_instances)
Erstellen Sie eine TabularSHAP-Erklärung, legen Sie die Eingabespalten auf alle Features fest, die das Modell verwendet. Geben Sie als Nächstes das Modell und die Zielausgabespalte an, die erläutert werden soll. Hier möchten wir die "Wahrscheinlichkeitsausgabe" erklären, bei der es sich um einen Vektor der Länge 2 handelt, und wir betrachten nur die Wahrscheinlichkeit der Klasse 1. Legen Sie targetClasses auf [0, 1]
fest, um die Wahrscheinlichkeit der Klassen 0 und 1 gleichzeitig zu erläutern. Schließlich wird eine Stichprobe von 100 Zeilen aus den Trainingsdaten als Hintergrunddaten entnommen, die für die Integration von Features in Kernel SHAP verwendet werden:
shap = TabularSHAP(
inputCols=categorical_features + numeric_features,
outputCol="shapValues",
numSamples=5000,
model=model,
targetCol="probability",
targetClasses=[1],
backgroundData=broadcast(training.orderBy(rand()).limit(100).cache()),
)
shap_df = shap.transform(explain_instances)
Mit dem resultierenden DataFrame extrahieren Sie
- die Wahrscheinlichkeit der Modellausgabe der Klasse 1
- die SHAP-Werte für die Zielklasse
- die ursprünglichen Features
- die echte Bezeichnung
Konvertieren Sie dann den Datenframe für die Visualisierung in einen Pandas-Datenframe.
Für jede Beobachtung ist das erste Element im SHAP-Wertevektor der Basiswert (die mittlere Ausgabe des Hintergrunddatensets). Jedes der folgenden Elemente ist die SHAP-Werte für jedes Feature:
shaps = (
shap_df.withColumn("probability", vec_access(col("probability"), lit(1)))
.withColumn("shapValues", vec2array(col("shapValues").getItem(0)))
.select(
["shapValues", "probability", "label"] + categorical_features + numeric_features
)
)
shaps_local = shaps.toPandas()
shaps_local.sort_values("probability", ascending=False, inplace=True, ignore_index=True)
pd.set_option("display.max_colwidth", None)
shaps_local
Verwenden Sie plotly subplot, um die SHAP-Werte zu visualisieren:
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import pandas as pd
features = categorical_features + numeric_features
features_with_base = ["Base"] + features
rows = shaps_local.shape[0]
fig = make_subplots(
rows=rows,
cols=1,
subplot_titles="Probability: "
+ shaps_local["probability"].apply("{:.2%}".format)
+ "; Label: "
+ shaps_local["label"].astype(str),
)
for index, row in shaps_local.iterrows():
feature_values = [0] + [row[feature] for feature in features]
shap_values = row["shapValues"]
list_of_tuples = list(zip(features_with_base, feature_values, shap_values))
shap_pdf = pd.DataFrame(list_of_tuples, columns=["name", "value", "shap"])
fig.add_trace(
go.Bar(
x=shap_pdf["name"],
y=shap_pdf["shap"],
hovertext="value: " + shap_pdf["value"].astype(str),
),
row=index + 1,
col=1,
)
fig.update_yaxes(range=[-1, 1], fixedrange=True, zerolinecolor="black")
fig.update_xaxes(type="category", tickangle=45, fixedrange=True)
fig.update_layout(height=400 * rows, title_text="SHAP explanations")
fig.show()