49 Commits

Author SHA1 Message Date
ltcptgeneral
7a58cd08e2 analysis pkg v 1.0.0.11
analysis.py v 1.1.13.009
superscript.py v 0.0.5.002
2020-04-12 02:51:40 +00:00
ltcptgeneral
337fae68ee analysis pkg v 1.0.0.10
analysis.py v 1.1.13.008
superscript.py v 0.0.5.001
2020-04-09 22:16:26 -05:00
art
5e71d05626 removed app from dep 2020-04-05 21:42:12 +00:00
art
01df42aa49 added gitgraph to vscode container 2020-04-05 21:36:12 +00:00
ltcptgeneral
33eea153c1 Merge pull request #8 from titanscout2022/containerization-testing
Containerization testing
2020-04-05 16:32:40 -05:00
art
114eee5d57 finalized changes to docker implements 2020-04-05 21:29:16 +00:00
ltcptgeneral
06f008746a Merge pull request #7 from titanscout2022/master
merge
2020-04-05 14:57:56 -05:00
art
4f9c4e0dbb verified and tested docker files 2020-04-05 19:53:01 +00:00
art
5697e8b79e created dockerfiles 2020-04-05 19:04:07 +00:00
ltcptgeneral
e054e66743 started on dockerfile 2020-04-05 12:46:21 -05:00
ltcptgeneral
c914bd3754 removed unessasary comment 2020-04-04 11:59:19 -05:00
ltcptgeneral
6c08885a53 created two new analysis variants
the existing amd64
new unpopulated arm64
2020-04-04 00:09:40 -05:00
ltcptgeneral
375befd0c4 analysis pkg v 1.0.0.9 2020-03-17 20:03:49 -05:00
ltcptgeneral
893d1fb1d0 analysis.py v 1.1.13.007 2020-03-16 22:05:52 -05:00
ltcptgeneral
6a426ae4cd a 2020-03-10 00:45:42 -05:00
ltcptgeneral
50c064ffa4 worked 2020-03-09 22:58:51 -05:00
ltcptgeneral
1b0a9967c8 test1 2020-03-09 22:58:11 -05:00
ltcptgeneral
2605f7c29f Merge pull request #6 from titanscout2022/testing
Testing
2020-03-09 20:42:30 -05:00
ltcptgeneral
6f5a3edd88 superscript.py v 0.0.5.000 2020-03-09 20:35:11 -05:00
ltcptgeneral
457146b0e4 working 2020-03-09 20:29:44 -05:00
ltcptgeneral
f7fd8ffcf9 working 2020-03-09 20:18:30 -05:00
art
77bc792426 removed unessasary stuff 2020-03-09 10:29:59 -05:00
ltcptgeneral
39146cc555 Merge pull request #5 from titanscout2022/comp-edits
Comp edits
2020-03-09 10:28:48 -05:00
ltcptgeneral
04141bbec8 analysis.py v 1.1.13.006
regression.py v 1.0.0.003
analysis pkg v 1.0.0.8
2020-03-08 16:48:19 -05:00
ltcptgeneral
40e5899972 added get_team_rakings.py 2020-03-08 14:26:21 -05:00
ltcptgeneral
025c7f9b3c a 2020-03-06 21:39:46 -06:00
Dev Singh
2daa09c040 hi 2020-03-06 21:21:37 -06:00
ltcptgeneral
9776136649 superscript.py v 0.0.4.002 2020-03-06 21:09:16 -06:00
Dev Singh
68d27a6302 add reqs 2020-03-06 20:44:40 -06:00
Dev Singh
7fc18b7c35 add Procfile 2020-03-06 20:41:53 -06:00
ltcptgeneral
9b412b51a8 analysis pkg v 1.0.0.7 2020-03-06 20:32:41 -06:00
ltcptgeneral
b6ac05a66e Merge pull request #4 from titanscout2022/comp-edits
Comp edits merge
2020-03-06 20:29:50 -06:00
Dev Singh
435c8a7bc6 tiny brain fix 2020-03-06 14:52:41 -06:00
Dev Singh
a69b18354b ultimate carl the fat kid brain working 2020-03-06 14:50:54 -06:00
Dev Singh
7b9e6921d0 ultra galaxybrain working 2020-03-06 14:44:13 -06:00
Dev Singh
fb2800cf9e fix 2020-03-06 13:12:01 -06:00
Dev Singh
12cbb21077 super ultra working 2020-03-06 12:43:01 -06:00
Dev Singh
46d1a48999 even more working 2020-03-06 12:21:17 -06:00
Dev Singh
ad0a761d53 more working 2020-03-06 12:18:42 -06:00
Dev Singh
43f503a38d working 2020-03-06 12:15:35 -06:00
Dev Singh
d38744438b working 2020-03-06 11:50:07 -06:00
Dev Singh
eb8914aa26 maybe working 2020-03-06 11:27:32 -06:00
Dev Singh
283140094f a 2020-03-06 11:18:02 -06:00
Dev Singh
66ac1c304e testing part 2 better electric boogaloo 2020-03-06 11:16:24 -06:00
Dev Singh
0eb9e07711 testing 2020-03-06 11:14:10 -06:00
Dev Singh
f56c85b298 10:57 2020-03-06 10:57:39 -06:00
Dev Singh
6a9a17c5b4 10:43 2020-03-06 10:43:45 -06:00
Dev Singh
e24c49bedb 10:25 2020-03-06 10:25:20 -06:00
Dev Singh
2daed73aaa 10:21 unverified 2020-03-06 10:21:23 -06:00
64 changed files with 624 additions and 918 deletions

2
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1,2 @@
FROM python
WORKDIR ~/

View File

@@ -0,0 +1,26 @@
{
"name": "TRA Analysis Development Environment",
"build": {
"dockerfile": "Dockerfile",
},
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"python.pythonPath": "/usr/local/bin/python",
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
"python.linting.banditPath": "/usr/local/py-utils/bin/bandit",
"python.linting.flake8Path": "/usr/local/py-utils/bin/flake8",
"python.linting.mypyPath": "/usr/local/py-utils/bin/mypy",
"python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle",
"python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle",
"python.linting.pylintPath": "/usr/local/py-utils/bin/pylint",
"python.testing.pytestPath": "/usr/local/py-utils/bin/pytest"
},
"extensions": [
"mhutchie.git-graph",
],
"postCreateCommand": "pip install -r analysis-master/analysis-amd64/requirements.txt"
}

5
.gitignore vendored
View File

@@ -18,4 +18,7 @@ data analysis/arthur_pull.ipynb
data analysis/keys.txt data analysis/keys.txt
data analysis/check_for_new_matches.ipynb data analysis/check_for_new_matches.ipynb
data analysis/test.ipynb data analysis/test.ipynb
data analysis/visualize_pit.ipynb data analysis/visualize_pit.ipynb
data analysis/config/keys.config
analysis-master/analysis/__pycache__/
data analysis/__pycache__/

View File

@@ -1,6 +1,6 @@
Metadata-Version: 2.1 Metadata-Version: 2.1
Name: analysis Name: analysis
Version: 1.0.0.6 Version: 1.0.0.11
Summary: analysis package developed by Titan Scouting for The Red Alliance Summary: analysis package developed by Titan Scouting for The Red Alliance
Home-page: https://github.com/titanscout2022/tr2022-strategy Home-page: https://github.com/titanscout2022/tr2022-strategy
Author: The Titan Scouting Team Author: The Titan Scouting Team

View File

@@ -1,6 +1,7 @@
setup.py setup.py
analysis/__init__.py analysis/__init__.py
analysis/analysis.py analysis/analysis.py
analysis/glicko2.py
analysis/regression.py analysis/regression.py
analysis/titanlearn.py analysis/titanlearn.py
analysis/trueskill.py analysis/trueskill.py
@@ -8,4 +9,5 @@ analysis/visualization.py
analysis.egg-info/PKG-INFO analysis.egg-info/PKG-INFO
analysis.egg-info/SOURCES.txt analysis.egg-info/SOURCES.txt
analysis.egg-info/dependency_links.txt analysis.egg-info/dependency_links.txt
analysis.egg-info/requires.txt
analysis.egg-info/top_level.txt analysis.egg-info/top_level.txt

View File

@@ -0,0 +1,6 @@
numba
numpy
scipy
scikit-learn
six
matplotlib

View File

@@ -7,10 +7,26 @@
# current benchmark of optimization: 1.33 times faster # current benchmark of optimization: 1.33 times faster
# setup: # setup:
__version__ = "1.1.13.001" __version__ = "1.1.13.009"
# changelog should be viewed using print(analysis.__changelog__) # changelog should be viewed using print(analysis.__changelog__)
__changelog__ = """changelog: __changelog__ = """changelog:
1.1.13.009:
- moved elo, glicko2, trueskill functions under class Metrics
1.1.13.008:
- moved Glicko2 to a seperate package
1.1.13.007:
- fixed bug with trueskill
1.1.13.006:
- cleaned up imports
1.1.13.005:
- cleaned up package
1.1.13.004:
- small fixes to regression to improve performance
1.1.13.003:
- filtered nans from regression
1.1.13.002:
- removed torch requirement, and moved Regression back to regression.py
1.1.13.001: 1.1.13.001:
- bug fix with linear regression not returning a proper value - bug fix with linear regression not returning a proper value
- cleaned up regression - cleaned up regression
@@ -239,7 +255,6 @@ __author__ = (
) )
__all__ = [ __all__ = [
'_init_device',
'load_csv', 'load_csv',
'basic_stats', 'basic_stats',
'z_score', 'z_score',
@@ -260,8 +275,6 @@ __all__ = [
'SVM', 'SVM',
'random_forest_classifier', 'random_forest_classifier',
'random_forest_regressor', 'random_forest_regressor',
'Regression',
'Glicko2',
# all statistics functions left out due to integration in other functions # all statistics functions left out due to integration in other functions
] ]
@@ -270,27 +283,19 @@ __all__ = [
# imports (now in alphabetical order! v 1.0.3.006): # imports (now in alphabetical order! v 1.0.3.006):
import csv import csv
from analysis import glicko2 as Glicko2
import numba import numba
from numba import jit from numba import jit
import numpy as np import numpy as np
import math
import scipy import scipy
from scipy import * from scipy import *
import sklearn import sklearn
from sklearn import * from sklearn import *
import torch from analysis import trueskill as Trueskill
try:
from analysis import trueskill as Trueskill
except:
import trueskill as Trueskill
class error(ValueError): class error(ValueError):
pass pass
def _init_device(): # initiates computation device for ANNs
device = 'cuda:0' if torch.cuda.is_available() else 'cpu'
return device
def load_csv(filepath): def load_csv(filepath):
with open(filepath, newline='') as csvfile: with open(filepath, newline='') as csvfile:
file_array = np.array(list(csv.reader(csvfile))) file_array = np.array(list(csv.reader(csvfile)))
@@ -349,15 +354,15 @@ def histo_analysis(hist_data):
def regression(inputs, outputs, args): # inputs, outputs expects N-D array def regression(inputs, outputs, args): # inputs, outputs expects N-D array
X = np.array(inputs)
y = np.array(outputs)
regressions = [] regressions = []
if 'lin' in args: # formula: ax + b if 'lin' in args: # formula: ax + b
try: try:
X = np.array(inputs)
y = np.array(outputs)
def func(x, a, b): def func(x, a, b):
return a * x + b return a * x + b
@@ -374,9 +379,6 @@ def regression(inputs, outputs, args): # inputs, outputs expects N-D array
try: try:
X = np.array(inputs)
y = np.array(outputs)
def func(x, a, b, c, d): def func(x, a, b, c, d):
return a * np.log(b*(x + c)) + d return a * np.log(b*(x + c)) + d
@@ -391,10 +393,7 @@ def regression(inputs, outputs, args): # inputs, outputs expects N-D array
if 'exp' in args: # formula: a e ^ (b(x + c)) + d if 'exp' in args: # formula: a e ^ (b(x + c)) + d
try: try:
X = np.array(inputs)
y = np.array(outputs)
def func(x, a, b, c, d): def func(x, a, b, c, d):
@@ -410,8 +409,8 @@ def regression(inputs, outputs, args): # inputs, outputs expects N-D array
if 'ply' in args: # formula: a + bx^1 + cx^2 + dx^3 + ... if 'ply' in args: # formula: a + bx^1 + cx^2 + dx^3 + ...
inputs = [inputs] inputs = np.array([inputs])
outputs = [outputs] outputs = np.array([outputs])
plys = [] plys = []
limit = len(outputs[0]) limit = len(outputs[0])
@@ -433,10 +432,7 @@ def regression(inputs, outputs, args): # inputs, outputs expects N-D array
if 'sig' in args: # formula: a tanh (b(x + c)) + d if 'sig' in args: # formula: a tanh (b(x + c)) + d
try: try:
X = np.array(inputs)
y = np.array(outputs)
def func(x, a, b, c, d): def func(x, a, b, c, d):
@@ -452,32 +448,34 @@ def regression(inputs, outputs, args): # inputs, outputs expects N-D array
return regressions return regressions
def elo(starting_score, opposing_score, observed, N, K): class Metrics:
expected = 1/(1+10**((np.array(opposing_score) - starting_score)/N)) def elo(starting_score, opposing_score, observed, N, K):
return starting_score + K*(np.sum(observed) - np.sum(expected)) expected = 1/(1+10**((np.array(opposing_score) - starting_score)/N))
def glicko2(starting_score, starting_rd, starting_vol, opposing_score, opposing_rd, observations): return starting_score + K*(np.sum(observed) - np.sum(expected))
player = Glicko2(rating = starting_score, rd = starting_rd, vol = starting_vol) def glicko2(starting_score, starting_rd, starting_vol, opposing_score, opposing_rd, observations):
player.update_player([x for x in opposing_score], [x for x in opposing_rd], observations) player = Glicko2.Glicko2(rating = starting_score, rd = starting_rd, vol = starting_vol)
return (player.rating, player.rd, player.vol) player.update_player([x for x in opposing_score], [x for x in opposing_rd], observations)
def trueskill(teams_data, observations): # teams_data is array of array of tuples ie. [[(mu, sigma), (mu, sigma), (mu, sigma)], [(mu, sigma), (mu, sigma), (mu, sigma)]] return (player.rating, player.rd, player.vol)
team_ratings = [] def trueskill(teams_data, observations): # teams_data is array of array of tuples ie. [[(mu, sigma), (mu, sigma), (mu, sigma)], [(mu, sigma), (mu, sigma), (mu, sigma)]]
for team in teams_data: team_ratings = []
team_temp = []
for player in team:
player = Trueskill.Rating(player[0], player[1])
team_temp.append(player)
team_ratings.append(team_temp)
return Trueskill.rate(teams_data, observations) for team in teams_data:
team_temp = ()
for player in team:
player = Trueskill.Rating(player[0], player[1])
team_temp = team_temp + (player,)
team_ratings.append(team_temp)
return Trueskill.rate(team_ratings, ranks=observations)
class RegressionMetrics(): class RegressionMetrics():
@@ -569,24 +567,25 @@ def decisiontree(data, labels, test_size = 0.3, criterion = "gini", splitter = "
return model, metrics return model, metrics
@jit(forceobj=True) class KNN:
def knn_classifier(data, labels, test_size = 0.3, algorithm='auto', leaf_size=30, metric='minkowski', metric_params=None, n_jobs=None, n_neighbors=5, p=2, weights='uniform'): #expects *2d data and 1d labels post-scaling
data_train, data_test, labels_train, labels_test = sklearn.model_selection.train_test_split(data, labels, test_size=test_size, random_state=1) def knn_classifier(data, labels, test_size = 0.3, algorithm='auto', leaf_size=30, metric='minkowski', metric_params=None, n_jobs=None, n_neighbors=5, p=2, weights='uniform'): #expects *2d data and 1d labels post-scaling
model = sklearn.neighbors.KNeighborsClassifier()
model.fit(data_train, labels_train)
predictions = model.predict(data_test)
return model, ClassificationMetrics(predictions, labels_test) data_train, data_test, labels_train, labels_test = sklearn.model_selection.train_test_split(data, labels, test_size=test_size, random_state=1)
model = sklearn.neighbors.KNeighborsClassifier()
model.fit(data_train, labels_train)
predictions = model.predict(data_test)
def knn_regressor(data, outputs, test_size, n_neighbors = 5, weights = "uniform", algorithm = "auto", leaf_size = 30, p = 2, metric = "minkowski", metric_params = None, n_jobs = None): return model, ClassificationMetrics(predictions, labels_test)
data_train, data_test, outputs_train, outputs_test = sklearn.model_selection.train_test_split(data, outputs, test_size=test_size, random_state=1) def knn_regressor(data, outputs, test_size, n_neighbors = 5, weights = "uniform", algorithm = "auto", leaf_size = 30, p = 2, metric = "minkowski", metric_params = None, n_jobs = None):
model = sklearn.neighbors.KNeighborsRegressor(n_neighbors = n_neighbors, weights = weights, algorithm = algorithm, leaf_size = leaf_size, p = p, metric = metric, metric_params = metric_params, n_jobs = n_jobs)
model.fit(data_train, outputs_train)
predictions = model.predict(data_test)
return model, RegressionMetrics(predictions, outputs_test) data_train, data_test, outputs_train, outputs_test = sklearn.model_selection.train_test_split(data, outputs, test_size=test_size, random_state=1)
model = sklearn.neighbors.KNeighborsRegressor(n_neighbors = n_neighbors, weights = weights, algorithm = algorithm, leaf_size = leaf_size, p = p, metric = metric, metric_params = metric_params, n_jobs = n_jobs)
model.fit(data_train, outputs_train)
predictions = model.predict(data_test)
return model, RegressionMetrics(predictions, outputs_test)
class NaiveBayes: class NaiveBayes:
@@ -698,322 +697,4 @@ def random_forest_regressor(data, outputs, test_size, n_estimators="warn", crite
kernel.fit(data_train, outputs_train) kernel.fit(data_train, outputs_train)
predictions = kernel.predict(data_test) predictions = kernel.predict(data_test)
return kernel, RegressionMetrics(predictions, outputs_test) return kernel, RegressionMetrics(predictions, outputs_test)
class Regression:
# Titan Robotics Team 2022: CUDA-based Regressions Module
# Written by Arthur Lu & Jacob Levine
# Notes:
# this module has been automatically inegrated into analysis.py, and should be callable as a class from the package
# this module is cuda-optimized and vectorized (except for one small part)
# setup:
__version__ = "1.0.0.003"
# changelog should be viewed using print(analysis.regression.__changelog__)
__changelog__ = """
1.0.0.003:
- bug fixes
1.0.0.002:
-Added more parameters to log, exponential, polynomial
-Added SigmoidalRegKernelArthur, because Arthur apparently needs
to train the scaling and shifting of sigmoids
1.0.0.001:
-initial release, with linear, log, exponential, polynomial, and sigmoid kernels
-already vectorized (except for polynomial generation) and CUDA-optimized
"""
__author__ = (
"Jacob Levine <jlevine@imsa.edu>",
"Arthur Lu <learthurgo@gmail.com>"
)
__all__ = [
'factorial',
'take_all_pwrs',
'num_poly_terms',
'set_device',
'LinearRegKernel',
'SigmoidalRegKernel',
'LogRegKernel',
'PolyRegKernel',
'ExpRegKernel',
'SigmoidalRegKernelArthur',
'SGDTrain',
'CustomTrain'
]
global device
device = "cuda:0" if torch.torch.cuda.is_available() else "cpu"
#todo: document completely
def set_device(self, new_device):
device=new_device
class LinearRegKernel():
parameters= []
weights=None
bias=None
def __init__(self, num_vars):
self.weights=torch.rand(num_vars, requires_grad=True, device=device)
self.bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.bias]
def forward(self,mtx):
long_bias=self.bias.repeat([1,mtx.size()[1]])
return torch.matmul(self.weights,mtx)+long_bias
class SigmoidalRegKernel():
parameters= []
weights=None
bias=None
sigmoid=torch.nn.Sigmoid()
def __init__(self, num_vars):
self.weights=torch.rand(num_vars, requires_grad=True, device=device)
self.bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.bias]
def forward(self,mtx):
long_bias=self.bias.repeat([1,mtx.size()[1]])
return self.sigmoid(torch.matmul(self.weights,mtx)+long_bias)
class SigmoidalRegKernelArthur():
parameters= []
weights=None
in_bias=None
scal_mult=None
out_bias=None
sigmoid=torch.nn.Sigmoid()
def __init__(self, num_vars):
self.weights=torch.rand(num_vars, requires_grad=True, device=device)
self.in_bias=torch.rand(1, requires_grad=True, device=device)
self.scal_mult=torch.rand(1, requires_grad=True, device=device)
self.out_bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.in_bias, self.scal_mult, self.out_bias]
def forward(self,mtx):
long_in_bias=self.in_bias.repeat([1,mtx.size()[1]])
long_out_bias=self.out_bias.repeat([1,mtx.size()[1]])
return (self.scal_mult*self.sigmoid(torch.matmul(self.weights,mtx)+long_in_bias))+long_out_bias
class LogRegKernel():
parameters= []
weights=None
in_bias=None
scal_mult=None
out_bias=None
def __init__(self, num_vars):
self.weights=torch.rand(num_vars, requires_grad=True, device=device)
self.in_bias=torch.rand(1, requires_grad=True, device=device)
self.scal_mult=torch.rand(1, requires_grad=True, device=device)
self.out_bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.in_bias, self.scal_mult, self.out_bias]
def forward(self,mtx):
long_in_bias=self.in_bias.repeat([1,mtx.size()[1]])
long_out_bias=self.out_bias.repeat([1,mtx.size()[1]])
return (self.scal_mult*torch.log(torch.matmul(self.weights,mtx)+long_in_bias))+long_out_bias
class ExpRegKernel():
parameters= []
weights=None
in_bias=None
scal_mult=None
out_bias=None
def __init__(self, num_vars):
self.weights=torch.rand(num_vars, requires_grad=True, device=device)
self.in_bias=torch.rand(1, requires_grad=True, device=device)
self.scal_mult=torch.rand(1, requires_grad=True, device=device)
self.out_bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.in_bias, self.scal_mult, self.out_bias]
def forward(self,mtx):
long_in_bias=self.in_bias.repeat([1,mtx.size()[1]])
long_out_bias=self.out_bias.repeat([1,mtx.size()[1]])
return (self.scal_mult*torch.exp(torch.matmul(self.weights,mtx)+long_in_bias))+long_out_bias
class PolyRegKernel():
parameters= []
weights=None
bias=None
power=None
def __init__(self, num_vars, power):
self.power=power
num_terms=self.num_poly_terms(num_vars, power)
self.weights=torch.rand(num_terms, requires_grad=True, device=device)
self.bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.bias]
def num_poly_terms(self,num_vars, power):
if power == 0:
return 0
return int(self.factorial(num_vars+power-1) / self.factorial(power) / self.factorial(num_vars-1)) + self.num_poly_terms(num_vars, power-1)
def factorial(self,n):
if n==0:
return 1
else:
return n*self.factorial(n-1)
def take_all_pwrs(self, vec, pwr):
#todo: vectorize (kinda)
combins=torch.combinations(vec, r=pwr, with_replacement=True)
out=torch.ones(combins.size()[0]).to(device).to(torch.float)
for i in torch.t(combins).to(device).to(torch.float):
out *= i
if pwr == 1:
return out
else:
return torch.cat((out,self.take_all_pwrs(vec, pwr-1)))
def forward(self,mtx):
#TODO: Vectorize the last part
cols=[]
for i in torch.t(mtx):
cols.append(self.take_all_pwrs(i,self.power))
new_mtx=torch.t(torch.stack(cols))
long_bias=self.bias.repeat([1,mtx.size()[1]])
return torch.matmul(self.weights,new_mtx)+long_bias
def SGDTrain(self, kernel, data, ground, loss=torch.nn.MSELoss(), iterations=1000, learning_rate=.1, return_losses=False):
optim=torch.optim.SGD(kernel.parameters, lr=learning_rate)
data_cuda=data.to(device)
ground_cuda=ground.to(device)
if (return_losses):
losses=[]
for i in range(iterations):
with torch.set_grad_enabled(True):
optim.zero_grad()
pred=kernel.forward(data_cuda)
ls=loss(pred,ground_cuda)
losses.append(ls.item())
ls.backward()
optim.step()
return [kernel,losses]
else:
for i in range(iterations):
with torch.set_grad_enabled(True):
optim.zero_grad()
pred=kernel.forward(data_cuda)
ls=loss(pred,ground_cuda)
ls.backward()
optim.step()
return kernel
def CustomTrain(self, kernel, optim, data, ground, loss=torch.nn.MSELoss(), iterations=1000, return_losses=False):
data_cuda=data.to(device)
ground_cuda=ground.to(device)
if (return_losses):
losses=[]
for i in range(iterations):
with torch.set_grad_enabled(True):
optim.zero_grad()
pred=kernel.forward(data)
ls=loss(pred,ground)
losses.append(ls.item())
ls.backward()
optim.step()
return [kernel,losses]
else:
for i in range(iterations):
with torch.set_grad_enabled(True):
optim.zero_grad()
pred=kernel.forward(data_cuda)
ls=loss(pred,ground_cuda)
ls.backward()
optim.step()
return kernel
class Glicko2:
_tau = 0.5
def getRating(self):
return (self.__rating * 173.7178) + 1500
def setRating(self, rating):
self.__rating = (rating - 1500) / 173.7178
rating = property(getRating, setRating)
def getRd(self):
return self.__rd * 173.7178
def setRd(self, rd):
self.__rd = rd / 173.7178
rd = property(getRd, setRd)
def __init__(self, rating = 1500, rd = 350, vol = 0.06):
self.setRating(rating)
self.setRd(rd)
self.vol = vol
def _preRatingRD(self):
self.__rd = math.sqrt(math.pow(self.__rd, 2) + math.pow(self.vol, 2))
def update_player(self, rating_list, RD_list, outcome_list):
rating_list = [(x - 1500) / 173.7178 for x in rating_list]
RD_list = [x / 173.7178 for x in RD_list]
v = self._v(rating_list, RD_list)
self.vol = self._newVol(rating_list, RD_list, outcome_list, v)
self._preRatingRD()
self.__rd = 1 / math.sqrt((1 / math.pow(self.__rd, 2)) + (1 / v))
tempSum = 0
for i in range(len(rating_list)):
tempSum += self._g(RD_list[i]) * \
(outcome_list[i] - self._E(rating_list[i], RD_list[i]))
self.__rating += math.pow(self.__rd, 2) * tempSum
def _newVol(self, rating_list, RD_list, outcome_list, v):
i = 0
delta = self._delta(rating_list, RD_list, outcome_list, v)
a = math.log(math.pow(self.vol, 2))
tau = self._tau
x0 = a
x1 = 0
while x0 != x1:
# New iteration, so x(i) becomes x(i-1)
x0 = x1
d = math.pow(self.__rating, 2) + v + math.exp(x0)
h1 = -(x0 - a) / math.pow(tau, 2) - 0.5 * math.exp(x0) \
/ d + 0.5 * math.exp(x0) * math.pow(delta / d, 2)
h2 = -1 / math.pow(tau, 2) - 0.5 * math.exp(x0) * \
(math.pow(self.__rating, 2) + v) \
/ math.pow(d, 2) + 0.5 * math.pow(delta, 2) * math.exp(x0) \
* (math.pow(self.__rating, 2) + v - math.exp(x0)) / math.pow(d, 3)
x1 = x0 - (h1 / h2)
return math.exp(x1 / 2)
def _delta(self, rating_list, RD_list, outcome_list, v):
tempSum = 0
for i in range(len(rating_list)):
tempSum += self._g(RD_list[i]) * (outcome_list[i] - self._E(rating_list[i], RD_list[i]))
return v * tempSum
def _v(self, rating_list, RD_list):
tempSum = 0
for i in range(len(rating_list)):
tempE = self._E(rating_list[i], RD_list[i])
tempSum += math.pow(self._g(RD_list[i]), 2) * tempE * (1 - tempE)
return 1 / tempSum
def _E(self, p2rating, p2RD):
return 1 / (1 + math.exp(-1 * self._g(p2RD) * \
(self.__rating - p2rating)))
def _g(self, RD):
return 1 / math.sqrt(1 + 3 * math.pow(RD, 2) / math.pow(math.pi, 2))
def did_not_compete(self):
self._preRatingRD()

View File

@@ -0,0 +1,99 @@
import math
class Glicko2:
_tau = 0.5
def getRating(self):
return (self.__rating * 173.7178) + 1500
def setRating(self, rating):
self.__rating = (rating - 1500) / 173.7178
rating = property(getRating, setRating)
def getRd(self):
return self.__rd * 173.7178
def setRd(self, rd):
self.__rd = rd / 173.7178
rd = property(getRd, setRd)
def __init__(self, rating = 1500, rd = 350, vol = 0.06):
self.setRating(rating)
self.setRd(rd)
self.vol = vol
def _preRatingRD(self):
self.__rd = math.sqrt(math.pow(self.__rd, 2) + math.pow(self.vol, 2))
def update_player(self, rating_list, RD_list, outcome_list):
rating_list = [(x - 1500) / 173.7178 for x in rating_list]
RD_list = [x / 173.7178 for x in RD_list]
v = self._v(rating_list, RD_list)
self.vol = self._newVol(rating_list, RD_list, outcome_list, v)
self._preRatingRD()
self.__rd = 1 / math.sqrt((1 / math.pow(self.__rd, 2)) + (1 / v))
tempSum = 0
for i in range(len(rating_list)):
tempSum += self._g(RD_list[i]) * \
(outcome_list[i] - self._E(rating_list[i], RD_list[i]))
self.__rating += math.pow(self.__rd, 2) * tempSum
def _newVol(self, rating_list, RD_list, outcome_list, v):
i = 0
delta = self._delta(rating_list, RD_list, outcome_list, v)
a = math.log(math.pow(self.vol, 2))
tau = self._tau
x0 = a
x1 = 0
while x0 != x1:
# New iteration, so x(i) becomes x(i-1)
x0 = x1
d = math.pow(self.__rating, 2) + v + math.exp(x0)
h1 = -(x0 - a) / math.pow(tau, 2) - 0.5 * math.exp(x0) \
/ d + 0.5 * math.exp(x0) * math.pow(delta / d, 2)
h2 = -1 / math.pow(tau, 2) - 0.5 * math.exp(x0) * \
(math.pow(self.__rating, 2) + v) \
/ math.pow(d, 2) + 0.5 * math.pow(delta, 2) * math.exp(x0) \
* (math.pow(self.__rating, 2) + v - math.exp(x0)) / math.pow(d, 3)
x1 = x0 - (h1 / h2)
return math.exp(x1 / 2)
def _delta(self, rating_list, RD_list, outcome_list, v):
tempSum = 0
for i in range(len(rating_list)):
tempSum += self._g(RD_list[i]) * (outcome_list[i] - self._E(rating_list[i], RD_list[i]))
return v * tempSum
def _v(self, rating_list, RD_list):
tempSum = 0
for i in range(len(rating_list)):
tempE = self._E(rating_list[i], RD_list[i])
tempSum += math.pow(self._g(RD_list[i]), 2) * tempE * (1 - tempE)
return 1 / tempSum
def _E(self, p2rating, p2RD):
return 1 / (1 + math.exp(-1 * self._g(p2RD) * \
(self.__rating - p2rating)))
def _g(self, RD):
return 1 / math.sqrt(1 + 3 * math.pow(RD, 2) / math.pow(math.pi, 2))
def did_not_compete(self):
self._preRatingRD()

View File

@@ -1,20 +1,23 @@
# Titan Robotics Team 2022: CUDA-based Regressions Module # Titan Robotics Team 2022: CUDA-based Regressions Module
# Written by Arthur Lu & Jacob Levine # Written by Arthur Lu & Jacob Levine
# Notes: # Notes:
# this should be imported as a python module using 'import regression' # this module has been automatically inegrated into analysis.py, and should be callable as a class from the package
# this should be included in the local directory or environment variable # this module is cuda-optimized and vectorized (except for one small part)
# this module is cuda-optimized and vectorized (except for one small part)
# setup: # setup:
__version__ = "1.0.0.002" __version__ = "1.0.0.004"
# changelog should be viewed using print(regression.__changelog__) # changelog should be viewed using print(analysis.regression.__changelog__)
__changelog__ = """ __changelog__ = """
1.0.0.004:
- bug fixes
- fixed changelog
1.0.0.003:
- bug fixes
1.0.0.002: 1.0.0.002:
-Added more parameters to log, exponential, polynomial -Added more parameters to log, exponential, polynomial
-Added SigmoidalRegKernelArthur, because Arthur apparently needs -Added SigmoidalRegKernelArthur, because Arthur apparently needs
to train the scaling and shifting of sigmoids to train the scaling and shifting of sigmoids
1.0.0.001: 1.0.0.001:
-initial release, with linear, log, exponential, polynomial, and sigmoid kernels -initial release, with linear, log, exponential, polynomial, and sigmoid kernels
-already vectorized (except for polynomial generation) and CUDA-optimized -already vectorized (except for polynomial generation) and CUDA-optimized
@@ -22,6 +25,7 @@ __changelog__ = """
__author__ = ( __author__ = (
"Jacob Levine <jlevine@imsa.edu>", "Jacob Levine <jlevine@imsa.edu>",
"Arthur Lu <learthurgo@gmail.com>"
) )
__all__ = [ __all__ = [
@@ -39,35 +43,15 @@ __all__ = [
'CustomTrain' 'CustomTrain'
] ]
# imports (just one for now):
import torch import torch
global device
device = "cuda:0" if torch.torch.cuda.is_available() else "cpu" device = "cuda:0" if torch.torch.cuda.is_available() else "cpu"
#todo: document completely #todo: document completely
def factorial(n): def set_device(self, new_device):
if n==0:
return 1
else:
return n*factorial(n-1)
def num_poly_terms(num_vars, power):
if power == 0:
return 0
return int(factorial(num_vars+power-1) / factorial(power) / factorial(num_vars-1)) + num_poly_terms(num_vars, power-1)
def take_all_pwrs(vec,pwr):
#todo: vectorize (kinda)
combins=torch.combinations(vec, r=pwr, with_replacement=True)
out=torch.ones(combins.size()[0])
for i in torch.t(combins):
out *= i
return torch.cat(out,take_all_pwrs(vec, pwr-1))
def set_device(new_device):
global device
device=new_device device=new_device
class LinearRegKernel(): class LinearRegKernel():
@@ -154,20 +138,39 @@ class PolyRegKernel():
power=None power=None
def __init__(self, num_vars, power): def __init__(self, num_vars, power):
self.power=power self.power=power
num_terms=num_poly_terms(num_vars, power) num_terms=self.num_poly_terms(num_vars, power)
self.weights=torch.rand(num_terms, requires_grad=True, device=device) self.weights=torch.rand(num_terms, requires_grad=True, device=device)
self.bias=torch.rand(1, requires_grad=True, device=device) self.bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.bias] self.parameters=[self.weights,self.bias]
def num_poly_terms(self,num_vars, power):
if power == 0:
return 0
return int(self.factorial(num_vars+power-1) / self.factorial(power) / self.factorial(num_vars-1)) + self.num_poly_terms(num_vars, power-1)
def factorial(self,n):
if n==0:
return 1
else:
return n*self.factorial(n-1)
def take_all_pwrs(self, vec, pwr):
#todo: vectorize (kinda)
combins=torch.combinations(vec, r=pwr, with_replacement=True)
out=torch.ones(combins.size()[0]).to(device).to(torch.float)
for i in torch.t(combins).to(device).to(torch.float):
out *= i
if pwr == 1:
return out
else:
return torch.cat((out,self.take_all_pwrs(vec, pwr-1)))
def forward(self,mtx): def forward(self,mtx):
#TODO: Vectorize the last part #TODO: Vectorize the last part
cols=[] cols=[]
for i in torch.t(mtx): for i in torch.t(mtx):
cols.append(take_all_pwrs(i,self.power)) cols.append(self.take_all_pwrs(i,self.power))
new_mtx=torch.t(torch.stack(cols)) new_mtx=torch.t(torch.stack(cols))
long_bias=self.bias.repeat([1,mtx.size()[1]]) long_bias=self.bias.repeat([1,mtx.size()[1]])
return torch.matmul(self.weights,new_mtx)+long_bias return torch.matmul(self.weights,new_mtx)+long_bias
def SGDTrain(kernel, data, ground, loss=torch.nn.MSELoss(), iterations=1000, learning_rate=.1, return_losses=False): def SGDTrain(self, kernel, data, ground, loss=torch.nn.MSELoss(), iterations=1000, learning_rate=.1, return_losses=False):
optim=torch.optim.SGD(kernel.parameters, lr=learning_rate) optim=torch.optim.SGD(kernel.parameters, lr=learning_rate)
data_cuda=data.to(device) data_cuda=data.to(device)
ground_cuda=ground.to(device) ground_cuda=ground.to(device)
@@ -192,7 +195,7 @@ def SGDTrain(kernel, data, ground, loss=torch.nn.MSELoss(), iterations=1000, lea
optim.step() optim.step()
return kernel return kernel
def CustomTrain(kernel, optim, data, ground, loss=torch.nn.MSELoss(), iterations=1000, return_losses=False): def CustomTrain(self, kernel, optim, data, ground, loss=torch.nn.MSELoss(), iterations=1000, return_losses=False):
data_cuda=data.to(device) data_cuda=data.to(device)
ground_cuda=ground.to(device) ground_cuda=ground.to(device)
if (return_losses): if (return_losses):
@@ -214,4 +217,4 @@ def CustomTrain(kernel, optim, data, ground, loss=torch.nn.MSELoss(), iterations
ls=loss(pred,ground_cuda) ls=loss(pred,ground_cuda)
ls.backward() ls.backward()
optim.step() optim.step()
return kernel return kernel

View File

@@ -0,0 +1 @@
python setup.py sdist bdist_wheel || python3 setup.py sdist bdist_wheel

View File

@@ -7,10 +7,26 @@
# current benchmark of optimization: 1.33 times faster # current benchmark of optimization: 1.33 times faster
# setup: # setup:
__version__ = "1.1.13.001" __version__ = "1.1.13.009"
# changelog should be viewed using print(analysis.__changelog__) # changelog should be viewed using print(analysis.__changelog__)
__changelog__ = """changelog: __changelog__ = """changelog:
1.1.13.009:
- moved elo, glicko2, trueskill functions under class Metrics
1.1.13.008:
- moved Glicko2 to a seperate package
1.1.13.007:
- fixed bug with trueskill
1.1.13.006:
- cleaned up imports
1.1.13.005:
- cleaned up package
1.1.13.004:
- small fixes to regression to improve performance
1.1.13.003:
- filtered nans from regression
1.1.13.002:
- removed torch requirement, and moved Regression back to regression.py
1.1.13.001: 1.1.13.001:
- bug fix with linear regression not returning a proper value - bug fix with linear regression not returning a proper value
- cleaned up regression - cleaned up regression
@@ -239,7 +255,6 @@ __author__ = (
) )
__all__ = [ __all__ = [
'_init_device',
'load_csv', 'load_csv',
'basic_stats', 'basic_stats',
'z_score', 'z_score',
@@ -260,8 +275,6 @@ __all__ = [
'SVM', 'SVM',
'random_forest_classifier', 'random_forest_classifier',
'random_forest_regressor', 'random_forest_regressor',
'Regression',
'Glicko2',
# all statistics functions left out due to integration in other functions # all statistics functions left out due to integration in other functions
] ]
@@ -270,27 +283,19 @@ __all__ = [
# imports (now in alphabetical order! v 1.0.3.006): # imports (now in alphabetical order! v 1.0.3.006):
import csv import csv
from analysis import glicko2 as Glicko2
import numba import numba
from numba import jit from numba import jit
import numpy as np import numpy as np
import math
import scipy import scipy
from scipy import * from scipy import *
import sklearn import sklearn
from sklearn import * from sklearn import *
import torch from analysis import trueskill as Trueskill
try:
from analysis import trueskill as Trueskill
except:
import trueskill as Trueskill
class error(ValueError): class error(ValueError):
pass pass
def _init_device(): # initiates computation device for ANNs
device = 'cuda:0' if torch.cuda.is_available() else 'cpu'
return device
def load_csv(filepath): def load_csv(filepath):
with open(filepath, newline='') as csvfile: with open(filepath, newline='') as csvfile:
file_array = np.array(list(csv.reader(csvfile))) file_array = np.array(list(csv.reader(csvfile)))
@@ -349,15 +354,15 @@ def histo_analysis(hist_data):
def regression(inputs, outputs, args): # inputs, outputs expects N-D array def regression(inputs, outputs, args): # inputs, outputs expects N-D array
X = np.array(inputs)
y = np.array(outputs)
regressions = [] regressions = []
if 'lin' in args: # formula: ax + b if 'lin' in args: # formula: ax + b
try: try:
X = np.array(inputs)
y = np.array(outputs)
def func(x, a, b): def func(x, a, b):
return a * x + b return a * x + b
@@ -374,9 +379,6 @@ def regression(inputs, outputs, args): # inputs, outputs expects N-D array
try: try:
X = np.array(inputs)
y = np.array(outputs)
def func(x, a, b, c, d): def func(x, a, b, c, d):
return a * np.log(b*(x + c)) + d return a * np.log(b*(x + c)) + d
@@ -391,10 +393,7 @@ def regression(inputs, outputs, args): # inputs, outputs expects N-D array
if 'exp' in args: # formula: a e ^ (b(x + c)) + d if 'exp' in args: # formula: a e ^ (b(x + c)) + d
try: try:
X = np.array(inputs)
y = np.array(outputs)
def func(x, a, b, c, d): def func(x, a, b, c, d):
@@ -410,8 +409,8 @@ def regression(inputs, outputs, args): # inputs, outputs expects N-D array
if 'ply' in args: # formula: a + bx^1 + cx^2 + dx^3 + ... if 'ply' in args: # formula: a + bx^1 + cx^2 + dx^3 + ...
inputs = [inputs] inputs = np.array([inputs])
outputs = [outputs] outputs = np.array([outputs])
plys = [] plys = []
limit = len(outputs[0]) limit = len(outputs[0])
@@ -433,10 +432,7 @@ def regression(inputs, outputs, args): # inputs, outputs expects N-D array
if 'sig' in args: # formula: a tanh (b(x + c)) + d if 'sig' in args: # formula: a tanh (b(x + c)) + d
try: try:
X = np.array(inputs)
y = np.array(outputs)
def func(x, a, b, c, d): def func(x, a, b, c, d):
@@ -452,32 +448,34 @@ def regression(inputs, outputs, args): # inputs, outputs expects N-D array
return regressions return regressions
def elo(starting_score, opposing_score, observed, N, K): class Metrics:
expected = 1/(1+10**((np.array(opposing_score) - starting_score)/N)) def elo(starting_score, opposing_score, observed, N, K):
return starting_score + K*(np.sum(observed) - np.sum(expected)) expected = 1/(1+10**((np.array(opposing_score) - starting_score)/N))
def glicko2(starting_score, starting_rd, starting_vol, opposing_score, opposing_rd, observations): return starting_score + K*(np.sum(observed) - np.sum(expected))
player = Glicko2(rating = starting_score, rd = starting_rd, vol = starting_vol) def glicko2(starting_score, starting_rd, starting_vol, opposing_score, opposing_rd, observations):
player.update_player([x for x in opposing_score], [x for x in opposing_rd], observations) player = Glicko2.Glicko2(rating = starting_score, rd = starting_rd, vol = starting_vol)
return (player.rating, player.rd, player.vol) player.update_player([x for x in opposing_score], [x for x in opposing_rd], observations)
def trueskill(teams_data, observations): # teams_data is array of array of tuples ie. [[(mu, sigma), (mu, sigma), (mu, sigma)], [(mu, sigma), (mu, sigma), (mu, sigma)]] return (player.rating, player.rd, player.vol)
team_ratings = [] def trueskill(teams_data, observations): # teams_data is array of array of tuples ie. [[(mu, sigma), (mu, sigma), (mu, sigma)], [(mu, sigma), (mu, sigma), (mu, sigma)]]
for team in teams_data: team_ratings = []
team_temp = []
for player in team:
player = Trueskill.Rating(player[0], player[1])
team_temp.append(player)
team_ratings.append(team_temp)
return Trueskill.rate(teams_data, observations) for team in teams_data:
team_temp = ()
for player in team:
player = Trueskill.Rating(player[0], player[1])
team_temp = team_temp + (player,)
team_ratings.append(team_temp)
return Trueskill.rate(team_ratings, ranks=observations)
class RegressionMetrics(): class RegressionMetrics():
@@ -569,24 +567,25 @@ def decisiontree(data, labels, test_size = 0.3, criterion = "gini", splitter = "
return model, metrics return model, metrics
@jit(forceobj=True) class KNN:
def knn_classifier(data, labels, test_size = 0.3, algorithm='auto', leaf_size=30, metric='minkowski', metric_params=None, n_jobs=None, n_neighbors=5, p=2, weights='uniform'): #expects *2d data and 1d labels post-scaling
data_train, data_test, labels_train, labels_test = sklearn.model_selection.train_test_split(data, labels, test_size=test_size, random_state=1) def knn_classifier(data, labels, test_size = 0.3, algorithm='auto', leaf_size=30, metric='minkowski', metric_params=None, n_jobs=None, n_neighbors=5, p=2, weights='uniform'): #expects *2d data and 1d labels post-scaling
model = sklearn.neighbors.KNeighborsClassifier()
model.fit(data_train, labels_train)
predictions = model.predict(data_test)
return model, ClassificationMetrics(predictions, labels_test) data_train, data_test, labels_train, labels_test = sklearn.model_selection.train_test_split(data, labels, test_size=test_size, random_state=1)
model = sklearn.neighbors.KNeighborsClassifier()
model.fit(data_train, labels_train)
predictions = model.predict(data_test)
def knn_regressor(data, outputs, test_size, n_neighbors = 5, weights = "uniform", algorithm = "auto", leaf_size = 30, p = 2, metric = "minkowski", metric_params = None, n_jobs = None): return model, ClassificationMetrics(predictions, labels_test)
data_train, data_test, outputs_train, outputs_test = sklearn.model_selection.train_test_split(data, outputs, test_size=test_size, random_state=1) def knn_regressor(data, outputs, test_size, n_neighbors = 5, weights = "uniform", algorithm = "auto", leaf_size = 30, p = 2, metric = "minkowski", metric_params = None, n_jobs = None):
model = sklearn.neighbors.KNeighborsRegressor(n_neighbors = n_neighbors, weights = weights, algorithm = algorithm, leaf_size = leaf_size, p = p, metric = metric, metric_params = metric_params, n_jobs = n_jobs)
model.fit(data_train, outputs_train)
predictions = model.predict(data_test)
return model, RegressionMetrics(predictions, outputs_test) data_train, data_test, outputs_train, outputs_test = sklearn.model_selection.train_test_split(data, outputs, test_size=test_size, random_state=1)
model = sklearn.neighbors.KNeighborsRegressor(n_neighbors = n_neighbors, weights = weights, algorithm = algorithm, leaf_size = leaf_size, p = p, metric = metric, metric_params = metric_params, n_jobs = n_jobs)
model.fit(data_train, outputs_train)
predictions = model.predict(data_test)
return model, RegressionMetrics(predictions, outputs_test)
class NaiveBayes: class NaiveBayes:
@@ -698,322 +697,4 @@ def random_forest_regressor(data, outputs, test_size, n_estimators="warn", crite
kernel.fit(data_train, outputs_train) kernel.fit(data_train, outputs_train)
predictions = kernel.predict(data_test) predictions = kernel.predict(data_test)
return kernel, RegressionMetrics(predictions, outputs_test) return kernel, RegressionMetrics(predictions, outputs_test)
class Regression:
# Titan Robotics Team 2022: CUDA-based Regressions Module
# Written by Arthur Lu & Jacob Levine
# Notes:
# this module has been automatically inegrated into analysis.py, and should be callable as a class from the package
# this module is cuda-optimized and vectorized (except for one small part)
# setup:
__version__ = "1.0.0.003"
# changelog should be viewed using print(analysis.regression.__changelog__)
__changelog__ = """
1.0.0.003:
- bug fixes
1.0.0.002:
-Added more parameters to log, exponential, polynomial
-Added SigmoidalRegKernelArthur, because Arthur apparently needs
to train the scaling and shifting of sigmoids
1.0.0.001:
-initial release, with linear, log, exponential, polynomial, and sigmoid kernels
-already vectorized (except for polynomial generation) and CUDA-optimized
"""
__author__ = (
"Jacob Levine <jlevine@imsa.edu>",
"Arthur Lu <learthurgo@gmail.com>"
)
__all__ = [
'factorial',
'take_all_pwrs',
'num_poly_terms',
'set_device',
'LinearRegKernel',
'SigmoidalRegKernel',
'LogRegKernel',
'PolyRegKernel',
'ExpRegKernel',
'SigmoidalRegKernelArthur',
'SGDTrain',
'CustomTrain'
]
global device
device = "cuda:0" if torch.torch.cuda.is_available() else "cpu"
#todo: document completely
def set_device(self, new_device):
device=new_device
class LinearRegKernel():
parameters= []
weights=None
bias=None
def __init__(self, num_vars):
self.weights=torch.rand(num_vars, requires_grad=True, device=device)
self.bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.bias]
def forward(self,mtx):
long_bias=self.bias.repeat([1,mtx.size()[1]])
return torch.matmul(self.weights,mtx)+long_bias
class SigmoidalRegKernel():
parameters= []
weights=None
bias=None
sigmoid=torch.nn.Sigmoid()
def __init__(self, num_vars):
self.weights=torch.rand(num_vars, requires_grad=True, device=device)
self.bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.bias]
def forward(self,mtx):
long_bias=self.bias.repeat([1,mtx.size()[1]])
return self.sigmoid(torch.matmul(self.weights,mtx)+long_bias)
class SigmoidalRegKernelArthur():
parameters= []
weights=None
in_bias=None
scal_mult=None
out_bias=None
sigmoid=torch.nn.Sigmoid()
def __init__(self, num_vars):
self.weights=torch.rand(num_vars, requires_grad=True, device=device)
self.in_bias=torch.rand(1, requires_grad=True, device=device)
self.scal_mult=torch.rand(1, requires_grad=True, device=device)
self.out_bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.in_bias, self.scal_mult, self.out_bias]
def forward(self,mtx):
long_in_bias=self.in_bias.repeat([1,mtx.size()[1]])
long_out_bias=self.out_bias.repeat([1,mtx.size()[1]])
return (self.scal_mult*self.sigmoid(torch.matmul(self.weights,mtx)+long_in_bias))+long_out_bias
class LogRegKernel():
parameters= []
weights=None
in_bias=None
scal_mult=None
out_bias=None
def __init__(self, num_vars):
self.weights=torch.rand(num_vars, requires_grad=True, device=device)
self.in_bias=torch.rand(1, requires_grad=True, device=device)
self.scal_mult=torch.rand(1, requires_grad=True, device=device)
self.out_bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.in_bias, self.scal_mult, self.out_bias]
def forward(self,mtx):
long_in_bias=self.in_bias.repeat([1,mtx.size()[1]])
long_out_bias=self.out_bias.repeat([1,mtx.size()[1]])
return (self.scal_mult*torch.log(torch.matmul(self.weights,mtx)+long_in_bias))+long_out_bias
class ExpRegKernel():
parameters= []
weights=None
in_bias=None
scal_mult=None
out_bias=None
def __init__(self, num_vars):
self.weights=torch.rand(num_vars, requires_grad=True, device=device)
self.in_bias=torch.rand(1, requires_grad=True, device=device)
self.scal_mult=torch.rand(1, requires_grad=True, device=device)
self.out_bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.in_bias, self.scal_mult, self.out_bias]
def forward(self,mtx):
long_in_bias=self.in_bias.repeat([1,mtx.size()[1]])
long_out_bias=self.out_bias.repeat([1,mtx.size()[1]])
return (self.scal_mult*torch.exp(torch.matmul(self.weights,mtx)+long_in_bias))+long_out_bias
class PolyRegKernel():
parameters= []
weights=None
bias=None
power=None
def __init__(self, num_vars, power):
self.power=power
num_terms=self.num_poly_terms(num_vars, power)
self.weights=torch.rand(num_terms, requires_grad=True, device=device)
self.bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.bias]
def num_poly_terms(self,num_vars, power):
if power == 0:
return 0
return int(self.factorial(num_vars+power-1) / self.factorial(power) / self.factorial(num_vars-1)) + self.num_poly_terms(num_vars, power-1)
def factorial(self,n):
if n==0:
return 1
else:
return n*self.factorial(n-1)
def take_all_pwrs(self, vec, pwr):
#todo: vectorize (kinda)
combins=torch.combinations(vec, r=pwr, with_replacement=True)
out=torch.ones(combins.size()[0]).to(device).to(torch.float)
for i in torch.t(combins).to(device).to(torch.float):
out *= i
if pwr == 1:
return out
else:
return torch.cat((out,self.take_all_pwrs(vec, pwr-1)))
def forward(self,mtx):
#TODO: Vectorize the last part
cols=[]
for i in torch.t(mtx):
cols.append(self.take_all_pwrs(i,self.power))
new_mtx=torch.t(torch.stack(cols))
long_bias=self.bias.repeat([1,mtx.size()[1]])
return torch.matmul(self.weights,new_mtx)+long_bias
def SGDTrain(self, kernel, data, ground, loss=torch.nn.MSELoss(), iterations=1000, learning_rate=.1, return_losses=False):
optim=torch.optim.SGD(kernel.parameters, lr=learning_rate)
data_cuda=data.to(device)
ground_cuda=ground.to(device)
if (return_losses):
losses=[]
for i in range(iterations):
with torch.set_grad_enabled(True):
optim.zero_grad()
pred=kernel.forward(data_cuda)
ls=loss(pred,ground_cuda)
losses.append(ls.item())
ls.backward()
optim.step()
return [kernel,losses]
else:
for i in range(iterations):
with torch.set_grad_enabled(True):
optim.zero_grad()
pred=kernel.forward(data_cuda)
ls=loss(pred,ground_cuda)
ls.backward()
optim.step()
return kernel
def CustomTrain(self, kernel, optim, data, ground, loss=torch.nn.MSELoss(), iterations=1000, return_losses=False):
data_cuda=data.to(device)
ground_cuda=ground.to(device)
if (return_losses):
losses=[]
for i in range(iterations):
with torch.set_grad_enabled(True):
optim.zero_grad()
pred=kernel.forward(data)
ls=loss(pred,ground)
losses.append(ls.item())
ls.backward()
optim.step()
return [kernel,losses]
else:
for i in range(iterations):
with torch.set_grad_enabled(True):
optim.zero_grad()
pred=kernel.forward(data_cuda)
ls=loss(pred,ground_cuda)
ls.backward()
optim.step()
return kernel
class Glicko2:
_tau = 0.5
def getRating(self):
return (self.__rating * 173.7178) + 1500
def setRating(self, rating):
self.__rating = (rating - 1500) / 173.7178
rating = property(getRating, setRating)
def getRd(self):
return self.__rd * 173.7178
def setRd(self, rd):
self.__rd = rd / 173.7178
rd = property(getRd, setRd)
def __init__(self, rating = 1500, rd = 350, vol = 0.06):
self.setRating(rating)
self.setRd(rd)
self.vol = vol
def _preRatingRD(self):
self.__rd = math.sqrt(math.pow(self.__rd, 2) + math.pow(self.vol, 2))
def update_player(self, rating_list, RD_list, outcome_list):
rating_list = [(x - 1500) / 173.7178 for x in rating_list]
RD_list = [x / 173.7178 for x in RD_list]
v = self._v(rating_list, RD_list)
self.vol = self._newVol(rating_list, RD_list, outcome_list, v)
self._preRatingRD()
self.__rd = 1 / math.sqrt((1 / math.pow(self.__rd, 2)) + (1 / v))
tempSum = 0
for i in range(len(rating_list)):
tempSum += self._g(RD_list[i]) * \
(outcome_list[i] - self._E(rating_list[i], RD_list[i]))
self.__rating += math.pow(self.__rd, 2) * tempSum
def _newVol(self, rating_list, RD_list, outcome_list, v):
i = 0
delta = self._delta(rating_list, RD_list, outcome_list, v)
a = math.log(math.pow(self.vol, 2))
tau = self._tau
x0 = a
x1 = 0
while x0 != x1:
# New iteration, so x(i) becomes x(i-1)
x0 = x1
d = math.pow(self.__rating, 2) + v + math.exp(x0)
h1 = -(x0 - a) / math.pow(tau, 2) - 0.5 * math.exp(x0) \
/ d + 0.5 * math.exp(x0) * math.pow(delta / d, 2)
h2 = -1 / math.pow(tau, 2) - 0.5 * math.exp(x0) * \
(math.pow(self.__rating, 2) + v) \
/ math.pow(d, 2) + 0.5 * math.pow(delta, 2) * math.exp(x0) \
* (math.pow(self.__rating, 2) + v - math.exp(x0)) / math.pow(d, 3)
x1 = x0 - (h1 / h2)
return math.exp(x1 / 2)
def _delta(self, rating_list, RD_list, outcome_list, v):
tempSum = 0
for i in range(len(rating_list)):
tempSum += self._g(RD_list[i]) * (outcome_list[i] - self._E(rating_list[i], RD_list[i]))
return v * tempSum
def _v(self, rating_list, RD_list):
tempSum = 0
for i in range(len(rating_list)):
tempE = self._E(rating_list[i], RD_list[i])
tempSum += math.pow(self._g(RD_list[i]), 2) * tempE * (1 - tempE)
return 1 / tempSum
def _E(self, p2rating, p2RD):
return 1 / (1 + math.exp(-1 * self._g(p2RD) * \
(self.__rating - p2rating)))
def _g(self, RD):
return 1 / math.sqrt(1 + 3 * math.pow(RD, 2) / math.pow(math.pi, 2))
def did_not_compete(self):
self._preRatingRD()

View File

@@ -0,0 +1,99 @@
import math
class Glicko2:
_tau = 0.5
def getRating(self):
return (self.__rating * 173.7178) + 1500
def setRating(self, rating):
self.__rating = (rating - 1500) / 173.7178
rating = property(getRating, setRating)
def getRd(self):
return self.__rd * 173.7178
def setRd(self, rd):
self.__rd = rd / 173.7178
rd = property(getRd, setRd)
def __init__(self, rating = 1500, rd = 350, vol = 0.06):
self.setRating(rating)
self.setRd(rd)
self.vol = vol
def _preRatingRD(self):
self.__rd = math.sqrt(math.pow(self.__rd, 2) + math.pow(self.vol, 2))
def update_player(self, rating_list, RD_list, outcome_list):
rating_list = [(x - 1500) / 173.7178 for x in rating_list]
RD_list = [x / 173.7178 for x in RD_list]
v = self._v(rating_list, RD_list)
self.vol = self._newVol(rating_list, RD_list, outcome_list, v)
self._preRatingRD()
self.__rd = 1 / math.sqrt((1 / math.pow(self.__rd, 2)) + (1 / v))
tempSum = 0
for i in range(len(rating_list)):
tempSum += self._g(RD_list[i]) * \
(outcome_list[i] - self._E(rating_list[i], RD_list[i]))
self.__rating += math.pow(self.__rd, 2) * tempSum
def _newVol(self, rating_list, RD_list, outcome_list, v):
i = 0
delta = self._delta(rating_list, RD_list, outcome_list, v)
a = math.log(math.pow(self.vol, 2))
tau = self._tau
x0 = a
x1 = 0
while x0 != x1:
# New iteration, so x(i) becomes x(i-1)
x0 = x1
d = math.pow(self.__rating, 2) + v + math.exp(x0)
h1 = -(x0 - a) / math.pow(tau, 2) - 0.5 * math.exp(x0) \
/ d + 0.5 * math.exp(x0) * math.pow(delta / d, 2)
h2 = -1 / math.pow(tau, 2) - 0.5 * math.exp(x0) * \
(math.pow(self.__rating, 2) + v) \
/ math.pow(d, 2) + 0.5 * math.pow(delta, 2) * math.exp(x0) \
* (math.pow(self.__rating, 2) + v - math.exp(x0)) / math.pow(d, 3)
x1 = x0 - (h1 / h2)
return math.exp(x1 / 2)
def _delta(self, rating_list, RD_list, outcome_list, v):
tempSum = 0
for i in range(len(rating_list)):
tempSum += self._g(RD_list[i]) * (outcome_list[i] - self._E(rating_list[i], RD_list[i]))
return v * tempSum
def _v(self, rating_list, RD_list):
tempSum = 0
for i in range(len(rating_list)):
tempE = self._E(rating_list[i], RD_list[i])
tempSum += math.pow(self._g(RD_list[i]), 2) * tempE * (1 - tempE)
return 1 / tempSum
def _E(self, p2rating, p2RD):
return 1 / (1 + math.exp(-1 * self._g(p2RD) * \
(self.__rating - p2rating)))
def _g(self, RD):
return 1 / math.sqrt(1 + 3 * math.pow(RD, 2) / math.pow(math.pi, 2))
def did_not_compete(self):
self._preRatingRD()

View File

@@ -1,20 +1,23 @@
# Titan Robotics Team 2022: CUDA-based Regressions Module # Titan Robotics Team 2022: CUDA-based Regressions Module
# Written by Arthur Lu & Jacob Levine # Written by Arthur Lu & Jacob Levine
# Notes: # Notes:
# this should be imported as a python module using 'import regression' # this module has been automatically inegrated into analysis.py, and should be callable as a class from the package
# this should be included in the local directory or environment variable # this module is cuda-optimized and vectorized (except for one small part)
# this module is cuda-optimized and vectorized (except for one small part)
# setup: # setup:
__version__ = "1.0.0.002" __version__ = "1.0.0.004"
# changelog should be viewed using print(regression.__changelog__) # changelog should be viewed using print(analysis.regression.__changelog__)
__changelog__ = """ __changelog__ = """
1.0.0.004:
- bug fixes
- fixed changelog
1.0.0.003:
- bug fixes
1.0.0.002: 1.0.0.002:
-Added more parameters to log, exponential, polynomial -Added more parameters to log, exponential, polynomial
-Added SigmoidalRegKernelArthur, because Arthur apparently needs -Added SigmoidalRegKernelArthur, because Arthur apparently needs
to train the scaling and shifting of sigmoids to train the scaling and shifting of sigmoids
1.0.0.001: 1.0.0.001:
-initial release, with linear, log, exponential, polynomial, and sigmoid kernels -initial release, with linear, log, exponential, polynomial, and sigmoid kernels
-already vectorized (except for polynomial generation) and CUDA-optimized -already vectorized (except for polynomial generation) and CUDA-optimized
@@ -22,6 +25,7 @@ __changelog__ = """
__author__ = ( __author__ = (
"Jacob Levine <jlevine@imsa.edu>", "Jacob Levine <jlevine@imsa.edu>",
"Arthur Lu <learthurgo@gmail.com>"
) )
__all__ = [ __all__ = [
@@ -39,35 +43,15 @@ __all__ = [
'CustomTrain' 'CustomTrain'
] ]
# imports (just one for now):
import torch import torch
global device
device = "cuda:0" if torch.torch.cuda.is_available() else "cpu" device = "cuda:0" if torch.torch.cuda.is_available() else "cpu"
#todo: document completely #todo: document completely
def factorial(n): def set_device(self, new_device):
if n==0:
return 1
else:
return n*factorial(n-1)
def num_poly_terms(num_vars, power):
if power == 0:
return 0
return int(factorial(num_vars+power-1) / factorial(power) / factorial(num_vars-1)) + num_poly_terms(num_vars, power-1)
def take_all_pwrs(vec,pwr):
#todo: vectorize (kinda)
combins=torch.combinations(vec, r=pwr, with_replacement=True)
out=torch.ones(combins.size()[0])
for i in torch.t(combins):
out *= i
return torch.cat(out,take_all_pwrs(vec, pwr-1))
def set_device(new_device):
global device
device=new_device device=new_device
class LinearRegKernel(): class LinearRegKernel():
@@ -154,20 +138,39 @@ class PolyRegKernel():
power=None power=None
def __init__(self, num_vars, power): def __init__(self, num_vars, power):
self.power=power self.power=power
num_terms=num_poly_terms(num_vars, power) num_terms=self.num_poly_terms(num_vars, power)
self.weights=torch.rand(num_terms, requires_grad=True, device=device) self.weights=torch.rand(num_terms, requires_grad=True, device=device)
self.bias=torch.rand(1, requires_grad=True, device=device) self.bias=torch.rand(1, requires_grad=True, device=device)
self.parameters=[self.weights,self.bias] self.parameters=[self.weights,self.bias]
def num_poly_terms(self,num_vars, power):
if power == 0:
return 0
return int(self.factorial(num_vars+power-1) / self.factorial(power) / self.factorial(num_vars-1)) + self.num_poly_terms(num_vars, power-1)
def factorial(self,n):
if n==0:
return 1
else:
return n*self.factorial(n-1)
def take_all_pwrs(self, vec, pwr):
#todo: vectorize (kinda)
combins=torch.combinations(vec, r=pwr, with_replacement=True)
out=torch.ones(combins.size()[0]).to(device).to(torch.float)
for i in torch.t(combins).to(device).to(torch.float):
out *= i
if pwr == 1:
return out
else:
return torch.cat((out,self.take_all_pwrs(vec, pwr-1)))
def forward(self,mtx): def forward(self,mtx):
#TODO: Vectorize the last part #TODO: Vectorize the last part
cols=[] cols=[]
for i in torch.t(mtx): for i in torch.t(mtx):
cols.append(take_all_pwrs(i,self.power)) cols.append(self.take_all_pwrs(i,self.power))
new_mtx=torch.t(torch.stack(cols)) new_mtx=torch.t(torch.stack(cols))
long_bias=self.bias.repeat([1,mtx.size()[1]]) long_bias=self.bias.repeat([1,mtx.size()[1]])
return torch.matmul(self.weights,new_mtx)+long_bias return torch.matmul(self.weights,new_mtx)+long_bias
def SGDTrain(kernel, data, ground, loss=torch.nn.MSELoss(), iterations=1000, learning_rate=.1, return_losses=False): def SGDTrain(self, kernel, data, ground, loss=torch.nn.MSELoss(), iterations=1000, learning_rate=.1, return_losses=False):
optim=torch.optim.SGD(kernel.parameters, lr=learning_rate) optim=torch.optim.SGD(kernel.parameters, lr=learning_rate)
data_cuda=data.to(device) data_cuda=data.to(device)
ground_cuda=ground.to(device) ground_cuda=ground.to(device)
@@ -192,7 +195,7 @@ def SGDTrain(kernel, data, ground, loss=torch.nn.MSELoss(), iterations=1000, lea
optim.step() optim.step()
return kernel return kernel
def CustomTrain(kernel, optim, data, ground, loss=torch.nn.MSELoss(), iterations=1000, return_losses=False): def CustomTrain(self, kernel, optim, data, ground, loss=torch.nn.MSELoss(), iterations=1000, return_losses=False):
data_cuda=data.to(device) data_cuda=data.to(device)
ground_cuda=ground.to(device) ground_cuda=ground.to(device)
if (return_losses): if (return_losses):
@@ -214,4 +217,4 @@ def CustomTrain(kernel, optim, data, ground, loss=torch.nn.MSELoss(), iterations
ls=loss(pred,ground_cuda) ls=loss(pred,ground_cuda)
ls.backward() ls.backward()
optim.step() optim.step()
return kernel return kernel

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,5 @@
FROM python
WORKDIR ~/
COPY ./ ./
RUN pip install -r requirements.txt
CMD ["bash"]

View File

@@ -0,0 +1,3 @@
cd ..
docker build -t tra-analysis-amd64-dev -f docker/Dockerfile .
docker run -it tra-analysis-amd64-dev

View File

@@ -0,0 +1,6 @@
numba
numpy
scipy
scikit-learn
six
matplotlib

View File

@@ -1,8 +1,14 @@
import setuptools import setuptools
requirements = []
with open("requirements.txt", 'r') as file:
for line in file:
requirements.append(line)
setuptools.setup( setuptools.setup(
name="analysis", # Replace with your own username name="analysis",
version="1.0.0.006", version="1.0.0.011",
author="The Titan Scouting Team", author="The Titan Scouting Team",
author_email="titanscout2022@gmail.com", author_email="titanscout2022@gmail.com",
description="analysis package developed by Titan Scouting for The Red Alliance", description="analysis package developed by Titan Scouting for The Red Alliance",
@@ -10,6 +16,7 @@ setuptools.setup(
long_description_content_type="text/markdown", long_description_content_type="text/markdown",
url="https://github.com/titanscout2022/tr2022-strategy", url="https://github.com/titanscout2022/tr2022-strategy",
packages=setuptools.find_packages(), packages=setuptools.find_packages(),
install_requires=requirements,
license = "GNU General Public License v3.0", license = "GNU General Public License v3.0",
classifiers=[ classifiers=[
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",

View File

@@ -0,0 +1,3 @@
cd ..
docker build -t tra-analysis-amd64-dev -f docker/Dockerfile .
docker run -it tra-analysis-amd64-dev

View File

@@ -1 +0,0 @@
python3 setup.py sdist bdist_wheel

Binary file not shown.

View File

@@ -1,13 +0,0 @@
2020ilch
balls-blocked,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
balls-collected,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
balls-lower,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
balls-started,basic_stats,historical_analyss,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
balls-upper,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
wheel-mechanism
low-balls
high-balls
wheel-success
strategic-focus
climb-mechanism
attitude
1 2020ilch
2 balls-blocked,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
3 balls-collected,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
4 balls-lower,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
5 balls-started,basic_stats,historical_analyss,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
6 balls-upper,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
7 wheel-mechanism
8 low-balls
9 high-balls
10 wheel-success
11 strategic-focus
12 climb-mechanism
13 attitude

View File

@@ -0,0 +1 @@
2020ilch

View File

@@ -0,0 +1,14 @@
balls-blocked,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
balls-collected,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
balls-lower-teleop,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
balls-lower-auto,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
balls-started,basic_stats,historical_analyss,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
balls-upper-teleop,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
balls-upper-auto,basic_stats,historical_analysis,regression_linear,regression_logarithmic,regression_exponential,regression_polynomial,regression_sigmoidal
wheel-mechanism
low-balls
high-balls
wheel-success
strategic-focus
climb-mechanism
attitude

View File

@@ -0,0 +1,59 @@
import data as d
from analysis import analysis as an
import pymongo
import operator
def load_config(file):
config_vector = {}
file = an.load_csv(file)
for line in file[1:]:
config_vector[line[0]] = line[1:]
return (file[0][0], config_vector)
def get_metrics_processed_formatted(apikey, competition):
client = pymongo.MongoClient(apikey)
db = client.data_scouting
mdata = db.teamlist
x=mdata.find_one({"competition":competition})
out = {}
for i in x:
try:
out[int(i)] = d.get_team_metrics_data(apikey, competition, int(i))
except:
pass
return out
def main():
apikey = an.load_csv("keys.txt")[0][0]
tbakey = an.load_csv("keys.txt")[1][0]
competition, config = load_config("config.csv")
metrics = get_metrics_processed_formatted(apikey, competition)
elo = {}
gl2 = {}
for team in metrics:
elo[team] = metrics[team]["metrics"]["elo"]["score"]
gl2[team] = metrics[team]["metrics"]["gl2"]["score"]
elo = {k: v for k, v in sorted(elo.items(), key=lambda item: item[1])}
gl2 = {k: v for k, v in sorted(gl2.items(), key=lambda item: item[1])}
for team in elo:
print("teams sorted by elo:")
print("" + str(team) + " | " + str(elo[team]))
print("*"*25)
for team in gl2:
print("teams sorted by glicko2:")
print("" + str(team) + " | " + str(gl2[team]))
main()

View File

@@ -0,0 +1,4 @@
requests
pymongo
pandas
dnspython

View File

@@ -3,11 +3,28 @@
# Notes: # Notes:
# setup: # setup:
__version__ = "0.0.3.000" __version__ = "0.0.5.002"
# changelog should be viewed using print(analysis.__changelog__) # changelog should be viewed using print(analysis.__changelog__)
__changelog__ = """changelog: __changelog__ = """changelog:
0.0.3.00: 0.0.5.002:
- made changes due to refactoring of analysis
0.0.5.001:
- text fixes
- removed matplotlib requirement
0.0.5.000:
- improved user interface
0.0.4.002:
- removed unessasary code
0.0.4.001:
- fixed bug where X range for regression was determined before sanitization
- better sanitized data
0.0.4.000:
- fixed spelling issue in __changelog__
- addressed nan bug in regression
- fixed errors on line 335 with metrics calling incorrect key "glicko2"
- fixed errors in metrics computing
0.0.3.000:
- added analysis to pit data - added analysis to pit data
0.0.2.001: 0.0.2.001:
- minor stability patches - minor stability patches
@@ -71,7 +88,9 @@ __all__ = [
from analysis import analysis as an from analysis import analysis as an
import data as d import data as d
import matplotlib.pyplot as plt import numpy as np
from os import system, name
from pathlib import Path
import time import time
import warnings import warnings
@@ -80,16 +99,16 @@ def main():
while(True): while(True):
current_time = time.time() current_time = time.time()
print("time: " + str(current_time)) print("[OK] time: " + str(current_time))
print(" loading config") start = time.time()
competition, config = load_config("config.csv") config = load_config(Path("config/stats.config"))
print(" config loaded") competition = an.load_csv(Path("config/competition.config"))[0][0]
print("[OK] configs loaded")
print(" loading database keys") apikey = an.load_csv(Path("config/keys.config"))[0][0]
apikey = an.load_csv("keys.txt")[0][0] tbakey = an.load_csv(Path("config/keys.config"))[1][0]
tbakey = an.load_csv("keys.txt")[1][0] print("[OK] loaded keys")
print(" loaded keys")
previous_time = d.get_analysis_flags(apikey, "latest_update") previous_time = d.get_analysis_flags(apikey, "latest_update")
@@ -102,38 +121,55 @@ def main():
previous_time = previous_time["latest_update"] previous_time = previous_time["latest_update"]
print(" analysis backtimed to: " + str(previous_time)) print("[OK] analysis backtimed to: " + str(previous_time))
print(" loading data") print("[OK] loading data")
start = time.time()
data = d.get_match_data_formatted(apikey, competition) data = d.get_match_data_formatted(apikey, competition)
pit_data = d.pit = d.get_pit_data_formatted(apikey, competition) pit_data = d.pit = d.get_pit_data_formatted(apikey, competition)
print(" loaded data") print("[OK] loaded data in " + str(time.time() - start) + " seconds")
print(" running tests") print("[OK] running tests")
start = time.time()
results = simpleloop(data, config) results = simpleloop(data, config)
print(" finished tests") print("[OK] finished tests in " + str(time.time() - start) + " seconds")
print(" running metrics") print("[OK] running metrics")
metrics = metricsloop(tbakey, apikey, competition, previous_time) start = time.time()
print(" finished metrics") metricsloop(tbakey, apikey, competition, previous_time)
print("[OK] finished metrics in " + str(time.time() - start) + " seconds")
print(" running pit analysis") print("[OK] running pit analysis")
start = time.time()
pit = pitloop(pit_data, config) pit = pitloop(pit_data, config)
print(" finished pit analysis") print("[OK] finished pit analysis in " + str(time.time() - start) + " seconds")
d.set_analysis_flags(apikey, "latest_update", {"latest_update":current_time}) d.set_analysis_flags(apikey, "latest_update", {"latest_update":current_time})
print(" pushing to database") print("[OK] pushing to database")
push_to_database(apikey, competition, results, metrics, pit) start = time.time()
print(" pushed to database") push_to_database(apikey, competition, results, pit)
print("[OK] pushed to database in " + str(time.time() - start) + " seconds")
clear()
def clear():
# for windows
if name == 'nt':
_ = system('cls')
# for mac and linux(here, os.name is 'posix')
else:
_ = system('clear')
def load_config(file): def load_config(file):
config_vector = {} config_vector = {}
file = an.load_csv(file) file = an.load_csv(file)
for line in file[1:]: for line in file:
config_vector[line[0]] = line[1:] config_vector[line[0]] = line[1:]
return (file[0][0], config_vector) return config_vector
def simpleloop(data, tests): # expects 3D array with [Team][Variable][Match] def simpleloop(data, tests): # expects 3D array with [Team][Variable][Match]
@@ -155,37 +191,37 @@ def simpleloop(data, tests): # expects 3D array with [Team][Variable][Match]
def simplestats(data, test): def simplestats(data, test):
data = np.array(data)
data = data[np.isfinite(data)]
ranges = list(range(len(data)))
if(test == "basic_stats"): if(test == "basic_stats"):
return an.basic_stats(data) return an.basic_stats(data)
if(test == "historical_analysis"): if(test == "historical_analysis"):
return an.histo_analysis([list(range(len(data))), data]) return an.histo_analysis([ranges, data])
if(test == "regression_linear"): if(test == "regression_linear"):
return an.regression(list(range(len(data))), data, ['lin']) return an.regression(ranges, data, ['lin'])
if(test == "regression_logarithmic"): if(test == "regression_logarithmic"):
return an.regression(list(range(len(data))), data, ['log']) return an.regression(ranges, data, ['log'])
if(test == "regression_exponential"): if(test == "regression_exponential"):
return an.regression(list(range(len(data))), data, ['exp']) return an.regression(ranges, data, ['exp'])
if(test == "regression_polynomial"): if(test == "regression_polynomial"):
return an.regression(list(range(len(data))), data, ['ply']) return an.regression(ranges, data, ['ply'])
if(test == "regression_sigmoidal"): if(test == "regression_sigmoidal"):
return an.regression(list(range(len(data))), data, ['sig']) return an.regression(ranges, data, ['sig'])
def push_to_database(apikey, competition, results, metrics, pit): def push_to_database(apikey, competition, results, pit):
for team in results: for team in results:
d.push_team_tests_data(apikey, competition, team, results[team]) d.push_team_tests_data(apikey, competition, team, results[team])
for team in metrics:
d.push_team_metrics_data(apikey, competition, team, metrics[team])
for variable in pit: for variable in pit:
d.push_team_pit_data(apikey, competition, variable, pit[variable]) d.push_team_pit_data(apikey, competition, variable, pit[variable])
@@ -197,8 +233,6 @@ def metricsloop(tbakey, apikey, competition, timestamp): # listener based metric
matches = d.pull_new_tba_matches(tbakey, competition, timestamp) matches = d.pull_new_tba_matches(tbakey, competition, timestamp)
return_vector = {}
red = {} red = {}
blu = {} blu = {}
@@ -206,7 +240,7 @@ def metricsloop(tbakey, apikey, competition, timestamp): # listener based metric
red = load_metrics(apikey, competition, match, "red") red = load_metrics(apikey, competition, match, "red")
blu = load_metrics(apikey, competition, match, "blue") blu = load_metrics(apikey, competition, match, "blue")
elo_red_total = 0 elo_red_total = 0
elo_blu_total = 0 elo_blu_total = 0
@@ -254,11 +288,11 @@ def metricsloop(tbakey, apikey, competition, timestamp): # listener based metric
observations = {"red": 0.5, "blu": 0.5} observations = {"red": 0.5, "blu": 0.5}
red_elo_delta = an.elo(red_elo["score"], blu_elo["score"], observations["red"], elo_N, elo_K) - red_elo["score"] red_elo_delta = an.Metrics.elo(red_elo["score"], blu_elo["score"], observations["red"], elo_N, elo_K) - red_elo["score"]
blu_elo_delta = an.elo(blu_elo["score"], red_elo["score"], observations["blu"], elo_N, elo_K) - blu_elo["score"] blu_elo_delta = an.Metrics.elo(blu_elo["score"], red_elo["score"], observations["blu"], elo_N, elo_K) - blu_elo["score"]
new_red_gl2_score, new_red_gl2_rd, new_red_gl2_vol = an.glicko2(red_gl2["score"], red_gl2["rd"], red_gl2["vol"], [blu_gl2["score"]], [blu_gl2["rd"]], [observations["red"], observations["blu"]]) new_red_gl2_score, new_red_gl2_rd, new_red_gl2_vol = an.Metrics.glicko2(red_gl2["score"], red_gl2["rd"], red_gl2["vol"], [blu_gl2["score"]], [blu_gl2["rd"]], [observations["red"], observations["blu"]])
new_blu_gl2_score, new_blu_gl2_rd, new_blu_gl2_vol = an.glicko2(blu_gl2["score"], blu_gl2["rd"], blu_gl2["vol"], [red_gl2["score"]], [red_gl2["rd"]], [observations["blu"], observations["red"]]) new_blu_gl2_score, new_blu_gl2_rd, new_blu_gl2_vol = an.Metrics.glicko2(blu_gl2["score"], blu_gl2["rd"], blu_gl2["vol"], [red_gl2["score"]], [red_gl2["rd"]], [observations["blu"], observations["red"]])
red_gl2_delta = {"score": new_red_gl2_score - red_gl2["score"], "rd": new_red_gl2_rd - red_gl2["rd"], "vol": new_red_gl2_vol - red_gl2["vol"]} red_gl2_delta = {"score": new_red_gl2_score - red_gl2["score"], "rd": new_red_gl2_rd - red_gl2["rd"], "vol": new_red_gl2_vol - red_gl2["vol"]}
blu_gl2_delta = {"score": new_blu_gl2_score - blu_gl2["score"], "rd": new_blu_gl2_rd - blu_gl2["rd"], "vol": new_blu_gl2_vol - blu_gl2["vol"]} blu_gl2_delta = {"score": new_blu_gl2_score - blu_gl2["score"], "rd": new_blu_gl2_rd - blu_gl2["rd"], "vol": new_blu_gl2_vol - blu_gl2["vol"]}
@@ -279,36 +313,13 @@ def metricsloop(tbakey, apikey, competition, timestamp): # listener based metric
blu[team]["gl2"]["rd"] = blu[team]["gl2"]["rd"] + blu_gl2_delta["rd"] blu[team]["gl2"]["rd"] = blu[team]["gl2"]["rd"] + blu_gl2_delta["rd"]
blu[team]["gl2"]["vol"] = blu[team]["gl2"]["vol"] + blu_gl2_delta["vol"] blu[team]["gl2"]["vol"] = blu[team]["gl2"]["vol"] + blu_gl2_delta["vol"]
""" not functional for now temp_vector = {}
red_trueskill = [] temp_vector.update(red)
blu_trueskill = [] temp_vector.update(blu)
red_ts_team_lookup = [] for team in temp_vector:
blu_ts_team_lookup = []
for team in red: d.push_team_metrics_data(apikey, competition, team, temp_vector[team])
red_trueskill.append((red[team]["ts"]["mu"], red[team]["ts"]["sigma"]))
red_ts_team_lookup.append(team)
for team in blu:
blu_trueskill.append((blu[team]["ts"]["mu"], blu[team]["ts"]["sigma"]))
blu_ts_team_lookup.append(team)
print(red_trueskill)
print(blu_trueskill)
results = an.trueskill([red_trueskill, blu_trueskill], [observations["red"], observations["blu"]])
print(results)
"""
return_vector.update(red)
return_vector.update(blu)
return return_vector
def load_metrics(apikey, competition, match, group_name): def load_metrics(apikey, competition, match, group_name):
@@ -324,16 +335,17 @@ def load_metrics(apikey, competition, match, group_name):
gl2 = {"score": 1500, "rd": 250, "vol": 0.06} gl2 = {"score": 1500, "rd": 250, "vol": 0.06}
ts = {"mu": 25, "sigma": 25/3} ts = {"mu": 25, "sigma": 25/3}
d.push_team_metrics_data(apikey, competition, team, {"elo":elo, "gliko2":gl2,"trueskill":ts}) #d.push_team_metrics_data(apikey, competition, team, {"elo":elo, "gl2":gl2,"trueskill":ts})
group[team] = {"elo": elo, "gl2": gl2, "ts": ts} group[team] = {"elo": elo, "gl2": gl2, "ts": ts}
else: else:
metrics = db_data["metrics"] metrics = db_data["metrics"]
elo = metrics["elo"] elo = metrics["elo"]
gl2 = metrics["gliko2"] gl2 = metrics["gl2"]
ts = metrics["trueskill"] ts = metrics["ts"]
group[team] = {"elo": elo, "gl2": gl2, "ts": ts} group[team] = {"elo": elo, "gl2": gl2, "ts": ts}

View File

@@ -34,7 +34,7 @@ import numpy as np
# %% # %%
fig, ax = plt.subplots(1, len(pit), sharey=True, figsize=(20,10)) fig, ax = plt.subplots(1, len(pit), sharey=True, figsize=(80,15))
i = 0 i = 0