Voir la mise à jour ci-dessous...
J'écris une simulation Python qui attribue à un nombre arbitraire de joueurs imaginaires un but parmi un ensemble arbitraire de buts. Les objectifs ont deux niveaux ou proportions différents de rareté, prop_high
et prop_low
dans un rapport d'environ 3:1.
Par exemple, s'il y a 16 joueurs et 4 buts, ou 8 joueurs et 4 buts, les deux pools de buts ressembleront à ceci :
{'A': 6, 'B': 6, 'C': 2, 'D': 2}
{'A': 3, 'B': 3, 'C': 1, 'D': 1}
...avec des buts A et B survenant 3 fois plus souvent que C et D. 6+6+2+2 = 16, ce qui correspond au nombre de joueurs dans la simulation, ce qui est bien.
Je veux avoir une réserve de buts égale au nombre de joueurs et répartie de manière à ce qu'il y ait environ trois fois plus de buts. prop_high
comme il y a prop_low
objectifs.
Quelle est la meilleure façon de construire un algorithme d'allocation en fonction d'un ratio approximatif ou approximatif - quelque chose qui peut gérer les arrondis ?
Mise à jour :
En supposant 8 joueurs, voici à quoi devraient ressembler les distributions de 2 à 8 buts ( prop_high
les joueurs sont marqués d'une étoile) :
A B C D E F G H
2 6* 2
3 6* 1 1
4 3* 3* 1 1
5 3* 2* 1 1 1
6 2* 2* 1* 1 1 1
7 2* 1* 1* 1 1 1 1
8 1* 1* 1* 1* 1 1 1 1
Ces chiffres ne correspondent pas à des joueurs. Par exemple, avec 5 buts et 8 joueurs, les buts A et B ont une forte proportion dans la poule (3 et 2 respectivement) tandis que les buts C, D et E sont plus rares (1 chacun).
Quand il y a un nombre impair de buts, le dernier des prop_high
en reçoit un de moins que les autres. Au fur et à mesure que le nombre de buts se rapproche du nombre de joueurs, chacun des prop_high
Les postes en obtiennent un de moins jusqu'à la fin, lorsqu'il ne reste plus qu'un seul de chaque objectif dans la poule.
Ce que j'ai fait ci-dessous est d'attribuer des quantités aux extrémités haute et basse de la poule, puis d'ajuster l'extrémité haute, en soustrayant des valeurs en fonction de la proximité entre le nombre de buts et le nombre de joueurs. Cela fonctionne bien avec 8 joueurs (le nombre de buts dans le pool est toujours égal à 8), mais c'est tout.
Je suis absolument sûr qu'il existe une meilleure façon, plus pythonique, de gérer ce genre d'algorithme, et je suis pratiquement sûr que c'est un modèle de conception relativement commun. Je ne sais pas par où commencer pour trouver une manière plus élégante de gérer ce type de structure (au lieu de la méthode de force brute que j'utilise pour l'instant).
import string
import math
letters = string.uppercase
num_players = 8
num_goals = 5
ratio = (3, 1)
prop_high = ratio[0] / float(sum(ratio)) / (float(num_goals)/2)
prop_low = ratio[1] / float(sum(ratio)) / (float(num_goals)/2)
if num_goals % 2 == 1:
is_odd = True
else:
is_odd = False
goals_high = []
goals_low = []
high = []
low = []
# Allocate the goals to the pool. Final result will be incorrect.
count = 0
for i in range(num_goals):
if count < num_goals/2: # High proportion
high.append(math.ceil(prop_high * num_players))
goals_high.append(letters[i])
else: # Low proportion
low.append(math.ceil(prop_low * num_players))
goals_low.append(letters[i])
count += 1
# Make adjustments to the pool allocations to account for rounding and odd numbers
ratio_high_total = len(high)/float(num_players)
overall_ratio = ratio[1]/float(sum(ratio))
marker = (num_players / 2) + 1
offset = num_goals - marker
if num_players == num_goals:
for i in high:
high[int(i)] -= 1
elif num_goals == 1:
low[0] = num_players
elif ratio_high_total == overall_ratio and is_odd:
high[-1] -= 1
elif ratio_high_total >= overall_ratio: # Upper half of possible goals
print offset
for i in range(offset):
index = -(int(i) + 1)
high[index] -= 1
goals = goals_high + goals_low
goals_quantities = high + low
print "Players:", num_players
print "Types of goals:", num_goals
print "Total goals in pool:", sum(goals_quantities)
print "High pool:", goals_high, high
print "Low pool:", goals_low, low
print goals, goals_quantities
print "High proportion:", prop_high, " || Low proportion:", prop_low