Trainieren von Explainable Boosting Machines – Klassifizierung (Vorschau)

In diesem Artikel erfahren Sie, wie Sie Klassifizierungsmodelle mithilfe von erklärenden Verstärkungsmaschinen (EBM) trainieren. Explainable Boosting Machines (EBM) stellen eine Machine Learning-Technik dar, bei der die Leistungsfähigkeit des Gradient Boosting mit einer Betonung der Modellinterpretierbarkeit kombiniert wird. Es schafft ein Ensemble von Entscheidungsbäumen, ähnlich dem Gradient-Boosting, aber mit einem einzigartigen Fokus auf das Erzeugen von menschenlesbaren Modellen. EBMs bieten nicht nur genaue Vorhersagen, sondern bieten auch klare und intuitive Erklärungen für diese Vorhersagen. Sie eignen sich gut für Anwendungen, bei denen das Verständnis der zugrunde liegenden Faktoren, die Modellentscheidungen fördern, von wesentlicher Bedeutung ist, z. B. Gesundheitsversorgung, Finanzen und Einhaltung gesetzlicher Vorschriften.

In SynapseML können Sie eine skalierbare Implementierung einer EBM verwenden, die von Apache Spark unterstützt wird, um neue Modelle zu trainieren. Dieser Artikel führt Sie durch den Prozess der Anwendung der Skalierbarkeit und Interpretationsfähigkeit von EBMs in Microsoft Fabric mithilfe von Apache Spark.

Wichtig

Dieses Feature befindet sich in der Vorschau.

In diesem Artikel werden Sie schrittweise durch den Prozess der Erfassung und Vorverarbeitung von Daten aus Azure Open Datasets geführt, die NYC Yellow Taxi Trips aufzeichnet. Dann trainieren Sie ein Prädiktivmodell mit dem ultimativen Ziel, zu bestimmen, ob eine bestimmte Reise eintritt oder nicht.

Vorteile von Explainable Boosting Machines

EBMs bieten eine einzigartige Mischung aus Interpretationsfähigkeit und Prädiktivkraft, sodass sie eine ideale Wahl sind, wenn Transparenz und Verständlichkeit von Machine Learning-Modellen entscheidend sind. Mit EBMs können Benutzer wertvolle Einblicke in die zugrunde liegenden Faktoren gewinnen, die vorhersagen, sodass sie verstehen können, warum ein Modell bestimmte Entscheidungen oder Vorhersagen trifft, was für die Erstellung von Vertrauen in KI-Systeme unerlässlich ist.

Ihre Fähigkeit, komplexe Beziehungen innerhalb der Daten aufzudecken und gleichzeitig klare und interpretierbare Ergebnisse bereitzustellen, macht sie in Bereichen wie Finanzen, Gesundheitswesen und Betrugserkennung unschätzbar. In diesen Feldern ist die Modellerklärbarkeit nicht nur wünschenswert, sondern häufig eine regulatorische Anforderung. Letztendlich können Benutzer, die sich für EBMs entscheiden, ein Gleichgewicht zwischen Modellleistung und Transparenz schaffen, um sicherzustellen, dass KI-Lösungen präzise, leicht verständlich und rechenschaftsfähig sind.

Voraussetzungen

  • Erstellen Sie ein neues Notizbuch in Ihrem Arbeitsbereich, indem Sie + und dann Notizbuch-auswählen.

Installieren von Bibliotheken

Installieren Sie zunächst die Open Datasets-Bibliothek von Azure Machine Learning, die Zugriff auf das Dataset gewährt. Dieser Installationsschritt ist für den effektiven Zugriff und die effektive Nutzung des Datasets unerlässlich.

%pip install azureml-opendatasets

MLflow importieren

MLflow ermöglicht es Ihnen, die Parameter und Ergebnisse des Modells nachzuverfolgen. Der folgende Codeausschnitt veranschaulicht die Verwendung von MLflow für Experiment- und Nachverfolgungszwecke. Der ebm_classification_nyc_taxi Wert ist der Name des Experiments, in dem die Informationen protokolliert werden.

import mlflow

# Set up the experiment name
mlflow.set_experiment("ebm_classification_nyc_taxi")

Importieren von Bibliotheken

Fügen Sie als Nächstes den folgenden Code hinzu, um die wesentlichen Pakete zu importieren, die für die Analyse verwendet werden:

# Import necessary packages
import interpret
from pyspark.ml.feature import StringIndexer, VectorAssembler
from pyspark.ml import Pipeline
from pyspark.mllib.evaluation import BinaryClassificationMetrics
from pyspark.sql import SparkSession
from pyspark.sql.functions import *
from pyspark.sql.types import DoubleType
from synapse.ml.ebm import EbmClassification

Diese importierten Pakete stellen die grundlegenden Tools und Funktionen bereit, die für Ihre Analyse- und Modellierungsaufgaben erforderlich sind.

Laden von Daten

Fügen Sie als Nächstes den folgenden Code hinzu, um die NYC Yellow Taxi-Daten aus Azure Machine Learning Open Datasets abzurufen und optional das Dataset nach unten zu durchlaufen, um die Entwicklung zu beschleunigen:

# Import NYC Yellow Taxi data from Azure Open Datasets
from azureml.opendatasets import NycTlcYellow

from datetime import datetime
from dateutil import parser

# Define the start and end dates for the dataset
end_date = parser.parse('2018-05-08 00:00:00')
start_date = parser.parse('2018-05-01 00:00:00')

# Load the NYC Yellow Taxi dataset within the specified date range
nyc_tlc = NycTlcYellow(start_date=start_date, end_date=end_date)
nyc_pd = nyc_tlc.to_pandas_dataframe()
nyc_tlc_df = spark.createDataFrame(nyc_pd)

Um die Entwicklung zu erleichtern und den Rechenaufwand zu reduzieren, können Sie das Dataset heruntersampen:

# For development convenience, consider down-sampling the dataset
sampled_taxi_df = nyc_tlc_df.sample(True, 0.001, seed=1234)

Down-Sampling ermöglicht eine schnellere und kostengünstigere Entwicklungserfahrung, insbesondere bei der Arbeit mit großen Datasets.

Vorbereiten der Daten

In diesem Abschnitt bereiten Sie das Dataset vor, indem Sie Zeilen mit Ausreißern und irrelevanten Variablen herausfiltern.

Generieren von Features

Erstellen Sie Add-Code für neue abgeleitete Features, die die Modellleistung verbessern sollen:

taxi_df = sampled_taxi_df.select('totalAmount', 'fareAmount', 'tipAmount', 'paymentType', 'rateCodeId', 'passengerCount',
                                'tripDistance', 'tpepPickupDateTime', 'tpepDropoffDateTime',
                                date_format('tpepPickupDateTime', 'hh').alias('pickupHour'),
                                date_format('tpepPickupDateTime', 'EEEE').alias('weekdayString'),
                                (unix_timestamp(col('tpepDropoffDateTime')) - unix_timestamp(col('tpepPickupDateTime'))).alias('tripTimeSecs'),
                                (when(col('tipAmount') > 0, 1).otherwise(0)).alias('tipped')
                                )\
                        .filter((sampled_taxi_df.passengerCount > 0) & (sampled_taxi_df.passengerCount < 8)
                                & (sampled_taxi_df.tipAmount >= 0) & (sampled_taxi_df.tipAmount <= 25)
                                & (sampled_taxi_df.fareAmount >= 1) & (sampled_taxi_df.fareAmount <= 250)
                                & (sampled_taxi_df.tipAmount < sampled_taxi_df.fareAmount)
                                & (sampled_taxi_df.tripDistance > 0) & (sampled_taxi_df.tripDistance <= 100)
                                & (sampled_taxi_df.rateCodeId <= 5)
                                & (sampled_taxi_df.paymentType.isin({"1", "2"}))
                                )

Nachdem Sie nun neue Variablen erstellt haben, fügen Sie Code hinzu, um die Spalten abzulegen, von denen sie abgeleitet wurden. Der Datenrahmen ist jetzt für die Modelleingabe optimiert. Darüber hinaus können Sie weitere Features basierend auf den neu erstellten Spalten generieren:

taxi_featurised_df = taxi_df.select('totalAmount', 'fareAmount', 'tipAmount', 'paymentType', 'passengerCount',
                                    'tripDistance', 'weekdayString', 'pickupHour', 'tripTimeSecs', 'tipped',
                                    when((taxi_df.pickupHour <= 6) | (taxi_df.pickupHour >= 20), "Night")
                                    .when((taxi_df.pickupHour >= 7) & (taxi_df.pickupHour <= 10), "AMRush")
                                    .when((taxi_df.pickupHour >= 11) & (taxi_df.pickupHour <= 15), "Afternoon")
                                    .when((taxi_df.pickupHour >= 16) & (taxi_df.pickupHour <= 19), "PMRush")
                                    .otherwise(0).alias('trafficTimeBins'))\
                                    .filter((taxi_df.tripTimeSecs >= 30) & (taxi_df.tripTimeSecs <= 7200))

Diese Datenvorbereitungsschritte stellen sicher, dass Ihr Datensatz sowohl verfeinert als auch für nachfolgende Modellierungsprozesse optimiert ist.

Codieren der Daten

Im Kontext von SynapseML-EBMs erwartet Estimator Eingabedaten in Form eines org.apache.spark.mllib.linalg.Vector (im Wesentlichen einen Vektor von Doubles). Daher ist es erforderlich, alle kategorisierten (Zeichenfolgen)-Variablen in numerische Darstellungen zu konvertieren, und alle Variablen, die numerische Werte besitzen, aber nicht numerische Datentypen müssen in numerische Datentypen umgewandelt werden.

Derzeit verwenden SynapseML EBMs den StringIndexer-Ansatz zur Verwaltung kategorischer Variablen. Derzeit bieten SynapseML EBMs keine spezielle Behandlung für kategorisierte Features.

Im Folgenden finden Sie eine Reihe von Schritten zum Hinzufügen zum Code, um die Daten für die Verwendung mit SynapseML EBMs vorzubereiten:

# Convert categorical features into numerical representations using StringIndexer
sI1 = StringIndexer(inputCol="trafficTimeBins", outputCol="trafficTimeBinsIndex")
sI2 = StringIndexer(inputCol="weekdayString", outputCol="weekdayIndex")

# Apply the encodings to create a new dataframe
encoded_df = Pipeline(stages=[sI1, sI2]).fit(taxi_featurised_df).transform(taxi_featurised_df)
final_df = encoded_df.select('fareAmount', 'paymentType', 'passengerCount', 'tripDistance',
                             'pickupHour', 'tripTimeSecs', 'trafficTimeBinsIndex', 'weekdayIndex',
                             'tipped')

# Ensure that any string representations of numbers in the data are cast to numeric data types
final_df = final_df.withColumn('paymentType', final_df['paymentType'].cast(DoubleType()))
final_df = final_df.withColumn('pickupHour', final_df['pickupHour'].cast(DoubleType()))

# Define the label column name
labelColumnName = 'tipped'

# Assemble the features into a vector
assembler = VectorAssembler(outputCol='features')
assembler.setInputCols([c for c in final_df.columns if c != labelColumnName])
vectorized_final_df = assembler.transform(final_df)

Diese Datenvorbereitungsschritte sind entscheidend für die Ausrichtung des Datenformats an die Anforderungen von SynapseML EBMs, um eine genaue und effektive Modellschulung sicherzustellen.

Generieren von Test- und Schulungsdatensätzen

Fügen Sie nun Code hinzu, um das Dataset mithilfe einer einfachen Aufteilung in Schulungs- und Testsätze aufzuteilen. 70% der Daten werden für Schulungen und 30% zum Testen des Modells zugewiesen:

# Decide on the split between training and test data from the dataframe 
trainingFraction = 0.7
testingFraction = (1-trainingFraction)
seed = 1234

# Split the dataframe into test and training dataframes
train_data_df, test_data_df = vectorized_final_df.randomSplit([trainingFraction, testingFraction], seed=seed)

Diese Datenteilung ermöglicht es uns, das Modell in einem wesentlichen Teil zu trainieren und gleichzeitig einen anderen Teil zu reservieren, um seine Leistung effektiv zu bewerten.

Trainieren des Modells

Fügen Sie nun Code hinzu, um das EBM-Modell zu trainieren, und bewerten Sie dann die Leistung mithilfe der Fläche unter der Receiver Operating Characteristic (ROC) Kurve (AUROC) als Metrik.

# Create an instance of the EBMClassifier
estimator = EbmClassification()
estimator.setLabelCol(labelColumnName)

# Fit the EBM model to the training data
model = estimator.fit(train_data_df)

# Make predictions for tip (1/0 - yes/no) on the test dataset and evaluate using AUROC
predictions = model.transform(test_data_df)
predictionsAndLabels = predictions.select("prediction", labelColumnName)
predictionsAndLabels = predictionsAndLabels.withColumn(labelColumnName, predictionsAndLabels[labelColumnName].cast(DoubleType()))

# Calculate AUROC using BinaryClassificationMetrics
metrics = BinaryClassificationMetrics(predictionsAndLabels.rdd)
print("Area under ROC = %s" % metrics.areaUnderROC)

Dieser Prozess beinhaltet eine Schulung des EBM-Modells auf dem Schulungsdatensatz und anschließendes Verwenden, um Vorhersagen für das Testdatenset zu erstellen, gefolgt von der Bewertung der Leistung des Modells mithilfe von AUROC als Schlüsselmetrik.

Globale Erklärungen anzeigen

Um die Allgemeine Erläuterung des Modells zu visualisieren, können Sie Code hinzufügen, um den Visualisierungswrapper abzurufen und die Methode der interpret Bibliothek show zu verwenden. Der Visualisierungswrapper fungiert als Brücke, um die Visualisierungserfahrung des Modells zu erleichtern. Hier erfahren Sie, wie Sie dies tun können:

wrapper = model.getVizWrapper()
explanation = wrapper.explain_global()

Fügen Sie als Nächstes Code zum Importieren der interpret Bibliothek hinzu, und verwenden Sie die show Methode, um die Erklärung anzuzeigen:

import interpret
interpret.show(explanation)

Screenshot der globalen Erklärungen.

Der Begriff "Wichtigkeiten" stellt den mittleren absoluten Beitrag (Score) jedes Begriffs (Feature oder Interaktion) gegenüber Vorhersagen dar. Diese Beiträge werden im gesamten Trainingsdataset gemittelt, wobei die Anzahl der Beispiele in den einzelnen Intervallen und Stichprobengewichtungen berücksichtigt wird (sofern zutreffend). Die wichtigsten 15 wichtigsten Begriffe werden in der Erläuterung angezeigt.

Lokale Erklärungen anzeigen

Die bereitgestellten Erklärungen sind global, aber es gibt Szenarios, in denen Ausgaben pro Feature ebenfalls hilfreich sind. Sowohl Trainer als auch das Modell bieten die Möglichkeit, die featurescores festzulegen, wodurch beim Auffüllen eine weitere vektorwertige Spalte eingeführt wird. Jeder Vektor in dieser Spalte entspricht der Länge der Featurespalte, wobei jeder Wert dem Feature am gleichen Index entspricht. Diese Werte stellen den Beitrag des Werts jedes Features zur endgültigen Ausgabe des Modells dar.

Im Gegensatz zu globalen Erklärungen gibt es derzeit keine direkte Integration in die interpret-Visualisierung für Ausgaben pro Feature. Dies liegt daran, dass globale Visualisierungen hauptsächlich mit der Anzahl der Features skaliert werden (die in der Regel klein sind), während lokale Erklärungen mit der Anzahl der Zeilen skaliert werden (was, wenn ein Spark-Datenframe erheblich sein kann).

Hier ist der Code, den Sie zum Hinzufügen, Einrichten und Verwenden des featurescores benötigen:

prediction2 = model.setFeatureScoresCol("featurescores").transform(train_data_df)

Zur Veranschaulichung fügen wir Code hinzu, um die Details des ersten Beispiels zu drucken:

# Convert to Pandas for easier inspection
predictions_pandas = prediction2.toPandas()
predictions_list = prediction2.collect()

# Extract the first example from the collected predictions.
first = predictions_list[0]

# Print the lengths of the features and feature scores.
print('Length of the features is', len(first['features']), 'while the feature scores have length', len(first['featurescores']))

# Print the values of the features and feature scores.
print('Features are', first['features'])
print('Feature scores are', first['featurescores'])