Customer Churn Prediction with Amazon SageMaker Autopilot


This notebook’s CI test result for us-west-2 is as follows. CI test results in other regions can be found at the end of the notebook.

This us-west-2 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable


Using AutoPilot to Predict Mobile Customer Departure



Kernel Python 3 (Data Science) works well with this notebook.

Contents

  1. Introduction

  2. Setup

  3. Data

  4. Train

  5. Autopilot Results

  6. Host

  7. Cleanup


Introduction

Amazon SageMaker Autopilot is an automated machine learning (commonly referred to as AutoML) solution for tabular datasets. You can use SageMaker Autopilot in different ways: on autopilot (hence the name) or with human guidance, without code through SageMaker Studio, or using the AWS SDKs. This notebook, as a first glimpse, will use the AWS SDKs to simply create and deploy a machine learning model.

Losing customers is costly for any business. Identifying unhappy customers early on gives you a chance to offer them incentives to stay. This notebook describes using machine learning (ML) for the automated identification of unhappy customers, also known as customer churn prediction. ML models rarely give perfect predictions though, so this notebook is also about how to incorporate the relative costs of prediction mistakes when determining the financial outcome of using ML.

We use an example of churn that is familiar to all of us–leaving a mobile phone operator. Seems like I can always find fault with my provider du jour! And if my provider knows that I’m thinking of leaving, it can offer timely incentives–I can always use a phone upgrade or perhaps have a new feature activated–and I might just stick around. Incentives are often much more cost effective than losing and reacquiring a customer.


Setup

This notebook was created and tested on an ml.m4.xlarge notebook instance.

Let’s start by specifying:

  • The S3 bucket and prefix that you want to use for training and model data. This should be within the same region as the Notebook Instance, training, and hosting.

  • The IAM role arn used to give training and hosting access to your data. See the documentation for how to create these. Note, if more than one role is required for notebook instances, training, and/or hosting, please replace the boto regexp with a the appropriate full IAM role arn string(s).

[5]:
import sagemaker
import boto3
from sagemaker import get_execution_role

region = boto3.Session().region_name

session = sagemaker.Session()

# You can modify the following to use a bucket of your choosing
bucket = session.default_bucket()
prefix = "sagemaker/DEMO-autopilot-churn"

role = get_execution_role()

# This is the client we will use to interact with SageMaker AutoPilot
sm = boto3.Session().client(service_name="sagemaker", region_name=region)

Next, we’ll import the Python libraries we’ll need for the remainder of the exercise.

[6]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import io
import os
import sys
import time
import json
from IPython.display import display
from time import strftime, gmtime
import boto3
import sagemaker
from sagemaker.predictor import csv_serializer

Data

Mobile operators have historical records on which customers ultimately ended up churning and which continued using the service. We can use this historical information to construct an ML model of one mobile operator’s churn using a process called training. After training the model, we can pass the profile information of an arbitrary customer (the same profile information that we used to train the model) to the model, and have the model predict whether this customer is going to churn. Of course, we expect the model to make mistakes–after all, predicting the future is tricky business! But I’ll also show how to deal with prediction errors.

The dataset we will use is synthetically generated, but indictive of the types of features you’d see in this use case.

[ ]:
s3 = boto3.client("s3")
s3.download_file(
    f"sagemaker-example-files-prod-{region}", "datasets/tabular/synthetic/churn.txt", "churn.txt"
)

Upload the dataset to S3

Before you run Autopilot on the dataset, first perform a check of the dataset to make sure that it has no obvious errors. The Autopilot process can take long time, and it’s generally a good practice to inspect the dataset before you start a job. This particular dataset is small, so you can inspect it in the notebook instance itself. If you have a larger dataset that will not fit in a notebook instance memory, inspect the dataset offline using a big data analytics tool like Apache Spark. Deequ is a library built on top of Apache Spark that can be helpful for performing checks on large datasets. Autopilot is capable of handling datasets up to 5 GB.

Read the data into a Pandas data frame and take a look.

[7]:
churn = pd.read_csv("./churn.txt")
pd.set_option("display.max_columns", 500)
churn
[7]:
State Account Length Area Code Phone Int'l Plan VMail Plan VMail Message Day Mins Day Calls Day Charge Eve Mins Eve Calls Eve Charge Night Mins Night Calls Night Charge Intl Mins Intl Calls Intl Charge CustServ Calls Churn?
0 KS 128 415 382-4657 no yes 25 265.1 110 45.07 197.4 99 16.78 244.7 91 11.01 10.0 3 2.70 1 False.
1 OH 107 415 371-7191 no yes 26 161.6 123 27.47 195.5 103 16.62 254.4 103 11.45 13.7 3 3.70 1 False.
2 NJ 137 415 358-1921 no no 0 243.4 114 41.38 121.2 110 10.30 162.6 104 7.32 12.2 5 3.29 0 False.
3 OH 84 408 375-9999 yes no 0 299.4 71 50.90 61.9 88 5.26 196.9 89 8.86 6.6 7 1.78 2 False.
4 OK 75 415 330-6626 yes no 0 166.7 113 28.34 148.3 122 12.61 186.9 121 8.41 10.1 3 2.73 3 False.
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
3328 AZ 192 415 414-4276 no yes 36 156.2 77 26.55 215.5 126 18.32 279.1 83 12.56 9.9 6 2.67 2 False.
3329 WV 68 415 370-3271 no no 0 231.1 57 39.29 153.4 55 13.04 191.3 123 8.61 9.6 4 2.59 3 False.
3330 RI 28 510 328-8230 no no 0 180.8 109 30.74 288.8 58 24.55 191.9 91 8.64 14.1 6 3.81 2 False.
3331 CT 184 510 364-6381 yes no 0 213.8 105 36.35 159.6 84 13.57 139.2 137 6.26 5.0 10 1.35 2 False.
3332 TN 74 415 400-4344 no yes 25 234.4 113 39.85 265.9 82 22.60 241.4 77 10.86 13.7 4 3.70 0 False.

3333 rows × 21 columns

By modern standards, it’s a relatively small dataset, with only 5,000 records, where each record uses 21 attributes to describe the profile of a customer of an unknown US mobile operator. The attributes are:

  • State: the US state in which the customer resides, indicated by a two-letter abbreviation; for example, OH or NJ

  • Account Length: the number of days that this account has been active

  • Area Code: the three-digit area code of the corresponding customer’s phone number

  • Phone: the remaining seven-digit phone number

  • Int’l Plan: whether the customer has an international calling plan: yes/no

  • VMail Plan: whether the customer has a voice mail feature: yes/no

  • VMail Message: presumably the average number of voice mail messages per month

  • Day Mins: the total number of calling minutes used during the day

  • Day Calls: the total number of calls placed during the day

  • Day Charge: the billed cost of daytime calls

  • Eve Mins, Eve Calls, Eve Charge: the billed cost for calls placed during the evening

  • Night Mins, Night Calls, Night Charge: the billed cost for calls placed during nighttime

  • Intl Mins, Intl Calls, Intl Charge: the billed cost for international calls

  • CustServ Calls: the number of calls placed to Customer Service

  • Churn?: whether the customer left the service: true/false

The last attribute, Churn?, is known as the target attribute–the attribute that we want the ML model to predict.

Reserve some data for calling inference on the model

Divide the data into training and testing splits. The training split is used by SageMaker Autopilot. The testing split is reserved to perform inference using the suggested model.

[8]:
train_data = churn.sample(frac=0.8, random_state=200)

test_data = churn.drop(train_data.index)

test_data_no_target = test_data.drop(columns=["Churn?"])

Now we’ll upload these files to S3.

[9]:
train_file = "train_data.csv"
train_data.to_csv(train_file, index=False, header=True)
train_data_s3_path = session.upload_data(path=train_file, key_prefix=prefix + "/train")
print("Train data uploaded to: " + train_data_s3_path)

test_file = "test_data.csv"
test_data_no_target.to_csv(test_file, index=False, header=False)
test_data_s3_path = session.upload_data(path=test_file, key_prefix=prefix + "/test")
print("Test data uploaded to: " + test_data_s3_path)
Train data uploaded to: s3://sagemaker-us-west-2-262002448484/sagemaker/DEMO-autopilot-churn/train/train_data.csv
Test data uploaded to: s3://sagemaker-us-west-2-262002448484/sagemaker/DEMO-autopilot-churn/test/test_data.csv

Setting up the SageMaker Autopilot Job

After uploading the dataset to Amazon S3, you can invoke Autopilot to find the best ML pipeline to train a model on this dataset.

The required inputs for invoking a Autopilot job are: * Amazon S3 location for input dataset and for all output artifacts * Name of the column of the dataset you want to predict (Churn? in this case) * An IAM role

Currently Autopilot supports only tabular datasets in CSV format. Either all files should have a header row, or the first file of the dataset, when sorted in alphabetical/lexical order by name, is expected to have a header row.

[10]:
input_data_config = [
    {
        "DataSource": {
            "S3DataSource": {
                "S3DataType": "S3Prefix",
                "S3Uri": "s3://{}/{}/train".format(bucket, prefix),
            }
        },
        "TargetAttributeName": "Churn?",
    }
]

output_data_config = {"S3OutputPath": "s3://{}/{}/output".format(bucket, prefix)}

You can also specify the type of problem you want to solve with your dataset (Regression, MulticlassClassification, BinaryClassification). In case you are not sure, SageMaker Autopilot will infer the problem type based on statistics of the target column (the column you want to predict).

Because the target attribute, Churn?, is binary, our model will be performing binary prediction, also known as binary classification. In this example we will let AutoPilot infer the type of problem for us.

You have the option to limit the running time of a SageMaker Autopilot job by providing either the maximum number of pipeline evaluations or candidates (one pipeline evaluation is called a Candidate because it generates a candidate model) or providing the total time allocated for the overall Autopilot job. Under default settings, this job takes about four hours to run. This varies between runs because of the nature of the exploratory process Autopilot uses to find optimal training parameters.

Launching the SageMaker Autopilot Job

You can now launch the Autopilot job by calling the create_auto_ml_job API. We limit the number of candidates to 20 so that the job finishes in a few minutes.

[11]:
from time import gmtime, strftime, sleep

timestamp_suffix = strftime("%d-%H-%M-%S", gmtime())

auto_ml_job_name = "automl-churn-" + timestamp_suffix
print("AutoMLJobName: " + auto_ml_job_name)

sm.create_auto_ml_job(
    AutoMLJobName=auto_ml_job_name,
    InputDataConfig=input_data_config,
    OutputDataConfig=output_data_config,
    AutoMLJobConfig={"CompletionCriteria": {"MaxCandidates": 20}},
    RoleArn=role,
)
AutoMLJobName: automl-churn-03-17-50-14
[11]:
{'AutoMLJobArn': 'arn:aws:sagemaker:us-west-2:262002448484:automl-job/automl-churn-03-17-50-14',
 'ResponseMetadata': {'RequestId': '346f751d-4738-4c0f-86a4-513f15e2b2ea',
  'HTTPStatusCode': 200,
  'HTTPHeaders': {'x-amzn-requestid': '346f751d-4738-4c0f-86a4-513f15e2b2ea',
   'content-type': 'application/x-amz-json-1.1',
   'content-length': '95',
   'date': 'Wed, 03 Feb 2021 17:50:14 GMT'},
  'RetryAttempts': 0}}
[12]:
# Store the AutoMLJobName name for use in subsequent notebooks
%store auto_ml_job_name
auto_ml_job_name
Stored 'auto_ml_job_name' (str)
[12]:
'automl-churn-03-17-50-14'

Tracking SageMaker Autopilot job progress

SageMaker Autopilot job consists of the following high-level steps : * Analyzing Data, where the dataset is analyzed and Autopilot comes up with a list of ML pipelines that should be tried out on the dataset. The dataset is also split into train and validation sets. * Feature Engineering, where Autopilot performs feature transformation on individual features of the dataset as well as at an aggregate level. * Model Tuning, where the top performing pipeline is selected along with the optimal hyperparameters for the training algorithm (the last stage of the pipeline).

[13]:
print("JobStatus - Secondary Status")
print("------------------------------")


describe_response = sm.describe_auto_ml_job(AutoMLJobName=auto_ml_job_name)
print(describe_response["AutoMLJobStatus"] + " - " + describe_response["AutoMLJobSecondaryStatus"])
job_run_status = describe_response["AutoMLJobStatus"]

while job_run_status not in ("Failed", "Completed", "Stopped"):
    describe_response = sm.describe_auto_ml_job(AutoMLJobName=auto_ml_job_name)
    job_run_status = describe_response["AutoMLJobStatus"]

    print(
        describe_response["AutoMLJobStatus"] + " - " + describe_response["AutoMLJobSecondaryStatus"]
    )
    sleep(30)
JobStatus - Secondary Status
------------------------------
InProgress - Starting
InProgress - Starting
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - AnalyzingData
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - FeatureEngineering
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
InProgress - ModelTuning
Completed - MaxCandidatesReached

AutoPilot automatically generates two executable Jupyter Notebooks: - SageMakerAutopilotDataExplorationNotebook.ipynb and - SageMakerAutopilotCandidateDefinitionNotebook.ipynb. These notebooks are stored in S3. Let us download them onto our SageMaker Notebook instance so we could explore them later.

[14]:
# print(describe_response)
print(describe_response["AutoMLJobArtifacts"]["CandidateDefinitionNotebookLocation"])
print(describe_response["AutoMLJobArtifacts"]["DataExplorationNotebookLocation"])

candidate_nbk = describe_response["AutoMLJobArtifacts"]["CandidateDefinitionNotebookLocation"]
data_explore_nbk = describe_response["AutoMLJobArtifacts"]["DataExplorationNotebookLocation"]
s3://sagemaker-us-west-2-262002448484/sagemaker/DEMO-autopilot-churn/output/automl-churn-03-17-50-14/sagemaker-automl-candidates/pr-1-087be24846d8436faecf8de3c2d70c10cd7e5218bb62499f822657956b/notebooks/SageMakerAutopilotCandidateDefinitionNotebook.ipynb
s3://sagemaker-us-west-2-262002448484/sagemaker/DEMO-autopilot-churn/output/automl-churn-03-17-50-14/sagemaker-automl-candidates/pr-1-087be24846d8436faecf8de3c2d70c10cd7e5218bb62499f822657956b/notebooks/SageMakerAutopilotDataExplorationNotebook.ipynb
[15]:
def split_s3_path(s3_path):
    path_parts = s3_path.replace("s3://", "").split("/")
    bucket = path_parts.pop(0)
    key = "/".join(path_parts)
    return bucket, key


s3_bucket, candidate_nbk_key = split_s3_path(candidate_nbk)
_, data_explore_nbk_key = split_s3_path(data_explore_nbk)

print(s3_bucket, candidate_nbk_key, data_explore_nbk_key)

session.download_data(path="./", bucket=s3_bucket, key_prefix=candidate_nbk_key)

session.download_data(path="./", bucket=s3_bucket, key_prefix=data_explore_nbk_key)
sagemaker-us-west-2-262002448484 sagemaker/DEMO-autopilot-churn/output/automl-churn-03-17-50-14/sagemaker-automl-candidates/pr-1-087be24846d8436faecf8de3c2d70c10cd7e5218bb62499f822657956b/notebooks/SageMakerAutopilotCandidateDefinitionNotebook.ipynb sagemaker/DEMO-autopilot-churn/output/automl-churn-03-17-50-14/sagemaker-automl-candidates/pr-1-087be24846d8436faecf8de3c2d70c10cd7e5218bb62499f822657956b/notebooks/SageMakerAutopilotDataExplorationNotebook.ipynb

Results

Now use the describe_auto_ml_job API to look up the best candidate selected by the SageMaker Autopilot job.

[21]:
best_candidate = sm.describe_auto_ml_job(AutoMLJobName=auto_ml_job_name)["BestCandidate"]
best_candidate_name = best_candidate["CandidateName"]
print(best_candidate)
print("\n")
print("CandidateName: " + best_candidate_name)
print(
    "FinalAutoMLJobObjectiveMetricName: "
    + best_candidate["FinalAutoMLJobObjectiveMetric"]["MetricName"]
)
print(
    "FinalAutoMLJobObjectiveMetricValue: "
    + str(best_candidate["FinalAutoMLJobObjectiveMetric"]["Value"])
)
{'CandidateName': 'tuning-job-1-3572d1c0effe4c2db9-017-ab2e9b77', 'FinalAutoMLJobObjectiveMetric': {'MetricName': 'validation:f1', 'Value': 0.923229992389679}, 'ObjectiveStatus': 'Succeeded', 'CandidateSteps': [{'CandidateStepType': 'AWS::SageMaker::ProcessingJob', 'CandidateStepArn': 'arn:aws:sagemaker:us-west-2:262002448484:processing-job/db-1-dc376427266845c88039d2bdb3410fdf23ec309a025e4f1eb84b5eb853', 'CandidateStepName': 'db-1-dc376427266845c88039d2bdb3410fdf23ec309a025e4f1eb84b5eb853'}, {'CandidateStepType': 'AWS::SageMaker::TrainingJob', 'CandidateStepArn': 'arn:aws:sagemaker:us-west-2:262002448484:training-job/automl-chu-dpp5-1-705bf26de0f842c3b3cd5e0e57f12bce7834aa5c88b04', 'CandidateStepName': 'automl-chu-dpp5-1-705bf26de0f842c3b3cd5e0e57f12bce7834aa5c88b04'}, {'CandidateStepType': 'AWS::SageMaker::TransformJob', 'CandidateStepArn': 'arn:aws:sagemaker:us-west-2:262002448484:transform-job/automl-chu-dpp5-rpb-1-61fcb42b552d4a4b8ab2655f68ff1f4e8048ada21', 'CandidateStepName': 'automl-chu-dpp5-rpb-1-61fcb42b552d4a4b8ab2655f68ff1f4e8048ada21'}, {'CandidateStepType': 'AWS::SageMaker::TrainingJob', 'CandidateStepArn': 'arn:aws:sagemaker:us-west-2:262002448484:training-job/tuning-job-1-3572d1c0effe4c2db9-017-ab2e9b77', 'CandidateStepName': 'tuning-job-1-3572d1c0effe4c2db9-017-ab2e9b77'}], 'CandidateStatus': 'Completed', 'InferenceContainers': [{'Image': '246618743249.dkr.ecr.us-west-2.amazonaws.com/sagemaker-sklearn-automl:0.2-1-cpu-py3', 'ModelDataUrl': 's3://sagemaker-us-west-2-262002448484/sagemaker/DEMO-autopilot-churn/output/automl-churn-03-17-50-14/data-processor-models/automl-chu-dpp5-1-705bf26de0f842c3b3cd5e0e57f12bce7834aa5c88b04/output/model.tar.gz', 'Environment': {'AUTOML_SPARSE_ENCODE_RECORDIO_PROTOBUF': '1', 'AUTOML_TRANSFORM_MODE': 'feature-transform', 'SAGEMAKER_DEFAULT_INVOCATIONS_ACCEPT': 'application/x-recordio-protobuf', 'SAGEMAKER_PROGRAM': 'sagemaker_serve', 'SAGEMAKER_SUBMIT_DIRECTORY': '/opt/ml/model/code'}}, {'Image': '246618743249.dkr.ecr.us-west-2.amazonaws.com/sagemaker-xgboost:1.0-1-cpu-py3', 'ModelDataUrl': 's3://sagemaker-us-west-2-262002448484/sagemaker/DEMO-autopilot-churn/output/automl-churn-03-17-50-14/tuning/automl-chu-dpp5-xgb/tuning-job-1-3572d1c0effe4c2db9-017-ab2e9b77/output/model.tar.gz', 'Environment': {'MAX_CONTENT_LENGTH': '20971520', 'SAGEMAKER_DEFAULT_INVOCATIONS_ACCEPT': 'text/csv', 'SAGEMAKER_INFERENCE_OUTPUT': 'predicted_label', 'SAGEMAKER_INFERENCE_SUPPORTED': 'predicted_label,probability,probabilities'}}, {'Image': '246618743249.dkr.ecr.us-west-2.amazonaws.com/sagemaker-sklearn-automl:0.2-1-cpu-py3', 'ModelDataUrl': 's3://sagemaker-us-west-2-262002448484/sagemaker/DEMO-autopilot-churn/output/automl-churn-03-17-50-14/data-processor-models/automl-chu-dpp5-1-705bf26de0f842c3b3cd5e0e57f12bce7834aa5c88b04/output/model.tar.gz', 'Environment': {'AUTOML_TRANSFORM_MODE': 'inverse-label-transform', 'SAGEMAKER_DEFAULT_INVOCATIONS_ACCEPT': 'text/csv', 'SAGEMAKER_INFERENCE_INPUT': 'predicted_label', 'SAGEMAKER_INFERENCE_OUTPUT': 'predicted_label', 'SAGEMAKER_INFERENCE_SUPPORTED': 'predicted_label,probability,labels,probabilities', 'SAGEMAKER_PROGRAM': 'sagemaker_serve', 'SAGEMAKER_SUBMIT_DIRECTORY': '/opt/ml/model/code'}}], 'CreationTime': datetime.datetime(2021, 2, 3, 18, 12, 19, tzinfo=tzlocal()), 'EndTime': datetime.datetime(2021, 2, 3, 18, 13, 2, tzinfo=tzlocal()), 'LastModifiedTime': datetime.datetime(2021, 2, 3, 18, 15, 52, 159000, tzinfo=tzlocal())}


CandidateName: tuning-job-1-3572d1c0effe4c2db9-017-ab2e9b77
FinalAutoMLJobObjectiveMetricName: validation:f1
FinalAutoMLJobObjectiveMetricValue: 0.923229992389679

Due to some randomness in the algorithms involved, different runs will provide slightly different results, but accuracy will be around or above \(93\%\), which is a good result.

If you are curious to explore the performance of other algorithms that AutoPilot explored, they are enumerated for you below via list_candidates_for_auto_ml_job() API call

[56]:
# sm.describe_auto_ml_job(AutoMLJobName=auto_ml_job_name)
# sm.list_auto_ml_jobs()
sm_dict = sm.list_candidates_for_auto_ml_job(AutoMLJobName=auto_ml_job_name)
[109]:
for item in sm_dict["Candidates"]:
    print(item["CandidateName"], item["FinalAutoMLJobObjectiveMetric"])
    print(item["InferenceContainers"][1]["Image"], "\n")
tuning-job-1-3572d1c0effe4c2db9-020-e82606f5 {'MetricName': 'validation:binary_f_beta', 'Value': 0.35087719559669495}
174872318107.dkr.ecr.us-west-2.amazonaws.com/linear-learner:latest

tuning-job-1-3572d1c0effe4c2db9-019-343c7bdb {'MetricName': 'validation:f1', 'Value': 0.752780020236969}
246618743249.dkr.ecr.us-west-2.amazonaws.com/sagemaker-xgboost:1.0-1-cpu-py3

tuning-job-1-3572d1c0effe4c2db9-018-7eb3911a {'MetricName': 'validation:f1', 'Value': 0.923229992389679}
246618743249.dkr.ecr.us-west-2.amazonaws.com/sagemaker-xgboost:1.0-1-cpu-py3

tuning-job-1-3572d1c0effe4c2db9-017-ab2e9b77 {'MetricName': 'validation:f1', 'Value': 0.923229992389679}
246618743249.dkr.ecr.us-west-2.amazonaws.com/sagemaker-xgboost:1.0-1-cpu-py3

tuning-job-1-3572d1c0effe4c2db9-016-5aa287c4 {'MetricName': 'validation:binary_f_beta', 'Value': 0.23999999463558197}
174872318107.dkr.ecr.us-west-2.amazonaws.com/linear-learner:latest

tuning-job-1-3572d1c0effe4c2db9-015-56ca82e5 {'MetricName': 'validation:binary_f_beta', 'Value': 0.23999999463558197}
174872318107.dkr.ecr.us-west-2.amazonaws.com/linear-learner:latest

tuning-job-1-3572d1c0effe4c2db9-014-e9ec7e8c {'MetricName': 'validation:f1', 'Value': 0.8602499961853027}
246618743249.dkr.ecr.us-west-2.amazonaws.com/sagemaker-xgboost:1.0-1-cpu-py3

tuning-job-1-3572d1c0effe4c2db9-013-b86fdc91 {'MetricName': 'validation:f1', 'Value': 0.8618000149726868}
246618743249.dkr.ecr.us-west-2.amazonaws.com/sagemaker-xgboost:1.0-1-cpu-py3

tuning-job-1-3572d1c0effe4c2db9-012-c8883e70 {'MetricName': 'validation:f1', 'Value': 0.7779200077056885}
246618743249.dkr.ecr.us-west-2.amazonaws.com/sagemaker-xgboost:1.0-1-cpu-py3

tuning-job-1-3572d1c0effe4c2db9-011-c4159396 {'MetricName': 'validation:binary_f_beta', 'Value': 0.47926267981529236}
174872318107.dkr.ecr.us-west-2.amazonaws.com/linear-learner:latest


Host

Now that we’ve trained the algorithm, let’s create a model and deploy it to a hosted endpoint.

[17]:
timestamp_suffix = strftime("%d-%H-%M-%S", gmtime())
model_name = best_candidate_name + timestamp_suffix + "-model"
model_arn = sm.create_model(
    Containers=best_candidate["InferenceContainers"], ModelName=model_name, ExecutionRoleArn=role
)

epc_name = best_candidate_name + timestamp_suffix + "-epc"
ep_config = sm.create_endpoint_config(
    EndpointConfigName=epc_name,
    ProductionVariants=[
        {
            "InstanceType": "ml.m5.2xlarge",
            "InitialInstanceCount": 1,
            "ModelName": model_name,
            "VariantName": "main",
        }
    ],
)

ep_name = best_candidate_name + timestamp_suffix + "-ep"
create_endpoint_response = sm.create_endpoint(EndpointName=ep_name, EndpointConfigName=epc_name)
[18]:
sm.get_waiter("endpoint_in_service").wait(EndpointName=ep_name)

Evaluate

Now that we have a hosted endpoint running, we can make real-time predictions from our model very easily, simply by making an http POST request. But first, we’ll need to setup serializers and deserializers for passing our test_data NumPy arrays to the model behind the endpoint.

[19]:
from io import StringIO

if sagemaker.__version__ < "2":
    from sagemaker.predictor import RealTimePredictor
    from sagemaker.content_types import CONTENT_TYPE_CSV

    predictor = RealTimePredictor(
        endpoint=ep_name,
        sagemaker_session=session,
        content_type=CONTENT_TYPE_CSV,
        accept=CONTENT_TYPE_CSV,
    )

    # Remove the target column from the test data
    test_data_inference = test_data.drop("Churn?", axis=1)

    # Obtain predictions from SageMaker endpoint
    prediction = predictor.predict(
        test_data_inference.to_csv(sep=",", header=False, index=False)
    ).decode("utf-8")

    # Load prediction in pandas and compare to ground truth
    prediction_df = pd.read_csv(StringIO(prediction), header=None)
    accuracy = (test_data.reset_index()["Churn?"] == prediction_df[0]).sum() / len(
        test_data_inference
    )
    print("Accuracy: {}".format(accuracy))

else:
    from sagemaker.predictor import Predictor
    from sagemaker.serializers import CSVSerializer
    from sagemaker.deserializers import CSVDeserializer

    predictor = Predictor(
        endpoint_name=ep_name,
        sagemaker_session=session,
        serializer=CSVSerializer(),
        deserializer=CSVDeserializer(),
    )

    # Remove the target column from the test data
    test_data_inference = test_data.drop("Churn?", axis=1)

    # Obtain predictions from SageMaker endpoint
    prediction = predictor.predict(test_data_inference.to_csv(sep=",", header=False, index=False))

    # Load prediction in pandas and compare to ground truth
    prediction_df = pd.DataFrame(prediction)
    accuracy = (test_data.reset_index()["Churn?"] == prediction_df[0]).sum() / len(
        test_data_inference
    )
    print("Accuracy: {}".format(accuracy))
Accuracy: 0.9610194902548725
[20]:
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

accuracy = accuracy_score(test_data.reset_index()["Churn?"], prediction_df[0])
precision = precision_score(test_data.reset_index()["Churn?"], prediction_df[0], pos_label="True.")
recall = recall_score(
    test_data.reset_index()["Churn?"], prediction_df[0], pos_label="True.", average="binary"
)
f1 = f1_score(test_data.reset_index()["Churn?"], prediction_df[0], pos_label="True.")

print("Accuracy: {}".format(accuracy))
print("Precision: {}".format(precision))
print("Recall: {}".format(recall))
print("F1: {}".format(f1))
Accuracy: 0.9610194902548725
Precision: 0.896551724137931
Recall: 0.8210526315789474
F1: 0.8571428571428572

Cleanup

The Autopilot job creates many underlying artifacts such as dataset splits, preprocessing scripts, or preprocessed data, etc. This code, when un-commented, deletes them. This operation deletes all the generated models and the auto-generated notebooks as well.

s3 = boto3.resource(‘s3’) s3_bucket = s3.Bucket(bucket)

print(s3_bucket) job_outputs_prefix = ‘{}/output/{}’.format(prefix, auto_ml_job_name) print(job_outputs_prefix) #s3_bucket.objects.filter(Prefix=job_outputs_prefix).delete()

Finally, we delete the endpoint and associated resources.

sm.delete_endpoint(EndpointName=ep_name) sm.delete_endpoint_config(EndpointConfigName=epc_name) sm.delete_model(ModelName=model_name)

Notebook CI Test Results

This notebook was tested in multiple regions. The test results are as follows, except for us-west-2 which is shown at the top of the notebook.

This us-east-1 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This us-east-2 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This us-west-1 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This ca-central-1 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This sa-east-1 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This eu-west-1 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This eu-west-2 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This eu-west-3 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This eu-central-1 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This eu-north-1 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This ap-southeast-1 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This ap-southeast-2 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This ap-northeast-1 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This ap-northeast-2 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable

This ap-south-1 badge failed to load. Check your device’s internet connectivity, otherwise the service is currently unavailable