Image Credit: Instapages

Thompson Sampling with Django — Part2

William Okafor
3 min readJan 3, 2019

--

Welcome back! In this second part, I will show you how to display the ad selected by your algorithm on a page, how to add buttons to enable users ‘Like’ or ‘Dislike’ images thereby helping the program get better and i’d throw some bonuses in the mix.

In case you missed the previous part, you really should have a look at it here before proceeding

Let’s Begin

In the home function of the ads/views file add the following code:

ads = Ad.objects.all()
context = {
'clicks' : ads_rewards,
'numb1' : numbers_of_rewards_1,
'numb0' : numbers_of_rewards_0,
'selected' : ads_selected,#The ads displayed to all users
'ad' : ads[ad]#The last ad selected by the algorithm
}
return render(request,'ads/home.html', context)

Let’s create the page that would receive these variables

Create a templatesfolder inside the ads folder then create another folder called ads then create ahome.html page inside it

I know, Django can be annoying

Now add the following code into your home.html page

{% load static %} 
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<title>Adverts</title>
</head>
<body>
<h1>Thomas Sampling Ads</h1>
<div class="container">
<div class="row">
<div class="col-4">
<img src="{{ad.image.url}}" alt="" class="img-fluid">
</div>
<div class="col-4">
<a class="btn btn-small btn-primary" href="{% url 'like-ad' ad.id %}">Like</a>
<a class="btn btn-small btn-danger" href="{% url 'dislike-ad' ad.id %}">Dislike</a>
<br/>Indexes of ads that has been shown to different users - {{ selected }}
<br> Reward 1 : {{ numb1 }}
<br> Reward 0 : {{ numb0 }}
<br> Clicks as seen in db : {{ clicks }}
</div>
</div>
</div>
</body>
</html>

I didn’t spend time on design as this isn’t a design tutorial

Pfft! I’m terrible with designs

I added buttons for liking and disliking the ad image shown to the user so let’s create the route for that as well as it’s respective methods.

Liking and disliking an ad:

Add the following items to your the urlspattern list of youadd/urls.py file

path('like/<int:ad>', views.like, name ='like-ad'),
path('dislike/<int:ad>', views.dislike, name ='dislike-ad')

Now we would create a like and dislike function in the ad/views.py file to handle each button click

def like(request, ad):
inter_id = 0
cell = f"ad_{ad}"
inter_id = request.session['user_interaction_id']
Interaction.objects.filter(pk=inter_id).update(**{cell : 1})
return redirect( reverse_lazy('ads-home') )def dislike(request, ad):
inter_id = 0
cell = f"ad_{ad}"
inter_id = request.session['user_interaction_id']
Interaction.objects.filter(pk=inter_id).update(**{cell : 0})
return redirect( reverse_lazy('ads-home') )

And we’re done.

You can start the server and navigate to localhost:8000 to view your new application running. Each reload or interaction (Like or Dislike) gives a new ad which was selected by our algorithm which uses the previous interactions with the ads to select which ad is shown to us.

Extra:

If you’re like me, you don’t have the luxury of 100s of users to test our app so as to give us the convergence we are hoping to find, so i did these:

Randomly create X number of users where they make random ‘clicks’ on the ads by adding this at the top of the home function:

X = 500
for n in range(500):
cell = f"ad_{random.randint(1,10)}"
new = Interaction_Thomas(**{cell : 1})
new.save()

Run this only once, after which you should comment or it out to prevent yourself from creating 500 new user interactions each time you load this page.

To further quicken this convergence, i created a session to store number_of_rewards_0 and number_of_rewards_1 like so:

After the Loop through the users, i added the following code:

request.session['thomas_rewards_0'] = numbers_of_rewards_0
request.session['thomas_rewards_1'] = numbers_of_rewards_1

Then before the loop, i added the following code:

if not request.session.get('thomas_rewards_0', None):
numbers_of_rewards_1 = [0] * d
numbers_of_rewards_0 = [0] * d
else:
numbers_of_rewards_0 = request.session['thomas_rewards_0']
numbers_of_rewards_1 = request.session['thomas_rewards_1']

With this, the number_of_rewards used in the algorithm becomes persistent and we’d be able to see the convergence in just 3–5 reloads instead of waiting for say 1,500 user’s interaction on our ad.

I hope this was helpful to you and I want to thank you for reading this post. Hit clap in case it was helpful so that others may find it too. You can also give suggestions in the comment section.

Finally, you can access the full source code of this program on this Github Repo

--

--