Sdílet prostřednictvím


Kurz: Vytvoření, trénování a vyhodnocení modelu uplift

Tento kurz představuje ucelený příklad pracovního postupu Synapse Datová Věda v Microsoft Fabric. Naučíte se vytvářet, trénovat a vyhodnocovat modely upliftu a používat techniky modelování vzhůru.

Požadavky

Sledování v poznámkovém bloku

V poznámkovém bloku můžete postupovat jedním ze dvou způsobů:

  • Otevření a spuštění integrovaného poznámkového bloku v prostředí Datová Věda Synapse
  • Nahrání poznámkového bloku z GitHubu do prostředí synapse Datová Věda

Otevření integrovaného poznámkového bloku

Tento kurz doprovází ukázkový poznámkový blok modelování upliftu . Navštivte stránku Pro otevření integrovaného ukázkového poznámkového bloku kurzu v prostředí Synapse Datová Věda:1. Přejděte na domovskou stránku Synapse Datová Věda. 1. Vyberte Použít ukázku. 1. Vyberte odpovídající ukázku:* Na výchozí kartě Kompletní pracovní postupy (Python), pokud je ukázka pro kurz Pythonu. * Na kartě Kompletní pracovní postupy (R) platí, že pokud je ukázka pro kurz jazyka R. * Na kartě Rychlé kurzy , pokud je ukázka pro rychlý kurz.1. Než začnete spouštět kód, připojte k poznámkovému bloku lakehouse. Další informace o přístupu k integrovaným ukázkovým poznámkovým blokům najdete v kurzech.

Otevření integrovaného ukázkového poznámkového bloku kurzu v prostředí Datová Věda Synapse:

  1. Přechod na domovskou stránku synapse Datová Věda

  2. Výběr možnosti Použít ukázku

  3. Vyberte odpovídající ukázku:

    1. Na výchozí kartě Kompletní pracovní postupy (Python), pokud je ukázka pro kurz Pythonu
    2. Pokud je ukázka kurzu jazyka R na kartě Kompletní pracovní postupy (R)
    3. Pokud je ukázka ukázky pro rychlý kurz, na kartě Rychlé kurzy
  4. Než začnete spouštět kód, připojte k poznámkovému bloku lakehouse.

Import poznámkového bloku z GitHubu

Poznámkový blok AIsample - Uplift Modeling.ipynb doprovází tento kurz.

Pokud chcete otevřít doprovodný poznámkový blok pro tento kurz, postupujte podle pokynů v části Příprava systému na kurzy datových věd a importujte poznámkový blok do pracovního prostoru.

Pokud chcete raději zkopírovat a vložit kód z této stránky, můžete vytvořit nový poznámkový blok .

Než začnete spouštět kód, nezapomeňte k poznámkovému bloku připojit lakehouse.

Krok 1: Načtení dat

Datová sada

Testovací prostředí Criteo AI vytvořilo datovou sadu. Tato datová sada má 13M řádků. Každý řádek představuje jednoho uživatele. Každý řádek má 12 funkcí, indikátor léčby a dva binární popisky, které zahrnují návštěvu a převod.

Snímek obrazovky znázorňující strukturu datové sady Criteo AI Lab

  • f0 - f11: hodnoty funkcí (hustá, plovoucí hodnota)
  • léčba: zda byl uživatel náhodně zaměřen na léčbu (například reklama) (1 = léčba, 0 = kontrola)
  • převod: jestli došlo k převodu (například nákup) pro uživatele (binární, popisek)
  • visit: zda došlo k převodu (například nákup) pro uživatele (binární, popisek)

Citace

Datová sada používaná pro tento poznámkový blok vyžaduje tuto citaci BibTex:

@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

Definováním následujících parametrů můžete tento poznámkový blok snadno použít u různých datových sad.

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

Import knihoven

Před zpracováním je nutné importovat požadované knihovny Spark a SynapseML. Musíte také importovat knihovnu vizualizací dat – například Seaborn, knihovnu vizualizací dat Pythonu. Knihovna vizualizací dat poskytuje rozhraní vysoké úrovně pro vytváření vizuálních prostředků na datových rámcích a polích. Přečtěte si další informace o Sparku, SynapseML a Seabornu.

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

Stažení datové sady a nahrání do lakehouse

Tento kód stáhne veřejně dostupnou verzi datové sady a pak uloží tento datový prostředek do objektu Fabric Lakehouse.

Důležité

Než ho spustíte, nezapomeňte do poznámkového bloku přidat lakehouse . Pokud to neuděláte, dojde k chybě.

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.")

Spusťte záznam modulu runtime tohoto poznámkového bloku.

# Record the notebook running time
import time

ts = time.time()

Nastavení sledování experimentu MLflow

Pokud chcete rozšířit možnosti protokolování MLflow, automatické protokolování automaticky zaznamenává hodnoty vstupních parametrů a výstupních metrik modelu strojového učení během trénování. Tyto informace se pak zaprotokolují do pracovního prostoru, kde k němu mají přístup a vizualizovat rozhraní API MLflow nebo odpovídající experiment v pracovním prostoru. Další informace o automatickém přihlašování najdete v tomto zdroji.

# Set up the MLflow experiment
import mlflow

mlflow.set_experiment(EXPERIMENT_NAME)
mlflow.autolog(disable=True)  # Disable MLflow autologging

Poznámka:

Pokud chcete zakázat automatické protokolování Microsoft Fabric v relaci poznámkového bloku, zavolejte mlflow.autolog() a nastavte disable=True.

Čtení dat z jezera

Přečtěte si nezpracovaná data z oddílu Soubory lakehouse a přidejte další sloupce pro různé části kalendářních dat. Stejné informace slouží k vytvoření dělené tabulky delta.

raw_df = spark.read.csv(f"{DATA_FOLDER}/raw/{DATA_FILE}", header=True, inferSchema=True).cache()

Krok 2: Průzkumná analýza dat

display Pomocí příkazu můžete zobrazit statistiky vysoké úrovně o datové sadě. Můžete také zobrazit zobrazení grafů, abyste mohli snadno vizualizovat podmnožinu datové sady.

display(raw_df.limit(20))

Prozkoumejte procento uživatelů, kteří navštíví, procento uživatelů, kteří převedou, a procento návštěvníků, které převedou.

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()

Analýza udává, že 4,9 % uživatelů z testovací skupiny – uživatelé, kteří obdrželi léčbu nebo reklamu – navštívili online obchod. Totéž udělalo pouze 3,8 % uživatelů z kontrolní skupiny – uživatelé, kteří nikdy nedostali léčbu, nebo nikdy nebyli nabízeni ani vystaveni reklamě. Kromě toho se 0,31 % všech uživatelů z testovací skupiny změnilo nebo si koupilo – zatímco pouze 0,19 % uživatelů z kontrolní skupiny to udělalo. V důsledku toho je míra konverze návštěvníků, kteří provedli nákup, kteří byli také členy testovací skupiny, 6,36 %, oproti pouze 5,07%** pro uživatele kontrolní skupiny. Na základě těchto výsledků může léčba potenciálně zlepšit míru návštěv o přibližně 1 %, a míru konverze návštěvníků o přibližně 1,3 %. Léčba vede k významnému zlepšení.

Krok 3: Definování modelu pro trénování

Příprava trénování a testování datových sad

V tomto případě se do datového raw_df rámce vejde transformátor Featurize, který extrahuje funkce ze zadaných vstupních sloupců a vypíše tyto funkce do nového sloupce s názvem features.

Výsledný datový rámec je uložen v novém datovém rámci s názvem 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()

Příprava zpracování a řízení datových sad

Po vytvoření trénovacích a testovacích datových sad musíte také vytvořit testovací a řídicí datové sady, abyste mohli vytrénovat modely strojového učení tak, aby změřily výkon.

# 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")

Teď, když jste připravili data, můžete pokračovat v trénování modelu pomocí LightGBM.

Uplift modeling: T-Learner with LightGBM

Metaučující jsou sada algoritmů založených na algoritmech strojového učení, jako je LightGBM, Xgboost atd. Pomáhají odhadnout podmíněný průměrný účinek léčby nebo CATE. T-learner je metauč, který nepoužívá jediný model. Místo toho T-learner používá jeden model na proměnnou ošetření. Proto jsou vyvinuty dva modely a jako t-learner se odkazujeme na metaučujícího. T-learner používá více modelů strojového učení k překonání problému zcela zahození léčby tím, že vynutí, aby se na něj nejprve rozdělil.

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
     

Použití testovací datové sady pro predikci

V této části použijete k treatment_model control_modeltransformaci test_df testovací datové sady sadu a , jak je definována dříve. Pak vypočítáte predikovaný uplift. Předpovězený vzestup definujete jako rozdíl mezi predikovaným výsledkem léčby a predikovaným kontrolním výsledkem. Tím větší je predikovaný rozdíl ve zvýšení výkonu, tím větší je účinnost léčby (například reklama) u jednotlivce nebo podskupiny.

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))

Vyhodnocení modelu

Vzhledem k tomu, že skutečný zvedání nelze pozorovat u každého jednotlivce, je nutné měřit zvedání nad skupinou jednotlivců. Použijete křivku upliftu, která vykreslují skutečný, kumulativní vzestup v rámci populace.

Snímek obrazovky s grafem, který znázorňuje normalizovanou křivku modelu vzestupného v porovnání s náhodným ošetřením

Osa x představuje poměr populace vybrané pro léčbu. Hodnota 0 naznačuje, že žádná testovací skupina - nikdo není vystaven ani nabízen, léčba. Hodnota 1 navrhuje úplnou skupinu léčby - všichni jsou vystaveni nebo nabízena léčba. Osa y zobrazuje míru zvedání. Cílem je najít velikost testovací skupiny nebo procento populace, která by byla nabízena nebo vystavena léčbě (například reklama). Tento přístup optimalizuje výběr cíle pro optimalizaci výsledku.

Nejprve seřadí pořadí testovacích datových rámců podle předpovídaného upliftu. Predikovaný vzestup je rozdíl mezi predikovaným výsledkem léčby a predikovaným kontrolním výsledkem.

# 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))

V dalším kroku vypočítejte kumulativní procento návštěv v testovacích i kontrolních skupinách.

# 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))

Nakonec při každém procentu vypočítejte vzestup skupiny jako rozdíl mezi kumulativním procentem návštěv mezi léčbou a kontrolními skupinami.

test_ranked_df = test_ranked_df.withColumn("group_uplift", F.col("treatment_cumsum") - F.col("control_cumsum")).cache()
display(test_ranked_df.limit(20))

Nyní vykreslujte křivku zvedání pro předpověď testovací datové sady. Před vykreslením je nutné převést datový rámec PySpark na datový rámec Pandas.

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")

Snímek obrazovky s grafem, který znázorňuje normalizovanou křivku modelu vzestupného v porovnání s náhodným ošetřením

Osa x představuje poměr populace vybrané pro léčbu. Hodnota 0 naznačuje, že žádná testovací skupina - nikdo není vystaven ani nabízen, léčba. Hodnota 1 navrhuje úplnou skupinu léčby - všichni jsou vystaveni nebo nabízena léčba. Osa y zobrazuje míru zvedání. Cílem je najít velikost testovací skupiny nebo procento populace, která by byla nabízena nebo vystavena léčbě (například reklama). Tento přístup optimalizuje výběr cíle pro optimalizaci výsledku.

Nejprve seřadí pořadí testovacích datových rámců podle předpovídaného upliftu. Predikovaný vzestup je rozdíl mezi predikovaným výsledkem léčby a predikovaným kontrolním výsledkem.

# 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))

V dalším kroku vypočítejte kumulativní procento návštěv v testovacích i kontrolních skupinách.

# 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))

Nakonec při každém procentu vypočítejte vzestup skupiny jako rozdíl mezi kumulativním procentem návštěv mezi léčbou a kontrolními skupinami.

test_ranked_df = test_ranked_df.withColumn("group_uplift", F.col("treatment_cumsum") - F.col("control_cumsum")).cache()
display(test_ranked_df.limit(20))

Nyní vykreslujte křivku zvedání pro předpověď testovací datové sady. Před vykreslením je nutné převést datový rámec PySpark na datový rámec Pandas.

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")

Snímek obrazovky s grafem, který znázorňuje normalizovanou křivku modelu vzestupného v porovnání s náhodným ošetřením

Analýza i křivka nahoru ukazují, že top 20% populace, jak je seřazeno podle předpovědi, by měl velký zisk v případě, že obdrželi léčbu. To znamená, že top 20 % populace představuje skupinu persuadables. Proto můžete nastavit skóre pro požadovanou velikost testovací skupiny na 20 %, abyste identifikovali cílové zákazníky výběru pro největší dopad.

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}
)

Krok 4: Registrace konečného modelu ML

Pomocí MLflow můžete sledovat a protokolovat všechny experimenty pro testovací i kontrolní skupiny. Toto sledování a protokolování zahrnuje odpovídající parametry, metriky a modely. Tyto informace se protokolují pod názvem experimentu v pracovním prostoru pro pozdější použití.

# 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()

Zobrazení experimentů:

  1. Na levém panelu vyberte pracovní prostor.
  2. Vyhledejte a vyberte název experimentu, v tomto případě aisample-upliftmodelling.

Snímek obrazovky znázorňující výsledky experimentu se zprovozněním modelu

Krok 5: Uložení výsledků předpovědi

Microsoft Fabric nabízí funkci PREDICT – škálovatelnou funkci, která podporuje dávkové bodování v jakémkoli výpočetním modulu. Umožňuje zákazníkům zprovoznit modely strojového učení. Uživatelé můžou vytvářet dávkové předpovědi přímo z poznámkového bloku nebo stránky položky pro konkrétní model. Další informace o funkci PREDICT najdete v tomto zdroji a dozvíte se, jak používat funkci PREDICT v 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.")