Created
November 26, 2023 01:51
-
-
Save IgorKhomyanin/4c5f3b1a71c6decb793f0d638c4593ec to your computer and use it in GitHub Desktop.
Necessary Imports
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### IMPORTS | |
import numpy as np | |
import scipy.stats as stats | |
import matplotlib.pyplot as plt | |
### CONSTANTS | |
# Between what options we choose. | |
TITLE_OPTION_ONE = 'Title Option One' | |
TITLE_OPTION_TWO = 'Title Option Two' | |
# "Real" CTRs that are not known for the bandit. | |
# We need them to simulate viewers' behavior. | |
OPTION_ONE_POPULATION_CLICK_THROUGH_RATE = 0.05 | |
OPTION_TWO_POPULATION_CLICK_THROUGH_RATE = 0.07 | |
# Number of visitors to whom we will show titles. | |
VISITORS_CNT = 1000 | |
# Our prior belief about CTRs. | |
# Using a=1 and b=1, we state that there are no beliefs; any CTR is equally probable. | |
PRIOR_A = 1 | |
PRIOR_B = 1 | |
### SIMULATION | |
# To replicate results | |
np.random.seed(20231119) | |
# Variables to track how many viewers have seen and clicked on a title. | |
title_one_seen = 0 | |
title_one_clicked = 0 | |
title_two_seen = 0 | |
title_two_clicked = 0 | |
# These arrays are needed to evaluate the performance of algorithms later on | |
bandit_visitors_seen_highest_ctr_title = [] | |
random_visitors_seen_highest_ctr_title = [] | |
# For each visitor... | |
for _ in range(VISITORS_CNT): | |
# ... generate a posterior using Beta distribution adjusted based on observed data ... | |
option_one_beta_distribution = stats.beta( | |
a=PRIOR_A + title_one_clicked, # Add a number of "clicks" | |
b=PRIOR_B + (title_one_seen - title_one_clicked) # Add a number of "skips" | |
) | |
option_two_beta_distribution = stats.beta( | |
a=PRIOR_A + title_two_clicked, # Add a number of "clicks" | |
b=PRIOR_B + (title_two_seen - title_two_clicked) # Add a number of "skips" | |
) | |
# ... sample CTRs from these distributions ... | |
title_one_sample_ctr = option_one_beta_distribution.rvs() | |
title_two_sample_ctr = option_two_beta_distribution.rvs() | |
# ... choose what title to show using Thompson sampling. | |
if title_one_sample_ctr >= title_two_sample_ctr: | |
# Show title 1 | |
title_one_seen += 1 | |
# We know that Title One has a lower CTR. Hence, the algorithm made a mistake. | |
bandit_visitors_seen_highest_ctr_title.append(0) | |
# Determine if the visitor has clicked on the title. | |
if np.random.uniform(0.0, 1.0) <= OPTION_ONE_POPULATION_CLICK_THROUGH_RATE: | |
title_one_clicked += 1 | |
else: | |
# Show title 2 | |
title_two_seen += 1 | |
# We know that Title Two has a higher CTR. Hence, the algorithm made a correct decision. | |
bandit_visitors_seen_highest_ctr_title.append(1) | |
# Determine if the visitor has clicked | |
if np.random.uniform(0.0, 1.0) <= OPTION_TWO_POPULATION_CLICK_THROUGH_RATE: | |
title_two_clicked += 1 | |
# Our alternative to a Bayesian Multi-armed Bandit is a random split between both options | |
# Split is 50/50, which is why, with a probability of 0.5, random split will assign the higher CTR title. | |
if np.random.uniform(0.0, 1.0) <= 0.5: | |
random_visitors_seen_highest_ctr_title.append(1) | |
else: | |
random_visitors_seen_highest_ctr_title.append(0) | |
### SHOW RESULTS | |
print('RESULTS OF THE SIMULATION') | |
print('Viewers seen Title One', title_one_seen) | |
print('Viewers clicked on Title One', title_one_clicked) | |
print('Observed CTR of Title One', title_one_clicked / title_one_seen) | |
print() | |
print('RESULTS OF THE SIMULATION') | |
print('Viewers seen Title Two', title_two_seen) | |
print('Viewers clicked on Title Two', title_two_clicked) | |
print('Observed CTR of Title Two', title_two_clicked / title_two_seen) | |
print() | |
print('% of viewers whom Multi-armed Bandit showed the highest CTR title', np.mean(bandit_visitors_seen_highest_ctr_title)) | |
print('% of viewers whom Random Split showed the highest CTR title', np.mean(random_visitors_seen_highest_ctr_title)) | |
### RESULTS | |
# >>> RESULTS OF THE SIMULATION | |
# >>> Viewers seen Title One 227 | |
# >>> Viewers clicked on Title One 10 | |
# >>> Observed CTR of Title One 0.04405286343612335 | |
# >>> RESULTS OF THE SIMULATION | |
# >>> Viewers seen Title Two 773 | |
# >>> Viewers clicked on Title Two 54 | |
# >>> Observed CTR of Title Two 0.06985769728331177 | |
# >>> % of viewers whom Multi-armed Bandit showed the highest CTR title 0.773 | |
# >>> % of viewers whom Random Split showed the highest CTR title 0.502 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment