diff --git a/Minor Project/ProjectSubmission.md b/Minor Project/ProjectSubmission.md index e661c66..ca2386e 100644 --- a/Minor Project/ProjectSubmission.md +++ b/Minor Project/ProjectSubmission.md @@ -1,9 +1,9 @@ -Roll Number : < Roll no. allotted for this internship eg - 23470 > +Roll Number : 23489 -Student Name : < Your good name > +Student Name : Yashika Rajora -Project Title : < Problem statement allotted to you > +Project Title : Flowcast:Credit Card Approval Fraud Detection -Google Colab Link : < View only link of your Google Colab Notebook > +Google Colab Link : https://colab.research.google.com/drive/1b7R2oEDCqZRISLzhRYMv21H4X7VUC2ou?usp=sharing -Summary(Optional) : < Brief summary of your project > \ No newline at end of file +Summary(Optional) : < Brief summary of your project > diff --git a/customer_lifetime_value_prediction.ipynb b/customer_lifetime_value_prediction.ipynb new file mode 100644 index 0000000..16dfbfe --- /dev/null +++ b/customer_lifetime_value_prediction.ipynb @@ -0,0 +1,13063 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "F9WuH6oiRJFE" + }, + "outputs": [], + "source": [ + "# pip install kaggle" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "q6oQ1qeSO7j1" + }, + "outputs": [], + "source": [ + "# !pip install opendatasets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "69wlOOtXRY7X" + }, + "outputs": [], + "source": [ + "# import opendatasets as od\n", + "# od.download(\"https://www.kaggle.com/datasets/sergeymedvedev/customer_segmentation?select=customer_segmentation.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "t5DjR5ywT1W1" + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "# Try reading the file with Latin-1 encoding\n", + "data = pd.read_csv(\"/content/customer_segmentation/customer_segmentation.csv\", encoding='latin-1')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "RulfNo3ET4P-", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 293 + }, + "outputId": "2d6c99e0-b57e-4fcf-c876-03bc38c7f506" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " InvoiceNo StockCode Description Quantity \\\n", + "0 536365 85123A WHITE HANGING HEART T-LIGHT HOLDER 6 \n", + "1 536365 71053 WHITE METAL LANTERN 6 \n", + "2 536365 84406B CREAM CUPID HEARTS COAT HANGER 8 \n", + "3 536365 84029G KNITTED UNION FLAG HOT WATER BOTTLE 6 \n", + "4 536365 84029E RED WOOLLY HOTTIE WHITE HEART. 6 \n", + "\n", + " InvoiceDate UnitPrice CustomerID Country \n", + "0 12/1/2010 8:26 2.55 17850.0 United Kingdom \n", + "1 12/1/2010 8:26 3.39 17850.0 United Kingdom \n", + "2 12/1/2010 8:26 2.75 17850.0 United Kingdom \n", + "3 12/1/2010 8:26 3.39 17850.0 United Kingdom \n", + "4 12/1/2010 8:26 3.39 17850.0 United Kingdom " + ], + "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", + "
InvoiceNoStockCodeDescriptionQuantityInvoiceDateUnitPriceCustomerIDCountry
053636585123AWHITE HANGING HEART T-LIGHT HOLDER612/1/2010 8:262.5517850.0United Kingdom
153636571053WHITE METAL LANTERN612/1/2010 8:263.3917850.0United Kingdom
253636584406BCREAM CUPID HEARTS COAT HANGER812/1/2010 8:262.7517850.0United Kingdom
353636584029GKNITTED UNION FLAG HOT WATER BOTTLE612/1/2010 8:263.3917850.0United Kingdom
453636584029ERED WOOLLY HOTTIE WHITE HEART.612/1/2010 8:263.3917850.0United Kingdom
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "data" + } + }, + "metadata": {}, + "execution_count": 48 + } + ], + "source": [ + "data.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YCamZwYdO1L7" + }, + "source": [ + "

Customer Lifetime prediction value

" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8IfuOcu7O1L9" + }, + "source": [ + "We invest in customers (acquisition costs, offline ads, promotions, discounts & etc.) to generate revenue and be profitable. Naturally, these actions make some customers super valuable in terms of lifetime value but there are always some customers who pull down the profitability. We need to identify these behavior patterns, segment customers and act accordingly.\n", + "Calculating Lifetime Value is the easy part. First we need to select a time window. It can be anything like 3, 6, 12, 24 months. By the equation below, we can have Lifetime Value for each customer in that specific time window:\n", + "\n", + "**Lifetime Value: Total Gross Revenue - Total Cost**\n", + "\n", + "This equation now gives us the historical lifetime value. If we see some customers having very high negative lifetime value historically, it could be too late to take an action.\n", + "\n", + "We are going to build a simple machine learning model that predicts our customers lifetime value.\n", + "\n", + "

Lifetime Value Prediction

\n", + "\n", + "* Define an appropriate time frame for Customer Lifetime Value calculation\n", + "* Identify the features we are going to use to predict future and create them\n", + "* Calculate lifetime value (LTV) for training the machine learning model\n", + "* Build and run the machine learning model\n", + "* Check if the model is useful\n", + "\n", + "**1. How to decide the timeframe**\n", + "\n", + "Deciding the time frame really depends on your industry, business model, strategy and more. For some industries, 1 year is a very long period while for the others it is very short. In our example, we will go ahead with 6 months.\n", + "\n", + "**2. Identifying the features for prediction**\n", + "\n", + "RFM scores for each customer ID (which we calculated in the previous article) are the perfect candidates for feature set. To implement it correctly, we need to split our dataset. We will take 3 months of data, calculate RFM and use it for predicting next 6 months. So we need to create two dataframes first and append RFM scores to them.\n", + "\n", + "After the first two steps, it is easy to calculate CLTV and train and test the model.\n", + "\n", + "- 1. Identifying the features \n", + "- 2. Importing necessary libraries and packages and reading files\n", + " - 2.1 Feature Engineering\n", + "- 3. Recency\n", + " - 3.1 Assigning a recency score \n", + " - 3.2 Ordering clusters\n", + "- 4. Frequency\n", + " - 4.1 Frequency clusters\n", + "- 5. Revenue\n", + " - 5.1 Revenue clusters\n", + "- 6. Overall score based on RFM Clustering \n", + "- 7. Customer Lifetime Value \n", + " - 7.1 Feature engineering\n", + "- 8. Machine Learning Model for Customer Lifetime Value Prediction \n", + "- 9. Final Clusters for Customer Lifetime Value \n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IuAe94sWO1L-" + }, + "source": [ + "

1. Identifying the features

" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "G4iLix3sO1L_" + }, + "source": [ + "

2. Importing relevant packages and libraries

" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "T2LbA3IeUia8", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "0265df55-fac3-4986-a94b-104ab1eb60a1" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Error: File not found at ../input/customer_segmentation/customer_segmentation.csv\n", + "Please make sure the file exists in the correct location.\n", + "If you are using a platform like Kaggle, ensure the dataset is added to your notebook.\n" + ] + } + ], + "source": [ + "import os\n", + "import pandas as pd\n", + "\n", + "# Check if the file exists\n", + "file_path = '../input/customer_segmentation/customer_segmentation.csv'\n", + "if os.path.exists(file_path):\n", + " # Read data if the file exists\n", + " tx_data = pd.read_csv(file_path, encoding='cp1252')\n", + " print(\"Data loaded successfully!\")\n", + "else:\n", + " print(f\"Error: File not found at {file_path}\")\n", + " print(\"Please make sure the file exists in the correct location.\")\n", + " print(\"If you are using a platform like Kaggle, ensure the dataset is added to your notebook.\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "aXbTXM12O1L_" + }, + "outputs": [], + "source": [ + "\n", + "#import libraries\n", + "from __future__ import division\n", + "\n", + "from datetime import datetime, timedelta,date\n", + "import pandas as pd\n", + "%matplotlib inline\n", + "from sklearn.metrics import classification_report,confusion_matrix\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import seaborn as sns\n", + "from sklearn.cluster import KMeans\n", + "\n", + "\n", + "import plotly as py\n", + "import plotly.offline as pyoff\n", + "import plotly.graph_objs as go\n", + "\n", + "import xgboost as xgb\n", + "from sklearn.model_selection import KFold, cross_val_score, train_test_split\n", + "\n", + "import xgboost as xgb\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8wzIlmpbW71J", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 293 + }, + "outputId": "3c29b099-f7d7-41f4-f165-ad5d2cec5947" + }, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/html": [ + " \n", + " " + ] + }, + "metadata": {} + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " InvoiceNo StockCode Description Quantity \\\n", + "0 536365 85123A WHITE HANGING HEART T-LIGHT HOLDER 6 \n", + "1 536365 71053 WHITE METAL LANTERN 6 \n", + "2 536365 84406B CREAM CUPID HEARTS COAT HANGER 8 \n", + "3 536365 84029G KNITTED UNION FLAG HOT WATER BOTTLE 6 \n", + "4 536365 84029E RED WOOLLY HOTTIE WHITE HEART. 6 \n", + "\n", + " InvoiceDate UnitPrice CustomerID Country \n", + "0 12/1/2010 8:26 2.55 17850.0 United Kingdom \n", + "1 12/1/2010 8:26 3.39 17850.0 United Kingdom \n", + "2 12/1/2010 8:26 2.75 17850.0 United Kingdom \n", + "3 12/1/2010 8:26 3.39 17850.0 United Kingdom \n", + "4 12/1/2010 8:26 3.39 17850.0 United Kingdom " + ], + "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", + "
InvoiceNoStockCodeDescriptionQuantityInvoiceDateUnitPriceCustomerIDCountry
053636585123AWHITE HANGING HEART T-LIGHT HOLDER612/1/2010 8:262.5517850.0United Kingdom
153636571053WHITE METAL LANTERN612/1/2010 8:263.3917850.0United Kingdom
253636584406BCREAM CUPID HEARTS COAT HANGER812/1/2010 8:262.7517850.0United Kingdom
353636584029GKNITTED UNION FLAG HOT WATER BOTTLE612/1/2010 8:263.3917850.0United Kingdom
453636584029ERED WOOLLY HOTTIE WHITE HEART.612/1/2010 8:263.3917850.0United Kingdom
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_data" + } + }, + "metadata": {}, + "execution_count": 51 + } + ], + "source": [ + "import plotly.offline as pyoff\n", + "import pandas as pd\n", + "\n", + "# Initialize Plotly in notebook mode\n", + "pyoff.init_notebook_mode(connected=True)\n", + "\n", + "# Load data from CSV, specify encoding as 'cp1252'\n", + "tx_data = pd.read_csv('/content/customer_segmentation/customer_segmentation.csv', encoding='cp1252')\n", + "\n", + "# Display the first few rows of the DataFrame\n", + "tx_data.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sO2n6T_2O1MB" + }, + "source": [ + "We have all the crucial information we need:\n", + "Customer ID\n", + "Unit Price\n", + "Quantity\n", + "Invoice Date\n", + "Revenue = Active Customer Count * Order Count * Average Revenue per Order\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_0fdKfH-O1MC" + }, + "source": [ + "

2.1 Feature Engineering

" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "huU-F1FBO1MC" + }, + "outputs": [], + "source": [ + "#converting the type of Invoice Date Field from string to datetime.\n", + "tx_data['InvoiceDate'] = pd.to_datetime(tx_data['InvoiceDate'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WFxG5zk0O1MD" + }, + "outputs": [], + "source": [ + "#creating YearMonth field for the ease of reporting and visualization\n", + "tx_data['InvoiceYearMonth'] = tx_data['InvoiceDate'].map(lambda date: 100*date.year + date.month)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "j2-PrRLxO1MD", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 300 + }, + "outputId": "80ee2cd2-eec6-4dd4-de8c-cb303a9d191b" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " Quantity InvoiceDate UnitPrice \\\n", + "count 541909.000000 541909 541909.000000 \n", + "mean 9.552250 2011-07-04 13:34:57.156386048 4.611114 \n", + "min -80995.000000 2010-12-01 08:26:00 -11062.060000 \n", + "25% 1.000000 2011-03-28 11:34:00 1.250000 \n", + "50% 3.000000 2011-07-19 17:17:00 2.080000 \n", + "75% 10.000000 2011-10-19 11:27:00 4.130000 \n", + "max 80995.000000 2011-12-09 12:50:00 38970.000000 \n", + "std 218.081158 NaN 96.759853 \n", + "\n", + " CustomerID InvoiceYearMonth \n", + "count 406829.000000 541909.000000 \n", + "mean 15287.690570 201099.713989 \n", + "min 12346.000000 201012.000000 \n", + "25% 13953.000000 201103.000000 \n", + "50% 15152.000000 201107.000000 \n", + "75% 16791.000000 201110.000000 \n", + "max 18287.000000 201112.000000 \n", + "std 1713.600303 25.788703 " + ], + "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", + "
QuantityInvoiceDateUnitPriceCustomerIDInvoiceYearMonth
count541909.000000541909541909.000000406829.000000541909.000000
mean9.5522502011-07-04 13:34:57.1563860484.61111415287.690570201099.713989
min-80995.0000002010-12-01 08:26:00-11062.06000012346.000000201012.000000
25%1.0000002011-03-28 11:34:001.25000013953.000000201103.000000
50%3.0000002011-07-19 17:17:002.08000015152.000000201107.000000
75%10.0000002011-10-19 11:27:004.13000016791.000000201110.000000
max80995.0000002011-12-09 12:50:0038970.00000018287.000000201112.000000
std218.081158NaN96.7598531713.60030325.788703
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "summary": "{\n \"name\": \"tx_data\",\n \"rows\": 8,\n \"fields\": [\n {\n \"column\": \"Quantity\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 196412.4226608867,\n \"min\": -80995.0,\n \"max\": 541909.0,\n \"num_unique_values\": 8,\n \"samples\": [\n 9.55224954743324,\n 10.0,\n 541909.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"InvoiceDate\",\n \"properties\": {\n \"dtype\": \"date\",\n \"min\": \"1970-01-01 00:00:00.000541909\",\n \"max\": \"2011-12-09 12:50:00\",\n \"num_unique_values\": 7,\n \"samples\": [\n \"541909\",\n \"2011-07-04 13:34:57.156386048\",\n \"2011-10-19 11:27:00\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"UnitPrice\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 190752.07570771928,\n \"min\": -11062.06,\n \"max\": 541909.0,\n \"num_unique_values\": 8,\n \"samples\": [\n 4.611113626088513,\n 4.13,\n 541909.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 139204.1680069419,\n \"min\": 1713.600303321598,\n \"max\": 406829.0,\n \"num_unique_values\": 8,\n \"samples\": [\n 15287.690570239585,\n 16791.0,\n 406829.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"InvoiceYearMonth\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 148392.75129663633,\n \"min\": 25.788702574753856,\n \"max\": 541909.0,\n \"num_unique_values\": 8,\n \"samples\": [\n 201099.71398888004,\n 201110.0,\n 541909.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 54 + } + ], + "source": [ + "tx_data.describe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pVkRPygEO1ME", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "outputId": "a4fa7729-9654-4a65-b3fa-78cff035be03" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "Country\n", + "United Kingdom 495478\n", + "Germany 9495\n", + "France 8557\n", + "EIRE 8196\n", + "Spain 2533\n", + "Netherlands 2371\n", + "Belgium 2069\n", + "Switzerland 2002\n", + "Portugal 1519\n", + "Australia 1259\n", + "Norway 1086\n", + "Italy 803\n", + "Channel Islands 758\n", + "Finland 695\n", + "Cyprus 622\n", + "Sweden 462\n", + "Unspecified 446\n", + "Austria 401\n", + "Denmark 389\n", + "Japan 358\n", + "Poland 341\n", + "Israel 297\n", + "USA 291\n", + "Hong Kong 288\n", + "Singapore 229\n", + "Iceland 182\n", + "Canada 151\n", + "Greece 146\n", + "Malta 127\n", + "United Arab Emirates 68\n", + "European Community 61\n", + "RSA 58\n", + "Lebanon 45\n", + "Lithuania 35\n", + "Brazil 32\n", + "Czech Republic 30\n", + "Bahrain 19\n", + "Saudi Arabia 10\n", + "Name: count, dtype: int64" + ], + "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", + "
count
Country
United Kingdom495478
Germany9495
France8557
EIRE8196
Spain2533
Netherlands2371
Belgium2069
Switzerland2002
Portugal1519
Australia1259
Norway1086
Italy803
Channel Islands758
Finland695
Cyprus622
Sweden462
Unspecified446
Austria401
Denmark389
Japan358
Poland341
Israel297
USA291
Hong Kong288
Singapore229
Iceland182
Canada151
Greece146
Malta127
United Arab Emirates68
European Community61
RSA58
Lebanon45
Lithuania35
Brazil32
Czech Republic30
Bahrain19
Saudi Arabia10
\n", + "

" + ] + }, + "metadata": {}, + "execution_count": 55 + } + ], + "source": [ + "tx_data['Country'].value_counts()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Hs--bgmPO1ME" + }, + "source": [ + "Starting from this part, we will be focusing on UK data only (which has the most records). We can get the monthly active customers by counting unique CustomerIDs. The same analysis can be carried out for customers of other countries as well." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "BTwLXOvnO1ME" + }, + "outputs": [], + "source": [ + "#we will be using only UK data\n", + "tx_uk = tx_data.query(\"Country=='United Kingdom'\").reset_index(drop=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "oLuM42fjO1ME" + }, + "source": [ + "**Segmentation Techniques**\n", + "\n", + "You can do many different segmentations according to what you are trying to achieve. If you want to increase retention rate, you can do a segmentation based on churn probability and take actions. But there are very common and useful segmentation methods as well. Now we are going to implement one of them to our business: RFM.\n", + "RFM stands for Recency - Frequency - Monetary Value. Theoretically we will have segments like below:\n", + "\n", + "* Low Value: Customers who are less active than others, not very frequent buyer/visitor and generates very low - zero - maybe negative revenue.\n", + "* Mid Value: In the middle of everything. Often using our platform (but not as much as our High Values), fairly frequent and generates moderate revenue.\n", + "* High Value: The group we don’t want to lose. High Revenue, Frequency and low Inactivity.\n", + "\n", + "As the methodology, we need to calculate Recency, Frequency and Monetary Value (we will call it Revenue from now on) and apply unsupervised machine learning to identify different groups (clusters) for each. Let’s jump into coding and see how to do RFM Clustering.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3-mxLNAsO1ME" + }, + "source": [ + "

3. Recency

\n", + "\n", + "To calculate recency, we need to find out most recent purchase date of each customer and see how many days they are inactive for. After having no. of inactive days for each customer, we will apply K-means* clustering to assign customers a recency score.\n", + "\n", + "Lets go ahead and calculate that." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "En8CHNYJO1ME", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "c0d02f79-a82c-4b17-8ee9-78898b07bde6" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID\n", + "0 17850.0\n", + "1 13047.0\n", + "2 12583.0\n", + "3 13748.0\n", + "4 15100.0" + ], + "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", + "
CustomerID
017850.0
113047.0
212583.0
313748.0
415100.0
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_user", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 4373,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1722.390705427691,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 4372,\n \"samples\": [\n 14633.0,\n 13050.0,\n 17975.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 57 + } + ], + "source": [ + "#create a generic user dataframe to keep CustomerID and new segmentation scores\n", + "tx_user = pd.DataFrame(tx_data['CustomerID'].unique())\n", + "tx_user.columns = ['CustomerID']\n", + "tx_user.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "AriZIC_qO1MF", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 538 + }, + "outputId": "6e1d50e1-a8e5-450e-cc3b-83c017dedeee" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " InvoiceNo StockCode Description Quantity \\\n", + "0 536365 85123A WHITE HANGING HEART T-LIGHT HOLDER 6 \n", + "1 536365 71053 WHITE METAL LANTERN 6 \n", + "2 536365 84406B CREAM CUPID HEARTS COAT HANGER 8 \n", + "3 536365 84029G KNITTED UNION FLAG HOT WATER BOTTLE 6 \n", + "4 536365 84029E RED WOOLLY HOTTIE WHITE HEART. 6 \n", + "\n", + " InvoiceDate UnitPrice CustomerID Country InvoiceYearMonth \n", + "0 2010-12-01 08:26:00 2.55 17850.0 United Kingdom 201012 \n", + "1 2010-12-01 08:26:00 3.39 17850.0 United Kingdom 201012 \n", + "2 2010-12-01 08:26:00 2.75 17850.0 United Kingdom 201012 \n", + "3 2010-12-01 08:26:00 3.39 17850.0 United Kingdom 201012 \n", + "4 2010-12-01 08:26:00 3.39 17850.0 United Kingdom 201012 " + ], + "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", + "
InvoiceNoStockCodeDescriptionQuantityInvoiceDateUnitPriceCustomerIDCountryInvoiceYearMonth
053636585123AWHITE HANGING HEART T-LIGHT HOLDER62010-12-01 08:26:002.5517850.0United Kingdom201012
153636571053WHITE METAL LANTERN62010-12-01 08:26:003.3917850.0United Kingdom201012
253636584406BCREAM CUPID HEARTS COAT HANGER82010-12-01 08:26:002.7517850.0United Kingdom201012
353636584029GKNITTED UNION FLAG HOT WATER BOTTLE62010-12-01 08:26:003.3917850.0United Kingdom201012
453636584029ERED WOOLLY HOTTIE WHITE HEART.62010-12-01 08:26:003.3917850.0United Kingdom201012
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_uk" + } + }, + "metadata": {}, + "execution_count": 58 + } + ], + "source": [ + "tx_uk.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7fguh8DxO1MF" + }, + "source": [ + "Since we are calculating recency, we need to know when last the person bought something. Let us calculate the last date of transaction for a person." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "sLG_dwdsO1MF", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "cdc273df-a8cb-4520-d883-f384ffa070e2" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID MaxPurchaseDate\n", + "0 12346.0 2011-01-18 10:17:00\n", + "1 12747.0 2011-12-07 14:34:00\n", + "2 12748.0 2011-12-09 12:20:00\n", + "3 12749.0 2011-12-06 09:56:00\n", + "4 12820.0 2011-12-06 15:12:00" + ], + "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", + "
CustomerIDMaxPurchaseDate
012346.02011-01-18 10:17:00
112747.02011-12-07 14:34:00
212748.02011-12-09 12:20:00
312749.02011-12-06 09:56:00
412820.02011-12-06 15:12:00
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_max_purchase", + "summary": "{\n \"name\": \"tx_max_purchase\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 17160.0,\n 15758.0,\n 15349.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"MaxPurchaseDate\",\n \"properties\": {\n \"dtype\": \"date\",\n \"min\": \"2010-12-01 09:53:00\",\n \"max\": \"2011-12-09 12:49:00\",\n \"num_unique_values\": 3836,\n \"samples\": [\n \"2011-08-12 16:54:00\",\n \"2011-03-04 14:13:00\",\n \"2010-12-02 17:03:00\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 59 + } + ], + "source": [ + "#get the max purchase date for each customer and create a dataframe with it\n", + "tx_max_purchase = tx_uk.groupby('CustomerID').InvoiceDate.max().reset_index()\n", + "tx_max_purchase.columns = ['CustomerID','MaxPurchaseDate']\n", + "tx_max_purchase.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gH4XygopO1MF", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "af2ddd48-3839-4ad5-cb4d-7bf076b80074" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID MaxPurchaseDate Recency\n", + "0 12346.0 2011-01-18 10:17:00 325\n", + "1 12747.0 2011-12-07 14:34:00 1\n", + "2 12748.0 2011-12-09 12:20:00 0\n", + "3 12749.0 2011-12-06 09:56:00 3\n", + "4 12820.0 2011-12-06 15:12:00 2" + ], + "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", + "
CustomerIDMaxPurchaseDateRecency
012346.02011-01-18 10:17:00325
112747.02011-12-07 14:34:001
212748.02011-12-09 12:20:000
312749.02011-12-06 09:56:003
412820.02011-12-06 15:12:002
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_max_purchase", + "summary": "{\n \"name\": \"tx_max_purchase\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 17160.0,\n 15758.0,\n 15349.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"MaxPurchaseDate\",\n \"properties\": {\n \"dtype\": \"date\",\n \"min\": \"2010-12-01 09:53:00\",\n \"max\": \"2011-12-09 12:49:00\",\n \"num_unique_values\": 3836,\n \"samples\": [\n \"2011-08-12 16:54:00\",\n \"2011-03-04 14:13:00\",\n \"2010-12-02 17:03:00\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 283,\n 129,\n 171\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 60 + } + ], + "source": [ + "# Compare the last transaction of the dataset with last transaction dates of the individual customer IDs.\n", + "tx_max_purchase['Recency'] = (tx_max_purchase['MaxPurchaseDate'].max() - tx_max_purchase['MaxPurchaseDate']).dt.days\n", + "tx_max_purchase.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "lqhsgB-MO1MF", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "d25477ef-4dc8-4a2c-8153-420cd963c106" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Recency\n", + "0 17850.0 301\n", + "1 13047.0 31\n", + "2 13748.0 95\n", + "3 15100.0 329\n", + "4 15291.0 25" + ], + "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", + "
CustomerIDRecency
017850.0301
113047.031
213748.095
315100.0329
415291.025
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_user", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 16189.0,\n 13740.0,\n 16023.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 76,\n 252,\n 248\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 61 + } + ], + "source": [ + "#merge this dataframe to our new user dataframe\n", + "tx_user = pd.merge(tx_user, tx_max_purchase[['CustomerID','Recency']], on='CustomerID')\n", + "tx_user.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gzr0uKd-O1MF" + }, + "source": [ + "\\\\

3.1 Assigning a recency score

\n", + "\n", + "We are going to apply K-means clustering to assign a recency score. But we should tell how many clusters we need to K-means algorithm. To find it out, we will apply Elbow Method. Elbow Method simply tells the optimal cluster number for optimal inertia. Code snippet and Inertia graph are as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PS3PXH7OO1MF", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "outputId": "0ea21c49-f623-4610-96db-ed8bfa04d151" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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+vfvr+LiYj322GO65pprtGXLFsXHx5tdXlDs3r1bL7zwgmbPnq2HH35Ya9as0S9+8QtFRUVp2rRpZpcXVEuXLtWJEyd0++23m11K0Dz00ENyOp0aMGCAbDab3G63nnzySU2dOtXs0oImPj5eWVlZeuKJJzRw4EAlJyfrrbfeUn5+vi699NLWLaZVn8O0QQrz1zT33nuv0bNnT6OoqMjsUoLO5XIZ33//vbF27VrjoYceMjp37mxs3brV7LKCorCw0OjatauxceNG375wek1ztuPHjxsOhyOsXrNFRkYaWVlZfvt+/vOfG6NGjTKpopZz0003GTfffLPZZQTVW2+9ZaSlpRlvvfWWsWnTJuONN94wEhMTjYULF5pdWlDt3LnTuPbaaw1Jhs1mM6644gpj6tSpxoABA1q1DsJIGIeR6dOnG2lpacbu3bvNLqVV3HDDDca///u/m11GUCxZssT3HwfvJsmwWCyGzWYzamtrzS4x6C6//HLjoYceMruMoOnRo4dx1113+e3705/+ZKSmpppUUcvYu3evYbVajaVLl5pdSlClpaUZzz//vN++J554wujfv79JFbWsiooK4+DBg4ZhGMatt95q/OhHP2rV69NnJAwZhqEZM2ZoyZIl+uSTT9SrVy+zS2oVHo9HLpfL7DKC4oYbbtDmzZtVUFDg2y6//HJNnTpVBQUFstlsZpcYVBUVFdq1a5e6detmdilBc9VVV50zpP67775Tz549TaqoZSxYsEBdu3bV+PHjzS4lqE6ePCmr1f9XpM1mk8fjMamilhUbG6tu3brp+PHjWr58uSZOnNiq12+XfUYqKiq0c+dO3+c9e/aooKBAiYmJ6tGjh4mVBcf06dO1aNEivffee4qPj1dJSYkkKSEhQTExMSZXFxy5ubkaN26cevToofLyci1atEirVq3S8uXLzS4tKOLj48/p4xMbG6ukpKSw6PvzwAMPaMKECerZs6cOHjyoOXPmyGaz6bbbbjO7tKC57777lJ2drd/97ne69dZb9c033+jll1/Wyy+/bHZpQePxeLRgwQJNmzYt7IZmT5gwQU8++aR69OihwYMHa8OGDXr66ad15513ml1aUC1fvlyGYah///7auXOnHnzwQQ0YMEB33HFH6xbSqs9h2ohPP/3UkHTONm3aNLNLC4qG7k2SsWDBArNLC5o777zT6NmzpxEVFWV06dLFuOGGG4yPP/7Y7LJaVDj1GZkyZYrRrVs3IyoqyujevbsxZcoUY+fOnWaXFXR///vfjSFDhhh2u90YMGCA8fLLL5tdUlAtX77ckGTs2LHD7FKCzul0GjNnzjR69OhhREdHG7179zZ+/etfGy6Xy+zSgurtt982evfubURFRRkpKSnG9OnTjRMnTrR6HazaCwAATEWfEQAAYCrCCAAAMBVhBAAAmIowAgAATEUYAQAApiKMAAAAUxFGAACAqQgjAADAVIQRAD579+6VxWJRQUGB2aX4bN++XaNGjVJ0dLSGDRsW8PFt8Z4A+COMAG3I7bffLovForlz5/rtX7p0qSwWi0lVmWvOnDmKjY3Vjh07tHLlSrPL0cKFC9WxY0ezywDCCmEEaGOio6M1b948HT9+3OxSgqa6urrZx+7atUtXX321evbsqaSkpCBWZS632x22K8ACgSKMAG3MmDFjlJKSory8vEbbPProo+e8snj22Wd1ySWX+D7ffvvtmjRpkn73u98pOTlZHTt21OOPP67a2lo9+OCDSkxMVFpamhYsWHDO+bdv367s7GxFR0dryJAh+uyzz/y+37Jli8aNG6e4uDglJyfr3/7t33TkyBHf99ddd51mzJihWbNmqXPnzho7dmyD9+HxePT4448rLS1Ndrtdw4YN07Jly3zfWywWrVu3To8//rgsFoseffTRRs/z+9//Xpdeeqnsdrt69OihJ598ssG2DT3ZOPvJ08aNG3X99dcrPj5eDodDI0aM0Nq1a7Vq1SrdcccdKisrk8Vi8avJ5XLpgQceUPfu3RUbG6uRI0dq1apV51z3/fff16BBg2S321VYWNhgjUB7QxgB2hibzabf/e53+uMf/6j9+/df1Lk++eQTHTx4UKtXr9bTTz+tOXPm6Oabb1anTp309ddf695779V//Md/nHOdBx98UPfff782bNigrKwsTZgwQUePHpUknThxQj/4wQ80fPhwrV27VsuWLVNpaaluvfVWv3O8/vrrioqK0hdffKEXX3yxwfqee+45PfXUU/p//+//adOmTRo7dqz+5V/+Rd9//70kqbi4WIMHD9b999+v4uJiPfDAAw2eJzc3V3PnztUjjzyibdu2adGiRUpOTm7239vUqVOVlpamNWvWaN26dXrooYcUGRmp7OxsPfvss3I4HCouLvaracaMGcrPz9fixYu1adMmTZ48WT/84Q999yJJJ0+e1Lx58/Tqq69q69at6tq1a7NrBMJKq68TDKBR06ZNMyZOnGgYhmGMGjXKuPPOOw3DMIwlS5YYZ/7rOmfOHCMzM9Pv2Geeecbo2bOn37l69uxpuN1u377+/fsb11xzje9zbW2tERsba7z11luGYRjGnj17DEnG3LlzfW1qamqMtLQ0Y968eYZhGMYTTzxh3HTTTX7XLioq8ltKfvTo0cbw4cMveL+pqanGk08+6bfviiuuMH72s5/5PmdmZhpz5sxp9BxOp9Ow2+3GK6+80uD33nvasGGDYRiGsWDBAiMhIcGvzdl/v/Hx8cbChQsbPF9Dx+/bt8+w2WzGgQMH/PbfcMMNRm5uru84SUZBQUGj9wK0VxFmBiEAjZs3b55+8IMfNPo0oCkGDx4sq/X0A9Dk5GQNGTLE99lmsykpKUmHDh3yOy4rK8v3c0REhC6//HJ9++23kupeYXz66aeKi4s753q7du1Sv379JEkjRow4b21Op1MHDx7UVVdd5bf/qquu0saNG5t4h9K3334rl8ulG264ocnHXMjs2bN19913689//rPGjBmjyZMnq0+fPo2237x5s9xut+/evVwul18/l6ioKGVkZAStTiBcEEaANuraa6/V2LFjlZubq9tvv93vO6vVKsMw/PbV1NScc47IyEi/zxaLpcF9gXSkrKio0IQJEzRv3rxzvuvWrZvv59jY2Caf82LExMQE1L4pf3ePPvqo/vVf/1X/+Mc/9NFHH2nOnDlavHixfvzjHzd4zoqKCtlsNq1bt042m83vuzNDW0xMTLsdFQWcD31GgDZs7ty5+vvf/678/Hy//V26dFFJSYnfL9VgzqPx1Vdf+X6ura3VunXrNHDgQEnSZZddpq1bt+qSSy7RpZde6rcFEkAcDodSU1P1xRdf+O3/4osvNGjQoCafp2/fvoqJiWnysN8uXbqovLxclZWVvn0N/d3169dP9913nz7++GPdcsstvo6+UVFRcrvdfm2HDx8ut9utQ4cOnfN3kpKS0uR7AdorwgjQhg0dOlRTp07Vf/3Xf/ntv+6663T48GH9/ve/165duzR//nx99NFHQbvu/PnztWTJEm3fvl3Tp0/X8ePHdeedd0qSpk+frmPHjum2227TmjVrtGvXLi1fvlx33HHHOb+kL+TBBx/UvHnz9Pbbb2vHjh166KGHVFBQoJkzZzb5HNHR0frVr36lX/7yl3rjjTe0a9cuffXVV/rv//7vBtuPHDlSHTp00MMPP6xdu3Zp0aJFWrhwoe/7U6dOacaMGVq1apX27dunL774QmvWrPGFsUsuuUQVFRVauXKljhw5opMnT6pfv36aOnWqcnJy9O6772rPnj365ptvlJeXp3/84x8B/Z0A7RFhBGjjHn/88XNeowwcOFB/+tOfNH/+fGVmZuqbb765qL4lZ5s7d67mzp2rzMxMff7553r//ffVuXNnSfI9zXC73brppps0dOhQzZo1Sx07dvTrn9IUv/jFLzR79mzdf//9Gjp0qJYtW6b3339fffv2Deg8jzzyiO6//3799re/1cCBAzVlypRz+sF4JSYm6s0339SHH36ooUOH6q233vIbMmyz2XT06FHl5OSoX79+uvXWWzVu3Dg99thjkqTs7Gzde++9mjJlirp06aLf//73kqQFCxYoJydH999/v/r3769JkyZpzZo16tGjR0D3ArRHFuPsl6cAAACtiCcjAADAVIQRAABgKsIIAAAwFWEEAACYijACAABMRRgBAACmIowAAABTEUYAAICpCCMAAMBUhBEAAGAqwggAADAVYQQAAJjq/weN41ArJ8lIswAAAABJRU5ErkJggg==\n" + }, + "metadata": {} + } + ], + "source": [ + "from sklearn.cluster import KMeans\n", + "\n", + "sse={} # error\n", + "tx_recency = tx_user[['Recency']]\n", + "for k in range(1, 10):\n", + " kmeans = KMeans(n_clusters=k, max_iter=1000).fit(tx_recency)\n", + " tx_recency[\"clusters\"] = kmeans.labels_ #cluster names corresponding to recency values\n", + " sse[k] = kmeans.inertia_ #sse corresponding to clusters\n", + "plt.figure()\n", + "plt.plot(list(sse.keys()), list(sse.values()))\n", + "plt.xlabel(\"Number of cluster\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aLVKWpNJO1MG" + }, + "source": [ + "Here it looks like 3 is the optimal one. Based on business requirements, we can go ahead with less or more clusters. We will be selecting 4 for this example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "AnxjkIHPO1MG", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "52e7b9ce-44e7-4d3d-fd7c-af94a2454667" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n" + ] + } + ], + "source": [ + "#build 4 clusters for recency and add it to dataframe\n", + "kmeans = KMeans(n_clusters=4)\n", + "tx_user['RecencyCluster'] = kmeans.fit_predict(tx_user[['Recency']])\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jSZvJQNyO1MG", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "9fc305ac-c7f8-4641-b2fd-f6de412da836" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Recency RecencyCluster\n", + "0 17850.0 301 1\n", + "1 13047.0 31 2\n", + "2 13748.0 95 0\n", + "3 15100.0 329 1\n", + "4 15291.0 25 2" + ], + "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", + "
CustomerIDRecencyRecencyCluster
017850.03011
113047.0312
213748.0950
315100.03291
415291.0252
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_user", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 16189.0,\n 13740.0,\n 16023.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 76,\n 252,\n 248\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"int32\",\n \"num_unique_values\": 4,\n \"samples\": [\n 2,\n 3,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 64 + } + ], + "source": [ + "tx_user.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "yAgz_qk5O1MG", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "9a82ed31-8374-48d7-e362-a82be4f451da" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " count mean std min 25% 50% 75% \\\n", + "RecencyCluster \n", + "0 954.0 77.679245 22.850898 48.0 59.00 72.5 93.00 \n", + "1 478.0 304.393305 41.183489 245.0 266.25 300.0 336.00 \n", + "2 1950.0 17.488205 13.237058 0.0 6.00 16.0 28.00 \n", + "3 568.0 184.625000 31.753602 132.0 156.75 184.0 211.25 \n", + "\n", + " max \n", + "RecencyCluster \n", + "0 131.0 \n", + "1 373.0 \n", + "2 47.0 \n", + "3 244.0 " + ], + "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", + "
countmeanstdmin25%50%75%max
RecencyCluster
0954.077.67924522.85089848.059.0072.593.00131.0
1478.0304.39330541.183489245.0266.25300.0336.00373.0
21950.017.48820513.2370580.06.0016.028.0047.0
3568.0184.62500031.753602132.0156.75184.0211.25244.0
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 4,\n \"fields\": [\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"int32\",\n \"num_unique_values\": 4,\n \"samples\": [\n 1,\n 3,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"count\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 674.06700952749,\n \"min\": 478.0,\n \"max\": 1950.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 478.0,\n 568.0,\n 954.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"mean\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 126.17887851902452,\n \"min\": 17.488205128205127,\n \"max\": 304.39330543933056,\n \"num_unique_values\": 4,\n \"samples\": [\n 304.39330543933056,\n 184.625,\n 77.67924528301887\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"std\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 11.974125219307917,\n \"min\": 13.237058477856872,\n \"max\": 41.183489256909944,\n \"num_unique_values\": 4,\n \"samples\": [\n 41.183489256909944,\n 31.753601776012104,\n 22.850897908212414\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"min\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 107.38831407560136,\n \"min\": 0.0,\n \"max\": 245.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 245.0,\n 132.0,\n 48.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"25%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 114.65982295468626,\n \"min\": 6.0,\n \"max\": 266.25,\n \"num_unique_values\": 4,\n \"samples\": [\n 266.25,\n 156.75,\n 59.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"50%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 125.73674549099267,\n \"min\": 16.0,\n \"max\": 300.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 300.0,\n 184.0,\n 72.5\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"75%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 135.78910962101,\n \"min\": 28.0,\n \"max\": 336.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 336.0,\n 211.25,\n 93.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"max\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 141.4552343794083,\n \"min\": 47.0,\n \"max\": 373.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 373.0,\n 244.0,\n 131.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 65 + } + ], + "source": [ + "tx_user.groupby('RecencyCluster')['Recency'].describe()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HUFV41OKO1MG" + }, + "source": [ + "

3.2 Ordering clusters

\n", + "\n", + "We have a cluster corresponding to each customerID. But each cluster is randomly assigned. Cluster 2 is not better than cluster 1 for e.g. and so on. We want to give clusters according to most recent transactions.\n", + "\n", + "We will first find the mean of recency value corresponding to each cluster. Then we will sort these values. Let's say cluster 3 has the most recent transactions mean value. From the above table we see that cluster 1(mean recency 304) > cluster 2 > cluster 3 > cluster 0. That means that cluster 1 is most inactive and cluster 0 is most recent. We will give indices to these clusters as 0,1,2,3. So cluster 1 becomes cluster 0, cluster 2 becomes cluster 1, cluster 3 becomes cluster 2 and so on. Now we will drop the original cluster numbers and replace them with 0,1,2,3. Code is below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8_1qP5jaO1MG" + }, + "outputs": [], + "source": [ + "#function for ordering cluster numbers\n", + "def order_cluster(cluster_field_name, target_field_name,df,ascending):\n", + " new_cluster_field_name = 'new_' + cluster_field_name\n", + " df_new = df.groupby(cluster_field_name)[target_field_name].mean().reset_index()\n", + " df_new = df_new.sort_values(by=target_field_name,ascending=ascending).reset_index(drop=True)\n", + " df_new['index'] = df_new.index\n", + " df_final = pd.merge(df,df_new[[cluster_field_name,'index']], on=cluster_field_name)\n", + " df_final = df_final.drop([cluster_field_name],axis=1)\n", + " df_final = df_final.rename(columns={\"index\":cluster_field_name})\n", + " return df_final\n", + "\n", + "tx_user = order_cluster('RecencyCluster', 'Recency',tx_user,False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xR2X2kg-O1MG", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "f8df2fa7-501b-4b31-d997-bb192f6fe3ee" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Recency RecencyCluster\n", + "0 17850.0 301 0\n", + "1 15100.0 329 0\n", + "2 18074.0 373 0\n", + "3 16250.0 260 0\n", + "4 13747.0 373 0" + ], + "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", + "
CustomerIDRecencyRecencyCluster
017850.03010
115100.03290
218074.03730
316250.02600
413747.03730
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_user", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 13067.0,\n 17947.0,\n 16968.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 169,\n 0,\n 161\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 3,\n 1,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 67 + } + ], + "source": [ + "tx_user.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TkmwGorBO1MH", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "e1eebde4-61b6-4100-bdaa-c06c34aaa5d6" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " count mean std min 25% 50% 75% \\\n", + "RecencyCluster \n", + "0 478.0 304.393305 41.183489 245.0 266.25 300.0 336.00 \n", + "1 568.0 184.625000 31.753602 132.0 156.75 184.0 211.25 \n", + "2 954.0 77.679245 22.850898 48.0 59.00 72.5 93.00 \n", + "3 1950.0 17.488205 13.237058 0.0 6.00 16.0 28.00 \n", + "\n", + " max \n", + "RecencyCluster \n", + "0 373.0 \n", + "1 244.0 \n", + "2 131.0 \n", + "3 47.0 " + ], + "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", + "
countmeanstdmin25%50%75%max
RecencyCluster
0478.0304.39330541.183489245.0266.25300.0336.00373.0
1568.0184.62500031.753602132.0156.75184.0211.25244.0
2954.077.67924522.85089848.059.0072.593.00131.0
31950.017.48820513.2370580.06.0016.028.0047.0
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 4,\n \"fields\": [\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 1,\n 3,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"count\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 674.06700952749,\n \"min\": 478.0,\n \"max\": 1950.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 568.0,\n 1950.0,\n 478.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"mean\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 126.17887851902452,\n \"min\": 17.488205128205127,\n \"max\": 304.39330543933056,\n \"num_unique_values\": 4,\n \"samples\": [\n 184.625,\n 17.488205128205127,\n 304.39330543933056\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"std\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 11.974125219307917,\n \"min\": 13.237058477856872,\n \"max\": 41.183489256909944,\n \"num_unique_values\": 4,\n \"samples\": [\n 31.753601776012104,\n 13.237058477856872,\n 41.183489256909944\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"min\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 107.38831407560136,\n \"min\": 0.0,\n \"max\": 245.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 132.0,\n 0.0,\n 245.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"25%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 114.65982295468626,\n \"min\": 6.0,\n \"max\": 266.25,\n \"num_unique_values\": 4,\n \"samples\": [\n 156.75,\n 6.0,\n 266.25\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"50%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 125.73674549099267,\n \"min\": 16.0,\n \"max\": 300.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 184.0,\n 16.0,\n 300.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"75%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 135.78910962101,\n \"min\": 28.0,\n \"max\": 336.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 211.25,\n 28.0,\n 336.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"max\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 141.4552343794083,\n \"min\": 47.0,\n \"max\": 373.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 244.0,\n 47.0,\n 373.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 68 + } + ], + "source": [ + "tx_user.groupby('RecencyCluster')['Recency'].describe()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tQAvdnJmO1MH" + }, + "source": [ + "Great! cluster 1 earlier is now cluster0, cluster 2 earlier is now cluster 1 and so on. The clusters are arranged according to inactiviuty. Cluster 0 now is most inactive, cluster 3 is most active." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "k9DV2TEzO1MH" + }, + "source": [ + "

4. Frequency

\n", + "\n", + "To create frequency clusters, we need to find total number orders for each customer. First calculate this and see how frequency look like in our customer database" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rRQH30JpO1MH" + }, + "outputs": [], + "source": [ + "#get order counts for each user and create a dataframe with it\n", + "tx_frequency = tx_uk.groupby('CustomerID').InvoiceDate.count().reset_index()\n", + "tx_frequency.columns = ['CustomerID','Frequency']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "RR6vbiWkO1MH", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "0da3050e-c1fc-480b-ab17-f99cec0eb5cc" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Frequency\n", + "0 12346.0 2\n", + "1 12747.0 103\n", + "2 12748.0 4642\n", + "3 12749.0 231\n", + "4 12820.0 59" + ], + "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", + "
CustomerIDFrequency
012346.02
112747.0103
212748.04642
312749.0231
412820.059
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_frequency", + "summary": "{\n \"name\": \"tx_frequency\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 17160.0,\n 15758.0,\n 15349.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Frequency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 220,\n \"min\": 1,\n \"max\": 7983,\n \"num_unique_values\": 455,\n \"samples\": [\n 415,\n 154,\n 452\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 70 + } + ], + "source": [ + "tx_frequency.head() #how many orders does a customer have" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_RNAanFYO1MH", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "94dfcc91-7337-4e34-8c04-f899942b671e" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Recency RecencyCluster Frequency\n", + "0 17850.0 301 0 312\n", + "1 15100.0 329 0 6\n", + "2 18074.0 373 0 13\n", + "3 16250.0 260 0 24\n", + "4 13747.0 373 0 1" + ], + "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", + "
CustomerIDRecencyRecencyClusterFrequency
017850.03010312
115100.032906
218074.0373013
316250.0260024
413747.037301
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_user", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 13067.0,\n 17947.0,\n 16968.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 169,\n 0,\n 161\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 3,\n 1,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Frequency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 220,\n \"min\": 1,\n \"max\": 7983,\n \"num_unique_values\": 455,\n \"samples\": [\n 253,\n 41,\n 604\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 71 + } + ], + "source": [ + "#add this data to our main dataframe\n", + "tx_user = pd.merge(tx_user, tx_frequency, on='CustomerID')\n", + "\n", + "tx_user.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "h3hMNQCRO1MH" + }, + "source": [ + "

4.1 Frequency clusters

" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CX9yWweXO1MI" + }, + "source": [ + "Determine the right number of clusters for K-Means by elbow method" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "UpKtowM3O1MI", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "outputId": "bd57aaaf-c32d-4925-9610-d73b32ed813d" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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\n" + }, + "metadata": {} + } + ], + "source": [ + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "from sklearn.cluster import KMeans\n", + "\n", + "# Assuming tx_user is your DataFrame\n", + "# Create a copy of the 'Frequency' column\n", + "tx_recency = tx_user[['Frequency']].copy()\n", + "\n", + "sse = {} # Dictionary to store SSE for each k value\n", + "\n", + "# Loop over different values of k\n", + "for k in range(1, 10):\n", + " kmeans = KMeans(n_clusters=k, max_iter=1000).fit(tx_recency)\n", + " # Assign cluster labels to the DataFrame\n", + " tx_recency.loc[:, \"clusters\"] = kmeans.labels_\n", + " # Store the SSE value for the current number of clusters\n", + " sse[k] = kmeans.inertia_\n", + "\n", + "# Plotting the results\n", + "plt.figure()\n", + "plt.plot(list(sse.keys()), list(sse.values()))\n", + "plt.xlabel(\"Number of clusters\")\n", + "plt.ylabel(\"SSE\")\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nQ2GXbYkO1MI" + }, + "source": [ + "By Elbow method, clusters number should be 4 as after 4, the graph goes down." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "N4NR3Wp-O1MI", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 295 + }, + "outputId": "03eb594c-dfea-4671-e69e-2e5b44cf1190" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " count mean std min 25% 50% \\\n", + "FrequencyCluster \n", + "0 3496.0 49.525744 44.954212 1.0 15.0 33.0 \n", + "1 429.0 331.221445 133.856510 191.0 228.0 287.0 \n", + "2 22.0 1313.136364 505.934524 872.0 988.5 1140.0 \n", + "3 3.0 5917.666667 1805.062418 4642.0 4885.0 5128.0 \n", + "\n", + " 75% max \n", + "FrequencyCluster \n", + "0 73.0 190.0 \n", + "1 399.0 803.0 \n", + "2 1452.0 2782.0 \n", + "3 6555.5 7983.0 " + ], + "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", + "
countmeanstdmin25%50%75%max
FrequencyCluster
03496.049.52574444.9542121.015.033.073.0190.0
1429.0331.221445133.856510191.0228.0287.0399.0803.0
222.01313.136364505.934524872.0988.51140.01452.02782.0
33.05917.6666671805.0624184642.04885.05128.06555.57983.0
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 4,\n \"fields\": [\n {\n \"column\": \"FrequencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 1,\n 3,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"count\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1683.8373832806224,\n \"min\": 3.0,\n \"max\": 3496.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 429.0,\n 3.0,\n 3496.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"mean\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 2730.7716948007696,\n \"min\": 49.525743707093824,\n \"max\": 5917.666666666667,\n \"num_unique_values\": 4,\n \"samples\": [\n 331.2214452214452,\n 5917.666666666667,\n 49.525743707093824\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"std\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 813.3004715715977,\n \"min\": 44.95421190788836,\n \"max\": 1805.0624181266787,\n \"num_unique_values\": 4,\n \"samples\": [\n 133.85651023921278,\n 1805.0624181266787,\n 44.95421190788836\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"min\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 2176.0377600890415,\n \"min\": 1.0,\n \"max\": 4642.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 191.0,\n 4642.0,\n 1.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"25%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 2275.9374030275962,\n \"min\": 15.0,\n \"max\": 4885.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 228.0,\n 4885.0,\n 15.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"50%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 2368.4739109111306,\n \"min\": 33.0,\n \"max\": 5128.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 287.0,\n 5128.0,\n 33.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"75%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 3015.0696060234936,\n \"min\": 73.0,\n \"max\": 6555.5,\n \"num_unique_values\": 4,\n \"samples\": [\n 399.0,\n 6555.5,\n 73.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"max\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 3539.5894771380854,\n \"min\": 190.0,\n \"max\": 7983.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 803.0,\n 7983.0,\n 190.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 73 + } + ], + "source": [ + "# Applying k-Means\n", + "kmeans=KMeans(n_clusters=4)\n", + "tx_user['FrequencyCluster']=kmeans.fit_predict(tx_user[['Frequency']])\n", + "\n", + "#order the frequency cluster\n", + "tx_user = order_cluster('FrequencyCluster', 'Frequency', tx_user, True )\n", + "tx_user.groupby('FrequencyCluster')['Frequency'].describe()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9oJXU2QlO1MJ" + }, + "source": [ + "Clsuter with max frequency is cluster 3, least frequency cluster is cluster 0." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ilAR6e1zO1MJ" + }, + "source": [ + "

5. Revenue

\n", + "\n", + "Let’s see how our customer database looks like when we cluster them based on revenue. We will calculate revenue for each customer, plot a histogram and apply the same clustering method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "sKITGPzgO1MJ" + }, + "outputs": [], + "source": [ + "#calculate revenue for each customer\n", + "tx_uk['Revenue'] = tx_uk['UnitPrice'] * tx_uk['Quantity']\n", + "tx_revenue = tx_uk.groupby('CustomerID').Revenue.sum().reset_index()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "R7d63RXGO1MJ", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "74920f4e-a00e-4473-dbc2-89cb5e5b48f5" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Revenue\n", + "0 12346.0 0.00\n", + "1 12747.0 4196.01\n", + "2 12748.0 29072.10\n", + "3 12749.0 3868.20\n", + "4 12820.0 942.34" + ], + "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", + "
CustomerIDRevenue
012346.00.00
112747.04196.01
212748.029072.10
312749.03868.20
412820.0942.34
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_revenue", + "summary": "{\n \"name\": \"tx_revenue\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 17160.0,\n 15758.0,\n 15349.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 6548.608224207446,\n \"min\": -4287.63,\n \"max\": 256438.49,\n \"num_unique_values\": 3878,\n \"samples\": [\n 1979.3,\n 264.65,\n 8727.61\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 75 + } + ], + "source": [ + "tx_revenue.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "McYXLZ78O1MJ", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "c62fe818-7cd6-4310-d998-67c1c08a4640" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Recency RecencyCluster Frequency FrequencyCluster Revenue\n", + "0 17850.0 301 0 312 1 5288.63\n", + "1 15808.0 305 0 210 1 3724.77\n", + "2 13047.0 31 3 196 1 3079.10\n", + "3 14688.0 7 3 359 1 5107.38\n", + "4 16029.0 38 3 274 1 50992.61" + ], + "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", + "
CustomerIDRecencyRecencyClusterFrequencyFrequencyClusterRevenue
017850.0301031215288.63
115808.0305021013724.77
213047.031319613079.10
314688.07335915107.38
416029.0383274150992.61
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_user", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 14951.0,\n 14345.0,\n 12981.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 174,\n 353,\n 161\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 3,\n 1,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Frequency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 220,\n \"min\": 1,\n \"max\": 7983,\n \"num_unique_values\": 455,\n \"samples\": [\n 15,\n 320,\n 146\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"FrequencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 0,\n 3,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 6548.608224207446,\n \"min\": -4287.63,\n \"max\": 256438.49,\n \"num_unique_values\": 3878,\n \"samples\": [\n -1592.49,\n 532.94,\n 110.46\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 76 + } + ], + "source": [ + "#merge it with our main dataframe\n", + "tx_user = pd.merge(tx_user, tx_revenue, on='CustomerID')\n", + "tx_user.head()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "n31rm5_IO1MJ" + }, + "source": [ + "We have some customers with negative revenue as well. Let’s continue and apply k-means clustering:\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "53T5G22lO1MJ" + }, + "source": [ + "**Elbow method to find out the optimum number of clusters for K-Means**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xTLXwIJZO1MJ", + "scrolled": true, + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "outputId": "0d15de27-c7e3-4415-d207-87edb731dbb8" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + ":7: SettingWithCopyWarning:\n", + "\n", + "\n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + ":7: SettingWithCopyWarning:\n", + "\n", + "\n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + ":7: SettingWithCopyWarning:\n", + "\n", + "\n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + ":7: SettingWithCopyWarning:\n", + "\n", + "\n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + ":7: SettingWithCopyWarning:\n", + "\n", + "\n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + ":7: SettingWithCopyWarning:\n", + "\n", + "\n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + ":7: SettingWithCopyWarning:\n", + "\n", + "\n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + ":7: SettingWithCopyWarning:\n", + "\n", + "\n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + ":7: SettingWithCopyWarning:\n", + "\n", + "\n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + "\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiwAAAHACAYAAACBGTONAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABIvElEQVR4nO3deXxU5d3///fMJJONLITsJOybbGFRY8AFahQoUtF+lVpaFmt71xutFJeKrSBugFWLvaVarQrWH4u9FbStgpoauFWUNWwKsgqBhD0rMElmzu+PJBPGBMiEJGdm8no+HudBcuY6J59DW/LuuT7XORbDMAwBAAD4MKvZBQAAAFwMgQUAAPg8AgsAAPB5BBYAAODzCCwAAMDnEVgAAIDPI7AAAACfR2ABAAA+j8ACAAB8HoEFAAD4vIALLKtXr9aYMWOUkpIii8Wi5cuXe3X82bNnNWnSJPXr109BQUEaO3ZsnTH5+fn66U9/qh49eshqtWrq1KlNUjsAAKhfwAWWsrIypaena/78+Y063ul0KiwsTL/5zW+UlZVV7xiHw6H4+Hj94Q9/UHp6+qWUCwAAGiDI7AKa2qhRozRq1Kjzfu5wOPT73/9eixcvVmFhofr27au5c+dq2LBhkqSIiAi99NJLkqTPP/9chYWFdc7RqVMnvfDCC5Kk119/vcmvAQAAeAq4OywXc88992jNmjVasmSJtmzZottuu00jR47Url27zC4NAACcR6sKLAcOHNAbb7yhf/zjH7rmmmvUtWtXPfDAA7r66qv1xhtvmF0eAAA4j4CbErqQrVu3yul0qkePHh77HQ6H2rVrZ1JVAADgYlpVYCktLZXNZtOGDRtks9k8PmvTpo1JVQEAgItpVYFl4MCBcjqdOnr0qK655hqzywEAAA0UcIGltLRUu3fvdn+/b98+5ebmKjY2Vj169ND48eM1YcIEPffccxo4cKCOHTum7Oxs9e/fX6NHj5Ykff311yovL9fJkydVUlKi3NxcSdKAAQPc563ZV1paqmPHjik3N1d2u129e/duqUsFAKDVsBiGYZhdRFPKycnR8OHD6+yfOHGiFixYoIqKCj355JN68803dejQIcXFxemqq67SrFmz1K9fP0lVy5a/++67Ouc496/KYrHU+bxjx47av39/010MAACQFICBBQAABJ5WtawZAAD4JwILAADweQHR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R//85z+1Zs0aj/3x8fEqKCjw+MXblM8Z+fLLL91fV1ZWasOGDbrsssskSYMGDdL27dvVqVMndevWzWPzJqRERUUpJSVFn3/+ucf+zz//XL17927webp3766wsLAGL3mOj49XSUmJysrK3Pvq+7vr0aOHfvvb3+qjjz7Srbfe6m5OttvtcjqdHmMHDhwop9Opo0eP1vk7SUpKavC1AK0VgQXwc/369dP48eP15z//2WP/sGHDdOzYMT3zzDPas2eP5s+frw8//LDJfu78+fO1bNky7dixQ1OmTNGpU6d05513SpKmTJmikydP6o477tC6deu0Z88erVy5UpMnT67zi/xiHnzwQc2dO1dLly7Vzp079fDDDys3N1f33Xdfg88RGhqq3/3ud3rooYf05ptvas+ePfryyy/12muv1Ts+IyND4eHheuSRR7Rnzx4tWrRICxYscH9+5swZ3XPPPcrJydF3332nzz//XOvWrXMHtk6dOqm0tFTZ2dk6fvy4Tp8+rR49emj8+PGaMGGC3n33Xe3bt09r167V7Nmz9e9//9urvxOgNSKwAAHg8ccfrzNlc9lll+kvf/mL5s+fr/T0dK1du/aSel2+b86cOZozZ47S09P12Wef6f3331dcXJwkue+KOJ1O3XjjjerXr5+mTp2qmJgYj36ZhvjNb36jadOm6f7771e/fv20YsUKvf/+++revbtX53n00Ud1//33a8aMGbrssss0bty4On05NWJjY/XWW2/pgw8+UL9+/bR48WKP5dI2m00nTpzQhAkT1KNHD91+++0aNWqUZs2aJUkaMmSIfv3rX2vcuHGKj4/XM888I0l64403NGHCBN1///3q2bOnxo4dq3Xr1qlDhw5eXQvQGlmM70/UAgAA+BjusAAAAJ9HYAEAAD6PwAIAAHwegQUAAPg8AgsAAPB5BBYAAODzCCwAAMDnEVgAAIDPI7AAAACfR2ABAAA+j8ACAAB8HoEFAAD4vP8fquBUi6O7gyEAAAAASUVORK5CYII=\n" + }, + "metadata": {} + } + ], + "source": [ + "from sklearn.cluster import KMeans\n", + "\n", + "sse={} # error\n", + "tx_recency = tx_user[['Revenue']]\n", + "for k in range(1, 10):\n", + " kmeans = KMeans(n_clusters=k, max_iter=1000).fit(tx_recency)\n", + " tx_recency[\"clusters\"] = kmeans.labels_ #cluster names corresponding to recency values\n", + " sse[k] = kmeans.inertia_ #sse corresponding to clusters\n", + "plt.figure()\n", + "plt.plot(list(sse.keys()), list(sse.values()))\n", + "plt.xlabel(\"Number of cluster\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "GXgm-ZDkO1MJ" + }, + "source": [ + "From elbow's method, we find that clusters can be 3 or 4. Lets take 4 as the number of clusters" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "K5eV2YpfO1MK" + }, + "source": [ + "

5.1. Revenue clusters

" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UOhe7qFR7ho3" + }, + "source": [ + "Let’s see how our customer database looks like when we cluster them based on revenue. We will calculate revenue\n", + "for each customer, plot a histogram and apply the same clustering method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PxaBHYUZ7lYr" + }, + "outputs": [], + "source": [ + "#calculate revenue for each customer\n", + "tx_uk['Revenue'] = tx_uk['UnitPrice'] * tx_uk['Quantity']\n", + "tx_revenue = tx_uk.groupby('CustomerID').Revenue.sum().reset_index()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fUoJewNL7qU0", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "362054b0-6e8b-40fc-dad4-d4972ba6291b" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Revenue\n", + "0 12346.0 0.00\n", + "1 12747.0 4196.01\n", + "2 12748.0 29072.10\n", + "3 12749.0 3868.20\n", + "4 12820.0 942.34" + ], + "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", + "
CustomerIDRevenue
012346.00.00
112747.04196.01
212748.029072.10
312749.03868.20
412820.0942.34
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_revenue", + "summary": "{\n \"name\": \"tx_revenue\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 17160.0,\n 15758.0,\n 15349.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 6548.608224207446,\n \"min\": -4287.63,\n \"max\": 256438.49,\n \"num_unique_values\": 3878,\n \"samples\": [\n 1979.3,\n 264.65,\n 8727.61\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 79 + } + ], + "source": [ + "tx_revenue.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "EHlcZWt77vhH", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "95cd9806-e20f-4900-8056-19f1f3909a66" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Recency RecencyCluster Frequency FrequencyCluster Revenue\n", + "0 17850.0 301 0 312 1 5288.63\n", + "1 15808.0 305 0 210 1 3724.77\n", + "2 13047.0 31 3 196 1 3079.10\n", + "3 14688.0 7 3 359 1 5107.38\n", + "4 16029.0 38 3 274 1 50992.61" + ], + "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", + "
CustomerIDRecencyRecencyClusterFrequencyFrequencyClusterRevenue
017850.0301031215288.63
115808.0305021013724.77
213047.031319613079.10
314688.07335915107.38
416029.0383274150992.61
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_user", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 14951.0,\n 14345.0,\n 12981.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 174,\n 353,\n 161\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 3,\n 1,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Frequency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 220,\n \"min\": 1,\n \"max\": 7983,\n \"num_unique_values\": 455,\n \"samples\": [\n 15,\n 320,\n 146\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"FrequencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 0,\n 3,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 6548.608224207446,\n \"min\": -4287.63,\n \"max\": 256438.49,\n \"num_unique_values\": 3878,\n \"samples\": [\n -1592.49,\n 532.94,\n 110.46\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 80 + } + ], + "source": [ + "#merge it with our main dataframe\n", + "tx_user = pd.merge(tx_user, tx_revenue, on='CustomerID')\n", + "tx_user = tx_user.drop(columns=['Revenue_y'])\n", + "tx_user=tx_user.rename(columns={'Revenue_x':'Revenue'})\n", + "tx_user.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3-0UCAqU8ADu" + }, + "source": [ + "We have some customers with negative revenue as well. Let’s continue and apply k-means clustering:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "j61HnJJ08FsZ" + }, + "outputs": [], + "source": [ + "#Elbow method to find out the optimum number of clusters for K-Means" + ] + }, + { + "cell_type": "code", + "source": [ + "tx_user" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 423 + }, + "id": "LhWFt4de1Kbz", + "outputId": "5fd75a8e-cb29-46c9-8697-bfa7cc353f57" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Recency RecencyCluster Frequency FrequencyCluster \\\n", + "0 17850.0 301 0 312 1 \n", + "1 15808.0 305 0 210 1 \n", + "2 13047.0 31 3 196 1 \n", + "3 14688.0 7 3 359 1 \n", + "4 16029.0 38 3 274 1 \n", + "... ... ... ... ... ... \n", + "3945 14056.0 0 3 1128 2 \n", + "3946 14456.0 4 3 977 2 \n", + "3947 12748.0 0 3 4642 3 \n", + "3948 17841.0 1 3 7983 3 \n", + "3949 14096.0 3 3 5128 3 \n", + "\n", + " Revenue \n", + "0 5288.63 \n", + "1 3724.77 \n", + "2 3079.10 \n", + "3 5107.38 \n", + "4 50992.61 \n", + "... ... \n", + "3945 8124.40 \n", + "3946 3047.63 \n", + "3947 29072.10 \n", + "3948 40340.78 \n", + "3949 57120.91 \n", + "\n", + "[3950 rows x 6 columns]" + ], + "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", + "
CustomerIDRecencyRecencyClusterFrequencyFrequencyClusterRevenue
017850.0301031215288.63
115808.0305021013724.77
213047.031319613079.10
314688.07335915107.38
416029.0383274150992.61
.....................
394514056.003112828124.40
394614456.04397723047.63
394712748.0034642329072.10
394817841.0137983340340.78
394914096.0335128357120.91
\n", + "

3950 rows × 6 columns

\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_user", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 14951.0,\n 14345.0,\n 12981.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 174,\n 353,\n 161\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 3,\n 1,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Frequency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 220,\n \"min\": 1,\n \"max\": 7983,\n \"num_unique_values\": 455,\n \"samples\": [\n 15,\n 320,\n 146\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"FrequencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 0,\n 3,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 6548.608224207446,\n \"min\": -4287.63,\n \"max\": 256438.49,\n \"num_unique_values\": 3878,\n \"samples\": [\n -1592.49,\n 532.94,\n 110.46\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 82 + } + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JjKhsRjbJSeg", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "outputId": "d5fe75f2-b71a-4b1c-8c7a-9d55109f4239" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n", + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAHACAYAAABeV0mSAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABBi0lEQVR4nO3deXgV9d338c/JyUo2CJCEkLDvAiECJgEVlxSKSOW2j/JYbkEQW3tDlaK2xFZxeWyg1rq0VFxBpQjaFlxaoRYEbzEIQSObIDsBEvbkJIGcJOfM80fIwWMWCJxkcibv13XNFWfmN5PvpFc5n+s335ljMwzDEAAAgEUEmF0AAACALxFuAACApRBuAACApRBuAACApRBuAACApRBuAACApRBuAACApRBuAACApRBuAACApRBuAACApbTocPPpp59q7NixSkhIkM1m0/Llyxt0fFlZme666y4NGDBAgYGBGjduXI0x+fn5+slPfqJevXopICBAM2bM8EntAACgdi063JSWlio5OVnz5s27pONdLpfCwsJ03333KSMjo9YxTqdT7du3129/+1slJydfTrkAAOAiBJpdgJlGjx6t0aNH17nf6XTqN7/5jd5++20VFhaqf//+mjt3rq677jpJUnh4uF588UVJ0rp161RYWFjjHF26dNHzzz8vSXr99dd9fg0AAMBbi565uZDp06crOztbS5Ys0ebNm3Xbbbfphz/8oXbt2mV2aQAAoA6EmzocPHhQCxYs0LvvvqtrrrlG3bt314MPPqirr75aCxYsMLs8AABQhxZ9W6o+W7ZskcvlUq9evby2O51OtW3b1qSqAADAhRBu6lBSUiK73a5NmzbJbrd77YuIiDCpKgAAcCGEmzqkpKTI5XLp2LFjuuaaa8wuBwAAXKQWHW5KSkq0e/duz/q+ffuUm5urmJgY9erVSxMmTNDEiRP1zDPPKCUlRcePH9eqVas0cOBAjRkzRpK0fft2lZeX69SpUyouLlZubq4kadCgQZ7zVm8rKSnR8ePHlZubq+DgYPXr16+pLhUAgBbDZhiGYXYRZlmzZo2uv/76GtsnTZqkhQsXqqKiQv/v//0/vfnmmzp8+LDatWuntLQ0Pf744xowYICkqke9Dxw4UOMc3/2z2my2Gvs7d+6s/fv3++5iAACApBYebgAAgPXwKDgAALAUwg0AALCUFtdQ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6LsBAFiZzWjg13ifOHFC69atU3x8vNctKUn65z//qX79+qlr164+LdKXHA6HoqOjVVRU1KJvUY169lPtPFqsFydcyftuAADNXkM+vxt0Wyo7O1vr16/XLbfc4gk2b775prp27arY2Fi99957SkhIuPTK0WTouwEAWFWDws0TTzyhbdu2eda3bNmiu+++WxkZGZo1a5Y++OADZWVl+bxI+F56d/puAADW1KBwk5ubqxtvvNGzvmTJEqWmpuqVV17RzJkz9cILL+idd97xeZHwvau6VoWb6r4bAACsokHh5vTp04qLi/Osr1271uu7oYYOHdri3yPjL2LCg9UnnvfdAACsp0HhJi4uzvPN4OXl5fryyy+Vlpbm2V9cXKygoCDfVohGc/6RcPpuAADW0aBwc9NNN2nWrFn63//9X2VmZqpVq1a65pprPPs3b96s7t27+7xINI7zTcXM3AAArKNB77l58skndeutt2rEiBGKiIjQG2+8oeDgYM/+119/XSNHjvR5kWgc3++74X03AAAraFC4adeunT799FMVFRUpIiJCdrvda/+7776riIgInxaIxlPdd7OjoFhf7Dulm3jfDQDAAhp0W6padHR0jWAjSTExMV4zOWj+6LsBAFjNJYUbWAcv8wMAWA3hpoWr7rv59miJTvC+GwCABRBuWjjedwMAsBrCDei7AQBYCuEG9N0AACyFcAP6bgAAlkK4AX03AABLIdxAEn03AADrINxAEn03AADrINxAEn03AADrINxAEn03AADrINzAg74bAIAVEG7gQbgBAFgB4QYeqV2rmorpuwEA+DPCDTza0HcDALAAwg28cGsKAODvCDfwQrgBAPg7wg280HcDAPB3hBt4+W7fzRd76bsBAPgfwg1q4NYUAMCfEW5QA+EGAODPCDeoobrvZtcx+m4AAP6HcIMa6LsBAPgzwg1qxa0pAIC/ItygVoQbAIC/ItygVvTdAAD8FeEGtaLvBgDgrwg3qBO3pgAA/ohwgzoRbgAA/ohwgzqldYuRzUbfDQDAvxBuUKfWrYLVJz5KEn03AAD/QbhBvdK6VT01xa0pAIC/INygXvTdAAD8DeEG9UrtSt8NAMC/EG5QL/puAAD+hnCDC6LvBgDgTwg3uKDqvptswg0AwA8QbnBB1X03u4+V6HgxfTcAgObN1HDz6aefauzYsUpISJDNZtPy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pmD7+bDj+ekVhOyefSFeY89t/06o+u5YrzHn1kODAhRst6tViF3tLvHv7guEGwAAamGz2RQeEqjwkMBLasaWpEqXWyXOShWfa74uLqtUibNSzkqXyivdcla6z/08v/7dbd7rbpVXb6twq9zlruU8brnchuf3u9yGzrpdOlvh8tWf5aIkJ7XWe9OGN+nv/K5mEW7mzZunp59+WgUFBUpOTtaf/vQnXXXVVXWOf/fdd/XII49o//796tmzp+bOnaubbrqpCSsGAODCAu0Bat0qWK1bBSupiX5npetc8Kn47k+Xyr6zXlsoqg5O50NWzTHf317bceWVboUFmXs7zPRws3TpUs2cOVPz589XamqqnnvuOY0aNUo7d+5UbGxsjfGff/657rjjDmVlZenmm2/W4sWLNW7cOH355Zfq37+/CVcAAEDzEXiu16ZVsNmVmMdmGIZx4WGNJzU1VUOHDtWf//xnSZLb7VZSUpJ+8YtfaNasWTXGjx8/XqWlpfrwww8929LS0jRo0CDNnz//gr/P4XAoOjpaRUVFioqK8t2FAACARtOQz29T543Ky8u1adMmZWRkeLYFBAQoIyND2dnZtR6TnZ3tNV6SRo0aVed4AADQsph6W+rEiRNyuVyKi4vz2h4XF6cdO3bUekxBQUGt4wsKCmod73Q65XSe7053OGr/pl0AAGANln8APisrS9HR0Z4lKampWroAAIAZTA037dq1k91u19GjR722Hz16VPHx8bUeEx8f36DxmZmZKioq8ix5eXm+KR4AADRLpoab4OBgDR48WKtWrfJsc7vdWrVqldLT02s9Jj093Wu8JH388cd1jg8JCVFUVJTXAgAArMv0R8FnzpypSZMmaciQIbrqqqv03HPPqbS0VJMnT5YkTZw4UR07dlRWVpYk6f7779eIESP0zDPPaMyYMVqyZIlycnL08ssvm3kZAACgmTA93IwfP17Hjx/Xo48+qoKCAg0aNEgrVqzwNA0fPHhQAQHnJ5iGDRumxYsX67e//a0efvhh9ezZU8uXL+cdNwAAQFIzeM9NU+M9NwAA+B+/ec8NAACArxFuAACApRBuAACApRBuAACApRBuAACApZj+KHhTq344jO+YAgDAf1R/bl/MQ94tLtwUFxdLEt8xBQCAHyouLlZ0dHS9Y1rce27cbreOHDmiyMhI2Ww2n57b4XAoKSlJeXl5lnyHjtWvT7L+NXJ9/s/q18j1+b/GukbDMFRcXKyEhASvl/vWpsXN3AQEBCgxMbFRf4fVv8PK6tcnWf8auT7/Z/Vr5Pr8X2Nc44VmbKrRUAwAACyFcAMAACyFcONDISEhmj17tkJCQswupVFY/fok618j1+f/rH6NXJ//aw7X2OIaigEAgLUxcwMAACyFcAMAACyFcAMAACyFcOMDn376qcaOHauEhATZbDYtX77c7JJ8KisrS0OHDlVkZKRiY2M1btw47dy50+yyfObFF1/UwIEDPe9kSE9P10cffWR2WY1mzpw5stlsmjFjhtml+Mxjjz0mm83mtfTp08fssnzq8OHD+u///m+1bdtWYWFhGjBggHJycswuy2e6dOlS439Dm82madOmmV2aT7hcLj3yyCPq2rWrwsLC1L17dz355JMX9VUC/qK4uFgzZsxQ586dFRYWpmHDhmnjxo2m1NLiXuLXGEpLS5WcnKwpU6bo1ltvNbscn1u7dq2mTZumoUOHqrKyUg8//LBGjhyp7du3Kzw83OzyLltiYqLmzJmjnj17yjAMvfHGG7rlllv01Vdf6YorrjC7PJ/auHGjXnrpJQ0cONDsUnzuiiuu0H/+8x/PemCgdf55O336tIYPH67rr79eH330kdq3b69du3apTZs2ZpfmMxs3bpTL5fKsb926VT/4wQ902223mViV78ydO1cvvvii3njjDV1xxRXKycnR5MmTFR0drfvuu8/s8nxi6tSp2rp1q9566y0lJCRo0aJFysjI0Pbt29WxY8emLcaAT0kyli1bZnYZjerYsWOGJGPt2rVml9Jo2rRpY7z66qtml+FTxcXFRs+ePY2PP/7YGDFihHH//febXZLPzJ4920hOTja7jEbz61//2rj66qvNLqNJ3X///Ub37t0Nt9ttdik+MWbMGGPKlCle22699VZjwoQJJlXkW2fOnDHsdrvx4Ycfem2/8sorjd/85jdNXg+3pdBgRUVFkqSYmBiTK/E9l8ulJUuWqLS0VOnp6WaX41PTpk3TmDFjlJGRYXYpjWLXrl1KSEhQt27dNGHCBB08eNDsknzm/fff15AhQ3TbbbcpNjZWKSkpeuWVV8wuq9GUl5dr0aJFmjJlis+/A9Asw4YN06pVq/Ttt99Kkr7++mt99tlnGj16tMmV+UZlZaVcLpdCQ0O9toeFhemzzz5r8nqsM2+LJuF2uzVjxgwNHz5c/fv3N7scn9myZYvS09NVVlamiIgILVu2TP369TO7LJ9ZsmSJvvzyS9Pufze21NRULVy4UL1791Z+fr4ef/xxXXPNNdq6dasiIyPNLu+y7d27Vy+++KJmzpyphx9+WBs3btR9992n4OBgTZo0yezyfG758uUqLCzUXXfdZXYpPjNr1iw5HA716dNHdrtdLpdLTz31lCZMmGB2aT4RGRmp9PR0Pfnkk+rbt6/i4uL09ttvKzs7Wz169Gj6gpp8rsjiZPHbUvfee6/RuXNnIy8vz+xSfMrpdBq7du0ycnJyjFmzZhnt2rUztm3bZnZZPnHw4EEjNjbW+Prrrz3brHZb6vtOnz5tREVFWebWYlBQkJGenu617Re/+IWRlpZmUkWNa+TIkcbNN99sdhk+9fbbbxuJiYnG22+/bWzevNl48803jZiYGGPhwoVml+Yzu3fvNq699lpDkmG3242hQ4caEyZMMPr06dPktRBufMzK4WbatGlGYmKisXfvXrNLaXQ33nij8dOf/tTsMnxi2bJlnn9sqhdJhs1mM+x2u1FZWWl2iY1iyJAhxqxZs8wuwyc6depk3H333V7b/vKXvxgJCQkmVdR49u/fbwQEBBjLly83uxSfSkxMNP785z97bXvyySeN3r17m1RR4ykpKTGOHDliGIZh3H777cZNN93U5DXQc4MLMgxD06dP17Jly7R69Wp17drV7JIandvtltPpNLsMn7jxxhu1ZcsW5ebmepYhQ4ZowoQJys3Nld1uN7tEnyspKdGePXvUoUMHs0vxieHDh9d4/cK3336rzp07m1RR41mwYIFiY2M1ZswYs0vxqTNnziggwPsj1263y+12m1RR4wkPD1eHDh10+vRprVy5UrfcckuT10DPjQ+UlJRo9+7dnvV9+/YpNzdXMTEx6tSpk4mV+ca0adO0ePFivffee4qMjFRBQYEkKTo6WmFhYSZXd/kyMzM1evRoderUScXFxVq8eLHWrFmjlStXml2aT0RGRtbojwoPD1fbtm0t0zf14IMPauzYsercubOOHDmi2bNny26364477jC7NJ/45S9/qWHDhul3v/udbr/9dm3YsEEvv/yyXn75ZbNL8ym3260FCxZo0qRJlnqUX5LGjh2rp556Sp06ddIVV1yhr776Sn/84x81ZcoUs0vz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\n" + }, + "metadata": {} + } + ], + "source": [ + "# Assuming 'tx_data' is your original DataFrame containing all transactional data\n", + "# Ensure it contains 'CustomerID', 'UnitPrice', 'Quantity', and any other relevant columns\n", + "\n", + "# Step 1: Calculate 'Revenue' for each transaction\n", + "tx_data['Revenue'] = tx_data['UnitPrice'] * tx_data['Quantity']\n", + "\n", + "# Step 2: Group by 'CustomerID' to sum up the revenue for each customer\n", + "tx_user2 = tx_data.groupby('CustomerID')['Revenue'].sum().reset_index()\n", + "\n", + "# Step 3: Prepare the tx_recency DataFrame with the 'Revenue' column\n", + "tx_recency = tx_user2[['Revenue']]\n", + "\n", + "# Step 4: Run KMeans clustering and calculate SSE for different cluster numbers\n", + "sse = {} # Store the sum of squared errors\n", + "for k in range(1, 10):\n", + " kmeans = KMeans(n_clusters=k, max_iter=1000).fit(tx_recency)\n", + " tx_recency[\"clusters\"] = kmeans.labels_ # Assign cluster labels\n", + " sse[k] = kmeans.inertia_ # Store SSE for each k\n", + "\n", + "# Step 5: Plotting the Elbow method graph\n", + "plt.figure()\n", + "plt.plot(list(sse.keys()), list(sse.values()))\n", + "plt.xlabel(\"Number of clusters\")\n", + "plt.ylabel(\"SSE\")\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yA1j35uVO1MK" + }, + "source": [ + "

6. Overall Score based on RFM Clsutering

\n", + "\n", + "We have scores (cluster numbers) for recency, frequency & revenue. Let’s create an overall score out of them\n" + ] + }, + { + "cell_type": "code", + "source": [ + "#apply clustering\n", + "kmeans = KMeans(n_clusters=4)\n", + "tx_user['RevenueCluster'] = kmeans.fit_predict(tx_user[['Revenue']])\n", + "\n", + "#order the cluster numbers\n", + "tx_user = order_cluster('RevenueCluster', 'Revenue',tx_user,True)\n", + "\n", + "#show details of the dataframe\n", + "tx_user.groupby('RevenueCluster')['Revenue'].describe()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 295 + }, + "id": "neRDRJuQ2fZY", + "outputId": "2eea423d-149a-475f-aa69-f816638fa5ee" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " count mean std min 25% \\\n", + "RevenueCluster \n", + "0 3687.0 907.254414 921.910820 -4287.63 263.115 \n", + "1 234.0 7760.699530 3637.173671 4330.67 5161.485 \n", + "2 27.0 43070.445185 15939.249588 25748.35 28865.490 \n", + "3 2.0 221960.330000 48759.481478 187482.17 204721.250 \n", + "\n", + " 50% 75% max \n", + "RevenueCluster \n", + "0 572.56 1258.220 4314.72 \n", + "1 6549.38 9142.305 21535.90 \n", + "2 36351.42 53489.790 88125.38 \n", + "3 221960.33 239199.410 256438.49 " + ], + "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", + "
countmeanstdmin25%50%75%max
RevenueCluster
03687.0907.254414921.910820-4287.63263.115572.561258.2204314.72
1234.07760.6995303637.1736714330.675161.4856549.389142.30521535.90
227.043070.44518515939.24958825748.3528865.49036351.4253489.79088125.38
32.0221960.33000048759.481478187482.17204721.250221960.33239199.410256438.49
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 4,\n \"fields\": [\n {\n \"column\": \"RevenueCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 1,\n 3,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"count\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1802.6677453152593,\n \"min\": 2.0,\n \"max\": 3687.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 234.0,\n 2.0,\n 3687.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"mean\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 104010.82368070885,\n \"min\": 907.2544138866288,\n \"max\": 221960.33000000002,\n \"num_unique_values\": 4,\n \"samples\": [\n 7760.69952991453,\n 221960.33000000002,\n 907.2544138866288\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"std\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 21958.023661503135,\n \"min\": 921.9108197203295,\n \"max\": 48759.481477669535,\n \"num_unique_values\": 4,\n \"samples\": [\n 3637.173671171341,\n 48759.481477669535,\n 921.9108197203295\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"min\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 90329.53968761419,\n \"min\": -4287.63,\n \"max\": 187482.17,\n \"num_unique_values\": 4,\n \"samples\": [\n 4330.67,\n 187482.17,\n -4287.63\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"25%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 97449.32308515052,\n \"min\": 263.115,\n \"max\": 204721.25,\n \"num_unique_values\": 4,\n \"samples\": [\n 5161.485,\n 204721.25,\n 263.115\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"50%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 104908.33313947511,\n \"min\": 572.56,\n \"max\": 221960.33000000002,\n \"num_unique_values\": 4,\n \"samples\": [\n 6549.38,\n 221960.33000000002,\n 572.56\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"75%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 111350.54989645646,\n \"min\": 1258.22,\n \"max\": 239199.41,\n \"num_unique_values\": 4,\n \"samples\": [\n 9142.305,\n 239199.41,\n 1258.22\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"max\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 115047.04827536555,\n \"min\": 4314.72,\n \"max\": 256438.49,\n \"num_unique_values\": 4,\n \"samples\": [\n 21535.9,\n 256438.49,\n 4314.72\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 84 + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5BiRQiYpO1MK" + }, + "source": [ + "Score 8 is our best customer, score 0 is our worst customer." + ] + }, + { + "cell_type": "code", + "source": [ + "tx_user" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 423 + }, + "id": "40YdmjGNyuN_", + "outputId": "e2021ff5-0e20-4c0b-8da2-b34c0f27b13a" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Recency RecencyCluster Frequency FrequencyCluster \\\n", + "0 17850.0 301 0 312 1 \n", + "1 14688.0 7 3 359 1 \n", + "2 13767.0 1 3 399 1 \n", + "3 15513.0 30 3 314 1 \n", + "4 14849.0 21 3 392 1 \n", + "... ... ... ... ... ... \n", + "3945 12748.0 0 3 4642 3 \n", + "3946 17841.0 1 3 7983 3 \n", + "3947 14096.0 3 3 5128 3 \n", + "3948 17450.0 7 3 351 1 \n", + "3949 18102.0 0 3 433 1 \n", + "\n", + " Revenue RevenueCluster \n", + "0 5288.63 1 \n", + "1 5107.38 1 \n", + "2 16945.71 1 \n", + "3 14520.08 1 \n", + "4 7904.28 1 \n", + "... ... ... \n", + "3945 29072.10 2 \n", + "3946 40340.78 2 \n", + "3947 57120.91 2 \n", + "3948 187482.17 3 \n", + "3949 256438.49 3 \n", + "\n", + "[3950 rows x 7 columns]" + ], + "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", + "
CustomerIDRecencyRecencyClusterFrequencyFrequencyClusterRevenueRevenueCluster
017850.0301031215288.631
114688.07335915107.381
213767.013399116945.711
315513.0303314114520.081
414849.021339217904.281
........................
394512748.0034642329072.102
394617841.0137983340340.782
394714096.0335128357120.912
394817450.0733511187482.173
394918102.0034331256438.493
\n", + "

3950 rows × 7 columns

\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_user", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 17172.0,\n 13607.0,\n 13379.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 189,\n 307,\n 161\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 3,\n 1,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Frequency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 220,\n \"min\": 1,\n \"max\": 7983,\n \"num_unique_values\": 455,\n \"samples\": [\n 718,\n 500,\n 99\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"FrequencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 0,\n 3,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 6548.608224207447,\n \"min\": -4287.63,\n \"max\": 256438.49,\n \"num_unique_values\": 3878,\n \"samples\": [\n 102.83,\n 190.53,\n 314.69\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RevenueCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 0,\n 3,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 85 + } + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "NyWdB45wH8Cx" + }, + "outputs": [], + "source": [ + "# import pandas as pd\n", + "# from sklearn.cluster import KMeans\n", + "# from sklearn.preprocessing import StandardScaler\n", + "\n", + "# # Function to create clusters based on the provided number of clusters and column name\n", + "# def create_clusters(data, num_clusters, col_name):\n", + "# # Ensure the column exists in the DataFrame\n", + "# if col_name not in data.columns:\n", + "# raise ValueError(f\"Column '{col_name}' not found in the DataFrame.\")\n", + "\n", + "# # Standardize the data before clustering\n", + "# scaler = StandardScaler()\n", + "# scaled_data = scaler.fit_transform(data[[col_name]])\n", + "\n", + "# # Fit KMeans on the standardized data\n", + "# kmeans = KMeans(n_clusters=num_clusters, max_iter=1000, random_state=42)\n", + "# kmeans.fit(scaled_data)\n", + "\n", + "# # Add the cluster labels to the original DataFrame\n", + "# data[col_name + 'Cluster'] = kmeans.labels_\n", + "# return data\n", + "\n", + "# # Example DataFrame (replace with your own data loading step)\n", + "# # tx_user = pd.read_csv('path_to_your_user_data.csv')\n", + "\n", + "# # Define the number of clusters\n", + "# num_clusters = 4\n", + "\n", + "# # Check if required columns exist\n", + "# required_columns = ['Recency', 'Frequency', 'Revenue']\n", + "# missing_columns = [col for col in required_columns if col not in tx_user.columns]\n", + "# if missing_columns:\n", + "# raise ValueError(f\"Missing columns in the DataFrame: {missing_columns}\")\n", + "\n", + "# # Assuming tx_user has 'Recency', 'Frequency', and 'Revenue' columns\n", + "# tx_user = create_clusters(tx_user, num_clusters, 'Recency')\n", + "# tx_user = create_clusters(tx_user, num_clusters, 'Frequency')\n", + "# tx_user = create_clusters(tx_user, num_clusters, 'Revenue')\n", + "\n", + "# # Calculate the OverallScore\n", + "# tx_user['OverallScore'] = tx_user['RecencyCluster'] + tx_user['FrequencyCluster'] + tx_user['RevenueCluster']\n", + "\n", + "# # Group by OverallScore and calculate the mean of Recency, Frequency, and Revenue\n", + "# result = tx_user.groupby('OverallScore')[['Recency', 'Frequency', 'Revenue']].mean()\n", + "\n", + "# # Display the result\n", + "# print(result)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "source": [ + "# Calculate overall score\n", + "tx_user['OverallScore'] = tx_user['RecencyCluster'] + tx_user['FrequencyCluster'] + tx_user['RevenueCluster']\n", + "\n", + "# Use mean() to see details for the selected columns\n", + "tx_user.groupby('OverallScore')[['Recency', 'Frequency', 'Revenue']].mean()\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 363 + }, + "id": "Ah7vxM_Szgrv", + "outputId": "8c84fa7f-3645-43a0-eac9-33e632c78c49" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " Recency Frequency Revenue\n", + "OverallScore \n", + "0 304.584388 21.995781 303.339705\n", + "1 185.362989 32.596085 498.087546\n", + "2 78.991304 46.963043 868.082991\n", + "3 20.689610 68.419590 1091.416414\n", + "4 14.892617 271.755034 3607.097114\n", + "5 9.662162 373.290541 9136.946014\n", + "6 7.740741 876.037037 22777.914815\n", + "7 1.857143 1272.714286 103954.025714\n", + "8 1.333333 5917.666667 42177.930000" + ], + "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", + "
RecencyFrequencyRevenue
OverallScore
0304.58438821.995781303.339705
1185.36298932.596085498.087546
278.99130446.963043868.082991
320.68961068.4195901091.416414
414.892617271.7550343607.097114
59.662162373.2905419136.946014
67.740741876.03703722777.914815
71.8571431272.714286103954.025714
81.3333335917.66666742177.930000
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 9,\n \"fields\": [\n {\n \"column\": \"OverallScore\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 2,\n \"min\": 0,\n \"max\": 8,\n \"num_unique_values\": 9,\n \"samples\": [\n 7,\n 1,\n 5\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 106.51315302965865,\n \"min\": 1.3333333333333333,\n \"max\": 304.584388185654,\n \"num_unique_values\": 9,\n \"samples\": [\n 1.8571428571428572,\n 185.3629893238434,\n 9.662162162162161\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Frequency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1899.447716676171,\n \"min\": 21.9957805907173,\n \"max\": 5917.666666666667,\n \"num_unique_values\": 9,\n \"samples\": [\n 1272.7142857142858,\n 32.596085409252666,\n 373.2905405405405\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 34322.49841955528,\n \"min\": 303.3397046413502,\n \"max\": 103954.0257142857,\n \"num_unique_values\": 9,\n \"samples\": [\n 103954.0257142857,\n 498.0875462633452,\n 9136.946013513514\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 87 + } + ] + }, + { + "cell_type": "code", + "source": [ + "tx_user['Segment'] = 'Low-Value'\n", + "tx_user.loc[tx_user['OverallScore']>2,'Segment'] = 'Mid-Value'\n", + "tx_user.loc[tx_user['OverallScore']>4,'Segment'] = 'High-Value'" + ], + "metadata": { + "id": "jL7SNKmF4qyX" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XMNspW2NO1MK" + }, + "outputs": [], + "source": [ + "\n", + "# else:\n", + "# print(\"Warning: 'OverallScore' column not found. Cannot group and calculate means.\")\n", + "\n", + "# # --- (Code from ipython-input-164-5ca3f4963d0c) ---\n", + "# tx_user['Segment'] = 'Low-Value'import pandas as pd\n", + "# from sklearn.cluster import KMeans\n", + "\n", + "# # Assuming tx_user is already defined and populated with Recency, Frequency, and Revenue columns\n", + "# # For example:\n", + "# # tx_user = pd.read_csv('path_to_your_user_data.csv')\n", + "# # If you don't have Recency, Frequency calculated, you'll need to add that logic here\n", + "\n", + "# # Step 1: Create clusters for Recency, Frequency, and Revenue\n", + "# def create_clusters(data, num_clusters, col_name):\n", + "# kmeans = KMeans(n_clusters=num_clusters, max_iter=1000)\n", + "# # Check if column exists before fitting\n", + "# if col_name in data.columns:\n", + "# kmeans.fit(data[[col_name]])\n", + "# # Ensure the new cluster column is assigned back to the DataFrame\n", + "# data[col_name + 'Cluster'] = kmeans.labels_\n", + "# else:\n", + "# print(f\"Warning: Column '{col_name}' not found in DataFrame. Skipping clustering for this column.\")\n", + "# return data\n", + "\n", + "# # Define the number of clusters you want\n", + "# num_clusters = 4\n", + "\n", + "# # Create clusters for Recency, Frequency, and Revenue\n", + "# tx_user = create_clusters(tx_user, num_clusters, 'Recency')\n", + "# tx_user = create_clusters(tx_user, num_clusters, 'Frequency')\n", + "# tx_user = create_clusters(tx_user, num_clusters, 'Revenue')\n", + "\n", + "# # Step 2: Calculate OverallScore\n", + "# # Check if all cluster columns exist before calculating OverallScore\n", + "# if 'RecencyCluster' in tx_user.columns and 'FrequencyCluster' in tx_user.columns and 'RevenueCluster' in tx_user.columns:\n", + "# tx_user['OverallScore'] = tx_user['RecencyCluster'] + tx_user['FrequencyCluster'] + tx_user['RevenueCluster']\n", + "# else:\n", + "# print(\"Warning: One or more cluster columns are missing. Cannot calculate OverallScore.\")\n", + "\n", + "# # Step 3: Group by OverallScore and calculate mean of Recency, Frequency, and Revenue\n", + "# # Check if OverallScore column exists before grouping\n", + "# if 'OverallScore' in tx_user.columns:\n", + "# result = tx_user.groupby('OverallScore')[['Recency', 'Frequency', 'Revenue']].mean()\n", + "# # Display the result\n", + "# print(result)\n", + "# tx_user.loc[tx_user['OverallScore']>2,'Segment'] = 'Mid-Value'\n", + "# tx_user.loc[tx_user['OverallScore']>4,'Segment'] = 'High-Value'\n", + "# Use code with caution" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SLhYVJZtO1MK" + }, + "source": [ + "

7. Customer Lifetime Value

" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5BNtUPKDO1ML" + }, + "source": [ + "Since our feature set is ready, let’s calculate 6 months LTV for each customer which we are going to use for training our model.\n", + "\n", + "**Lifetime Value: Total Gross Revenue - Total Cost**\n", + "\n", + "There is no cost specified in the dataset. That’s why Revenue becomes our LTV directly.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "iVr0rk7NO1ML", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 538 + }, + "outputId": "f1bd50af-4929-4512-8ce6-6f1e7e1732f9" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " InvoiceNo StockCode Description Quantity \\\n", + "0 536365 85123A WHITE HANGING HEART T-LIGHT HOLDER 6 \n", + "1 536365 71053 WHITE METAL LANTERN 6 \n", + "2 536365 84406B CREAM CUPID HEARTS COAT HANGER 8 \n", + "3 536365 84029G KNITTED UNION FLAG HOT WATER BOTTLE 6 \n", + "4 536365 84029E RED WOOLLY HOTTIE WHITE HEART. 6 \n", + "\n", + " InvoiceDate UnitPrice CustomerID Country \\\n", + "0 2010-12-01 08:26:00 2.55 17850.0 United Kingdom \n", + "1 2010-12-01 08:26:00 3.39 17850.0 United Kingdom \n", + "2 2010-12-01 08:26:00 2.75 17850.0 United Kingdom \n", + "3 2010-12-01 08:26:00 3.39 17850.0 United Kingdom \n", + "4 2010-12-01 08:26:00 3.39 17850.0 United Kingdom \n", + "\n", + " InvoiceYearMonth Revenue \n", + "0 201012 15.30 \n", + "1 201012 20.34 \n", + "2 201012 22.00 \n", + "3 201012 20.34 \n", + "4 201012 20.34 " + ], + "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", + "
InvoiceNoStockCodeDescriptionQuantityInvoiceDateUnitPriceCustomerIDCountryInvoiceYearMonthRevenue
053636585123AWHITE HANGING HEART T-LIGHT HOLDER62010-12-01 08:26:002.5517850.0United Kingdom20101215.30
153636571053WHITE METAL LANTERN62010-12-01 08:26:003.3917850.0United Kingdom20101220.34
253636584406BCREAM CUPID HEARTS COAT HANGER82010-12-01 08:26:002.7517850.0United Kingdom20101222.00
353636584029GKNITTED UNION FLAG HOT WATER BOTTLE62010-12-01 08:26:003.3917850.0United Kingdom20101220.34
453636584029ERED WOOLLY HOTTIE WHITE HEART.62010-12-01 08:26:003.3917850.0United Kingdom20101220.34
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_uk" + } + }, + "metadata": {}, + "execution_count": 90 + } + ], + "source": [ + "tx_uk.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2cm4zAl-O1ML", + "scrolled": true, + "colab": { + "base_uri": "https://localhost:8080/", + "height": 303 + }, + "outputId": "fa9e2726-4781-46d7-bbde-483057d75dc3" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "count 495478\n", + "mean 2011-07-04 05:01:41.098131456\n", + "min 2010-12-01 08:26:00\n", + "25% 2011-03-27 12:06:00\n", + "50% 2011-07-19 11:47:00\n", + "75% 2011-10-20 10:41:00\n", + "max 2011-12-09 12:49:00\n", + "Name: InvoiceDate, dtype: object" + ], + "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", + "
InvoiceDate
count495478
mean2011-07-04 05:01:41.098131456
min2010-12-01 08:26:00
25%2011-03-27 12:06:00
50%2011-07-19 11:47:00
75%2011-10-20 10:41:00
max2011-12-09 12:49:00
\n", + "

" + ] + }, + "metadata": {}, + "execution_count": 91 + } + ], + "source": [ + "tx_uk['InvoiceDate'].describe()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aVs_AWrVO1ML" + }, + "source": [ + "We see that customers are active from 1 December 2010. Let us consider customers from March onwards (so that they are not new customers). We shall divide them into 2 subgroups. One will be where timeframe of analysing is 3 months, another will be timeframe of 6 months." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Wiz_GDbYYxMP" + }, + "outputs": [], + "source": [ + "from datetime import datetime\n", + "\n", + "tx_3m = tx_uk[(tx_uk.InvoiceDate < datetime(2011,6,1)) & (tx_uk.InvoiceDate >= datetime(2011,3,1))].reset_index(drop=True) #3 months time\n", + "tx_6m = tx_uk[(tx_uk.InvoiceDate >= datetime(2011,6,1)) & (tx_uk.InvoiceDate < datetime(2011,12,1))].reset_index(drop=True) # 6 months time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7SkELym7O1ML" + }, + "outputs": [], + "source": [ + "#calculate revenue and create a new dataframe for it\n", + "tx_6m['Revenue'] = tx_6m['UnitPrice'] * tx_6m['Quantity']\n", + "tx_user_6m = tx_6m.groupby('CustomerID')['Revenue'].sum().reset_index()\n", + "tx_user_6m.columns = ['CustomerID','m6_Revenue']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mYAEizUTO1ML", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "outputId": "0ab10fca-b0ef-4f50-a12b-ab56275824c0" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID m6_Revenue\n", + "0 12747.0 1666.11\n", + "1 12748.0 18679.01\n", + "2 12749.0 2323.04\n", + "3 12820.0 561.53\n", + "4 12822.0 918.98" + ], + "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", + "
CustomerIDm6_Revenue
012747.01666.11
112748.018679.01
212749.02323.04
312820.0561.53
412822.0918.98
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_user_6m", + "summary": "{\n \"name\": \"tx_user_6m\",\n \"rows\": 3167,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1572.9401142163365,\n \"min\": 12747.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3167,\n \"samples\": [\n 13805.0,\n 15130.0,\n 13115.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"m6_Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 4782.390775124077,\n \"min\": -4287.63,\n \"max\": 180469.05,\n \"num_unique_values\": 3117,\n \"samples\": [\n 2687.56,\n 1638.68,\n 465.96\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 94 + } + ], + "source": [ + "tx_user_6m.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "sfzhm8egO1ML", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 472 + }, + "outputId": "44db0832-c93d-44fb-93c4-9a9d267e2602" + }, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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xSYGAABqhWoNRMYYJSYm6osvvtDy5csVHR193m3S09MlSeHh4ZKk2NhYbdmyRQcOHLBqUlJSFBAQoLZt21o1y5Ytc9tPSkqKYmNjyzyG0+lUQECA2wsAANRd1RqIEhIS9OGHH2r27NmqX7++srOzlZ2drZMnT0qSdu3apVdeeUVpaWn6+eefNX/+fA0ePFhdu3ZVx44dJUk9e/ZU27Zt9cADD2jTpk1asmSJXnzxRSUkJMjpdEqSHnvsMf3000969tlntX37dr377ruaO3eunnrqqWqbOwAAqDmqNRBNnTpV+fn56tatm8LDw63XnDlzJEk+Pj5aunSpevbsqdatW+vpp59Wv3799N///tfah6enpxYsWCBPT0/Fxsbq/vvv1+DBg/Xyyy9bNdHR0Vq4cKFSUlLUqVMnvfHGG/rHP/7BI/cAAEBSNd9UbYw553hkZKRWrVp13v1ERUVp0aJF56zp1q2bNm7ceEH9AQAAe6gRN1UDAABUJwIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwPQIRAACwvWoNRMnJybr22mtVv359hYSEqG/fvsrMzHSrOXXqlBISEtSoUSNddtll6tevn3JyctxqsrKy1KdPH/n7+yskJESjRo3SmTNn3GpWrlypzp07y+l0qmXLlpo5c+alnh4AAKglqjUQrVq1SgkJCVq3bp1SUlJUWFionj176vjx41bNU089pf/+97/65JNPtGrVKu3bt0933323NV5UVKQ+ffro9OnTWrt2rWbNmqWZM2dqzJgxVs3u3bvVp08fde/eXenp6RoxYoSGDRumJUuWVOl8AQBA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0LXXXqt27dppzZo1l6pXAACAS+KCAtGbb76p4cOHKyAgoNRYYGCgHn30UU2aNKnSmgMAAKgKFxSINm3apF69ep11vGfPnkpLS7vopgAAAKrSBQWinJycMh+3L+Hl5aWDBw9edFMAAABV6YICUZMmTZSRkXHW8c2bNys8PPyimwIAAKhKFxSIbrvtNr300ks6depUqbGTJ09q7Nixuv322yutOQAAgKpwQY/dv/jii/r888915ZVXKjExUa1atZIkbd++XVOmTFFRUZFeeOGFS9IoAADApXJBgSg0NFRr167V448/rqSkJBljJEkOh0Px8fGaMmWKQkNDL0mjAAAAl8oFfzFjVFSUFi1apCNHjmjnzp0yxuiKK65QgwYNLkV/AAAAl1yFvqlakho0aKBrr722MnsBAACoFhX6XWYAAAB1CYEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYHoEIAADYXrUGotWrV+uOO+5QRESEHA6H5s2b5zZujNGYMWMUHh4uPz8/xcXFaceOHW41ubm5GjRokAICAhQUFKShQ4fq2LFjbjWbN2/WzTffLF9fX0VGRmrixImXemoAAKAWqdZAdPz4cXXq1ElTpkwpc3zixIl6++23NW3aNK1fv1716tVTfHy8Tp06ZdUMGjRIW7duVUpKihYsWKDVq1frkUcescZdLpd69uypqKgopaWl6bXXXtO4ceP03nvvXfL5AQCA2sGrOg/eu3dv9e7du8wxY4zefPNNvfjii7rrrrskSf/85z8VGhqqefPmacCAAdq2bZsWL16s7777Ttdcc40k6Z133tFtt92m119/XREREfroo490+vRpzZgxQz4+PmrXrp3S09M1adIkt+AEAADsq8beQ7R7925lZ2crLi7OWhcYGKiYmBilpqZKklJTUxUUFGSFIUmKi4uTh4eH1q9fb9V07dpVPj4+Vk18fLwyMzN15MiRKpoNAACoyar1CtG5ZGdnS5JCQ0Pd1oeGhlpj2dnZCgkJcRv38vJS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\n" + }, + "metadata": {} + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "# Plot the histogram\n", + "plt.hist(tx_user_6m['m6_Revenue'], bins=30, edgecolor='black')\n", + "\n", + "# Set the title and labels\n", + "plt.title('6m Revenue')\n", + "plt.xlabel('Revenue')\n", + "plt.ylabel('Count')\n", + "\n", + "# Display the plot\n", + "plt.show()\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "RbWoD9C9O1ML" + }, + "source": [ + "Histogram clearly shows we have customers with negative LTV. We have some outliers too. Filtering out the outliers makes sense to have a proper machine learning model." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "TuIbH_htO1MM" + }, + "source": [ + "Ok, next step. We will merge our 3 months and tx_uk and also merge 6 months dataframe and tx_uk to see correlations between LTV and the feature set we have." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "s3ywyb_JO1MM", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 313 + }, + "outputId": "2506c89e-802b-41bd-8927-fd39d6ff3584" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Recency RecencyCluster Frequency FrequencyCluster Revenue \\\n", + "0 17850.0 301 0 312 1 5288.63 \n", + "1 14688.0 7 3 359 1 5107.38 \n", + "2 13767.0 1 3 399 1 16945.71 \n", + "3 15513.0 30 3 314 1 14520.08 \n", + "4 14849.0 21 3 392 1 7904.28 \n", + "\n", + " RevenueCluster OverallScore Segment \n", + "0 1 2 Low-Value \n", + "1 1 5 High-Value \n", + "2 1 5 High-Value \n", + "3 1 5 High-Value \n", + "4 1 5 High-Value " + ], + "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", + "
CustomerIDRecencyRecencyClusterFrequencyFrequencyClusterRevenueRevenueClusterOverallScoreSegment
017850.0301031215288.6312Low-Value
114688.07335915107.3815High-Value
213767.013399116945.7115High-Value
315513.0303314114520.0815High-Value
414849.021339217904.2815High-Value
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_user", + "summary": "{\n \"name\": \"tx_user\",\n \"rows\": 3950,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1576.8483250815016,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3950,\n \"samples\": [\n 17172.0,\n 13607.0,\n 13379.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 189,\n 307,\n 161\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 3,\n 1,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Frequency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 220,\n \"min\": 1,\n \"max\": 7983,\n \"num_unique_values\": 455,\n \"samples\": [\n 718,\n 500,\n 99\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"FrequencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 0,\n 3,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 6548.608224207447,\n \"min\": -4287.63,\n \"max\": 256438.49,\n \"num_unique_values\": 3878,\n \"samples\": [\n 102.83,\n 190.53,\n 314.69\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RevenueCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 0,\n 3,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"OverallScore\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 8,\n \"num_unique_values\": 9,\n \"samples\": [\n 7,\n 5,\n 6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Segment\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"Low-Value\",\n \"High-Value\",\n \"Mid-Value\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 96 + } + ], + "source": [ + "tx_user.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "npq34CtaO1MM", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 538 + }, + "outputId": "a10d8f0f-d3a1-4ccf-d957-b81bd8f932db" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " InvoiceNo StockCode Description Quantity \\\n", + "0 536365 85123A WHITE HANGING HEART T-LIGHT HOLDER 6 \n", + "1 536365 71053 WHITE METAL LANTERN 6 \n", + "2 536365 84406B CREAM CUPID HEARTS COAT HANGER 8 \n", + "3 536365 84029G KNITTED UNION FLAG HOT WATER BOTTLE 6 \n", + "4 536365 84029E RED WOOLLY HOTTIE WHITE HEART. 6 \n", + "\n", + " InvoiceDate UnitPrice CustomerID Country \\\n", + "0 2010-12-01 08:26:00 2.55 17850.0 United Kingdom \n", + "1 2010-12-01 08:26:00 3.39 17850.0 United Kingdom \n", + "2 2010-12-01 08:26:00 2.75 17850.0 United Kingdom \n", + "3 2010-12-01 08:26:00 3.39 17850.0 United Kingdom \n", + "4 2010-12-01 08:26:00 3.39 17850.0 United Kingdom \n", + "\n", + " InvoiceYearMonth Revenue \n", + "0 201012 15.30 \n", + "1 201012 20.34 \n", + "2 201012 22.00 \n", + "3 201012 20.34 \n", + "4 201012 20.34 " + ], + "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", + "
InvoiceNoStockCodeDescriptionQuantityInvoiceDateUnitPriceCustomerIDCountryInvoiceYearMonthRevenue
053636585123AWHITE HANGING HEART T-LIGHT HOLDER62010-12-01 08:26:002.5517850.0United Kingdom20101215.30
153636571053WHITE METAL LANTERN62010-12-01 08:26:003.3917850.0United Kingdom20101220.34
253636584406BCREAM CUPID HEARTS COAT HANGER82010-12-01 08:26:002.7517850.0United Kingdom20101222.00
353636584029GKNITTED UNION FLAG HOT WATER BOTTLE62010-12-01 08:26:003.3917850.0United Kingdom20101220.34
453636584029ERED WOOLLY HOTTIE WHITE HEART.62010-12-01 08:26:003.3917850.0United Kingdom20101220.34
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_uk" + } + }, + "metadata": {}, + "execution_count": 97 + } + ], + "source": [ + "tx_uk.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rq3lDDlTO1MM" + }, + "outputs": [], + "source": [ + "tx_merge = pd.merge(tx_user, tx_user_6m, on='CustomerID', how='left') #Only people who are in the timeline of tx_user_6m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zLvMF5H0O1MM" + }, + "outputs": [], + "source": [ + "tx_merge = tx_merge.fillna(0)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "id": "lLMnrL9OO1MM", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 557 + }, + "outputId": "34051a3e-fd21-4a10-fdaf-a46d81245ca0" + }, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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AAAAADiEQAYAAAAADiGQAQAAAIBDCGQp6OGHH1b//v2Vk5OjYcOG6Z133nG6pJSxbNkyXXDBBerTp48sy9ILL7zgdEkp45577tGpp56qvLw89erVSxMmTND69eudLitlPPLIIxoyZEjzYZklJSV65ZVXnC4rZd17772yLEtTpkxxupSUcOedd8qyrBaPQYMGOV1WStmyZYuuuOIKde/eXZ06ddIJJ5yg1atXO11Wyujfv3+r32HLsjRp0iSnS0t6TU1NmjZtmgYMGKBOnTrpG9/4hv7nf/5HybRvIYEsxTzzzDOaOnWqZsyYoffee08nnniixo4dq+3btztdWkqora3ViSeeqIcfftjpUlLO0qVLNWnSJL311lt6/fXX1dDQoHPOOUe1tbVOl5YS+vbtq3vvvVdr1qzR6tWrdfbZZ+s73/mOPvroI6dLSznvvvuu/vjHP2rIkCFOl5JSjjvuOH355ZfNjxUrVjhdUsrYuXOnhg8frqysLL3yyiv6+OOP9dvf/lZdu3Z1urSU8e6777b4/X399dclSd///vcdriz5/frXv9Yjjzyihx56SBUVFfr1r3+t++67T3/4wx+cLi1ibHufYoYNG6ZTTz1VDz30kCQpFAqpsLBQN954o2677TaHq0stlmXp+eef14QJE5wuJSVVVVWpV69eWrp0qUaOHOl0OSmpW7du+s1vfqNrrrnG6VJSxq5du3TyySdr1qxZ+uUvf6mTTjpJDzzwgNNlJb0777xTL7zwgsrLy50uJSXddtttWrlypZYvX+50KWljypQpevnll/XJJ5/Isiyny0lq559/vnr37q2//vWvzdcuuugiderUSU8++aSDlUWOEbIUUl9frzVr1mjMmDHN11wul8aMGaNVq1Y5WBkQPb/fL8mEBsRWU1OTnn76adXW1qqkpMTpclLKpEmTNH78+Bb/HkZsfPLJJ+rTp4+OPvpoXX755dq0aZPTJaWMl156Saeccoq+//3vq1evXiouLtaf//xnp8tKWfX19XryySd19dVXE8Zi4Fvf+pYWLVqkDRs2SJLef/99rVixQuPGjXO4sshlOl0AYmfHjh1qampS7969W1zv3bu31q1b51BVQPRCoZCmTJmi4cOH6/jjj3e6nJSxdu1alZSUqK6uTl26dNHzzz+vwYMHO11Wynj66af13nvv6d1333W6lJQzbNgwzZkzRwMHDtSXX36pu+66SyNGjNCHH36ovLw8p8tLep9++qkeeeQRTZ06VXfccYfeffdd/fjHP1Z2drYmTpzodHkp54UXXlB1dbWuvPJKp0tJCbfddpsCgYAGDRqkjIwMNTU16Ve/+pUuv/xyp0uLGIEMQMKZNGmSPvzwQ9aIxNjAgQNVXl4uv9+v//u//9PEiRO1dOlSQlkMbN68WTfddJNef/115eTkOF1Oytn3L91DhgzRsGHDdNRRR+nZZ59lym0MhEIhnXLKKbr77rslScXFxfrwww81e/ZsAlkc/PWvf9W4cePUp08fp0tJCc8++6yeeuopzZ07V8cdd5zKy8s1ZcoU9enTJ2l+fwlkKaRHjx7KyMjQtm3bWlzftm2bCgoKHKoKiM7kyZP18ssva9myZerbt6/T5aSU7OxsHXPMMZKkoUOH6t1339Xvf/97/fGPf3S4suS3Zs0abd++XSeffHLztaamJi1btkwPPfSQgsGgMjIyHKwwteTn5+vYY4/Vv/71L6dLSQlHHHFEqz/MFBUV6e9//7tDFaWuzz//XAsXLtQ//vEPp0tJGT/72c9022236ZJLLpEknXDCCfr88891zz33JE0gYw1ZCsnOztbQoUO1aNGi5muhUEiLFi1inQgSnm3bmjx5sp5//nktXrxYAwYMcLqklBcKhRQMBp0uIyWMHj1aa9euVXl5efPjlFNO0eWXX67y8nLCWIzt2rVL//73v3XEEUc4XUpKGD58eKtjRjZs2KCjjjrKoYpS12OPPaZevXpp/PjxTpeSMnbv3i2Xq2WkycjIUCgUcqii6DFClmKmTp2qiRMn6pRTTtFpp52mBx54QLW1tbrqqqucLi0l7Nq1q8VfZDdu3Kjy8nJ169ZN/fr1c7Cy5Ddp0iTNnTtXL774ovLy8lRZWSlJ8nq96tSpk8PVJb/bb79d48aNU79+/VRTU6O5c+dqyZIleu2115wuLSXk5eW1Wu+Ym5ur7t27sw4yBn7605/qggsu0FFHHaWtW7dqxowZysjI0KWXXup0aSnh5ptv1re+9S3dfffd+u///m+98847+tOf/qQ//elPTpeWUkKhkB577DFNnDhRmZl8BI+VCy64QL/61a/Ur18/HXfccfL5fPrd736nq6++2unSImcj5fzhD3+w+/XrZ2dnZ9unnXaa/dZbbzldUsp44403bEmtHhMnTnS6tKR3oPsqyX7sscecLi0lXH311fZRRx1lZ2dn2z179rRHjx5t//Of/3S6rJQ2atQo+6abbnK6jJRw8cUX20cccYSdnZ1tH3nkkfbFF19s/+tf/3K6rJQyb948+/jjj7fdbrc9aNAg+09/+pPTJaWc1157zZZkr1+/3ulSUkogELBvuukmu1+/fnZOTo599NFH2z//+c/tYDDodGkR4xwyAAAAAHAIa8gAAAAAwCEEMgAAAABwCIEMAAAAABxCIAMAAAAAhxDIAAAAAMAhBDIAAAAAcAiBDAAAAAAcQiADAAAAAIcQyAAAAADAIQQyAEDSu/LKK2VZlizLUlZWlgYMGKBbbrlFdXV1LdqF2+z7OOOMM1q9/9Zbb7XoFwwG1b17d1mWpSVLlhy0jqqqKt1www3q16+f3G63CgoKNHbsWK1cuTKmPy8AIHVkOl0AAACxcO655+qxxx5TQ0OD1qxZo4kTJ8qyLP36179u0e6xxx7Tueee2/w6Ozu7xfuFhYV67LHHdPrppzdfe/7559WlSxd9/fXXh6zhoosuUn19vR5//HEdffTR2rZtmxYtWqSvvvoqBj/hgdXX17f6GQAAyYMRMgBASgiPSBUWFmrChAkaM2aMXn/99Vbt8vPzVVBQ0Pzo1q1bi/cnTpyop59+Wnv27Gm+9uijj2rixImH/P7V1dVavny5fv3rX+uss87SUUcdpdNOO0233367/uu//qtFux/96Efq3bu3cnJydPzxx+vll19ufv/vf/+7jjvuOLndbvXv31+//e1vW3yf/v3763/+53/0gx/8QB6PRz/84Q8lSStWrNCIESPUqVMnFRYW6sc//rFqa2sjv4EAAEcQyAAAKefDDz/Um2++2a6Ro6FDh6p///76+9//LknatGmTli1bptLS0kP269Kli7p06aIXXnhBwWDwgG1CoZDGjRunlStX6sknn9THH3+se++9VxkZGZKkNWvW6L//+791ySWXaO3atbrzzjs1bdo0zZkzp8XX+d///V+deOKJ8vl8mjZtmv7973/r3HPP1UUXXaQPPvhAzzzzjFasWKHJkydH/fMDADqWZdu27XQRAAAcjiuvvFJPPvmkcnJy1NjYqGAwKJfLpWeffVYXXXRRczvLspSTk9McgCTpySef1IQJE5rff/755/X555/rxRdf1OLFizVz5kyVl5fr0UcfVdeuXfXGG2/ozDPPPGAdf//733Xddddpz549OvnkkzVq1ChdcsklGjJkiCTpn//8p8aNG6eKigode+yxrfpffvnlqqqq0j//+c/ma7fccovmz5+vjz76SJIZISsuLtbzzz/f3Obaa69VRkaG/vjHPzZfW7FihUaNGqXa2lrl5OREf1MBAB2CETIAQEo466yzVF5errffflsTJ07UVVdd1SKMhd1///0qLy9vfnz7299u1eaKK67QqlWr9Omnn2rOnDm6+uqrI6rhoosu0tatW/XSSy/p3HPP1ZIlS3TyySc3j3CVl5erb9++BwxjklRRUaHhw4e3uDZ8+HB98sknampqar52yimntGjz/vvva86cOc2jdF26dNHYsWMVCoW0cePGiGoHADiDTT0AACkhNzdXxxxzjCSz5uvEE0/UX//6V11zzTUt2hUUFDS3O5ju3bvr/PPP1zXXXKO6ujqNGzdONTU1EdWRk5Ojb3/72/r2t7+tadOm6dprr9WMGTN05ZVXqlOnTu374faTm5vb4vWuXbv0ox/9SD/+8Y9bte3Xr19MvicAID4YIQMApByXy6U77rhDv/jFL1pszhGNq6++WkuWLNEPfvCDFlMcozV48ODmzTWGDBmiL774Qhs2bDhg26KiolZb5K9cuVLHHnvsIWs4+eST9fHHH+uYY45p9WAHRgBIbAQyAEBK+v73v6+MjAw9/PDD7ep/7rnnqqqqSjNnzoyo/VdffaWzzz5bTz75pD744ANt3LhRzz33nO677z595zvfkSSNGjVKI0eO1EUXXaTXX39dGzdu1CuvvKJXX31VkvSTn/xEixYt0v/8z/9ow4YNevzxx/XQQw/ppz/96SG/96233qo333xTkydPVnl5uT755BO9+OKLbOoBAEmAQAYASEmZmZmaPHmy7rvvvnZt/25Zlnr06BHxCFOXLl00bNgw3X///Ro5cqSOP/54TZs2Tdddd50eeuih5nZ///vfdeqpp+rSSy/V4MGDdcsttzSvDzv55JP17LPP6umnn9bxxx+v6dOna+bMmbryyisP+b2HDBmipUuXasOGDRoxYoSKi4s1ffp09enTJ+qfGwDQsdhlEQAAAAAcwggZAAAAADiEQAYAAAAADiGQAQAAAIBDCGQAAAAA4BACGQAAAAA4hEAGAAAAAA4hkAEAAACAQwhkAAAAAOAQAhkAAAAAOIRABgAAAAAOIZABAAAAgEP+P1rL3hHgrlaqAAAAAElFTkSuQmCC\n" + }, + "metadata": {} + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "# Filter the data\n", + "tx_graph = tx_merge.query(\"m6_Revenue < 50000\")\n", + "\n", + "# Create the figure and axis objects\n", + "plt.figure(figsize=(10, 6))\n", + "\n", + "# Plot the scatter plots for each segment\n", + "plt.scatter(\n", + " tx_graph.query(\"Segment == 'Low-Value'\")['OverallScore'],\n", + " tx_graph.query(\"Segment == 'Low-Value'\")['m6_Revenue'],\n", + " color='blue',\n", + " s=7**2, # Marker size (matplotlib sizes markers by area, hence s=7^2)\n", + " alpha=0.8,\n", + " label='Low'\n", + ")\n", + "\n", + "plt.scatter(\n", + " tx_graph.query(\"Segment == 'Mid-Value'\")['OverallScore'],\n", + " tx_graph.query(\"Segment == 'Mid-Value'\")['m6_Revenue'],\n", + " color='green',\n", + " s=9**2, # Marker size\n", + " alpha=0.5,\n", + " label='Mid'\n", + ")\n", + "\n", + "plt.scatter(\n", + " tx_graph.query(\"Segment == 'High-Value'\")['OverallScore'],\n", + " tx_graph.query(\"Segment == 'High-Value'\")['m6_Revenue'],\n", + " color='red',\n", + " s=11**2, # Marker size\n", + " alpha=0.9,\n", + " label='High'\n", + ")\n", + "\n", + "# Set the title and labels\n", + "plt.title('LTV')\n", + "plt.xlabel('RFM Score')\n", + "plt.ylabel('6m LTV')\n", + "\n", + "# Add a legend\n", + "plt.legend()\n", + "\n", + "# Show the plot\n", + "plt.show()\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "RCMmivKsO1MM" + }, + "source": [ + "We can visualise correlation between overall RFM score and revenue. Positive correlation is quite visible here. High RFM score means high LTV.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UPJ__rwiO1MM" + }, + "source": [ + "Before building the machine learning model, we need to identify what is the type of this machine learning problem. LTV itself is a regression problem. A machine learning model can predict the $ value of the LTV. But here, we want LTV segments. Because it makes it more actionable and easy to communicate with other people. By applying K-means clustering, we can identify our existing LTV groups and build segments on top of it.\n", + "\n", + "Considering business part of this analysis, we need to treat customers differently based on their predicted LTV. For this example, we will apply clustering and have 3 segments (number of segments really depends on your business dynamics and goals):\n", + "* Low LTV\n", + "* Mid LTV\n", + "* High LTV\n", + "\n", + "We are going to apply K-means clustering to decide segments and observe their characteristics\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "keUkjb1LO1MM" + }, + "outputs": [], + "source": [ + "#remove outliers\n", + "tx_merge = tx_merge[tx_merge['m6_Revenue']\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CustomerIDRecencyRecencyClusterFrequencyFrequencyClusterRevenueRevenueClusterOverallScoreSegmentm6_Revenue
017850.0301031215288.6312Low-Value0.00
114688.07335915107.3815High-Value1702.06
414849.021339217904.2815High-Value5498.07
613468.01330615656.7515High-Value1813.09
717690.029325814748.4515High-Value2616.15
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + " \n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_merge", + "summary": "{\n \"name\": \"tx_merge\",\n \"rows\": 3910,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1575.3246255165336,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3910,\n \"samples\": [\n 16209.0,\n 16172.0,\n 17500.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 189,\n 307,\n 161\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 3,\n 1,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Frequency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 131,\n \"min\": 1,\n \"max\": 2782,\n \"num_unique_values\": 437,\n \"samples\": [\n 163,\n 299,\n 340\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"FrequencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 2,\n \"num_unique_values\": 3,\n \"samples\": [\n 1,\n 0,\n 2\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1896.155427288516,\n \"min\": -4287.63,\n \"max\": 21535.9,\n \"num_unique_values\": 3838,\n \"samples\": [\n 2584.4,\n 2126.93,\n 741.26\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RevenueCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 1,\n \"num_unique_values\": 2,\n \"samples\": [\n 0,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"OverallScore\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 6,\n \"num_unique_values\": 7,\n \"samples\": [\n 2,\n 5\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Segment\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"Low-Value\",\n \"High-Value\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"m6_Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1057.0800280963301,\n \"min\": -4287.63,\n \"max\": 8432.68,\n \"num_unique_values\": 3077,\n \"samples\": [\n 4016.29,\n 173.76\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 102 + } + ], + "source": [ + "tx_merge.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XWUBYq8rO1MN", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 382 + }, + "outputId": "0416683c-4c66-4eac-da71-2ecfb68f4d1f" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning:\n", + "\n", + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n", + "\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Recency RecencyCluster Frequency FrequencyCluster Revenue \\\n", + "0 17850.0 301 0 312 1 5288.63 \n", + "1 14688.0 7 3 359 1 5107.38 \n", + "4 14849.0 21 3 392 1 7904.28 \n", + "6 13468.0 1 3 306 1 5656.75 \n", + "7 17690.0 29 3 258 1 4748.45 \n", + "\n", + " RevenueCluster OverallScore Segment m6_Revenue LTVCluster \n", + "0 1 2 Low-Value 0.00 0 \n", + "1 1 5 High-Value 1702.06 2 \n", + "4 1 5 High-Value 5498.07 1 \n", + "6 1 5 High-Value 1813.09 2 \n", + "7 1 5 High-Value 2616.15 2 " + ], + "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", + "
CustomerIDRecencyRecencyClusterFrequencyFrequencyClusterRevenueRevenueClusterOverallScoreSegmentm6_RevenueLTVCluster
017850.0301031215288.6312Low-Value0.000
114688.07335915107.3815High-Value1702.062
414849.021339217904.2815High-Value5498.071
613468.01330615656.7515High-Value1813.092
717690.029325814748.4515High-Value2616.152
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_merge", + "summary": "{\n \"name\": \"tx_merge\",\n \"rows\": 3910,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1575.3246255165336,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3910,\n \"samples\": [\n 16209.0,\n 16172.0,\n 17500.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 189,\n 307,\n 161\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 3,\n 1,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Frequency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 131,\n \"min\": 1,\n \"max\": 2782,\n \"num_unique_values\": 437,\n \"samples\": [\n 163,\n 299,\n 340\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"FrequencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 2,\n \"num_unique_values\": 3,\n \"samples\": [\n 1,\n 0,\n 2\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1896.155427288516,\n \"min\": -4287.63,\n \"max\": 21535.9,\n \"num_unique_values\": 3838,\n \"samples\": [\n 2584.4,\n 2126.93,\n 741.26\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RevenueCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 1,\n \"num_unique_values\": 2,\n \"samples\": [\n 0,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"OverallScore\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 6,\n \"num_unique_values\": 7,\n \"samples\": [\n 2,\n 5\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Segment\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"Low-Value\",\n \"High-Value\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"m6_Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1057.0800280963301,\n \"min\": -4287.63,\n \"max\": 8432.68,\n \"num_unique_values\": 3077,\n \"samples\": [\n 4016.29,\n 173.76\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LTVCluster\",\n \"properties\": {\n \"dtype\": \"int32\",\n \"num_unique_values\": 3,\n \"samples\": [\n 0,\n 2\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 103 + } + ], + "source": [ + "#creating 3 clusters\n", + "kmeans = KMeans(n_clusters=3)\n", + "tx_merge['LTVCluster'] = kmeans.fit_predict(tx_merge[['m6_Revenue']])\n", + "\n", + "tx_merge.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XPs3Nq6MO1MN", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 174 + }, + "outputId": "45b881df-f289-43dd-87ab-26b6f6a4a259" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " count mean std min 25% 50% \\\n", + "LTVCluster \n", + "0 2960.0 277.296717 282.043305 -4287.63 0.0000 229.110 \n", + "1 794.0 1609.586914 549.435635 941.95 1148.8350 1482.900 \n", + "2 156.0 4645.661795 1345.674897 3129.27 3537.7325 4256.115 \n", + "\n", + " 75% max \n", + "LTVCluster \n", + "0 452.9325 940.83 \n", + "1 1945.7975 3113.70 \n", + "2 5497.9800 8432.68 " + ], + "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", + "
countmeanstdmin25%50%75%max
LTVCluster
02960.0277.296717282.043305-4287.630.0000229.110452.9325940.83
1794.01609.586914549.435635941.951148.83501482.9001945.79753113.70
2156.04645.6617951345.6748973129.273537.73254256.1155497.98008432.68
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "summary": "{\n \"name\": \"tx_cluster\",\n \"rows\": 3,\n \"fields\": [\n {\n \"column\": \"LTVCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 2,\n \"num_unique_values\": 3,\n \"samples\": [\n 0,\n 1,\n 2\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"count\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1469.7514529107746,\n \"min\": 156.0,\n \"max\": 2960.0,\n \"num_unique_values\": 3,\n \"samples\": [\n 2960.0,\n 794.0,\n 156.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"mean\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 2238.874765777621,\n \"min\": 277.2967172297297,\n \"max\": 4645.661794871795,\n \"num_unique_values\": 3,\n \"samples\": [\n 277.2967172297297,\n 1609.5869143576826,\n 4645.661794871795\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"std\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 553.2943440760093,\n \"min\": 282.0433045759854,\n \"max\": 1345.6748974689422,\n \"num_unique_values\": 3,\n \"samples\": [\n 282.0433045759854,\n 549.4356347614342,\n 1345.6748974689422\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"min\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 3811.0208905401364,\n \"min\": -4287.63,\n \"max\": 3129.27,\n \"num_unique_values\": 3,\n \"samples\": [\n -4287.63,\n 941.95,\n 3129.27\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"25%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1804.7254807074078,\n \"min\": 0.0,\n \"max\": 3537.7325,\n \"num_unique_values\": 3,\n \"samples\": [\n 0.0,\n 1148.835,\n 3537.7325\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"50%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 2060.7231768786896,\n \"min\": 229.11,\n \"max\": 4256.115,\n \"num_unique_values\": 3,\n \"samples\": [\n 229.11,\n 1482.9,\n 4256.115\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"75%\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 2591.6259599843074,\n \"min\": 452.9325,\n \"max\": 5497.98,\n \"num_unique_values\": 3,\n \"samples\": [\n 452.9325,\n 1945.7975,\n 5497.98\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"max\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 3854.450429909994,\n \"min\": 940.83,\n \"max\": 8432.68,\n \"num_unique_values\": 3,\n \"samples\": [\n 940.83,\n 3113.7,\n 8432.68\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 104 + } + ], + "source": [ + "#order cluster number based on LTV\n", + "tx_merge = order_cluster('LTVCluster', 'm6_Revenue',tx_merge,True)\n", + "\n", + "#creatinga new cluster dataframe\n", + "tx_cluster = tx_merge.copy()\n", + "\n", + "#see details of the clusters\n", + "tx_cluster.groupby('LTVCluster')['m6_Revenue'].describe()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pPG-wmbUO1MN" + }, + "source": [ + "We have finished LTV clustering and here are the characteristics of each clusters as shown above.\n", + "\n", + "Cluster 2 is the best with average 8.2k LTV whereas 0 is the worst with 396." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "l8g5GKAvO1MN" + }, + "source": [ + "There are few more step before training the machine learning model:\n", + "* Feature engineering.\n", + "* Convert categorical columns to numerical columns.\n", + "* We will check the correlation of features against our label, LTV clusters.\n", + "* We will split our feature set and label (LTV) as X and y. We use X to predict y.\n", + "* Will create Training and Test dataset. Training set will be used for building the machine learning model. We will apply our model to Test set to see its real performance.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wRCSfnIQO1MN", + "scrolled": true, + "colab": { + "base_uri": "https://localhost:8080/", + "height": 313 + }, + "outputId": "27a54dc2-28e2-4e47-83c5-92a91930b528" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Recency RecencyCluster Frequency FrequencyCluster Revenue \\\n", + "0 17850.0 301 0 312 1 5288.63 \n", + "1 13093.0 266 0 170 0 7741.47 \n", + "2 15032.0 255 0 55 0 4464.10 \n", + "3 16000.0 2 3 9 0 12393.70 \n", + "4 15749.0 234 1 15 0 21535.90 \n", + "\n", + " RevenueCluster OverallScore Segment m6_Revenue LTVCluster \n", + "0 1 2 Low-Value 0.0 0 \n", + "1 1 1 Low-Value 0.0 0 \n", + "2 1 1 Low-Value 0.0 0 \n", + "3 1 4 Mid-Value 0.0 0 \n", + "4 1 2 Low-Value 0.0 0 " + ], + "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", + "
CustomerIDRecencyRecencyClusterFrequencyFrequencyClusterRevenueRevenueClusterOverallScoreSegmentm6_RevenueLTVCluster
017850.0301031215288.6312Low-Value0.00
113093.0266017007741.4711Low-Value0.00
215032.025505504464.1011Low-Value0.00
316000.0239012393.7014Mid-Value0.00
415749.0234115021535.9012Low-Value0.00
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_cluster", + "summary": "{\n \"name\": \"tx_cluster\",\n \"rows\": 3910,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1575.3246255165336,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3910,\n \"samples\": [\n 15925.0,\n 16967.0,\n 14652.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 174,\n 319,\n 203\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 3,\n 2,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Frequency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 131,\n \"min\": 1,\n \"max\": 2782,\n \"num_unique_values\": 437,\n \"samples\": [\n 380,\n 27,\n 247\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"FrequencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 2,\n \"num_unique_values\": 3,\n \"samples\": [\n 1,\n 0,\n 2\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1896.155427288516,\n \"min\": -4287.63,\n \"max\": 21535.9,\n \"num_unique_values\": 3838,\n \"samples\": [\n 176.6,\n 338.8,\n 1430.94\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RevenueCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 1,\n \"num_unique_values\": 2,\n \"samples\": [\n 0,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"OverallScore\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 6,\n \"num_unique_values\": 7,\n \"samples\": [\n 2,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Segment\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"Low-Value\",\n \"Mid-Value\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"m6_Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1057.0800280963301,\n \"min\": -4287.63,\n \"max\": 8432.68,\n \"num_unique_values\": 3077,\n \"samples\": [\n 283.84,\n 124.14999999999999\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LTVCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 2,\n \"num_unique_values\": 3,\n \"samples\": [\n 0,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 105 + } + ], + "source": [ + "tx_cluster.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cwIcGIBYO1MN" + }, + "source": [ + "

7.1 Feature Engineering

" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "k_dd1HfjO1MN", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 243 + }, + "outputId": "0b9102cf-2ad1-49c4-d60d-e80d639b9cd8" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " CustomerID Recency RecencyCluster Frequency FrequencyCluster Revenue \\\n", + "0 17850.0 301 0 312 1 5288.63 \n", + "1 13093.0 266 0 170 0 7741.47 \n", + "2 15032.0 255 0 55 0 4464.10 \n", + "3 16000.0 2 3 9 0 12393.70 \n", + "4 15749.0 234 1 15 0 21535.90 \n", + "\n", + " RevenueCluster OverallScore m6_Revenue LTVCluster Segment_High-Value \\\n", + "0 1 2 0.0 0 False \n", + "1 1 1 0.0 0 False \n", + "2 1 1 0.0 0 False \n", + "3 1 4 0.0 0 False \n", + "4 1 2 0.0 0 False \n", + "\n", + " Segment_Low-Value Segment_Mid-Value \n", + "0 True False \n", + "1 True False \n", + "2 True False \n", + "3 False True \n", + "4 True False " + ], + "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", + "
CustomerIDRecencyRecencyClusterFrequencyFrequencyClusterRevenueRevenueClusterOverallScorem6_RevenueLTVClusterSegment_High-ValueSegment_Low-ValueSegment_Mid-Value
017850.0301031215288.63120.00FalseTrueFalse
113093.0266017007741.47110.00FalseTrueFalse
215032.025505504464.10110.00FalseTrueFalse
316000.0239012393.70140.00FalseFalseTrue
415749.0234115021535.90120.00FalseTrueFalse
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "tx_class", + "summary": "{\n \"name\": \"tx_class\",\n \"rows\": 3910,\n \"fields\": [\n {\n \"column\": \"CustomerID\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1575.3246255165336,\n \"min\": 12346.0,\n \"max\": 18287.0,\n \"num_unique_values\": 3910,\n \"samples\": [\n 15925.0,\n 16967.0,\n 14652.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Recency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 100,\n \"min\": 0,\n \"max\": 373,\n \"num_unique_values\": 348,\n \"samples\": [\n 174,\n 319,\n 203\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RecencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 3,\n \"num_unique_values\": 4,\n \"samples\": [\n 3,\n 2,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Frequency\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 131,\n \"min\": 1,\n \"max\": 2782,\n \"num_unique_values\": 437,\n \"samples\": [\n 380,\n 27,\n 247\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"FrequencyCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 2,\n \"num_unique_values\": 3,\n \"samples\": [\n 1,\n 0,\n 2\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1896.155427288516,\n \"min\": -4287.63,\n \"max\": 21535.9,\n \"num_unique_values\": 3838,\n \"samples\": [\n 176.6,\n 338.8,\n 1430.94\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RevenueCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 1,\n \"num_unique_values\": 2,\n \"samples\": [\n 0,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"OverallScore\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1,\n \"min\": 0,\n \"max\": 6,\n \"num_unique_values\": 7,\n \"samples\": [\n 2,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"m6_Revenue\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1057.0800280963301,\n \"min\": -4287.63,\n \"max\": 8432.68,\n \"num_unique_values\": 3077,\n \"samples\": [\n 283.84,\n 124.14999999999999\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LTVCluster\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 2,\n \"num_unique_values\": 3,\n \"samples\": [\n 0,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Segment_High-Value\",\n \"properties\": {\n \"dtype\": \"boolean\",\n \"num_unique_values\": 2,\n \"samples\": [\n true,\n false\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Segment_Low-Value\",\n \"properties\": {\n \"dtype\": \"boolean\",\n \"num_unique_values\": 2,\n \"samples\": [\n false,\n true\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Segment_Mid-Value\",\n \"properties\": {\n \"dtype\": \"boolean\",\n \"num_unique_values\": 2,\n \"samples\": [\n true,\n false\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 106 + } + ], + "source": [ + "#convert categorical columns to numerical\n", + "tx_class = pd.get_dummies(tx_cluster) #There is only one categorical variable segment\n", + "tx_class.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YuVfI9ASO1MN", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 491 + }, + "outputId": "6ab184d3-330c-4b48-f1a8-8f9479a8bb74" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "LTVCluster 1.000000\n", + "m6_Revenue 0.877872\n", + "Revenue 0.775550\n", + "RevenueCluster 0.605556\n", + "Frequency 0.569399\n", + "OverallScore 0.542147\n", + "FrequencyCluster 0.515290\n", + "Segment_High-Value 0.496939\n", + "RecencyCluster 0.358319\n", + "Segment_Mid-Value 0.189268\n", + "CustomerID -0.030020\n", + "Recency -0.350378\n", + "Segment_Low-Value -0.378387\n", + "Name: LTVCluster, dtype: float64" + ], + "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", + "
LTVCluster
LTVCluster1.000000
m6_Revenue0.877872
Revenue0.775550
RevenueCluster0.605556
Frequency0.569399
OverallScore0.542147
FrequencyCluster0.515290
Segment_High-Value0.496939
RecencyCluster0.358319
Segment_Mid-Value0.189268
CustomerID-0.030020
Recency-0.350378
Segment_Low-Value-0.378387
\n", + "

" + ] + }, + "metadata": {}, + "execution_count": 107 + } + ], + "source": [ + "#calculate and show correlations\n", + "corr_matrix = tx_class.corr()\n", + "corr_matrix['LTVCluster'].sort_values(ascending=False)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6mQIIrm3O1MN" + }, + "outputs": [], + "source": [ + "#create X and y, X will be feature set and y is the label - LTV\n", + "X = tx_class.drop(['LTVCluster','m6_Revenue'],axis=1)\n", + "y = tx_class['LTVCluster']\n", + "\n", + "#split training and test sets\n", + "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.05, random_state=56)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wGeL5dMlO1MN" + }, + "source": [ + "We see that Revenue, Frequency and RFM scores will be helpful for our machine learning models from the correlation with LTVCluster.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_I_atw61O1MO" + }, + "source": [ + "

8. Machine Learning Model for Customer Lifetime Value Prediction

" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "z4ttDEDmO1MO" + }, + "source": [ + "Since our LTV Clusters are 3 types, high LTV, mid LTV and low LTV; we will perform multi class classification." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8IwktUt1O1MO", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "1507fc23-d1ca-49b9-c775-b5524055fd3b" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Accuracy of XGB classifier on training set: 0.95\n", + "Accuracy of XGB classifier on test set: 0.92\n" + ] + } + ], + "source": [ + "#XGBoost Multiclassification Model\n", + "ltv_xgb_model = xgb.XGBClassifier(max_depth=5, learning_rate=0.1,n_jobs=-1).fit(X_train, y_train)\n", + "\n", + "print('Accuracy of XGB classifier on training set: {:.2f}'\n", + " .format(ltv_xgb_model.score(X_train, y_train)))\n", + "print('Accuracy of XGB classifier on test set: {:.2f}'\n", + " .format(ltv_xgb_model.score(X_test[X_train.columns], y_test)))\n", + "\n", + "y_pred = ltv_xgb_model.predict(X_test)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "QyNtxmQpO1MO" + }, + "source": [ + "Accuracy looks good on training and test set. Let's check the precision, recall, fscore too" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gPB-DmRUO1MO", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "c2b91906-d279-46e9-bd8c-24f8ea09195a" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " precision recall f1-score support\n", + "\n", + " 0 0.95 0.94 0.95 145\n", + " 1 0.80 0.84 0.82 43\n", + " 2 1.00 0.88 0.93 8\n", + "\n", + " accuracy 0.92 196\n", + " macro avg 0.92 0.89 0.90 196\n", + "weighted avg 0.92 0.92 0.92 196\n", + "\n" + ] + } + ], + "source": [ + "print(classification_report(y_test, y_pred))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eowRMitRO1MO" + }, + "source": [ + "

9. Final Clusters for Customer Lifetime Value

\n", + "\n", + "- **Cluster 0**: Good precision, recall, f1-score and support\n", + "- **Cluster 1**: Needs better precision, recall and f1-score\n", + "- **Cluster 2**: Bad precision, F1-Score needs improvement" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NmU-1l4WO1MO" + }, + "source": [ + "If model tells us this customer belongs to cluster 0, 93 out of 100 will be correct (precision). And the model successfully identifies 95% of actual cluster 0 customers (recall).\n", + "\n", + "We really need to improve the model for other clusters. For example, we barely detect 67% of Mid LTV customers.\n", + "\n", + "**Possible actions to improve performance**\n", + "\n", + "- Adding more features and improve feature engineering\n", + "- Try different models other than XGBoost\n", + "- Apply hyper parameter tuning to current model\n", + "- Add more data to the model if possible\n" + ] + } + ], + "metadata": { + "colab": { + "provenance": [], + "include_colab_link": true + }, + "kaggle": { + "accelerator": "none", + "dataSources": [ + { + "datasetId": 302641, + "sourceId": 618141, + "sourceType": "datasetVersion" + } + ], + "dockerImageVersionId": 29867, + "isGpuEnabled": false, + "isInternetEnabled": true, + "language": "python", + "sourceType": "notebook" + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "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.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file