{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# DISPLAY OPTIONS (uncomment and customize to activate)\n", "\n", "# prevent annoying tendency of not displaying 'middle' columns if data is very wide\n", "# change the max_columns value for even wider datasets\n", "\n", "# pd.options.display.max_columns = None\n", "# pd.options.display.max_columns = 40\n", "\n", "# see \"all\" the rows if needed\n", "# change max_rows to desired number\n", "\n", "# pd.options.display.max_rows = 105\n", "\n", "# pd.reset_option('^display.', silent=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Analysis of Font change on Website\n", "## Project Goal : Determine if new font resulted in more food product sales by analyzing A/A/B testing via sales funnel." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Project Description\n", "\n", "We sell food products. We need to investigate user behavior for the company's app.\n", "\n", "We will study the sales funnel. Find out how users reach the purchase stage. How many users actually make it to this stage? How many get stuck at previous stages? Which stages in particular?\n", "\n", "Then look at the results of an A/A/B test. \n", "\n", "**PROBLEM:** The designers would like to change the fonts for the entire app, but the managers are afraid the users might find the new design intimidating. \n", "\n", "**SOLUTION:** They decide to make a decision based on the results of an A/A/B test.\n", "\n", "The users are split into three groups: two control groups get the old fonts and one test group gets the new ones. Find out which set of fonts produces better results.\n", "\n", "Creating two A groups has certain advantages. We can make it a principle that we will only be confident in the accuracy of our testing when the two control groups are similar. If there are significant differences between the A groups, this can help us uncover factors that may be distorting the results. Comparing control groups also tells us how much time and data we'll need when running further tests.\n", "\n", "We'll be using the same dataset for general analytics and for A/A/B analysis. In real projects, experiments are constantly being conducted. Analysts study the quality of an app using general data, without paying attention to whether users are participating in experiments.\n", "\n", "Description of the data\n", "\n", "Each log entry is a user action or an event.\n", "\n", "* ```EventName``` — event name (we will change to ```event_name```)\n", "* ```DeviceIDHash``` — unique user identifier (we will change to ```user_id```)\n", "* ```EventTimestamp``` — event time (we will change to ```date_time```)\n", "* ```ExpId``` — experiment number: 246 and 247 are the control groups, 248 is the test group (we will change to ```group```)\n", "\n", "\n", "### Step 1. Open the data file and read the general information\n", "\n", "File path: /datasets/logs_exp_us.csv Download dataset\n", "\n", "### Step 2. Prepare the data for analysis\n", "\n", "* Rename the columns in a way that's convenient for you\n", "* Check for missing values and data types. Correct the data if needed\n", "* Add a date and time column and a separate column for dates\n", "\n", "### Step 3. Study and check the data\n", "\n", "* How many events are in the logs?\n", "* How many users are in the logs?\n", "* What's the average number of events per user?\n", "* What period of time does the data cover? Find the maximum and the minimum date. Plot a histogram by date and time. Can you be sure that you have equally complete data for the entire period? Older events could end up in some users' logs for technical reasons, and this could skew the overall picture. Find the moment at which the data starts to be complete and ignore the earlier section. What period does the data actually represent?\n", "* Did you lose many events and users when excluding the older data?\n", "* Make sure you have users from all three experimental groups.\n", "\n", "### Step 4. Study the event funnel\n", "\n", "* See what events are in the logs and their frequency of occurrence. Sort them by frequency.\n", "* Find the number of users who performed each of these actions. Sort the events by the number of users. Calculate the proportion of users who performed the action at least once.\n", "* In what order do you think the actions took place. Are all of them part of a single sequence? You don't need to take them into account when calculating the funnel.\n", "* Use the event funnel to find the share of users that proceed from each stage to the next. (For instance, for the sequence of events A → B → C, calculate the ratio of users at stage B to the number of users at stage A and the ratio of users at stage C to the number at stage B.)\n", "* At what stage do you lose the most users?\n", "* What share of users make the entire journey from their first event to payment?\n", "\n", "### Step 5. Study the results of the experiment\n", "\n", "* How many users are there in each group?\n", "* We have two control groups in the A/A test, where we check our mechanisms and calculations. See if there is a statistically significant difference between samples 246 and 247.\n", "* Select the most popular event. In each of the control groups, find the number of users who performed this action. Find their share. Check whether the difference between the groups is statistically significant. Repeat the procedure for all other events (it will save time if you create a special function for this test). Can you confirm that the groups were split properly?\n", "* Do the same thing for the group with altered fonts. Compare the results with those of each of the control groups for each event in isolation. Compare the results with the combined results for the control groups. What conclusions can you draw from the experiment?\n", "* What significance level have you set to test the statistical hypotheses mentioned above? Calculate how many statistical hypothesis tests you carried out. With a statistical significance level of 0.1, one in 10 results could be false. What should the significance level be? If you want to change it, run through the previous steps again and check your conclusions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "# Table of Contents\n", "\n", "Opening Data\n", " \n", "[Data Preprocessing](#preprocessing_data)\n", " \n", "[Study and check the data](#data_analysis)\n", "\n", "[Study the event funnel](#funnel)\n", "\n", "[Study the results of the experimnent](#results)\n", "\n", "[Conclusion](#conclusion)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Opening the Data" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "import seaborn as sns\n", "import matplotlib.pyplot as plt\n", "from scipy import stats as st\n", "import math as mth\n", "%matplotlib inline\n", "\n", "sns.set_color_codes(\"pastel\")\n", "\n", "#practicum path\n", "#path = \"/datasets/\"\n", "\n", "#local path\n", "path = 'datasets/'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Note about path:\n", "In the above cell, I have two path options. The local path works for me, and I have found I need to add the first forward slash for the reviewer's to work. I just toggle which one. I think in the last case, I hadn't put in the second forward slash. Hopefully, it works for you now." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "df = pd.read_csv(path + 'logs_exp_us.csv', sep = '\\t')" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
EventNameDeviceIDHashEventTimestampExpId
0MainScreenAppear45755885289746102571564029816246
1MainScreenAppear74166953133115606581564053102246
2PaymentScreenSuccessful35181230913070055091564054127248
3CartScreenAppear35181230913070055091564054127248
4PaymentScreenSuccessful62178076530949959991564055322248
\n", "
" ], "text/plain": [ " EventName DeviceIDHash EventTimestamp ExpId\n", "0 MainScreenAppear 4575588528974610257 1564029816 246\n", "1 MainScreenAppear 7416695313311560658 1564053102 246\n", "2 PaymentScreenSuccessful 3518123091307005509 1564054127 248\n", "3 CartScreenAppear 3518123091307005509 1564054127 248\n", "4 PaymentScreenSuccessful 6217807653094995999 1564055322 248" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.head()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "RangeIndex: 244126 entries, 0 to 244125\n", "Data columns (total 4 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 EventName 244126 non-null object\n", " 1 DeviceIDHash 244126 non-null int64 \n", " 2 EventTimestamp 244126 non-null int64 \n", " 3 ExpId 244126 non-null int64 \n", "dtypes: int64(3), object(1)\n", "memory usage: 7.5+ MB\n" ] } ], "source": [ "df.info()" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
EventNameDeviceIDHashEventTimestampExpId
244121MainScreenAppear45996283640492018121565212345247
244122MainScreenAppear58498066124374865901565212439246
244123MainScreenAppear57469699388019990501565212483246
244124MainScreenAppear57469699388019990501565212498246
244125OffersScreenAppear57469699388019990501565212517246
\n", "
" ], "text/plain": [ " EventName DeviceIDHash EventTimestamp ExpId\n", "244121 MainScreenAppear 4599628364049201812 1565212345 247\n", "244122 MainScreenAppear 5849806612437486590 1565212439 246\n", "244123 MainScreenAppear 5746969938801999050 1565212483 246\n", "244124 MainScreenAppear 5746969938801999050 1565212498 246\n", "244125 OffersScreenAppear 5746969938801999050 1565212517 246" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.tail()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Opening Data Conclusion\n", "Needed to add the tab separator argument; otherwise very straightforward" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "# Data Preprocessing\n", " * Check for NULLS\n", " * Check for duplicates\n", " * Add separate date and time columns" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# check if any null values exist\n", "df.isnull().values.any()" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
EventNameDeviceIDHashEventTimestampExpId
154227MainScreenAppear75478817509155342621565003581248
217104MainScreenAppear89425530030706715451565158894247
107509OffersScreenAppear92039893560007281411564868642246
21377CartScreenAppear70207598883975030091564666137246
154260MainScreenAppear51933264454304295081565003672248
171532CartScreenAppear10698643421365995051565027926248
44433CartScreenAppear33782849814399319351564727341246
65434MainScreenAppear44551669994382328421564763003247
200522CartScreenAppear91604370166856431941565104909247
83471PaymentScreenSuccessful33318238781094901501564824412246
95700MainScreenAppear61382390310260083731564843052247
26832CartScreenAppear81185538422683999631564673940248
31064OffersScreenAppear88046770611693534791564679627246
77969MainScreenAppear15820185920223185191564813282247
20887CartScreenAppear49800454491186190051564665459247
189175CartScreenAppear37768502356813458801565086211247
31936OffersScreenAppear78493802402390828911564681028246
243538PaymentScreenSuccessful19896853204451483481565209427247
89305MainScreenAppear8179589064910150491564832809246
234272OffersScreenAppear1041939948661236571565191761248
\n", "
" ], "text/plain": [ " EventName DeviceIDHash EventTimestamp ExpId\n", "154227 MainScreenAppear 7547881750915534262 1565003581 248\n", "217104 MainScreenAppear 8942553003070671545 1565158894 247\n", "107509 OffersScreenAppear 9203989356000728141 1564868642 246\n", "21377 CartScreenAppear 7020759888397503009 1564666137 246\n", "154260 MainScreenAppear 5193326445430429508 1565003672 248\n", "171532 CartScreenAppear 1069864342136599505 1565027926 248\n", "44433 CartScreenAppear 3378284981439931935 1564727341 246\n", "65434 MainScreenAppear 4455166999438232842 1564763003 247\n", "200522 CartScreenAppear 9160437016685643194 1565104909 247\n", "83471 PaymentScreenSuccessful 3331823878109490150 1564824412 246\n", "95700 MainScreenAppear 6138239031026008373 1564843052 247\n", "26832 CartScreenAppear 8118553842268399963 1564673940 248\n", "31064 OffersScreenAppear 8804677061169353479 1564679627 246\n", "77969 MainScreenAppear 1582018592022318519 1564813282 247\n", "20887 CartScreenAppear 4980045449118619005 1564665459 247\n", "189175 CartScreenAppear 3776850235681345880 1565086211 247\n", "31936 OffersScreenAppear 7849380240239082891 1564681028 246\n", "243538 PaymentScreenSuccessful 1989685320445148348 1565209427 247\n", "89305 MainScreenAppear 817958906491015049 1564832809 246\n", "234272 OffersScreenAppear 104193994866123657 1565191761 248" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.sample(20)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "df['date_time'] = pd.to_datetime(df['EventTimestamp'], unit = 's')" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "RangeIndex: 244126 entries, 0 to 244125\n", "Data columns (total 5 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 EventName 244126 non-null object \n", " 1 DeviceIDHash 244126 non-null int64 \n", " 2 EventTimestamp 244126 non-null int64 \n", " 3 ExpId 244126 non-null int64 \n", " 4 date_time 244126 non-null datetime64[ns]\n", "dtypes: datetime64[ns](1), int64(3), object(1)\n", "memory usage: 9.3+ MB\n" ] } ], "source": [ "df.info()" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(244126, 5)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.shape" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# df['event_date'] = df['date_time'].dt.strftime('%Y-%m-%d')\n", "df['event_date'] = df['date_time'].dt.date\n", "df['event_time'] = df['date_time'].dt.time\n" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['EventName', 'DeviceIDHash', 'EventTimestamp', 'ExpId', 'date_time',\n", " 'event_date', 'event_time'],\n", " dtype='object')" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.columns" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "df.drop('EventTimestamp', axis=1, inplace=True)\n", "df.index = df['date_time']" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "df.columns = ['event_name',\n", " 'user_id',\n", " 'group',\n", " 'date_time',\n", " 'event_date',\n", " 'event_time']" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "DatetimeIndex: 244126 entries, 2019-07-25 04:43:36 to 2019-08-07 21:15:17\n", "Data columns (total 6 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 event_name 244126 non-null object \n", " 1 user_id 244126 non-null int64 \n", " 2 group 244126 non-null int64 \n", " 3 date_time 244126 non-null datetime64[ns]\n", " 4 event_date 244126 non-null object \n", " 5 event_time 244126 non-null object \n", "dtypes: datetime64[ns](1), int64(2), object(3)\n", "memory usage: 13.0+ MB\n" ] } ], "source": [ "df.info()" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
event_nameuser_idgroupdate_timeevent_dateevent_time
date_time
2019-07-25 04:43:36MainScreenAppear45755885289746102572462019-07-25 04:43:362019-07-2504:43:36
2019-07-25 11:11:42MainScreenAppear74166953133115606582462019-07-25 11:11:422019-07-2511:11:42
2019-07-25 11:28:47PaymentScreenSuccessful35181230913070055092482019-07-25 11:28:472019-07-2511:28:47
2019-07-25 11:28:47CartScreenAppear35181230913070055092482019-07-25 11:28:472019-07-2511:28:47
2019-07-25 11:48:42PaymentScreenSuccessful62178076530949959992482019-07-25 11:48:422019-07-2511:48:42
\n", "
" ], "text/plain": [ " event_name user_id group \\\n", "date_time \n", "2019-07-25 04:43:36 MainScreenAppear 4575588528974610257 246 \n", "2019-07-25 11:11:42 MainScreenAppear 7416695313311560658 246 \n", "2019-07-25 11:28:47 PaymentScreenSuccessful 3518123091307005509 248 \n", "2019-07-25 11:28:47 CartScreenAppear 3518123091307005509 248 \n", "2019-07-25 11:48:42 PaymentScreenSuccessful 6217807653094995999 248 \n", "\n", " date_time event_date event_time \n", "date_time \n", "2019-07-25 04:43:36 2019-07-25 04:43:36 2019-07-25 04:43:36 \n", "2019-07-25 11:11:42 2019-07-25 11:11:42 2019-07-25 11:11:42 \n", "2019-07-25 11:28:47 2019-07-25 11:28:47 2019-07-25 11:28:47 \n", "2019-07-25 11:28:47 2019-07-25 11:28:47 2019-07-25 11:28:47 \n", "2019-07-25 11:48:42 2019-07-25 11:48:42 2019-07-25 11:48:42 " ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Find and delete duplicate rows**" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "scrolled": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
event_nameuser_idgroupdate_timeevent_dateevent_time
date_time
2019-07-30 08:19:44MainScreenAppear56134080413240105522482019-07-30 08:19:442019-07-3008:19:44
2019-07-31 21:51:39CartScreenAppear16949406453358072442482019-07-31 21:51:392019-07-3121:51:39
2019-08-01 02:59:37MainScreenAppear4341037464545915872482019-08-01 02:59:372019-08-0102:59:37
2019-08-01 03:47:46MainScreenAppear37613737641797626332472019-08-01 03:47:462019-08-0103:47:46
2019-08-01 04:44:01MainScreenAppear28353287397893066222482019-08-01 04:44:012019-08-0104:44:01
.....................
2019-08-07 19:26:44MainScreenAppear88703583733139686332472019-08-07 19:26:442019-08-0719:26:44
2019-08-07 19:26:45PaymentScreenSuccessful47180029649831056932472019-08-07 19:26:452019-08-0719:26:45
2019-08-07 19:27:29PaymentScreenSuccessful23825917823032819352462019-08-07 19:27:292019-08-0719:27:29
2019-08-07 19:27:29CartScreenAppear23825917823032819352462019-08-07 19:27:292019-08-0719:27:29
2019-08-07 19:36:58MainScreenAppear40977826674457905122462019-08-07 19:36:582019-08-0719:36:58
\n", "

413 rows × 6 columns

\n", "
" ], "text/plain": [ " event_name user_id group \\\n", "date_time \n", "2019-07-30 08:19:44 MainScreenAppear 5613408041324010552 248 \n", "2019-07-31 21:51:39 CartScreenAppear 1694940645335807244 248 \n", "2019-08-01 02:59:37 MainScreenAppear 434103746454591587 248 \n", "2019-08-01 03:47:46 MainScreenAppear 3761373764179762633 247 \n", "2019-08-01 04:44:01 MainScreenAppear 2835328739789306622 248 \n", "... ... ... ... \n", "2019-08-07 19:26:44 MainScreenAppear 8870358373313968633 247 \n", "2019-08-07 19:26:45 PaymentScreenSuccessful 4718002964983105693 247 \n", "2019-08-07 19:27:29 PaymentScreenSuccessful 2382591782303281935 246 \n", "2019-08-07 19:27:29 CartScreenAppear 2382591782303281935 246 \n", "2019-08-07 19:36:58 MainScreenAppear 4097782667445790512 246 \n", "\n", " date_time event_date event_time \n", "date_time \n", "2019-07-30 08:19:44 2019-07-30 08:19:44 2019-07-30 08:19:44 \n", "2019-07-31 21:51:39 2019-07-31 21:51:39 2019-07-31 21:51:39 \n", "2019-08-01 02:59:37 2019-08-01 02:59:37 2019-08-01 02:59:37 \n", "2019-08-01 03:47:46 2019-08-01 03:47:46 2019-08-01 03:47:46 \n", "2019-08-01 04:44:01 2019-08-01 04:44:01 2019-08-01 04:44:01 \n", "... ... ... ... \n", "2019-08-07 19:26:44 2019-08-07 19:26:44 2019-08-07 19:26:44 \n", "2019-08-07 19:26:45 2019-08-07 19:26:45 2019-08-07 19:26:45 \n", "2019-08-07 19:27:29 2019-08-07 19:27:29 2019-08-07 19:27:29 \n", "2019-08-07 19:27:29 2019-08-07 19:27:29 2019-08-07 19:27:29 \n", "2019-08-07 19:36:58 2019-08-07 19:36:58 2019-08-07 19:36:58 \n", "\n", "[413 rows x 6 columns]" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[df.duplicated()]" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "df = df.drop_duplicates()" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(243713, 6)" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Data Preprocessing Conclusion\n", "* We had no nulls, but did have 413 duplicate rows, which we dropped. 413 out of 244K doesn't seem like a lot, but in and of itself, that seems like a significant number of duplicates. **SUGGESTED ACTION**: follow up with data engineering to see why there are so many duplicates\n", "* We converted the timestamp into datetime, as well as into separate date and time columns\n", "* We have a cleaned up dataset of 243713 observations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "# Study and check the data\n", " * How many events are in the logs?\n", " * How many users are in the logs?\n", " * What's the average number of events per user?\n", " * What period of time does the data cover? \n", " * Find the maximum and the minimum date\n", " * Plot a histogram by date and time. \n", " Can you be sure that you have equally complete data for the entire period? Older events could end up in some users' logs for technical reasons, and this could skew the overall picture. \n", " * Find the moment at which the data starts to be complete and ignore the earlier section. What period does the data actually represent?\n", " * Did you lose many events and users when excluding the older data?\n", " * Make sure you have users from all three experimental groups.\n" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
event_nameuser_idgroupdate_timeevent_dateevent_time
date_time
2019-07-25 04:43:36MainScreenAppear45755885289746102572462019-07-25 04:43:362019-07-2504:43:36
2019-07-25 11:11:42MainScreenAppear74166953133115606582462019-07-25 11:11:422019-07-2511:11:42
2019-07-25 11:28:47PaymentScreenSuccessful35181230913070055092482019-07-25 11:28:472019-07-2511:28:47
2019-07-25 11:28:47CartScreenAppear35181230913070055092482019-07-25 11:28:472019-07-2511:28:47
2019-07-25 11:48:42PaymentScreenSuccessful62178076530949959992482019-07-25 11:48:422019-07-2511:48:42
\n", "
" ], "text/plain": [ " event_name user_id group \\\n", "date_time \n", "2019-07-25 04:43:36 MainScreenAppear 4575588528974610257 246 \n", "2019-07-25 11:11:42 MainScreenAppear 7416695313311560658 246 \n", "2019-07-25 11:28:47 PaymentScreenSuccessful 3518123091307005509 248 \n", "2019-07-25 11:28:47 CartScreenAppear 3518123091307005509 248 \n", "2019-07-25 11:48:42 PaymentScreenSuccessful 6217807653094995999 248 \n", "\n", " date_time event_date event_time \n", "date_time \n", "2019-07-25 04:43:36 2019-07-25 04:43:36 2019-07-25 04:43:36 \n", "2019-07-25 11:11:42 2019-07-25 11:11:42 2019-07-25 11:11:42 \n", "2019-07-25 11:28:47 2019-07-25 11:28:47 2019-07-25 11:28:47 \n", "2019-07-25 11:28:47 2019-07-25 11:28:47 2019-07-25 11:28:47 \n", "2019-07-25 11:48:42 2019-07-25 11:48:42 2019-07-25 11:48:42 " ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### How many events are in the logs?" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "There are 5 types of events, numbering in total 243713 total events.\n" ] } ], "source": [ "print(\"There are \" + str(df.event_name.nunique()) + \n", " \" types of events, numbering in total \" +\n", " str(df.shape[0]) +\n", " \" total events.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### How many users are in the logs?" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "There are 7551 users.\n" ] } ], "source": [ "print(\"There are \" + str(df.user_id.nunique()) + \" users.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### What's the average number of events per user?" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "df_by_user = df.groupby('user_id').agg({'event_name':'count'}).reset_index()" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The average number of events per user is 32.27559263673685\n" ] } ], "source": [ "print(\"The average number of events per user is \" + str(df_by_user.event_name.mean()))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### What period of time does the data cover?" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The time period covered by the data is from 2019-07-25 to 2019-08-07\n" ] } ], "source": [ "print(\"The time period covered by the data is from \" +\n", " str(df.event_date.min()) +\n", " \" to \" +\n", " str(df.event_date.max()))" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "df_by_datetime = df.groupby('event_date').agg({'event_name':'count'}).reset_index()" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
event_dateevent_name
02019-07-259
12019-07-2631
22019-07-2755
32019-07-28105
42019-07-29184
52019-07-30412
62019-07-312030
72019-08-0136141
82019-08-0235554
92019-08-0333282
102019-08-0432968
112019-08-0536058
122019-08-0635788
132019-08-0731096
\n", "
" ], "text/plain": [ " event_date event_name\n", "0 2019-07-25 9\n", "1 2019-07-26 31\n", "2 2019-07-27 55\n", "3 2019-07-28 105\n", "4 2019-07-29 184\n", "5 2019-07-30 412\n", "6 2019-07-31 2030\n", "7 2019-08-01 36141\n", "8 2019-08-02 35554\n", "9 2019-08-03 33282\n", "10 2019-08-04 32968\n", "11 2019-08-05 36058\n", "12 2019-08-06 35788\n", "13 2019-08-07 31096" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_by_datetime" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAuIAAAJQCAYAAADL4QFBAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nOzdfVSUZcLH8d/oIJWoLMqIsa2tbmgLGiq9uE8L2SZgwFps9iJp++xuIpbabumSkISlmUuGpmg9vWq1yeoK5SLW6prmS5l7Hg3X3Be1VApBSV4UHOB+/vA4jxPhYDFcAt/PORzmvuaee34Xzun85u6ae2yWZVkCAAAA0Ko6mQ4AAAAAdEQUcQAAAMAAijgAAABgAEUcAAAAMIAiDgAAABhAEQcAXBTa+0W82vv8AFw4ijiANm3cuHEaPHiwDh482Oi+vXv3asCAAfrwww+9muHDDz/UgAED9Mknn3j1eS6E0+nUI488ovDwcF177bU6cuSI6UjnlZubq+zs7G/9+MOHD2vAgAEqLCxswVTf7LnnntOQIUMu6DEff/yxpkyZ4qVEANoqijiANq+2tlaPPfYYZxzPsXnzZr3zzjuaNGmScnJy1KdPH9ORzmvp0qWqrKw0HcNrVq5cqQMHDpiOAeAiQxEH0OZ169ZNH330kVauXGk6ykXjxIkTkqQ77rhD1157rTp14j/3AHCx4b/MANq8YcOGacSIEZo3b55KS0ub3O/Pf/6zBgwYoOPHj7vGKioqNGDAAP35z3+WdGbZQWJiovLy8jRy5EgNHjxYv/zlL3X06FG99dZbuummmzRs2DA98sgjOnXqlNvx9+zZo8TERA0aNEiJiYnasmWL2/3Hjh3T9OnTdd1112nIkCGaOHGiDh065Lr/7HPPmTNHERERuvvuu5ucy44dO5SUlKShQ4fqJz/5iWbNmqXq6mpJUmpqqlJTUyVJw4cPd93+Jlu2bNGYMWM0ePBgRUZGasGCBaqvr3flGTp0qE6fPu32mClTpigpKcm1vWbNGiUkJGjQoEG65ZZbtHz5crf9z/59f/vb32rIkCG6/vrrNXv2bNXV1UmSbr75Zh05ckRvvPGGBgwYIEk6efKk0tLSdOONN2rw4MG6/fbb9e677zY5j7MOHTqkcePGadCgQRo1apTeeecd132JiYlKTk5227+2tlbDhg3T66+/3uQxX3rpJY0YMULh4eGaNm2aampq3O53Op1auHChYmJiFBYWpmuvvVYPPvigvvjiC0ln/j1Wr16tf/3rX25LpTy9HgC0fxRxAO1CRkaG6urq9MQTT3znYx04cED/8z//o+nTp+vJJ5/Url27NG7cOK1atUoZGRlKTk7WmjVrtGzZMrfHzZkzR7fccosWLVqkXr16KTk5Wf/5z38kSTU1NRo/frx27typ9PR0zZs3T2VlZbr33ntdZ68lad++ffrkk0/03HPPaeLEid+Y7/3339f48eMVGBioZ599VpMnT9Zf/vIXJScnq6GhQZMmTVJKSook6cUXX9SkSZO+8Tjbtm3T/fffr+9///tatGiRfv3rX+uVV17Rk08+KUmKj49XdXW1Nm/e7HrMyZMntWnTJsXFxUmSVq9erYcffljXXnutlixZottuu01PPfWUXnzxxUZ/m4CAAOXk5CgpKUnLli1Tbm6uJGnRokUKDAxUTEyMVqxYIUl6+umntX37dqWlpen5559X//79NXXqVNffsynZ2dn68Y9/rJycHF1zzTV65JFHtHXrVknS6NGjtWXLFpWXl7v237Bhg2pqanTrrbd+4/FeeuklPfPMM7r99tu1cOFCOZ1Ovfbaa277PPXUU3r99dd1//336+WXX9ZDDz2kbdu2ac6cOZKkSZMmKSoqSldccYVWrFih0NDQZr8eALRzFgC0Yffee681YcIEy7Is67XXXrNCQkKsv/71r5ZlWdY//vEPKyQkxNq+fbtlWZa1atUqKyQkxDp27Jjr8SdOnLBCQkKsVatWWZZlWQsXLrRCQkKs//3f/3Xt89vf/tYKCQmxDh8+7Bq75557rJSUFMuyLGv79u1WSEiI9eyzz7rur62ttSIjI61HH33UsizL+uMf/2hdffXV1r///W/XPpWVlVZERIT13HPPuT337t27zzvn22+/3brzzjvdxjZt2mSFhIRY69evb3KuX3fnnXdad999t9vY6tWrrYEDB1qHDh1yPdcjjzziun/NmjXWj3/8Y+vYsWNWfX29deONN1oPP/yw2zEWLVpkDRkyxKqurrYsy7JCQkKs3/zmN2773HbbbVZycrJre8SIEVZmZqZr+9Zbb7Uee+wx13Ztba311FNPWZ9++uk3zuXQoUNWSEiIW1bLsqw77rjDGj9+vGVZlnXs2DErNDTU+uMf/+i6PyUlxS3Huerr663rr7/emjlzpmusoaHBSkhIsMLDw11jU6dOtf70pz+5PfaJJ56wrrvuOtf273//eysuLs613ZzXA4D2jzPiANqNe++9V9dcc41mzZqlqqqqb30cm82msLAw13bPnj0VEBCg4OBg15i/v3+jDxfGxMS4bnfp0kU33nij60oqH374ofr27au+ffuqrq5OdXV1uuSSSzRs2DBt377d7Tj9+/dvMlt1dbX+8Y9/KDY21m38pz/9qXr06KEdO3Y0a46nTp3S7t27NWLECFeeuro6RUZGqqGhwbV8IiEhQRs2bHAtT1m7dq1+8pOfKCAgQAcOHNDRo0d10003NTpGdXW1du/e7Xq+a665xu35e/furZMnTzaZb8iQIcrNzdXEiRO1YsUKlZeXKzU11bV0pSnn/htI0ogRI1w5AgICdOONN+ovf/mLJOmrr77Spk2bNHr06G881oEDB1ReXq7IyEjXmM1mU3R0tNt+2dnZuuOOO1RSUqJt27bpjTfe0N///vdGS3rOdSGvBwDtl910AABoKZ06ddITTzyhxMREPfPMM7rzzju/1XEuvfRSde7cudGYJz179nTbDggI0NGjRyWdKX379+9XaGhoo8ddeeWVrtuXXXaZLrvssiafo7KyUpZlNXqus8/X3DcgFRUVamho0DPPPKNnnnmm0f1n19rfeuutmjdvnj744ANdf/312rx5szIzM11zkqSHH35YDz/8cJPHkBr//Tp16nTeq9ykp6fL4XAoPz9ff/vb39SpUyeNHDlSc+bMkZ+fX5OP+6Z/g5MnT6qqqkp+fn66/fbbNXXqVH355ZfauHGjLrnkEt18883feKyzS0S+973vuY336tXLbfvvf/+7Hn/8ce3bt0/dunXT1VdfLV9f3yYzSs1/PQBo3yjiANqVAQMG6Ne//rVeeOEF/ehHP3K7z2azSXL/YpXznZW9UBUVFXI4HK7tsrIy+fv7SzpzZZeBAwe61l+fq0uXLs1+jm7duslms+nYsWON7jv3+Tzp2rWrJCklJUU/+9nPGt1/dh69e/dWRESE3n33Xdff6pZbbnFlkaSZM2dq8ODBjY7x/e9/v1lZvskll1yiKVOmaMqUKdq/f7/WrVunnJwc/eEPf3C9EfgmFRUVbttlZWXq0qWL683NiBEj1L17d7333nv629/+ptjY2CZL89m/5bkf7pX+/w2IdOaN0cSJEzV06FA999xz6tu3ryRp3rx5+vTTT5vM2VKvBwBtG0tTALQ7DzzwgPr27av58+e7jZ89k3r2LLV05otWWsq5H2qsqanRpk2bdN1110mShg4dqsOHDys4OFiDBg3SoEGDFBYWpldffVUbN25s9nN07dpVV199daMvrtm8ebMqKys1dOjQZh3Hz89PAwcO1KFDh1x5Bg0aJB8fH82fP19ffvmla9+EhARt2rRJ69at00033eT6O/br10/+/v4qKSlxO8ZXX32lBQsWXNDyoHMvr1hfX6/4+Hi9+uqrrudJSUlReHi460okTTn338CyLL333ntul2/s0qWL62oqH330UZPLUiTphz/8oRwOR6OrtWzatMl1e//+/Tpx4oTuu+8+VwlvaGjQ1q1b3d7wff3ykS31egDQtnFGHEC74+vrq8zMTN13331u49dff718fX01e/ZspaSkqLi4WEuWLGmxM5DPP/+8fH19FRwcrJdfflmnTp3S/fffL+nM9byXL1+uX/3qV5owYYL8/f21YsUKvfvuu/r5z39+Qc8zefJkTZo0SQ899JASExP1xRdfaP78+RoyZIjbemZPpkyZogceeEB+fn4aOXKkysvLlZ2drU6dOikkJMS1X0xMjGbNmqX169drwYIFrnG73a7Jkydr7ty5ks5cKvHw4cN65plndOWVV17QGfHu3btrz5492rFjhyIiIjR48GAtXrxYvr6+6tevn3bt2qWdO3ee92y4JK1atUqBgYEKCwvTn/70J/373//WzJkz3fa5/fbb9dZbbyk4OFgRERFNHstms2nKlCl67LHH1LNnT/3Xf/2X1q5dq6KiItfSpX79+qlr167KyclRQ0ODampq9Oabb+rTTz+VzWaTZVmy2Wzq3r27vvzyS23ZskVhYWEt+noA0HZxRhxAu3TDDTfoF7/4hdtY9+7dlZ2drePHjys5OVlvvvmm5s2bd9412RciMzNTb775ph588EHV1tZq2bJl+sEPfiDpzBnoN954Q/369dPjjz+uSZMmqbi4WDk5OYqKirqg57n55pu1ePFiff7555o0aZKee+45xcfH68UXX2y0tv18fvaznyknJ0dFRUVKSUnRnDlzFB4ermXLlrmt6e7Ro4d++tOf6rLLLmuU9d5779Xjjz+uDRs26P7779eCBQsU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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "sns.set(style = 'whitegrid')\n", "\n", "\n", "f, ax = plt.subplots(figsize = (12, 9))\n", "sns.barplot(x = 'event_date',\n", " y = 'event_name',\n", " data = df_by_datetime,\n", " color = 'b',\n", " alpha = 0.6).set_title(\"Number of events by date\", fontsize = 16)\n", "ax.set(xlabel=\"Log Date\", ylabel = \"Number of Events\")\n", "ax.set_xticklabels(ax.get_xticklabels(), rotation=45);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Observation\n", "We can see that prior to August 1, 2019, there is barely any events logged. This can be due to a number of possible reasons:\n", "\n", "1. The website itself was not officially launched; perhaps those small early numbers were testers trying out the system\n", "2. The sales funnel was not launched until a few days prior to August 1, and those small early numbers again were from testing\n", "3. The website and sales funnel were installed, and a marketing campaign began on August 1 -- a combination of online ads and influencers. Perhaps those early numbers were also influencers invited to review the product (and got a coupon to get free product in return?)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "df_users_by_datetime = df.groupby('group').agg({'event_date':'count'}).reset_index()" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
groupevent_date
024680181
124777950
224885582
\n", "
" ], "text/plain": [ " group event_date\n", "0 246 80181\n", "1 247 77950\n", "2 248 85582" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_users_by_datetime" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
event_dategroupevent_name
02019-07-252464
12019-07-252471
22019-07-252484
32019-07-2624614
42019-07-262478
52019-07-262489
62019-07-2724624
72019-07-2724723
82019-07-272488
92019-07-2824633
102019-07-2824736
112019-07-2824836
122019-07-2924655
132019-07-2924758
142019-07-2924871
152019-07-30246129
162019-07-30247138
172019-07-30248145
182019-07-31246620
192019-07-31247664
202019-07-31248746
212019-08-0124611561
222019-08-0124712306
232019-08-0124812274
242019-08-0224610946
252019-08-0224710990
262019-08-0224813618
272019-08-0324610575
282019-08-0324711024
292019-08-0324811683
302019-08-0424611514
312019-08-042479942
322019-08-0424811512
332019-08-0524612368
342019-08-0524710949
352019-08-0524812741
362019-08-0624611726
372019-08-0624711720
382019-08-0624812342
392019-08-0724610612
402019-08-0724710091
412019-08-0724810393
\n", "
" ], "text/plain": [ " event_date group event_name\n", "0 2019-07-25 246 4\n", "1 2019-07-25 247 1\n", "2 2019-07-25 248 4\n", "3 2019-07-26 246 14\n", "4 2019-07-26 247 8\n", "5 2019-07-26 248 9\n", "6 2019-07-27 246 24\n", "7 2019-07-27 247 23\n", "8 2019-07-27 248 8\n", "9 2019-07-28 246 33\n", "10 2019-07-28 247 36\n", "11 2019-07-28 248 36\n", "12 2019-07-29 246 55\n", "13 2019-07-29 247 58\n", "14 2019-07-29 248 71\n", "15 2019-07-30 246 129\n", "16 2019-07-30 247 138\n", "17 2019-07-30 248 145\n", "18 2019-07-31 246 620\n", "19 2019-07-31 247 664\n", "20 2019-07-31 248 746\n", "21 2019-08-01 246 11561\n", "22 2019-08-01 247 12306\n", "23 2019-08-01 248 12274\n", "24 2019-08-02 246 10946\n", "25 2019-08-02 247 10990\n", "26 2019-08-02 248 13618\n", "27 2019-08-03 246 10575\n", "28 2019-08-03 247 11024\n", "29 2019-08-03 248 11683\n", "30 2019-08-04 246 11514\n", "31 2019-08-04 247 9942\n", "32 2019-08-04 248 11512\n", "33 2019-08-05 246 12368\n", "34 2019-08-05 247 10949\n", "35 2019-08-05 248 12741\n", "36 2019-08-06 246 11726\n", "37 2019-08-06 247 11720\n", "38 2019-08-06 248 12342\n", "39 2019-08-07 246 10612\n", "40 2019-08-07 247 10091\n", "41 2019-08-07 248 10393" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.groupby(['event_date', 'group']).agg({'event_name':'count'}).reset_index()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All three groups appear to be accounted for if we drop data prior to August 1st." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "DatetimeIndex: 243713 entries, 2019-07-25 04:43:36 to 2019-08-07 21:15:17\n", "Data columns (total 6 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 event_name 243713 non-null object \n", " 1 user_id 243713 non-null int64 \n", " 2 group 243713 non-null int64 \n", " 3 date_time 243713 non-null datetime64[ns]\n", " 4 event_date 243713 non-null object \n", " 5 event_time 243713 non-null object \n", "dtypes: datetime64[ns](1), int64(2), object(3)\n", "memory usage: 13.0+ MB\n" ] } ], "source": [ "df.info()" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "# drop data from before August 1\n", "df = df[df['date_time'] >= '2019-08-01']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Conlusion on data study and prep\n", "* We eliminated all rows prior to August 1, 2019 -- with minimal impact, only some 2000 rows total out of 244K\n", "* There are about 7500 users\n", "* There are 5 event types that the user experiences\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "# Study the event funnel\n", "\n", "* See what events are in the logs and their frequency of occurrence. Sort them by frequency.\n", "* Find the number of users who performed each of these actions. Sort the events by the number of users. Calculate the proportion of users who performed the action at least once.\n", "* In what order do you think the actions took place. Are all of them part of a single sequence? You don't need to take them into account when calculating the funnel.\n", "* Use the event funnel to find the share of users that proceed from each stage to the next. (For instance, for the sequence of events A → B → C, calculate the ratio of users at stage B to the number of users at stage A and the ratio of users at stage C to the number at stage B.)\n", "* At what stage do you lose the most users?\n", "* What share of users make the entire journey from their first event to payment?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### See what events are in the logs and their frequency of occurrence. Sort them by frequency." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [], "source": [ "df_by_events = df.groupby(['event_name']).agg({'user_id':'count'}).sort_values('user_id', ascending = False).reset_index()" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
event_nameuser_id
0MainScreenAppear117328
1OffersScreenAppear46333
2CartScreenAppear42303
3PaymentScreenSuccessful33918
4Tutorial1005
\n", "
" ], "text/plain": [ " event_name user_id\n", "0 MainScreenAppear 117328\n", "1 OffersScreenAppear 46333\n", "2 CartScreenAppear 42303\n", "3 PaymentScreenSuccessful 33918\n", "4 Tutorial 1005" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_by_events" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Observation\n", "* Grouping by events shows that the MainScreenAppear is number one\n", "* The Tutorial event has little to do with this study, and we will not include it when crunching the numbers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "### Find the number of users who performed each of these actions. \n", "- Sort the events by the number of users. \n", "- Calculate the proportion of users who performed the action at least once." ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "def create_df_events_by_unique_users(df):\n", " new_df = df.groupby(['event_name']).agg({'user_id':'nunique'}).sort_values('user_id', ascending = False).reset_index()\n", " new_df.columns = ['event_name', 'unique_users']\n", " return new_df" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [], "source": [ "df_events_unique_users = create_df_events_by_unique_users(df)" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
event_nameunique_users
0MainScreenAppear7419
1OffersScreenAppear4593
2CartScreenAppear3734
3PaymentScreenSuccessful3539
4Tutorial840
\n", "
" ], "text/plain": [ " event_name unique_users\n", "0 MainScreenAppear 7419\n", "1 OffersScreenAppear 4593\n", "2 CartScreenAppear 3734\n", "3 PaymentScreenSuccessful 3539\n", "4 Tutorial 840" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_events_unique_users" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Order of events\n", "When we sort by number of users in reverse order, we can see that, with the exception of tutorial, the order of events naturally follow the funnel shape.\n", "\n", "The MainScreenAppear has the most users, which makes sense. That's most likely the first page a visitor will see (by typing in the website, or clicking a link via search results, etc)\n", "\n", "Then, while the user is scrolling perhaps, or is about to navigate away, the OffersScreenAppear event occurs. This could also be a link that they click. Or it's something that pops up when they add an item to the shopping cart, etc.\n", "\n", "Now, the user finally goes to the cart to see what s/he has addeded, and then from there a certain percentage decides to finally clikc the \"pay now\" button, which brings up the final PaymentScreenSuccessful event." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ratios of users\n", "Use the event funnel to find the share of users that proceed from each stage to the next. (For instance, for the sequence of events A → B → C, calculate the ratio of users at stage B to the number of users at stage A and the ratio of users at stage C to the number at stage B.)\n", "* At what stage do you lose the most users?\n", "* What share of users make the entire journey from their first event to payment?" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "# We will drop the Tutorial event since it has nothing to do with the funnel.\n", "df_events_unique_users = df_events_unique_users.drop(df_events_unique_users.index[4])\n" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [], "source": [ "# This function will calculate the proportion of users that proceed from each stage to the next.\n", "# Takes a dataframe grouped by event, and a group name so we know which group for which\n", "# we're making the calculations\n", "\n", "def check_proportions(df_by_events, group):\n", " print('For group ' + group + ':')\n", " for i in range(1, len(df_by_events)):\n", " print('The proportion of ' + df_by_events.loc[i, 'event_name'] +\n", " ' users coming from ' +\n", " df_by_events.loc[i-1, 'event_name'] +\n", " ' is ' + \n", " str(round((df_by_events.loc[i, 'unique_users'] /\n", " df_by_events.loc[i-1, 'unique_users'] *\n", " 100), 2)) + '%')" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "For group all:\n", "The proportion of OffersScreenAppear users coming from MainScreenAppear is 61.91%\n", "The proportion of CartScreenAppear users coming from OffersScreenAppear is 81.3%\n", "The proportion of PaymentScreenSuccessful users coming from CartScreenAppear is 94.78%\n" ] } ], "source": [ "check_proportions(df_events_unique_users, 'all')" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "from plotly import graph_objects as go\n", "\n", "def show_funnel(df, group_name, color):\n", " fig = go.Figure(go.Funnel(\n", " name = group_name,\n", " y = df['event_name'],\n", " x = df['unique_users'],\n", " textposition = \"inside\",\n", " textinfo = \"value+percent previous\",\n", " opacity = 0.65, marker = {\"color\": color,\n", " \"line\": {\"width\": 1, \"color\": \"blue\"}},\n", " connector = {\"line\": {\"color\": \"lightblue\", \"dash\": \"dot\", \"width\": 1}})\n", " )\n", "\n", " fig.show()\n", "\n", "#fig = px.funnel(df_by_events, x='user_id', y='event_name')\n", "#fig.show()" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/html": [ " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "connector": { "line": { "color": "lightblue", "dash": "dot", "width": 1 } }, "marker": { "color": "deepskyblue", "line": { "color": "blue", "width": 1 } }, "name": "Group 246", "opacity": 0.65, "textinfo": "value+percent previous", "textposition": "inside", "type": "funnel", "x": [ 7419, 4593, 3734, 3539 ], "y": [ "MainScreenAppear", "OffersScreenAppear", "CartScreenAppear", "PaymentScreenSuccessful" ] } ], "layout": { "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "sequentialminus": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } } } }, "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_funnel(df_events_unique_users, 'Group 246', 'deepskyblue')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Observation\n", "We lose the most users from the MainScreenAppear to the OffersScreenAppear, i.e. the first event. So, the user comes onto the website, and basically right away decides the product isn't for him/her and leaves. Almost 40% of users who visit leave without making a purchase" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "def calculate_share_entire_journey(df_grouped):\n", " return (str(round((df_grouped.loc[len(df_grouped) - 1, 'unique_users']) /\n", " (df_grouped.loc[0, 'unique_users']) * 100, 2)) + '%')" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The share of users who make the entire journey from their first event to payment is: 47.7%\n" ] } ], "source": [ "print('The share of users who make the entire journey from their first event to payment is: ' +\n", " (calculate_share_entire_journey(df_events_unique_users)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## Study the results of the experiment\n", "\n", "* How many users are there in each group?\n", "* We have two control groups in the A/A test, where we check our mechanisms and calculations. See if there is a statistically significant difference between samples 246 and 247.\n", "* Select the most popular event. In each of the control groups, find the number of users who performed this action. Find their share. Check whether the difference between the groups is statistically significant. Repeat the procedure for all other events (it will save time if you create a special function for this test). Can you confirm that the groups were split properly?\n", "* Do the same thing for the group with altered fonts. Compare the results with those of each of the control groups for each event in isolation. Compare the results with the combined results for the control groups. What conclusions can you draw from the experiment?\n", "* What significance level have you set to test the statistical hypotheses mentioned above? Calculate how many statistical hypothesis tests you carried out. With a statistical significance level of 0.1, one in 10 results could be false. What should the significance level be? If you want to change it, run through the previous steps again and check your conclusions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Number of users in each group" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
user_id
group
2462484
2472513
2482537
\n", "
" ], "text/plain": [ " user_id\n", "group \n", "246 2484\n", "247 2513\n", "248 2537" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.groupby(['group']).agg({'user_id':'nunique'})" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [], "source": [ "# let's make a dataframe for each group\n", "\n", "df_246 = df[df['group'] == 246]\n", "df_247 = df[df['group'] == 247]\n", "df_248 = df[df['group'] == 248]" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [], "source": [ "# for each group, create a dataframe grouped by events\n", "\n", "df_246_events_users = create_df_events_by_unique_users(df_246)\n", "df_247_events_users = create_df_events_by_unique_users(df_247)\n", "df_248_events_users = create_df_events_by_unique_users(df_248)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [], "source": [ "# drop the Tutorial event rows from each dataframe\n", "\n", "df_246_events_users = df_246_events_users.drop(df_246_events_users.index[4])\n", "df_247_events_users = df_247_events_users.drop(df_247_events_users.index[4])\n", "df_248_events_users = df_248_events_users.drop(df_248_events_users.index[4])" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
event_nameunique_users
0MainScreenAppear2450
1OffersScreenAppear1542
2CartScreenAppear1266
3PaymentScreenSuccessful1200
\n", "
" ], "text/plain": [ " event_name unique_users\n", "0 MainScreenAppear 2450\n", "1 OffersScreenAppear 1542\n", "2 CartScreenAppear 1266\n", "3 PaymentScreenSuccessful 1200" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_246_events_users" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
event_nameunique_users
0MainScreenAppear2476
1OffersScreenAppear1520
2CartScreenAppear1238
3PaymentScreenSuccessful1158
\n", "
" ], "text/plain": [ " event_name unique_users\n", "0 MainScreenAppear 2476\n", "1 OffersScreenAppear 1520\n", "2 CartScreenAppear 1238\n", "3 PaymentScreenSuccessful 1158" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_247_events_users" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
event_nameunique_users
0MainScreenAppear2493
1OffersScreenAppear1531
2CartScreenAppear1230
3PaymentScreenSuccessful1181
\n", "
" ], "text/plain": [ " event_name unique_users\n", "0 MainScreenAppear 2493\n", "1 OffersScreenAppear 1531\n", "2 CartScreenAppear 1230\n", "3 PaymentScreenSuccessful 1181" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_248_events_users" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "For group 246:\n", "The proportion of OffersScreenAppear users coming from MainScreenAppear is 62.94%\n", "The proportion of CartScreenAppear users coming from OffersScreenAppear is 82.1%\n", "The proportion of PaymentScreenSuccessful users coming from CartScreenAppear is 94.79%\n" ] } ], "source": [ "# check the proportions of each share of users by event, for each group\n", "\n", "check_proportions(df_246_events_users, '246')" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "connector": { "line": { "color": "lightblue", "dash": "dot", "width": 1 } }, "marker": { "color": "red", "line": { "color": "blue", "width": 1 } }, "name": "Group 246", "opacity": 0.65, "textinfo": "value+percent previous", "textposition": "inside", "type": "funnel", "x": [ 2450, 1542, 1266, 1200 ], "y": [ "MainScreenAppear", "OffersScreenAppear", "CartScreenAppear", "PaymentScreenSuccessful" ] } ], "layout": { "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "sequentialminus": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } } } }, "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_funnel(df_246_events_users, 'Group 246', 'red')" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The share of users who make the entire journey from their first event to payment is: 48.98%\n" ] } ], "source": [ "print('The share of users who make the entire journey from their first event to payment is: ' +\n", " (calculate_share_entire_journey(df_246_events_users)))" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "For group 247:\n", "The proportion of OffersScreenAppear users coming from MainScreenAppear is 61.39%\n", "The proportion of CartScreenAppear users coming from OffersScreenAppear is 81.45%\n", "The proportion of PaymentScreenSuccessful users coming from CartScreenAppear is 93.54%\n" ] } ], "source": [ "check_proportions(df_247_events_users, '247')" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "connector": { "line": { "color": "lightblue", "dash": "dot", "width": 1 } }, "marker": { "color": "lightgreen", "line": { "color": "blue", "width": 1 } }, "name": "Group 247", "opacity": 0.65, "textinfo": "value+percent previous", "textposition": "inside", "type": "funnel", "x": [ 2476, 1520, 1238, 1158 ], "y": [ "MainScreenAppear", "OffersScreenAppear", "CartScreenAppear", "PaymentScreenSuccessful" ] } ], "layout": { "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "sequentialminus": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } } } }, "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_funnel(df_247_events_users, 'Group 247', 'lightgreen')" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The share of users who make the entire journey from their first event to payment is: 46.77%\n" ] } ], "source": [ "print('The share of users who make the entire journey from their first event to payment is: ' +\n", " (calculate_share_entire_journey(df_247_events_users)))" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "For group 248:\n", "The proportion of OffersScreenAppear users coming from MainScreenAppear is 61.41%\n", "The proportion of CartScreenAppear users coming from OffersScreenAppear is 80.34%\n", "The proportion of PaymentScreenSuccessful users coming from CartScreenAppear is 96.02%\n" ] } ], "source": [ "check_proportions(df_248_events_users, '248')" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "connector": { "line": { "color": "lightblue", "dash": "dot", "width": 1 } }, "marker": { "color": "purple", "line": { "color": "blue", "width": 1 } }, "name": "Group 248", "opacity": 0.65, "textinfo": "value+percent previous", "textposition": "inside", "type": "funnel", "x": [ 2493, 1531, 1230, 1181 ], "y": [ "MainScreenAppear", "OffersScreenAppear", "CartScreenAppear", "PaymentScreenSuccessful" ] } ], "layout": { "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "sequentialminus": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } } } }, "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_funnel(df_248_events_users, 'Group 248', 'purple')" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The share of users who make the entire journey from their first event to payment is: 47.37%\n" ] } ], "source": [ "print('The share of users who make the entire journey from their first event to payment is: ' +\n", " (calculate_share_entire_journey(df_248_events_users)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Observation\n", "The percentage numbers are pretty close, so let's do some statistical tests\n", "\n" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [], "source": [ "# I enclosed the code into a function that takes two dataframes and an alpha level\n", "\n", "def custom_ztest(df1, df2, alpha_level = 0.05):\n", " \n", " alpha = alpha_level\n", " \n", " print('Chosen alpha level: ', alpha, '\\n')\n", " \n", "\n", " for i in range(1, len(df1)):\n", " \n", " successes = (df1.loc[i, 'unique_users'], df2.loc[i, 'unique_users'])\n", " trials = (df1.loc[i-1, 'unique_users'], df2.loc[i-1, 'unique_users'])\n", "\n", " # success proportion in the first group:\n", " p1 = successes[0]/trials[0]\n", " \n", " # success proportion in the second group:\n", " p2 = successes[1]/trials[1]\n", "\n", " # success proportion in the combined dataset:\n", " p_combined = (successes[0] + successes[1]) / (trials[0] + trials[1])\n", " \n", " # the difference between the datasets' proportions\n", " difference = p1 - p2\n", " \n", " # print('sqrt operand: ', (p_combined * (1 - p_combined) * (1/trials[0] + 1/trials[1])))\n", " \n", " # calculating the statistic in standard deviations of the standard normal distribution\n", " z_value = difference / mth.sqrt(abs(p_combined * (1 - p_combined) * (1/trials[0] + 1/trials[1])))\n", " \n", " # setting up the standard normal distribution (mean 0, standard deviation 1)\n", " distr = st.norm(0, 1)\n", "\n", " p_value = (1 - distr.cdf(abs(z_value))) * 2\n", "\n", " print('p-value for proportion of ' + df1.loc[i, 'event_name'] +\n", " ' users to that of ' +\n", " df1.loc[i-1, 'event_name'] + ': ', p_value)\n", "\n", " if (p_value < alpha):\n", " print(\"Rejecting the null hypothesis: there is a significant difference between the proportions\")\n", " else:\n", " print(\"Failed to reject the null hypothesis: there is no reason to consider the proportions different\")\n", " print()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Null hypothesis #1:\n", "That there is no significant differences between the two control groups from event to event when comparing proportions\n", "### Alternate hyposthesis #1:\n", "That there is significant difference between the two control groups from event to event when comparing proportions" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Chosen alpha level: 0.05 \n", "\n", "p-value for proportion of OffersScreenAppear users to that of MainScreenAppear: 0.2622344959255778\n", "Failed to reject the null hypothesis: there is no reason to consider the proportions different\n", "\n", "p-value for proportion of CartScreenAppear users to that of OffersScreenAppear: 0.6393754713145263\n", "Failed to reject the null hypothesis: there is no reason to consider the proportions different\n", "\n", "p-value for proportion of PaymentScreenSuccessful users to that of CartScreenAppear: 0.18243439408067652\n", "Failed to reject the null hypothesis: there is no reason to consider the proportions different\n", "\n" ] } ], "source": [ "# test for statistical significance between groups 246 and 247\n", "\n", "custom_ztest(df_246_events_users, df_247_events_users)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Result: there is no significant difference in all event comparisons between 246 and 247\n", "**Therefore,** we fail to reject the null hypothesis. So we can combine the two A/A groups together" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [], "source": [ "# create a dataframe of both groups 246 and 247\n", "\n", "df_AA_group = df[df['group'] != 248]" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
event_nameunique_users
0MainScreenAppear4926
1OffersScreenAppear3062
2CartScreenAppear2504
3PaymentScreenSuccessful2358
\n", "
" ], "text/plain": [ " event_name unique_users\n", "0 MainScreenAppear 4926\n", "1 OffersScreenAppear 3062\n", "2 CartScreenAppear 2504\n", "3 PaymentScreenSuccessful 2358" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_AA_users = create_df_events_by_unique_users(df_AA_group)\n", "df_AA_users = df_AA_users.drop(df_AA_users.index[4])\n", "df_AA_users" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "For group Group 248:\n", "The proportion of OffersScreenAppear users coming from MainScreenAppear is 61.41%\n", "The proportion of CartScreenAppear users coming from OffersScreenAppear is 80.34%\n", "The proportion of PaymentScreenSuccessful users coming from CartScreenAppear is 96.02%\n" ] } ], "source": [ "check_proportions(df_248_events_users, 'Group 248')" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "For group 246 and 247 combined:\n", "The proportion of OffersScreenAppear users coming from MainScreenAppear is 62.16%\n", "The proportion of CartScreenAppear users coming from OffersScreenAppear is 81.78%\n", "The proportion of PaymentScreenSuccessful users coming from CartScreenAppear is 94.17%\n" ] } ], "source": [ "check_proportions(df_AA_users, '246 and 247 combined')" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "name": "AA Group", "textinfo": "value+percent previous", "type": "funnel", "x": [ 4926, 3062, 2504, 2358 ], "y": [ "MainScreenAppear", "OffersScreenAppear", "CartScreenAppear", "PaymentScreenSuccessful" ] }, { "name": "248 users AKA B group", "orientation": "h", "textinfo": "value+percent previous", "type": "funnel", "x": [ 2493, 1531, 1230, 1181 ], "y": [ "MainScreenAppear", "OffersScreenAppear", "CartScreenAppear", "PaymentScreenSuccessful" ] } ], "layout": { "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "sequentialminus": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } } } }, "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig = go.Figure()\n", "\n", "fig.add_trace(go.Funnel(\n", " name = 'AA Group',\n", " y = df_AA_users['event_name'],\n", " x = df_AA_users['unique_users'],\n", " textinfo = \"value+percent previous\"))\n", "\n", "fig.add_trace(go.Funnel(\n", " name = '248 users AKA B group',\n", " orientation = \"h\",\n", " y = df_248_events_users['event_name'],\n", " x = df_248_events_users['unique_users'],\n", " textinfo = \"value+percent previous\"))\n", "\n", "fig.show()" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The share of users who make the entire journey from their first event to payment is: 47.87%\n" ] } ], "source": [ "print('The share of users who make the entire journey from their first event to payment is: ' +\n", " (calculate_share_entire_journey(df_AA_users)))" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The share of users who make the entire journey from their first event to payment is: 47.37%\n" ] } ], "source": [ "print('The share of users who make the entire journey from their first event to payment is: ' +\n", " (calculate_share_entire_journey(df_248_events_users)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Null hypothesis #2:\n", "That there is no significant differences between the AA group and the B group (aka group 248) from event to event\n", "### Alternate hypothesis #2:\n", "There is a significant difference between the AA group and the B group from event to event" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Chosen alpha level: 0.05 \n", "\n", "p-value for proportion of OffersScreenAppear users to that of MainScreenAppear: 0.5308589432077624\n", "Failed to reject the null hypothesis: there is no reason to consider the proportions different\n", "\n", "p-value for proportion of CartScreenAppear users to that of OffersScreenAppear: 0.23905954279947372\n", "Failed to reject the null hypothesis: there is no reason to consider the proportions different\n", "\n", "p-value for proportion of PaymentScreenSuccessful users to that of CartScreenAppear: 0.017114434319547067\n", "Rejecting the null hypothesis: there is a significant difference between the proportions\n", "\n" ] } ], "source": [ "custom_ztest(df_AA_users, df_248_events_users)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Observation\n", "The tests show that the only instance where there is significant difference is in the final part of the funnel, the PaymentScreenSuccessful event.\n", "\n", "Since this is (presumably) not a life/death situation, we choose the alpha level to be 0.05. Even with 0.1 as a suggestion, we would get the same results." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## Conclusion" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### We analyzed a dataset of over 244k logs from about 7500 users to see if changing the fonts resulted in better sales.\n", "\n", "Our control group consisted of two A groups, and one test group (B group), each of which comprised ~2400 users.\n", "\n", "There were no significant differences between the two A groups, which indicated we can be confident in the accuracy of our testing.\n", "\n", "Intuitively, it would seem that the B group (group 248) did slightly better, but only a little bit. We can see that the PaymentScreenSuccessful proportions for the B group is almost a full 2% higher. However, in the A group the percentages for the first two parts of the funnels were around 1% higher in the A group.\n", "\n", "**UPDATE:** When we do a simple comparison of the amount of users from each group who make the entire journey, however, we get a difference of only 0.5%, with actually the control (A/A) group doing better. That difference turns out to be about 38 users.\n", "\n", "If anything, this test suggests that we should perhaps compare other metrics such as profits, to see if we can gain any more useful insights.\n", "\n", "Otherwise, from this testing, I would conclude that if there were any differences in switching fonts, that difference is very negligible. I would recommend we do something else that can show more significant difference.\n", "\n", "**RECOMMENDATION ON FONT CHANGE:** We suggest no change in font." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " " ] } ], "metadata": { "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.8.3" } }, "nbformat": 4, "nbformat_minor": 4 }