风险控制下的比赛顺序决策模型
摘要 本文围绕"五羽轮比"比赛的出场顺序决策问题进行讨论,建立了基于蒙特卡洛模拟和博弈论均衡的两个决策模型。利用蒙特卡洛方法、Nash均衡等知识分别建立决策模型,为在这一特殊形式的比赛中排兵布阵提供了建议,并深入地分析了模型的优点与缺点,提...
摘要 本文围绕”五羽轮比”比赛的出场顺序决策问题进行讨论,建立了基于蒙特卡洛模拟和博弈论均衡的两个决策模型。利用蒙特卡洛方法、Nash均衡等知识分别建立决策模型,为在这一特殊形式的比赛中排兵布阵提供了建议,并深入地分析了模型的优点与缺点,提出了改善的方向。
针对问题一,题目给出过往比赛中两支队伍不同二联选手组合之间对战结果的不完整数据。利用这些数据,基于蒙特卡洛方法,可以得出胜率矩阵,作为相对二联实力的量化展示。在已知对方出场顺序的情况下,可以搭建起一个蒙特卡洛模拟模型,找出获胜的最优顺序解。最终得到的计算结果是一个”富足”的混合策略解。为了达到优中选优的效果,引入了时间风险概念。在不牺牲混合策略获胜概率的前提下,选择能以较少局数结束游戏的方案。得出的最后的结果是。
针对问题二,双方位置发生互换,对方在已知己方出场顺序的基础上排兵布阵。利用在解决问题一时搭建的蒙特卡洛模拟模型,求出了对方所有策略中相对最占优的三种策略,由优到次分别是:、和。此时针对对手的这三种策略,假设其发生可能性相同,利用蒙特卡洛模拟模型反过来求己方的最优顺序解,结果是。
针对问题三,发现决策者处于”局中人”的位置,双方的策略设计都建立在无法知晓对方策略的基础上,因此引入博弈论知识,建立博弈论均衡模型。利用数据处理阶段的胜率矩阵,借助格雷码的理念实现完全穷举,创建出反映双方使用任意人员安排与出场顺序的策略胜率矩阵,利用相关数学知识寻找到了矩阵的Nash均衡点,通过一定的数据处理分析,最终根据题目要求得到己方和对方的均衡顺序解,分别是:和。使用这样的策略时,双方有稳定的与对方出场顺序无关的己方出场顺序。
文末先对模型的准确性和敏感性进行测试,得出模型具有一定的稳定性的结论,但是由于模拟方法本身的局限性,最后的结果并不完全准确。对两个子模型分别做出了评价,然后分析了其在现实生活中的可行性以及局限性,最后为读者在现实生活中如何灵活使用这两个子模型提出了建议,并且对如何基于现实再次完善我们的比赛顺序决策模型进行了思考,尤其是动态因素会怎么影响本文涉及模型的实时使用。
问题重述
问题背景
先谋后事者昌,先事后谋者亡。通过好的策略,决策者可以扬长避短,获得胜利,这一点在群体类的体育活动中展现得淋漓尽致。在比赛”五羽轮比”中,除了选手的自身实力以外,队伍排兵布阵的顺序也发挥着关键的作用。每个队伍有五名队员,比赛采用50分制,率先获得50分的队伍胜出(即使出现49:49时也无需领先两分致胜)。每局比赛任意一方先得10n(n=1,2,3,4)分时,双方换下一位队员,后得10n分的一方不再换人。双方确定出场人员后,在对抗的过程中不允许更改出场顺序。己方队友的编号分别为对方成员的编号分别为。
- 问题提出
问题一:在已知己方五位选手和对方五位选手的部分历史对抗数据的情况下,试根据对方已知的出场顺序,找出己方的最优出场顺序解。
问题二:在已知己方五位选手和对方五位选手的部分历史对抗数据的情况下,如果己方的出场顺序为,求出对方胜率最高的三种出场顺序,并计算假设对方采取这三种中的一种,己方的最优出场顺序解。
问题三:己方和对方分别新增选手和,并且已知这两位选手部分历史对抗数据。两组在六人中选择五人按照一定顺序出战,试求双方是否存在不受对方策略影响的均衡策略。如果有,给出均衡策略;如果没有,给出己方的占优策略。
- 问题分析
由于每有一个特定的二人组率先获得10分就要换人,全局游戏获得50分胜利的目标可以抽象为要获得5次单位胜利,获得单位胜利的要求为率先获得10分。三个问题对应的获胜条件都可以进行相同的简化。
问题一: 对方的出场顺序已经确定,我们对应的出场顺序有5!=120种。根据游戏规则与题目要求,我们只需要找出其中己方最快得到50分的一种,就能够得出了我们的最终答案。
问题二: 己方的出场顺序已经确定,对方对应的出场顺序有5!=120种。根据游戏规则与题目要求,我们只需要找出其中对方最快得到50分的三种,再根据这三种对方可能选取的方案,分别由第一题的模型得出己方的最优策略。
问题三:探究双方是否存在稳定的与对方出场顺序无关的己方出场顺序,题目与前两问出现了本质上的不同,因为此时决策者的决定还要考虑他人的尚未做出的决策,需要利用博弈论的知识。问题本质上是在寻找一个博弈论中”均衡”状态,在这种状态下,双方的决策都不会因为对方的决策改变而变得更差或更好。并不是每一场博弈都存在均衡,均衡也不一定同时存在于双方的决策空间中。如果均衡不存在,那么按照题目的要求,我们应该求出占优策略。此时哪怕找不到均衡,我们依然可以通过排除劣势策略和选择优势策略的方法缩小双方可以选择的策略的范围,求出最理想的方案。
模型假设与符号说明
模型假设
(1)双方对抗的部分历史数据可以真实地反映选手的水平,忽略偶然因素的影响。
(2)选手在场上按照自身水平稳定发挥,既不超常发挥,也不失常发挥。
(3)没有交手数据的组合获胜概率均设置为0.5。因为双打比赛不仅是对个人能力的体现,更与同台两人的默契程度密不可分,所以我们认为不能利用公平分配的数学建模方法来量化个人的水平能力,必须以两人合作时的成绩为参考进行建模。对于那些没有数据的合作组合,获胜概率设置为0.5,代表无法判断他们与其他组合比赛时孰强孰弱。
符号说明
数据预处理
题目中给出的数据以双方对抗的部分历史数据的形式呈现,基于对这些事件的统计结果,为了探究任意两人对战时可能出现的结果,使用蒙特卡洛法设计出一个胜率矩阵,用来反映任意双打组合对战的胜率[1]。为了弥补数据的不完善,我们选择将没有交手数据的组合获胜概率均设置为0.5。下面是题干给出的历史数据:
表 4-1:双方对抗的部分历史数据(来源于两队间的非正式比赛,采用正常的 21 分赛制)
用Python进行蒙特卡洛法处理,程序会产生随机数,模拟任意队伍对决,根据输入的历史数据预测胜负。根据伯努利大数定律:
可以利用频率估计概率,最终可以得到如下的二联胜率矩阵(第一问和第二问代码相同,见附录1代码I,第三问代码见附录1代码III)。它代表了不同的二联组合在进行对战时,己方(A组)的获胜概率:
表4-3:问题一、问题二对应二联胜率矩阵
注:加粗字体代表利用已知数据计算出的结果,其余为填充值
B1,B2 B1,B3 B1,B4 B1,B5 B2,B3 B2,B4 B2,B5 B3,B4 B3,B5 B4,B5
A1,A2 0.531 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
A1,A3 0.506 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.673 0.5
A1,A4 0.5 0.5 0.5 0.5 0.5 0.514 0.5 0.5 0.5 0.5
A1,A5 0.5 0.5 0.5 0.537 0.5 0.5 0.5 0.5 0.5 0.5
A2,A3 0.5 0.5 0.5 0.5 0.610 0.5 0.5 0.5 0.5 0.5
A2,A4 0.5 0.5 0.5 0.5 0.5 0.482 0.5 0.5 0.5 0.5
A2,A5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.601 0.5
A3,A4 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.503 0.5 0.597
A3,A5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
A4,A5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.526 0.5
表4-4:问题三对应二联胜率矩阵
注:加粗字体代表利用已知数据计算出的结果,其余为填充值
B1,B2 B1,B3 B1,B4 B1,B5 B2,B3 B2,B4 B2,B5 B3,B4 B3,B5 B4,B5 B1,B6 B2,B6 B3,B6 B4,B6 B5,B6
A1,A2 0.531 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
A1,A3 0.506 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.673 0.5 0.5 0.5 0.5 0.5 0.5
A1,A4 0.5 0.5 0.5 0.5 0.5 0.514 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
A1,A5 0.5 0.5 0.5 0.537 0.5 0.5 0.5 0.5 0.5 0.5 0.531 0.5 0.5 0.5 0.5
A2,A3 0.5 0.5 0.5 0.5 0.61 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
A2,A4 0.5 0.5 0.5 0.5 0.5 0.482 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
A2,A5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.601 0.5 0.5 0.5 0.5 0.5 0.5
A3,A4 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.503 0.5 0.597 0.5 0.5 0.5 0.595 0.5
A3,A5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.493
A4,A5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.526 0.5 0.5 0.5 0.5 0.5 0.5
A1,A6 0.5 0.473 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
A2,A6 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.457 0.5 0.5 0.5
A3,A6 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
A4,A6 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
A5,A6 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.494 0.5 0.5 0.5 0.5 0.5
模型建立与求解
问题一模型建立与求解
问题一求解思路
第一问在已知对方出场顺序的情况和部分历史对抗数据的情况下,寻找己方最佳的出场顺序。问题的本质是在情况下按照规则推进比赛时,计算如何可以先在五局中取胜。由于总共可以选择的方案只有120种,可以采取模拟的方法。如果面对更大的数据,也可以利用线性规划中的整数规划方法来解决这一问题。本题我们选择采取模拟的方法,因为这种方法更加的直观与有利于理解,且计算量相对线性规划小,对数据准确度的依赖性低。
- 蒙特卡洛模拟模型的建立
在数据处理阶段,我们已经利用蒙特卡洛模拟得出了以及的二联胜率,并且依据假设将无法利用已知数据得到的胜率用0.5代替,现在已经可以判断任意两个双人组对战时己方组合率先获得10分并赢下单位胜利的可能性。
在对方已经确定了的出场顺序后,我们对己方可以采取的120种策略进行模拟,模拟的过程由于是对大量随机事件的统计,我们再次使用蒙特卡洛法(如图5-1)来完成模拟的过程。由于我们在数据处理阶段求出的二联胜率之间其实差别并不大,所以预期最后通过模拟得出的结果可能存在争议性,所以我们用多个变量的值重复进行模拟,在计算机硬件允许的情况下尽量提高模拟的次数,得出最优顺序答案。同时我们还计算了己方在使用模拟出来的最优顺序时的获胜概率,这将有利于对问题本质的深刻理解,有利于解答得出结果后的一些疑问。下面是我们进行蒙特卡洛模拟时的思路流程图(模拟的代码请查看附录1代码II):
图5-1 蒙特卡洛模拟流程图
- 问题一求解与分析
在多次的遍历中,以模拟次数作为变量,得到下面的结果:
表5-1:问题一模拟结果
模拟次数 获胜概率 A组最优顺序
1000 0.66
2000 0.65
3000 0.64
4000 0.63
5000 0.63
6000 0.64
通过模拟所算出来的A组最优顺序似乎并不存在规律性,但是获胜的概率却趋近于0.63~0.64。换句话说,可能有多种不同的决策方案可以带来统计意义上相同的结果。这似乎是代表了,A组的综合实力强于B组,以至于前者可以用多种方式打败后者。
从另一个角度理解,我们也可以将结果的多样性理解为博弈论混合策略或者”富足”解状态。结果可以用一个混合策略集合表示:
其中代表混合策略解集中的一个策略,代表所有策略所处的空间。
利用博弈论的思维,我们将这个结果解读为混合策略中不可消除的随机性,通过一定的随机策略选择,能够将胜率维持在最高水平。在某些博弈中,决策者甚至必须依靠不可消除的随机性来维持最高胜率。我们利用蒙特卡洛模拟模型得出的结论似乎符合这一情况。
事实上,在很多博弈论经典模型n重赛马博弈中,最优策略往往不止一个,那么在存在多个最优策略的情况下, 我们能否优中选优?针对这一问题,本文将风险这一概念引入最后的答案求解过程,对最优策略混合解优中选优进行简单的研究[3]。
在一场真实的比赛中,消耗时间越长,就越可能出现意外。在保证一定胜率的前提下,“快刀斩烂麻”的策略优于持久战。因为风险随着时间的延长而增加,所以我们认为能在最少的总局数中获胜的策略为最终应该给出的答案。
为了寻找到这样的策略,利用胜率矩阵,将应战对方对应二联组合时胜率最高的己方组合提取出来,能够得到下面的表格:
表5-2:占优胜率矩阵
B1,B2 B2,B3 B3,B4 B4,B5 B5,B1
A1,A2 A2,A3 A3,A4 A3,A4 A5,A1
胜率越高,就能越快地取得一个单位胜利,因此该表实际反映了相对对方的每一轮选手,最快打败对方的己方二联组合。
不难发现,对应的A组出场顺序除了第四轮,恰好符合一局替换一人的游戏规则,可以直接被使用。所以将第四轮替换为A4,A5就可以得出最后答案:
表5-3:规则修订版占优胜率矩阵
B1,B2 B2,B3 B3,B4 B4,B5 B5,B1
A1,A2 A2,A3 A3,A4 A4,A5 A5,A1
由于的出场顺序可以在保持前文混合策略的稳定胜率的前提下最快地结束整场游戏,拥有最小的时间风险,所以我们认为在这场游戏的顺序安排中,最优的策略是。
问题二模型建立与求解
问题二求解思路
在问题分析中,我们已经抽象出了问题二的本质,接下来将延续问题一的模型,求出在已知己方出场顺序的情况下,对方最优的三种策略,并根据这三种策略分别求出己方的最优策略。
5.2.2问题二求解与分析
第一步,在已知己方顺序为时利用蒙特卡洛模拟,但是此次保留前三理想的结果,也就是对方获胜概率前三所对应的策略。
第二步,假设对方采用这三种方案的概率都是,再次使用蒙特卡洛模拟模型的算法,求出己方的最优策略。
使用问题一类似的方法(请查看附录1代码IV),得出了如下的结果:
表5-4 问题二模拟结果
模拟次数 获胜概率 B组最优顺序 A组最优顺序
0.642
4000 0.640
0.637
同样地,第二问也可以使用第一问相同的思路进行风险控制,因为随着模拟次数的改变,最后的答案依然呈现混合解集的特点。但是由于第二问涉及的时间风险控制过于复杂,本文不予讨论,仅展示一轮模拟得到的结果。
问题三模型建立与求解
博弈论均衡模型的建立
根据题意,我们会利用博弈论的知识,尝试寻找双方均衡状态。这一均衡状态在博弈论中被称为”Nash均衡”。找到Nash均衡点的关键是,在这一状态下,己方所采取的顺序一定是关于对方所采取策略的最佳反应。因此没有一方会轻易地偏离这个均衡策略从而使自己蒙受损失[2]。如果无法找到双方的均衡状态,我们会通过排除劣势策略和选择优势策略的方法缩小双方可以选择的策略的范围,最终找到己方的优势策略。
胜率越高,可以认为收益越大。由于是零和博弈,只需要分析一方的收益就可以反映出对方的收益。此时对于己方和对方,各有策略集:
它们的收益分别为:
假设”Nash均衡”对应的解集是:**
在数学意义上,达到均衡点的要求对双方而言都有:
题目本质上是求解零和博弈的平衡点,即博弈论中的Nash均衡点。
在实际的计算中,如果将所有的策略放在矩阵的环境下,则有一套成熟的方法可以直接寻找均衡点。
在矩阵的环境下,该点存在的条件为:
其中为策略胜率矩阵的元素。
策略胜率矩阵不同于前文的胜率矩阵,它由胜率矩阵推理得到(这一过程可以由计算机完成),反映了双方不同人员配置、不同出场顺序的完整策略在随机匹配时的胜率,它总共拥有的元素个数为:
而由于我们是使用蒙特卡洛算法求解的,所以存在求得的胜率存在一定的误差。故我们要检验的是胜率矩阵是否满足
在实际的操作中,取即可。
因此这道题只需要按照之前的方法计算出每种策略对应的胜率矩阵的值(胜率),再检验上述条件是否满足,然后找出上述条件对应的己方以及对方的排序即可。
如果没有满足上述条件的策略,己方只需要选出按照第二问方法算出的对应胜率最大的方法即可。
- 问题三求解与分析
为了求解零和博弈的平衡点,我们需要计算每种可能的出场顺序的胜率,并检查这些胜率是否满足特定条件。具体步骤如下:
第一步,首先,我们需要根据历史数据计算出每对选手的胜率。在数据处理阶段我们已经完成了这一工作。然后,我们需要构建所有可能的出场顺序,包括新增的候选选手。
第二步,进行蒙特卡洛模拟:对于每种出场顺序,我们进行蒙特卡洛模拟,模拟多场比赛,以估计每种出场顺序的胜率。
第三步,计算策略胜率矩阵:基于蒙特卡洛模拟的结果,我们可以计算出每种出场顺序的胜率,这些胜率将构成一个矩阵,其中每个元素代表一种出场顺序对另一种出场顺序的胜率。在算法实现的过程中,由于需要遍历的元素数量巨大,我们使用格雷码知识,一次只改变一对相邻元素,保证遍历的准确性与完备性。下面是我们得到的策略胜率矩阵(由于矩阵的元素数量过于庞大,我们只展示矩阵的部分元素):
表5-5 决策胜率矩阵
0.61 0.57 0.55 0.54
0.74 0.59 0.52 0.52
0.58 0.58 0.51 0.51
0.53 0.54 0.48 0.60
第四步,检验平衡点条件:我们需要检验这个胜率矩阵是否满足平衡点的条件,即任意元素都不大于1减去其对应的行和列的元素之和。这可以通过计算每个元素的值,并与ε(通常取0.01)进行比较来实现。这一步是在利用计算机计算是否存在Nash均衡点。
第五步,找出满足条件的策略:如果存在满足平衡点条件的策略,那么这就是我们要找的稳定出场顺序。如果所有策略都不满足条件,那么我们只需选择胜率最高的策略。
通过程序的运行(代码见附录1代码V以及代码VI),我们找到了矩阵的Nash均衡点,它所对应的出场顺序分别是和。使用这样的策略时,双方有稳定的与对方出场顺序无关的己方出场顺序。
6.模型检验和评估(蒙特卡洛模型)
6.1准确性分析
将已有数据分成数据集(80%)和测试集(20%),并通过生成随机数加入一些额外的特征,如球员年龄、主场优势等。据此创建逻辑回归模型,用数据集训练模型。将测试集中的数据输入已经训练好的回归模型中,计算模型准确度(代码见附录1代码VII)。最后通过输入新的特征值对新的比赛进行预测,输出结果。(结果,即模型准确度为70%左右)。
评价:该模型高于随机猜测。70%的准确度明显高于随机猜测的准确度(如果完全随机猜测,准确度是50%),这表明模型能够学习到一定的数据规律并做出有用的预测。
6.2敏感度分析
敏感度分析用于评估模型输出对于输入参数变化的敏感程度。首先输入历史数据(两队历史交手比分),据此计算获胜概率。以A队为例,改变A队历史赢球数(代码调试数据从1到10),在计算模拟获胜概率并与历史模型中的历史获胜概率比较(代码见附录1代码VIII)。
表6-1 敏感度分析结果
在评估过程中,模型呈现出如下的特点:
(1)趋势观察:随着A队历史赢球数的增加,A队的模拟获胜概率也随之增加,而B队的获胜概率相应减少。这符合直觉,因为历史赢球数更多可能意味着A队更强。
(2)敏感度评估:模型对A队历史赢球数的增加表现出一定的敏感性,但变化并不是非常剧烈。这表明模型在一定程度上是稳健的,但仍然对输入数据有一定依赖。
(3)概率变化:获胜概率的变化幅度在可接受范围内,没有出现极端的跳跃,这通常意味着模型没有过敏感。
(4)模型稳健性:尽管随着历史赢球数的增加,A队的获胜概率逐渐上升,但变化并不是线性的,这可能表明模型在处理不同数据点时有一定的非线性特性。
(5)决策支持:这些结果可以为决策者提供一定的支持,比如在体育博彩或战术安排中。然而,应该注意到,模型的预测并不是百分之百准确,存在一定的不确定性。
7.模型评价与推广
基于蒙特卡洛法得出的模型简单易懂,在现实中可操作性强。
使用时间风险控制最后的答案,提出了”优中选优”的最佳方案,可执行性强。
基于”均衡”概念得出的模型使用了博弈论知识,符合双方都是有主观性的”局中人”的现实。
模型的不足
通过模拟算法实现的模型相对不准确,得出的结论存在一定的偶然性。
第一、二问得到的结果为混合解集,无法用比较精确的语言将其表示出来。
对于现实竞赛环境的许多干扰因素(如临场发挥等)选择忽略,过于理想化。
模型的推广
进一步使最终的模型适应于复杂的现实情境,理所当然地考虑加入动态因素,允许决策者在游戏进行中进行策略调整,灵活地派出接下来出场的选手。需要特别指明的是,如果选手们可以完全按照题目给出数据反映出的能力进行比赛,一个理智的决策者不能临时调整策略,因为我们在前文中给出的模型已经足够解决无意外的情况了。如果有选手超常发挥或者失常发挥,那么决策者可以考虑调整策略。
对策略的调整其实很简单,决策者只需要根据前两个模型中提供的算法,在当前的局势下进行再次的运算即可。然而必须承认,如果要利用数学语言,是无法简练地将所有的动态变化都直观地反映出来了的。不过至少,我们还是可以利用强大的主观能动性去应对现场的随机性,尤其是在已经掌握了比赛顺序决策的方法后。
****
参考文献
[1] 司守荃;孙玺菁;数学建模算法与应用[M].北京:国防工业出版社,2021:27-29
[2] Avinash K. Dixit;Barry J. Nalebuff;策略思维: 商界、政界及日常生活中的策略竞争[M]. 中国人民大学出版社,2013
[3] 尹向飞.”田忌赛马”类博弈的最优策略风险探讨[J].统计与决策,2007,(17):34-36.
附录1 关键代码
代码I: 第一问 实现蒙特卡洛模拟法的python程序
蒙特卡洛模拟模拟 假设的历史赢球数(分别输入比赛中的获胜球数,下面用(A1,A2)VS(B1,B2)作为示例)
import random
wins_A_history = 23+21+21
wins_B_history = 21+18+19
total_games_history = wins_A_history + wins_B_history
蒙特卡洛模拟模拟 根据历史数据计算获胜概率
win_probabilities = {
'A_team': wins_A_history / total_games_history, 蒙特卡洛模拟模拟 A队获胜的概率
'B_team': wins_B_history / total_games_history 蒙特卡洛模拟模拟 B队获胜的概率
}
蒙特卡洛模拟模拟 蒙特卡洛模拟的场次数
num_simulations = 10000
蒙特卡洛模拟模拟 初始化获胜次数计数器
wins_A = 0
wins_B = 0
蒙特卡洛模拟模拟 进行蒙特卡洛模拟
for _ in range(num_simulations):
蒙特卡洛模拟模拟 根据获胜概率随机决定哪队获胜
if random.random() < win_probabilities['A_team']:
wins_A += 1
else:
wins_B += 1
蒙特卡洛模拟模拟 计算并打印获胜概率(这里打印的是模拟得到的概率,不是历史概率)
print(f"A队模拟获胜的概率: {wins_A / num_simulations:.2%}")
print(f"B队模拟获胜的概率: {wins_B / num_simulations:.2%}")
代码II: 第一次遍历代码
import itertools
import numpy as np
蒙特卡洛模拟模拟 胜率数据(二维列表)由于B组顺序已经固定,照表填写即可
win_rates = [
蒙特卡洛模拟模拟 A1 vs B队
[0.531, 0.506, 0.500, 0.500, 0.500], 蒙特卡洛模拟模拟 A1 vs B1, B2, B3, B4, B5
蒙特卡洛模拟模拟 A2 vs B队(在A1之后出场)
[0.500, 0.610, 0.500, 0.500, 0.500], 蒙特卡洛模拟模拟 A2 vs B2, B3, B4, B5, B1(因为B1在B2之前但A2在A1之后)
蒙特卡洛模拟模拟 A3 vs B队(在A2之后出场)
[0.500, 0.500, 0.500, 0.500, 0.673], 蒙特卡洛模拟模拟 A3 vs B3, B4, B5, B1, B2
蒙特卡洛模拟模拟 A4 vs B队(在A3之后出场)
[0.500, 0.500, 0.503, 0.514, 0.500], 蒙特卡洛模拟模拟 A4 vs B4, B5, B1, B2, B3
蒙特卡洛模拟模拟 A5 vs B队(在A4之后出场)
[0.537, 0.500, 0.597, 0.500, 0.601], 蒙特卡洛模拟模拟 A5 vs B5, B1, B2, B3, B4
]
蒙特卡洛模拟模拟 B队的出场顺序是固定的 B1, B2, B3, B4, B5
B_order = ['B1', 'B2', 'B3', 'B4', 'B5']
蒙特卡洛模拟模拟 可能的A队出场顺序(所有排列)
A_possible_orders = list(itertools.permutations(['A1', 'A2', 'A3', 'A4', 'A5']))
蒙特卡洛模拟模拟 蒙特卡洛模拟函数,用于计算给定出场顺序下A队的获胜概率
def simulate_order(A_order, B_order, win_rates, num_simulations=10000):
wins = 0
for _ in range(num_simulations):
score_A = 0
score_B = 0
A_index = 0
B_index = 0
while score_A < 50 and score_B < 50:
蒙特卡洛模拟模拟 随机决定当前回合的胜负
if np.random.rand() < win_rates[A_order.index(A_order[A_index])][B_order.index(B_order[B_index])]:
score_A += 1
else:
score_B += 1
蒙特卡洛模拟模拟 检查是否达到换人的分数点
if score_A in [10, 20, 30, 40] or score_B in [10, 20, 30, 40]:
蒙特卡洛模拟模拟 换人逻辑
if score_A >= 10:
A_index = (A_index + 1) % len(A_order)
if score_B >= 10:
B_index = (B_index + 1) % len(B_order)
蒙特卡洛模拟模拟 判断哪一方获胜
if score_A >= 50:
wins += 1
return wins / num_simulations
蒙特卡洛模拟模拟 初始化最优出场顺序和最高获胜概率
best_order = None
highest_win_rate = 0
蒙特卡洛模拟模拟 遍历所有可能的出场顺序,并计算获胜概率
for A_order in A_possible_orders:
win_rate = simulate_order(A_order, B_order, win_rates)
if win_rate > highest_win_rate:
highest_win_rate = win_rate
best_order = A_order
蒙特卡洛模拟模拟 输出最优出场顺序和最高获胜概率
print("最优出场顺序:", best_order)
print("最高获胜概率:", highest_win_rate)
代码III:第二问 实现蒙特卡洛模拟法的python程序
# 计算B队胜率最高的三种出场顺序
best_B_orders = []
for B_order in itertools.permutations(['B1', 'B2', 'B3', 'B4', 'B5']):
win_rate = simulate_order(['A1', 'A2', 'A3', 'A4', 'A5'], B_order, win_rates)
best_B_orders.append((B_order, win_rate))
# 按胜率排序并获取前三个最高的
best_B_orders.sort(key=lambda x: x[1], reverse=True)
top_3_B_orders = best_B_orders[:3]
print("对方胜率最高的三种出场顺序:", top_3_B_orders)
代码IV:第二次遍历代码
#计算A组的最佳出场顺序
import itertools
# 假设的胜率矩阵,实际应用中需要根据历史数据填充
win_matrix = {
'A1': {'B1': 0.531, 'B2': 0.506, 'B3': 0.5, 'B4': 0.5, 'B5': 0.537},
'A2': {'B1': 0.5, 'B2': 0.61, 'B3': 0.5, 'B4': 0.482, 'B5': 0.5},
'A3': {'B1': 0.5, 'B2': 0.5, 'B3': 0.5, 'B4': 0.5, 'B5': 0.673},
'A4': {'B1': 0.5, 'B2': 0.5, 'B3': 0.503, 'B4': 0.514, 'B5': 0.5},
'A5': {'B1': 0.537, 'B2': 0.5, 'B3': 0.597, 'B4': 0.5, 'B5': 0.601},
}
# 计算给定出场顺序下的预期胜率
def calculate_expected_win_rate(a_order, b_order, win_matrix):
expected_win_rate = 1
for a_player, b_player in zip(a_order, b_order):
player_win_rate = win_matrix.get(a_player, {}).get(b_player, 0.5) # 默认胜率为0.5
expected_win_rate *= player_win_rate
return expected_win_rate
# 寻找最优出场顺序
def find_best_order(original_order, opponent_orders, win_matrix):
all_orders = list(itertools.permutations(original_order))
best_a_order = None
highest_average_win_rate = 0
for a_order in all_orders:
average_win_rate = sum(calculate_expected_win_rate(a_order, opponent_order, win_matrix)
for opponent_order in opponent_orders) / len(opponent_orders)
if average_win_rate > highest_average_win_rate:
highest_average_win_rate = average_win_rate
best_a_order = a_order
return best_a_order, highest_average_win_rate
# 己方原计划的出场顺序
original_order = ['A1', 'A2', 'A3', 'A4', 'A5']
# 对方可能的三种出场顺序
opponent_orders = [
['B3', 'B1', 'B5', 'B2', 'B4'],
['B4', 'B3', 'B1', 'B5', 'B2'],
['B1', 'B5', 'B2', 'B4', 'B3']
]
# 找到并输出最优出场顺序和最高平均胜率
best_order, highest_average_win_rate = find_best_order(original_order, opponent_orders, win_matrix)
print(f"最优出场顺序为:{best_order}")
代码V:生成随机数
//每一次蒙特卡洛模拟中,利用随机数生成器来模拟比赛结果,至多100次,c++形式的模拟代码如下:
#include<iostream>
#include<cstdlib>
#include<iomanip>
using namespace std;
int main()
{
srand(time(0));
double a = 0.0;
for (int i = 1; i <= 100; i++)
{
a =rand() % 100;
cout << setw(10)<<(float)a/100;
if (i % 10 == 0)
{
cout << endl;
}
}
}
//蒙特卡洛模拟进行100次,100场对局中A队获胜局数除以100可得当前出场顺序的胜率下A队胜率,也即上方矩阵中的元素
代码VI:第三问均衡求解
import numpy as np
from itertools import permutations
# 历史数据
win_rates = {
# ...(根据表A-1和表A-2中的数据填充)
}
# 所有可能的出场顺序(包括新增的候选选手)
all_possible_orderings = list(permutations(['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6']))
# 蒙特卡洛模拟的次数
num_simulations = 10000
# 初始化最佳出场顺序和最佳胜率
best_ordering = None
best_win_rate = 0
# 计算每种出场顺序的胜率
for ordering in all_possible_orderings:
wins = 0
for opponent_ordering in all_possible_orderings:
score_a = 0
score_b = 0
while score_a < 50 and score_b < 50:
matchup_a = tuple(ordering[(score_a // 10) % 5]) if score_a < 40 else tuple(ordering[4:])
matchup_b = tuple(opponent_ordering[(score_b // 10) % 5]) if score_b < 40 else tuple(opponent_ordering[4:])
win_rate = win_rates[matchup_a + matchup_b]
if np.random.random() < win_rate:
score_a += 1
else:
score_b += 1
if score_a >= 50:
wins += 1
win_rate = wins / num_simulations
if win_rate > best_win_rate:
best_win_rate = win_rate
best_ordering = ordering
# 检验平衡点条件
epsilon = 0.01
winning_matrix = np.zeros((len(all_possible_orderings), len(all_possible_orderings)))
for i, ordering_a in enumerate(all_possible_orderings):
for j, ordering_b in enumerate(all_possible_orderings):
score_a = 0
score_b = 0
while score_a < 50 and score_b < 50:
matchup_a = tuple(ordering_a[(score_a // 10) % 5]) if score_a < 40 else tuple(ordering_a[4:])
matchup_b = tuple(ordering_b[(score_b // 10) % 5]) if score_b < 40 else tuple(ordering_b[4:])
winning_matrix[i, j] += win_rates[matchup_a + matchup_b]
winning_matrix[i, j] /= num_simulations
# 检验平衡点条件
if abs(winning_matrix[i, j] - (1 - np.sum(winning_matrix[i, :]) - np.sum(winning_matrix[:, j]))) > epsilon:
print(f"平衡点条件不满足:{winning_matrix[i, j]} > {1 - np.sum(winning_matrix[i, :]) - np.sum(winning_matrix[:, j])}")
break
else:
continue
break
else:
print("所有策略都满足平衡点条件。")
# 输出结果
print("最佳出场顺序:", best_ordering)
print("最佳胜率:", best_win_rate)
代码VII:准确度分析代码
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# 假设我们有一些额外的特征,例如主场优势、球员平均年龄等
# 这里我们随机生成一些数据作为示例
np.random.seed(0) # 为了可重复性设置随机种子
features = np.random.rand(100, 5) # 100场比赛,5个特征
labels = np.random.randint(0, 2, 100) # 随机生成100场比赛的胜负结果,0代表A队胜,1代表B队胜
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.2, random_state=42)
# 创建逻辑回归模型
model = LogisticRegression()
# 训练模型
model.fit(X_train, y_train)
# 预测测试集
y_pred = model.predict(X_test)
# 计算准确度
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确度: {accuracy:.2%}")
# 使用模型进行预测(示例)
new_data = np.array([[0.5, 0.3, 0.2, 0.7, 0.1]]) # 假设这是新比赛的特征
new_prediction = model.predict(new_data)
print(f"新比赛预测结果: {'A队' if new_prediction[0] == 0 else 'B队'}")
代码VIII:敏感度分析代码
import random
# 假设的历史赢球数
wins_A_history = 23 + 21 + 21
wins_B_history = 21 + 18 + 19
# 根据历史数据计算获胜概率
win_probabilities = {
'A_team': wins_A_history / (wins_A_history + wins_B_history),
'B_team': wins_B_history / (wins_A_history + wins_B_history)
}
# 蒙特卡洛模拟的场次数
num_simulations = 10000
# 存储不同历史数据下模拟的获胜概率
sensitivity_results = {}
# 进行敏感度分析
for i in range(1, 11): # 改变历史赢球数,这里以A队为例,从1到10增加赢球数
wins_A_history_i = wins_A_history + i
win_probabilities_i = {
'A_team': wins_A_history_i / (wins_A_history_i + wins_B_history),
'B_team': wins_B_history / (wins_A_history_i + wins_B_history)
}
wins_A = 0
wins_B = 0
# 进行蒙特卡洛模拟
for _ in range(num_simulations):
if random.random() < win_probabilities_i['A_team']:
wins_A += 1
else:
wins_B += 1
# 记录模拟获胜概率
sensitivity_results[i] = {
'A_team_win_prob': wins_A / num_simulations,
'B_team_win_prob': wins_B / num_simulations
}
# 打印敏感度分析结果
for change in sensitivity_results:
print(f"当A队历史赢球数增加{change}时,")
print(f"A队模拟获胜的概率: {sensitivity_results[change]['A_team_win_prob']:.2%}")
print(f"B队模拟获胜的概率: {sensitivity_results[change]['B_team_win_prob']:.2%}")
print()