Zelfstudie: Een upliftmodel maken, trainen en evalueren
In deze handleiding wordt een end-to-end voorbeeld van een Synapse Data Science-werkstroom in Microsoft Fabric gepresenteerd. U leert hoe u upliftmodellen maakt, traint en evalueert en hoe u uplift-modelleringstechnieken toepast.
Voorwaarden
Een Microsoft Fabric-abonnementophalen. Of meld u aan voor een gratis microsoft Fabric-proefversie.
Meld u aan bij Microsoft Fabric-.
Gebruik de ervaringswisselaar aan de linkerkant van de startpagina om over te schakelen naar Fabric.
- Bekendheid met Microsoft Fabric-notebooks
- Een lakehouse bij dit notebook om gegevens voor dit voorbeeld op te slaan. Ga naar Een lakehouse toevoegen aan uw notitieblok voor meer informatie
Volg mee in een notitieboekje
U kunt een notitieblok op twee manieren volgen:
- Open en voer het ingebouwde notebook uit.
- Upload uw notebook vanuit GitHub.
Het ingebouwde notebook openen
Het voorbeeld Uplift-modellering-notebook begeleidt deze handleiding.
Als u het voorbeeldnotitieblok voor deze zelfstudie wilt openen, volgt u de instructies in Uw systeem voorbereiden op zelfstudies voor gegevenswetenschap.
Zorg ervoor dat u een lakehouse koppelt aan het notebook voordat u begint met het uitvoeren van code.
Het notebook importeren vanuit GitHub
De AIsample - Uplift Modeling.ipynb notebook begeleidt deze tutorial.
Als u het bijbehorende notitieblok voor deze zelfstudie wilt openen, volgt u de instructies in Uw systeem voorbereiden op zelfstudies voor gegevenswetenschap, om het notebook in uw werkruimte te importeren.
U kunt een nieuw notitieblok maken als u liever de code van deze pagina kopieert en plakt.
Zorg ervoor dat een lakehouse aan het notebook koppelen voordat u begint met het uitvoeren van code.
Stap 1: de gegevens laden
Dataset
Het Criteo AI Lab heeft de gegevensset gemaakt. Deze gegevensset heeft 13 miljoen rijen. Elke rij vertegenwoordigt één gebruiker. Elke rij heeft 12 kenmerken, een behandelindicator en twee binaire labels die bezoek en conversie bevatten.
- f0 - f11: functiewaarden (dichte, zwevende waarden)
- behandeling: of een gebruiker willekeurig werd geselecteerd voor behandeling (bijvoorbeeld reclame) (1 = behandeling, 0 = controle)
- conversie: of er een conversie heeft plaatsgevonden (bijvoorbeeld een aankoop gedaan) voor een gebruiker (binair, label)
- Bezoek aan : of er een conversie heeft plaatsgevonden (bijvoorbeeld of er een aankoop door de gebruiker is gedaan) (binair, label)
Citaat
- Startpagina van gegevensset: https://ailab.criteo.com/criteo-uplift-prediction-dataset/
Voor de gegevensset die voor dit notebook wordt gebruikt, is deze BibTex-bronvermelding vereist:
@inproceedings{Diemert2018,
author = {{Diemert Eustache, Betlei Artem} and Renaudin, Christophe and Massih-Reza, Amini},
title={A Large Scale Benchmark for Uplift Modeling},
publisher = {ACM},
booktitle = {Proceedings of the AdKDD and TargetAd Workshop, KDD, London,United Kingdom, August, 20, 2018},
year = {2018}
}
Tip
Door de volgende parameters te definiëren, kunt u dit notebook eenvoudig toepassen op verschillende gegevenssets.
IS_CUSTOM_DATA = False # If True, the user must upload the dataset manually
DATA_FOLDER = "Files/uplift-modelling"
DATA_FILE = "criteo-research-uplift-v2.1.csv"
# Data schema
FEATURE_COLUMNS = [f"f{i}" for i in range(12)]
TREATMENT_COLUMN = "treatment"
LABEL_COLUMN = "visit"
EXPERIMENT_NAME = "aisample-upliftmodelling" # MLflow experiment name
Bibliotheken importeren
Voordat u gaat verwerken, moet u de vereiste Spark- en SynapseML-bibliotheken importeren. U moet ook een bibliotheek voor gegevensvisualisatie importeren, bijvoorbeeld Seaborn, een Bibliotheek voor gegevensvisualisatie in Python. Een gegevensvisualisatiebibliotheek biedt een interface op hoog niveau voor het bouwen van visuele resources op DataFrames en matrices. Meer informatie over Spark, SynapseML-en Seaborn-.
import os
import gzip
import pyspark.sql.functions as F
from pyspark.sql.window import Window
from pyspark.sql.types import *
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.style as style
import seaborn as sns
%matplotlib inline
from synapse.ml.featurize import Featurize
from synapse.ml.core.spark import FluentAPI
from synapse.ml.lightgbm import *
from synapse.ml.train import ComputeModelStatistics
import mlflow
Een gegevensset downloaden en uploaden naar Lakehouse
Met deze code wordt een openbaar beschikbare versie van de gegevensset gedownload en wordt die gegevensresource vervolgens opgeslagen in een Fabric Lakehouse.
Belangrijk
Zorg ervoor dat u Een lakehouse- toevoegen aan het notebook voordat u het uitvoert. Als u dit niet doet, treedt er een fout op.
if not IS_CUSTOM_DATA:
# Download demo data files into lakehouse if not exist
import os, requests
remote_url = "http://go.criteo.net/criteo-research-uplift-v2.1.csv.gz"
download_file = "criteo-research-uplift-v2.1.csv.gz"
download_path = f"/lakehouse/default/{DATA_FOLDER}/raw"
if not os.path.exists("/lakehouse/default"):
raise FileNotFoundError("Default lakehouse not found, please add a lakehouse and restart the session.")
os.makedirs(download_path, exist_ok=True)
if not os.path.exists(f"{download_path}/{DATA_FILE}"):
r = requests.get(f"{remote_url}", timeout=30)
with open(f"{download_path}/{download_file}", "wb") as f:
f.write(r.content)
with gzip.open(f"{download_path}/{download_file}", "rb") as fin:
with open(f"{download_path}/{DATA_FILE}", "wb") as fout:
fout.write(fin.read())
print("Downloaded demo data files into lakehouse.")
Begin met het opnemen van de runtime van dit notebook.
# Record the notebook running time
import time
ts = time.time()
Stel het bijhouden van MLflow-experimenten in
Als u de MLflow-logboekregistratiemogelijkheden wilt uitbreiden, worden de waarden van invoerparameters en metrische uitvoergegevens van een machine learning-model automatisch vastgelegd tijdens de training. Deze informatie wordt vervolgens geregistreerd bij de werkruimte, waar de MLflow-API's of het bijbehorende experiment in de werkruimte deze kunnen openen en visualiseren. Ga naar deze resource voor meer informatie over automatisch inloggen.
# Set up the MLflow experiment
import mlflow
mlflow.set_experiment(EXPERIMENT_NAME)
mlflow.autolog(disable=True) # Disable MLflow autologging
Notitie
Als u automatische aanmelding van Microsoft Fabric in een notebooksessie wilt uitschakelen, roept u mlflow.autolog()
aan en stelt u disable=True
in.
Gegevens lezen uit lakehouse
Lees onbewerkte gegevens uit de sectie Lakehouse Files en voeg meer kolommen toe voor verschillende datumonderdelen. Dezelfde informatie wordt gebruikt om een gepartitioneerde deltatabel te maken.
raw_df = spark.read.csv(f"{DATA_FOLDER}/raw/{DATA_FILE}", header=True, inferSchema=True).cache()
Stap 2: Verkennende gegevensanalyse
Gebruik de opdracht display
om statistieken op hoog niveau over de gegevensset weer te geven. U kunt ook de grafiekweergaven weergeven om eenvoudig subsets van de gegevensset te visualiseren.
display(raw_df.limit(20))
Bekijk het percentage van de gebruikers die bezoeken, het percentage gebruikers dat converteert en het percentage van de bezoekers die converteren.
raw_df.select(
F.mean("visit").alias("Percentage of users that visit"),
F.mean("conversion").alias("Percentage of users that convert"),
(F.sum("conversion") / F.sum("visit")).alias("Percentage of visitors that convert"),
).show()
De analyse geeft aan dat 4,9% van gebruikers van de behandel-groep - gebruikers die de behandeling of de reclame hebben gekregen - de online winkel bezochten. Alleen 3.8% van gebruikers uit de controlegroep - gebruikers die nooit de behandeling hebben ontvangen of nooit aan reclame werden aangeboden of blootgesteld - deden hetzelfde. Daarnaast hebben 0,31% van alle gebruikers uit de behandelgroep geconverteerd of een aankoop gedaan, terwijl slechts 0,19% van de gebruikers uit de controlegroep dit deden. Als gevolg hiervan is de conversieverhouding van bezoekers die ook lid waren van een behandelgroep, 6,36%, vergeleken met slechts 5,07%** voor gebruikers van de controlegroep. Op basis van deze resultaten kan de behandeling de bezoekfrequentie mogelijk verbeteren met ongeveer 1%en de conversieratio van bezoekers met ongeveer 1,3%. De behandeling leidt tot een aanzienlijke verbetering.
Stap 3: Het model voor training definiëren
De training voorbereiden en de gegevenssets testen
Hier past u een Featurize-transformator aan het raw_df
DataFrame toe om functies uit de opgegeven invoerkolommen te extraheren en deze functies uit te voeren naar een nieuwe kolom met de naam features
.
Het resulterende DataFrame wordt opgeslagen in een nieuw DataFrame met de naam df
.
transformer = Featurize().setOutputCol("features").setInputCols(FEATURE_COLUMNS).fit(raw_df)
df = transformer.transform(raw_df)
# Split the DataFrame into training and test sets, with a 80/20 ratio and a seed of 42
train_df, test_df = df.randomSplit([0.8, 0.2], seed=42)
# Print the training and test dataset sizes
print("Size of train dataset: %d" % train_df.count())
print("Size of test dataset: %d" % test_df.count())
# Group the training dataset by the treatment column, and count the number of occurrences of each value
train_df.groupby(TREATMENT_COLUMN).count().show()
De gegevenssets voor de behandeling en controle voorbereiden
Nadat u de trainings- en testgegevenssets hebt gemaakt, moet u ook de behandel- en controlegegevenssets vormen om de machine learning-modellen te trainen om de uplift te meten.
# Extract the treatment and control DataFrames
treatment_train_df = train_df.where(f"{TREATMENT_COLUMN} > 0")
control_train_df = train_df.where(f"{TREATMENT_COLUMN} = 0")
Nu u uw gegevens hebt voorbereid, kunt u doorgaan met het trainen van een model met LightGBM.
Uplift modellering: T-Learner met LightGBM
Meta-learners zijn een set algoritmen, gebouwd op basis van machine learning-algoritmen zoals LightGBM, Xgboost, enzovoort. Ze helpen bij het schatten van het effect van de voorwaardelijke gemiddelde behandeling of CATE. T-learner is een meta-learner die geen enkel model gebruikt. In plaats daarvan gebruikt T-learner één model per behandelingsvariabele. Daarom worden twee modellen ontwikkeld en verwijzen we naar de meta-learner als T-learner. T-learner maakt gebruik van meerdere machine learning-modellen om het probleem van het volledig negeren van de behandeling te verhelpen door de cursist te dwingen eerst te splitsen.
mlflow.autolog(exclusive=False)
classifier = (
LightGBMClassifier(dataTransferMode="bulk")
.setFeaturesCol("features") # Set the column name for features
.setNumLeaves(10) # Set the number of leaves in each decision tree
.setNumIterations(100) # Set the number of boosting iterations
.setObjective("binary") # Set the objective function for binary classification
.setLabelCol(LABEL_COLUMN) # Set the column name for the label
)
# Start a new MLflow run with the name "uplift"
active_run = mlflow.start_run(run_name="uplift")
# Start a new nested MLflow run with the name "treatment"
with mlflow.start_run(run_name="treatment", nested=True) as treatment_run:
treatment_run_id = treatment_run.info.run_id # Get the ID of the treatment run
treatment_model = classifier.fit(treatment_train_df) # Fit the classifier on the treatment training data
# Start a new nested MLflow run with the name "control"
with mlflow.start_run(run_name="control", nested=True) as control_run:
control_run_id = control_run.info.run_id # Get the ID of the control run
control_model = classifier.fit(control_train_df) # Fit the classifier on the control training data
De testgegevensset gebruiken voor een voorspelling
Hier gebruikt u de treatment_model
en control_model
, beide eerder gedefinieerd, om de test_df
testgegevensset te transformeren. Vervolgens berekent u de verwachte uplift. U definieert de voorspelde uplift als het verschil tussen het voorspelde behandelresultaat en het voorspelde controleresultaat. Hoe groter dit voorspelde verhogingsverschil, hoe groter de effectiviteit van de behandeling (bijvoorbeeld reclame) op een persoon of subgroep.
getPred = F.udf(lambda v: float(v[1]), FloatType())
# Cache the resulting DataFrame for easier access
test_pred_df = (
test_df.mlTransform(treatment_model)
.withColumn("treatment_pred", getPred("probability"))
.drop("rawPrediction", "probability", "prediction")
.mlTransform(control_model)
.withColumn("control_pred", getPred("probability"))
.drop("rawPrediction", "probability", "prediction")
.withColumn("pred_uplift", F.col("treatment_pred") - F.col("control_pred"))
.select(TREATMENT_COLUMN, LABEL_COLUMN, "treatment_pred", "control_pred", "pred_uplift")
.cache()
)
# Display the first twenty rows of the resulting DataFrame
display(test_pred_df.limit(20))
Modelevaluatie uitvoeren
Omdat de werkelijke uplift niet kan worden waargenomen voor elk individu, moet u de uplift over een groep individuen meten. U gebruikt een uplift-curve die de werkelijke, cumulatieve uplift in de populatie in kaart brengt.
De x-as vertegenwoordigt de verhouding van de populatie die is geselecteerd voor de behandeling. Een waarde van 0 suggereert geen behandelingsgroep - niemand wordt blootgesteld aan of aangeboden, de behandeling. Een waarde van 1 suggereert een volledige behandelingsgroep - iedereen wordt blootgesteld aan of aangeboden, de behandeling. Op de y-as wordt de uplift-meting weergegeven. Het doel is om de grootte van de behandelgroep te bepalen, of het percentage van de populatie dat aan de behandeling zou worden aangeboden of blootgesteld (bijvoorbeeld reclame). Deze benadering optimaliseert de doelselectie om het resultaat te optimaliseren.
Rangschik eerst de DataFrame-testvolgorde op basis van de voorspelde uplift. De voorspelde uplift is het verschil tussen het voorspelde behandelresultaat en het voorspelde controleresultaat.
# Compute the percentage rank of the predicted uplift values in descending order, and display the top twenty rows
test_ranked_df = test_pred_df.withColumn("percent_rank", F.percent_rank().over(Window.orderBy(F.desc("pred_uplift"))))
display(test_ranked_df.limit(20))
Vervolgens berekent u het cumulatieve percentage bezoeken in zowel de behandel- als controlegroepen.
# Calculate the number of control and treatment samples
C = test_ranked_df.where(f"{TREATMENT_COLUMN} == 0").count()
T = test_ranked_df.where(f"{TREATMENT_COLUMN} != 0").count()
# Add columns to the DataFrame to calculate the control and treatment cumulative sum
test_ranked_df = (
test_ranked_df.withColumn(
"control_label",
F.when(F.col(TREATMENT_COLUMN) == 0, F.col(LABEL_COLUMN)).otherwise(0),
)
.withColumn(
"treatment_label",
F.when(F.col(TREATMENT_COLUMN) != 0, F.col(LABEL_COLUMN)).otherwise(0),
)
.withColumn(
"control_cumsum",
F.sum("control_label").over(Window.orderBy("percent_rank")) / C,
)
.withColumn(
"treatment_cumsum",
F.sum("treatment_label").over(Window.orderBy("percent_rank")) / T,
)
)
# Display the first 20 rows of the dataframe
display(test_ranked_df.limit(20))
Ten slotte berekent u voor elk percentage de verbetering van de groep als het verschil tussen het cumulatieve percentage bezoeken tussen de behandel- en controlegroep.
test_ranked_df = test_ranked_df.withColumn("group_uplift", F.col("treatment_cumsum") - F.col("control_cumsum")).cache()
display(test_ranked_df.limit(20))
Plot nu de uplift-curve voor de voorspelling van de testgegevensset. U moet het PySpark DataFrame converteren naar een Pandas DataFrame voordat u plott.
def uplift_plot(uplift_df):
"""
Plot the uplift curve
"""
gain_x = uplift_df.percent_rank
gain_y = uplift_df.group_uplift
# Plot the data
fig = plt.figure(figsize=(10, 6))
mpl.rcParams["font.size"] = 8
ax = plt.plot(gain_x, gain_y, color="#2077B4", label="Normalized Uplift Model")
plt.plot(
[0, gain_x.max()],
[0, gain_y.max()],
"--",
color="tab:orange",
label="Random Treatment",
)
plt.legend()
plt.xlabel("Porportion Targeted")
plt.ylabel("Uplift")
plt.grid()
return fig, ax
test_ranked_pd_df = test_ranked_df.select(["pred_uplift", "percent_rank", "group_uplift"]).toPandas()
fig, ax = uplift_plot(test_ranked_pd_df)
mlflow.log_figure(fig, "UpliftCurve.png")
De x-as vertegenwoordigt de verhouding van de populatie die is geselecteerd voor de behandeling. Een waarde van 0 suggereert geen behandelingsgroep - niemand wordt blootgesteld aan of aangeboden, de behandeling. Een waarde van 1 suggereert een volledige behandelingsgroep - iedereen wordt blootgesteld aan of aangeboden, de behandeling. Op de y-as wordt de meting voor opheffen weergegeven. Het doel is om de grootte van de behandelgroep te bepalen, of het percentage van de populatie dat aan de behandeling zou worden aangeboden of blootgesteld (bijvoorbeeld reclame). Deze benadering optimaliseert de doelselectie om het resultaat te optimaliseren.
Rangschik eerst de DataFrame-testvolgorde op basis van de voorspelde uplift. De voorspelde uplift is het verschil tussen het voorspelde behandelresultaat en het voorspelde controleresultaat.
# Compute the percentage rank of the predicted uplift values in descending order, and display the top twenty rows
test_ranked_df = test_pred_df.withColumn("percent_rank", F.percent_rank().over(Window.orderBy(F.desc("pred_uplift"))))
display(test_ranked_df.limit(20))
Vervolgens berekent u het cumulatieve percentage bezoeken in zowel de behandel- als controlegroepen.
# Calculate the number of control and treatment samples
C = test_ranked_df.where(f"{TREATMENT_COLUMN} == 0").count()
T = test_ranked_df.where(f"{TREATMENT_COLUMN} != 0").count()
# Add columns to the DataFrame to calculate the control and treatment cumulative sum
test_ranked_df = (
test_ranked_df.withColumn(
"control_label",
F.when(F.col(TREATMENT_COLUMN) == 0, F.col(LABEL_COLUMN)).otherwise(0),
)
.withColumn(
"treatment_label",
F.when(F.col(TREATMENT_COLUMN) != 0, F.col(LABEL_COLUMN)).otherwise(0),
)
.withColumn(
"control_cumsum",
F.sum("control_label").over(Window.orderBy("percent_rank")) / C,
)
.withColumn(
"treatment_cumsum",
F.sum("treatment_label").over(Window.orderBy("percent_rank")) / T,
)
)
# Display the first 20 rows of the dataframe
display(test_ranked_df.limit(20))
Ten slotte berekent u bij elk percentage de toename van de groep als het verschil tussen het cumulatieve percentage bezoeken tussen de behandel- en controlegroep.
test_ranked_df = test_ranked_df.withColumn("group_uplift", F.col("treatment_cumsum") - F.col("control_cumsum")).cache()
display(test_ranked_df.limit(20))
Plot nu de uplift-curve voor de voorspelling van de testgegevensset. U moet het PySpark DataFrame converteren naar een Pandas DataFrame voordat u plott.
def uplift_plot(uplift_df):
"""
Plot the uplift curve
"""
gain_x = uplift_df.percent_rank
gain_y = uplift_df.group_uplift
# Plot the data
fig = plt.figure(figsize=(10, 6))
mpl.rcParams["font.size"] = 8
ax = plt.plot(gain_x, gain_y, color="#2077B4", label="Normalized Uplift Model")
plt.plot(
[0, gain_x.max()],
[0, gain_y.max()],
"--",
color="tab:orange",
label="Random Treatment",
)
plt.legend()
plt.xlabel("Porportion Targeted")
plt.ylabel("Uplift")
plt.grid()
return fig, ax
test_ranked_pd_df = test_ranked_df.select(["pred_uplift", "percent_rank", "group_uplift"]).toPandas()
fig, ax = uplift_plot(test_ranked_pd_df)
mlflow.log_figure(fig, "UpliftCurve.png")
De analyse en de uplift-curve tonen beide aan dat de top 20% populatie, zoals gerangschikt op basis van de voorspelling, een grote winst zou hebben als ze de behandeling kregen. Dit betekent dat de top 20% van de populatie de overtuigende groep vertegenwoordigt. Daarom kunt u vervolgens de cutoff-score instellen voor de gewenste grootte van de behandelgroep op 20%, om de doelklanten met de meeste impact te identificeren.
cutoff_percentage = 0.2
cutoff_score = test_ranked_pd_df.iloc[int(len(test_ranked_pd_df) * cutoff_percentage)][
"pred_uplift"
]
print("Uplift scores that exceed {:.4f} map to Persuadables.".format(cutoff_score))
mlflow.log_metrics(
{"cutoff_score": cutoff_score, "cutoff_percentage": cutoff_percentage}
)
Stap 4: het uiteindelijke ML-model registreren
U gebruikt MLflow om alle experimenten voor zowel behandelings- als controlegroepen bij te houden en te registreren. Deze tracering en logboekregistratie bevatten de bijbehorende parameters, metrische gegevens en de modellen. Deze informatie wordt vastgelegd onder de naam van het experiment, in de werkruimte, voor later gebruik.
# Register the model
treatment_model_uri = "runs:/{}/model".format(treatment_run_id)
mlflow.register_model(treatment_model_uri, f"{EXPERIMENT_NAME}-treatmentmodel")
control_model_uri = "runs:/{}/model".format(control_run_id)
mlflow.register_model(control_model_uri, f"{EXPERIMENT_NAME}-controlmodel")
mlflow.end_run()
Uw experimenten weergeven:
- Selecteer uw werkruimte in het linkerdeelvenster.
- Zoek en selecteer de naam van het experiment, in dit geval aisample-upliftmodelling.
Stap 5: de voorspellingsresultaten opslaan
Microsoft Fabric biedt PREDICT: een schaalbare functie die ondersteuning biedt voor batchgewijs scoren in elke rekenengine. Hiermee kunnen klanten machine learning-modellen operationeel maken. Gebruikers kunnen batchvoorspellingen rechtstreeks vanuit een notebook of de itempagina voor een specifiek model maken. Ga naar deze resource voor meer informatie over PREDICT en voor meer informatie over het gebruik van PREDICT in Microsoft Fabric.
# Load the model back
loaded_treatmentmodel = mlflow.spark.load_model(treatment_model_uri, dfs_tmpdir="Files/spark")
loaded_controlmodel = mlflow.spark.load_model(control_model_uri, dfs_tmpdir="Files/spark")
# Make predictions
batch_predictions_treatment = loaded_treatmentmodel.transform(test_df)
batch_predictions_control = loaded_controlmodel.transform(test_df)
batch_predictions_treatment.show(5)
# Save the predictions in the lakehouse
batch_predictions_treatment.write.format("delta").mode("overwrite").save(
f"{DATA_FOLDER}/predictions/batch_predictions_treatment"
)
batch_predictions_control.write.format("delta").mode("overwrite").save(
f"{DATA_FOLDER}/predictions/batch_predictions_control"
)
# Determine the entire runtime
print(f"Full run cost {int(time.time() - ts)} seconds.")