Search code examples
roptimizationsolverknapsack-problemlpsolve

R Team Roster constraint with lpsolve - must pick at least x players from Team


I'm having trouble trying to build on the foundation of a previous question

I'd like to optimize so there are at least 3 players from the same team, but I don't care which team it is.

In the code below I can brute-force it to pick 3 players from the Bears (or another team I specify). How would you go about picking the optimal roster with 3 players from the same team, any team?

library(Rglpk)
DF <- data.frame(Team=c(rep("Bears",5), rep("Jets",5), rep("49ers", 5)), Player=c("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"), Role=c(rep(c("WR", "RB", "TE"),5)), Avgpts=c(22, 19, 30, 25, 20, 21, 26, 14, 21, 13, 11, 8, 4, 3, 5), Salary=c(930, 900, 1300, 970, 910, 920, 980, 720, 650, 589, 111, 1239, 145, 560, 780))
obj = DF$Avgpts
con = rbind(as.numeric(DF$Role=="WR"), as.numeric(DF$Role=="RB"), as.numeric(DF$Role=="TE"), as.numeric(DF$Team == "Bears"), DF$Salary)
dir = c("==","==","==","==","<=")
rhs = c(1,1,1,3,100000)
sol <- Rglpk_solve_LP(obj = obj
                , mat = con
                , dir = dir
                , rhs = rhs
                , types = rep("B", length(DF$Team))
                , max=TRUE)

solution <- DF[sol$solution==1,]

Solution

  • Forgive me if I get some of the terms wrong, but here's the solution I ended coming up with. Each player is treated as a column and I also have a column for each team. I put in a dummy variable for each Team=Team equal to the minimum number of players I want on a single team.

    library("lpSolveAPI")
    DF <- data.frame(Team=c(rep("Bears",5), rep("Jets",5), rep("49ers", 5)), Player=c("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"), Role=c(rep(c("WR", "RB", "TE"),5)), Avgpts=c(22, 19, 30, 25, 20, 21, 26, 14, 21, 13, 11, 8, 4, 3, 5), Salary=c(930, 900, 1300, 970, 910, 920, 980, 720, 650, 589, 111, 1239, 145, 560, 780))
    
    ncol <- nrow(DF) # of players in DF
    nteams <- length(unique(DF$Team))
    teams <- unique(DF$Team)
    
    lp_rowpicker <- make.lp(ncol=(ncol+nteams))
    
    obj_vals <- DF[, "Avgpts"]
    set.objfn(lp_rowpicker, c(obj_vals, rep(0, nteams))) #dummy 0s for team variable
    lp.control(lp_rowpicker,sense='max')
    set.type(lp_rowpicker, columns=1:(ncol+nteams), type = "binary")
    add.constraint(lp_rowpicker, xt=c(DF$Salary, rep(0, nteams)), type="<=", rhs=35000)
    add.constraint(lp_rowpicker, xt=c(as.numeric(DF$Role=="WR"), rep(0, nteams)), type="=", rhs=1)
    add.constraint(lp_rowpicker, xt=c(as.numeric(DF$Role=="RB"), rep(0, nteams)), type="=", rhs=1)
    add.constraint(lp_rowpicker, xt=c(as.numeric(DF$Role=="TE"), rep(0, nteams)), type="=", rhs=1)
    

    I then set a constraint that the number of team columns set to one is equal to the total number of teams minus the number of teams I want in the optimal solution. In this case since I'm looking for 1 team out of the 3 in the dataframe, 2 teams will be set to 1 and the team that is set to 0 will require at least 3 players in order to meet the mininum constraint on the row level.

    #3 players total
    add.constraint(lp_rowpicker, xt=c(rep(1, ncol), rep(0, nteams)), type="=", rhs=3)
    
    # add a constraint that every team must have between 3 and 6 players.
    # put a dummy value of 3 in for each team
    # if the flag for the team column is 0 then 3 players must be selected (each with a value of 1 in that team's column.
    for (i in 1:nteams){
        team <- teams[i]
        add.constraint(lp_rowpicker, lhs=3, xt=c(as.numeric(DF$Team==team), rep(0, i-1), 3, rep(0, nteams-i)), type="<=", rhs=7)
    }
    
    # one team will not have the dummy value in the team column, forcing at     least 3 players picked from the same team to meet the lhs of the above constraint
    add.constraint(lp_rowpicker, xt=c(rep(0, ncol), rep(1, nteams)), type="=", rhs=(nteams-1))
    
    solve(lp_rowpicker)
    get.objective(lp_rowpicker)
    soln <- get.variables(lp_rowpicker)>0
    solution <- DF[soln[0:ncol],]
    print(solution[order(solution$Team),])