罗兰谈MATLAB的艺术

将想法转化为MATLAB

优化生存

今天的客座博主是Mary Fenelon,她是MathWorks的优化和数学产品营销经理。在今天的文章中,她描述了她如何使用优化来努力使产品营销团队的其他成员做到最好。

美国国家橄榄球联盟2018赛季即将拉开帷幕。我们MathWorks的产品营销团队中有几个人在过去几年里参加了办公室联赛。我不是很关注NFL,所以我没有想过要参加,直到我的一位产品营销经理同事向我提出挑战,说这看起来像是一个优化问题。这就够了!

内容

规则

  1. 这是一个击倒或幸存者风格的池。每周,你的目标是在一场比赛中选出获胜的队伍。整个赛季你只能选择一支球队。如果你的队伍赢了或打平了,你就可以进入下一周,从剩下的队伍中挑选。只要你没有选择输球的球队,你就可以从整个NFL球队中选择。
  2. 如果你选了一支输掉比赛的队伍,你还没有被淘汰出局。你现在只能从上赛季战绩不佳的球队中挑选。你可以试着保持你的连胜,但现在你必须用更有限的团队来做到这一点。
  3. 谁活得最久谁就赢得淘汰赛。你保持淘汰赛的时间越长淘汰赛的机会就越大。它将从池的50%开始,并继续增长。这个罐子会越来越大,直到最后一个人损失两次为止。如果两人或两人以上打平,他们将平分奖金,或者在停车场比拼最终赢家。
  4. 在你第二次失败后,你仍然可以赢得第二池,即在整个赛季中选出最多赢家的人。一旦你输了两次,你就可以回去选择任何球队,只要你还没有选过他们。无论谁赢得淘汰赛都没有资格获得这个奖项,除非有不可预见的情况(例如,如果每个人都在第2周被淘汰)。

我的策略

我可以每周选择一个团队,而不考虑选择更远的团队会更好。这种短视的策略可能会让我在赛季结束时做出糟糕的选择。相反,我的第一个策略决策是每周运行一次优化,为本赛季剩余的所有周选择球队,但只使用当前周的选择。这样,随着赛季的进展,我可以从更新的信息中受益,同时还能看到整个赛程。

提出一组选择可以被建模为一个线性分配问题.分配问题的目标是将工作人员分配到任务中,以使完成所有任务的成本最小化。每个工人只能做一项任务。对于NFL来说,工作人员是团队,任务是周。

每个团队每周任务的成本使用什么?这个选择是建模的艺术和科学发挥作用的第二个地方。艺术是考虑度量,而科学是验证所选择的度量能给出预期的结果。我的选择是使用fivethirtyeight.com这篇文章解释了他们如何利用NFL的整个历史作为数据来建立预测模型。通过这种方法,目标是最大化所选球队在整个赛季中的获胜概率之和。

线性指派问题可以用匈牙利算法这个实现在MATLAB文件交换是一个流行的。这些问题也可以通过中的函数来解决优化工具箱.将问题表述为优化问题,让我可以选择指定额外的约束条件,例如,遵循这样的规则:在一次损失后,我被限制从损失方中进行选择。

数据

赛季的数据

在这篇文章中,我将生成一些数据,而不是使用实际的NFL数据。我会用一半的球队和一半的比赛。

nSeasonWeeks = 8;队伍= [“豚”“蝙蝠”“猎豹”“龙”“鸸鹋”“狐狸”“长颈鹿”“河马”“野山羊”“野狗”...“考拉”“狐猴”“猴子”“蝾螈”“水獭”“豪猪”]“;nTeams = number (teams);

在失败者组中,从上个赛季中选出一些失败者。设置随机种子以在每次运行脚本时重新生成相同的括号。

rng (19);nLosers =楼层(nTeams/2);idx = randperm(nTeams);输家=队伍(idx(1: nloser));

每周的数据

我将每周重新运行这个模型,跟踪赛季中的那一周以及我已经选择了哪些球队。

每一周我都增加一周计数器。

本周= 2;

每周我都会添加前一周选择的团队

previousPicks = [“豚”];

为剩下的几周生成标签:

周=“周”+字符串(这个星期:nSeasonWeeks) ';nWeeksLeft = nSeasonWeeks -本周+ 1;

得到概率。

在这里,我会从网页上抓取预测。相反,我将使用一个随机矩阵来表示获胜概率。随机值不会显示在真实数据中看到的模式,但它们足以显示如何建立和运行优化模型。实现更现实的概率的一个步骤是首先生成游戏的团队配对和游戏时间表。这本身就是一个优化问题;有关示例,请参见安排ACC篮球会议

winProbs = rand(nTeams,nWeeksLeft);

线性分配模型

我将使用具体问题具体分析工作流R2017b中引入的优化。该工作流简化了指定和求解线性和混合整数线性程序的过程,即具有线性约束和目标以及具有连续或离散值的变量的优化问题。

变量

首先,定义二维空间optimvarx,以团队和周为索引。优化求解器将计算an的值optimvar包括在optimproblem.我让它成为一个二进制变量,它是一个只取值为0和1的变量:

X = optimvar(“x”、团队周,下界的0,“UpperBound”, 1“类型”“整数”);

在我的模型中,值为1x (i, j)就意味着这个团队被选为一周j值为0表示它未被选中。

为了消除已经被选中的球队,将这些球队对应的变量的上界设置为0。

x.UpperBound(previousPicks,weeks) = 0;

优化问题与目标

接下来,定义优化问题和目标,以最大化所选团队的获胜概率之和:

P = optimproblem;p.ObjectiveSense =“最大化”;p.Objective = sum(sum(winProbs.*x));

约束

第一个约束语句为每个团队生成一个约束:一个团队最多只能被选择一次。结果是optimconstr.显示每个集合的第一个约束,以检查公式的构建。

p.Constraints.eachTeamAtMostOnce = sum(x,2) <= 1;showconstr (p.Constraints.eachTeamAtMostOnce (1))
x(“豚”,“week2”)+ x(“豚”,“week3”)+ x(“豚”,“week4”)+ x(“豚”,“week5”)+ x(“豚”,“week6”)+ x(“豚”,“week7”)+ x(“豚”,“week8”)< = 1

第二个约束语句为每周生成一个约束:必须选择一个团队。

p.Constraints.mustPickOne = sum(x,1) == 1;showconstr (p.Constraints.mustPickOne (1))
x(“豚”,“week2”)+ x(“蝙蝠”、“week2”)+ x(‘猎豹’,‘week2) + x(‘龙’,‘week2) + x(鸸鹋,week2) + x(“狐狸”、“week2”)+ x(“长颈鹿”、“week2”)+ x(“河马”,“week2”)+ x(“野山羊”、“week2”)+ x(“豺”、“week2”)+ x(“考拉”,“week2”)+ x(“狐猴”、“week2”)+ x(‘猴子’,‘week2) + x(蝾螈,week2) + x(“水獭”、“week2”)+ x(“豪猪”、“week2”)= = 1

解决

现在求解最优化问题。的解决函数将调用混合整数线性规划求解器,intlinprog,| b|,因为一些优化变量是整数类型

Soln = solve(p);
LP:最佳目标值为-6.661074。找到最优解。Intlinprog停止在根节点,因为目标值在最佳值的间隙公差范围内,选项。AbsoluteGapTolerance = 0(默认值)。intcon变量是公差范围内的整数,选项。IntegerTolerance = 1e-05(默认值)。

汇总的选择

“优化工具箱”求解器使用浮点算法,因此解值可能不是整数。我想使用这些值作为逻辑索引,所以我将它们四舍五入,以确保它们是。

pick = round(soln.x);[teampicks,weekpicks] = find(picks);Probpicks = find(选择);表(周(weekpicks),团队(teampicks) winProbs (probpicks),...“VariableNames”, {“周”“团队”“WinProb”})
ans = 7×3 table Week Team WinProb _______ _________ _______ "week2" "狐狸" 0.94616 "week3" "狐猴" 0.9943 "week4" "蝙蝠" 0.97137 "week5" "考拉" 0.99744 "week6" "龙" 0.91183 "week7" "野山羊" 0.98344 "week8" "河马" 0.85654

扩展模型

随着赛季的进展,获胜概率将根据之前比赛的结果进行更新。也许我不想把赛季结束的可能性看得和本周一样高。这可以通过应用贴现因子来实现。在生活的脚本在这篇文章的版本中,我设置了折扣因子现场控制为了便于对不同的值进行实验。

scalePerWeek = (1-discountFactor).^(0: nweeklefft -1);dProbs = winProbs.*scalePerWeek;p.Objective = sum(sum(x.*dProbs));Soln = solve(p);[teampicks,weekpicks] = find(picks);Probpicks = find(选择);表(周(weekpicks),团队(teampicks) winProbs (probpicks),...“VariableNames”, {“周”“团队”“WinProb”})
LP:最佳客观值为-5.755877。找到最优解。Intlinprog停止在根节点,因为目标值在最佳值的间隙公差范围内,选项。AbsoluteGapTolerance = 0(默认值)。intcon变量是公差范围内的整数,选项。IntegerTolerance = 1e-05(默认值)。ans = 7×3 table Week Team WinProb _______ _________ _______ "week2" "狐狸" 0.94616 "week3" "狐猴" 0.9943 "week4" "蝙蝠" 0.97137 "week5" "考拉" 0.99744 "week6" "龙" 0.91183 "week7" "野山羊" 0.98344 "week8" "河马" 0.85654

应用5%的折现因子并没有改变结果。

我可能只会在没有损失的情况下选择获胜的球队这样我就可以在失败的球队中选择最好的。

onlyWinners = false;如果约束。onlyWinners = sum(x(输家,周),1)== 0;结束

输了一场,我必须从输家组中挑选。

onlyloser = true;如果p.Constraints.onlyLosers = sum(x(losers,weeks),1) >= 1;showconstr (p.Constraints.onlyLosers (1))结束
x(“豚”,“week2”)+ x(‘猎豹’,‘week2) + x(‘龙’,‘week2) + x(鸸鹋,week2) + x(“狐狸”、“week2”)+ x(“考拉”,“week2”)+ x(蝾螈,week2) + x(“水獭”、“week2”)> = 1
Soln = solve(p);[teampicks,weekpicks] = find(picks);Probpicks = find(选择);表(周(weekpicks),团队(teampicks) winProbs (probpicks),...“VariableNames”, {“周”“团队”“WinProb”})
LP:最佳目标值为-4.838951。找到最优解。Intlinprog停止在根节点,因为目标值在最佳值的间隙公差范围内,选项。AbsoluteGapTolerance = 0(默认值)。intcon变量是公差范围内的整数,选项。IntegerTolerance = 1e-05(默认值)。ans = 7×3 table Week Team WinProb _______ _________ _______ "week2" "狐狸" 0.94616 "week3" "狐猴" 0.9943 "week4" "蝙蝠" 0.97137 "week5" "考拉" 0.99744 "week6" "龙" 0.91183 "week7" "野山羊" 0.98344 "week8" "河马" 0.85654

结果

我做得怎么样?在这两年里,我都很早就被淘汰了,但在第二梯队中名列前茅。

不幸的是,有一名球员在这两年都没有损失,所以没有二级池奖。该玩家没有透露他的策略,但有人猜测他使用了优化模型。一位只输了一场比赛的球员透露了他的策略:每周从fivethirtyeight.com网站上挑选最好的球队。这是我不想用的短视策略!不过我明白为什么这么做是有道理的。球队数量大约是比赛数量的两倍,所以只要你能从整个联盟中选择,每周都应该有一些不错的选择。当预测在赛季中发生变化时,贪婪策略也是有意义的。

我不愿意放弃在二级池中取得好成绩,所以我会保持我的分配模型。我可以用更高的折现因子让它更贪婪。也许我还应该通过使用来自多个来源的数据或使用随机优化方法来处理概率中的不确定性。现在我有了两年的数据,在决定今年的策略之前,我可以做一些模型验证。是时候忙碌起来了!

你有更好的方法吗?让我们知道你的想法在这里




发布与MATLAB®R2018a

|
  • 打印
  • 发送电子邮件

评论

如欲留言,请点击在这里登录您的MathWorks帐户或创建一个新帐户。