Skip to content

Instantly share code, notes, and snippets.

@tadeoos
Last active September 10, 2017 16:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tadeoos/a351d0a9549b7a82e0d01a04042124ae to your computer and use it in GitHub Desktop.
Save tadeoos/a351d0a9549b7a82e0d01a04042124ae to your computer and use it in GitHub Desktop.
Script for calculating spotify's discover weekly probabilities
from __future__ import print_function, division
import itertools, sys, time
# simple factorial function
def fact(n, acc=1):
return acc if n == 0 else fact(n - 1, n * acc)
# binomial coefficient
def newton(n, k):
return 0 if k > n else fact(n) / (fact(k) * fact(n - k))
# our function!
def discover_weekly_prob(n, x, y):
if x * y < n:
return 0
sigma_sum = sum([((-1)**(i - 1)) * newton(n, i) * (((newton((n - i), y)
* fact(y) * fact(n - y)) / (fact(n)))**x) for i in range(1, n - y + 1)])
return 1 - sigma_sum
def filter_heads(p, head):
# This function flattens a tuple of tuples into list of gotten heads
# filter_heads(((1,4,2,3), (3,1,2,4)), 2) => [1,4,3,1]
return [y for x in p for y in x[:head]]
def brute_prob(n, x, y):
# all possible permutations of our initial set
permuts = [p for p in itertools.permutations(range(n))]
# list of every possible outcome of our experiment. Shrinked to y-long heads.
space = [filter_heads(prdct, y) for prdct in itertools.product(permuts, repeat=x)]
# the number of outcomes in which we got all elements of our initial set
good = sum([1 for outcome in space if len(set(outcome)) == n])
return (good / len(space))
def tests(n=5):
for x in range(1, n+1):
for h in range(1, n):
for t in range(1, 4):
w = brute_prob(x, t, h)
# if w>0:
# print('for n:{} x:{} y:{} prob is {}'.format(x,t,h,w))
assert (abs(w - discover_weekly_prob(x,t,h)) < 0.01)
print('--tests passed--')
def best_ratio(sngtme=5, hours=7, scale=1, prnt=False, tmlimit=False):
TIME_LIMIT = hours*60/sngtme
res = []
data_dict = {'x':[], 'y':[], 'ratio':[]} # dict used for creating a scatter plot
for x in range(1,31):
for y in range(1,31):
prob = discover_weekly_prob(30, x, y)
filtered_prob = 0 if prob <= 0.5 else prob
if tmlimit:
if prob == 0 or (x*y > TIME_LIMIT):
continue
ratio = (30*scale*filtered_prob) / (y * x)
res.append((ratio,x,y))
data_dict['x'].append(x)
data_dict['y'].append(y)
rt_to_add = ratio*2 if ratio!=1 else ratio+0.1 # scaling for scatter plot
data_dict['ratio'].append(rt_to_add)
res.sort(reverse=True)
if prnt:
for x in res:
print('y: {} x: {} ratio: {:.6}'.format(x[2],x[1], x[0]))
return res, data_dict
if __name__ == "__main__":
# tests()
try:
assert len(sys.argv)==4
n, x, y = int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3])
res = discover_weekly_prob(n,x,y)
ratio = (30*res) / (y * x)
print('With n={}, x={} & y={}\nThe probability of listening to every song is ~{:.0%}\nProbability/time ratio is {:.4}'.format(n,x,y,res,ratio))
except Exception as e:
print("Something went wrong...")
if len(sys.argv)!=4:
print("It looks like you haven't passed three arguments!")
elif y>n:
print('y cannot be bigger then n!')
else:
print('Your error is: ', e)
print('Correct syntax looks like this: "python spot.py 30 14 5"')
@tadeoos
Copy link
Author

tadeoos commented Feb 15, 2017

For context see my post.

USAGE

You need to have Python installed. Both 2.7+ and 3+ versions are supported.

If you are on mac - don't worry you should have Python 2.7 already installed. Otherwise - read this.

Once you have Python installed, download the above file. Then open Terminal and go to the folder where you saved the file.

Example for mac users:

If you downloaded the file to your "Downloads" folder, you should simply type cd ~/Downloads in Terminal and you should be good to go.

Once you're there you just run the script and pass the values for n, x and y by typing for example:

python spot.py 30 14 6

this will print the probability for n=30 x=14 and y=6 as well as it's ratio measure.

Have fun! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment