다음을 통해 공유


자습서: 변동 예측 모델 만들기, 평가 및 점수 매기기

이 자습서에서는 Microsoft Fabric에서 Synapse 데이터 과학 워크플로의 엔드투엔드 예시를 제공합니다. 이 시나리오는 은행 고객의 이탈 여부를 예측하는 모델을 빌드합니다. 변동률 또는 감소율에는 은행 고객이 은행과 사업을 종료하는 비율이 포함됩니다.

이 자습서에서는 다음과 같은 단계를 다룹니다.

  • 사용자 지정 라이브러리 설치
  • 데이터 로드
  • 예비 데이터 분석을 통해 데이터 이해 및 처리 및 패브릭 데이터 랭글러 기능의 사용 표시
  • scikit-learn 및 LightGBM을 사용하여 기계 학습 모델을 학습시키고 MLflow 및 패브릭 자동 로깅 기능을 사용하여 실험을 추적합니다.
  • 최종 기계 학습 모델 평가 및 저장
  • Power BI 시각화를 사용하여 모델 성능 표시

필수 조건

Notebook에서 따라 하기

다음 옵션 중 하나를 선택하여 Notebook에서 따를 수 있습니다.

  • 데이터 과학 환경에서 기본 제공 Notebook 열기 및 실행
  • GitHub에서 데이터 과학 환경으로 Notebook 업로드

기본 제공 Notebook 열기

샘플 고객 이탈 Notebook은 이 자습서와 함께 제공됩니다.

Synapse 데이터 과학 환경에서 자습서의 기본 제공 샘플 Notebook을 열려면 다음을 수행합니다.

  1. Synapse 데이터 과학 홈페이지로 이동합니다.

  2. 샘플 사용을 선택합니다.

  3. 해당 샘플을 선택합니다.

    • 샘플이 Python 자습서용인 경우, 기본 엔드 투 엔드 워크플로(Python) 탭에서.
    • 샘플이 R 자습서용인 경우, 엔드 투 엔드 워크플로(R) 탭에서.
    • 샘플이 빠른 자습서용인 경우, 빠른 자습서 탭에서.
  4. 코드 실행을 시작하기 전에 레이크하우스를 Notebook에 연결합니다.

GitHub에서 Notebook 가져오기

AIsample - Bank Customer Churn.ipynb Notebook은 이 자습서와 함께 제공됩니다.

이 자습서에 대해 함께 제공되는 Notebook을 열려면 데이터 과학 자습서를 위해 시스템 준비 자습서의 지침에 따라 Notebook을 작업 영역으로 가져옵니다.

이 페이지에서 코드를 복사하여 붙여 넣으면 새 Notebook을 만들 수 있습니다.

코드 실행을 시작하기 전에 레이크하우스를 Notebook에 연결해야 합니다.

1단계: 사용자 지정 라이브러리 설치

기계 학습 모델 개발 또는 임시 데이터 분석의 경우 Apache Spark 세션에 대한 사용자 지정 라이브러리를 신속하게 설치해야 할 수 있습니다. 라이브러리를 설치하는 두 가지 옵션이 있습니다.

  • 현재 Notebook에만 라이브러리를 설치하려면 Notebook의 인라인 설치 기능(%pip 또는 %conda)을 사용합니다.
  • 또는 Fabric 환경을 만들거나, 공개 소스에서 라이브러리를 설치하거나, 사용자 지정 라이브러리를 업로드한 다음, 작업 영역 관리자가 해당 환경을 작업 영역의 기본값으로 연결할 수 있습니다. 그러면 환경의 모든 라이브러리를 작업 영역의 모든 Notebook 및 Spark 작업 정의에서 사용할 수 있게 됩니다. 환경에 대한 자세한 내용은 Microsoft Fabric에서 환경 만들기, 구성 및 사용을 참조하세요.

이 자습서에서는 %pip install(을)를 사용하여 Notebook에 imblearn 라이브러리를 설치합니다.

참고 항목

%pip install 실행 후 PySpark 커널이 다시 시작됩니다. 다른 셀을 실행하기 전에 필요한 라이브러리를 설치합니다.

# Use pip to install libraries
%pip install imblearn

2단계: 데이터 로드

churn.csv 데이터 세트에는 10,000명의 고객의 변동 상태와 다음을 포함하는 14개의 특성이 포함됩니다.

  • 신용 점수
  • 지리적 위치(독일, 프랑스, 스페인)
  • 성별(남성, 여성).
  • 나이
  • 재임 기간(해당 은행에서 고객이 된 기간 수)
  • 계정 잔액
  • 예상 급여
  • 고객이 은행을 통해 구매한 제품 수
  • 신용 카드 상태(고객에게 신용 카드가 있는지 여부)
  • 활성 회원 상태(사용자가 활성 은행 고객인지 여부)

데이터 세트에는 행 번호, 고객 ID 및 고객 성 열도 포함됩니다. 이러한 열의 값은 고객이 은행을 떠나기로 한 결정에 영향을 주지 않아야 합니다.

고객 은행 계좌 폐쇄 이벤트는 해당 고객의 변동을 정의합니다. 데이터 세트 Exited 열은 고객의 중단을 나타냅니다. 이러한 특성에 대한 컨텍스트가 거의 없으므로 데이터 세트에 대한 배경 정보가 필요하지 않습니다. 이러한 특성이 Exited 상태에 어떻게 기여하는지 이해하려고 합니다.

10,000명의 고객 중 2037명의 고객(약 20%)만이 은행을 떠났습니다. 클래스 불균형 비율 때문에 합성 데이터를 생성하는 것이 좋습니다. 혼동 행렬 정확도는 불균형 분류와 관련이 없을 수 있습니다. AUPRC(정밀도 재현율 곡선) 아래 영역을 사용하여 정확도를 측정하려고 할 수 있습니다.

  • 이 표에는 churn.csv 데이터의 미리 보기가 표시됩니다.
CustomerID CreditScore 지리 성별 나이 보유 Balance NumOfProducts HasCrCard IsActiveMember EstimatedSalary 종료
15634602 하그레이브 619 프랑스 여성 42 2 0.00 1 1 1 101348.88 1
15647311 언덕 608 스페인 여성 41 1 83807.86 1 0 1 112542.58 0

데이터 세트를 다운로드하고 레이크하우스에 업로드

다른 데이터 세트와 함께 이 Notebook을 사용할 수 있도록 이러한 매개 변수를 정의합니다.

IS_CUSTOM_DATA = False  # If TRUE, the dataset has to be uploaded manually

IS_SAMPLE = False  # If TRUE, use only SAMPLE_ROWS of data for training; otherwise, use all data
SAMPLE_ROWS = 5000  # If IS_SAMPLE is True, use only this number of rows for training

DATA_ROOT = "/lakehouse/default"
DATA_FOLDER = "Files/churn"  # Folder with data files
DATA_FILE = "churn.csv"  # Data file name

이 코드는 공개적으로 사용 가능한 버전의 데이터 세트를 다운로드한 다음, 해당 데이터 세트를 Fabric 레이크하우스에 저장합니다.

Important

실행하기 전에 Notebook에 레이크하우스를 추가합니다. 그렇게 하지 않으면 오류가 발생합니다.

import os, requests
if not IS_CUSTOM_DATA:
# With an Azure Synapse Analytics blob, this can be done in one line

# Download demo data files into the lakehouse if they don't exist
    remote_url = "https://synapseaisolutionsa.blob.core.windows.net/public/bankcustomerchurn"
    file_list = ["churn.csv"]
    download_path = "/lakehouse/default/Files/churn/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)
    for fname in file_list:
        if not os.path.exists(f"{download_path}/{fname}"):
            r = requests.get(f"{remote_url}/{fname}", timeout=30)
            with open(f"{download_path}/{fname}", "wb") as f:
                f.write(r.content)
    print("Downloaded demo data files into lakehouse.")

Notebook을 실행하는 데 필요한 시간 기록을 시작합니다.

# Record the notebook running time
import time

ts = time.time()

레이크하우스에서 원시 데이터 읽기

이 코드는 레이크하우스의 파일 구역에서 원시 데이터를 읽고 다른 날짜 부분에 대해 더 많은 열을 추가합니다. 분할된 델타 테이블을 만들면 이 정보가 사용됩니다.

df = (
    spark.read.option("header", True)
    .option("inferSchema", True)
    .csv("Files/churn/raw/churn.csv")
    .cache()
)

Pandas DataFrame에서 데이터 세트 만들기

이 코드는 더 쉽게 처리하고 시각화할 수 있도록 Spark DataFrame을 pandas DataFrame으로 변환합니다.

df = df.toPandas()

3단계: 예비 데이터 분석 수행

원시 데이터 표시

display(을)를 사용하여 원시 데이터를 탐색하고, 몇 가지 기본 통계를 계산하고, 차트 보기를 표시합니다. 먼저 데이터 시각화에 필요한 라이브러리(예: seaborn)를 가져와야 합니다. Seaborn은 Python 데이터 시각화 라이브러리이며 데이터 프레임 및 배열에 대한 시각적 개체를 빌드하는 고급 인터페이스를 제공합니다.

import seaborn as sns
sns.set_theme(style="whitegrid", palette="tab10", rc = {'figure.figsize':(9,6)})
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
from matplotlib import rc, rcParams
import numpy as np
import pandas as pd
import itertools
display(df, summary=True)

데이터 랭글러를 사용하여 초기 데이터 정리 수행

Launch Data Wrangler는 Notebook에서 직접 데이터 랭글러를 시작하여 Pandas DataFrame을 탐색하고 변환할 수 있습니다. Notebook 리본 데이터 탭에서 데이터 랭글러 드롭다운 프롬프트를 사용하여 편집에 사용할 수 있는 활성화된 pandas DataFrames를 찾아봅니다. 데이터 랭글러에서 열려는 DataFrame을 선택합니다.

참고 항목

Notebook 커널이 통화 중인 동안에는 Data Wrangler를 열 수 없습니다. 데이터 랭글러를 시작하기 전에 셀 실행이 완료되어야 합니다. 데이터 랭글러에 대해 자세히 알아봅니다.

데이터 랭글러에 액세스할 수 있는 위치를 보여 주는 스크린샷.

데이터 랭글러가 시작되면 다음 이미지와 같이 데이터 패널에 대한 설명적인 개요가 생성됩니다. 개요에는 DataFrame의 차원, 누락된 값 등에 대한 정보가 포함되어 있습니다. Data Wrangler를 사용하여 스크립트를 생성하여 값이 누락된 행, 중복 행 및 특정 이름의 열을 삭제할 수 있습니다. 그런 다음 스크립트를 셀에 복사할 수 있습니다. 다음 셀에는 복사된 스크립트가 표시됩니다.

데이터 가져오기 메뉴를 보여 주는 스크린샷.

데이터 랭글러에서 누락된 데이터를 보여 주는 스크린샷.

def clean_data(df):
    # Drop rows with missing data across all columns
    df.dropna(inplace=True)
    # Drop duplicate rows in columns: 'RowNumber', 'CustomerId'
    df.drop_duplicates(subset=['RowNumber', 'CustomerId'], inplace=True)
    # Drop columns: 'RowNumber', 'CustomerId', 'Surname'
    df.drop(columns=['RowNumber', 'CustomerId', 'Surname'], inplace=True)
    return df

df_clean = clean_data(df.copy())

인터페이스 특성

이 코드는 범주, 숫자 및 대상 특성을 결정합니다.

# Determine the dependent (target) attribute
dependent_variable_name = "Exited"
print(dependent_variable_name)
# Determine the categorical attributes
categorical_variables = [col for col in df_clean.columns if col in "O"
                        or df_clean[col].nunique() <=5
                        and col not in "Exited"]
print(categorical_variables)
# Determine the numerical attributes
numeric_variables = [col for col in df_clean.columns if df_clean[col].dtype != "object"
                        and df_clean[col].nunique() >5]
print(numeric_variables)

5개 숫자 요약 표시

상자 플롯을 사용하여 5개 숫자 요약 표시

  • 최소 벡터
  • 첫 번째 사분위수
  • 중앙값
  • 세 번째 사분위수
  • 최대 점수

숫자 특성에 대한 입니다.

df_num_cols = df_clean[numeric_variables]
sns.set(font_scale = 0.7) 
fig, axes = plt.subplots(nrows = 2, ncols = 3, gridspec_kw =  dict(hspace=0.3), figsize = (17,8))
fig.tight_layout()
for ax,col in zip(axes.flatten(), df_num_cols.columns):
    sns.boxplot(x = df_num_cols[col], color='green', ax = ax)
# fig.suptitle('visualize and compare the distribution and central tendency of numerical attributes', color = 'k', fontsize = 12)
fig.delaxes(axes[1,2])

숫자 특성에 대한 상자 플롯의 Notebook 표시를 보여 주는 스크린샷.

종료된 고객 및 종료되지 않은 고객의 분포 표시

범주 특성에서 종료된 고객 및 종료되지 않은 고객의 분포를 표시합니다.

attr_list = ['Geography', 'Gender', 'HasCrCard', 'IsActiveMember', 'NumOfProducts', 'Tenure']
fig, axarr = plt.subplots(2, 3, figsize=(15, 4))
for ind, item in enumerate (attr_list):
    sns.countplot(x = item, hue = 'Exited', data = df_clean, ax = axarr[ind%2][ind//2])
fig.subplots_adjust(hspace=0.7)

종료된 고객 및 종료되지 않은 고객의 배포를 보여 주는 Notebook 표시 스크린샷.

숫자 특성의 분포 표시

히스토그램을 사용하여 숫자 특성의 빈도 분포를 표시합니다.

columns = df_num_cols.columns[: len(df_num_cols.columns)]
fig = plt.figure()
fig.set_size_inches(18, 8)
length = len(columns)
for i,j in itertools.zip_longest(columns, range(length)):
    plt.subplot((length // 2), 3, j+1)
    plt.subplots_adjust(wspace = 0.2, hspace = 0.5)
    df_num_cols[i].hist(bins = 20, edgecolor = 'black')
    plt.title(i)
# fig = fig.suptitle('distribution of numerical attributes', color = 'r' ,fontsize = 14)
plt.show()

숫자 특성의 Notebook 표시를 보여 주는 스크린샷.

기능 엔지니어링 수행

이 기능 엔지니어링은 현재 특성을 기반으로 새 특성을 생성합니다.

df_clean["NewTenure"] = df_clean["Tenure"]/df_clean["Age"]
df_clean["NewCreditsScore"] = pd.qcut(df_clean['CreditScore'], 6, labels = [1, 2, 3, 4, 5, 6])
df_clean["NewAgeScore"] = pd.qcut(df_clean['Age'], 8, labels = [1, 2, 3, 4, 5, 6, 7, 8])
df_clean["NewBalanceScore"] = pd.qcut(df_clean['Balance'].rank(method="first"), 5, labels = [1, 2, 3, 4, 5])
df_clean["NewEstSalaryScore"] = pd.qcut(df_clean['EstimatedSalary'], 10, labels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

데이터 랭글러를 사용하여 원 핫 인코딩 수행

앞에서 설명한 대로 데이터 랭글러를 시작하는 동일한 단계를 사용하여 데이터 랭글러를 사용하여 원 핫 인코딩을 수행합니다. 이 셀은 원 핫 인코딩에 대해 복사된 생성된 스크립트를 보여줍니다.

데이터 랭글러의 원 핫 인코딩을 보여 주는 스크린샷.

데이터 랭글러의 열 선택을 보여 주는 스크린샷.

df_clean = pd.get_dummies(df_clean, columns=['Geography', 'Gender'])

Power BI 보고서를 생성하는 델타 테이블 만들기

table_name = "df_clean"
# Create a PySpark DataFrame from pandas
sparkDF=spark.createDataFrame(df_clean) 
sparkDF.write.mode("overwrite").format("delta").save(f"Tables/{table_name}")
print(f"Spark DataFrame saved to delta table: {table_name}")

예비 데이터 분석의 관찰 요약

  • 대부분의 고객은 프랑스 출신입니다. 스페인은 프랑스와 독일에 비해 변동률이 가장 낮습니다.
  • 대부분의 고객에게는 신용 카드가 있습니다.
  • 일부 고객은 모두 60세 이상이며 신용 점수가 400 미만입니다. 그러나 이상값으로 간주할 수 없습니다.
  • 은행 상품이 두 개 이상 있는 고객은 거의 없습니다.
  • 비활성 고객은 변동률이 높습니다.
  • 성별 및 임기 연도는 은행 계좌를 폐쇄하기로 한 고객의 결정에 거의 영향을 미치지 않습니다.

4단계: 모델 학습 및 추적 수행

데이터를 배치하면 이제 모델을 정의할 수 있습니다. 이 Notebook에서 임의 포리스트 및 LightGBM 모델을 적용합니다.

scikit-learn 및 LightGBM 라이브러리를 사용하여 몇 줄의 코드로 모델을 구현합니다. 또한 MLfLow 및 패브릭 자동 로깅을 사용하여 실험을 추적합니다.

이 코드 샘플은 레이크하우스에서 델타 테이블을 로드합니다. 레이크하우스를 원본으로 사용하는 다른 델타 테이블을 사용할 수 있습니다.

SEED = 12345
df_clean = spark.read.format("delta").load("Tables/df_clean").toPandas()

MLflow를 사용하여 모델 추적 및 로깅을 위한 실험 생성

이 구역에서는 실험을 생성하는 방법을 보여 줍니다. 모델 및 학습 매개 변수와 점수 매기기 메트릭을 지정합니다. 또한 나중에 사용할 수 있도록 모델을 학습시키고, 기록하고, 학습된 모델을 저장하는 방법을 보여 줍니다.

import mlflow

# Set up the experiment name
EXPERIMENT_NAME = "sample-bank-churn-experiment"  # MLflow experiment name

자동 로깅은 해당 모델이 학습될 때 입력 매개 변수 값과 기계 학습 모델의 출력 메트릭을 모두 자동으로 캡처합니다. 그런 다음 이 정보는 작업 영역에 기록됩니다. 여기서 MLflow API 또는 작업 영역의 해당 실험에 액세스하여 시각화할 수 있습니다.

완료되면 실험은 다음 이미지와 유사합니다.

은행 변동 실험의 실험 페이지를 보여 주는 스크린샷.

해당 이름의 모든 실험이 기록되며 해당 매개 변수 및 성능 메트릭을 추적할 수 있습니다. 자동 로깅에 대한 자세한 내용은 Microsoft Fabric의 자동 로깅을 참조하세요.

실험 및 자동 로깅 사양 설정

mlflow.set_experiment(EXPERIMENT_NAME) # Use a date stamp to append to the experiment
mlflow.autolog(exclusive=False)

scikit-learn 및 LightGBM 가져오기

# Import the required libraries for model training
from sklearn.model_selection import train_test_split
from lightgbm import LGBMClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, f1_score, precision_score, confusion_matrix, recall_score, roc_auc_score, classification_report

학습 및 테스트용 데이터 세트 준비

y = df_clean["Exited"]
X = df_clean.drop("Exited",axis=1)
# Train/test separation
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=SEED)

학습 데이터에 SMOTE 적용

모델에서 의사 결정 경계를 효과적으로 학습할 수 있는 소수 클래스의 예가 너무 적기 때문에 불균형 분류에 문제가 있습니다. 이를 처리하기 위해 SMOTE(가상 소수 민족 과다 샘플링 기술)는 소수 클래스에 대한 새 샘플을 합성하는 데 가장 널리 사용되는 기술입니다. 1단계에서 설치한 imblearn 라이브러리를 사용하여 SMOTE에 액세스합니다.

학습 데이터 세트에만 SMOTE를 적용합니다. 원래 데이터에 대한 모델 성능의 유효한 근사치를 얻으려면 테스트 데이터 세트를 원래 불균형 분포에 두어야 합니다. 이 실험은 프로덕션의 상황을 나타냅니다.

from collections import Counter
from imblearn.over_sampling import SMOTE

sm = SMOTE(random_state=SEED)
X_res, y_res = sm.fit_resample(X_train, y_train)
new_train = pd.concat([X_res, y_res], axis=1)

자세한 내용은 SMOTE무작위 오버 샘플링에서 SMOTE 및 ADASYN으로의 작업을 참조하세요. 불균형 학습 웹 사이트는 이러한 리소스를 호스팅합니다.

모델 학습

임의 포리스트를 사용하여 최대 깊이가 4개이고 다음 네 가지 기능을 사용하여 모델을 학습시킵니다.

mlflow.sklearn.autolog(registered_model_name='rfc1_sm')  # Register the trained model with autologging
rfc1_sm = RandomForestClassifier(max_depth=4, max_features=4, min_samples_split=3, random_state=1) # Pass hyperparameters
with mlflow.start_run(run_name="rfc1_sm") as run:
    rfc1_sm_run_id = run.info.run_id # Capture run_id for model prediction later
    print("run_id: {}; status: {}".format(rfc1_sm_run_id, run.info.status))
    # rfc1.fit(X_train,y_train) # Imbalanced training data
    rfc1_sm.fit(X_res, y_res.ravel()) # Balanced training data
    rfc1_sm.score(X_test, y_test)
    y_pred = rfc1_sm.predict(X_test)
    cr_rfc1_sm = classification_report(y_test, y_pred)
    cm_rfc1_sm = confusion_matrix(y_test, y_pred)
    roc_auc_rfc1_sm = roc_auc_score(y_res, rfc1_sm.predict_proba(X_res)[:, 1])

임의 포리스트를 사용하여 최대 깊이가 8이고 6가지 기능을 사용하여 모델을 학습시킵니다.

mlflow.sklearn.autolog(registered_model_name='rfc2_sm')  # Register the trained model with autologging
rfc2_sm = RandomForestClassifier(max_depth=8, max_features=6, min_samples_split=3, random_state=1) # Pass hyperparameters
with mlflow.start_run(run_name="rfc2_sm") as run:
    rfc2_sm_run_id = run.info.run_id # Capture run_id for model prediction later
    print("run_id: {}; status: {}".format(rfc2_sm_run_id, run.info.status))
    # rfc2.fit(X_train,y_train) # Imbalanced training data
    rfc2_sm.fit(X_res, y_res.ravel()) # Balanced training data
    rfc2_sm.score(X_test, y_test)
    y_pred = rfc2_sm.predict(X_test)
    cr_rfc2_sm = classification_report(y_test, y_pred)
    cm_rfc2_sm = confusion_matrix(y_test, y_pred)
    roc_auc_rfc2_sm = roc_auc_score(y_res, rfc2_sm.predict_proba(X_res)[:, 1])

LightGBM을 사용하여 모델을 훈련합니다.

# lgbm_model
mlflow.lightgbm.autolog(registered_model_name='lgbm_sm')  # Register the trained model with autologging
lgbm_sm_model = LGBMClassifier(learning_rate = 0.07, 
                        max_delta_step = 2, 
                        n_estimators = 100,
                        max_depth = 10, 
                        eval_metric = "logloss", 
                        objective='binary', 
                        random_state=42)

with mlflow.start_run(run_name="lgbm_sm") as run:
    lgbm1_sm_run_id = run.info.run_id # Capture run_id for model prediction later
    # lgbm_sm_model.fit(X_train,y_train) # Imbalanced training data
    lgbm_sm_model.fit(X_res, y_res.ravel()) # Balanced training data
    y_pred = lgbm_sm_model.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    cr_lgbm_sm = classification_report(y_test, y_pred)
    cm_lgbm_sm = confusion_matrix(y_test, y_pred)
    roc_auc_lgbm_sm = roc_auc_score(y_res, lgbm_sm_model.predict_proba(X_res)[:, 1])

모델 성능을 추적하려면 실험 아티팩트 보기

실험 실행은 실험 아티팩트에서 자동으로 저장됩니다. 작업 영역에서 해당 아티팩트 찾을 수 있습니다. 아티팩트 이름은 실험을 설정하는 데 사용되는 이름을 기반으로 합니다. 학습된 모든 모델, 실행, 성능 메트릭 및 모델 매개 변수가 실험 페이지에 기록됩니다.

실험을 보려면 다음을 수행합니다.

  1. 왼쪽 패널에서 작업 영역을 선택합니다.
  2. 실험 이름(이 경우 sample-bank-churn-experiment)을 찾아 선택합니다.

모델 중 하나에 대해 기록된 값을 보여 주는 스크린샷.

5단계: 최종 기계 학습 모델 평가 및 저장

작업 영역에서 저장된 실험을 열어 최상의 모델을 선택하고 저장합니다.

# Define run_uri to fetch the model
# MLflow client: mlflow.model.url, list model
load_model_rfc1_sm = mlflow.sklearn.load_model(f"runs:/{rfc1_sm_run_id}/model")
load_model_rfc2_sm = mlflow.sklearn.load_model(f"runs:/{rfc2_sm_run_id}/model")
load_model_lgbm1_sm = mlflow.lightgbm.load_model(f"runs:/{lgbm1_sm_run_id}/model")

테스트 데이터 세트에서 저장된 모델의 성능 평가.

ypred_rfc1_sm = load_model_rfc1_sm.predict(X_test) # Random forest with maximum depth of 4 and 4 features
ypred_rfc2_sm = load_model_rfc2_sm.predict(X_test) # Random forest with maximum depth of 8 and 6 features
ypred_lgbm1_sm = load_model_lgbm1_sm.predict(X_test) # LightGBM

혼동 행렬을 사용하여 true/false 긍정/부정 표시

분류의 정확도를 평가하려면 혼동 행렬을 그리는 스크립트를 작성합니다. 사기 감지 샘플에 표시된 것처럼 SynapseML 도구를 사용하여 혼동 행렬을 그릴 수도 있습니다.

def plot_confusion_matrix(cm, classes,
                          normalize=False,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):
    print(cm)
    plt.figure(figsize=(4,4))
    plt.rcParams.update({'font.size': 10})
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45, color="blue")
    plt.yticks(tick_marks, classes, color="blue")

    fmt = '.2f' if normalize else 'd'
    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, format(cm[i, j], fmt),
                 horizontalalignment="center",
                 color="red" if cm[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

네 가지 기능을 사용하여 최대 깊이가 4인 임의 포리스트 분류자의 혼동 행렬을 만듭니다.

cfm = confusion_matrix(y_test, y_pred=ypred_rfc1_sm)
plot_confusion_matrix(cfm, classes=['Non Churn','Churn'],
                      title='Random Forest with max depth of 4')
tn, fp, fn, tp = cfm.ravel()

최대 깊이가 4인 임의 포리스트에 대한 혼동 행렬의 Notebook 표시를 보여 주는 스크린샷.

6개의 기능을 사용하여 최대 깊이가 8인 임의 포리스트 분류자의 혼동 행렬을 만듭니다.

cfm = confusion_matrix(y_test, y_pred=ypred_rfc2_sm)
plot_confusion_matrix(cfm, classes=['Non Churn','Churn'],
                      title='Random Forest with max depth of 8')
tn, fp, fn, tp = cfm.ravel()

최대 깊이가 8인 임의 포리스트에 대한 혼동 행렬의 Notebook 표시를 보여 주는 스크린샷.

LightGBM에 대한 혼동 행렬을 만듭니다.

cfm = confusion_matrix(y_test, y_pred=ypred_lgbm1_sm)
plot_confusion_matrix(cfm, classes=['Non Churn','Churn'],
                      title='LightGBM')
tn, fp, fn, tp = cfm.ravel()

LightGBM에 대한 혼동 행렬의 Notebook 표시를 보여 주는 스크린샷.

Power BI에 대한 결과 저장

모델 예측 결과를 Power BI 시각화로 이동하려면 델타 프레임을 레이크하우스에 저장합니다.

df_pred = X_test.copy()
df_pred['y_test'] = y_test
df_pred['ypred_rfc1_sm'] = ypred_rfc1_sm
df_pred['ypred_rfc2_sm'] =ypred_rfc2_sm
df_pred['ypred_lgbm1_sm'] = ypred_lgbm1_sm
table_name = "df_pred_results"
sparkDF=spark.createDataFrame(df_pred)
sparkDF.write.mode("overwrite").format("delta").option("overwriteSchema", "true").save(f"Tables/{table_name}")
print(f"Spark DataFrame saved to delta table: {table_name}")

6단계: Power BI에서 시각화에 액세스

Power BI에서 저장된 테이블에 액세스합니다.

  1. 왼쪽에서 OneLake 데이터 허브를 선택합니다.
  2. 이 Notebook에 추가한 레이크하우스 선택
  3. 이 레이크하우스 열기 구역에서 열기를 선택합니다.
  4. 리본에서 새 시맨틱 모델을 선택합니다. df_pred_results(을)를 선택한 다음 계속을 선택하여 예측에 연결된 새 Power BI 시맨틱 모델을 만듭니다.
  5. 시맨틱 모델 페이지의 맨 위에 있는 도구에서 새 보고서를 선택하여 Power BI 보고서 작성 페이지를 엽니다.

다음 스크린샷은 몇 가지 예제 시각화를 보여 줍니다. 데이터 패널에는 테이블에서 선택할 델타 테이블과 열이 표시됩니다. 적절한 범주(x) 및 값(y) 축을 선택한 후 필터 및 함수(예: 테이블 열의 합계 또는 평균)를 선택할 수 있습니다.

참고 항목

이 스크린샷에서는 Power BI에서 저장된 예측 결과를 분석하는 예제를 설명합니다.

Power BI 대시보드 예시를 보여 주는 스크린샷.

그러나 실제 고객 이탈 사용 사례의 경우 사용자는 주제별 전문 지식과 회사 및 비즈니스 분석 팀과 회사가 메트릭으로 표준화한 내용에 따라 시각화에 대한 보다 철저한 요구 사항 집합이 필요할 수 있습니다.

Power BI 보고서에 따르면 은행 상품 중 두 개 이상을 사용하는 고객은 변동률이 더 높습니다. 그러나 두 개 이상의 제품을 가진 고객은 거의 없습니다. (왼쪽 아래 패널의 플롯을 참조하세요.) 은행은 더 많은 데이터를 수집해야 하지만 더 많은 제품과 상관 관계가 있는 다른 기능도 조사해야 합니다.

독일의 은행 고객은 프랑스와 스페인의 고객에 비해 이탈률이 높습니다. (오른쪽 아래 패널의 플롯 참조). 보고서 결과에 따라 고객이 떠나도록 유도한 요인에 대한 조사가 도움이 될 수 있습니다.

중년 고객(25세에서 45세 사이)이 더 많습니다. 45에서 60 사이의 고객은 더 많은 것을 종료하는 경향이 있습니다.

마지막으로 신용 점수가 낮은 고객은 다른 금융 기관을 위해 은행을 떠날 가능성이 큽니다. 은행은 신용 점수와 계좌 잔액이 낮은 고객이 은행에 머물도록 장려하는 방법을 모색해야 합니다.

# Determine the entire runtime
print(f"Full run cost {int(time.time() - ts)} seconds.")