如何在PuLP优化器中限制球员变量仅出现一次
解决PuLP梦幻足球优化器中球员重复选中的问题
我正在跟着一篇教程制作PuLP优化器(感谢Branko Blagojevic的出色工作!),但教程存在一个问题:最终输出会重复选中同一球员(比如DeSean Jackson同时出现在FLEX和WR位置——这是规则不允许的,每个位置必须是唯一球员)。我的问题是:如何确保FLEX位置的球员与其他所有位置的球员不重复?我知道有类似问题,但它们的结构和我的不完全匹配。
我已尝试的方法
曾考虑在设置奖励时,一旦球员被选入最优解就从
_vars字典中删除该球员,代码如下:del _vars['__player__']但随后意识到优化求解并非像设置奖励那样的迭代过程,因此该方法无效。
之后想到可以添加约束来确保每个球员仅出现一次,尝试的代码如下:
# _vars 的定义方式 _vars = {k: LpVariable.dict(k, v, cat="Binary") for k, v in points.items()} current = current.set_index(['displayName','position']) pairs = current.index # 格式为 (name, pos) 的元组 name_set = current.index.unique(0) # 设置奖励项 for k, v in _vars.items(): costs += pulp.lpSum([salaries[k][i] * _vars[k][i] for i in v]) rewards += pulp.lpSum([points[k][i] * _vars[k][i] for i in v]) prob += pulp.lpSum([_vars[k][i] for i in v]) <= pos_num_available[k] # 我认为正确的思路应该类似这样 for name in name_set: prob += pulp.lpSum([_vars[n, p] for (n, p) in pairs if n == name]) <=1 prob += pulp.lpSum(rewards) prob += pulp.lpSum(costs) <= SALARY_CAP但没能成功实现——我觉得需要调整
pairs使其匹配_vars的结构?无论如何,我确信添加约束让每个球员仅出现一次是正确的思路,只是需要帮助完成该约束的编写。
正确的约束实现方案
你的思路完全正确:必须添加每个球员只能被选中一次的约束。之前的问题在于_vars的结构是按位置分组(键是位置字符串,比如'WR'、'FLEX'),而非(球员名, 位置)元组,所以_vars[n, p]的写法不匹配变量结构。
下面是可行的实现代码:
# 第一步:构建球员到所属位置的映射字典 player_pos_map = {} # 遍历所有位置(比如WR、RB、FLEX等) for position in points.keys(): # 遍历当前位置下的所有球员 for player_name in points[position].keys(): if player_name not in player_pos_map: player_pos_map[player_name] = [] # 记录该球员所属的位置(可能多个,比如WR和FLEX) player_pos_map[player_name].append(position) # 第二步:添加每个球员只能被选中一次的约束 for player_name, positions in player_pos_map.items(): # 收集该球员在所有可选位置中的二进制变量 selected_vars = [] for pos in positions: # 从对应位置的变量组中取出该球员的变量 if player_name in _vars[pos]: selected_vars.append(_vars[pos][player_name]) # 设置约束:该球员被选中的总次数 ≤1 prob += pulp.lpSum(selected_vars) <= 1
代码说明
- 构建球员位置映射:先遍历所有位置和球员,记录每个球员可以被选入的所有位置(比如部分球员同时属于WR和FLEX池)。
- 添加唯一性约束:对每个球员,把他在各个位置对应的二进制变量求和,约束总和不超过1,这样就彻底避免了同一球员被重复选中到不同位置的情况。
把这段代码添加到你现有逻辑中(在设置完位置数量约束之后,目标函数之前即可),就能解决重复选人的问题。
内容的提问来源于stack exchange,提问作者bismo
相关产品推荐
相关产品推荐

