Självstudie: Skapa, träna och utvärdera en upplyftningsmodell
I den här självstudien visas ett exempel från slutpunkt till slutpunkt på ett Synapse-Datavetenskap arbetsflöde i Microsoft Fabric. Du lär dig hur du skapar, tränar och utvärderar upplyftningsmodeller och tillämpar upplyftningsmodelleringstekniker.
Förutsättningar
Skaffa en Microsoft Fabric-prenumeration. Eller registrera dig för en kostnadsfri utvärderingsversion av Microsoft Fabric.
Logga in på Microsoft Fabric.
Använd upplevelseväxlaren till vänster på startsidan för att växla till Synapse Datavetenskap upplevelse.
- Kunskaper om Microsoft Fabric-notebook-filer
- Ett lakehouse för den här notebook-filen för att lagra data för det här exemplet. Mer information finns i Lägg till ett sjöhus i anteckningsboken
Följ med i en notebook-fil
Du kan följa med i en notebook-fil på något av två sätt:
- Öppna och kör den inbyggda notebook-filen i Synapse Datavetenskap-upplevelsen
- Ladda upp din notebook-fil från GitHub till Synapse Datavetenskap-upplevelsen
Öppna den inbyggda notebook-filen
Exempelanteckningsboken för Uplift-modellering medföljer den här självstudien. Besök För att öppna självstudiekursens inbyggda exempelanteckningsbok i Synapse Datavetenskap experience:1. Gå till startsidan för Synapse Datavetenskap. 1. Välj Använd ett exempel. 1. Välj motsvarande exempel:* På standardfliken för arbetsflöden från slutpunkt till slutpunkt (Python) om exemplet är för en Python-självstudiekurs. * Från fliken Arbetsflöden från slutpunkt till slutpunkt (R) om exemplet är för en R-självstudie. * Från fliken Snabb självstudier , om exemplet är för en snabb självstudie.1. Koppla ett lakehouse till notebook-filen innan du börjar köra kod. för mer information om åtkomst till inbyggda exempelanteckningsböcker för självstudier.
Så här öppnar du självstudiekursens inbyggda exempelanteckningsbok i Synapse Datavetenskap upplevelse:
Gå till startsidan för Synapse Datavetenskap
Välj Använd ett exempel
Välj motsvarande exempel:
- Från standardfliken för arbetsflöden från slutpunkt till slutpunkt (Python) om exemplet är för en Python-självstudie
- Från fliken Arbetsflöden från slutpunkt till slutpunkt (R) om exemplet är för en R-självstudie
- Om exemplet är till för en snabb självstudiekurs på fliken Snabbstudier
Koppla ett lakehouse till notebook-filen innan du börjar köra kod
Importera anteckningsboken från GitHub
Notebook-filen AIsample – Uplift Modeling.ipynb medföljer den här självstudien.
Om du vill öppna den medföljande notebook-filen för den här självstudien följer du anvisningarna i Förbereda systemet för självstudier för datavetenskap för att importera anteckningsboken till din arbetsyta.
Du kan skapa en ny notebook-fil om du hellre kopierar och klistrar in koden från den här sidan.
Se till att bifoga ett lakehouse i notebook-filen innan du börjar köra kod.
Steg 1: Läs in data
Datamängd
Criteo AI Lab skapade datauppsättningen. Datamängden har 13 miljoner rader. Varje rad representerar en användare. Varje rad har 12 funktioner, en behandlingsindikator och två binära etiketter som inkluderar besök och konvertering.
- f0 – f11: funktionsvärden (täta, flytande värden)
- behandling: om en användare slumpmässigt var mål för behandling (till exempel reklam) (1 = behandling, 0 = kontroll)
- konvertering: om en konvertering har inträffat (till exempel gjort ett köp) för en användare (binär, etikett)
- besök: om en konvertering har inträffat (till exempel gjort ett köp) för en användare (binär, etikett)
Hänvisning
- Startsida för datauppsättning: https://ailab.criteo.com/criteo-uplift-prediction-dataset/
Den datauppsättning som används för den här notebook-filen kräver denna BibTex-källhänvisning:
@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}
}
Dricks
Genom att definiera följande parametrar kan du enkelt använda den här notebook-filen på olika datauppsättningar.
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
Importera bibliotek
Innan du bearbetar måste du importera nödvändiga Spark- och SynapseML-bibliotek. Du måste också importera ett datavisualiseringsbibliotek – till exempel Seaborn, ett Python-datavisualiseringsbibliotek. Ett datavisualiseringsbibliotek tillhandahåller ett högnivågränssnitt för att skapa visuella resurser på DataFrames och matriser. Läs mer om Spark, SynapseML och 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
Ladda ned en datauppsättning och ladda upp till lakehouse
Den här koden laddar ned en offentligt tillgänglig version av datauppsättningen och lagrar sedan den dataresursen i en Infrastruktursjöhus.
Viktigt!
Se till att du lägger till ett sjöhus i anteckningsboken innan du kör det. Om du inte gör det uppstår ett fel.
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.")
Börja spela in körningen av den här notebook-filen.
# Record the notebook running time
import time
ts = time.time()
Konfigurera MLflow-experimentspårning
För att utöka MLflow-loggningsfunktionerna samlar automatisk loggning automatiskt in värdena för indataparametrar och utdatamått för en maskininlärningsmodell under träningen. Den här informationen loggas sedan till arbetsytan, där MLflow-API:erna eller motsvarande experiment på arbetsytan kan komma åt och visualisera den. Besök den här resursen om du vill ha mer information om automatisk loggning.
# Set up the MLflow experiment
import mlflow
mlflow.set_experiment(EXPERIMENT_NAME)
mlflow.autolog(disable=True) # Disable MLflow autologging
Kommentar
Om du vill inaktivera automatisk loggning av Microsoft Fabric i en notebook-session anropar mlflow.autolog()
du och anger disable=True
.
Läsa data från lakehouse
Läs rådata från avsnittet Lakehouse Files och lägg till fler kolumner för olika datumdelar. Samma information används för att skapa en partitionerad deltatabell.
raw_df = spark.read.csv(f"{DATA_FOLDER}/raw/{DATA_FILE}", header=True, inferSchema=True).cache()
Steg 2: Undersökande dataanalys
display
Använd kommandot för att visa statistik på hög nivå om datauppsättningen. Du kan också visa diagramvyerna för att enkelt visualisera delmängder av datamängden.
display(raw_df.limit(20))
Granska procentandelen av de användare som besöker, procentandelen användare som konverterar och procentandelen besökare som konverterar.
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()
Analysen visar att 4,9% av användarna från behandlingsgruppen - användare som fick behandlingen eller reklam - besökte onlinebutiken. Endast 3,8% av användarna från kontrollgruppen - användare som aldrig fick behandlingen, eller aldrig erbjöds eller exponerades för reklam - gjorde detsamma. Dessutom konverterade eller gjorde 0,31 % av alla användare från behandlingsgruppen ett köp , medan endast 0,19 % av användarna från kontrollgruppen gjorde det. Som ett resultat är konverteringsgraden för besökare som gjorde ett köp, som också var medlemmar i behandlingsgruppen, 6,36%, jämfört med endast 5,07%** för användare av kontrollgruppen. Baserat på dessa resultat kan behandlingen potentiellt förbättra besöksfrekvensen med cirka 1%, och omräkningsfrekvensen för besökare med cirka 1,3%. Behandlingen leder till en betydande förbättring.
Steg 3: Definiera modellen för träning
Förbereda träningen och testa datauppsättningarna
Här kan du anpassa en Featurize-transformator till raw_df
DataFrame för att extrahera funktioner från de angivna indatakolumnerna och mata ut dessa funktioner till en ny kolumn med namnet features
.
Resulterande DataFrame lagras i en ny DataFrame med namnet 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()
Förbereda datauppsättningarna för behandling och kontroll
När du har skapat tränings- och testdatauppsättningarna måste du också bilda datauppsättningarna för behandling och kontroll för att träna maskininlärningsmodellerna för att mäta upplyftningen.
# 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 när du har förberett dina data kan du fortsätta att träna en modell med LightGBM.
Upplyftningsmodellering: T-Learner med LightGBM
Metainlärare är en uppsättning algoritmer som bygger på maskininlärningsalgoritmer som LightGBM, Xgboost osv. De hjälper till att beräkna villkorsstyrd genomsnittlig behandlingseffekt, eller CATE. T-learner är en metainlärare som inte använder en enda modell. I stället använder T-learner en modell per behandlingsvariabel. Därför utvecklas två modeller och vi refererar till meta-learner som T-learner. T-learner använder flera maskininlärningsmodeller för att lösa problemet med att helt ta bort behandlingen, genom att tvinga eleven att först dela på den.
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
Använda testdatauppsättningen för en förutsägelse
Här använder treatment_model
du och control_model
, som båda definierades tidigare, för att transformera testdatauppsättningen test_df
. Sedan beräknar du den förväntade upplyftningen. Du definierar den förutsagda upplyftningen som skillnaden mellan det förväntade behandlingsresultatet och det förutsagda kontrollresultatet. Ju större denna förutsagda ökningsskillnad är, desto större blir behandlingens effektivitet (till exempel reklam) på en individ eller en undergrupp.
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))
Utföra modellutvärdering
Eftersom faktisk upplyftning inte kan observeras för varje individ måste du mäta upplyftningen över en grupp individer. Du använder en upplyftningskurva som ritar den verkliga, kumulativa upplyftningen i hela populationen.
X-axeln representerar förhållandet mellan den population som valts för behandlingen. Ett värde på 0 tyder på att ingen behandlingsgrupp - ingen exponeras för, eller erbjuds, behandlingen. Ett värde på 1 tyder på en fullständig behandlingsgrupp - alla utsätts för, eller erbjuds, behandlingen. Y-axeln visar upplyftningsmåttet. Syftet är att hitta storleken på behandlingsgruppen, eller den procentandel av befolkningen som skulle erbjudas eller exponeras för behandlingen (till exempel reklam). Den här metoden optimerar målvalet för att optimera resultatet.
Rangordna först dataramens testordning efter den förutsagda upplyftningen. Den förutsagda upplyftningen är skillnaden mellan det förväntade behandlingsresultatet och det förväntade kontrollresultatet.
# 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))
Beräkna sedan den kumulativa procentandelen besök i både behandlings- och kontrollgrupperna.
# 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))
Vid varje procent beräknar du slutligen upplyftningen av gruppen som skillnaden mellan den kumulativa procentandelen besök mellan behandlings- och kontrollgrupperna.
test_ranked_df = test_ranked_df.withColumn("group_uplift", F.col("treatment_cumsum") - F.col("control_cumsum")).cache()
display(test_ranked_df.limit(20))
Rita nu upplyftningskurvan för förutsägelsen av testdatauppsättningen. Du måste konvertera PySpark DataFrame till en Pandas DataFrame innan du ritar.
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")
X-axeln representerar förhållandet mellan den population som valts för behandlingen. Ett värde på 0 tyder på att ingen behandlingsgrupp - ingen exponeras för, eller erbjuds, behandlingen. Ett värde på 1 tyder på en fullständig behandlingsgrupp - alla utsätts för, eller erbjuds, behandlingen. Y-axeln visar upplyftningsmåttet. Syftet är att hitta storleken på behandlingsgruppen, eller den procentandel av befolkningen som skulle erbjudas eller exponeras för behandlingen (till exempel reklam). Den här metoden optimerar målvalet för att optimera resultatet.
Rangordna först dataramens testordning efter den förutsagda upplyftningen. Den förutsagda upplyftningen är skillnaden mellan det förväntade behandlingsresultatet och det förväntade kontrollresultatet.
# 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))
Beräkna sedan den kumulativa procentandelen besök i både behandlings- och kontrollgrupperna.
# 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))
Vid varje procent beräknar du slutligen upplyftningen av gruppen som skillnaden mellan den kumulativa procentandelen besök mellan behandlings- och kontrollgrupperna.
test_ranked_df = test_ranked_df.withColumn("group_uplift", F.col("treatment_cumsum") - F.col("control_cumsum")).cache()
display(test_ranked_df.limit(20))
Rita nu upplyftningskurvan för förutsägelsen av testdatauppsättningen. Du måste konvertera PySpark DataFrame till en Pandas DataFrame innan du ritar.
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")
Analysen och upplyftningskurvan visar båda att den översta 20% populationen, enligt förutsägelsen, skulle ha en stor vinst om de fick behandlingen. Det innebär att de översta 20 % av populationen representerar gruppen med övertalningsbara objekt. Därför kan du sedan ange brytpoängen för den önskade storleken på behandlingsgruppen till 20 %, för att identifiera målvalskunderna för den största effekten.
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}
)
Steg 4: Registrera den slutliga ML-modellen
Du använder MLflow för att spåra och logga alla experiment för både behandlings- och kontrollgrupper. Den här spårningen och loggningen omfattar motsvarande parametrar, mått och modeller. Den här informationen loggas under experimentnamnet på arbetsytan för senare användning.
# 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()
Så här visar du dina experiment:
- Välj din arbetsyta i den vänstra panelen.
- Leta upp och välj experimentnamnet, i det här fallet aisample-upliftmodelling.
Steg 5: Spara förutsägelseresultatet
Microsoft Fabric erbjuder PREDICT – en skalbar funktion som stöder batchbedömning i alla beräkningsmotorer. Det gör det möjligt för kunder att operationalisera maskininlärningsmodeller. Användare kan skapa batchförutsägelser direkt från en notebook-fil eller objektsidan för en specifik modell. Besök den här resursen om du vill veta mer om PREDICT och lära dig hur du använder PREDICT i 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.")