Sdílet prostřednictvím


Tutoriál: Vytvoření, školení a hodnocení modelu podpory

Tento kurz představuje ucelený příklad pracovního postupu pro datové vědy Synapse v Microsoft Fabric. Naučíte se vytvářet, trénovat a vyhodnocovat modely pro zvýšení účinnosti a používat techniky modelování pro zvýšení účinnosti.

Požadavky

  • Znalost poznámkových bloků Microsoft Fabric
  • Lakehouse pro tento poznámkový blok, které slouží k ukládání dat pro tento příklad. Další informace najdete v tématu Přidání jezera do poznámkového bloku

Následujte v poznámkovém bloku

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

  • Otevřete a spusťte integrovaný poznámkový blok.
  • Nahrajte poznámkový blok z GitHubu.

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

Tento kurz doprovází ukázka modelování poznámkového bloku uplift.

  1. Pokud chcete otevřít ukázkový poznámkový blok pro tento kurz, postupujte podle pokynů v Příprava systému na kurzy datových věd.

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

Import poznámkového bloku z GitHubu

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

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

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

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

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 prvků, indikátor léčby a dva binární popisky, které zahrnují návštěvu a konverzi.

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

  • f0 - f11: hodnoty funkcí (hustá, plovoucí hodnota)
  • intervence: zda byl uživatel náhodně zařazen do intervenční skupiny (například při reklamě) (1 = intervence, 0 = kontrolní skupina)
  • konverze: zda došlo ke konverzi (například provedl nákup) pro uživatele (binární označení)
  • návštěva: zda došlo k konverzi (například k nákupu) pro uživatele (binární, označení)

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

Spropitné

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, SynapseMLa 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

Stáhněte datovou sadu a nahrajte ji do úložiště typu 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ý

Před spuštěním 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.")

Začněte měřit dobu běhu tohoto notebooku.

# 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 zaznamenají do pracovního prostoru, kde k nim mají přístup rozhraní API MLflow a odpovídající experiment v pracovním prostoru a mohou je vizualizovat. 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 v relaci poznámkového bloku zakázat automatické protokolování Microsoft Fabric, zavolejte mlflow.autolog() a nastavte disable=True.

Čtení dat z jezera

Přečtěte si nezpracovaná data z oddílu 'Lakehouse' souborů a přidejte další sloupce pro různé části 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

Pomocí příkazu display 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ělali jenom 3,8% uživatelů z kontrolní skupiny – uživatelé, kteří nikdy nedostali léčbu nebo nebyli nikdy nabízeni nebo vystaveni reklamě. Kromě toho 0,31% všech uživatelů z testovací skupiny převedli se, nebo provedli nákup – zatímco pouze 0,19% uživatelů z kontrolní skupiny to udělali. V důsledku toho je převodní sazba návštěvníků, kteří provedli nákup, kteří byli také členy testovací skupiny, 6,36%v porovnání 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 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 rámce raw_df 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.

Modelování vzestupu: T-Learner s LightGBM

Meta-učící se algoritmy jsou soubor algoritmů založených na algoritmech strojového učení, jako například LightGBM, Xgboost atd. Pomáhají při odhadování podmíněného průměrného účinku léčby nebo CATE. T-learner je meta-učitel, který nepoužívá jediný model. Místo toho T-learner používá jeden model na léčebnou proměnnou. Proto jsou vyvinuty dva modely a metaučícího nazýváme T-learner. T-learner používá více modelů strojového učení, aby překonal problém zcela zanedbání léčby tím, že přinutí model nejprve zohlednit tento faktor.

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

Tady použijete treatment_model a control_model, jak bylo dříve definováno, k transformaci test_df testovací sady dat. Pak vypočítáte předpokládaný nárůst. 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ý nárůst nelze pozorovat u každého jednotlivce, je nutné měřit nárůst ve skupině jednotlivců. Použijete křivku upliftu, která vykresluje skutečný, kumulativní vzestup v rámci populace.

snímek obrazovky s grafem, který zobrazuje normalizovanou křivku modelu nárůstu proti náhodnému srovnání

Osa x představuje poměr populace vybrané pro léčbu. Hodnota 0 naznačuje, že neexistuje žádná léčebná skupina - nikdo není vystaven léčbě ani mu léčba není nabízena. Hodnota 1 naznačuje úplnou léčebnou skupinu, ve které jsou všichni vystaveni léčbě nebo jim je léčba nabízena. Osa y zobrazuje míru navýšení. 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ý zobrazuje normalizovanou křivku modelu zvýšení proti náhodné léčbě

Osa x představuje poměr populace vybrané pro léčbu. Hodnota 0 naznačuje, že neexistuje žádná léčebná skupina - nikdo není vystaven léčení ani mu není nabízena léčba. Hodnota 1 naznačuje kompletní skupinu podstupující léčbu - všichni jsou léčbě vystaveni nebo jim je léčba nabízena. Osa y zobrazuje míru navýšení. 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ý zobrazuje normalizovanou křivku modelu upliftu versus náhodnou úpravu.

Analýza i křivka vzpruhu ukazují, že prvních 20 % populace%, seřazené podle předpovědi, by při podstoupení léčby zaznamenal značný nárůst. To znamená, že prvních 20% populace představuje skupinu, kterou lze přesvědčit. Proto můžete nastavit skóre pro požadovanou velikost léčebné skupiny na 20%, abyste identifikovali cílové zákazníky 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()

Chcete-li zobrazit své experimenty:

  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 s modelováním vzestupu aisample

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