<jupyter_start><jupyter_text>Starbucks Capstone Challenge IntroductionThis data set contains simulated data that mimics customer behavior on the Starbucks rewards mobile app. Once every few days, Starbucks sends out an offer to users of the mobile app. An offer can be merely an advertisement for a drink or an actual offer such as a discount or BOGO (buy one get one free). Some users might not receive any offer during certain weeks. Not all users receive the same offer, and that is the challenge to solve with this data set.Your task is to combine transaction, demographic and offer data to determine which demographic groups respond best to which offer type. This data set is a simplified version of the real Starbucks app because the underlying simulator only has one product whereas Starbucks actually sells dozens of products.Every offer has a validity period before the offer expires. As an example, a BOGO offer might be valid for only 5 days. You'll see in the data set that informational offers have a validity period even though these ads are merely providing information about a product; for example, if an informational offer has 7 days of validity, you can assume the customer is feeling the influence of the offer for 7 days after receiving the advertisement.You'll be given transactional data showing user purchases made on the app including the timestamp of purchase and the amount of money spent on a purchase. This transactional data also has a record for each offer that a user receives as well as a record for when a user actually views the offer. There are also records for when a user completes an offer. Keep in mind as well that someone using the app might make a purchase through the app without having received an offer or seen an offer.  Data SetsThe data is contained in three files:* portfolio.json - containing offer ids and meta data about each offer (duration, type, etc.)* profile.json - demographic data for each customer* transcript.json - records for transactions, offers received, offers viewed, and offers completed**Note:** You may need to upgrade numpy before reading in the files. This is because the old version of pandas cannot read in the transcript.json file correctly, but the newest version of pandas can.   Installing and importing required packages<jupyter_code>!pip install numpy --upgrade
!pip install autogluon --no-cache-dir
import datetime
import time
import tarfile
import math
import json
import boto3
import random
import pandas as pd
import numpy as np
from sagemaker import get_execution_role
import sagemaker
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

sm_boto3 = boto3.client("sagemaker")
sess = sagemaker.Session()
region = sess.boto_session.region_name
bucket = sess.default_bucket()  # this could also be a hard-coded bucket name
print("Using bucket " + bucket)
#To connect to google drive in colab
#from google.colab import drive
#drive.mount('/content/MyDrive')
#%cd MyDrive/MyDrive/AWS_Capstone
#pwd<jupyter_output><empty_output><jupyter_text>Reading and cleansing data<jupyter_code># read in the json files
transcript = pd.read_json('transcript.json', orient='records', lines=True)
portfolio = pd.read_json('portfolio.json', orient='records', lines=True)
profile = pd.read_json('profile.json', orient='records', lines=True, )<jupyter_output><empty_output><jupyter_text>transcript table<jupyter_code>#observing the raw table of transcript
transcript
#transcript_value contains each of keys of value column in a separate column 
transcript_value = pd.json_normalize(transcript['value'])

#Merging 'offer id' and 'offer_id' columns to 'offers' column, because by type of event we can see that an offer received, viewed or completed 
transcript_value['offers'] = transcript_value['offer id'].fillna(transcript_value['offer_id'])

#Deleting 'offer id' and 'offer_id' columns
transcript_value = transcript_value.drop(['offer_id', 'offer id'], axis = 1)

#deleting the value column from transcript 
transcript = transcript.drop(['value'], axis = 1)

#concatenating the separated columns of value in the transcript_value to the transcript
transcript = pd.concat([transcript, transcript_value], axis=1)

#observing categorical data in event and offers columns
print("event types:", np.unique(transcript['event']))
print("offers ids:", transcript['offers'].unique())

#One-hot encoding of the events column and deleting the event itself
for chan in ['offer_completed', 'offer_received', 'offer_viewed', 'transaction']:
    transcript[chan] = transcript.event.apply(lambda x: 1 if x==chan.replace('_',' ') else 0)
transcript.pop('event')

#Filling the NaN in transcript table
transcript['amount'] = transcript['amount'].fillna(0)
transcript['reward'] = transcript['reward'].fillna(0)
#Watching the infographic of its whole data
transcript.info()
#View the edited transcript table
transcript
#Saving transcript as a csv file
transcript.to_csv("transcript_edited.csv",index=False)<jupyter_output><empty_output><jupyter_text>portfolio table<jupyter_code>#View the raw table of portfolio
portfolio
#One-hot encoding of the channels column and deleting the channels column itself
for chan in ['web', 'email', 'mobile', 'social']:
    portfolio[chan] = portfolio.channels.apply(lambda x: 1 if chan in x else 0)
portfolio.pop('channels')

#One-hot encoding of the offer_type column and deleting the offer_type column itself
for chan in ['bogo', 'discount', 'informational']:
    portfolio[chan] = portfolio.offer_type.apply(lambda x: 1 if x==chan else 0)
portfolio.pop('offer_type')

#Renaming columns to avoid in common names with the profile table
portfolio = portfolio.rename(columns={'reward': 'offer_reward', 'duration': 'offer_duration',
                                      'difficulty': 'offer_difficulty'})

#View the infographic of the portfolio table
portfolio.info()
#View edited portfolio table
portfolio
#Saving portfolio as a csv file
portfolio.to_csv("portfolio_edited.csv",index=False)<jupyter_output><empty_output><jupyter_text>profile table<jupyter_code>profile = pd.read_json('profile.json', orient='records', lines=True, )
#View the raw table of profile
profile
#Reading the became_member_on column as date type and parse it to year and months
profile.to_csv('profile_edited.csv', index=False)
profile = pd.read_csv('profile_edited.csv', parse_dates=['became_member_on'])
profile['year'] = profile['became_member_on'].dt.year
profile['month'] = profile['became_member_on'].dt.month
profile
#View the raw data plots before filling the NaNs 
profile.hist(bins=30, figsize=(15,10))
#Creating one column named 'membership_duration' instead of the 'became_member_on', 'year', 'month' columns
this_year = datetime.datetime.today().year
this_month = datetime.datetime.today().month
#print(f"This year: {this_year}, This month: {this_month}")

#creating the column 'membership_duration' that contains membership duration in month
profile['membership_duration'] = (this_year-profile['year'])*12 + (12-profile['month']+this_month)
for col in ['became_member_on', 'year', 'month']:
    profile.pop(col)
#investigate the number of the NaN cells to fill
profile.info()
#Calculating the average of people whose ages are not 118
mean_age = profile['age'][profile['age']!=118].mean()
mean_age = int(mean_age)

#fill the NaN cells of the age column with average age
profile.loc[profile.age == 118, 'age'] = mean_age

#fill the NaN cells of the income column with the average income
mean_income = round(np.mean(profile['income']),0)
profile['income'] = profile['income'].fillna(mean_income)

O_count = profile[profile['gender']=='O']['gender'].count()
print(f"There are {O_count} persons having non obvious gender")

#fill the NaN cells of gender column in random, we don't Other genders for random choicing because of their minority

num_na = profile['gender'].isna().sum()  # number of missing cases
profile.loc[profile['gender'].isna(), 'gender'] = random.choices(["M", "F"], k=num_na)
#One-hot encoding of the gender column
print("gender types: ", profile.gender.unique())

for chan in ['M', 'F', 'O']:
    profile[chan] = profile.gender.apply(lambda x: 1 if x==chan else 0)
profile.pop('gender')

#Renaming to appropriate names
profile = profile.rename(columns={'F': 'Female', 'M': 'Male', 'O': 'Other'})
#View edited profile table
profile
#Check to see if we have NaN cells
profile.info()
#Saving the profile table as a csv file
profile.to_csv("profile_edited.csv", index=False)<jupyter_output><empty_output><jupyter_text>Merging all Data<jupyter_code>transcript = pd.read_csv("transcript_edited.csv")
portfolio = pd.read_csv("portfolio_edited.csv")
profile = pd.read_csv("profile_edited.csv")
#Merging transcript and profile tables on the joint person ids
transcript_profile_merged = pd.merge(transcript, profile, left_on='person', 
                                     right_on='id', how='left').drop('id', axis=1)
#Merge the above table with the portfolio table on the joint offer ids
my_starbuck = pd.merge(transcript_profile_merged, portfolio, left_on='offers',
                       right_on='id', how='left').drop('id', axis=1)
#Adding total transaction amount as a column to the above dataframe
total_transcript = ((my_starbuck['amount']).groupby(my_starbuck['person'])).sum()
total_transcript_df = pd.DataFrame({'id':total_transcript.index, 'total_transaction':total_transcript.values})
my_starbuck = pd.merge(my_starbuck, total_transcript_df, left_on='person',
                       right_on='id', how='left').drop('id', axis=1)

#Converting time from hours to days, because offer's times are in days
my_starbuck['time'] /= 24.0
my_starbuck['time'] = np.ceil(my_starbuck['time'])

#Sorting the dataframe based on person ids and time
my_starbuck = my_starbuck.sort_values(['person','time',])

#changing non zero entries of the reward column to 1, to remove dependendy of it with column offer_reward
my_starbuck['reward'] = my_starbuck.reward.apply(lambda x: 1 if x!=0 else 0)
my_starbuck

#Adding cumulative amount of transactions as the 'cumsum' column to my dataframe
my_starbuck['cumsum'] = (my_starbuck['amount']).groupby(my_starbuck['person']).cumsum()

my_starbuck
#Assigning the cumsum column to the amount column and deleting cumsum
my_starbuck['amount'] = my_starbuck['cumsum']
my_starbuck.pop('cumsum')

#Renaming amount column
my_starbuck = my_starbuck.rename(columns={'amount':'cumulative_transaction'})

#Decreasing the table size and just selecting rows that contain an offer (received/viewed/completed)
my_starbuck = my_starbuck[my_starbuck['transaction']==0].copy()

#Deleting the transaction column
my_starbuck.pop('transaction')

my_starbuck['offers'] = my_starbuck['offers'].astype('category')

#Reseting my goal table indexes
my_starbuck.reset_index(drop=True, inplace=True)
#View the edited table to work with
my_starbuck
#View infographic of my source table
my_starbuck.info()
#Saving my source file as my_starbuck.csv file
my_starbuck.to_csv("my_starbuck.csv", index=False)
#Uploading to s3
sess.upload_data(path="my_starbuck.csv", bucket=bucket, key_prefix="capstone")<jupyter_output><empty_output><jupyter_text>Data Analysis<jupyter_code>print("Transactions and offers receive/view/complete plots")
transcript = pd.read_csv("transcript_edited.csv")
transcript[transcript[transcript.columns]!=0].hist(bins=40, figsize=(15, 10))
print("You can see number of offers that people received, viewed or completed:")
plt.figure(figsize=(8,6))
plt.hist(transcript.offer_received[transcript.offer_received!=0], bins=30, alpha=0.5, label="offer_received")
plt.hist(transcript.offer_viewed[transcript.offer_viewed!=0], bins=30, alpha=0.5, label="offer_viewed")
plt.hist(transcript.offer_completed[transcript.offer_completed!=0], bins=30, alpha=0.5, label="offer_completed")
plt.xlabel("Data", size=14)
plt.ylabel("Count", size=14)
plt.title("Multiple Histograms with Matplotlib")
plt.legend(loc='upper right')
print("portfolio table review")
portfolio = pd.read_csv("portfolio_edited.csv")
portfolio
print("Edited profile table's feature histograms:")
profile = pd.read_csv("profile_edited.csv")
profile[profile[profile.columns]!=0].hist(bins=30, figsize=(15, 10))
#plot my source table (my_starbuck) feature histograms
my_starbuck = pd.read_csv("my_starbuck.csv")
print("Histogram of all features")
my_starbuck[my_starbuck[my_starbuck.columns]!=0].hist(bins=30, figsize=(15, 10))
print("Histogram of female customer's completed rewards ")
(my_starbuck[(my_starbuck['Female']==1) & (my_starbuck['reward']==1)]['offer_reward']).hist(bins=30, figsize=(10, 5))
print("Histogram of female customer's completed offer types ")
(my_starbuck[(my_starbuck['Female']==1) & (my_starbuck['reward']==1) ][['bogo',	'discount',	'informational']]).hist(bins=30, figsize=(10, 5))
print("Histogram of male customer's completed rewards ")
(my_starbuck[(my_starbuck['Male']==1) & (my_starbuck['reward']==1)]['offer_reward']).hist(bins=30, figsize=(10, 5))
print("Histogram of male customer's completed offer types ")
(my_starbuck[(my_starbuck['Male']==1) & (my_starbuck['reward']==1) ][['bogo',	'discount',	'informational']]).hist(bins=30, figsize=(10, 5))<jupyter_output>Histogram of male customer's completed offer types<jupyter_text>Training with Scikit_Learn random forest model<jupyter_code>my_starbuck = pd.read_csv("my_starbuck.csv")
len(my_starbuck)
print("Number of rows containing Other genders:")
my_starbuck[(my_starbuck['Other']==1)]['person'].count()
#Reading my source table
my_starbuck = pd.read_csv("my_starbuck.csv")

#Deleting the rows containing Other genders
my_starbuck = my_starbuck.drop(my_starbuck[(my_starbuck['Other']==1)].index)

#Reseting my goal table indexes
my_starbuck.reset_index(drop=True, inplace=True)

#drop unimportant and unnecessary columns
my_starbuck = my_starbuck.drop([ 'person','offers', 'Other',  'email',
                                'informational', 'offer_completed', 'offer_received', 
                                'offer_viewed', 'total_transaction',], axis=1)
#Check my source table "my_starbuck"
my_starbuck.info()
#Do some preprocessing if necessary
from sklearn import preprocessing

#Normalizing some columns that contain big numbers
x = my_starbuck[['income', 'age', 'time','membership_duration',]].values #returns a numpy array
min_max_scaler = preprocessing.MinMaxScaler()
x_scaled = min_max_scaler.fit_transform(x)
normalized_columns = pd.DataFrame(x_scaled)

data = my_starbuck.copy()
data['income'] = normalized_columns[0]
data['age'] = normalized_columns[1]
data['time'] = normalized_columns[2]
data['membership_duration'] = normalized_columns[3]
data = data.round(5)
from sklearn.model_selection import train_test_split

#splitting the data to train and test
train, test = train_test_split(
    data, test_size=0.25, random_state=42)
#Saving the train and test files to csv
train.to_csv("train.csv")
test.to_csv("test.csv")

# Save data to S3, SageMaker will take training data from s3
trainpath = sess.upload_data(
    path="train.csv", bucket=bucket, key_prefix="capstone"
)

testpath = sess.upload_data(
    path="test.csv", bucket=bucket, key_prefix="capstone"
)
#print(train.shape, test.shape)<jupyter_output><empty_output><jupyter_text>Write model training job on a RandomForestRegressor to script.py file<jupyter_code>%%writefile script.py

import argparse
import joblib
import os

import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestRegressor


# inference functions ---------------
def model_fn(model_dir):
    clf = joblib.load(os.path.join(model_dir, "model.joblib"))
    return clf


if __name__ == "__main__":

    print("extracting arguments")
    parser = argparse.ArgumentParser()

    # hyperparameters sent by the client are passed as command-line arguments to the script.
    # to simplify the demo we don't use all sklearn RandomForest hyperparameters
    parser.add_argument("--n-estimators", type=int, default=10)
    parser.add_argument("--min-samples-leaf", type=int, default=3)

    # Data, model, and output directories
    parser.add_argument("--model-dir", type=str, default=os.environ.get("SM_MODEL_DIR"))
    parser.add_argument("--train", type=str, default=os.environ.get("SM_CHANNEL_TRAIN"))
    parser.add_argument("--test", type=str, default=os.environ.get("SM_CHANNEL_TEST"))
    parser.add_argument("--train-file", type=str, default="train.csv")
    parser.add_argument("--test-file", type=str, default="test.csv")
    parser.add_argument(
        "--features", type=str
    )  # in this script we ask user to explicitly name features
    parser.add_argument(
        "--target", type=str
    )  # in this script we ask user to explicitly name the target

    args, _ = parser.parse_known_args()

    print("reading data")
    train_df = pd.read_csv(os.path.join(args.train, args.train_file))
    test_df = pd.read_csv(os.path.join(args.test, args.test_file))

    print("building training and testing datasets")
    X_train = train_df[args.features.split()]
    X_test = test_df[args.features.split()]
    y_train = train_df[args.target]
    y_test = test_df[args.target]

    # train
    print("training model")
    model = RandomForestRegressor(
        n_estimators=args.n_estimators, min_samples_leaf=args.min_samples_leaf, n_jobs=-1
    )

    model.fit(X_train, y_train)

    # print abs error
    print("validating model")
    abs_err = np.abs(model.predict(X_test) - y_test)

    # print couple perf metrics
    for q in [10, 50, 90]:
        print("AE-at-" + str(q) + "th-percentile: " + str(np.percentile(a=abs_err, q=q)))

    # persist model
    path = os.path.join(args.model_dir, "model.joblib")
    joblib.dump(model, path)
    print("model persisted at " + path)
    print(args.min_samples_leaf)


print("train features: ", train.columns)
feature_names = ['time', 'reward', 'age', 'income',
       'membership_duration', 'Male', 'Female', 'offer_reward',
       'offer_difficulty', 'offer_duration', 'web', 'mobile', 'social', 'bogo',
       'discount' ]<jupyter_output>train features:  Index(['time', 'cumulative_transaction', 'reward', 'age', 'income',
       'membership_duration', 'Male', 'Female', 'offer_reward',
       'offer_difficulty', 'offer_duration', 'web', 'mobile', 'social', 'bogo',
       'discount'],
      dtype='object')<jupyter_text>Local training<jupyter_code>! python script.py --n-estimators 100 \
                   --min-samples-leaf 2 \
                   --model-dir ./ \
                   --train ./ \
                   --test ./ \
                   --features 'time reward age income membership_duration Male Female offer_reward offer_difficulty offer_duration web mobile social bogo discount' \
                   --target cumulative_transaction<jupyter_output>extracting arguments
reading data
building training and testing datasets
training model
validating model
AE-at-10th-percentile: 0.16653535714286247
AE-at-50th-percentile: 14.753534285714306
AE-at-90th-percentile: 66.80788100288605
model persisted at ./model.joblib
2<jupyter_text>Launch a Tuning Job<jupyter_code># We use the Estimator from the SageMaker Python SDK
from sagemaker.sklearn.estimator import SKLearn

FRAMEWORK_VERSION = "0.23-1"
hyperparameters = {"n-estimators": 147, \
                   "min-samples-leaf":  2, \
                  "features": 'time reward age income membership_duration Male Female offer_reward offer_difficulty offer_duration web mobile social bogo discount' , \
                   "target": 'cumulative_transaction', }

sklearn_estimator = SKLearn(
    entry_point="script.py",
    role=get_execution_role(),
    instance_count=1,
    instance_type="ml.m4.xlarge",#"ml.c5.xlarge",#"ml.m4.xlarge",
    framework_version=FRAMEWORK_VERSION,
    base_job_name="train-star",
    metric_definitions=[{"Name": "median-AE", "Regex": "AE-at-50th-percentile: ([0-9.]+).*$"}],
    hyperparameters=hyperparameters,
)

# we use the Hyperparameter Tuner
from sagemaker.tuner import IntegerParameter

# Define exploration boundaries
hyperparameter_ranges = {
    "n-estimators": IntegerParameter(20, 200),
    "min-samples-leaf": IntegerParameter(2, 10),
}

# create Optimizer
Optimizer = sagemaker.tuner.HyperparameterTuner(
    estimator=sklearn_estimator,
    hyperparameter_ranges=hyperparameter_ranges,
    base_tuning_job_name="tuner-star",
    objective_type="Minimize",
    objective_metric_name="median-AE",
    metric_definitions=[
        {"Name": "median-AE", "Regex": "AE-at-50th-percentile: ([0-9.]+).*$"}
    ],  # extract tracked metric from logs with regexp
    max_jobs=10,
    max_parallel_jobs=2,
)
import time
tic = time.clock()

Optimizer.fit({"train": trainpath, "test": testpath})

toc = time.clock()
print(toc - tic)
# get tuner results in a df
results = Optimizer.analytics().dataframe()
while results.empty:
    time.sleep(1)
    results = Optimizer.analytics().dataframe()
results.head()

best_estimator=Optimizer.best_estimator()
best_estimator.hyperparameters()
hyperparameters = {"n-estimators": int(best_estimator.hyperparameters()['n-estimators'].replace('"', '')), \
                   "min-samples-leaf":  int(best_estimator.hyperparameters()['min-samples-leaf'].replace('"', '')), \
                  "features": best_estimator.hyperparameters()['features'].replace('"', ''), \
                   "target": best_estimator.hyperparameters()['target'].replace('"', ''), }
hyperparameters<jupyter_output><empty_output><jupyter_text>Launching a training job on best hyperparameters<jupyter_code># We use the Estimator from the SageMaker Python SDK
from sagemaker.sklearn.estimator import SKLearn
import time

FRAMEWORK_VERSION = "0.23-1"

sklearn_estimator = SKLearn(
    entry_point="script.py",
    role=get_execution_role(),
    instance_count=1,
    instance_type="ml.m4.xlarge",#"ml.c5.xlarge",#"ml.m4.xlarge",
    framework_version=FRAMEWORK_VERSION,
    base_job_name="train-star",
    metric_definitions=[{"Name": "median-AE", "Regex": "AE-at-50th-percentile: ([0-9.]+).*$"}],
    hyperparameters=hyperparameters,
)

tic = time.clock()

# launch training job
sklearn_estimator.fit({"train": trainpath, "test": testpath}, wait=True)

toc = time.clock()
print(toc - tic)<jupyter_output>2022-02-13 02:43:41 Starting - Starting the training job...
2022-02-13 02:44:05 Starting - Launching requested ML instancesProfilerReport-1644720221: InProgress
......
2022-02-13 02:45:11 Starting - Preparing the instances for training............
2022-02-13 02:47:06 Downloading - Downloading input data
2022-02-13 02:47:06 Training - Downloading the training image.....[34m2022-02-13 02:47:47,454 sagemaker-containers INFO     Imported framework sagemaker_sklearn_container.training[0m
[34m2022-02-13 02:47:47,456 sagemaker-training-toolkit INFO     No GPUs detected (normal if no gpus installed)[0m
[34m2022-02-13 02:47:47,469 sagemaker_sklearn_container.training INFO     Invoking user training script.[0m
[34m2022-02-13 02:47:47,864 sagemaker-training-toolkit INFO     No GPUs detected (normal if no gpus installed)[0m
[34m2022-02-13 02:47:47,878 sagemaker-training-toolkit INFO     No GPUs detected (normal if no gpus installed)[0m
[34m2022-02-13 02:47:47,893 sagemaker-training-tool[...]<jupyter_text>Deploy to a real-time endpoint<jupyter_code>from sagemaker.sklearn.model import SKLearnModel

sklearn_estimator.latest_training_job.wait(logs="None")
artifact = sm_boto3.describe_training_job(
    TrainingJobName= sklearn_estimator.latest_training_job.name#'train-star-2022-02-11-09-09-36-428' 
)["ModelArtifacts"]["S3ModelArtifacts"]

print("Model artifact persisted at " + artifact)

model = SKLearnModel(
    model_data=artifact,
    role=get_execution_role(),
    entry_point="script.py",
    framework_version=FRAMEWORK_VERSION,
)

predictor = model.deploy(instance_type="ml.c5.large", initial_instance_count=1)<jupyter_output>2022-02-13 02:49:26 Starting - Preparing the instances for training
2022-02-13 02:49:26 Downloading - Downloading input data
2022-02-13 02:49:26 Training - Training image download completed. Training in progress.
2022-02-13 02:49:26 Uploading - Uploading generated training model
2022-02-13 02:49:26 Completed - Training job completed
Model artifact persisted at s3://sagemaker-us-east-1-201557610166/train-star-2022-02-13-02-43-41-075/output/model.tar.gz
-----!<jupyter_text>Invoke the endpoint<jupyter_code># the SKLearnPredictor does the serialization from pandas for us
response = predictor.predict(test[feature_names])
test_target = test['cumulative_transaction']
test_target = test_target.to_numpy() 

print("response \t\t target")
for i in range(100):
    print(response[i] , "\t",test_target[i])<jupyter_output>response 		 target
42.741547781017154 	 42.75
62.41656648850017 	 31.57
5.431426303854877 	 0.0
111.42925178166503 	 61.63
119.83790046971173 	 146.2
30.473342484612882 	 37.57
81.09920667314543 	 29.75
73.52277721088433 	 73.36
5.504794001727676 	 2.54
35.42429664723034 	 20.41
132.62019595616022 	 138.12
45.86012331281719 	 23.98
57.533254994061096 	 33.6
61.2219977324263 	 37.06
56.77866553287983 	 20.52
14.928407446672761 	 128.26
20.11640678652412 	 29.56
39.824623744735995 	 121.08
64.26413265306118 	 33.97
6.332217624867687 	 8.84
20.02664085951841 	 12.79
15.32111321671525 	 0.0
138.58601587301595 	 789.81
110.23857701652086 	 55.65
144.37812649821834 	 155.09
107.90099708454815 	 124.15
69.68707636864272 	 83.38
124.63938921282798 	 130.97
0.0 	 0.0
8.765819327214734 	 3.92
1.18198223733938 	 0.05
81.47381827016518 	 99.23
89.95767454918476 	 108.05
48.186443013713415 	 109.19
0.0 	 0.0
89.26236799481691 	 76.01
10.935080793356306 	 0.0
50.988030936184 	 19.95
95.8436182917611[...]<jupyter_text>Evaluate the sklearn random forest model<jupyter_code>from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

mean_squared_error = mean_squared_error(test_target, response)
mean_absolute_error = mean_absolute_error(test_target, response)
r2_score = r2_score(test_target, response)
print(f"R2 score: {r2_score}, mean_squared_error: {mean_squared_error}, mean_absolute_error {mean_absolute_error}")<jupyter_output>R2 score: 0.4523693254058069, mean_squared_error: 4236.3759983377595, mean_absolute_error 29.62099167956011<jupyter_text>Delete the endpoint<jupyter_code>#Don’t forget to delete the endpoint!
predictor.delete_endpoint()<jupyter_output><empty_output><jupyter_text>Training with autogluon.tabularBecause the R2 score of the Scikit_Learn Random Forest model is rather low, we train the dataset using Autogluon Tabular models to check if we obtain better results. We know that autogluon.tabular contains RFModel (Random Forest model (scikit-learn)) as one of its models. So we hope we will certainly improve the result.<jupyter_code>from sklearn.model_selection import train_test_split

#Read from my source table
my_starbuck = pd.read_csv("my_starbuck.csv")

#Splitting to train and test files
train, test = train_test_split(
    my_starbuck, test_size=0.25, random_state=42
)
print(train.shape, test.shape)
from autogluon.tabular import TabularPredictor

#Training with Autogluon Tabular
save_path = 'transaction_models'
predictor = TabularPredictor('cumulative_transaction', problem_type='regression', 
                                          path=save_path, learner_kwargs={'ignored_columns':['person', 'offers','Other', 'email', 'informational', 'offer_completed', 'offer_received', 'offer_viewed', 'total_transaction']} ).fit(train, time_limit=1200, presets='best_quality')<jupyter_output>Warning: path already exists! This predictor may overwrite an existing predictor! path="transaction_models"
Presets specified: ['best_quality']
Beginning AutoGluon training ... Time limit = 1200s
AutoGluon will save models to "transaction_models/"
AutoGluon Version:  0.3.1
Train Data Rows:    125685
Train Data Columns: 24
Preprocessing data ...
Using Feature Generators to preprocess the data ...
Dropping user-specified ignored columns: ['person', 'offers', 'Other', 'email', 'informational', 'offer_completed', 'offer_received', 'offer_viewed', 'total_transaction']
Fitting AutoMLPipelineFeatureGenerator...
	Available Memory:                    2719.5 MB
	Train Data (Original)  Memory Usage: 15.08 MB (0.6% of available memory)
	Inferring data type of each feature based on column values. Set feature_metadata_in to manually specify special dtypes of the features.
	Stage 1 Generators:
		Fitting AsTypeFeatureGenerator...
			Note: Converting 8 features to boolean dtype as they only contain 2 u[...]<jupyter_text>My Tabular predictor leaderboard<jupyter_code>#The predictor leaderboard that is produced using the data previously reserved for validation inside fit, and can display extra information about each model:
predictor.leaderboard(extra_info=True, silent=True)
print("Predictor features: ", predictor.features())<jupyter_output>Predictor features:  ['time', 'reward', 'age', 'income', 'membership_duration', 'Male', 'Female', 'offer_reward', 'offer_difficulty', 'offer_duration', 'web', 'mobile', 'social', 'bogo', 'discount']<jupyter_text>Getting predictions from TabularPredictor<jupyter_code>response = predictor.predict(test)
test_target = test['cumulative_transaction']
print("response:\n ",response)
print("target:\n",test_target)<jupyter_output>response:
  53680    766.571960
60296     44.871216
93002     23.226473
51223     16.035902
63364      0.295056
            ...    
38068     32.941368
96695     11.738913
51438     95.026451
85069    133.813339
88609     19.691917
Name: cumulative_transaction, Length: 41896, dtype: float32
target:
 53680    674.56
60296      8.59
93002      8.48
51223     13.22
63364      0.00
          ...  
38068     34.04
96695      4.60
51438     44.72
85069     71.67
88609      9.95
Name: cumulative_transaction, Length: 41896, dtype: float64<jupyter_text>Evaluate the Autogluon predictor<jupyter_code>predictor.evaluate(test)<jupyter_output>Evaluation: root_mean_squared_error on test data: -40.85419444299454
	Note: Scores are always higher_is_better. This metric score can be multiplied by -1 to get the metric value.
Evaluations on test data:
{
    "root_mean_squared_error": -40.85419444299454,
    "mean_squared_error": -1669.0652035860114,
    "mean_absolute_error": -18.183393678980757,
    "r2": 0.7690994021106778,
    "pearsonr": 0.8772191133365619,
    "median_absolute_error": -8.33363681793214
}<jupyter_text>Feature importance<jupyter_code>feature_importance = predictor.feature_importance(test)
feature_importance
predictor.get_model_best()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.115102735244078, 'fraction_numerical': 0.05794398638921607, 'mean_word_length': 5.2852148879292615, 'pattern_counts': {'":': 27, '<': 74, '<?xml version=': 0, '>': 74, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '21', 'dir': 'jupyter-structured-clean-dedup', 'id': '151399', 'license': 'Apache-2.0', 'n_tokens_mistral': 11165, 'n_tokens_neox': 9563, 'n_words': 2608, 'path': 'Starbucks_Capstone_notebook_last.ipynb', 'repo_name': 'EnsiyehRaoufi/AWS-ML-Capstone-project', 'size': '30564'}