Last active
September 10, 2017 16:55
-
-
Save tadeoos/a351d0a9549b7a82e0d01a04042124ae to your computer and use it in GitHub Desktop.
Script for calculating spotify's discover weekly probabilities
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
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"') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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! :)