{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Guided Project: Mobile App for Lottery Addiction\n", "\n", "In this project, we are going to contribute to the development of a mobile app by writing a couple of functions that are mostly focused on calculating probabilities. The app is aimed to both prevent and treat lottery addiction by helping people better estimate their chances of winning.\n", "\n", "The app idea comes from a medical institute which is specialized in treating gambling addictions. The institute already has a team of engineers that will build the app, but they need us to create the logical core of the app and calculate probabilities. For the first version of the app, they want us to focus on the 6/49 lottery and build functions that can answer users the following questions:\n", "\n", "- What is the probability of winning the big prize with a single ticket?\n", "- What is the probability of winning the big prize if we play 40 different tickets (or any other number)?\n", "- What is the probability of having at least five (or four, or three) winning numbers on a single ticket?\n", "\n", "The scenario we're following throughout this project is fictional — the main purpose is to practice applying probability and combinatorics (permutations and combinations) concepts in a setting that simulates a real-world scenario.\n", "\n", "## Core Functions\n", "\n", "Below, we're going to write two functions that we'll be using frequently:\n", "\n", "- `factorial()` — a function that calculates factorials\n", "- `combinations()` — a function that calculates combinations" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "def factorial(n):\n", " final_product = 1\n", " for i in range(n, 0, -1):\n", " final_product *= i\n", " return final_product\n", "\n", "def combinations(n, k):\n", " numerator = factorial(n)\n", " denominator = factorial(k) * factorial(n-k)\n", " return numerator/denominator" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## One-ticket Probability\n", "\n", "We need to build a function that calculates the probability of winning the big prize for any given ticket. For each drawing, six numbers are drawn from a set of 49, and a player wins the big prize if the six numbers on their tickets match all six numbers.\n", "\n", "The engineer team told us that we need to be aware of the following details when we write the function:\n", "\n", "- Inside the app, the user inputs six different numbers from 1 to 49.\n", "- Under the hood, the six numbers will come as a Python list and serve as an input to our function.\n", "- The engineering team wants the function to print the probability value in a friendly way — in a way that people without any probability training are able to understand.\n", "\n", "Below, we write the `one_ticket_probability()` function, which takes in a list of six unique numbers and prints the probability of winning in a way that's easy to understand." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def one_ticket_probability(user_numbers):\n", " \n", " n_combinations = combinations(49, 6)\n", " probability_one_ticket = 1/n_combinations\n", " percentage_form = probability_one_ticket * 100\n", " \n", " print('''Your chances to win the big prize with the numbers {} are {:.7f}%.\n", "In other words, you have a 1 in {:,} chances to win.'''.format(user_numbers,\n", " percentage_form, int(n_combinations)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now test a bit the function on two different outputs." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Your chances to win the big prize with the numbers [2, 43, 22, 23, 11, 5] are 0.0000072%.\n", "In other words, you have a 1 in 13,983,816 chances to win.\n" ] } ], "source": [ "test_input_1 = [2, 43, 22, 23, 11, 5]\n", "one_ticket_probability(test_input_1)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Your chances to win the big prize with the numbers [9, 26, 41, 7, 15, 6] are 0.0000072%.\n", "In other words, you have a 1 in 13,983,816 chances to win.\n" ] } ], "source": [ "test_input_2 = [9, 26, 41, 7, 15, 6]\n", "one_ticket_probability(test_input_2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Historical Data Check for Canada Lottery\n", "\n", "The institute also wants us to consider the data coming from the national 6/49 lottery game in Canada. The data set contains historical data for 3,665 drawings, dating from 1982 to 2018 (the data set can be downloaded from [here](https://www.kaggle.com/datascienceai/lottery-dataset))." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(3665, 11)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "\n", "lottery_canada = pd.read_csv('649.csv')\n", "lottery_canada.shape" ] }, { "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
PRODUCTDRAW NUMBERSEQUENCE NUMBERDRAW DATENUMBER DRAWN 1NUMBER DRAWN 2NUMBER DRAWN 3NUMBER DRAWN 4NUMBER DRAWN 5NUMBER DRAWN 6BONUS NUMBER
0649106/12/19823111214414313
1649206/19/1982833363739419
2649306/26/1982162324273934
\n", "
" ], "text/plain": [ " PRODUCT DRAW NUMBER SEQUENCE NUMBER DRAW DATE NUMBER DRAWN 1 \\\n", "0 649 1 0 6/12/1982 3 \n", "1 649 2 0 6/19/1982 8 \n", "2 649 3 0 6/26/1982 1 \n", "\n", " NUMBER DRAWN 2 NUMBER DRAWN 3 NUMBER DRAWN 4 NUMBER DRAWN 5 \\\n", "0 11 12 14 41 \n", "1 33 36 37 39 \n", "2 6 23 24 27 \n", "\n", " NUMBER DRAWN 6 BONUS NUMBER \n", "0 43 13 \n", "1 41 9 \n", "2 39 34 " ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lottery_canada.head(3)" ] }, { "cell_type": "code", "execution_count": 7, "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", "
PRODUCTDRAW NUMBERSEQUENCE NUMBERDRAW DATENUMBER DRAWN 1NUMBER DRAWN 2NUMBER DRAWN 3NUMBER DRAWN 4NUMBER DRAWN 5NUMBER DRAWN 6BONUS NUMBER
3662649358906/13/20186222431323416
3663649359006/16/2018215213138498
3664649359106/20/201814243135374817
\n", "
" ], "text/plain": [ " PRODUCT DRAW NUMBER SEQUENCE NUMBER DRAW DATE NUMBER DRAWN 1 \\\n", "3662 649 3589 0 6/13/2018 6 \n", "3663 649 3590 0 6/16/2018 2 \n", "3664 649 3591 0 6/20/2018 14 \n", "\n", " NUMBER DRAWN 2 NUMBER DRAWN 3 NUMBER DRAWN 4 NUMBER DRAWN 5 \\\n", "3662 22 24 31 32 \n", "3663 15 21 31 38 \n", "3664 24 31 35 37 \n", "\n", " NUMBER DRAWN 6 BONUS NUMBER \n", "3662 34 16 \n", "3663 49 8 \n", "3664 48 17 " ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lottery_canada.tail(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Function for Historical Data Check\n", "\n", "The engineering team tells us that we need to write a function that can help users determine whether they would have ever won by now using a certain combination of six numbers. These are the details we'll need to be aware of:\n", "\n", "- Inside the app, the user inputs six different numbers from 1 to 49.\n", "- Under the hood, the six numbers will come as a Python list and serve as an input to our function.\n", "- The engineering team wants us to write a function that prints:\n", " - the number of times the combination selected occurred; and\n", " - the probability of winning the big prize in the next drawing with that combination.\n", " \n", "\n", "We're going to begin by extracting all the winning numbers from the lottery data set. The `extract_numbers()` function will go over each row of the dataframe and extract the six winning numbers as a Python set." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 {3, 41, 11, 12, 43, 14}\n", "1 {33, 36, 37, 39, 8, 41}\n", "2 {1, 6, 39, 23, 24, 27}\n", "3 {3, 9, 10, 43, 13, 20}\n", "4 {34, 5, 14, 47, 21, 31}\n", "dtype: object" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def extract_numbers(row):\n", " row = row[4:10]\n", " row = set(row.values)\n", " return row\n", "\n", "winning_numbers = lottery_canada.apply(extract_numbers, axis=1)\n", "winning_numbers.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Below, we write the `check_historical_occurrence()` function that takes in the user numbers and the historical numbers and prints information with respect to the number of occurrences and the probability of winning in the next drawing." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "def check_historical_occurrence(user_numbers, historical_numbers): \n", " '''\n", " user_numbers: a Python list\n", " historical numbers: a pandas Series\n", " '''\n", " \n", " user_numbers_set = set(user_numbers)\n", " check_occurrence = historical_numbers == user_numbers_set\n", " n_occurrences = check_occurrence.sum()\n", " \n", " if n_occurrences == 0:\n", " print('''The combination {} has never occured.\n", "This doesn't mean it's more likely to occur now. Your chances to win the big prize in the next drawing using the combination {} are 0.0000072%.\n", "In other words, you have a 1 in 13,983,816 chances to win.'''.format(user_numbers, user_numbers))\n", " \n", " else:\n", " print('''The number of times combination {} has occured in the past is {}.\n", "Your chances to win the big prize in the next drawing using the combination {} are 0.0000072%.\n", "In other words, you have a 1 in 13,983,816 chances to win.'''.format(user_numbers, n_occurrences,\n", " user_numbers))" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The number of times combination [33, 36, 37, 39, 8, 41] has occured in the past is 1.\n", "Your chances to win the big prize in the next drawing using the combination [33, 36, 37, 39, 8, 41] are 0.0000072%.\n", "In other words, you have a 1 in 13,983,816 chances to win.\n" ] } ], "source": [ "test_input_3 = [33, 36, 37, 39, 8, 41]\n", "check_historical_occurrence(test_input_3, winning_numbers)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The combination [3, 2, 44, 22, 1, 44] has never occured.\n", "This doesn't mean it's more likely to occur now. Your chances to win the big prize in the next drawing using the combination [3, 2, 44, 22, 1, 44] are 0.0000072%.\n", "In other words, you have a 1 in 13,983,816 chances to win.\n" ] } ], "source": [ "test_input_4 = [3, 2, 44, 22, 1, 44]\n", "check_historical_occurrence(test_input_4, winning_numbers)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Multi-ticket Probability\n", "\n", "For the first version of the app, users should also be able to find the probability of winning if they play multiple different tickets. For instance, someone might intend to play 15 different tickets and they want to know the probability of winning the big prize.\n", "\n", "The engineering team wants us to be aware of the following details when we're writing the function:\n", "\n", "- The user will input the number of different tickets they want to play (without inputting the specific combinations they intend to play).\n", "- Our function will see an integer between 1 and 13,983,816 (the maximum number of different tickets).\n", "- The function should print information about the probability of winning the big prize depending on the number of different tickets played.\n", "\n", "The `multi_ticket_probability()` function below takes in the number of tickets and prints probability information depending on the input." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "def multi_ticket_probability(n_tickets):\n", " \n", " n_combinations = combinations(49, 6)\n", " \n", " probability = n_tickets / n_combinations\n", " percentage_form = probability * 100\n", " \n", " if n_tickets == 1:\n", " print('''Your chances to win the big prize with one ticket are {:.6f}%.\n", "In other words, you have a 1 in {:,} chances to win.'''.format(percentage_form, int(n_combinations)))\n", " \n", " else:\n", " combinations_simplified = round(n_combinations / n_tickets) \n", " print('''Your chances to win the big prize with {:,} different tickets are {:.6f}%.\n", "In other words, you have a 1 in {:,} chances to win.'''.format(n_tickets, percentage_form,\n", " combinations_simplified))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Below, we run a couple of tests for our function." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Your chances to win the big prize with one ticket are 0.000007%.\n", "In other words, you have a 1 in 13,983,816 chances to win.\n", "------------------------\n", "Your chances to win the big prize with 10 different tickets are 0.000072%.\n", "In other words, you have a 1 in 1,398,382 chances to win.\n", "------------------------\n", "Your chances to win the big prize with 100 different tickets are 0.000715%.\n", "In other words, you have a 1 in 139,838 chances to win.\n", "------------------------\n", "Your chances to win the big prize with 10,000 different tickets are 0.071511%.\n", "In other words, you have a 1 in 1,398 chances to win.\n", "------------------------\n", "Your chances to win the big prize with 1,000,000 different tickets are 7.151124%.\n", "In other words, you have a 1 in 14 chances to win.\n", "------------------------\n", "Your chances to win the big prize with 6,991,908 different tickets are 50.000000%.\n", "In other words, you have a 1 in 2 chances to win.\n", "------------------------\n", "Your chances to win the big prize with 13,983,816 different tickets are 100.000000%.\n", "In other words, you have a 1 in 1 chances to win.\n", "------------------------\n" ] } ], "source": [ "test_inputs = [1, 10, 100, 10000, 1000000, 6991908, 13983816]\n", "\n", "for test_input in test_inputs:\n", " multi_ticket_probability(test_input)\n", " print('------------------------') # output delimiter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Less Winning Numbers — Function\n", "\n", "In most 6/49 lotteries, there are smaller prizes if a player's ticket match two, three, four, or five of the six numbers drawn. This means that players might be interested in finding out the probability of having two, three, four, or five winning numbers — for the first version of the app, users should be able to find those probabilities.\n", "\n", "These are the details we need to be aware of when we write a function to make the calculations of those probabilities possible:\n", "\n", "- Inside the app, the user inputs:\n", " - six different numbers from 1 to 49; and\n", " - an integer between 2 and 5 that represents the number of winning numbers expected\n", "- Our function prints information about the probability of having a certain number of winning numbers\n", "\n", "To calculate the probabilities, we tell the engineering team that the specific combination on the ticket is irrelevant and we only need the integer between 2 and 5 representing the number of winning numbers expected. Consequently, we will write a function named `probability_less_6()` which takes in an integer and prints information about the chances of winning depending on the value of that integer.\n", "\n", "The function below calculates the probability that a player's ticket matches exactly the given number of winning numbers. If the player wants to find out the probability of having five winning numbers, the function will return the probability of having five winning numbers exactly (no more and no less). The function will not return the probability of having _at least_ five winning numbers." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "def probability_less_6(n_winning_numbers):\n", " \n", " n_combinations_ticket = combinations(6, n_winning_numbers)\n", " n_combinations_remaining = combinations(43, 6 - n_winning_numbers)\n", " successful_outcomes = n_combinations_ticket * n_combinations_remaining\n", " \n", " n_combinations_total = combinations(49, 6) \n", " probability = successful_outcomes / n_combinations_total\n", " \n", " probability_percentage = probability * 100 \n", " combinations_simplified = round(n_combinations_total/successful_outcomes) \n", " print('''Your chances of having {} winning numbers with this ticket are {:.6f}%.\n", "In other words, you have a 1 in {:,} chances to win.'''.format(n_winning_numbers, probability_percentage,\n", " int(combinations_simplified)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's test the function on all the three possible inputs." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Your chances of having 2 winning numbers with this ticket are 13.237803%.\n", "In other words, you have a 1 in 8 chances to win.\n", "--------------------------\n", "Your chances of having 3 winning numbers with this ticket are 1.765040%.\n", "In other words, you have a 1 in 57 chances to win.\n", "--------------------------\n", "Your chances of having 4 winning numbers with this ticket are 0.096862%.\n", "In other words, you have a 1 in 1,032 chances to win.\n", "--------------------------\n", "Your chances of having 5 winning numbers with this ticket are 0.001845%.\n", "In other words, you have a 1 in 54,201 chances to win.\n", "--------------------------\n" ] } ], "source": [ "for test_input in [2, 3, 4, 5]:\n", " probability_less_6(test_input)\n", " print('--------------------------') # output delimiter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Next steps\n", "\n", "For the first version of the app, we coded four main functions:\n", "\n", "- `one_ticket_probability()` — calculates the probability of winning the big prize with a single ticket\n", "- `check_historical_occurrence()` — checks whether a certain combination has occurred in the Canada lottery data set\n", "- `multi_ticket_probability()` — calculates the probability for any number of of tickets between 1 and 13,983,816\n", "- `probability_less_6()` — calculates the probability of having two, three, four or five winning numbers exactly\n", "\n", "Possible features for a second version of the app include:\n", "\n", "- Making the outputs even easier to understand by adding fun analogies (for example, we can find probabilities for strange events and compare with the chances of winning in lottery; for instance, we can output something along the lines \"You are 100 times more likely to be the victim of a shark attack than winning the lottery\")\n", "- Combining the `one_ticket_probability()` and `check_historical_occurrence()` to output information on probability and historical occurrence at the same time\n", "- Create a function similar to `probability_less_6()` which calculates the probability of having _at least_ two, three, four or five winning numbers. Hint: the number of successful outcomes for having at least four winning numbers is the sum of these three numbers:\n", " - The number of successful outcomes for having four winning numbers exactly\n", " - The number of successful outcomes for having five winning numbers exactly\n", " - The number of successful outcomes for having six winning numbers exactly" ] } ], "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.7.3" } }, "nbformat": 4, "nbformat_minor": 4 }