Reputation: 83
I am running a tournament for 16 people, and each tournament, every person earns a certain number of points. These points are earned from 8 different games.
I need to make four teams of four, and their averages and standard deviations should ideally be as close together as possible (to make the fairest teams). I have already done this using a binpacking library. However, I have read that the knapsack problem is often better than binpacking at picking teams.
Ideally, I would be able to select one of the 8 games to balance points off of and obtain fair teams from that; right now I am just using overall points.
If anybody knows of any libraries or functions I can borrow to complete this task, please let me know. Additionally, if there are ways I can further optimize my code, please tell– I am still a beginner. My code is below.
import numpy as np
levels = np.genfromtxt('points.txt', dtype = 'float')
players = np.genfromtxt('players.txt', dtype = 'str')
playerLevels = zip(players, levels)
playerLevelsList = list(playerLevels)
averageLevels = sum(levels)/len(levels)
print('Average points are', averageLevels)
bins = binpacking.to_constant_bin_number(playerLevelsList, 4, 1)
a, b, c, d = [ [individualArray] for individualArray in bins]
a = a[0]
b = b[0]
c = c[0]
d = d[0]
a1 = a[1]
b1 = b[1]
c1 = c[1]
d1 = d[1]
team1 = list(zip(*a))
team2 = list(zip(*b))
team3 = list(zip(*c))
team4 = list(zip(*d))
points1 = sum(team1[1])/4
points2 = sum(team2[1])/4
points3 = sum(team3[1])/4
points4 = sum(team4[1])/4
stdev1 = np.std(team1[1])
stdev2 = np.std(team2[1])
stdev3 = np.std(team3[1])
stdev4 = np.std(team4[1])
print('Team 1 is', team1[0])
print('Team 2 is', team2[0])
print('Team 3 is', team3[0])
print('Team 4 is', team4[0])
print('\n-----Stats-----')
print('Team 1 Average is', points1, 'with a standard deviation of', stdev1)
print('Team 2 Average is', points2, 'with a standard deviation of', stdev2)
print('Team 3 Average is', points3, 'with a standard deviation of', stdev3)
print('Team 4 Average is', points4, 'with a standard deviation of', stdev4)```
Upvotes: 1
Views: 428
Reputation: 196
This may be a start to your answer. This was interesting and I had some time to kill. I was curious just how many unique team combinations are possible. Using an online combinations and permutations calculator I found out there are only 1820 unique teams possible when selecting 4 from 16 when order is not important. Using Python I generated a list of possible unique teams.
import matplotlib.pyplot as plt
import itertools as it
team_score_total=[]
teams = []
players=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
for i in it.combinations(players, 4):
teams.append(list(i))
# only 1,820 unique team possibilities
print(len(teams))
#check if there are duplicate players before adding to league
def CanAddTeamLeague(team, league):
for t in league:
for i in t:
if i in team:
return False
return True;
#check if there are duplicate leagues before adding to list
def CanAddLeagueToList(league, league_list):
for lg_list in league_list:
count=0
for t1 in lg_list:
for t2 in league:
if t1 == t2:
count+=1
if count ==4:
return False
return True;
unique_league_list = []
for i in range(len(teams)):
league = []
league.append(teams[i])
for t in teams:
if CanAddTeamLeague(t,league):
if len(league) < 4:
league.append(t)
if len(league) == 4:
if CanAddLeagueToList(league,unique_league_list):
unique_league_list.append(league)
print(len(unique_league_list))
for l in unique_league_list:
print(l)
# for i in teams:
# print(i)
# for t in teams:
# team_score_total.append(scores[t[0]]+scores[t[1]]+scores[t[2]]+scores[t[3]])
# fig, ax = plt.subplots(figsize=(20, 12))
# plt.plot(range(len(teams)),team_score_total)
This got me to wondering just how many truly unique leagues of 4 teams are possible. I think the answer is 1715. I switched to Java to figure this out and it took 24 seconds on my machine for the code to eliminate duplicate possibilities. I don't think I have the math skills to calculate that with combinations/permutations (but somebody does). Having said that, 1715 is not a huge number to deal with for brute force methods and I don't think it would take much time to calculate the stats for each team.
Here is the final piece. I put this in another cell so you don't have to recalculate the time consuming part every time.
import numpy as np
scores=[7,11,20,21,22,12,13,14,15,16,23,18,19,17,24,10]
league_score_list = []
for league in unique_league_list:
league_score=[]
for team in league:
team_score=0
for ts in range(4):
team_score += scores[team[ts]]
league_score.append(team_score)
league_score_list.append(league_score)
std_list=[]
for l in league_score_list:
std_list.append(np.std(l))
sorted_list = np.argsort(std_list)
print(league_score_list[sorted_list[0]])
print(unique_league_list[sorted_list[0]])
Upvotes: 1