前天一时兴起, 想用计算机模拟Ti5外卡赛和正赛来看看最后的结果如何,这样就能完成小金本的预测~ 现在记录一下一些有趣的东西。
外卡赛4只队伍CDEC, Vega, MVP 和 Archon, 问题的关键是如何模拟一场比赛的胜负。我最初的想法是查下有没有人研究过每支战队的MMR值与胜率之间的关系, 但是没有找到类似的结论。退而求其次, 我决定用MMR值作为一个基准,然后利用近3个月来战队之间相互战绩进行调整, 具体方案如下:
http://www.joindota.com/en/edb/teams 这个使用points值作为战队排名的依据, 同时点开每支战队,可以查看近期的对战情况, 打开每场比赛还能看到双方交手胜负,比如Secret 的points 是34779, EG的points是33485, 那么Secret 对 EG的基础胜率就是 , EG对Secret的胜率则与之相反。 然后http://www.joindota.com/en/matches/162345-evil-geniuses-vs-team-secret 这里记录了双方相互战绩为Secret为70%胜率。 那么我们最终的胜率定为 winrate["Secret"]["EG"] = alpha * 实际胜率 + (1 - alpha) * 基础胜率
这里alpha由自己确定, 我设为0.65。 如果alpha> 0.5 则实际战绩比重更大, 反之基础胜率比重更大。
当然我具体做的时候并不精确, 其一我没有找到一个网站能够提供给我战队之间近3个月的相互战绩。 在dotamax我能查到各个战队的比赛情况, 但是我只能手工统计,这样太麻烦, 我就采用了joindata里面现成的数据, 但不知道这些交手战绩是什么时候的~。 其二是有些队伍之间比赛次数很少, 相互战绩并不能具体体现双方实力,但我还是按同样的公式进行加权平均。
对于外卡赛4只队伍,确实找不到相互战绩。。。所以直接使用points作为最终的胜率,当然这很不精确, 我就试试看有什么结果~4只战队的points如下:
points = {"CDEC" : 31462, "Vega" : 30157, "MVP" : 29431, "Archon" : 23050 }
赛制是这样的, CDEC和Vega一组, MVP和Archon一组。 两组胜者在进行一轮比赛,胜者是外卡赛第一。两组败者进行一轮比赛, 败者是外开赛第四, 然后剩下两只队再争夺2,3名,所有比赛均为BO3。 由于我要完成小金本的预测,所以我统计不同的排名次序,看看出现最多的情况是什么,但是结果很出乎我的意料.............我进行了100万次循环, 出现前三多的排名情况竟然是这样的:
第一名竟然是points第三的MVP,并且出现较多的两种情况都是MVP居榜首, 我就瞬间凌乱了....正常来说最强的队出现第一的次数应该也是最多的吧,但是模拟的结果完全不是这样的。。。 一时想不通,我就把它放着了,直到今天我和室友说起这事的时候,他给了我一个很好的解释~
首先我们看看具体模拟时候的胜率:
'MVP': {'MVP': -1, 'CDEC': 0.48332320627986797, 'Vega': 0.4939081694300866, 'Archon': 0.5607934300032392}
这是MVP对战各只队伍的胜率,可以看到按照我们的假设,其实MVP, CDEC, Vega之间实力差距并不大。 那么在BO3中获胜的胜率又有多少呢?
MVP vs CDEC : 0.483*0.483 + 0.483 * (1-0.483) *0.483 + (1-0.483) * 0.483 * 0.483 = 0.475
MVP vs Vega : 类似的0.491
MVP vs Archon: 0.591
CDEC vs Vega : 0.516
好,再次基础上考虑1000000次模拟,对于CDEC vs Vega的情况, CDEC 有 516000次进入决赛, Vega有484000次进入决赛。 而对于MVP vs Archon, MVP有591000次可能进入决赛。 这里我们发现MVP进入决赛的次数远远大于CDEC, Vega两队。 所以即使MVP在最后决胜的胜率偏低,有49.1% 和 47.5%,但是由于它进入决赛的次数比另外两队多,最终模拟出来的结果MVP得第一的次数就是最多的了...........很简单吧
好的,总结一下:
(1) 这里有违反直觉的地方存在, 胜率高的队伍在大量重复模拟的情况下得第一的次数竟然有可能比胜率偏低的队伍少, 原因是两只强队分入了死亡之组,而另一只稍弱的队伍稳稳地可以进入决赛, 在大量模拟的情况下,稍弱的队伍利用偏多的决赛次数弥补了胜率的不足。
(2) 我想用大量模拟的结果完成小金本名次预测这个方案本身不对, 因为在单次比赛中,显然按各队胜率从高往低依次为前四的概率显然是最高的,但是在大量统计的情况下却不是这样的。。。建议预测的话就按照实力强弱来排即可,最多也就24种情况,大家分分工总会对的
(3) 其实我也对正赛做了简单的模拟, 模拟次数是500万次, 想知道前六排名, 而出现最多的情况是这些:
可以看到每种情况出现的次数是很少的。。总共好像有150多万种可能吧,所以从500w的量级来看这个数量也很少, 但是无一例外的是Secret都是第一。。。。当然这只是模拟的结果,实际情况千变万化~不过第一种情况有4只中国队前六也很不错啦, IG意外的比VG和EG还厉害。
(4) 运气真的是实力的一部分,还要看临场发挥啊、适应情况,不过这些都很难说清,期望中国队能取得好成绩了!
# -*- coding: utf-8 -*- """ Created on Fri Jul 24 03:49:03 2015 @author: Mihawk """ import random points = {"CDEC" : 31462, "Vega" : 30157, "MVP" : 29431, "Archon" : 23050 } name = points.keys() winrate = {} for i in name: winrate[i] = {} for i in name: for j in name: if i != j: winrate[i][j] = points[i]*1.0 / (points[i] + points[j]) else: winrate[i][j] = -1 def gamePlayWin(team1, team2): """ 三局两胜 """ win = 0 for i in range(3): if (random.random() < winrate[team1][team2]): win = win + 1 if win >= 2: return True else: return False def simulate(): """ "CDEC" vs "Vega" """ if (gamePlayWin("CDEC", "Vega")): (A1Win, A1Lose) = ("CDEC", "Vega") else: (A1Win, A1Lose) = ("Vega", "CDEC") """ "MVP" vs "Archon" """ if (gamePlayWin("MVP", "Archon")): (B1Win, B1Lose) = ("MVP", "Archon") else: (B1Win, B1Lose) = ("Archon", "MVP") """ 胜者组决赛 """ if (gamePlayWin(A1Win, B1Win)): (A2Win, A2Lose) = (A1Win, B1Win) else: (A2Win, A2Lose) = (B1Win, A1Win) """ 败者组半决赛 """ if (gamePlayWin(A1Lose, B1Lose)): (B2Win, B2Lose) = (A1Lose, B1Lose) else: (B2Win, B2Lose) = (B1Lose, A1Lose) """ 败者组决赛 """ if (gamePlayWin(A2Lose, B2Win)): (B3Win, B3Lose) = (A2Lose, B2Win) else: (B3Win, B3Lose) = (B2Win, A2Lose) return "1 " + A2Win +"\n2 " + B3Win + "\n3 " + B3Lose + "\n4 " + B2Lose """ # 最后排名 print("1 " + A2Win) print("2 " + B3Win) print("3 " + B3Lose) print("4 " + B2Lose) """ result = {} for i in range(1000000): res = simulate() if (result.has_key(res)): result[res] = result[res] + 1 else: result[res] = 1 final = sorted(result.items(), key = lambda d:d[1], reverse=True) for i in range(5): print(final[i][0]), print(final[i][1])
# -*- coding: utf-8 -*- """ Created on Fri Jul 24 04:43:37 2015 @author: Mihawk """ points = {"CDEC" : 31462, "CG" : 29834, "IG" : 32528, "LGD" : 33226, "Navi" : 30746, "Fnatic" : 28179, "C9" : 32613, "Secret" : 34789, "MVP.P" : 29431, "Ehome" : 30642, "EG" : 33495, "Empire" : 31768, "VG" : 33111, "Newbee" : 30526, "VP" : 32187, "MVP.H" : 30032} name = points.keys() winrate = {} alpha = 0.65 for i in name: winrate[i] = {} for i in name: for j in name: if i != j: winrate[i][j] = points[i]*1.0 / (points[i] + points[j]) else: winrate[i][j] = -1 # 进行胜率调整 def interploate(team1, team2, actual): winrate[team1][team2] = alpha * actual + (1 - alpha) * winrate[team1][team2] winrate[team2][team1] = alpha * (1 - actual) + (1 - alpha) * winrate[team2][team1] interploate("CDEC", "LGD", 0.29) interploate("CDEC", "VG", 0.38) interploate("CDEC", "IG", 0.44) interploate("CDEC", "Secret", 0.2) interploate("CDEC", "Ehome", 0.57) interploate("IG", "LGD", 0.57) interploate("IG", "Ehome", 0.71) interploate("IG", "LGD", 0.57) interploate("IG", "Secret", 0.0) interploate("IG", "C9", 0.50) interploate("IG", "EG", 0.75) interploate("IG", "Fnatic", 0.8) interploate("LGD", "Empire", 0.50) interploate("LGD", "Navi", 0.44) interploate("LGD", "Secret", 0.0) interploate("Navi", "VP", 0.71) interploate("Navi", "IG", 0.36) interploate("Navi", "CDEC", 0.50) interploate("Navi", "Secret", 0.0) interploate("Fnatic", "Secret", 0.2) interploate("Fnatic", "C9", 0.8) interploate("Fnatic", "VG", 0.2) interploate("Fnatic", "Secret", 0.2) interploate("Fnatic", "VP", 0.5) interploate("C9", "EG", 0.5) interploate("C9", "VP", 0.7) interploate("C9", "VG", 0.33) interploate("C9", "Secret", 0.13) interploate("C9", "Newbee", 0.17) interploate("C9", "Ehome", 0.67) interploate("C9", "Empire", 0.67) interploate("Secret", "EG", 0.7) interploate("Secret", "VP", 0.78) interploate("Secret", "EG", 0.7) interploate("Secret", "Empire", 1.0) interploate("Secret", "Ehome", 1.0) interploate("MVP.P", "MVP.H", 0.5) interploate("MVP.P", "EG", 0.25) interploate("Ehome", "Newbee", 0.6) interploate("Ehome", "VG", 0.0) interploate("Ehome", "Empire", 0.8) interploate("Ehome", "LGD", 0.0) interploate("EG", "VP", 0.62) interploate("EG", "VG", 0.64) interploate("Empire", "VP", 0.77) interploate("Empire", "VG", 0.6) interploate("Empire", "Newbee", 1.0) interploate("VG", "VP", 0.2) interploate("VG", "Newbee", 0.65) interploate("VG", "LGD", 0.59) interploate("Newbee", "IG", 0.41) interploate("Newbee", "LGD", 0.70) interploate("Newbee", "CDEC", 0.67) groupA = ["CDEC", "CG", "IG", "LGD", "Navi", "Fnatic", "C9", "Secret"] groupB = ["MVP.P", "Ehome", "EG", "Empire", "VG", "Newbee", "VP", "MVP.H"] import random def gamePlay(team1, team2): win1 = 0 for i in range(2): if (random.random() < winrate[team1][team2]): win1 = win1 + 1 if win1 == 0: return (0, 3) elif win1 == 1: return (1, 1) else: return (3, 0) # 小组赛 def group(teamname): point = {} for team in teamname: point[team] = 0 for team1 in teamname: for team2 in teamname: if team1 < team2: (point1, point2) = gamePlay(team1, team2) point[team1] = point[team1] + point1 point[team2] = point[team2] + point2 #print(sorted(point.items(), key = lambda d:d[1], reverse = True)) res = sorted(point.items(), key = lambda d:d[1], reverse = True) UB = [res[i][0] for i in range(4)] LB = [res[i+4][0] for i in range(4)] return (UB, LB) def gamePlayWin(team1, team2): """ 三局两胜 """ win = 0 for i in range(3): if (random.random() < winrate[team1][team2]): win = win + 1 if win >= 2: return True else: return False def gamePlayWin5(team1, team2): """ BO5 """ win = 0 for i in range(5): if (random.random() < winrate[team1][team2]): win = win + 1 if win >= 3: return True else: return False def gamePlayWin1(team1, team2): """ BO1 """ if (random.random() < winrate[team1][team2]): return True else: return False def simulate(): (A1UB, A1LB) = group(groupA) (B1UB, B1LB) = group(groupB) round11 = [A1UB[0], B1UB[1], B1UB[0], A1UB[1]] round12 = [0, 0, 0, 0] if winrate[A1UB[0]][B1UB[2]] > winrate[A1UB[0]][B1UB[3]]: round12[0] = B1UB[2] round12[3] = B1UB[3] else: round12[0] = B1UB[3] round12[3] = B1UB[2] if winrate[B1UB[0]][A1UB[2]] > winrate[B1UB[0]][A1UB[3]]: round12[2] = A1UB[2] round12[1] = A1UB[3] else: round12[2] = A1UB[3] round12[1] = A1UB[2] A1Win = [i for i in range(4)] A1Lose = [i for i in range(4)] A2Win = [i for i in range(2)] A2Lose = [i for i in range(2)] """ 胜者组 """ for i in range(4): if gamePlayWin(round11[i], round12[i]): (A1Win[i], A1Lose[i]) = (round11[i], round12[i]) else: (A1Win[i], A1Lose[i]) = (round12[i], round11[i]) for i in range(2): if gamePlayWin(A1Win[2*i], A1Win[2*i+1]): (A2Win[i], A2Lose[i]) = (A1Win[2*i], A1Win[2*i+1]) else: (A2Win[i], A2Lose[i]) = (A1Win[2*i+1], A1Win[2*i]) if gamePlayWin(A2Win[0], A2Win[1]): (A3Win, A3Lose) = (A2Win[0], A2Win[1]) else: (A3Win, A3Lose) = (A2Win[1], A2Win[0]) """ 败者组 """ round21 = [A1LB[0], B1LB[1], B1LB[0], A1LB[1]] round22 = [0, 0, 0, 0] if winrate[A1LB[0]][B1LB[2]] > winrate[A1LB[0]][B1LB[3]]: round22[0] = B1LB[2] round22[3] = B1LB[3] else: round22[0] = B1LB[3] round22[3] = B1LB[2] if winrate[B1LB[0]][A1LB[2]] > winrate[B1LB[0]][A1LB[3]]: round22[2] = A1LB[2] round22[1] = A1LB[3] else: round22[2] = A1LB[3] round22[1] = A1LB[2] B1Win = [i for i in range(4)] B2Win = [i for i in range(4)] B3Win = [i for i in range(2)] B4Win = [i for i in range(2)] B4Lose = [i for i in range(2)] for i in range(4): if gamePlayWin1(round21[i], round22[i]): B1Win[i] = round21[i] else: B1Win[i] = round22[i] for i in range(4): if gamePlayWin(A1Lose[i], B1Win[i]): B2Win[i] = A1Lose[i] else: B2Win[i] = B1Win[i] for i in range(2): if gamePlayWin(B2Win[2*i], B2Win[2*i+1]): B3Win[i] = B2Win[2*i] else: B3Win[i] = B2Win[2*i+1] for i in range(2): if gamePlayWin(B3Win[i], A2Lose[1-i]): (B4Win[i], B4Lose[i]) = (B3Win[i], A2Lose[1-i]); else: (B4Win[i], B4Lose[i]) = (A2Lose[1-i], B3Win[i]) if gamePlayWin(B4Win[0], B4Win[1]): (B5Win, B5Lose) = (B4Win[0], B4Win[1]) else: (B5Win, B5Lose) = (B4Win[1], B4Win[0]) if gamePlayWin(B5Win, A3Lose): (B6Win, B6Lose) = (B5Win, A3Lose) else: (B6Win, B6Lose) = (A3Lose, B5Win) if gamePlayWin5(B6Win, A3Win): (B7Win, B7Lose) = (B6Win, A3Win) else: (B7Win, B7Lose) = (A3Win, B6Win) res = "1 "+B7Win+"\n2 "+B7Lose+"\n3 "+B6Lose res = res + "\n4 "+B5Lose+"\n5 "+B4Lose[0]+"\n6 "+B4Lose[1] return res iterations = 5000000 result = {} for i in range(iterations): print(i) res = simulate() if (result.has_key(res)): result[res] = result[res] + 1 else: result[res] = 1 writelog = open("D:\\log.txt", "wb") final = sorted(result.items(), key = lambda d:d[1], reverse=True) for i in range(10): writelog.write(final[i][0]) writelog.write("\n"+str(final[i][1]) + "\n") writelog.write("########################################\n") writelog.close()