Reputation: 115
The Problem
I am using lpSolve to find the optimal lineup for a fantasy baseball team - a knapsack problem involving the price SALARY
and projected points DK
of each player PLAYERID
within the given constraints of the contest.
The current code works great, but I have a constraint I would like to add that I can't quite figure out. The new constraint is to not have any players in the lineup facing one of the pitchers SP
in the same lineup.
What I Have So Far
I created a column called MNBT
(Must Not Be Together) which defines the opposing pitcher's PLAYERID
that must not be found in the same lineup as each player, but I am stuck there. The first 20 rows of the data.frame slate_players
are as follows (I can provide all 91 rows for this specific contest if needed):
PLAYERID POS TEAM OPP SALARY DK TEAM_O MNBT
1 37584 SP LAD OAK 10000 18.42 0SP 13170
2 11292 SP TEX HOU 9300 18.41 0SP 1452665
3 1452665 SP HOU TEX 7400 15.22 0SP 11292
4 11168 SP BAL BOS 6900 9.06 0SP 13502
5 13170 SP OAK LAD 6800 6.06 0SP 37584
6 13502 SP BOS BAL 6700 13.52 0SP 11168
7 2038873 SP KCR DET 6600 18.45 0SP 34649
8 34649 SP DET KCR 6500 7.46 0SP 2038873
9 11446 C KCR DET 5300 7.55 KCR 34649
10 1054004 C LAD OAK 5000 8.25 LAD 13170
11 15541 C BOS BAL 4500 7.08 BOS 11168
12 1252110 C OAK LAD 4100 5.07 OAK 37584
13 22667 C BAL BOS 3400 7.09 BAL 13502
14 10290 C TEX HOU 2900 4.08 TEX 1452665
15 13171 C DET KCR 2800 5.45 DET 2038873
16 17552 C HOU TEX 2600 4.47 HOU 11292
17 36727 1B LAD OAK 5800 9.09 LAD 13170
18 17648 1B LAD OAK 5400 8.57 LAD 13170
19 17887 1B OAK LAD 4900 7.30 OAK 37584
20 17851 1B KCR DET 4400 7.24 KCR 34649
[...]
The Current lpSolve Code
# count the unique players and teams on the slate
unique_teams = unique(slate_players$TEAM_O)
unique_players = unique(slate_players$PLAYERID)
# define the objective for the solver
obj = slate_players$DK
# create a constraint matrix for the solver
con = rbind(t(model.matrix(~ POS + 0, slate_players)), #Positions
t(model.matrix(~ PLAYERID + 0, slate_players)), #DupPlayers
t(model.matrix(~ TEAM_O + 0, slate_players)), #SameTeam
rep(1,nrow(slate_players)), #TotPlayers
slate_players$SALARY) #MaxSalary
# set the direction for each of the constraints
dir = c("==", #1B
"==", #2B
"==", #3B
"==", #C
"==", #OF
"==", #SP
"==", #SS
rep('<=',length(unique_players)), #DupPlayers
rep('<=',length(unique_teams)), #SameTeam
"==", #TotPlayers
"<=") #MaxSalary
# set the limits for the right-hand side of the constraints
rhs = c(1, #1B
1, #2B
1, #3B
1, #C
3, #OF
2, #SP
1, #SS
rep(1,length(unique_players)), #DupPlayers
rep(5,length(unique_teams)), #SameTeam
10, #TotPlayers
50000) #MaxSalary
# find the optimal solution using the solver
result = lp("max", obj, con, dir, rhs, all.bin = TRUE)
# create a table for the players that are in optimal solution
solindex = which(result$solution==1)
optsolution = slate_players[solindex,]
The Question
How do I code this new constraint? I have been doing these kinds of adjustments manually, but I would really appreciate it if there were a solution available to automate this process. Thank you!
Upvotes: 2
Views: 242
Reputation: 115
What I ended up doing, rather than a single MNBT
column, was creating a helper column for each individual pitcher SP
to indicate which hitters he may not appear in the optimal solution with. In these columns, I assigned a value for the pitcher of 5
and a value of 1
for each hitter he must not appear with. The constraint then became that the sum of each of these columns would be <=
5
. The logic is that a maximum of 5
hitters may be in the same lineup facing any individual pitcher, but if that same pitcher appeared in the optimal solution, none of the hitters he was facing would be.
Upvotes: 1
Reputation: 561
While this doesn't create the set of constraints for you, this example is of one of those constraints that @AirSquid mentioned might help.
In the example above, the 6th player (13502) could not play against the 13th player (22667).
Add to the constraint:
c(0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0)
Add to the directions:
"<="
Add to the right hand side:
1
The next trick is how to generate all of these sets of constraints in R. Cheerio.
Upvotes: 0