如何将OR条件纳入纸浆优化问题



我正试图建立一支幻想团队,目标是根据受某些约束的单个玩家的期望值,最大限度地提高其总期望值
这是我的代码的相关部分:

players = [player for player in input_dict]
prices = {player: input_dict[player]['price'] for player in players}
player_teams = {player: input_dict[player]['team'] for player in players}
player_positions = {player: input_dict[player]['position'] for player in players}
points = {player: input_dict[player]['expected_points'] for player in players}
league_teams = list(set(team for team in player_teams.values()))
prob = LpProblem('Fantasy_team', LpMaximize)
player_var = LpVariable.dicts('Players', players, 0, 1, cat='Integer')
# maximize points
prob += lpSum([player_var[player] * points[player] for player in players])
# number of players to be selected
prob += lpSum([player_var[player] for player in players]) == 11 
# max budget
prob += lpSum([player_var[player] * prices[player] for player in players]) <= 100
# position constraints
prob += lpSum([player_var[player] for player in players if player_positions[player] == 'goalkeeper']) == 1
prob += lpSum([player_var[player] for player in players if player_positions[player] == 'defender']) >= 2
prob += lpSum([player_var[player] for player in players if player_positions[player] == 'defender']) <= 5
prob += lpSum([player_var[player] for player in players if player_positions[player] == 'midfielder']) >= 2
prob += lpSum([player_var[player] for player in players if player_positions[player] == 'midfielder']) <= 5
prob += lpSum([player_var[player] for player in players if player_positions[player] == 'forward']) >= 0
prob += lpSum([player_var[player] for player in players if player_positions[player] == 'forward']) <= 3
# max players from one team
for league_team in league_teams:
team_players = []
for player, lp_var in player_var.items():
if player_teams[player] == league_team:
team_players.append(lp_var)
prob += lpSum(team_players) <= 3

然而,如果我想增加一个额外的限制:一支球队的最低防守队员(或任何其他位置(=2。换句话说,至少有两名后卫必须来自同一支球队。

在我看来,需要另一个决策变量,但我不明白应该如何做到这一点。

编辑:

我取得了一些进步,但现在我陷入了这个错误。显然Pulp对max函数不满意。有什么办法绕过这个吗?

positions = ['defender',]
team_hires = LpVariable.dicts('count', (positions, league_teams), cat='Integer')
for league_team in league_teams:
player_vars = []
for player in player_var:
if player_teams[player] == league_team:
player_vars.append(player_var[player])
team_hires['defender'].update({league_team: lpSum(player_vars)})
prob += max([team_hires['defender'][team] for team in league_teams]) >= 2
TypeError: '>' not supported between instances of 'LpAffineExpression' and 'LpAffineExpression'

我需要重新发布这个答案,因为我之前的答案(已删除(令人困惑,我想我把你引入了歧途。。。

为了编写一个约束条件,迫使至少一个团队支持每个职位的最低招聘人数,您需要能够对团队进行迭代(因此您需要一组团队(,并且需要能够对具有最低招聘约束的职位进行迭代。下面的例子用一个";"多选";约束是一个二进制变量,它意味着源团队正在支持某个特定职位的最低招聘人数。因此,如果一个特定的团队是";选择";通过求解器来支持最小雇佣;1〃;然后该团队的雇佣人数必须大于最低要求(这是约束的第一部分(。第二部分是,您必须强制所有团队的变量之和至少为1,以确保至少有一个团队被迫支持该需求。这是约束的第二部分。

请注意,如果您将决策变量更改为三重索引[player,pos,source_team],那么语法可能会更干净一些,但这仍然可以正常工作!

数据文件(Data.csv(

player,price,team,position,expected_points
bob,24,wolves,defender,2.1
sam,23,wolves,defender,2.4
tommy,20,wolves,forward,3.4
bill,20,wolves,forward,3.6
eddie,22,wolves,forward,3.1
tim,23,bears,defender,2.2
earl,23,bears,defender,1.0
dorf,24,bears,forward,3.5
bennie,30,bears,forward,3.6

型号

from pulp import *
import pandas as pd
df = pd.read_csv('data.csv')
df = df.set_index('player')
input_dict = df.to_dict('index')

players = [player for player in input_dict]
prices = {player: input_dict[player]['price'] for player in players}
player_teams = {player: input_dict[player]['team'] for player in players}
player_positions = {player: input_dict[player]['position'] for player in players}
points = {player: input_dict[player]['expected_points'] for player in players}
league_teams = list(set(team for team in player_teams.values()))
# min numbers per position
pos_mins = {'defender':2,
'forward':2}
# min numbers from single team by position
team_pos_mins = {'defender':2}   # must hire at least 2 defenders from same source team
positions = player_positions.values()
pos_team_combos = {(pos, team) for pos in positions for team in league_teams}
prob = LpProblem('Fantasy_team', LpMaximize)
hire = LpVariable.dicts('Players', players, cat='Binary')   # this is binary decision...
support_min_hires = LpVariable.dicts('team hires', pos_team_combos, cat='Binary')  # 1 if that team supports the min for position

# maximize points
prob += lpSum([hire[player] * points[player] for player in players])
# number of players to be selected
prob += lpSum([hire[player] for player in players]) == 4
# max budget
prob += lpSum([hire[player] * prices[player] for player in players]) <= 100
# position constraints
for pos in pos_mins:
# this pattern could be replicated for all of your max/mins
prob += lpSum(hire[player] for player in players if player_positions[player] == pos) >= pos_mins[pos]
# hires by team constraint
for pos in team_pos_mins:
# the min number hired from team must be greater than the requirement, if that team is selected to support the min...
for team in league_teams:
prob += lpSum(hire[player] for player in players 
if player_positions[player] == pos
and player_teams[player] == team) >= support_min_hires[pos, team] * team_pos_mins[pos]
# force at least one team to suppoprt the minimum hires
prob += lpSum(support_min_hires[pos,team] for team in league_teams) >= 1
#print(prob)
status = prob.solve()
print(status)
for p in players:
print(p, hire[p].value())
# for QA...
for pos in team_pos_mins:
for team in league_teams:
print(f'{team} covers min hires for {pos}:  {support_min_hires[pos,team].value()>0}')

结果

Result - Optimal solution found
Objective value:                11.70000000
Enumerated nodes:               0
Total iterations:               0
Time (CPU seconds):             0.00
Time (Wallclock seconds):       0.00
Option for printingOptions changed from normal to all
Total time (CPU seconds):       0.00   (Wallclock seconds):       0.01
1
bob 1.0
sam 1.0
tommy 0.0
bill 1.0
eddie 0.0
tim 0.0
earl 0.0
dorf 0.0
bennie 1.0
wolves covers min hires for defender:  True
bears covers min hires for defender:  False
[Finished in 0.9s]

最新更新