Python约束优化问题

2024-04-20 09:42:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在做一个梦幻足球项目,遇到了一个约束问题。幻想团队由1QB、2RBs、3WRs、1TE、1DEF和1FLEX组成(可以是RB、WR或TE)

我的输出是复制播放器。例如,如果John Doe担任RB职位,我需要他不要担任FLEX职位。我不知道如何完成这个约束。也许可以进行名称比较,以确保名称之间不相等

任何建议都将不胜感激

以下是一些示例数据:

| position | displayName         | Roster   | Position | salary | points |
|----------+---------------------+----------+----------+--------+--------|
| RB       | Christian McCaffrey | 15033483 | RB/FLEX  | 10000  | 30.95  |
| WR       | Michael Thomas      | 15033799 | WR/FLEX  | 9000   | 24.62  |
| QB       | Lamar Jackson       | 15033397 | QB       | 8100   | 29.85  |
| RB       | Dalvin Cook         | 15033485 | RB/FLEX  | 7900   | 21.62  |
# Set constraints
##################################################################
salaries = {}
points = {}

for pos in availables.position.unique():
    available_pos = availables[availables.position == pos]
    salary = list(available_pos[["displayName","salary"]].set_index("displayName").to_dict().values())[0]
    point = list(available_pos[["displayName","points"]].set_index("displayName").to_dict().values())[0]
    salaries[pos] = salary
    points[pos] = point

pos_num_available = {
    "QB": 1,
    "RB": 2,
    "WR": 3,
    "TE": 1,
    "FLEX": 1,
    "DST": 1
}


pos_flex = {
    "QB": 0,
    "RB": 1,
    "WR": 1,
    "TE": 1,
    "FLEX": 0,
    "DST": 0
}


pos_flex_available = 3
SALARY_CAP = 50000

_vars = {k: LpVariable.dict(k, v, cat="Binary") for k, v in points.items()}
##################################################################
# Problem Definition
##################################################################

prob = LpProblem("Fantasy", LpMaximize)
rewards = []
costs = []
position_constraints = []


for k, v in _vars.items():
     costs += lpSum([salaries[k][i] * _vars[k][i] for i in v])
     rewards += lpSum([points[k][i] * _vars[k][i] for i in v])
     prob += lpSum([_vars[k][i] for i in v]) <= pos_num_available[k]
     prob += lpSum([pos_flex[k] * _vars[k][i] for i in v]) <= pos_flex_available

prob += lpSum(rewards)
prob += lpSum(costs) <= SALARY_CAP
prob.solve()

Tags: inposforpositionvarswrpointsavailable
1条回答
网友
1楼 · 发布于 2024-04-20 09:42:18

为了便于阅读,我对您的代码进行了一些清理。结构完全相同,只是一些语法方面的东西

考虑如下:

import pulp as pl
import pandas as pd

availables = pd.DataFrame(
    [
        ["RB", "Christian McCaffrey", 15033483, "RB/FLEX", 10000, 30.95],
        ["WR", "Michael Thomas", 15033799, "WR/FLEX", 9000, 24.62],
        ["QB", "Lamar Jackson", 15033397, "QB", 8100, 29.85],
        ["RB", "Dalvin Cook", 15033485, "RB/FLEX", 7900, 21.62]
    ],
    columns=["position", "displayName", "Roster", "Position", "salary", "points"]
)

##################################################################
# Set constraints
##################################################################
salaries = {}
points = {}
players = {}

for position in availables.position.unique():
    available_for_position = availables[availables.position == position]
    players[position] = list(available_for_position.Roster.values)

    salaries[position] = {
        player_roster: salary for player_roster, salary in
        zip(players[position], available_for_position.salary.values)
    }
    points[position] = {
        player_roster: _points for player_roster, _points in
        zip(players[position], available_for_position.points.values)
    }

positions_available = {
    "QB": 1,
    "RB": 2,
    "WR": 3,
    "TE": 1,
    "FLEX": 1,
    "DST": 1
}

flexible_positions = ("RB", "WR", "TE")

SALARY_CAP = 50000

# Player variables['QB'][15033483] denotes whether Lamar Jackson is selected
variables = {position: pl.LpVariable.dict(position, players[position], cat="Binary")
             for position in players}

##################################################################
# Problem Definition
##################################################################

prob = pl.LpProblem("Fantasy", pl.LpMaximize)
rewards = []
costs = []
number_of_selected_players = []

for position, players in variables.items():
    for player, player_selected in players.items():
        # If this player is selected, he will add salaries and points
        costs += salaries[position][player] * player_selected
        rewards += points[position][player] * player_selected
        number_of_selected_players += player_selected

    # Of this position, if it does not support FLEX, at most `positions_available`
    # are supported. If it does support FLEX, increment that by
    # `flexible_positions_available`
    if position not in flexible_positions:
        prob += pl.lpSum(players.values()) == positions_available[position]
    else:
        # We need at least `positions_available` players on this position and at
        # most`positions_available + flexible_positions_available` players
        prob += pl.lpSum(players.values()) >= positions_available[position]
        prob += (pl.lpSum(players.values())
                          <= positions_available[position] + positions_available["FLEX"])

# In total, we need exactly `positions_available` players
prob += pl.lpSum(number_of_selected_players) == sum(positions_available.values())

prob += pl.lpSum(rewards)
prob += pl.lpSum(costs) <= SALARY_CAP
prob.solve()

您可以跟踪每个玩家是否被选中。然后,您最多允许positions_available个玩家处于该位置,除非是“灵活”位置,否则您允许positions_availablepositions_available + positions_available['FLEX']之间的玩家

因为您总共需要9名玩家,所以问题的唯一自由度是选择一名灵活玩家来填补最后的灵活位置

相关问题 更多 >