Membuat, melatih, dan mengevaluasi model uplift di Microsoft Fabric

Dalam artikel ini, pelajari cara membuat, melatih, dan mengevaluasi model peningkatan dan menerapkan teknik pemodelan peningkatan.

Penting

Microsoft Fabric saat ini dalam PRATINJAU. Informasi ini berkaitan dengan produk prarilis yang mungkin dimodifikasi secara substansial sebelum dirilis. Microsoft tidak memberikan jaminan, dinyatakan atau tersirat, sehubungan dengan informasi yang diberikan di sini.

  • Apa itu pemodelan yang lebih baik?

    Ini adalah keluarga teknologi inferensi kausal yang menggunakan model pembelajaran mesin untuk memperkirakan efek kausal dari beberapa perawatan pada perilaku individu.

    • Persuadables hanya merespons positif terhadap perawatan
    • Sleeping-dogs memiliki respons negatif yang kuat terhadap perawatan
    • Kehilangan penyebab tidak pernah mencapai hasil bahkan dengan perawatan
    • Yakin hal-hal selalu mencapai hasil dengan atau tanpa perawatan

    Tujuan pemodelan uplift adalah untuk mengidentifikasi "persuadables", tidak membuang-buang upaya pada "yakin hal-hal" dan "kehilangan penyebab", dan menghindari mengganggu "anjing tidur"

  • Bagaimana cara kerja pemodelan uplift?

    • Meta Learner: memprediksi perbedaan antara perilaku individu ketika ada perawatan dan ketika tidak ada perawatan
    • Uplift Tree: algoritma berbasis pohon di mana kriteria pemisahan didasarkan pada perbedaan peningkatan
    • Model berbasis NN:model jaringan neural yang biasanya berfungsi dengan data pengamatan
  • Di mana pemodelan yang dapat ditingkatkan berfungsi?

    • Pemasaran: membantu mengidentifikasi persuadables untuk menerapkan perawatan seperti kupon atau iklan online
    • Perawatan Medis: membantu memahami bagaimana perawatan dapat memengaruhi kelompok tertentu secara berbeda

Prasyarat

Langkah 1: Muat data

Tip

Contoh berikut mengasumsikan bahwa Anda menjalankan kode dari sel di buku catatan. Untuk informasi tentang membuat dan menggunakan buku catatan, lihat Cara menggunakan buku catatan.

Konfigurasi buku catatan

Dengan menentukan parameter di bawah ini, Anda dapat menerapkan contoh ini ke himpunan data yang berbeda.

IS_CUSTOM_DATA = False  # if True, dataset has to be uploaded manually by user
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

Mengimpor dependensi

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 os
import gzip

import mlflow

Mengunduh himpunan data dan mengunggah ke Lakehouse

Penting

Tambahkan Lakehouse ke buku catatan Anda sebelum menjalankannya.

  • Deskripsi himpunan data: Criteo AI Lab membuat himpunan data ini. Himpunan data terdiri dari baris 13M, masing-masing mewakili pengguna dengan 12 fitur, indikator perawatan dan 2 label biner (kunjungan dan konversi).

    • f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11: nilai fitur (padat, mengambang)
    • perawatan: grup perawatan (1 = dirawat, 0 = kontrol) yang menunjukkan apakah pelanggan ditargetkan oleh iklan secara acak
    • konversi: apakah konversi terjadi untuk pengguna ini (biner, label)
    • kunjungi: apakah kunjungan terjadi untuk pengguna ini (biner, label)
  • Beranda himpunan data: https://ailab.criteo.com/criteo-uplift-prediction-dataset/

  • Rujukan:

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

Membaca data dari Lakehouse

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

display(raw_df.limit(20))

Langkah 2: Menyiapkan himpunan data

Eksplorasi data

  • Tingkat keseluruhan pengguna yang mengunjungi/mengonversi

    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()
    
  • Efek pengobatan rata-rata keseluruhan pada kunjungan

    raw_df.groupby("treatment").agg(
         F.mean("visit").alias("Mean of visit"),
         F.sum("visit").alias("Sum of visit"),
         F.count("visit").alias("Count"),
    ).show()
    
  • Efek perawatan rata-rata keseluruhan pada konversi

    raw_df.groupby("treatment").agg(
         F.mean("conversion").alias("Mean of conversion"),
         F.sum("conversion").alias("Sum of conversion"),
         F.count("conversion").alias("Count"),
    ).show()
    

Memisahkan himpunan data uji pelatihan

transformer = (
    Featurize().setOutputCol("features").setInputCols(FEATURE_COLUMNS).fit(raw_df)
)

df = transformer.transform(raw_df)
train_df, test_df = df.randomSplit([0.8, 0.2], seed=42)

print("Size of train dataset: %d" % train_df.count())
print("Size of test dataset: %d" % test_df.count())

train_df.groupby(TREATMENT_COLUMN).count().show()

Memisahkan himpunan data kontrol perawatan

treatment_train_df = train_df.where(f"{TREATMENT_COLUMN} > 0")
control_train_df = train_df.where(f"{TREATMENT_COLUMN} = 0")

Langkah 3: Pelatihan dan evaluasi model

Pemodelan uplift: T-Learner dengan LightGBM

classifier = (
    LightGBMClassifier()
    .setFeaturesCol("features")
    .setNumLeaves(10)
    .setNumIterations(100)
    .setObjective("binary")
    .setLabelCol(LABEL_COLUMN)
)

treatment_model = classifier.fit(treatment_train_df)
control_model = classifier.fit(control_train_df)

Memprediksi himpunan data pengujian

getPred = F.udf(lambda v: float(v[1]), FloatType())

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(test_pred_df.limit(20))

Evaluasi model

Karena peningkatan aktual tidak dapat diamati untuk setiap individu, ukur peningkatan atas sekelompok pelanggan.

  • Kurva Peningkatan: memplot peningkatan kumulatif nyata di seluruh populasi

Pertama, beri peringkat urutan dataframe pengujian berdasarkan peningkatan prediksi.

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

Selanjutnya, hitung persentase kumulatif kunjungan di setiap kelompok (perawatan atau kontrol).

C = test_ranked_df.where(f"{TREATMENT_COLUMN} == 0").count()
T = test_ranked_df.where(f"{TREATMENT_COLUMN} != 0").count()

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(test_ranked_df.limit(20))

Terakhir, hitung peningkatan grup pada setiap persentase.

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

display(test_ranked_df.limit(20))

Sekarang Anda dapat memplot kurva peningkatan pada prediksi himpunan data pengujian. Anda perlu mengonversi dataframe pyspark ke dataframe pandas sebelum merencanakan.

def uplift_plot(uplift_df):
    """
    Plot the uplift curve
    """
    gain_x = uplift_df.percent_rank
    gain_y = uplift_df.group_uplift
    # plot the data
    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(b=True, which="major")

    return ax


test_ranked_pd_df = test_ranked_df.select(
    ["pred_uplift", "percent_rank", "group_uplift"]
).toPandas()
uplift_plot(test_ranked_pd_df)

Bagan memperlihatkan kurva model peningkatan yang dinormalisasi versus perawatan acak.

Dari kurva peningkatan dalam contoh sebelumnya, perhatikan bahwa populasi 20% teratas yang diberi peringkat oleh prediksi Anda memiliki keuntungan besar jika mereka diberi perawatan, yang berarti mereka adalah yang dibujuk. Oleh karena itu, Anda dapat mencetak skor cutoff pada persentase 20% untuk mengidentifikasi pelanggan target.

cutoff_percentage = 0.2
cutoff_score = test_ranked_pd_df.iloc[int(len(test_ranked_pd_df) * cutoff_percentage)][
    "pred_uplift"
]

print("Uplift score higher than {:.4f} are Persuadables".format(cutoff_score))

Mencatat dan memuat model dengan MLflow

Sekarang setelah Anda memiliki model terlatih, simpan untuk digunakan nanti. Dalam contoh berikut, MLflow digunakan untuk mencatat metrik dan model. Anda juga dapat menggunakan API ini untuk memuat model untuk prediksi.

# setup mlflow
mlflow.set_experiment(EXPERIMENT_NAME)
# log model, metrics and params
with mlflow.start_run() as run:
    print("log model:")
    mlflow.spark.log_model(
        treatment_model,
        f"{EXPERIMENT_NAME}-treatmentmodel",
        registered_model_name=f"{EXPERIMENT_NAME}-treatmentmodel",
        dfs_tmpdir="Files/spark",
    )

    mlflow.spark.log_model(
        control_model,
        f"{EXPERIMENT_NAME}-controlmodel",
        registered_model_name=f"{EXPERIMENT_NAME}-controlmodel",
        dfs_tmpdir="Files/spark",
    )

    model_uri = f"runs:/{run.info.run_id}/{EXPERIMENT_NAME}"
    print("Model saved in run %s" % run.info.run_id)
    print(f"Model URI: {model_uri}-treatmentmodel")
    print(f"Model URI: {model_uri}-controlmodel")
# load model back
loaded_treatmentmodel = mlflow.spark.load_model(
    f"{model_uri}-treatmentmodel", dfs_tmpdir="Files/spark"
)