from collections import namedtuple
import numpy.matlib as mat
import numpy as np
from numpy.linalg import inv
Match = namedtuple("Match", ["teams", "score"])
def CalcOpr(matches):
"""
Given a list of matches, to least squares OPR calculation
"""
num_matches = len(matches) # rows
teams = list(set().union(*[match.teams for match in matches]))
num_teams = len(teams)
alliances = mat.zeros((num_matches, num_teams))
scores = mat.zeros((num_matches, 1))
for idx, match in enumerate(matches):
scores[idx, 0] = match.score
for team in match.teams:
alliances[idx, teams.index(team)] = 1
least_squares_approx = np.dot(
inv(np.dot(np.transpose(alliances), alliances)),
np.dot(np.transpose(alliances), scores))
oprs = {}
for idx, team in enumerate(teams):
oprs[team] = least_squares_approx[idx, 0]
return oprs
print(CalcOpr([
Match(teams=['A', 'B'], score=10),
Match(teams=['A', 'C'], score=13),
Match(teams=['B', 'C'], score=7),
Match(teams=['A', 'D'], score=15),
Match(teams=['B', 'D'], score=10),
]))
{'C': 5.0, 'A': 7.75, 'D': 7.5, 'B': 2.25}
import tbapy
from pprint import pprint
api_key = "6qOZ9uAEsb4CDrOBNG6ZnIdi9cWBaZ6DHnCSato97Qfo7bBeUwT9NfFt4Gi5sHFN"
tba = tbapy.TBA(api_key)
pprint(tba.status())
{'android': {'latest_app_version': 4020399, 'min_app_version': 4000299}, 'contbuild_enabled': True, 'current_season': 2018, 'down_events': [], 'ios': {'latest_app_version': -1, 'min_app_version': -1}, 'is_datafeed_down': False, 'json': {'android': {'latest_app_version': 4020399, 'min_app_version': 4000299}, 'contbuild_enabled': True, 'current_season': 2018, 'down_events': [], 'ios': {'latest_app_version': -1, 'min_app_version': -1}, 'is_datafeed_down': False, 'max_season': 2018, 'web': {'commit_time': '2018-02-08 16:24:47 -0500', 'current_commit': '0818a656fa52a99bd0af8943e91bf6107a80314d', 'deploy_time': 'Thu Feb 8 21:39:42 UTC 2018', 'travis_job': '339186456'}}, 'max_season': 2018, 'web': {'commit_time': '2018-02-08 16:24:47 -0500', 'current_commit': '0818a656fa52a99bd0af8943e91bf6107a80314d', 'deploy_time': 'Thu Feb 8 21:39:42 UTC 2018', 'travis_job': '339186456'}}
matches = tba.event_matches('2017roe')
match_outcomes = []
for match in matches:
match_outcomes.append(
Match(teams=match['alliances']['blue']['team_keys'],
score=match['alliances']['blue']['score'])
)
match_outcomes.append(
Match(teams=match['alliances']['red']['team_keys'],
score=match['alliances']['red']['score'])
)
score_oprs = sorted(CalcOpr(match_outcomes).items(), key=lambda x: -x[1])
pprint(score_oprs)
[('frc973', 177.56919288327308), ('frc115', 157.0259913331104), ('frc1011', 149.76450747382796), ('frc4265', 146.76438484413518), ('frc365', 143.49460917929289), ('frc2928', 135.80511381914454), ('frc624', 134.76677882359436), ('frc2403', 134.32245109158637), ('frc1574', 129.37613398098358), ('frc1414', 127.96800663206291), ('frc2642', 127.18581346587769), ('frc3824', 126.96309325527552), ('frc1339', 125.96798422065352), ('frc4590', 125.26308475200871), ('frc1002', 124.21225689931802), ('frc3316', 122.8078910824091), ('frc5970', 122.50535563795168), ('frc6325', 119.78641397302121), ('frc418', 116.62106655170464), ('frc1477', 114.77491503934719), ('frc8', 114.29890025268725), ('frc5803', 113.73483804756773), ('frc6705', 111.58307204661132), ('frc4561', 111.00355528639119), ('frc2468', 110.41012216879824), ('frc5026', 110.04546378593928), ('frc5614', 107.61788458386509), ('frc3402', 107.4626066948726), ('frc2655', 104.24531198243945), ('frc3158', 101.14330694999202), ('frc488', 98.055462452244143), ('frc4592', 98.052651237205325), ('frc435', 96.464573727156278), ('frc3834', 91.570774782459154), ('frc441', 91.149404570612035), ('frc3140', 90.638557116564982), ('frc5816', 89.708856584075434), ('frc4219', 89.586753586033979), ('frc2485', 88.505690883901565), ('frc585', 88.25561566820447), ('frc3229', 86.158182066996943), ('frc6304', 85.649736210525333), ('frc3653', 85.284652499378396), ('frc175', 85.116732278878715), ('frc6508', 84.873574464768041), ('frc4276', 81.574812779764528), ('frc5499', 81.076671646279891), ('frc2478', 80.843731553943798), ('frc5515', 80.505727211308368), ('frc3826', 78.089578436795648), ('frc2881', 76.769491169265663), ('frc955', 75.507539471727597), ('frc2183', 70.635782080362318), ('frc6361', 70.17568719278286), ('frc1482', 69.055515009333917), ('frc6560', 68.823962846736208), ('frc3991', 67.737826004420583), ('frc4371', 67.365329372744242), ('frc6388', 66.306467100842639), ('frc4060', 65.914273669761229), ('frc4191', 62.865270011745224), ('frc4723', 56.810485185257662), ('frc5472', 54.510742035159979), ('frc6144', 36.696388177764277), ('frc2905', 26.417361845177616), ('frc6409', 8.2241314774465888)]
match_outcomes = []
for match in matches:
match_outcomes.append(
Match(teams=match['alliances']['blue']['team_keys'],
score=match['score_breakdown']['blue']['kPaRankingPointAchieved'])
)
match_outcomes.append(
Match(teams=match['alliances']['red']['team_keys'],
score=match['score_breakdown']['red']['kPaRankingPointAchieved'])
)
kpa_oprs = CalcOpr(match_outcomes)
pprint(kpa_oprs)
{'frc1002': 0.011495807536502572, 'frc1011': -0.23843650566297964, 'frc115': -0.012713387884420797, 'frc1339': 0.049583694803860427, 'frc1414': -0.025609512663978932, 'frc1477': 0.022485935872360904, 'frc1482': 0.024757792159351494, 'frc1574': 0.66808268010260641, 'frc175': 0.014010517155780116, 'frc2183': 0.014016941366526755, 'frc2403': 0.080360541678350023, 'frc2468': 0.054313747859282599, 'frc2478': 0.056793675027969996, 'frc2485': -0.11004523242061667, 'frc2642': -0.0093209117666008812, 'frc2655': 0.026158138151728107, 'frc2881': 0.12976928277693456, 'frc2905': -0.0054328961126955868, 'frc2928': -0.14365141927979586, 'frc3140': 0.034966321717088245, 'frc3158': -0.0083270752513364132, 'frc3229': -0.052914169109274517, 'frc3316': 0.022681055565912493, 'frc3402': -0.036669808722433681, 'frc365': -0.033387969672823169, 'frc3653': 0.014729368563237756, 'frc3824': 0.080450382242200247, 'frc3826': 0.019110268657443839, 'frc3834': -0.038611090946230317, 'frc3991': 0.0069417322847042124, 'frc4060': 0.031568346005882965, 'frc418': -0.17836616410749317, 'frc4191': -0.027664312060668557, 'frc4219': 0.018668059497609552, 'frc4265': -0.039762814142503211, 'frc4276': -0.011733796335331451, 'frc435': 0.021490162884872023, 'frc4371': 0.0013029801530613384, 'frc441': -0.017291511574850489, 'frc4561': 0.039187096494449604, 'frc4590': -0.0047923055382814448, 'frc4592': -0.0099013917493386283, 'frc4723': 0.027083177527512065, 'frc488': 0.30838132037945404, 'frc5026': -0.020690991999509637, 'frc5472': 0.070349291821964782, 'frc5499': 0.019626942011950511, 'frc5515': 0.063851785439747955, 'frc5614': -0.024521676323755421, 'frc5803': -0.015295375370894511, 'frc5816': 0.016515716145632582, 'frc585': 0.0023789472066973009, 'frc5970': -0.0044706821988662231, 'frc6144': 0.050254228103232886, 'frc624': -0.081349484164234639, 'frc6304': 0.033648856674681996, 'frc6325': -0.034250313916356766, 'frc6361': 0.045042709293893271, 'frc6388': -0.021082445337662147, 'frc6409': 0.045497807930851217, 'frc6508': 0.074536576581233485, 'frc6560': -0.080212765492548535, 'frc6705': -0.056760688554744892, 'frc8': 0.013041665258332877, 'frc955': 0.05983277602696755, 'frc973': 0.69379487994753519}
true_positives = 0
true_negatives = 0
false_positives = 0
false_negatives = 0
for match in matches:
for alliance in ['red', 'blue']:
result = match['score_breakdown'][alliance]['kPaRankingPointAchieved']
prediction = sum(
kpa_oprs[team] for team in match['alliances'][alliance]['team_keys']
) > 0.5
if result and prediction:
true_positives += 1
elif result and not prediction:
false_negatives += 1
elif not result and prediction:
false_positives += 1
elif not result and not prediction:
true_negatives += 1
print("True positives", true_positives)
print("True negatives", true_negatives)
print("False positives", false_positives)
print("False negatives", false_negatives)
print("Correctness", (true_positives + true_negatives) / (true_positives + true_negatives + false_positives + false_negatives + 0.0))
True positives 17 True negatives 229 False positives 3 False negatives 3 Correctness 0.9761904761904762
match_outcomes = []
for match in matches:
match_outcomes.append(
Match(teams=match['alliances']['blue']['team_keys'],
score=match['score_breakdown']['blue']['rotorRankingPointAchieved'])
)
match_outcomes.append(
Match(teams=match['alliances']['red']['team_keys'],
score=match['score_breakdown']['red']['rotorRankingPointAchieved'])
)
rotor_oprs = CalcOpr(match_outcomes)
pprint(rotor_oprs)
{'frc1002': 0.17727192353651036, 'frc1011': 0.23646020615753144, 'frc115': 0.27027459301427076, 'frc1339': 0.27767467034227666, 'frc1414': 0.097528516725300579, 'frc1477': 0.24271506617743271, 'frc1482': -0.20183290190431527, 'frc1574': -0.062725432249641944, 'frc175': 0.066614006692210043, 'frc2183': 0.17779147326885175, 'frc2403': 0.26038237793502095, 'frc2468': 0.077335124862353138, 'frc2478': 0.11611763401010168, 'frc2485': 0.22766288292212927, 'frc2642': 0.44131736419305789, 'frc2655': 0.078615164315436414, 'frc2881': 0.026395389715158406, 'frc2905': -0.15742362551120212, 'frc2928': 0.19144017072648187, 'frc3140': 0.050819349427158898, 'frc3158': 0.099557651860255836, 'frc3229': 0.30137859678360285, 'frc3316': -0.017803621940292693, 'frc3402': 0.23407474552151586, 'frc365': 0.027014917937426858, 'frc3653': 0.055081036501289343, 'frc3824': 0.034654129291765062, 'frc3826': 0.1618711950878218, 'frc3834': -0.10927154609293535, 'frc3991': 0.20426591613959094, 'frc4060': -0.041813912600997927, 'frc418': -0.18067404916238411, 'frc4191': -0.16868864593985589, 'frc4219': 0.0035790511659747511, 'frc4265': 0.080896946538550563, 'frc4276': 0.13708185480133839, 'frc435': 0.16573089995659673, 'frc4371': 0.080681643521142932, 'frc441': -0.077337956468450111, 'frc4561': 0.06389536845233032, 'frc4590': -0.049808506391208721, 'frc4592': 0.10461776563177416, 'frc4723': 0.086487057324865432, 'frc488': 0.012815142631013174, 'frc5026': -0.039661993822559902, 'frc5472': -0.19424322205436845, 'frc5499': 0.19376531412413966, 'frc5515': 0.064064234500017039, 'frc5614': 0.08808190904164967, 'frc5803': 0.057311874395802438, 'frc5816': 0.069464650468857733, 'frc585': 0.035569288619228395, 'frc5970': 0.44357144135582388, 'frc6144': 0.0079100008274700304, 'frc624': 0.35576013463202721, 'frc6304': -0.10973657565707473, 'frc6325': 0.26476227726013973, 'frc6361': 0.13208922601294448, 'frc6388': -0.15295108609704131, 'frc6409': -0.10431659019076206, 'frc6508': 0.086131409830338679, 'frc6560': 0.074907461418003418, 'frc6705': 0.22003298058691301, 'frc8': 0.247847970810986, 'frc955': -0.010061945508252013, 'frc973': -0.076970861048886952}
true_positives = 0
true_negatives = 0
false_positives = 0
false_negatives = 0
for match in matches:
for alliance in ['red', 'blue']:
result = match['score_breakdown'][alliance]['rotorRankingPointAchieved']
prediction = sum(
rotor_oprs[team] for team in match['alliances'][alliance]['team_keys']
) > 0.5
if result and prediction:
true_positives += 1
elif result and not prediction:
false_negatives += 1
elif not result and prediction:
false_positives += 1
elif not result and not prediction:
true_negatives += 1
print("True positives", true_positives)
print("True negatives", true_negatives)
print("False positives", false_positives)
print("False negatives", false_negatives)
print("Correctness", (true_positives + true_negatives) / (true_positives + true_negatives + false_positives + false_negatives + 0.0))
True positives 27 True negatives 177 False positives 9 False negatives 39 Correctness 0.8095238095238095