{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Fraud detection combining both Amazon Fraud Detector and Amazon SageMaker models in the same transaction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Importing tools and libraries to be used" ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [], "source": [ "import os\n", "import io\n", "import sys\n", "import json\n", "import uuid\n", "import numpy as np \n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "import boto3\n", "import time\n", "import sklearn\n", "import seaborn as sns\n", "import sagemaker\n", "\n", "from IPython.display import clear_output\n", "from datetime import datetime\n", "from io import StringIO\n", "from imblearn.under_sampling import RandomUnderSampler\n", "from imblearn.over_sampling import SMOTENC\n", "from collections import Counter\n", "from sklearn.model_selection import train_test_split\n", "from sklearn.datasets import dump_svmlight_file\n", "from sklearn.metrics import balanced_accuracy_score, cohen_kappa_score, confusion_matrix\n", "from sklearn.metrics import roc_curve, roc_auc_score, auc, roc_auc_score, classification_report\n", "%matplotlib inline\n", "from sagemaker import get_execution_role\n", "from sagemaker.amazon.amazon_estimator import get_image_uri\n", "from sagemaker.predictor import csv_serializer\n", "from math import sqrt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Investigate and process the data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's start by downloading the dataset from: https://www.kaggle.com/mlg-ulb/creditcardfraud?select=creditcard.csv and upload it into the notebook file system as creditcard.csv." ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [], "source": [ "# Resources and env variables setup\n", "s3_resource = boto3.resource('s3')\n", "afd_resource = boto3.client('frauddetector')\n", "\n", "# suffix is appended to detector and model name for uniqueness \n", "sufx = datetime.now().strftime(\"%Y%m%d\")\n", "# prefix is prepended to the sagamaker components\n", "prefx = 'sagemaker-model'\n", "# replace with the training bucket created in the CloudFormation\n", "S3_BUCKET = \"afd-poc-trainingbucket-1i37svk9elcoe\"\n", "# replace with the output bucket created in the CloudFormation\n", "S3_OUT_BUCKET = \"afd-poc-outputbucket-1fhn20d7tumgg\"\n", "# Replace the ARN Role with the resources created in CloudFormation stack\n", "ARN_ROLE = \"arn:aws:iam::387461613214:role/afd-poc-NotebookInstanceExecutionRole-1FNQ41S8H2G68\" " ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "pd.set_option('display.max_rows', 500)\n", "pd.set_option('display.max_columns', 500)\n", "pd.set_option('display.width', 1000)\n", "\n", "data = pd.read_csv('creditcard.csv', delimiter=',')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's take a peek at our data (we only show a subset of the columns in the table):" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Index(['Time', 'V1', 'V2', 'V3', 'V4', 'V5', 'V6', 'V7', 'V8', 'V9', 'V10', 'V11', 'V12', 'V13', 'V14', 'V15', 'V16', 'V17', 'V18', 'V19', 'V20', 'V21', 'V22', 'V23', 'V24', 'V25', 'V26', 'V27', 'V28', 'Amount', 'Class'], dtype='object')\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
TimeV1V2V3V4V5V6V7V8V9V10V11V12V13V14V15V16V17V18V19V20V21V22V23V24V25V26V27V28AmountClass
count284807.0000002.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+052.848070e+05284807.000000284807.000000
mean94813.8595753.919560e-155.688174e-16-8.769071e-152.782312e-15-1.552563e-152.010663e-15-1.694249e-15-1.927028e-16-3.137024e-151.768627e-159.170318e-16-1.810658e-151.693438e-151.479045e-153.482336e-151.392007e-15-7.528491e-164.328772e-169.049732e-165.085503e-161.537294e-167.959909e-165.367590e-164.458112e-151.453003e-151.699104e-15-3.660161e-16-1.206049e-1688.3496190.001727
std47488.1459551.958696e+001.651309e+001.516255e+001.415869e+001.380247e+001.332271e+001.237094e+001.194353e+001.098632e+001.088850e+001.020713e+009.992014e-019.952742e-019.585956e-019.153160e-018.762529e-018.493371e-018.381762e-018.140405e-017.709250e-017.345240e-017.257016e-016.244603e-016.056471e-015.212781e-014.822270e-014.036325e-013.300833e-01250.1201090.041527
min0.000000-5.640751e+01-7.271573e+01-4.832559e+01-5.683171e+00-1.137433e+02-2.616051e+01-4.355724e+01-7.321672e+01-1.343407e+01-2.458826e+01-4.797473e+00-1.868371e+01-5.791881e+00-1.921433e+01-4.498945e+00-1.412985e+01-2.516280e+01-9.498746e+00-7.213527e+00-5.449772e+01-3.483038e+01-1.093314e+01-4.480774e+01-2.836627e+00-1.029540e+01-2.604551e+00-2.256568e+01-1.543008e+010.0000000.000000
25%54201.500000-9.203734e-01-5.985499e-01-8.903648e-01-8.486401e-01-6.915971e-01-7.682956e-01-5.540759e-01-2.086297e-01-6.430976e-01-5.354257e-01-7.624942e-01-4.055715e-01-6.485393e-01-4.255740e-01-5.828843e-01-4.680368e-01-4.837483e-01-4.988498e-01-4.562989e-01-2.117214e-01-2.283949e-01-5.423504e-01-1.618463e-01-3.545861e-01-3.171451e-01-3.269839e-01-7.083953e-02-5.295979e-025.6000000.000000
50%84692.0000001.810880e-026.548556e-021.798463e-01-1.984653e-02-5.433583e-02-2.741871e-014.010308e-022.235804e-02-5.142873e-02-9.291738e-02-3.275735e-021.400326e-01-1.356806e-025.060132e-024.807155e-026.641332e-02-6.567575e-02-3.636312e-033.734823e-03-6.248109e-02-2.945017e-026.781943e-03-1.119293e-024.097606e-021.659350e-02-5.213911e-021.342146e-031.124383e-0222.0000000.000000
75%139320.5000001.315642e+008.037239e-011.027196e+007.433413e-016.119264e-013.985649e-015.704361e-013.273459e-015.971390e-014.539234e-017.395934e-016.182380e-016.625050e-014.931498e-016.488208e-015.232963e-013.996750e-015.008067e-014.589494e-011.330408e-011.863772e-015.285536e-011.476421e-014.395266e-013.507156e-012.409522e-019.104512e-027.827995e-0277.1650000.000000
max172792.0000002.454930e+002.205773e+019.382558e+001.687534e+013.480167e+017.330163e+011.205895e+022.000721e+011.559499e+012.374514e+011.201891e+017.848392e+007.126883e+001.052677e+018.877742e+001.731511e+019.253526e+005.041069e+005.591971e+003.942090e+012.720284e+011.050309e+012.252841e+014.584549e+007.519589e+003.517346e+003.161220e+013.384781e+0125691.1600001.000000
\n", "
" ], "text/plain": [ " Time V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20 V21 V22 V23 V24 V25 V26 V27 V28 Amount Class\n", "count 284807.000000 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 2.848070e+05 284807.000000 284807.000000\n", "mean 94813.859575 3.919560e-15 5.688174e-16 -8.769071e-15 2.782312e-15 -1.552563e-15 2.010663e-15 -1.694249e-15 -1.927028e-16 -3.137024e-15 1.768627e-15 9.170318e-16 -1.810658e-15 1.693438e-15 1.479045e-15 3.482336e-15 1.392007e-15 -7.528491e-16 4.328772e-16 9.049732e-16 5.085503e-16 1.537294e-16 7.959909e-16 5.367590e-16 4.458112e-15 1.453003e-15 1.699104e-15 -3.660161e-16 -1.206049e-16 88.349619 0.001727\n", "std 47488.145955 1.958696e+00 1.651309e+00 1.516255e+00 1.415869e+00 1.380247e+00 1.332271e+00 1.237094e+00 1.194353e+00 1.098632e+00 1.088850e+00 1.020713e+00 9.992014e-01 9.952742e-01 9.585956e-01 9.153160e-01 8.762529e-01 8.493371e-01 8.381762e-01 8.140405e-01 7.709250e-01 7.345240e-01 7.257016e-01 6.244603e-01 6.056471e-01 5.212781e-01 4.822270e-01 4.036325e-01 3.300833e-01 250.120109 0.041527\n", "min 0.000000 -5.640751e+01 -7.271573e+01 -4.832559e+01 -5.683171e+00 -1.137433e+02 -2.616051e+01 -4.355724e+01 -7.321672e+01 -1.343407e+01 -2.458826e+01 -4.797473e+00 -1.868371e+01 -5.791881e+00 -1.921433e+01 -4.498945e+00 -1.412985e+01 -2.516280e+01 -9.498746e+00 -7.213527e+00 -5.449772e+01 -3.483038e+01 -1.093314e+01 -4.480774e+01 -2.836627e+00 -1.029540e+01 -2.604551e+00 -2.256568e+01 -1.543008e+01 0.000000 0.000000\n", "25% 54201.500000 -9.203734e-01 -5.985499e-01 -8.903648e-01 -8.486401e-01 -6.915971e-01 -7.682956e-01 -5.540759e-01 -2.086297e-01 -6.430976e-01 -5.354257e-01 -7.624942e-01 -4.055715e-01 -6.485393e-01 -4.255740e-01 -5.828843e-01 -4.680368e-01 -4.837483e-01 -4.988498e-01 -4.562989e-01 -2.117214e-01 -2.283949e-01 -5.423504e-01 -1.618463e-01 -3.545861e-01 -3.171451e-01 -3.269839e-01 -7.083953e-02 -5.295979e-02 5.600000 0.000000\n", "50% 84692.000000 1.810880e-02 6.548556e-02 1.798463e-01 -1.984653e-02 -5.433583e-02 -2.741871e-01 4.010308e-02 2.235804e-02 -5.142873e-02 -9.291738e-02 -3.275735e-02 1.400326e-01 -1.356806e-02 5.060132e-02 4.807155e-02 6.641332e-02 -6.567575e-02 -3.636312e-03 3.734823e-03 -6.248109e-02 -2.945017e-02 6.781943e-03 -1.119293e-02 4.097606e-02 1.659350e-02 -5.213911e-02 1.342146e-03 1.124383e-02 22.000000 0.000000\n", "75% 139320.500000 1.315642e+00 8.037239e-01 1.027196e+00 7.433413e-01 6.119264e-01 3.985649e-01 5.704361e-01 3.273459e-01 5.971390e-01 4.539234e-01 7.395934e-01 6.182380e-01 6.625050e-01 4.931498e-01 6.488208e-01 5.232963e-01 3.996750e-01 5.008067e-01 4.589494e-01 1.330408e-01 1.863772e-01 5.285536e-01 1.476421e-01 4.395266e-01 3.507156e-01 2.409522e-01 9.104512e-02 7.827995e-02 77.165000 0.000000\n", "max 172792.000000 2.454930e+00 2.205773e+01 9.382558e+00 1.687534e+01 3.480167e+01 7.330163e+01 1.205895e+02 2.000721e+01 1.559499e+01 2.374514e+01 1.201891e+01 7.848392e+00 7.126883e+00 1.052677e+01 8.877742e+00 1.731511e+01 9.253526e+00 5.041069e+00 5.591971e+00 3.942090e+01 2.720284e+01 1.050309e+01 2.252841e+01 4.584549e+00 7.519589e+00 3.517346e+00 3.161220e+01 3.384781e+01 25691.160000 1.000000" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(data.columns)\n", "data.describe()" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of frauds: 492\n", "Number of non-frauds: 284315\n", "Percentage of fradulent data: 0.1727485630620034\n" ] } ], "source": [ "nonfrauds, frauds = data.groupby('Class').size()\n", "print('Number of frauds: ', frauds)\n", "print('Number of non-frauds: ', nonfrauds)\n", "print('Percentage of fradulent data:', 100.*frauds/(frauds + nonfrauds))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The class column corresponds to whether or not a transaction is fradulent. We see that the majority of data is non-fraudulent with only $492$ ($.173\\%$), check the Class column mean, of the data corresponding to fraudulent examples." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A PCA have been made lets check the mean and standard deviation of the features." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "data.hist(bins=50,figsize=(20,15))\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Looks good, columns 𝑉𝑖 have been normalized to have 0 mean and unit standard deviation as the result of a PCA. Now, lets change the data to be Amazon Fraud Detector compatible." ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Index(['time', 'va', 'vb', 'vc', 'vd', 've', 'vf', 'vg', 'vh', 'vi', 'vj', 'vk', 'vl', 'vm', 'vn', 'vo', 'vp', 'vq', 'vr', 'vs', 'vt', 'vu', 'vv', 'vw', 'vx', 'vy', 'vz', 'vaa', 'vab', 'amount', 'class'], dtype='object')\n" ] } ], "source": [ "# to lowercase\n", "data.columns = map(str.lower, data.columns)\n", "print(data.columns)" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Index(['Time', 'va', 'vb', 'vc', 'vd', 've', 'vf', 'vg', 'vh', 'vi', 'vj', 'vk', 'vl', 'vm', 'vn', 'vo', 'vp', 'vq', 'vr', 'vs', 'vt', 'vu', 'vv', 'vw', 'vx', 'vy', 'vz', 'vaa', 'vab', 'Amount', 'Class'], dtype='object')\n" ] } ], "source": [ "# mapping column names numbers to letters\n", "\n", "def standardize_headers(x):\n", " if any(char.isdigit() for char in x):\n", " if int(x[1:]) > 26:\n", " return 'va'+chr(int(x[1:])+70)\n", " return 'v'+chr(int(x[1:])+96)\n", " return x\n", "\n", "data.rename(columns=standardize_headers, inplace=True)\n", "print(data.columns)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then change the timestamp and label column names" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
timevavbvcvdvevfvgvhvivjvkvlvmvnvovpvqvrvsvtvuvvvwvxvyvzvaavabamountEVENT_LABEL
00.0-1.359807-0.0727812.5363471.378155-0.3383210.4623880.2395990.0986980.3637870.090794-0.551600-0.617801-0.991390-0.3111691.468177-0.4704010.2079710.0257910.4039930.251412-0.0183070.277838-0.1104740.0669280.128539-0.1891150.133558-0.021053149.620
10.01.1918570.2661510.1664800.4481540.060018-0.082361-0.0788030.085102-0.255425-0.1669741.6127271.0652350.489095-0.1437720.6355580.463917-0.114805-0.183361-0.145783-0.069083-0.225775-0.6386720.101288-0.3398460.1671700.125895-0.0089830.0147242.690
21.0-1.358354-1.3401631.7732090.379780-0.5031981.8004990.7914610.247676-1.5146540.2076430.6245010.0660840.717293-0.1659462.345865-2.8900831.109969-0.121359-2.2618570.5249800.2479980.7716790.909412-0.689281-0.327642-0.139097-0.055353-0.059752378.660
31.0-0.966272-0.1852261.792993-0.863291-0.0103091.2472030.2376090.377436-1.387024-0.054952-0.2264870.1782280.507757-0.287924-0.631418-1.059647-0.6840931.965775-1.232622-0.208038-0.1083000.005274-0.190321-1.1755750.647376-0.2219290.0627230.061458123.500
42.0-1.1582330.8777371.5487180.403034-0.4071930.0959210.592941-0.2705330.8177390.753074-0.8228430.5381961.345852-1.1196700.175121-0.451449-0.237033-0.0381950.8034870.408542-0.0094310.798278-0.1374580.141267-0.2060100.5022920.2194220.21515369.990
\n", "
" ], "text/plain": [ " time va vb vc vd ve vf vg vh vi vj vk vl vm vn vo vp vq vr vs vt vu vv vw vx vy vz vaa vab amount EVENT_LABEL\n", "0 0.0 -1.359807 -0.072781 2.536347 1.378155 -0.338321 0.462388 0.239599 0.098698 0.363787 0.090794 -0.551600 -0.617801 -0.991390 -0.311169 1.468177 -0.470401 0.207971 0.025791 0.403993 0.251412 -0.018307 0.277838 -0.110474 0.066928 0.128539 -0.189115 0.133558 -0.021053 149.62 0\n", "1 0.0 1.191857 0.266151 0.166480 0.448154 0.060018 -0.082361 -0.078803 0.085102 -0.255425 -0.166974 1.612727 1.065235 0.489095 -0.143772 0.635558 0.463917 -0.114805 -0.183361 -0.145783 -0.069083 -0.225775 -0.638672 0.101288 -0.339846 0.167170 0.125895 -0.008983 0.014724 2.69 0\n", "2 1.0 -1.358354 -1.340163 1.773209 0.379780 -0.503198 1.800499 0.791461 0.247676 -1.514654 0.207643 0.624501 0.066084 0.717293 -0.165946 2.345865 -2.890083 1.109969 -0.121359 -2.261857 0.524980 0.247998 0.771679 0.909412 -0.689281 -0.327642 -0.139097 -0.055353 -0.059752 378.66 0\n", "3 1.0 -0.966272 -0.185226 1.792993 -0.863291 -0.010309 1.247203 0.237609 0.377436 -1.387024 -0.054952 -0.226487 0.178228 0.507757 -0.287924 -0.631418 -1.059647 -0.684093 1.965775 -1.232622 -0.208038 -0.108300 0.005274 -0.190321 -1.175575 0.647376 -0.221929 0.062723 0.061458 123.50 0\n", "4 2.0 -1.158233 0.877737 1.548718 0.403034 -0.407193 0.095921 0.592941 -0.270533 0.817739 0.753074 -0.822843 0.538196 1.345852 -1.119670 0.175121 -0.451449 -0.237033 -0.038195 0.803487 0.408542 -0.009431 0.798278 -0.137458 0.141267 -0.206010 0.502292 0.219422 0.215153 69.99 0" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# rename to the Amazon Fraud Detector name conventions \n", "data.rename(columns={'class':'EVENT_LABEL'}, inplace=True)\n", "data.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Get epoch time for the initial dataset date" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1600808118.409983\n" ] } ], "source": [ "# Get epoch time for the initial dataset date\n", "epoch = datetime.utcfromtimestamp(0)\n", "def unix_time_seconds(dt):\n", " return (dt - epoch).total_seconds()\n", "\n", "# Lets pretend that the data is from yesterday and could can test at the end with todays date.\n", "start_dt = datetime.strptime('Sep 22 2020 12:00AM', '%b %d %Y %I:%M%p')\n", "start_dt = datetime.now()\n", "start_ep = unix_time_seconds(start_dt)\n", "print(start_ep)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The date column is represented as incremental seconds, lets translate it to dates formats." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
timevavbvcvdvevfvgvhvivjvkvlvmvnvovpvqvrvsvtvuvvvwvxvyvzvaavabamountEVENT_LABELEVENT_TIMESTAMP
00.0-1.359807-0.0727812.5363471.378155-0.3383210.4623880.2395990.0986980.3637870.090794-0.551600-0.617801-0.991390-0.3111691.468177-0.4704010.2079710.0257910.4039930.251412-0.0183070.277838-0.1104740.0669280.128539-0.1891150.133558-0.021053149.6202020-09-22T20:55:18Z
10.01.1918570.2661510.1664800.4481540.060018-0.082361-0.0788030.085102-0.255425-0.1669741.6127271.0652350.489095-0.1437720.6355580.463917-0.114805-0.183361-0.145783-0.069083-0.225775-0.6386720.101288-0.3398460.1671700.125895-0.0089830.0147242.6902020-09-22T20:55:18Z
21.0-1.358354-1.3401631.7732090.379780-0.5031981.8004990.7914610.247676-1.5146540.2076430.6245010.0660840.717293-0.1659462.345865-2.8900831.109969-0.121359-2.2618570.5249800.2479980.7716790.909412-0.689281-0.327642-0.139097-0.055353-0.059752378.6602020-09-22T20:55:19Z
31.0-0.966272-0.1852261.792993-0.863291-0.0103091.2472030.2376090.377436-1.387024-0.054952-0.2264870.1782280.507757-0.287924-0.631418-1.059647-0.6840931.965775-1.232622-0.208038-0.1083000.005274-0.190321-1.1755750.647376-0.2219290.0627230.061458123.5002020-09-22T20:55:19Z
42.0-1.1582330.8777371.5487180.403034-0.4071930.0959210.592941-0.2705330.8177390.753074-0.8228430.5381961.345852-1.1196700.175121-0.451449-0.237033-0.0381950.8034870.408542-0.0094310.798278-0.1374580.141267-0.2060100.5022920.2194220.21515369.9902020-09-22T20:55:20Z
\n", "
" ], "text/plain": [ " time va vb vc vd ve vf vg vh vi vj vk vl vm vn vo vp vq vr vs vt vu vv vw vx vy vz vaa vab amount EVENT_LABEL EVENT_TIMESTAMP\n", "0 0.0 -1.359807 -0.072781 2.536347 1.378155 -0.338321 0.462388 0.239599 0.098698 0.363787 0.090794 -0.551600 -0.617801 -0.991390 -0.311169 1.468177 -0.470401 0.207971 0.025791 0.403993 0.251412 -0.018307 0.277838 -0.110474 0.066928 0.128539 -0.189115 0.133558 -0.021053 149.62 0 2020-09-22T20:55:18Z\n", "1 0.0 1.191857 0.266151 0.166480 0.448154 0.060018 -0.082361 -0.078803 0.085102 -0.255425 -0.166974 1.612727 1.065235 0.489095 -0.143772 0.635558 0.463917 -0.114805 -0.183361 -0.145783 -0.069083 -0.225775 -0.638672 0.101288 -0.339846 0.167170 0.125895 -0.008983 0.014724 2.69 0 2020-09-22T20:55:18Z\n", "2 1.0 -1.358354 -1.340163 1.773209 0.379780 -0.503198 1.800499 0.791461 0.247676 -1.514654 0.207643 0.624501 0.066084 0.717293 -0.165946 2.345865 -2.890083 1.109969 -0.121359 -2.261857 0.524980 0.247998 0.771679 0.909412 -0.689281 -0.327642 -0.139097 -0.055353 -0.059752 378.66 0 2020-09-22T20:55:19Z\n", "3 1.0 -0.966272 -0.185226 1.792993 -0.863291 -0.010309 1.247203 0.237609 0.377436 -1.387024 -0.054952 -0.226487 0.178228 0.507757 -0.287924 -0.631418 -1.059647 -0.684093 1.965775 -1.232622 -0.208038 -0.108300 0.005274 -0.190321 -1.175575 0.647376 -0.221929 0.062723 0.061458 123.50 0 2020-09-22T20:55:19Z\n", "4 2.0 -1.158233 0.877737 1.548718 0.403034 -0.407193 0.095921 0.592941 -0.270533 0.817739 0.753074 -0.822843 0.538196 1.345852 -1.119670 0.175121 -0.451449 -0.237033 -0.038195 0.803487 0.408542 -0.009431 0.798278 -0.137458 0.141267 -0.206010 0.502292 0.219422 0.215153 69.99 0 2020-09-22T20:55:20Z" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# translate seconds delta to actual datetimes in ISO 8601\n", "def to_datetime(x):\n", " current_ep = start_ep + x\n", " current_dt = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.localtime(current_ep))\n", " return current_dt\n", "\n", "\n", "data['EVENT_TIMESTAMP'] = data['time'].apply(to_datetime)\n", "data.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will split our dataset into a train and test to evaluate the performance of our models. It's important to do so before any techniques meant to alleviate the class imbalance are used. This ensures that we don't leak information from the test set into the train set." ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [], "source": [ "features = data.drop('EVENT_LABEL', axis=1).values\n", "labels = (data['EVENT_LABEL'].values).astype('float32')" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [], "source": [ "X, X_test, y, y_test = train_test_split(\n", " features, labels, test_size=0.1, random_state=42)" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Counter({0.0: 255880, 1.0: 446})\n" ] } ], "source": [ "counter = Counter(y)\n", "print(counter)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Getting the training and testing DataFrame back together" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Index(['time', 'va', 'vb', 'vc', 'vd', 've', 'vf', 'vg', 'vh', 'vi', 'vj', 'vk', 'vl', 'vm', 'vn', 'vo', 'vp', 'vq', 'vr', 'vs', 'vt', 'vu', 'vv', 'vw', 'vx', 'vy', 'vz', 'vaa', 'vab', 'amount'], dtype='object')\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
timevavbvcvdvevfvgvhvivjvkvlvmvnvovpvqvrvsvtvuvvvwvxvyvzvaavabamountEVENT_LABEL
028515.01.2266430.101988-0.0870720.111524-0.281992-1.3560270.469050-0.371725-0.153672-0.145105-0.1435050.3209640.1493130.4525150.7762530.028739-0.177867-1.0047460.2649530.019692-0.355100-1.1536630.1097930.4203180.1979320.699218-0.1148610.00758350.400
183125.01.1248480.1256020.2499620.489744-0.0403860.167561-0.2476140.284736-0.067302-0.1701391.8951170.507733-1.0086480.1872491.0216630.1363200.370186-0.573559-0.625413-0.204465-0.192467-0.5768190.190343-0.3574510.0008700.139971-0.0009930.0115051.980
275537.0-0.3079021.0037151.4042770.5926270.311014-0.3821060.531393-0.015292-0.758638-0.5115970.1496430.2458660.752802-0.3822141.590185-0.3325460.611852-0.5104950.5637790.125220-0.131802-0.3292680.0469900.057413-0.6569600.1931920.1420380.1575011.980
3156358.02.174919-1.535441-0.726428-1.430792-1.517258-0.751038-1.155344-0.180811-1.1118851.536101-0.735705-0.7717140.238603-0.447050-0.085886-0.5683450.591162-0.104975-0.327292-0.334351-0.1127660.0500180.2946661.123322-0.306025-0.2413430.006553-0.02756764.000
4162523.0-2.2215561.2619872.0476424.659268-0.5359414.542044-3.715525-5.311701-0.9553210.200601-1.3426220.8799050.241171-0.365540-1.7354100.5644950.3806481.2166921.8727110.895990-1.8203880.873723-2.648598-0.162180-0.4921110.6014900.6270300.088289379.290
5113992.0-0.3351980.8713780.6327034.1642421.7025821.9543540.3967220.495056-2.5060201.6091371.029249-0.143569-0.1291870.8624281.059507-0.8621440.597711-0.5099670.2176720.2604040.5296351.4735580.033413-1.333266-0.7799610.5951960.2315470.19333257.780
618653.0-1.3059781.7721180.7417300.9123510.4988981.737490-0.957795-1.6923010.755233-0.6414610.900131-0.9353813.0682281.564764-1.357441-0.2161560.7128780.3547010.959930-0.5793861.985454-1.2901090.108807-1.4279370.140905-0.3934440.078297-0.0525051.000
7133445.0-0.3033561.144996-0.843639-1.0466090.945826-1.8227001.694510-0.465604-0.095435-0.150239-1.004530-0.509581-1.0395960.805069-0.077089-0.649795-0.363229-0.307477-0.1636330.0074690.2081480.842970-0.2014900.076193-0.2772750.0933390.4977110.33648017.000
887252.0-0.4659200.6283651.4495694.4173511.0346541.0839050.103565-0.624355-0.2261902.979203-1.319708-1.136836-0.027942-0.9722510.758803-0.104912-0.4627340.5219721.049701-0.0554640.1921561.231734-0.1131150.603061-1.8900370.069854-0.907822-0.13317011.310
940607.00.271095-2.7204890.427427-0.080256-2.0773110.334682-0.6204120.1741670.0874800.3472860.319218-0.528176-1.560458-0.281460-1.1035531.1813540.433565-0.6231771.1654831.0684530.341998-0.188797-0.5044120.0272950.140939-0.294037-0.0638470.102788552.890
\n", "
" ], "text/plain": [ " time va vb vc vd ve vf vg vh vi vj vk vl vm vn vo vp vq vr vs vt vu vv vw vx vy vz vaa vab amount EVENT_LABEL\n", "0 28515.0 1.226643 0.101988 -0.087072 0.111524 -0.281992 -1.356027 0.469050 -0.371725 -0.153672 -0.145105 -0.143505 0.320964 0.149313 0.452515 0.776253 0.028739 -0.177867 -1.004746 0.264953 0.019692 -0.355100 -1.153663 0.109793 0.420318 0.197932 0.699218 -0.114861 0.007583 50.40 0\n", "1 83125.0 1.124848 0.125602 0.249962 0.489744 -0.040386 0.167561 -0.247614 0.284736 -0.067302 -0.170139 1.895117 0.507733 -1.008648 0.187249 1.021663 0.136320 0.370186 -0.573559 -0.625413 -0.204465 -0.192467 -0.576819 0.190343 -0.357451 0.000870 0.139971 -0.000993 0.011505 1.98 0\n", "2 75537.0 -0.307902 1.003715 1.404277 0.592627 0.311014 -0.382106 0.531393 -0.015292 -0.758638 -0.511597 0.149643 0.245866 0.752802 -0.382214 1.590185 -0.332546 0.611852 -0.510495 0.563779 0.125220 -0.131802 -0.329268 0.046990 0.057413 -0.656960 0.193192 0.142038 0.157501 1.98 0\n", "3 156358.0 2.174919 -1.535441 -0.726428 -1.430792 -1.517258 -0.751038 -1.155344 -0.180811 -1.111885 1.536101 -0.735705 -0.771714 0.238603 -0.447050 -0.085886 -0.568345 0.591162 -0.104975 -0.327292 -0.334351 -0.112766 0.050018 0.294666 1.123322 -0.306025 -0.241343 0.006553 -0.027567 64.00 0\n", "4 162523.0 -2.221556 1.261987 2.047642 4.659268 -0.535941 4.542044 -3.715525 -5.311701 -0.955321 0.200601 -1.342622 0.879905 0.241171 -0.365540 -1.735410 0.564495 0.380648 1.216692 1.872711 0.895990 -1.820388 0.873723 -2.648598 -0.162180 -0.492111 0.601490 0.627030 0.088289 379.29 0\n", "5 113992.0 -0.335198 0.871378 0.632703 4.164242 1.702582 1.954354 0.396722 0.495056 -2.506020 1.609137 1.029249 -0.143569 -0.129187 0.862428 1.059507 -0.862144 0.597711 -0.509967 0.217672 0.260404 0.529635 1.473558 0.033413 -1.333266 -0.779961 0.595196 0.231547 0.193332 57.78 0\n", "6 18653.0 -1.305978 1.772118 0.741730 0.912351 0.498898 1.737490 -0.957795 -1.692301 0.755233 -0.641461 0.900131 -0.935381 3.068228 1.564764 -1.357441 -0.216156 0.712878 0.354701 0.959930 -0.579386 1.985454 -1.290109 0.108807 -1.427937 0.140905 -0.393444 0.078297 -0.052505 1.00 0\n", "7 133445.0 -0.303356 1.144996 -0.843639 -1.046609 0.945826 -1.822700 1.694510 -0.465604 -0.095435 -0.150239 -1.004530 -0.509581 -1.039596 0.805069 -0.077089 -0.649795 -0.363229 -0.307477 -0.163633 0.007469 0.208148 0.842970 -0.201490 0.076193 -0.277275 0.093339 0.497711 0.336480 17.00 0\n", "8 87252.0 -0.465920 0.628365 1.449569 4.417351 1.034654 1.083905 0.103565 -0.624355 -0.226190 2.979203 -1.319708 -1.136836 -0.027942 -0.972251 0.758803 -0.104912 -0.462734 0.521972 1.049701 -0.055464 0.192156 1.231734 -0.113115 0.603061 -1.890037 0.069854 -0.907822 -0.133170 11.31 0\n", "9 40607.0 0.271095 -2.720489 0.427427 -0.080256 -2.077311 0.334682 -0.620412 0.174167 0.087480 0.347286 0.319218 -0.528176 -1.560458 -0.281460 -1.103553 1.181354 0.433565 -0.623177 1.165483 1.068453 0.341998 -0.188797 -0.504412 0.027295 0.140939 -0.294037 -0.063847 0.102788 552.89 0" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "saved_cols = data.drop('EVENT_LABEL', axis=1).columns\n", "print(saved_cols)\n", "data = pd.DataFrame(X, columns = saved_cols)\n", "data['EVENT_LABEL']=y.astype(int)\n", "data.head(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Get epoch time for the initial dataset date" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1600808761.483827\n" ] } ], "source": [ "# Get epoch time for the initial dataset date\n", "epoch = datetime.utcfromtimestamp(0)\n", "def unix_time_seconds(dt):\n", " return (dt - epoch).total_seconds()\n", "\n", "# Lets pretend that the data is from yesterday and could can test at the end with todays date.\n", "start_dt = datetime.strptime('Sep 22 2020 12:00AM', '%b %d %Y %I:%M%p')\n", "start_dt = datetime.now()\n", "start_ep = unix_time_seconds(start_dt)\n", "print(start_ep)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The date column is represented as incremental seconds, lets translate it to dates formats." ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
timevavbvcvdvevfvgvhvivjvkvlvmvnvovpvqvrvsvtvuvvvwvxvyvzvaavabamountEVENT_LABELEVENT_TIMESTAMP
028515.01.2266430.101988-0.0870720.111524-0.281992-1.3560270.469050-0.371725-0.153672-0.145105-0.1435050.3209640.1493130.4525150.7762530.028739-0.177867-1.0047460.2649530.019692-0.355100-1.1536630.1097930.4203180.1979320.699218-0.1148610.00758350.4002020-09-23T05:01:16Z
183125.01.1248480.1256020.2499620.489744-0.0403860.167561-0.2476140.284736-0.067302-0.1701391.8951170.507733-1.0086480.1872491.0216630.1363200.370186-0.573559-0.625413-0.204465-0.192467-0.5768190.190343-0.3574510.0008700.139971-0.0009930.0115051.9802020-09-23T20:11:26Z
275537.0-0.3079021.0037151.4042770.5926270.311014-0.3821060.531393-0.015292-0.758638-0.5115970.1496430.2458660.752802-0.3822141.590185-0.3325460.611852-0.5104950.5637790.125220-0.131802-0.3292680.0469900.057413-0.6569600.1931920.1420380.1575011.9802020-09-23T18:04:58Z
3156358.02.174919-1.535441-0.726428-1.430792-1.517258-0.751038-1.155344-0.180811-1.1118851.536101-0.735705-0.7717140.238603-0.447050-0.085886-0.5683450.591162-0.104975-0.327292-0.334351-0.1127660.0500180.2946661.123322-0.306025-0.2413430.006553-0.02756764.0002020-09-24T16:31:59Z
4162523.0-2.2215561.2619872.0476424.659268-0.5359414.542044-3.715525-5.311701-0.9553210.200601-1.3426220.8799050.241171-0.365540-1.7354100.5644950.3806481.2166921.8727110.895990-1.8203880.873723-2.648598-0.162180-0.4921110.6014900.6270300.088289379.2902020-09-24T18:14:44Z
\n", "
" ], "text/plain": [ " time va vb vc vd ve vf vg vh vi vj vk vl vm vn vo vp vq vr vs vt vu vv vw vx vy vz vaa vab amount EVENT_LABEL EVENT_TIMESTAMP\n", "0 28515.0 1.226643 0.101988 -0.087072 0.111524 -0.281992 -1.356027 0.469050 -0.371725 -0.153672 -0.145105 -0.143505 0.320964 0.149313 0.452515 0.776253 0.028739 -0.177867 -1.004746 0.264953 0.019692 -0.355100 -1.153663 0.109793 0.420318 0.197932 0.699218 -0.114861 0.007583 50.40 0 2020-09-23T05:01:16Z\n", "1 83125.0 1.124848 0.125602 0.249962 0.489744 -0.040386 0.167561 -0.247614 0.284736 -0.067302 -0.170139 1.895117 0.507733 -1.008648 0.187249 1.021663 0.136320 0.370186 -0.573559 -0.625413 -0.204465 -0.192467 -0.576819 0.190343 -0.357451 0.000870 0.139971 -0.000993 0.011505 1.98 0 2020-09-23T20:11:26Z\n", "2 75537.0 -0.307902 1.003715 1.404277 0.592627 0.311014 -0.382106 0.531393 -0.015292 -0.758638 -0.511597 0.149643 0.245866 0.752802 -0.382214 1.590185 -0.332546 0.611852 -0.510495 0.563779 0.125220 -0.131802 -0.329268 0.046990 0.057413 -0.656960 0.193192 0.142038 0.157501 1.98 0 2020-09-23T18:04:58Z\n", "3 156358.0 2.174919 -1.535441 -0.726428 -1.430792 -1.517258 -0.751038 -1.155344 -0.180811 -1.111885 1.536101 -0.735705 -0.771714 0.238603 -0.447050 -0.085886 -0.568345 0.591162 -0.104975 -0.327292 -0.334351 -0.112766 0.050018 0.294666 1.123322 -0.306025 -0.241343 0.006553 -0.027567 64.00 0 2020-09-24T16:31:59Z\n", "4 162523.0 -2.221556 1.261987 2.047642 4.659268 -0.535941 4.542044 -3.715525 -5.311701 -0.955321 0.200601 -1.342622 0.879905 0.241171 -0.365540 -1.735410 0.564495 0.380648 1.216692 1.872711 0.895990 -1.820388 0.873723 -2.648598 -0.162180 -0.492111 0.601490 0.627030 0.088289 379.29 0 2020-09-24T18:14:44Z" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# translate seconds delta to actual datetimes in ISO 8601\n", "def to_datetime(x):\n", " current_ep = start_ep + x\n", " current_dt = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.localtime(current_ep))\n", " return current_dt\n", "\n", "\n", "data['EVENT_TIMESTAMP'] = data['time'].apply(to_datetime)\n", "data.head()" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
timevavbvcvdvevfvgvhvivjvkvlvmvnvovpvqvrvsvtvuvvvwvxvyvzvaavabamount
041505.0-16.5265078.584972-18.6498539.505594-13.793819-2.832404-16.7016947.517344-8.507059-14.1101845.299236-10.8340061.671120-9.3738590.360806-9.899247-19.236292-8.3985523.101735-1.5149231.190739-1.127670-2.3585790.673461-1.413700-0.462762-2.018575-1.042804364.19
144261.00.339812-2.743745-0.134070-1.385729-1.4514131.015887-0.5243790.2240600.899746-0.565012-0.0876700.9794270.076883-0.217884-0.136830-2.1428920.1269561.7526620.4325460.506044-0.213436-0.942525-0.526819-1.1569920.311211-0.7466470.0409960.102038520.12
235484.01.399590-0.5907010.168619-1.029950-0.5398060.040444-0.7125670.002299-0.9717470.7568010.5438270.1124531.075384-0.2457720.1804831.769860-0.533172-0.5333001.1922450.2128770.1023980.168269-0.166639-0.8102500.505083-0.2323400.0114090.00463431.00
3167123.0-0.4320711.647895-1.669361-0.3495040.785785-0.6306470.2769900.586025-0.484715-1.376648-1.3283350.2236211.132627-0.5508750.6165680.4979740.5021950.9813430.101264-0.2446330.3589320.873663-0.178642-0.017171-0.207392-0.157756-0.2373860.0019341.50
4168473.02.014160-0.137394-1.0158390.327269-0.182179-0.9565710.043241-0.1607460.3632410.2594520.9421620.850038-0.6161660.592634-0.6038450.091077-0.471867-0.3338160.404711-0.255293-0.238644-0.6164000.3470450.061561-0.3601960.174730-0.078043-0.0705710.89
567878.0-0.641330-0.0573041.489998-1.688131-1.1510430.259996-1.391069-2.3340751.168644-2.0840800.4803810.473738-2.1922760.7739420.2944840.406074-0.5418551.0314500.0170760.618411-1.2316340.257164-0.371953-0.0385661.397514-0.6659470.0310030.180357100.00
6159763.02.023952-0.120140-1.0869180.423019-0.142901-1.1277520.178493-0.3032340.5645090.062831-0.7200470.366835-0.1108570.3190940.108359-0.153633-0.221312-0.9341410.070553-0.210864-0.276175-0.6977080.335631-0.017196-0.3249040.200023-0.071566-0.05822416.99
7139631.0-0.6889441.292153-0.564281-1.4575262.258333-0.3232701.678984-0.104128-1.285351-1.3034350.282728-0.402525-0.548687-0.504283-0.6853390.714828-0.0926740.798953-0.150085-0.037150-0.006880-0.171568-0.720019-0.4194351.2119910.670916-0.1039860.0300848.95
8133944.02.1193620.142639-2.3733370.5419490.608419-1.7755640.955775-0.5993830.0104200.295305-0.936569-0.452478-1.3407981.077459-0.099584-0.8150720.018481-0.639446-0.065427-0.3235730.2642640.898266-0.1680630.0593110.6269490.729035-0.129120-0.09471310.00
958769.0-5.584256-4.732413-0.448452-0.121442-0.707412-0.114376-1.5546281.402126-0.031693-0.942358-2.439501-0.552312-0.295588-0.250246-1.1977321.5495530.933237-1.2376890.416832-1.0469000.0416510.6217890.223467-0.7701370.621182-0.0287380.505194-1.898323101.49
\n", "
" ], "text/plain": [ " time va vb vc vd ve vf vg vh vi vj vk vl vm vn vo vp vq vr vs vt vu vv vw vx vy vz vaa vab amount\n", "0 41505.0 -16.526507 8.584972 -18.649853 9.505594 -13.793819 -2.832404 -16.701694 7.517344 -8.507059 -14.110184 5.299236 -10.834006 1.671120 -9.373859 0.360806 -9.899247 -19.236292 -8.398552 3.101735 -1.514923 1.190739 -1.127670 -2.358579 0.673461 -1.413700 -0.462762 -2.018575 -1.042804 364.19\n", "1 44261.0 0.339812 -2.743745 -0.134070 -1.385729 -1.451413 1.015887 -0.524379 0.224060 0.899746 -0.565012 -0.087670 0.979427 0.076883 -0.217884 -0.136830 -2.142892 0.126956 1.752662 0.432546 0.506044 -0.213436 -0.942525 -0.526819 -1.156992 0.311211 -0.746647 0.040996 0.102038 520.12\n", "2 35484.0 1.399590 -0.590701 0.168619 -1.029950 -0.539806 0.040444 -0.712567 0.002299 -0.971747 0.756801 0.543827 0.112453 1.075384 -0.245772 0.180483 1.769860 -0.533172 -0.533300 1.192245 0.212877 0.102398 0.168269 -0.166639 -0.810250 0.505083 -0.232340 0.011409 0.004634 31.00\n", "3 167123.0 -0.432071 1.647895 -1.669361 -0.349504 0.785785 -0.630647 0.276990 0.586025 -0.484715 -1.376648 -1.328335 0.223621 1.132627 -0.550875 0.616568 0.497974 0.502195 0.981343 0.101264 -0.244633 0.358932 0.873663 -0.178642 -0.017171 -0.207392 -0.157756 -0.237386 0.001934 1.50\n", "4 168473.0 2.014160 -0.137394 -1.015839 0.327269 -0.182179 -0.956571 0.043241 -0.160746 0.363241 0.259452 0.942162 0.850038 -0.616166 0.592634 -0.603845 0.091077 -0.471867 -0.333816 0.404711 -0.255293 -0.238644 -0.616400 0.347045 0.061561 -0.360196 0.174730 -0.078043 -0.070571 0.89\n", "5 67878.0 -0.641330 -0.057304 1.489998 -1.688131 -1.151043 0.259996 -1.391069 -2.334075 1.168644 -2.084080 0.480381 0.473738 -2.192276 0.773942 0.294484 0.406074 -0.541855 1.031450 0.017076 0.618411 -1.231634 0.257164 -0.371953 -0.038566 1.397514 -0.665947 0.031003 0.180357 100.00\n", "6 159763.0 2.023952 -0.120140 -1.086918 0.423019 -0.142901 -1.127752 0.178493 -0.303234 0.564509 0.062831 -0.720047 0.366835 -0.110857 0.319094 0.108359 -0.153633 -0.221312 -0.934141 0.070553 -0.210864 -0.276175 -0.697708 0.335631 -0.017196 -0.324904 0.200023 -0.071566 -0.058224 16.99\n", "7 139631.0 -0.688944 1.292153 -0.564281 -1.457526 2.258333 -0.323270 1.678984 -0.104128 -1.285351 -1.303435 0.282728 -0.402525 -0.548687 -0.504283 -0.685339 0.714828 -0.092674 0.798953 -0.150085 -0.037150 -0.006880 -0.171568 -0.720019 -0.419435 1.211991 0.670916 -0.103986 0.030084 8.95\n", "8 133944.0 2.119362 0.142639 -2.373337 0.541949 0.608419 -1.775564 0.955775 -0.599383 0.010420 0.295305 -0.936569 -0.452478 -1.340798 1.077459 -0.099584 -0.815072 0.018481 -0.639446 -0.065427 -0.323573 0.264264 0.898266 -0.168063 0.059311 0.626949 0.729035 -0.129120 -0.094713 10.00\n", "9 58769.0 -5.584256 -4.732413 -0.448452 -0.121442 -0.707412 -0.114376 -1.554628 1.402126 -0.031693 -0.942358 -2.439501 -0.552312 -0.295588 -0.250246 -1.197732 1.549553 0.933237 -1.237689 0.416832 -1.046900 0.041651 0.621789 0.223467 -0.770137 0.621182 -0.028738 0.505194 -1.898323 101.49" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "test = pd.DataFrame(X_test, columns = saved_cols)\n", "test.head(10)" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
timevavbvcvdvevfvgvhvivjvkvlvmvnvovpvqvrvsvtvuvvvwvxvyvzvaavabamountEVENT_LABEL
041505.0-16.5265078.584972-18.6498539.505594-13.793819-2.832404-16.7016947.517344-8.507059-14.1101845.299236-10.8340061.671120-9.3738590.360806-9.899247-19.236292-8.3985523.101735-1.5149231.190739-1.127670-2.3585790.673461-1.413700-0.462762-2.018575-1.042804364.191
144261.00.339812-2.743745-0.134070-1.385729-1.4514131.015887-0.5243790.2240600.899746-0.565012-0.0876700.9794270.076883-0.217884-0.136830-2.1428920.1269561.7526620.4325460.506044-0.213436-0.942525-0.526819-1.1569920.311211-0.7466470.0409960.102038520.120
235484.01.399590-0.5907010.168619-1.029950-0.5398060.040444-0.7125670.002299-0.9717470.7568010.5438270.1124531.075384-0.2457720.1804831.769860-0.533172-0.5333001.1922450.2128770.1023980.168269-0.166639-0.8102500.505083-0.2323400.0114090.00463431.000
3167123.0-0.4320711.647895-1.669361-0.3495040.785785-0.6306470.2769900.586025-0.484715-1.376648-1.3283350.2236211.132627-0.5508750.6165680.4979740.5021950.9813430.101264-0.2446330.3589320.873663-0.178642-0.017171-0.207392-0.157756-0.2373860.0019341.500
4168473.02.014160-0.137394-1.0158390.327269-0.182179-0.9565710.043241-0.1607460.3632410.2594520.9421620.850038-0.6161660.592634-0.6038450.091077-0.471867-0.3338160.404711-0.255293-0.238644-0.6164000.3470450.061561-0.3601960.174730-0.078043-0.0705710.890
\n", "
" ], "text/plain": [ " time va vb vc vd ve vf vg vh vi vj vk vl vm vn vo vp vq vr vs vt vu vv vw vx vy vz vaa vab amount EVENT_LABEL\n", "0 41505.0 -16.526507 8.584972 -18.649853 9.505594 -13.793819 -2.832404 -16.701694 7.517344 -8.507059 -14.110184 5.299236 -10.834006 1.671120 -9.373859 0.360806 -9.899247 -19.236292 -8.398552 3.101735 -1.514923 1.190739 -1.127670 -2.358579 0.673461 -1.413700 -0.462762 -2.018575 -1.042804 364.19 1\n", "1 44261.0 0.339812 -2.743745 -0.134070 -1.385729 -1.451413 1.015887 -0.524379 0.224060 0.899746 -0.565012 -0.087670 0.979427 0.076883 -0.217884 -0.136830 -2.142892 0.126956 1.752662 0.432546 0.506044 -0.213436 -0.942525 -0.526819 -1.156992 0.311211 -0.746647 0.040996 0.102038 520.12 0\n", "2 35484.0 1.399590 -0.590701 0.168619 -1.029950 -0.539806 0.040444 -0.712567 0.002299 -0.971747 0.756801 0.543827 0.112453 1.075384 -0.245772 0.180483 1.769860 -0.533172 -0.533300 1.192245 0.212877 0.102398 0.168269 -0.166639 -0.810250 0.505083 -0.232340 0.011409 0.004634 31.00 0\n", "3 167123.0 -0.432071 1.647895 -1.669361 -0.349504 0.785785 -0.630647 0.276990 0.586025 -0.484715 -1.376648 -1.328335 0.223621 1.132627 -0.550875 0.616568 0.497974 0.502195 0.981343 0.101264 -0.244633 0.358932 0.873663 -0.178642 -0.017171 -0.207392 -0.157756 -0.237386 0.001934 1.50 0\n", "4 168473.0 2.014160 -0.137394 -1.015839 0.327269 -0.182179 -0.956571 0.043241 -0.160746 0.363241 0.259452 0.942162 0.850038 -0.616166 0.592634 -0.603845 0.091077 -0.471867 -0.333816 0.404711 -0.255293 -0.238644 -0.616400 0.347045 0.061561 -0.360196 0.174730 -0.078043 -0.070571 0.89 0" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# The testing dataset with the labels to perform evaluations latter on\n", "test_label = pd.DataFrame(X_test, columns = saved_cols)\n", "test_label['EVENT_LABEL']=y_test.astype(int)\n", "test_label.head()" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of frauds in test data: 46\n", "Number of non-frauds in test data: 28435\n", "Percentage of fradulent data: 0.16151118289385907\n" ] } ], "source": [ "#validating the test dataset with labels\n", "nonfrauds, frauds = test_label.groupby('EVENT_LABEL').size()\n", "print('Number of frauds in test data: ', frauds)\n", "print('Number of non-frauds in test data: ', nonfrauds)\n", "print('Percentage of fradulent data:', 100.*frauds/(frauds + nonfrauds))" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of frauds: 446\n", "Number of non-frauds: 255880\n", "Percentage of fradulent data: 0.17399717547186005\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "#validating the training dataset\n", "nonfrauds, frauds = data.groupby('EVENT_LABEL').size()\n", "print('Number of frauds: ', frauds)\n", "print('Number of non-frauds: ', nonfrauds)\n", "print('Percentage of fradulent data:', 100.*frauds/(frauds + nonfrauds))\n", "\n", "count_class_0, count_class_1 = data.EVENT_LABEL.value_counts()\n", "data.EVENT_LABEL.value_counts().plot(kind='bar', title='Count (EVENT_LABEL)');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Uploading the data for training" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'ResponseMetadata': {'RequestId': 'AX5P2P5W6K2Y7V2W',\n", " 'HostId': 'dAdIFZFsxxw5ufQqVlMhLaO1zn5bPeuI2w7ua3cqHKYcg8DcZ27gyL3OMuFDaOifAfwszauk39g=',\n", " 'HTTPStatusCode': 200,\n", " 'HTTPHeaders': {'x-amz-id-2': 'dAdIFZFsxxw5ufQqVlMhLaO1zn5bPeuI2w7ua3cqHKYcg8DcZ27gyL3OMuFDaOifAfwszauk39g=',\n", " 'x-amz-request-id': 'AX5P2P5W6K2Y7V2W',\n", " 'date': 'Tue, 22 Sep 2020 21:06:38 GMT',\n", " 'x-amz-server-side-encryption': 'AES256',\n", " 'etag': '\"8baed18fc24e97ddcba8e6ff15de1f93\"',\n", " 'content-length': '0',\n", " 'server': 'AmazonS3'},\n", " 'RetryAttempts': 0},\n", " 'ETag': '\"8baed18fc24e97ddcba8e6ff15de1f93\"',\n", " 'ServerSideEncryption': 'AES256'}" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "csv_buffer = StringIO()\n", "data.to_csv(csv_buffer, index=False)\n", "s3_resource.Object(S3_BUCKET, 'dataset-training.csv').put(Body=csv_buffer.getvalue())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Uploading the data for testing" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'ResponseMetadata': {'RequestId': 'B6E8DEF11A9A2C22',\n", " 'HostId': 'jqD7xx2/tpv2PnFnhAiHXMRTaF7JDGex1nnP2GYXLFK/O19KkDONmxejes76LkFQtZE9mnbGlZU=',\n", " 'HTTPStatusCode': 200,\n", " 'HTTPHeaders': {'x-amz-id-2': 'jqD7xx2/tpv2PnFnhAiHXMRTaF7JDGex1nnP2GYXLFK/O19KkDONmxejes76LkFQtZE9mnbGlZU=',\n", " 'x-amz-request-id': 'B6E8DEF11A9A2C22',\n", " 'date': 'Tue, 22 Sep 2020 21:06:43 GMT',\n", " 'x-amz-server-side-encryption': 'AES256',\n", " 'etag': '\"4338feb9a18c65c7c0c98c68c5c935e6\"',\n", " 'content-length': '0',\n", " 'server': 'AmazonS3'},\n", " 'RetryAttempts': 0},\n", " 'ETag': '\"4338feb9a18c65c7c0c98c68c5c935e6\"',\n", " 'ServerSideEncryption': 'AES256'}" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "csv_buffer = StringIO()\n", "test.to_csv(csv_buffer, index=False)\n", "\n", "s3_resource.Object(S3_BUCKET, 'dataset-test.csv').put(Body=csv_buffer.getvalue())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once we have the datasets ready we need create the necesary entities for build and deploy the fraud detection model. This can be done within the Amazon Fraud Detector console or through the API as shown in the second jupyter notebook." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we are going to traing and deploy the SageMaker version of the model." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First we copy the data to an in-memory buffer." ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [], "source": [ "buf = io.BytesIO()\n", "\n", "sklearn.datasets.dump_svmlight_file(X, y, buf)\n", "buf.seek(0);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we upload the data to S3 using boto3." ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Uploaded training data location: s3://afd-poc-trainingbucket-1i37svk9elcoe/sagemaker-dataset-training\n", "Training artifacts will be uploaded to: s3://afd-poc-outputbucket-1fhn20d7tumgg\n" ] } ], "source": [ "key = 'sagemaker-dataset-training'\n", "boto3.resource('s3').Bucket(S3_BUCKET).Object(key).upload_fileobj(buf)\n", "\n", "s3_train_data = 's3://{}/{}'.format(S3_BUCKET, key)\n", "print('Uploaded training data location: {}'.format(s3_train_data))\n", "\n", "output_location = 's3://{}'.format(S3_OUT_BUCKET)\n", "print('Training artifacts will be uploaded to: {}'.format(output_location))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now train using SageMaker's built-in XGBoost algorithm. To specify the XGBoost algorithm, we use a utility function to obtain its URI. A complete list of built-in algorithms is found here: https://docs.aws.amazon.com/sagemaker/latest/dg/algos.html" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "'get_image_uri' method will be deprecated in favor of 'ImageURIProvider' class in SageMaker Python SDK v2.\n" ] } ], "source": [ "container = get_image_uri(boto3.Session().region_name, 'xgboost', repo_version='1.0-1')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "SageMaker abstracts training via Estimators. We can pass the classifier and parameters along with hyperparameters to the estimator, and fit the estimator to the data in S3. An important parameter here is scale_pos_weight which scales the weights of the positive vs. negative class examples. This is crucial to do in an imbalanced dataset like the one we are using here, otherwise the majority class would dominate the learning." ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Parameter image_name will be renamed to image_uri in SageMaker Python SDK v2.\n", "'s3_input' class will be renamed to 'TrainingInput' in SageMaker Python SDK v2.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2020-09-22 21:27:11 Starting - Starting the training job...\n", "2020-09-22 21:27:14 Starting - Launching requested ML instances......\n", "2020-09-22 21:28:42 Starting - Preparing the instances for training............\n", "2020-09-22 21:30:25 Downloading - Downloading input data...\n", "2020-09-22 21:30:46 Training - Downloading the training image..\u001b[34mINFO:sagemaker-containers:Imported framework sagemaker_xgboost_container.training\u001b[0m\n", "\u001b[34mINFO:sagemaker-containers:Failed to parse hyperparameter eval_metric value auc to Json.\u001b[0m\n", "\u001b[34mReturning the value itself\u001b[0m\n", "\u001b[34mINFO:sagemaker-containers:Failed to parse hyperparameter objective value binary:logistic to Json.\u001b[0m\n", "\u001b[34mReturning the value itself\u001b[0m\n", "\u001b[34mINFO:sagemaker-containers:No GPUs detected (normal if no gpus installed)\u001b[0m\n", "\u001b[34mINFO:sagemaker_xgboost_container.training:Running XGBoost Sagemaker in algorithm mode\u001b[0m\n", "\u001b[34m[21:31:19] 256326x30 matrix with 7688153 entries loaded from /opt/ml/input/data/train\u001b[0m\n", "\u001b[34mINFO:root:Single node training.\u001b[0m\n", "\u001b[34mINFO:root:Train matrix has 256326 rows\u001b[0m\n", "\u001b[34m[0]#011train-auc:0.94930\u001b[0m\n", "\u001b[34m[1]#011train-auc:0.97015\u001b[0m\n", "\u001b[34m[2]#011train-auc:0.97634\u001b[0m\n", "\u001b[34m[3]#011train-auc:0.97924\u001b[0m\n", "\u001b[34m[4]#011train-auc:0.97912\u001b[0m\n", "\u001b[34m[5]#011train-auc:0.98223\u001b[0m\n", "\u001b[34m[6]#011train-auc:0.98227\u001b[0m\n", "\u001b[34m[7]#011train-auc:0.98236\u001b[0m\n", "\u001b[34m[8]#011train-auc:0.98251\u001b[0m\n", "\u001b[34m[9]#011train-auc:0.98409\u001b[0m\n", "\u001b[34m[10]#011train-auc:0.98539\u001b[0m\n", "\u001b[34m[11]#011train-auc:0.98637\u001b[0m\n", "\u001b[34m[12]#011train-auc:0.99252\u001b[0m\n", "\u001b[34m[13]#011train-auc:0.99264\u001b[0m\n", "\u001b[34m[14]#011train-auc:0.99328\u001b[0m\n", "\u001b[34m[15]#011train-auc:0.99423\u001b[0m\n", "\u001b[34m[16]#011train-auc:0.99657\u001b[0m\n", "\u001b[34m[17]#011train-auc:0.99722\u001b[0m\n", "\u001b[34m[18]#011train-auc:0.99788\u001b[0m\n", "\n", "2020-09-22 21:31:16 Training - Training image download completed. Training in progress.\u001b[34m[19]#011train-auc:0.99883\u001b[0m\n", "\u001b[34m[20]#011train-auc:0.99899\u001b[0m\n", "\u001b[34m[21]#011train-auc:0.99914\u001b[0m\n", "\u001b[34m[22]#011train-auc:0.99910\u001b[0m\n", "\u001b[34m[23]#011train-auc:0.99972\u001b[0m\n", "\u001b[34m[24]#011train-auc:0.99973\u001b[0m\n", "\u001b[34m[25]#011train-auc:0.99984\u001b[0m\n", "\u001b[34m[26]#011train-auc:0.99989\u001b[0m\n", "\u001b[34m[27]#011train-auc:0.99989\u001b[0m\n", "\u001b[34m[28]#011train-auc:0.99990\u001b[0m\n", "\u001b[34m[29]#011train-auc:0.99991\u001b[0m\n", "\u001b[34m[30]#011train-auc:0.99993\u001b[0m\n", "\u001b[34m[31]#011train-auc:0.99994\u001b[0m\n", "\u001b[34m[32]#011train-auc:0.99995\u001b[0m\n", "\u001b[34m[33]#011train-auc:0.99995\u001b[0m\n", "\u001b[34m[34]#011train-auc:0.99996\u001b[0m\n", "\u001b[34m[35]#011train-auc:0.99996\u001b[0m\n", "\u001b[34m[36]#011train-auc:0.99996\u001b[0m\n", "\u001b[34m[37]#011train-auc:0.99996\u001b[0m\n", "\u001b[34m[38]#011train-auc:0.99996\u001b[0m\n", "\u001b[34m[39]#011train-auc:0.99996\u001b[0m\n", "\u001b[34m[40]#011train-auc:0.99997\u001b[0m\n", "\u001b[34m[41]#011train-auc:0.99997\u001b[0m\n", "\u001b[34m[42]#011train-auc:0.99997\u001b[0m\n", "\u001b[34m[43]#011train-auc:0.99997\u001b[0m\n", "\u001b[34m[44]#011train-auc:0.99997\u001b[0m\n", "\u001b[34m[45]#011train-auc:0.99998\u001b[0m\n", "\u001b[34m[46]#011train-auc:0.99998\u001b[0m\n", "\u001b[34m[47]#011train-auc:0.99998\u001b[0m\n", "\u001b[34m[48]#011train-auc:0.99998\u001b[0m\n", "\u001b[34m[49]#011train-auc:0.99998\u001b[0m\n", "\u001b[34m[50]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[51]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[52]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[53]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[54]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[55]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[56]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[57]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[58]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[59]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[60]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[61]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[62]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[63]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[64]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[65]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[66]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[67]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[68]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[69]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[70]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[71]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[72]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[73]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[74]#011train-auc:0.99999\u001b[0m\n", "\u001b[34m[75]#011train-auc:0.99999\u001b[0m\n", "\n", "2020-09-22 21:32:14 Uploading - Uploading generated training model\u001b[34m[76]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[77]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[78]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[79]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[80]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[81]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[82]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[83]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[84]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[85]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[86]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[87]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[88]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[89]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[90]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[91]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[92]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[93]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[94]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[95]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[96]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[97]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[98]#011train-auc:1.00000\u001b[0m\n", "\u001b[34m[99]#011train-auc:1.00000\u001b[0m\n", "\n", "2020-09-22 21:32:23 Completed - Training job completed\n", "Training seconds: 118\n", "Billable seconds: 118\n" ] } ], "source": [ "# Because the data set is so highly skewed, we set the scale position weight conservatively,\n", "# as sqrt(num_nonfraud/num_fraud).\n", "# Other recommendations for the scale_pos_weight are setting it to (num_nonfraud/num_fraud).\n", "session = sagemaker.Session()\n", "\n", "scale_pos_weight = sqrt(np.count_nonzero(y==0)/np.count_nonzero(y))\n", "hyperparams = {\n", " \"max_depth\":5,\n", " \"subsample\":0.8,\n", " \"num_round\":100,\n", " \"eta\":0.2,\n", " \"gamma\":4,\n", " \"min_child_weight\":6,\n", " \"silent\":0,\n", " \"objective\":'binary:logistic',\n", " \"eval_metric\":'auc',\n", " \"scale_pos_weight\": scale_pos_weight\n", "}\n", "\n", "clf = sagemaker.estimator.Estimator(container,\n", " get_execution_role(),\n", " hyperparameters=hyperparams,\n", " train_instance_count=1, \n", " train_instance_type='ml.m4.xlarge',\n", " output_path=output_location,\n", " sagemaker_session=session)\n", "clf.fit({'train': s3_train_data})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we deploy the estimator to and endpoint." ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Parameter image will be renamed to image_uri in SageMaker Python SDK v2.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "---------------!" ] } ], "source": [ "predictor = clf.deploy(initial_instance_count=1,\n", " endpoint_name=\"fraud-detection-endpoint\",\n", " instance_type='ml.m4.xlarge', \n", " serializer=csv_serializer,\n", " deserializer=None,\n", " content_type='text/csv')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once we have trained the model we can use it to make predictions for the test set." ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [], "source": [ "# Because we have a large test set, we call predict on smaller batches\n", "def predict(current_predictor, data, rows=500):\n", " split_array = np.array_split(data, int(data.shape[0] / float(rows) + 1))\n", " predictions = ''\n", " for array in split_array:\n", " predictions = ','.join([predictions, current_predictor.predict(array).decode('utf-8')])\n", "\n", " return np.fromstring(predictions[1:], sep=',')" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [], "source": [ "raw_preds = predict(predictor, X_test)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will use a few measures from the scikit-learn package to evaluate the performance of our model. When dealing with an imbalanced dataset, we need to choose metrics that take into account the frequency of each class in the data.\n", "Two such metrics are the balanced accuracy score, and Cohen's Kappa." ] }, { "cell_type": "code", "execution_count": 201, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Balanced accuracy = 0.9021211611532022\n" ] } ], "source": [ "# sagamaker model balanced accuracy for 0.5 threshold\n", "y_preds = np.where(raw_preds > 0.5, 1, 0)\n", "print(\"Balanced accuracy = {}\".format(balanced_accuracy_score(y_test, y_preds)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can already see that our model performs very well in terms of both metrics, Cohen's Kappa scores above 0.8 are generally very favorable.\n", "Apart from single-value metrics, it's also useful to look at metrics that indicate performance per class. A confusion matrix, and per-class precision, recall and f1-score can also provide more information about the model's performance." ] }, { "cell_type": "code", "execution_count": 202, "metadata": {}, "outputs": [], "source": [ "def plot_confusion_matrix(y_true, y_predicted):\n", " cm = confusion_matrix(y_true, y_predicted)\n", " # Get the per-class normalized value for each cell\n", " cm_norm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n", " # We color each cell according to its normalized value, annotate with exact counts.\n", " ax = sns.heatmap(cm_norm, annot=cm, fmt=\"d\")\n", " ax.set(xticklabels=[\"non-fraud\", \"fraud\"], yticklabels=[\"non-fraud\", \"fraud\"])\n", " ax.set_ylim([0,2])\n", " plt.title('Confusion Matrix')\n", " plt.ylabel('Real Classes')\n", " plt.xlabel('Predicted Classes')\n", " plt.show()" ] }, { "cell_type": "code", "execution_count": 203, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plot_confusion_matrix(y_test, y_preds)" ] }, { "cell_type": "code", "execution_count": 204, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " non-fraud 1.00 1.00 1.00 28435\n", " fraud 0.93 0.80 0.86 46\n", "\n", " accuracy 1.00 28481\n", " macro avg 0.96 0.90 0.93 28481\n", "weighted avg 1.00 1.00 1.00 28481\n", "\n" ] } ], "source": [ "print(classification_report(\n", " y_test, y_preds, target_names=['non-fraud', 'fraud']))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that we have the sagemaker model, lets build the Amazon Fraud Detector one" ] }, { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [], "source": [ "# -- This is all you need to fill out. Once complete simply interactively run each code cell. -- \n", "# your_entity_name\n", "ENTITY_TYPE = \"creditcardtrans{0}\".format(sufx) \n", "ENTITY_DESC = \"creditcard transactions: {0}\".format(sufx) \n", "# your_event_type\n", "EVENT_TYPE = \"creditcard{0}\".format(sufx) \n", "EVENT_DESC = \"creditcard card payment events: {0}\".format(sufx) \n", "# your_model_name\n", "MODEL_NAME = \"fraud_detector_model{0}\".format(sufx) \n", "MODEL_DESC = \"model trained on: {0}\".format(sufx) \n", "# your_detector_name\n", "DETECTOR_NAME = \"fraud_detector_endpoint{0}\".format(sufx) \n", "DETECTOR_DESC = \"detects synthetic fraud events created: {0}\".format(sufx) " ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "--- summary stats ---\n", " feature_name dtype count nunique null not_null null_pct nunique_pct feature_type feature_warning\n", "0 time float64 256326 119735 0 256326 0.0 0.4671 NUMERIC NO WARNING\n", "1 va float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "2 vb float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "3 vc float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "4 vd float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "5 ve float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "6 vf float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "7 vg float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "8 vh float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "9 vi float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "10 vj float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "11 vk float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "12 vl float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "13 vm float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "14 vn float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "15 vo float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "16 vp float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "17 vq float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "18 vr float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "19 vs float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "20 vt float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "21 vu float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "22 vv float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "23 vw float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "24 vx float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "25 vy float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "26 vz float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "27 vaa float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "28 vab float64 256326 248553 0 256326 0.0 0.9697 NUMERIC NO WARNING\n", "29 amount float64 256326 31154 0 256326 0.0 0.1215 PRICE NO WARNING\n", "30 EVENT_LABEL int64 256326 2 0 256326 0.0 0.0000 TARGET NO WARNING\n", "31 EVENT_TIMESTAMP object 256326 119735 0 256326 0.0 0.4671 EVENT_TIMESTAMP NO WARNING\n", "\n", "\n", "--- event variables ---\n", "['time', 'va', 'vb', 'vc', 'vd', 've', 'vf', 'vg', 'vh', 'vi', 'vj', 'vk', 'vl', 'vm', 'vn', 'vo', 'vp', 'vq', 'vr', 'vs', 'vt', 'vu', 'vv', 'vw', 'vx', 'vy', 'vz', 'vaa', 'vab', 'amount']\n", "\n", "\n", "--- event labels ---\n", "[0, 1]\n", "\n", "\n", "--- training data schema ---\n", "{'modelVariables': ['time', 'va', 'vb', 'vc', 'vd', 've', 'vf', 'vg', 'vh', 'vi', 'vj', 'vk', 'vl', 'vm', 'vn', 'vo', 'vp', 'vq', 'vr', 'vs', 'vt', 'vu', 'vv', 'vw', 'vx', 'vy', 'vz', 'vaa', 'vab'], 'labelSchema': {'labelMapper': {'FRAUD': ['1'], 'LEGIT': ['0']}}}\n", "\n", "\n" ] } ], "source": [ "# Dataset profiling, just run this code block\n", "def summary_stats(df):\n", " \"\"\" Generate summary statistics for a panda's data frame \n", " Args:\n", " df (DataFrame): panda's dataframe to create summary statistics for.\n", " Returns:\n", " DataFrame of summary statistics, training data schema, event variables and event lables \n", " \"\"\"\n", " df = df.copy()\n", " rowcnt = len(df)\n", " df_s1 = df.agg(['count', 'nunique']).transpose().reset_index().rename(columns={\"index\":\"feature_name\"})\n", " df_s1[\"null\"] = (rowcnt - df_s1[\"count\"]).astype('int64')\n", " df_s1[\"not_null\"] = rowcnt - df_s1[\"null\"]\n", " df_s1[\"null_pct\"] = df_s1[\"null\"] / rowcnt\n", " df_s1[\"nunique_pct\"] = df_s1['nunique']/ rowcnt\n", " dt = pd.DataFrame(df.dtypes).reset_index().rename(columns={\"index\":\"feature_name\", 0:\"dtype\"})\n", " df_stats = pd.merge(dt, df_s1, on='feature_name', how='inner').round(4)\n", " df_stats['nunique'] = df_stats['nunique'].astype('int64')\n", " df_stats['count'] = df_stats['count'].astype('int64')\n", " \n", " # -- variable type mapper -- \n", " df_stats['feature_type'] = \"UNKOWN\"\n", " df_stats.loc[df_stats[\"dtype\"] == object, 'feature_type'] = \"CATEGORY\"\n", " df_stats.loc[(df_stats[\"dtype\"] == \"int64\") | (df_stats[\"dtype\"] == \"float64\"), 'feature_type'] = \"NUMERIC\"\n", " df_stats.loc[df_stats[\"feature_name\"].str.contains(\"ipaddress|ip_address|ipcli\"), 'feature_type'] = \"IP_ADDRESS\"\n", " df_stats.loc[df_stats[\"feature_name\"].str.contains(\"email|email_address|emailaddr\"), 'feature_type'] = \"EMAIL_ADDRESS\"\n", " df_stats.loc[df_stats[\"feature_name\"].str.contains(\"canal|channel\"), 'feature_type'] = \"USERAGENT\"\n", " df_stats.loc[df_stats[\"feature_name\"].str.contains(\"monto|amount\"), 'feature_type'] = \"PRICE\"\n", " df_stats.loc[df_stats[\"feature_name\"].str.contains(\"nomdes|name\"), 'feature_type'] = \"BILLING_NAME\"\n", " df_stats.loc[df_stats[\"feature_name\"] == \"EVENT_LABEL\", 'feature_type'] = \"TARGET\"\n", " df_stats.loc[df_stats[\"feature_name\"] == \"EVENT_TIMESTAMP\", 'feature_type'] = \"EVENT_TIMESTAMP\"\n", " \n", " # -- variable warnings -- \n", " df_stats['feature_warning'] = \"NO WARNING\"\n", " df_stats.loc[(df_stats[\"nunique\"] != 2) & (df_stats[\"feature_name\"] == \"EVENT_LABEL\"),'feature_warning' ] = \"LABEL WARNING, NON-BINARY EVENT LABEL\"\n", " df_stats.loc[(df_stats[\"nunique_pct\"] > 0.97) & (df_stats['feature_type'] == \"CATEGORY\") ,'feature_warning' ] = \"EXCLUDE, GT 97% UNIQUE\"\n", " df_stats.loc[(df_stats[\"null_pct\"] > 0.2) & (df_stats[\"null_pct\"] <= 0.5), 'feature_warning' ] = \"NULL WARNING, GT 20% MISSING\"\n", " df_stats.loc[df_stats[\"null_pct\"] > 0.5,'feature_warning' ] = \"EXCLUDE, GT 50% MISSING\"\n", " df_stats.loc[((df_stats['dtype'] == \"int64\" ) | (df_stats['dtype'] == \"float64\" ) ) & (df_stats['nunique'] < 0.2), 'feature_warning' ] = \"LIKELY CATEGORICAL, NUMERIC w. LOW CARDINALITY\"\n", " \n", " # -- target check -- \n", " exclude_fields = df_stats.loc[(df_stats['feature_warning'] != 'NO WARNING')]['feature_name'].to_list()\n", " event_variables = df_stats.loc[(~df_stats['feature_name'].isin(['EVENT_LABEL', 'EVENT_TIMESTAMP']))]['feature_name'].to_list()\n", " event_labels = df[\"EVENT_LABEL\"].unique().tolist()\n", " \n", " trainingDataSchema = {\n", " 'modelVariables' : df_stats.loc[(df_stats['feature_type'].isin(['IP_ADDRESS', 'EMAIL_ADDRESS', 'CATEGORY', 'NUMERIC' ]))]['feature_name'].to_list(),\n", " 'labelSchema' : {\n", " 'labelMapper' : {\n", " 'FRAUD' : [str(df[\"EVENT_LABEL\"].value_counts().idxmin())],\n", " 'LEGIT' : [str(df[\"EVENT_LABEL\"].value_counts().idxmax())]\n", " }\n", " }\n", " }\n", " \n", " \n", " model_variables = df_stats.loc[(df_stats['feature_type'].isin(['IP_ADDRESS', 'EMAIL_ADDRESS', 'CATEGORY', 'NUMERIC' ]))]['feature_name'].to_list()\n", " \n", " \n", " # -- label schema -- \n", " label_map = {\n", " 'FRAUD' : [df[\"EVENT_LABEL\"].value_counts().idxmin()],\n", " 'LEGIT' : [df[\"EVENT_LABEL\"].value_counts().idxmax()]\n", " }\n", " \n", " \n", " print(\"--- summary stats ---\")\n", " print(df_stats)\n", " print(\"\\n\")\n", " print(\"--- event variables ---\")\n", " print(event_variables)\n", " print(\"\\n\")\n", " print(\"--- event labels ---\")\n", " print(event_labels)\n", " print(\"\\n\")\n", " print(\"--- training data schema ---\")\n", " print(trainingDataSchema)\n", " print(\"\\n\")\n", " \n", " return df_stats, trainingDataSchema, event_variables, event_labels\n", "\n", "# -- connect to S3, snag file, and convert to a panda's dataframe --\n", "#s3 = boto3.resource('s3')\n", "#obj = s3.Object(S3_BUCKET, S3_FILE)\n", "#body = obj.get()['Body']\n", "#df = pd.read_csv(body)\n", "\n", "# -- call profiling function -- \n", "df_stats, trainingDataSchema, eventVariables, eventLabels = summary_stats(data)" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Creating variable: time\n", "Creating variable: fraud_detector_model20200922_insightscore\n", "\n", " --- model variable dict --\n", "[{'name': 'amount'}, {'name': 'time'}, {'name': 'va'}, {'name': 'vb'}, {'name': 'vc'}, {'name': 'vd'}, {'name': 've'}, {'name': 'vf'}, {'name': 'vg'}, {'name': 'vh'}, {'name': 'vi'}, {'name': 'vj'}, {'name': 'vk'}, {'name': 'vl'}, {'name': 'vm'}, {'name': 'vn'}, {'name': 'vo'}, {'name': 'vp'}, {'name': 'vq'}, {'name': 'vr'}, {'name': 'vs'}, {'name': 'vt'}, {'name': 'vu'}, {'name': 'vv'}, {'name': 'vw'}, {'name': 'vx'}, {'name': 'vy'}, {'name': 'vz'}, {'name': 'vaa'}, {'name': 'vab'}]\n", "\n", " --- model label schema dict --\n", "{'labelKey': 'EVENT_LABEL', 'labelMapper': {'FRAUD': ['1'], 'LEGIT': ['0']}}\n" ] } ], "source": [ "# Variable creation just run this code block\n", "def create_label(df, FRAUD_LABEL):\n", " \"\"\"\n", " Returns a dictionary for the model labelSchema, by identifying the rare event as fraud / and common as not-fraud \n", " \n", " Arguments:\n", " df -- input dataframe \n", " FRAUD_LABEL -- the name of the field that contains fraud label \n", " \n", " Returns:\n", " labelSchema -- a dictionary containing labelKey & labelMapper \n", " \"\"\"\n", " label_summary = df[FRAUD_LABEL].value_counts()\n", " labelSchema = {'labelKey': FRAUD_LABEL,\n", " \"labelMapper\" : { \"FRAUD\": [str(label_summary.idxmin())], \n", " \"LEGIT\": [str(label_summary.idxmax())]}\n", " }\n", " afd_resource.put_label(\n", " name = str(label_summary.idxmin()),\n", " description = 'FRAUD')\n", " \n", " afd_resource.put_label(\n", " name = str(label_summary.idxmax()),\n", " description = 'LEGIT')\n", " \n", " return labelSchema\n", " \n", "# -- function to create all your variables --- \n", "def create_variables(df_stats, MODEL_NAME):\n", " \"\"\"\n", " Returns a variable list of model input variables, checks to see if variable exists,\n", " and, if not, then it adds the variable to Fraud Detector \n", " \n", " Arguments: \n", " enrichment_features -- dictionary of optional features, mapped to specific variable types enriched (CARD_BIN, USERAGENT)\n", " numeric_features -- optional list of numeric field names \n", " categorical_features -- optional list of categorical features \n", " \n", " Returns:\n", " variable_list -- a list of variable dictionaries \n", " \n", " \"\"\"\n", " enrichment_features = df_stats.loc[(df_stats['feature_type'].isin(['IP_ADDRESS', 'EMAIL_ADDRESS', 'USERAGENT', 'BILLING_NAME', 'PRICE']))]['feature_name'].to_dict()\n", " enrichment_type = df_stats.loc[(df_stats['feature_type'].isin(['IP_ADDRESS', 'EMAIL_ADDRESS', 'USERAGENT', 'BILLING_NAME', 'PRICE']))]['feature_type'].to_dict()\n", " numeric_features = df_stats.loc[(df_stats['feature_type'].isin(['NUMERIC']))]['feature_name'].to_dict()\n", " categorical_features = df_stats.loc[(df_stats['feature_type'].isin(['CATEGORY']))]['feature_name'].to_dict()\n", " \n", " variable_list = []\n", " # -- first do the enrichment features\n", " for feature in enrichment_features.keys(): \n", " variable_list.append( {'name' : enrichment_features[feature]+\"\"})\n", " try:\n", " varname = enrichment_features[feature]+\"\"\n", " afd_resource.get_variables(name=varname)\n", " except:\n", " print(\"Creating variable: {0}\".format(enrichment_features[feature]))\n", " if enrichment_type[feature] == \"PRICE\":\n", " resp = afd_resource.create_variable(\n", " name = varname,\n", " dataType = 'FLOAT',\n", " dataSource ='EVENT',\n", " defaultValue = '0', \n", " description = enrichment_features[feature],\n", " variableType = enrichment_type[feature] )\n", " else:\n", " resp = afd_resource.create_variable(\n", " name = varname,\n", " dataType = 'STRING',\n", " dataSource ='EVENT',\n", " defaultValue = '', \n", " description = enrichment_features[feature],\n", " variableType = enrichment_type[feature] )\n", " \n", " \n", " # -- check and update the numeric features \n", " for feature in numeric_features: \n", " variable_list.append( {'name' : numeric_features[feature]+\"\"})\n", " try:\n", " varname = numeric_features[feature]+\"\"\n", " afd_resource.get_variables(name=varname)\n", " except:\n", " print(\"Creating variable: {0}\".format(numeric_features[feature]))\n", " resp = afd_resource.create_variable(\n", " name = varname,\n", " dataType = 'FLOAT',\n", " dataSource ='EVENT',\n", " defaultValue = '0.0', \n", " description = numeric_features[feature],\n", " variableType = 'NUMERIC' )\n", " \n", " # -- check and update the categorical features \n", " for feature in categorical_features: \n", " variable_list.append( {'name' : categorical_features[feature]+\"\"})\n", " try:\n", " varname = categorical_features[feature]+\"\"\n", " afd_resource.get_variables(name=varname)\n", " except:\n", " print(\"Creating variable: {0}\".format(categorical_features[feature]))\n", " resp = afd_resource.create_variable(\n", " name = varname,\n", " dataType = 'STRING',\n", " dataSource ='EVENT',\n", " defaultValue = '', \n", " description = categorical_features[feature],\n", " variableType = 'CATEGORICAL' )\n", " \n", " # -- create a model score feature \n", " model_feature = \"{0}_insightscore\".format(MODEL_NAME) \n", " # variable_list.append( {'name' : model_feature})\n", " try:\n", " afd_resource.get_variables(name=model_feature)\n", " except:\n", " print(\"Creating variable: {0}\".format(model_feature))\n", " resp = afd_resource.create_variable(\n", " name = model_feature,\n", " dataType = 'FLOAT',\n", " dataSource ='MODEL_SCORE',\n", " defaultValue = '0.0', \n", " description = model_feature,\n", " variableType = 'NUMERIC' )\n", " \n", " return variable_list\n", "\n", "\n", "model_variables = create_variables(df_stats, MODEL_NAME)\n", "print(\"\\n --- model variable dict --\")\n", "print(model_variables)\n", "\n", "\n", "model_label = create_label(data, \"EVENT_LABEL\")\n", "print(\"\\n --- model label schema dict --\")\n", "print(model_label)" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['0', '1']\n" ] } ], "source": [ "#Amazon Fraud Detector expect the labels to be strings.\n", "eventLabels = list(map(str, eventLabels))\n", "print(eventLabels)" ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-- create entity --\n", "{'ResponseMetadata': {'RequestId': '88e9d45f-2c8b-4a90-b58c-8a6dcea3bc40', 'HTTPStatusCode': 200, 'HTTPHeaders': {'content-type': 'application/x-amz-json-1.1', 'date': 'Tue, 22 Sep 2020 21:48:52 GMT', 'x-amzn-requestid': '88e9d45f-2c8b-4a90-b58c-8a6dcea3bc40', 'content-length': '2', 'connection': 'keep-alive'}, 'RetryAttempts': 0}}\n", "-- create event type --\n", "{'ResponseMetadata': {'RequestId': 'd48b2c1c-34a2-4c97-bc7d-52c0e192f729', 'HTTPStatusCode': 200, 'HTTPHeaders': {'content-type': 'application/x-amz-json-1.1', 'date': 'Tue, 22 Sep 2020 21:48:53 GMT', 'x-amzn-requestid': 'd48b2c1c-34a2-4c97-bc7d-52c0e192f729', 'content-length': '2', 'connection': 'keep-alive'}, 'RetryAttempts': 0}}\n" ] } ], "source": [ "# Creating entity and event types just run this code block ---\n", "response = afd_resource.put_entity_type(\n", " name = ENTITY_TYPE,\n", " description = ENTITY_DESC\n", ")\n", "print(\"-- create entity --\")\n", "print(response)\n", "\n", "response = afd_resource.put_event_type (\n", " name = EVENT_TYPE,\n", " eventVariables = eventVariables,\n", " labels = eventLabels,\n", " entityTypes = [ENTITY_TYPE])\n", "print(\"-- create event type --\")\n", "print(response)" ] }, { "cell_type": "code", "execution_count": 96, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-- initalize model --\n", "{'ResponseMetadata': {'RequestId': '2c15f806-c600-4217-b400-8332dda66a47', 'HTTPStatusCode': 200, 'HTTPHeaders': {'content-type': 'application/x-amz-json-1.1', 'date': 'Tue, 22 Sep 2020 21:48:56 GMT', 'x-amzn-requestid': '2c15f806-c600-4217-b400-8332dda66a47', 'content-length': '2', 'connection': 'keep-alive'}, 'RetryAttempts': 0}}\n" ] } ], "source": [ "# -- create our model --\n", "response = afd_resource.create_model(\n", " description = MODEL_DESC,\n", " eventTypeName = EVENT_TYPE,\n", " modelId = MODEL_NAME,\n", " modelType = 'ONLINE_FRAUD_INSIGHTS')\n", "print(\"-- initalize model --\")\n", "print(response)" ] }, { "cell_type": "code", "execution_count": 97, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-- model training --\n", "{'modelId': 'fraud_detector_model20200922', 'modelType': 'ONLINE_FRAUD_INSIGHTS', 'modelVersionNumber': '1.0', 'status': 'TRAINING_IN_PROGRESS', 'ResponseMetadata': {'RequestId': 'e88dc617-42fe-4971-9509-ee6d1fbdf6f8', 'HTTPStatusCode': 200, 'HTTPHeaders': {'content-type': 'application/x-amz-json-1.1', 'date': 'Tue, 22 Sep 2020 21:49:02 GMT', 'x-amzn-requestid': 'e88dc617-42fe-4971-9509-ee6d1fbdf6f8', 'content-length': '137', 'connection': 'keep-alive'}, 'RetryAttempts': 0}}\n" ] } ], "source": [ "# -- initializes the model, it's now ready to train -- \n", "S3_FILE = \"dataset-training.csv\"\n", "S3_FILE_LOC = \"s3://{0}/{1}\".format(S3_BUCKET,S3_FILE)\n", "\n", "response = afd_resource.create_model_version(\n", " modelId = MODEL_NAME,\n", " modelType = 'ONLINE_FRAUD_INSIGHTS',\n", " trainingDataSource = 'EXTERNAL_EVENTS',\n", " trainingDataSchema = trainingDataSchema,\n", " externalEventsDetail = {\n", " 'dataLocation' : S3_FILE_LOC,\n", " 'dataAccessRoleArn': ARN_ROLE\n", " }\n", ")\n", "print(\"-- model training --\")\n", "print(response)" ] }, { "cell_type": "code", "execution_count": 98, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model status : TRAINING_COMPLETE\n", "\n", " --- model training complete --\n", "Elapsed time : 3134.791792869568 seconds \n", "\n", "{'modelId': 'fraud_detector_model20200922', 'modelType': 'ONLINE_FRAUD_INSIGHTS', 'modelVersionNumber': '1.0', 'trainingDataSource': 'EXTERNAL_EVENTS', 'trainingDataSchema': {'modelVariables': ['time', 'va', 'vb', 'vc', 'vd', 've', 'vf', 'vg', 'vh', 'vi', 'vj', 'vk', 'vl', 'vm', 'vn', 'vo', 'vp', 'vq', 'vr', 'vs', 'vt', 'vu', 'vv', 'vw', 'vx', 'vy', 'vz', 'vaa', 'vab'], 'labelSchema': {'labelMapper': {'FRAUD': ['1'], 'LEGIT': ['0']}}}, 'externalEventsDetail': {'dataLocation': 's3://afd-poc-trainingbucket-1i37svk9elcoe/dataset-training.csv', 'dataAccessRoleArn': 'arn:aws:iam::387461613214:role/afd-poc-NotebookInstanceExecutionRole-1FNQ41S8H2G68'}, 'status': 'TRAINING_COMPLETE', 'arn': 'arn:aws:frauddetector:us-west-2:387461613214:model-version/ONLINE_FRAUD_INSIGHTS/fraud_detector_model20200922/1.0', 'ResponseMetadata': {'RequestId': '7386e6d4-a8b0-4033-b965-899cd5814a26', 'HTTPStatusCode': 200, 'HTTPHeaders': {'content-type': 'application/x-amz-json-1.1', 'date': 'Tue, 22 Sep 2020 22:41:31 GMT', 'x-amzn-requestid': '7386e6d4-a8b0-4033-b965-899cd5814a26', 'content-length': '756', 'connection': 'keep-alive'}, 'RetryAttempts': 0}}\n" ] } ], "source": [ "# -- model training takes time, we'll loop until it's complete -- \n", "print(\"-- wait for model training to complete --\")\n", "stime = time.time()\n", "while True:\n", " clear_output(wait=True)\n", " response = afd_resource.get_model_version(modelId=MODEL_NAME, modelType = \"ONLINE_FRAUD_INSIGHTS\", modelVersionNumber = '1.0')\n", " if response['status'] == 'TRAINING_IN_PROGRESS':\n", " print(f\"current progress: {(time.time() - stime)/60:{3}.{3}} minutes\")\n", " time.sleep(60) # -- sleep for 60 seconds \n", " if response['status'] != 'TRAINING_IN_PROGRESS':\n", " print(\"Model status : \" + response['status'])\n", " break\n", " \n", "etime = time.time()\n", "\n", "# -- summarize -- \n", "print(\"\\n --- model training complete --\")\n", "print(\"Elapsed time : %s\" % (etime - stime) + \" seconds \\n\" )\n", "print(response)" ] }, { "cell_type": "code", "execution_count": 99, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model status : ACTIVE\n", "Elapsed time : 602.6856355667114 seconds \n", "\n", "{'modelId': 'fraud_detector_model20200922', 'modelType': 'ONLINE_FRAUD_INSIGHTS', 'modelVersionNumber': '1.0', 'trainingDataSource': 'EXTERNAL_EVENTS', 'trainingDataSchema': {'modelVariables': ['time', 'va', 'vb', 'vc', 'vd', 've', 'vf', 'vg', 'vh', 'vi', 'vj', 'vk', 'vl', 'vm', 'vn', 'vo', 'vp', 'vq', 'vr', 'vs', 'vt', 'vu', 'vv', 'vw', 'vx', 'vy', 'vz', 'vaa', 'vab'], 'labelSchema': {'labelMapper': {'FRAUD': ['1'], 'LEGIT': ['0']}}}, 'externalEventsDetail': {'dataLocation': 's3://afd-poc-trainingbucket-1i37svk9elcoe/dataset-training.csv', 'dataAccessRoleArn': 'arn:aws:iam::387461613214:role/afd-poc-NotebookInstanceExecutionRole-1FNQ41S8H2G68'}, 'status': 'ACTIVE', 'arn': 'arn:aws:frauddetector:us-west-2:387461613214:model-version/ONLINE_FRAUD_INSIGHTS/fraud_detector_model20200922/1.0', 'ResponseMetadata': {'RequestId': 'bca2079c-03d0-42f1-9863-7cd0c71fc4dc', 'HTTPStatusCode': 200, 'HTTPHeaders': {'content-type': 'application/x-amz-json-1.1', 'date': 'Tue, 22 Sep 2020 22:54:49 GMT', 'x-amzn-requestid': 'bca2079c-03d0-42f1-9863-7cd0c71fc4dc', 'content-length': '745', 'connection': 'keep-alive'}, 'RetryAttempts': 0}}\n" ] } ], "source": [ "# activating the model\n", "response = afd_resource.update_model_version_status (\n", " modelId = MODEL_NAME,\n", " modelType = 'ONLINE_FRAUD_INSIGHTS',\n", " modelVersionNumber = '1.0',\n", " status = 'ACTIVE'\n", ")\n", "print(\"-- activating model --\")\n", "print(response)\n", "\n", "#-- wait until model is active \n", "print(\"--- waiting until model status is active \")\n", "stime = time.time()\n", "while True:\n", " clear_output(wait=True)\n", " response = afd_resource.get_model_version(modelId=MODEL_NAME, modelType = \"ONLINE_FRAUD_INSIGHTS\", modelVersionNumber = '1.0')\n", " if response['status'] != 'ACTIVE':\n", " print(f\"current progress: {(time.time() - stime)/60:{3}.{3}} minutes\")\n", " time.sleep(60) # sleep for 1 minute \n", " if response['status'] == 'ACTIVE':\n", " print(\"Model status : \" + response['status'])\n", " break\n", " \n", "etime = time.time()\n", "print(\"Elapsed time : %s\" % (etime - stime) + \" seconds \\n\" )\n", "print(response)" ] }, { "cell_type": "code", "execution_count": 185, "metadata": {}, "outputs": [ { "data": { "image/png": "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P2OcqrJz507q1KnDK6+8wocffsiuXbsQERISEvK0QT39rCwhISHjLCMhIeGkBJfu8ccfJz4+ngsvvJCSJUtyyy23sHLlSqpUqUJaWhodO3bktttuY/ny5Rw5coQbb7yRhx9+mFGjRlG6dGkSEhIyLS/rug4fPky5cuXybPsguGcEFwMbVXWzqp4AJgI9spTpAYzxvf8CaCdBukpow+4wpqxuQqnwEGbOHGhJwOSL6Ohohg4dmtFrJiIigksvvZTJkyefVHbSpEm0a9cOgPbt2zN37tyAb6oXFRXFpk2bsp0WERGRcTQKsGfPnpPKZP3Z9enThyVLlrBjxw6mTp2akQiioqIoWbIkBw4cyDiKTkhIYO3atdmuu1mzZvz559/P9t66dSu33HILb7/9NrGxscTHx3P++ednqkrJGktUVBTvv/9+piP3xMRELrvsMpYtW8ZLL73ExoMlRQAADOJJREFUpEmTiIuLIz4+nrJly2Zanr9///vflC5dOse/7JQvX57q1avz66+/Zoz79ddfadq0abblw8PDefvtt9m5cyebN2+mYsWKtGzZktDQUA4ePMj27du58847KVmyJBUrVmTYsGHMmjULgKZNm/Lbb79liv+3337LtK7169dnqqbKEzk1HpztH3Ad8KHf8GDg7Sxl1gC1/IY3AZWyWdatwApgRe3atXNsJMnV1O669M76unTCxKwtKNZYXAgVpsbiffv2aalSpXTlypWqqrps2TItVaqUvvHGG5qQkKAHDx7Uxx9/XMuWLat//vmnqqoeP35cW7VqpR07dtT169dramqqHjhwQF988cVMDY3pEhIStFq1avraa6/p8ePHNSEhQb///ntVVf3ggw+0UaNGGhsbq7t379bWrVuf1FjsH2+6mJgYbd++vV544YWZxnfv3l3vvvtuPXTokKampurGjRt1yZIl2X4We/bs0QoVKmhiYqKqqq5du1ZLliypv//+u6akpOjHH3+soaGh+t///ldVncbiyy+/PNMyvvzyS23atKmuWbNGVZ3G6vTG2JkzZ2r16tV19+7dmpSUpM8++6yGhIRkuz1n4+GHH9arrrpKDx48qOvXr9dq1aplasD1t2PHDt25c6empaXpd999p7Vq1crU0HzOOefoiBEjNDk5WePi4rRnz546cOBAVVVNSkrS2rVr6+uvv67Hjx/Xt956S2vX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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# -- model performance summary -- \n", "auc = afd_resource.describe_model_versions(\n", " modelId= MODEL_NAME,\n", " modelVersionNumber='1.0',\n", " modelType='ONLINE_FRAUD_INSIGHTS',\n", " maxResults=10\n", ")['modelVersionDetails'][0]['trainingResult']['trainingMetrics']['auc']\n", "\n", "\n", "df_model = pd.DataFrame(afd_resource.describe_model_versions(\n", " modelId= MODEL_NAME,\n", " modelVersionNumber='1.0',\n", " modelType='ONLINE_FRAUD_INSIGHTS',\n", " maxResults=10\n", ")['modelVersionDetails'][0]['trainingResult']['trainingMetrics']['metricDataPoints'])\n", "\n", "\n", "plt.figure(figsize=(6,6))\n", "plt.plot(df_model[\"fpr\"], df_model[\"tpr\"], color='darkorange',\n", " lw=2, label='ROC curve (area = %0.3f)' % auc)\n", "plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')\n", "plt.xlabel('False Positive Rate')\n", "plt.ylabel('True Positive Rate')\n", "plt.title( MODEL_NAME + ' ROC Chart')\n", "plt.legend(loc=\"lower right\",fontsize=12)\n", "plt.axvline(x = 0.02 ,linewidth=2, color='r')\n", "plt.axhline(y = 0.73 ,linewidth=2, color='r')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 101, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'ResponseMetadata': {'RequestId': '4c1eb5b8-0bb0-4ac0-abf0-49d55c3861c6', 'HTTPStatusCode': 200, 'HTTPHeaders': {'content-type': 'application/x-amz-json-1.1', 'date': 'Tue, 22 Sep 2020 22:55:06 GMT', 'x-amzn-requestid': '4c1eb5b8-0bb0-4ac0-abf0-49d55c3861c6', 'content-length': '2', 'connection': 'keep-alive'}, 'RetryAttempts': 0}}\n" ] } ], "source": [ "# -- initialize your detector -- \n", "response = afd_resource.put_detector(detectorId = DETECTOR_NAME, \n", " description = DETECTOR_DESC, \n", " eventTypeName = EVENT_TYPE )\n", "\n", "print(response)" ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " --- score thresholds 1% to 6% --- \n", " fpr tpr threshold rule outcome\n", "0 0.01 0.85 970.0 $fraud_detector_model20200922_insightscore > 9... fraud\n", "1 0.02 0.87 925.0 $fraud_detector_model20200922_insightscore > 9... fraud\n", "2 0.03 0.87 880.0 $fraud_detector_model20200922_insightscore > 8... fraud\n", "3 0.04 0.90 835.0 $fraud_detector_model20200922_insightscore > 8... investigate\n", "4 0.05 0.91 790.0 $fraud_detector_model20200922_insightscore > 7... investigate\n", "5 0.06 0.91 755.0 $fraud_detector_model20200922_insightscore <= ... approve\n" ] } ], "source": [ "# -- make rules -- \n", "model_stat = df_model.round(decimals=2) \n", "\n", "m = model_stat.loc[model_stat.groupby([\"fpr\"])[\"threshold\"].idxmax()] \n", "\n", "def make_rule(x):\n", " rule = \"\"\n", " if x['fpr'] <= 0.05: \n", " rule = \"${0}_insightscore > {1}\".format(MODEL_NAME,x['threshold'])\n", " if x['fpr'] == 0.06:\n", " rule = \"${0}_insightscore <= {1}\".format(MODEL_NAME,x['threshold_prev'])\n", " return rule\n", " \n", "m[\"threshold_prev\"] = m['threshold'].shift(1)\n", "m['rule'] = m.apply(lambda x: make_rule(x), axis=1)\n", "\n", "m['outcome'] = \"approve\"\n", "m.loc[m['fpr'] <= 0.03, \"outcome\"] = \"fraud\"\n", "m.loc[(m['fpr'] > 0.03) & (m['fpr'] <= 0.05), \"outcome\"] = \"investigate\"\n", "\n", "print (\" --- score thresholds 1% to 6% --- \")\n", "print(m[[\"fpr\", \"tpr\", \"threshold\", \"rule\", \"outcome\"]].loc[(m['fpr'] > 0.0 ) & (m['fpr'] <= 0.06)].reset_index(drop=True))" ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "creating outcome variable: fraud \n", "creating outcome variable: investigate \n", "creating outcome variable: approve \n" ] } ], "source": [ "# -- create outcomes -- \n", "def create_outcomes(outcomes):\n", " \"\"\" create Fraud Detector Outcomes \n", " \n", " \"\"\" \n", " for outcome in outcomes:\n", " print(\"creating outcome variable: {0} \".format(outcome))\n", " response = afd_resource.put_outcome(\n", " name=outcome,\n", " description=outcome)\n", "\n", "# -- get distinct outcomes \n", "outcomes = m[\"outcome\"].unique().tolist()\n", "\n", "create_outcomes(outcomes)" ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "creating rule: rule0_fraud_detector_model20200922: IF $fraud_detector_model20200922_insightscore > 970.0 THEN fraud\n", "creating rule: rule1_fraud_detector_model20200922: IF $fraud_detector_model20200922_insightscore > 925.0 THEN fraud\n", "creating rule: rule2_fraud_detector_model20200922: IF $fraud_detector_model20200922_insightscore > 880.0 THEN fraud\n", "creating rule: rule3_fraud_detector_model20200922: IF $fraud_detector_model20200922_insightscore > 835.0 THEN investigate\n", "creating rule: rule4_fraud_detector_model20200922: IF $fraud_detector_model20200922_insightscore > 790.0 THEN investigate\n", "creating rule: rule5_fraud_detector_model20200922: IF $fraud_detector_model20200922_insightscore <= 790.0 THEN approve\n" ] }, { "data": { "text/plain": [ "[{'ruleId': 'rule0_fraud_detector_model20200922',\n", " 'ruleVersion': '1',\n", " 'detectorId': 'fraud_detector_endpoint20200922'},\n", " {'ruleId': 'rule1_fraud_detector_model20200922',\n", " 'ruleVersion': '1',\n", " 'detectorId': 'fraud_detector_endpoint20200922'},\n", " {'ruleId': 'rule2_fraud_detector_model20200922',\n", " 'ruleVersion': '1',\n", " 'detectorId': 'fraud_detector_endpoint20200922'},\n", " {'ruleId': 'rule3_fraud_detector_model20200922',\n", " 'ruleVersion': '1',\n", " 'detectorId': 'fraud_detector_endpoint20200922'},\n", " {'ruleId': 'rule4_fraud_detector_model20200922',\n", " 'ruleVersion': '1',\n", " 'detectorId': 'fraud_detector_endpoint20200922'},\n", " {'ruleId': 'rule5_fraud_detector_model20200922',\n", " 'ruleVersion': '1',\n", " 'detectorId': 'fraud_detector_endpoint20200922'}]" ] }, "execution_count": 104, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# creating te rules with the desired outcomes associated with our detector\n", "rule_set = m[(m[\"fpr\"] > 0.0) & (m[\"fpr\"] <= 0.06)][[\"outcome\", \"rule\"]].to_dict('records')\n", "rule_list = []\n", "for i, rule in enumerate(rule_set):\n", " ruleId = \"rule{0}_{1}\".format(i, MODEL_NAME)\n", " rule_list.append({\"ruleId\": ruleId, \n", " \"ruleVersion\" : '1',\n", " \"detectorId\" : DETECTOR_NAME\n", " \n", " })\n", " print(\"creating rule: {0}: IF {1} THEN {2}\".format(ruleId, rule[\"rule\"], rule['outcome']))\n", " try:\n", " response = afd_resource.create_rule(\n", " ruleId = ruleId,\n", " detectorId = DETECTOR_NAME,\n", " expression = rule['rule'],\n", " language = 'DETECTORPL',\n", " outcomes = [rule['outcome']]\n", " )\n", " except:\n", " print(\"this rule already exists in this detector\")\n", "rule_list" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " -- detector created -- \n", "{'rule': {'detectorId': 'fraud_detector_endpoint20200922', 'ruleId': 'rule5_fraud_detector_model20200922', 'ruleVersion': '1'}, 'ResponseMetadata': {'RequestId': 'ceb37fe4-61df-4797-b198-341bf37b8a7d', 'HTTPStatusCode': 200, 'HTTPHeaders': {'content-type': 'application/x-amz-json-1.1', 'date': 'Tue, 22 Sep 2020 22:55:26 GMT', 'x-amzn-requestid': 'ceb37fe4-61df-4797-b198-341bf37b8a7d', 'content-length': '121', 'connection': 'keep-alive'}, 'RetryAttempts': 0}}\n" ] } ], "source": [ "# creating the detector\n", "afd_resource.create_detector_version(\n", " detectorId = DETECTOR_NAME,\n", " rules = rule_list,\n", " modelVersions = [{\"modelId\":MODEL_NAME, \n", " \"modelType\" : \"ONLINE_FRAUD_INSIGHTS\",\n", " \"modelVersionNumber\" : \"1.0\"}],\n", " ruleExecutionMode = 'FIRST_MATCHED'\n", " )\n", "\n", "print(\"\\n -- detector created -- \")\n", "print(response) " ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " -- detector activated -- \n", "{'ResponseMetadata': {'RequestId': '12c43795-ac18-42d6-8d07-22f49ca7014d', 'HTTPStatusCode': 200, 'HTTPHeaders': {'content-type': 'application/x-amz-json-1.1', 'date': 'Tue, 22 Sep 2020 22:55:37 GMT', 'x-amzn-requestid': '12c43795-ac18-42d6-8d07-22f49ca7014d', 'content-length': '2', 'connection': 'keep-alive'}, 'RetryAttempts': 0}}\n" ] } ], "source": [ "# activating the detector\n", "response = afd_resource.update_detector_version_status(\n", " detectorId= DETECTOR_NAME,\n", " detectorVersionId='1',\n", " status='ACTIVE'\n", ")\n", "print(\"\\n -- detector activated -- \")\n", "print(response)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Testing our model endpoint" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [], "source": [ "S3_FILE = \"dataset-test.csv\"\n", "S3_FILE_LOC = \"s3://{0}/{1}\".format(S3_BUCKET,S3_FILE)\n", "\n", "s3_resource.Bucket(S3_BUCKET).download_file(S3_FILE, 'dataset-test.csv')" ] }, { "cell_type": "code", "execution_count": 108, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
timevavbvcvdvevfvgvhvivjvkvlvmvnvovpvqvrvsvtvuvvvwvxvyvzvaavabamount
041505.0-16.5265078.584972-18.6498539.505594-13.793819-2.832404-16.7016947.517344-8.507059-14.1101845.299236-10.8340061.671120-9.3738590.360806-9.899247-19.236292-8.3985523.101735-1.5149231.190739-1.127670-2.3585790.673461-1.413700-0.462762-2.018575-1.042804364.19
144261.00.339812-2.743745-0.134070-1.385729-1.4514131.015887-0.5243790.2240600.899746-0.565012-0.0876700.9794270.076883-0.217884-0.136830-2.1428920.1269561.7526620.4325460.506044-0.213436-0.942525-0.526819-1.1569920.311211-0.7466470.0409960.102038520.12
235484.01.399590-0.5907010.168619-1.029950-0.5398060.040444-0.7125670.002299-0.9717470.7568010.5438270.1124531.075384-0.2457720.1804831.769860-0.533172-0.5333001.1922450.2128770.1023980.168269-0.166639-0.8102500.505083-0.2323400.0114090.00463431.00
3167123.0-0.4320711.647895-1.669361-0.3495040.785785-0.6306470.2769900.586025-0.484715-1.376648-1.3283350.2236211.132627-0.5508750.6165680.4979740.5021950.9813430.101264-0.2446330.3589320.873663-0.178642-0.017171-0.207392-0.157756-0.2373860.0019341.50
4168473.02.014160-0.137394-1.0158390.327269-0.182179-0.9565710.043241-0.1607460.3632410.2594520.9421620.850038-0.6161660.592634-0.6038450.091077-0.471867-0.3338160.404711-0.255293-0.238644-0.6164000.3470450.061561-0.3601960.174730-0.078043-0.0705710.89
567878.0-0.641330-0.0573041.489998-1.688131-1.1510430.259996-1.391069-2.3340751.168644-2.0840800.4803810.473738-2.1922760.7739420.2944840.406074-0.5418551.0314500.0170760.618411-1.2316340.257164-0.371953-0.0385661.397514-0.6659470.0310030.180357100.00
6159763.02.023952-0.120140-1.0869180.423019-0.142901-1.1277520.178493-0.3032340.5645090.062831-0.7200470.366835-0.1108570.3190940.108359-0.153633-0.221312-0.9341410.070553-0.210864-0.276175-0.6977080.335631-0.017196-0.3249040.200023-0.071566-0.05822416.99
7139631.0-0.6889441.292153-0.564281-1.4575262.258333-0.3232701.678984-0.104128-1.285351-1.3034350.282728-0.402525-0.548687-0.504283-0.6853390.714828-0.0926740.798953-0.150085-0.037150-0.006880-0.171568-0.720019-0.4194351.2119910.670916-0.1039860.0300848.95
8133944.02.1193620.142639-2.3733370.5419490.608419-1.7755640.955775-0.5993830.0104200.295305-0.936569-0.452478-1.3407981.077459-0.099584-0.8150720.018481-0.639446-0.065427-0.3235730.2642640.898266-0.1680630.0593110.6269490.729035-0.129120-0.09471310.00
958769.0-5.584256-4.732413-0.448452-0.121442-0.707412-0.114376-1.5546281.402126-0.031693-0.942358-2.439501-0.552312-0.295588-0.250246-1.1977321.5495530.933237-1.2376890.416832-1.0469000.0416510.6217890.223467-0.7701370.621182-0.0287380.505194-1.898323101.49
\n", "
" ], "text/plain": [ " time va vb vc vd ve vf vg vh vi vj vk vl vm vn vo vp vq vr vs vt vu vv vw vx vy vz vaa vab amount\n", "0 41505.0 -16.526507 8.584972 -18.649853 9.505594 -13.793819 -2.832404 -16.701694 7.517344 -8.507059 -14.110184 5.299236 -10.834006 1.671120 -9.373859 0.360806 -9.899247 -19.236292 -8.398552 3.101735 -1.514923 1.190739 -1.127670 -2.358579 0.673461 -1.413700 -0.462762 -2.018575 -1.042804 364.19\n", "1 44261.0 0.339812 -2.743745 -0.134070 -1.385729 -1.451413 1.015887 -0.524379 0.224060 0.899746 -0.565012 -0.087670 0.979427 0.076883 -0.217884 -0.136830 -2.142892 0.126956 1.752662 0.432546 0.506044 -0.213436 -0.942525 -0.526819 -1.156992 0.311211 -0.746647 0.040996 0.102038 520.12\n", "2 35484.0 1.399590 -0.590701 0.168619 -1.029950 -0.539806 0.040444 -0.712567 0.002299 -0.971747 0.756801 0.543827 0.112453 1.075384 -0.245772 0.180483 1.769860 -0.533172 -0.533300 1.192245 0.212877 0.102398 0.168269 -0.166639 -0.810250 0.505083 -0.232340 0.011409 0.004634 31.00\n", "3 167123.0 -0.432071 1.647895 -1.669361 -0.349504 0.785785 -0.630647 0.276990 0.586025 -0.484715 -1.376648 -1.328335 0.223621 1.132627 -0.550875 0.616568 0.497974 0.502195 0.981343 0.101264 -0.244633 0.358932 0.873663 -0.178642 -0.017171 -0.207392 -0.157756 -0.237386 0.001934 1.50\n", "4 168473.0 2.014160 -0.137394 -1.015839 0.327269 -0.182179 -0.956571 0.043241 -0.160746 0.363241 0.259452 0.942162 0.850038 -0.616166 0.592634 -0.603845 0.091077 -0.471867 -0.333816 0.404711 -0.255293 -0.238644 -0.616400 0.347045 0.061561 -0.360196 0.174730 -0.078043 -0.070571 0.89\n", "5 67878.0 -0.641330 -0.057304 1.489998 -1.688131 -1.151043 0.259996 -1.391069 -2.334075 1.168644 -2.084080 0.480381 0.473738 -2.192276 0.773942 0.294484 0.406074 -0.541855 1.031450 0.017076 0.618411 -1.231634 0.257164 -0.371953 -0.038566 1.397514 -0.665947 0.031003 0.180357 100.00\n", "6 159763.0 2.023952 -0.120140 -1.086918 0.423019 -0.142901 -1.127752 0.178493 -0.303234 0.564509 0.062831 -0.720047 0.366835 -0.110857 0.319094 0.108359 -0.153633 -0.221312 -0.934141 0.070553 -0.210864 -0.276175 -0.697708 0.335631 -0.017196 -0.324904 0.200023 -0.071566 -0.058224 16.99\n", "7 139631.0 -0.688944 1.292153 -0.564281 -1.457526 2.258333 -0.323270 1.678984 -0.104128 -1.285351 -1.303435 0.282728 -0.402525 -0.548687 -0.504283 -0.685339 0.714828 -0.092674 0.798953 -0.150085 -0.037150 -0.006880 -0.171568 -0.720019 -0.419435 1.211991 0.670916 -0.103986 0.030084 8.95\n", "8 133944.0 2.119362 0.142639 -2.373337 0.541949 0.608419 -1.775564 0.955775 -0.599383 0.010420 0.295305 -0.936569 -0.452478 -1.340798 1.077459 -0.099584 -0.815072 0.018481 -0.639446 -0.065427 -0.323573 0.264264 0.898266 -0.168063 0.059311 0.626949 0.729035 -0.129120 -0.094713 10.00\n", "9 58769.0 -5.584256 -4.732413 -0.448452 -0.121442 -0.707412 -0.114376 -1.554628 1.402126 -0.031693 -0.942358 -2.439501 -0.552312 -0.295588 -0.250246 -1.197732 1.549553 0.933237 -1.237689 0.416832 -1.046900 0.041651 0.621789 0.223467 -0.770137 0.621182 -0.028738 0.505194 -1.898323 101.49" ] }, "execution_count": 108, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.set_option('display.max_rows', 500)\n", "pd.set_option('display.max_columns', 500)\n", "pd.set_option('display.width', 1000)\n", "\n", "test = pd.read_csv('dataset-test.csv', delimiter=',')\n", "test.head(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cleaning the test dataset from training columns and defining the start datetime." ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "time va vb vc vd ve vf vg vh vi vj vk vl vm vn vo vp vq vr vs vt vu vv vw vx vy vz vaa vab amount\n" ] } ], "source": [ "record_count = 500\n", "model_variables = [column for column in test.columns if column not in ['EVENT_LABEL', 'EVENT_TIMESTAMP']]\n", "dateTimeObj = datetime.now()\n", "timestampStr = dateTimeObj.strftime(\"%Y-%m-%dT%H:%M:%SZ\")\n", "print(' '.join(model_variables))" ] }, { "cell_type": "code", "execution_count": 110, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'modelScores': [{'modelVersion': {'modelId': 'fraud_detector_model20200922', 'modelType': 'ONLINE_FRAUD_INSIGHTS', 'modelVersionNumber': '1.0'}, 'scores': {'fraud_detector_model20200922_insightscore': 8.0}}], 'ruleResults': [{'ruleId': 'rule5_fraud_detector_model20200922', 'outcomes': ['approve']}], 'ResponseMetadata': {'RequestId': 'd85b48b5-4ed8-495f-a7ee-e545092a9021', 'HTTPStatusCode': 200, 'HTTPHeaders': {'content-type': 'application/x-amz-json-1.1', 'date': 'Tue, 22 Sep 2020 22:56:18 GMT', 'x-amzn-requestid': 'd85b48b5-4ed8-495f-a7ee-e545092a9021', 'content-length': '286', 'connection': 'keep-alive'}, 'RetryAttempts': 0}}\n" ] } ], "source": [ "import uuid\n", "\n", "# test the endpoint with a single prediction.\n", "eventId = uuid.uuid1()\n", "testrecord = test[model_variables].head(15).astype(str).to_dict(orient='records')[6]\n", "pred = afd_resource.get_event_prediction(detectorId=DETECTOR_NAME, \n", " detectorVersionId='1',\n", " eventId = str(eventId),\n", " eventTypeName = EVENT_TYPE,\n", " eventTimestamp = timestampStr, \n", " entities = [{'entityType': ENTITY_TYPE, 'entityId':str(eventId.int)}],\n", " eventVariables= testrecord)\n", "print(pred)" ] }, { "cell_type": "code", "execution_count": 122, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(28481,)" ] }, "execution_count": 122, "metadata": {}, "output_type": "execute_result" } ], "source": [ "test.count()\n", "y_test" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The next block will use some parallelization to run several test against the fraud detector endpoint." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import dask \n", "import time\n", "from IPython.core.display import display, HTML\n", "#display(HTML(\"\"))\n", "\n", "start = time.time()\n", "\n", "@dask.delayed\n", "def _predict(record):\n", " eventId = uuid.uuid1()\n", " try:\n", " pred = afd_resource.get_event_prediction(detectorId=DETECTOR_NAME, \n", " detectorVersionId='1',\n", " eventId = str(eventId),\n", " eventTypeName = EVENT_TYPE,\n", " eventTimestamp = timestampStr, \n", " entities = [{'entityType': ENTITY_TYPE, 'entityId':str(eventId.int)}],\n", " eventVariables= record) \n", " \n", " record[\"score\"] = pred['modelScores'][0]['scores'][\"{0}_insightscore\".format(MODEL_NAME)]\n", " if len(pred['ruleResults']) > 0:\n", " record[\"outcomes\"]= pred['ruleResults'][0]['outcomes']\n", " else:\n", " record[\"outcomes\"]= 'approve'\n", " return record\n", " \n", " except:\n", " pred = afd_resource.get_event_prediction(detectorId=DETECTOR_NAME, \n", " detectorVersionId='1',\n", " eventId = str(eventId),\n", " eventTypeName = EVENT_TYPE,\n", " eventTimestamp = timestampStr, \n", " entities = [{'entityType': ENTITY_TYPE, 'entityId':str(eventId.int)}],\n", " eventVariables= record) \n", " record[\"score\"] = \"-999\"\n", " record[\"outcomes\"]= \"error\"\n", " return record" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# dask approach, if you want to run the entire test dataset(28481) preffer the loop approach on the next cell\n", "predict_data = test[model_variables].head(400).astype(str).to_dict(orient='records')\n", "predict_score = []\n", "\n", "i=0\n", "for record in predict_data:\n", " clear_output(wait=True)\n", " rec = dask.delayed(_predict)(record)\n", " predict_score.append(rec)\n", " i += 1\n", " print(\"current progress: \", round((i/record_count)*100,2), \"%\" )\n", " \n", "predict_recs = dask.compute(*predict_score)\n", "\n", "# Calculate time taken and print results\n", "time_taken = time.time() - start\n", "tps = len(predict_recs) / time_taken\n", "\n", "print ('Process took %0.2f seconds' %time_taken)\n", "print ('Scored %d records' %len(predict_recs))" ] }, { "cell_type": "code", "execution_count": 124, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Process took 4600.17 seconds\n", "Scored 28481 records\n" ] } ], "source": [ "# loop approach, slower but doesnt freeze the browser, go grab a coffe :)\n", "predict_data = test[model_variables].head(28481).astype(str).to_dict(orient='records')\n", "predict_score = []\n", "start = time.time()\n", "\n", "for record in predict_data:\n", " eventId = uuid.uuid1()\n", " pred = afd_resource.get_event_prediction(detectorId=DETECTOR_NAME, \n", " detectorVersionId='1',\n", " eventId = str(eventId),\n", " eventTypeName = EVENT_TYPE,\n", " eventTimestamp = timestampStr, \n", " entities = [{'entityType': ENTITY_TYPE, 'entityId':str(eventId.int)}],\n", " eventVariables= record)\n", " record[\"score\"] = pred['modelScores'][0]['scores'][\"{0}_insightscore\".format(MODEL_NAME)]\n", " \n", "\n", "\n", "# Calculate time taken and print results\n", "time_taken = time.time() - start\n", "tps = len(predict_recs) / time_taken\n", "\n", "print ('Process took %0.2f seconds' %time_taken)\n", "print ('Scored %d records' %len(predict_data))" ] }, { "cell_type": "code", "execution_count": 184, "metadata": {}, "outputs": [], "source": [ "p_data = [d['score'] for d in predict_data]" ] }, { "cell_type": "code", "execution_count": 205, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Balanced accuracy = 0.949470569796867\n" ] } ], "source": [ "# fraud detector model balanced accuracy for 0.9 threshold\n", "afd_preds = np.where(np.array(p_data) > 950, 1, 0)\n", "print(\"Balanced accuracy = {}\".format(balanced_accuracy_score(y_test, afd_preds)))" ] }, { "cell_type": "code", "execution_count": 183, "metadata": {}, "outputs": [ { "data": { "image/png": "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wAcffsSRR53MXXc/VK6m5l40YysHB+tW0rNHd9ZbZ00AunRZir6r9Wb6zNlI4ot58wH4Yt58VuixPACjXniZ3fvvgCQ23GBdPv/8C2bO+oTFF1+cJZZYAoBvFiygJv77qzN//pfcds8DHD1w/1b+dJaFXr2+xy4DduDmm+9auG+7bbfi/vuTv6Zuv/0+9tj9pwBMmTKVN998m5qaSv9jvnJVEUVv5ZBJzlpS98aOR8QnWdSbFx99PJ233/s3P1x/Hc741dEc/etz+NM1NxI1wfAbLgNg+szZrLRCj4XXrLhCD6bPnEXPHt35ePpMjjttCB9O/ZhTjj+SFXomAf7Pw25j4P5707lz57J8Liutyy87nzPP+h3dunUFYPnll2POnLlUVydrmkz96GNW7rVSOZvYplT6DcasetavAGPS/58JTADeS1+/0tBFkgZJGiNpzI233dXQabk2f/6XnHz27zhj8NF07dKFex58jDNOHMTTD97O6YMHMeSiK4EkZ12XlCwS970Ve/Lgbdcx8p6bePjxvzHrk095Z8K/+eCjaez4k61a9fNYNnbdZUdmzJjFq6+9uXBf7c+/UH2/J9YyNc3YyiGTnnVE9AGQdD0wIiJGpu8HADs2ct1QYCjAglmT2txv4YKqKk46+3fsuvN27LRtElRHPP43zjopuRn40+37ce7FSbBeaYUe/GfGrIXXTp8xa2GKpNYKPZdnzT6r8errb/HJnLmMf2ciO+8zkOrqamZ/OpfDTjidW66+tJU+nZXSlltuys9225kB/benc+dOLL10Ny6/7HyWXXYZOnbsSHV1Nav0+h4fT5te7qa2Ge21Z11rs9pADRARjwM/ybjOihQRDLnoSvqu1puB+++9cH/PHsszOu09/fOVsazWuxcA2269BSOeeJqI4PW33qZr1y707NGd/8yYyVdffw3A3M8+57U3x7P6qquw/167MWrEHTx1/63cdt1lrN67lwN1jp19zsWs3ndT1lx7Cw46+DhGjXqRQweeyDPP/oN99klGexxyyC8Y8chTZW5p29Eue9YFZkk6BxhOchP1YGB245e0Ta+9MY5HnniatdZYnX0GHg/Ar44eyPlnDObi/72BqupqOi2xBOeePhiAbX68Gc+/NJoB+x7Bkp07c+FvTgZg0vsf8serhyGJiOCwA/Zm7TX6lO1zWes66ze/587h13LB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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plot_confusion_matrix(y_test, afd_preds)" ] }, { "cell_type": "code", "execution_count": 206, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " non-fraud 1.00 0.99 0.99 28435\n", " fraud 0.09 0.91 0.17 46\n", "\n", " accuracy 0.99 28481\n", " macro avg 0.55 0.95 0.58 28481\n", "weighted avg 1.00 0.99 0.99 28481\n", "\n" ] } ], "source": [ "print(classification_report(\n", " y_test, afd_preds, target_names=['non-fraud', 'fraud']))" ] }, { "cell_type": "code", "execution_count": 112, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
timevavbvcvdvevfvgvhvivjvkvlvmvnvovpvqvrvsvtvuvvvwvxvyvzvaavabamountscoreoutcomes
041505.0-16.52650656912318.58497179585822-18.6498531851944989.50559351508723-13.793818527095699-2.8324042993974703-16.7016942960457.517343903709871-8.50705863675898-14.1101844415456965.29923634963938-10.83400648147341.67112025332681-9.373858583649760.36080564163161705-9.899246540806661-19.2362923697613-8.398551994945753.10173536885404-1.514923435278521.19073869481428-1.1276700090206102-2.35857876978810.6734613289872371-1.4136996745881998-0.46276236139933-2.01857524875161-1.04280416970881364.191000.0[fraud]
1652913.00.6768548293865951.58702920998622-1.508146982548071.443814844350841.31678997910859-1.16034214105187021.1490491098159-0.4193931328245341-0.0905654487115674-0.3230584848927612.967920897973221-0.155026280352087-0.7177661091303009-3.709275179915210.7310503071803590.510125020058252.73026213011681041.46374586218951-0.5784055858811940.31792704392540505-0.1914184018868230.1014507814923720.05829839657805901-0.135311156556857-0.6044061673895129-0.45276321577020710.0464301769729269-0.38364151787050610.89977.0[fraud]
1955575.0-3.41942263819263-1.130075598090151.607086373753772.22997892209850962.64408903133496-0.79353772235042011.08824220975816-1.00840988415033-0.9333151682582161.921981759265391.95444539942508970.3888397669221480.30147367767299-0.427868493466856-0.0292266721907548-0.0750638320495107-0.7991270792650841-0.629796480633153-0.469016593690311-1.44533223472583-0.4796742054290580.5240222644533290.0936850261636710.305230152643873930.65396264039042710.0228521071220258-0.955552398442486-0.085629544571638322.7953.0[fraud]
32141655.0-29.942972270707894-25.8317821051362-16.22751192912736.690679169572508-20.787845811536313.085694370938917.2566228959585-9.161746211138565.00304130464362-2.43146639127421.75998939335631021.861432717528513.05338368623288-1.40963974297515023.680271528524714.531275030273720.22001123266623696-1.604536175899423.14031061569242-21.3871219290332-2.49469918146669-0.660297208514391-8.537815806510410.40080447201294-0.6430227870311340.49690284583126896.26770908866261-2.76507000175875953502.11962.0[fraud]
5156803.01.173609124328550.511603445630379-0.52045147570860111.122626206084360.35886736932159297-0.295960433531853030.02500463877529330.14444171501870098-0.110183833896483-0.5133584384151081.50090553458987-0.228726450784267-1.5703348271985802-0.8396775630709610.82551133038619420.66477432410181890.8862748303610830.925736187467082-0.5606318507221589-0.20184199976003606-0.0268349064777576-0.0755364811334122-0.129545704955994-0.48168672971307110.582500674589865-0.2898759014019720.03791282390347460.03743657518193761.0958.0[fraud]
5994330.0-0.1591882534515391.63642225435632051.545990380254814.554799403928640.9725001613143450.1356194690038960.890709635187871-0.308928981901544-0.7506710020331751.488085162255360.0189227146632523-3.514951120162031.378520839157811.75093472390239980.0364873683299348-0.3325434537365550.83124079874662720.02724267393996681.117555277824450.374095700292396-0.4149084993816161-0.72533256362199290.0198138142745913-0.0804172850283939-0.56664384906918710.02949884484729110.2068604920836630.0030600077367060412.74965.0[fraud]
17758954.01.238042617998440.77053043333537-0.3319975239085191.345464512194510.139816295211697-1.229675965953360.354259165638368-0.280804576159513-0.184996149214632-0.6998128892677070.2306550666583520.214775247241316050.561439138721415-1.45979426106370981.02124766236501020.5671136559722870.8590524028769070.516214961212954-0.629783953300129-0.0582422755483618-0.0605703154557262-0.0710964980063678-0.1310000239867180.2691442471066710.7120999799201929-0.329489178612648040.0393080261364550.05883787437146981.0947.0[fraud]
253878.0-2.51219240716515020.317838238718562041.270332802121071.214257950189791.17990250727029-0.412233265109121061.00271608138525-0.77468018394012411.656601996466922.7790737156669403-0.0847781328647432-0.18321933511528-0.330652014184725-1.27735053626582020.586282642874345-1.569661847674820.122172327014581-0.91672986647514520.66952463425091890.5929484938755051-0.6552577988297880.24236823281838-0.1350739000735970.1042607010447150.211102067974728-0.287306672363311030.3351291310584530.3282118191077618.8962.0[fraud]
328110199.01.751363243257720.3378124008339520.7952623929564184.31273176972153-0.681348924648448-0.126233056366034-0.566591255980354-0.03134405796601180.9195228807082540.9751300812665230.435764202447928-2.215695859205621.914571179079941.15256247746996-1.37465707640882020.82398092409294710.175328666447042-0.0483307755538258-2.38942182862032-0.2899434441092140.160070701106165950.8038411155151620.253569280923484960.8074573633362009-0.3400690874520441-0.00655722686278409-0.00813323923492112-0.025071551940193729.58955.0[fraud]
352164441.01.887761424030020.62826988690252-2.759570582863541.622395827442550.9446222968645832-1.154559012666870.364580675536746-0.135389346167279020.0345521682776357-0.97469507733035521.53126492421627-0.558651257008026-1.40204078796233-2.72556210859660.4057779092180571.431159483215741.956127100137552.26414005330485-0.8243269352259971-0.133303038078448980.1068235738572810.29362617939436403-0.136295490129905-0.73096267217823210.263143555477082-0.41954559365040990.02923912049066180.019826445101855148.8976.0[fraud]
36168878.0-4.80458628691832-4.350219221436540.85473394419768510.2078105803862342.91117776563597-2.16185200836836-2.10165901071884-1.60972469419277-1.245613056767151.136409004113531.56282964824949-0.656243196361657-1.353672680218550.4997651307796050.81534951867079510.77316997390809210.809416192491745-1.49110563925249022.03964533568703-2.16862341900588970.759812961941168-0.65509493945911791.646318675080590.04879335932347210.8261049032712451-0.09576068169313651.3059493867690302-0.57937853608619760.17960.0[fraud]
36623407.01.240746736507220.848160288821537-0.1998249517890071.553723837558020.171272503594932-1.194116483501410.228779262997882-0.3339504046228011.17298661915574-1.056222337416731.09596426457221-2.548640740955231.718976603118150.07083826639059470.336702692339511940.560484743900291.61892627448261050.8487676121649308-0.8297510609350229-0.13240918359282802-0.216617664690264-0.2968326218353089-0.1134421958930960.1949130118969550.67266243405551-0.3664718399033450.00942251427038020.05138885380081561.0902.0[fraud]
46753370.0-2.52338699856657-5.90958900863933-2.11454907610384042.68771715054533-1.71894595466850020.78834723929927012.62144747179771-0.387473414390844-0.304782617317214-0.75019119617736710.89256625998421490.679212965658016-0.5466734522705841.03001531809147-0.116777526168877-0.09147870610096-0.105836250043010.193687825429198-0.6820109170168113.676626072116961.17496005535309-0.8406424904120059-1.85015434331846-0.213489917842780.0526663052725845-0.42989130448891705-0.3449938939361070.3287425446865911918.5907.0[fraud]
\n", "
" ], "text/plain": [ " time va vb vc vd ve vf vg vh vi vj vk vl vm vn vo vp vq vr vs vt vu vv vw vx vy vz vaa vab amount score outcomes\n", "0 41505.0 -16.5265065691231 8.58497179585822 -18.649853185194498 9.50559351508723 -13.793818527095699 -2.8324042993974703 -16.701694296045 7.517343903709871 -8.50705863675898 -14.110184441545696 5.29923634963938 -10.8340064814734 1.67112025332681 -9.37385858364976 0.36080564163161705 -9.899246540806661 -19.2362923697613 -8.39855199494575 3.10173536885404 -1.51492343527852 1.19073869481428 -1.1276700090206102 -2.3585787697881 0.6734613289872371 -1.4136996745881998 -0.46276236139933 -2.01857524875161 -1.04280416970881 364.19 1000.0 [fraud]\n", "16 52913.0 0.676854829386595 1.58702920998622 -1.50814698254807 1.44381484435084 1.31678997910859 -1.1603421410518702 1.1490491098159 -0.4193931328245341 -0.0905654487115674 -0.323058484892761 2.967920897973221 -0.155026280352087 -0.7177661091303009 -3.70927517991521 0.731050307180359 0.51012502005825 2.7302621301168104 1.46374586218951 -0.578405585881194 0.31792704392540505 -0.191418401886823 0.101450781492372 0.05829839657805901 -0.135311156556857 -0.6044061673895129 -0.4527632157702071 0.0464301769729269 -0.3836415178705061 0.89 977.0 [fraud]\n", "19 55575.0 -3.41942263819263 -1.13007559809015 1.60708637375377 2.2299789220985096 2.64408903133496 -0.7935377223504201 1.08824220975816 -1.00840988415033 -0.933315168258216 1.92198175926539 1.9544453994250897 0.388839766922148 0.30147367767299 -0.427868493466856 -0.0292266721907548 -0.0750638320495107 -0.7991270792650841 -0.629796480633153 -0.469016593690311 -1.44533223472583 -0.479674205429058 0.524022264453329 0.093685026163671 0.30523015264387393 0.6539626403904271 0.0228521071220258 -0.955552398442486 -0.0856295445716383 22.7 953.0 [fraud]\n", "32 141655.0 -29.942972270707894 -25.8317821051362 -16.2275119291273 6.690679169572508 -20.7878458115363 13.0856943709389 17.2566228959585 -9.16174621113856 5.00304130464362 -2.4314663912742 1.7599893933563102 1.86143271752851 3.05338368623288 -1.4096397429751502 3.68027152852471 4.53127503027372 0.22001123266623696 -1.60453617589942 3.14031061569242 -21.3871219290332 -2.49469918146669 -0.660297208514391 -8.53781580651041 0.40080447201294 -0.643022787031134 0.4969028458312689 6.26770908866261 -2.7650700017587595 3502.11 962.0 [fraud]\n", "51 56803.0 1.17360912432855 0.511603445630379 -0.5204514757086011 1.12262620608436 0.35886736932159297 -0.29596043353185303 0.0250046387752933 0.14444171501870098 -0.110183833896483 -0.513358438415108 1.50090553458987 -0.228726450784267 -1.5703348271985802 -0.839677563070961 0.8255113303861942 0.6647743241018189 0.886274830361083 0.925736187467082 -0.5606318507221589 -0.20184199976003606 -0.0268349064777576 -0.0755364811334122 -0.129545704955994 -0.4816867297130711 0.582500674589865 -0.289875901401972 0.0379128239034746 0.0374365751819376 1.0 958.0 [fraud]\n", "59 94330.0 -0.159188253451539 1.6364222543563205 1.54599038025481 4.55479940392864 0.972500161314345 0.135619469003896 0.890709635187871 -0.308928981901544 -0.750671002033175 1.48808516225536 0.0189227146632523 -3.51495112016203 1.37852083915781 1.7509347239023998 0.0364873683299348 -0.332543453736555 0.8312407987466272 0.0272426739399668 1.11755527782445 0.374095700292396 -0.4149084993816161 -0.7253325636219929 0.0198138142745913 -0.0804172850283939 -0.5666438490691871 0.0294988448472911 0.206860492083663 0.00306000773670604 12.74 965.0 [fraud]\n", "177 58954.0 1.23804261799844 0.77053043333537 -0.331997523908519 1.34546451219451 0.139816295211697 -1.22967596595336 0.354259165638368 -0.280804576159513 -0.184996149214632 -0.699812889267707 0.230655066658352 0.21477524724131605 0.561439138721415 -1.4597942610637098 1.0212476623650102 0.567113655972287 0.859052402876907 0.516214961212954 -0.629783953300129 -0.0582422755483618 -0.0605703154557262 -0.0710964980063678 -0.131000023986718 0.269144247106671 0.7120999799201929 -0.32948917861264804 0.039308026136455 0.0588378743714698 1.0 947.0 [fraud]\n", "253 878.0 -2.5121924071651502 0.31783823871856204 1.27033280212107 1.21425795018979 1.17990250727029 -0.41223326510912106 1.00271608138525 -0.7746801839401241 1.65660199646692 2.7790737156669403 -0.0847781328647432 -0.18321933511528 -0.330652014184725 -1.2773505362658202 0.586282642874345 -1.56966184767482 0.122172327014581 -0.9167298664751452 0.6695246342509189 0.5929484938755051 -0.655257798829788 0.24236823281838 -0.135073900073597 0.104260701044715 0.211102067974728 -0.28730667236331103 0.335129131058453 0.32821181910776 18.8 962.0 [fraud]\n", "328 110199.0 1.75136324325772 0.337812400833952 0.795262392956418 4.31273176972153 -0.681348924648448 -0.126233056366034 -0.566591255980354 -0.0313440579660118 0.919522880708254 0.975130081266523 0.435764202447928 -2.21569585920562 1.91457117907994 1.15256247746996 -1.3746570764088202 0.8239809240929471 0.175328666447042 -0.0483307755538258 -2.38942182862032 -0.289943444109214 0.16007070110616595 0.803841115515162 0.25356928092348496 0.8074573633362009 -0.3400690874520441 -0.00655722686278409 -0.00813323923492112 -0.0250715519401937 29.58 955.0 [fraud]\n", "352 164441.0 1.88776142403002 0.62826988690252 -2.75957058286354 1.62239582744255 0.9446222968645832 -1.15455901266687 0.364580675536746 -0.13538934616727902 0.0345521682776357 -0.9746950773303552 1.53126492421627 -0.558651257008026 -1.40204078796233 -2.7255621085966 0.405777909218057 1.43115948321574 1.95612710013755 2.26414005330485 -0.8243269352259971 -0.13330303807844898 0.106823573857281 0.29362617939436403 -0.136295490129905 -0.7309626721782321 0.263143555477082 -0.4195455936504099 0.0292391204906618 0.0198264451018551 48.8 976.0 [fraud]\n", "361 68878.0 -4.80458628691832 -4.35021922143654 0.8547339441976851 0.207810580386234 2.91117776563597 -2.16185200836836 -2.10165901071884 -1.60972469419277 -1.24561305676715 1.13640900411353 1.56282964824949 -0.656243196361657 -1.35367268021855 0.499765130779605 0.8153495186707951 0.7731699739080921 0.809416192491745 -1.4911056392524902 2.03964533568703 -2.1686234190058897 0.759812961941168 -0.6550949394591179 1.64631867508059 0.0487933593234721 0.8261049032712451 -0.0957606816931365 1.3059493867690302 -0.579378536086197 60.17 960.0 [fraud]\n", "366 23407.0 1.24074673650722 0.848160288821537 -0.199824951789007 1.55372383755802 0.171272503594932 -1.19411648350141 0.228779262997882 -0.333950404622801 1.17298661915574 -1.05622233741673 1.09596426457221 -2.54864074095523 1.71897660311815 0.0708382663905947 0.33670269233951194 0.56048474390029 1.6189262744826105 0.8487676121649308 -0.8297510609350229 -0.13240918359282802 -0.216617664690264 -0.2968326218353089 -0.113442195893096 0.194913011896955 0.67266243405551 -0.366471839903345 0.0094225142703802 0.0513888538008156 1.0 902.0 [fraud]\n", "467 53370.0 -2.52338699856657 -5.90958900863933 -2.1145490761038404 2.68771715054533 -1.7189459546685002 0.7883472392992701 2.62144747179771 -0.387473414390844 -0.304782617317214 -0.7501911961773671 0.8925662599842149 0.679212965658016 -0.546673452270584 1.03001531809147 -0.116777526168877 -0.09147870610096 -0.10583625004301 0.193687825429198 -0.682010917016811 3.67662607211696 1.17496005535309 -0.8406424904120059 -1.85015434331846 -0.21348991784278 0.0526663052725845 -0.42989130448891705 -0.344993893936107 0.328742544686591 1918.5 907.0 [fraud]" ] }, "execution_count": 112, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# lets take a look to the predicted frauds\n", "predictions = pd.DataFrame.from_dict(predict_recs, orient='columns')\n", "predictions.loc[predictions['score'].astype('float32') > 900]" ] }, { "cell_type": "code", "execution_count": 113, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'ResponseMetadata': {'RequestId': '5B6ED35CCB4FB643',\n", " 'HostId': 'lfEj4Wi46OeQJbr7wiYy4Vh2xqAZdNFjHDXWIx449ZKcXRkZIb+RNiqI5eeyQ3fKi+Gv/0YZTtI=',\n", " 'HTTPStatusCode': 200,\n", " 'HTTPHeaders': {'x-amz-id-2': 'lfEj4Wi46OeQJbr7wiYy4Vh2xqAZdNFjHDXWIx449ZKcXRkZIb+RNiqI5eeyQ3fKi+Gv/0YZTtI=',\n", " 'x-amz-request-id': '5B6ED35CCB4FB643',\n", " 'date': 'Tue, 22 Sep 2020 22:57:06 GMT',\n", " 'x-amz-server-side-encryption': 'AES256',\n", " 'etag': '\"a349bb5bdc090d7f8ce04f7816ac60d5\"',\n", " 'content-length': '0',\n", " 'server': 'AmazonS3'},\n", " 'RetryAttempts': 0},\n", " 'ETag': '\"a349bb5bdc090d7f8ce04f7816ac60d5\"',\n", " 'ServerSideEncryption': 'AES256'}" ] }, "execution_count": 113, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# save the results to a csv file and upload it to the output s3 bucket\n", "csv_buffer = StringIO()\n", "predictions.to_csv(csv_buffer, index=False)\n", "s3_resource.Object(S3_BUCKET, MODEL_NAME + \"precictions{}.csv\".format(sufx)).put(Body=csv_buffer.getvalue())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finish" ] } ], "metadata": { "kernelspec": { "display_name": "conda_python3", "language": "python", "name": "conda_python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.10" } }, "nbformat": 4, "nbformat_minor": 2 }