Weighted distrobution with non-uniform sets
Full Frame logo: 1/4 Logo:
+------------+ +-----+------+ | | | A | B | | | +-----+------+ |Full Frame | | C | D | +------------+ +-----+------+
So i have a set of customers with properties:
- Name
- Limit (Amout of views they purchased)
- Shown (Amout of views aquired)
- FullScreen (If it’s a fullscreen or not)
I then try to generate every possible screen and give it a score(Later to be used as weight): I also iterate over every customer to gain a `total_remaining` for use in the `weight`
for customer in customers: remaining = customer['limit'] - customer['shown'] total_remaining += remaining if remaining < 0: continue if customer['fullscreen']: possible_fullscreeens.append({ 'name': customer['name'], 'limit': customer['limit'], 'shown': customer['shown'], 'remaining': remaining }) if not customer['fullscreen']: possible_quarts.append({ 'name': customer['name'], 'limit': customer['limit'], 'shown': customer['shown'], 'remaining': remaining })
Both fullscreen and quarts are now in a temporary dict, i neeede to iterate over twice to get the `total_remaining`
And for then we add all possible screens in `possible_ads` For the fullscreen this is straight forward:
for full in possible_fullscreeens: possible_ads.append({ "name": full['name'], "score": full['remaining'], "remaining": full['remaining'], "weight": (full['remaining'] / total_remaining) * 100.0 })
For quarts this is a lot more work, and i probably did it wrong in a stupid way. But here we go.
# First i get all the possible combinations for the given set possible_combinations = get_possible_combinations(len(possible_quarts), 4) for subset in itertools.combinations(possible_quarts, 4): score = 0 name = "" for customer in subset: customer_name = customer['name'] name += customer_name + ',' score += customer['remaining'] / 4.0 possible_ads.append({ "name": name, "score": score, "remaining": score, "weight": ((score / total_remaining) * 100.0) / (possible_combinations) })
Then we use the weights to do a weighted random selection
(total_remaining, possible_ads) = update_adds() if (len(possible_ads) <= 1): print("All done") break weights = [] for ad in possible_ads: weights.append(ad['weight']) ad = secure_random.choices(possible_ads, weights=weights, k=1)[0]
My assumtion is that it should take about as long for everyone to reach the limit, i have some wierd distrobution in that respect This is the response after 100_000 runs, the lower letters have high numbers because their limits is low, and `A`,`A1` and `A2` are fullscreen
A %: 24.82 A2 %: 24.908 A3 %: 24.81 B %: 19.68 C %: 19.296 D %: 19.42 F %: 3.7216 G %: 36.724000000000004 H %: 36.832 I %: 37.532 K %: 37.104 L %: 100.02 M %: 100.05 P %: 105.0 Q %: 110.00000000000001
This needs more work