Using multiple data sets to balance teams in Python?

Viewed 152

I am new to coding so please forgive if I overlook anything simple. I am writing a program to make four teams of four. Each player has a certain point value for 11 different categories (eg. speed, agility, strength, etc.). I know I could average these categories together and just balance off that, but that leaves some teams wildly unbalanced in certain categories.

I have a separate program that takes in one set of point values, iterates through all possible combinations of teams, and returns the set for which the teams have the lowest standard deviation. I have also written some code myself that calculates the difference between each the average score for each category and that player's score for that category to get each player's point differential for each category.

However, I do not know how to use this data to get what I want: teams balanced off each category. I assume the best way to do this would be, for each team, minimizing the sum of the absolute values of each team's collective point differential. I have included a simplification of my code below:

d1_game1 = player1_points - average_points # this is repeated for each player and each game
game1Differentials = [d1_game1, d2_game1, d3_game1, ..., d16_game1] # There are 11 of these, one for each category
team1Differential = sum(abs([game1Differentials, game2Differentials, ..., game11Differentials]))

This team1Differential value is what is tripping me up; how do I take player differentials and convert them to team differentials? Would I have to try every combination of players?

values_to_minimize = [team1Differential, team2Differential, team3Differential, team4Differential]

I assume that this approach combined with the function from the code I linked above is almost all the way there, but how could this be applied to multiple metrics? I feel that it is a simple option that I am overlooking. This problem has been stopping me for days and I would really appreciate any help. Also if I am looking at this the wrong way and there is an easier method to get what I want, please let me know.

1 Answers

The problem you're having here is that you're calculating your differential from all players, when the actual operation is a 16-choose-4 operation. Therefore, your actual optimization function looks like this:

team1_players = random.sample(players, 4)
skill_1_differential = sum(abs(x.skill_1 - average_skill_1) for x in team1_players)
team_1_differential = sum([skill_1_differential, ..., skill_11_differential])

and then you'll repeat this for each of the remaining teams. You'll have to be careful to "remove" players from the pool before calling random.sample between the calculation for each team because if you don't you might wind up with the same player on multiple teams. Once you have all of these then you can sum them up:

balance = team_1_differential + team_2_differential + team_3_differential + team_4_differential

which will give you a balance paramter. From here, there are a number of ways you could handle this:

  • The simplest would be to calculate all possible team combinations but as there are 63,063,000 unique combinations, you'll be waiting for a very long time.
  • You could use a stochastic algorithm, such as simulated annealing to choose the team assignments that reduce the balance score closest to zero. This will give you a good, but not perfect, balance in a reasonable time.
  • You could modify how your players are created so that any combination of four players is approximately balanced. This is the easiest but if you don't have control over the creation process then this won't work.
  • You could choose teams at random and have them play actual games, giving the players a score that is increased when they win and decreased when the lose. After doing this, you will easily be able to create balanced teams by choosing players with similar scores or scores that balance out. This will still be a knapsack problem, but a much easier one because you'll be balancing on one variable instead of eleven. For more information, see this question. It looks like Sabermetrics or Elo could be useful here as well.
Related