NBA style lottery (weighted lottery)
The NBA adopted a weighted lottery system in 1990 to give the team with the worst record the best chance of receiving the number 1 pick. The odds associated with the weighted lottery system within the NBA have been adjusted over the years to reduce both the number of first overall picks by the best team in the lottery and to reduce the overall odds of the worst team getting the first overall pick to prevent intentional tanking. In our league, the deterrent of no guarantee for the first overall pick and the shame of finishing last is currently enough to prevent any intentional tanking.
There is something beautiful about powers of 2 and our system increase the odds of winning the first pick by a power of 2. The league champion has a single chance (0.1%) chance of winning the first overall pick. The runner up has 2 chances (0.2%) of winning the first overall pick. The third and fourth place have odds of 0.4% (4 chances) and 0.8% (8 chances) respectively. Do you see a pattern emerging? This continues until the last place finisher in our league with 512 chances or 50% odds to win the first overall pick.
When we implemented this system we did so in both R and python, however for the purposes of this article we will detail only the R version. **Note: R and python will have different outcomes because the random number generators are different between the two.** To implement our system, we created lists of our league member’s names of length N with the N (number of chances) determined by their placement.
## Create Member Lists of Length N by Finish Position
first <- "Mack"
second <- rep("Colin", 2**1)
third <- rep("Frank", 2**2)
last_place <- rep("Matt", 2**9)
The above code is truncated for brevity, however, once we have lists of various sizes we pool the list names together and randomly sample. This is where the set seed comes into play, we use the year as the set seed for reproducibility. Finally, after randomly sampling we return the pick selection order by using the unique command to return the first occurrence of a member’s name.
## Establish set.seed
year <- 2020
set.seed(year)## Pool and randomly sample
pool <- c(first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, last_place)sampled_pool <- sample(pool)## Get unique output
pick_selection_order <- unique(shuffled_pool)
Making it available to everyone in the league
To increase the transparency of the program, we created a web application using R Shiny. The code for running the application is found on my GitHub. The shiny package is needed to run the application locally. The web application is currently specific for our league because of the inputs listed as choices. To make it unique to your league (if you have 10 players) simply change the list at each position in the application.
selectInput("last", h5("Select the Loser"),
choices = c("Mack", "Fish", "Todd", "Colin", "Andrew",
"Jake", "Frank", "Matt","Cody", "Jim"))
The Wisdom of our Commissioner
While the application is run by the commissioner and validated across the league, there were some that were unhappy with their draft position (2nd or 3rd) when they wanted to be near the 9th or 10th pick in our snake draft format. The commissioner changed the purpose of the draft pick generator not to define the positions in the draft, but the ordering to select pick positions. For example in the above ordering, Jim can select the first pick or anywhere else in the first round. As the person with the second pick, I can select any draft position except those that have been selected by those above me. This system has been accepted amongst 10 highly competitive fantasy footballers to organize our draft positions for the last 4 years. It has elements of randomness and control.