From aeb4990c81ab3ea16b8e20a7264c3b73a9e73d1c Mon Sep 17 00:00:00 2001 From: ltcptgeneral <35508619+ltcptgeneral@users.noreply.github.com> Date: Thu, 30 Apr 2020 16:03:37 -0500 Subject: [PATCH] analysis pkg v 1.0.0.12 analysis.py v 1.2.0.004 --- .../analysis-amd64/analysis.egg-info/PKG-INFO | 2 +- .../analysis.egg-info/SOURCES.txt | 8 +- .../analysis-amd64/analysis/analysis.py | 113 +-- .../build/lib/analysis/analysis.py | 263 ++++- .../build/lib/analysis/metrics/__init__.py | 0 .../build/lib/analysis/metrics/elo.py | 7 + .../build/lib/analysis/metrics/glicko2.py | 99 ++ .../build/lib/analysis/metrics/trueskill.py | 907 ++++++++++++++++++ .../dist/analysis-1.0.0.12-py3-none-any.whl | Bin 0 -> 32026 bytes .../dist/analysis-1.0.0.12.tar.gz | Bin 0 -> 21001 bytes analysis-master/analysis-amd64/setup.py | 2 +- 11 files changed, 1322 insertions(+), 79 deletions(-) create mode 100644 analysis-master/analysis-amd64/build/lib/analysis/metrics/__init__.py create mode 100644 analysis-master/analysis-amd64/build/lib/analysis/metrics/elo.py create mode 100644 analysis-master/analysis-amd64/build/lib/analysis/metrics/glicko2.py create mode 100644 analysis-master/analysis-amd64/build/lib/analysis/metrics/trueskill.py create mode 100644 analysis-master/analysis-amd64/dist/analysis-1.0.0.12-py3-none-any.whl create mode 100644 analysis-master/analysis-amd64/dist/analysis-1.0.0.12.tar.gz diff --git a/analysis-master/analysis-amd64/analysis.egg-info/PKG-INFO b/analysis-master/analysis-amd64/analysis.egg-info/PKG-INFO index 410189e2..83058193 100644 --- a/analysis-master/analysis-amd64/analysis.egg-info/PKG-INFO +++ b/analysis-master/analysis-amd64/analysis.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: analysis -Version: 1.0.0.11 +Version: 1.0.0.12 Summary: analysis package developed by Titan Scouting for The Red Alliance Home-page: https://github.com/titanscout2022/tr2022-strategy Author: The Titan Scouting Team diff --git a/analysis-master/analysis-amd64/analysis.egg-info/SOURCES.txt b/analysis-master/analysis-amd64/analysis.egg-info/SOURCES.txt index 25a54640..2d8be231 100644 --- a/analysis-master/analysis-amd64/analysis.egg-info/SOURCES.txt +++ b/analysis-master/analysis-amd64/analysis.egg-info/SOURCES.txt @@ -1,13 +1,15 @@ setup.py analysis/__init__.py analysis/analysis.py -analysis/glicko2.py analysis/regression.py analysis/titanlearn.py -analysis/trueskill.py analysis/visualization.py analysis.egg-info/PKG-INFO analysis.egg-info/SOURCES.txt analysis.egg-info/dependency_links.txt analysis.egg-info/requires.txt -analysis.egg-info/top_level.txt \ No newline at end of file +analysis.egg-info/top_level.txt +analysis/metrics/__init__.py +analysis/metrics/elo.py +analysis/metrics/glicko2.py +analysis/metrics/trueskill.py \ No newline at end of file diff --git a/analysis-master/analysis-amd64/analysis/analysis.py b/analysis-master/analysis-amd64/analysis/analysis.py index eb898a1a..c13aef90 100644 --- a/analysis-master/analysis-amd64/analysis/analysis.py +++ b/analysis-master/analysis-amd64/analysis/analysis.py @@ -7,10 +7,17 @@ # current benchmark of optimization: 1.33 times faster # setup: -__version__ = "1.2.0.003" +__version__ = "1.2.0.004" # changelog should be viewed using print(analysis.__changelog__) __changelog__ = """changelog: + 1.2.0.004: + - fixed __all__ to reflected the correct functions and classes + - fixed CorrelationTests and StatisticalTests class functions to require self invocation + - added missing math import + - fixed KNN class functions to require self invocation + - fixed Metrics class functions to require self invocation + - various spelling fixes in CorrelationTests and StatisticalTests 1.2.0.003: - bug fixes with CorrelationTests and StatisticalTests - moved glicko2 and trueskill to the metrics subpackage @@ -275,22 +282,19 @@ __all__ = [ 'z_normalize', 'histo_analysis', 'regression', - 'elo', - 'glicko2', - 'trueskill', + 'Metrics', 'RegressionMetrics', 'ClassificationMetrics', 'kmeans', 'pca', 'decisiontree', - 'knn_classifier', - 'knn_regressor', + 'KNN', 'NaiveBayes', 'SVM', 'random_forest_classifier', 'random_forest_regressor', 'CorrelationTests', - 'RegressionTests', + 'StatisticalTests', # all statistics functions left out due to integration in other functions ] @@ -301,6 +305,7 @@ __all__ = [ import csv from analysis.metrics import elo as Elo from analysis.metrics import glicko2 as Glicko2 +import math import numba from numba import jit import numpy as np @@ -467,11 +472,11 @@ def regression(inputs, outputs, args): # inputs, outputs expects N-D array class Metrics: - def elo(starting_score, opposing_score, observed, N, K): + def elo(self, starting_score, opposing_score, observed, N, K): return Elo.calculate(starting_score, opposing_score, observed, N, K) - def glicko2(starting_score, starting_rd, starting_vol, opposing_score, opposing_rd, observations): + def glicko2(self, starting_score, starting_rd, starting_vol, opposing_score, opposing_rd, observations): player = Glicko2.Glicko2(rating = starting_score, rd = starting_rd, vol = starting_vol) @@ -479,7 +484,7 @@ class Metrics: return (player.rating, player.rd, player.vol) - 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)]] + def trueskill(self, teams_data, observations): # teams_data is array of array of tuples ie. [[(mu, sigma), (mu, sigma), (mu, sigma)], [(mu, sigma), (mu, sigma), (mu, sigma)]] team_ratings = [] @@ -584,7 +589,7 @@ def decisiontree(data, labels, test_size = 0.3, criterion = "gini", splitter = " 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 + def knn_classifier(self, 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) model = sklearn.neighbors.KNeighborsClassifier() @@ -593,7 +598,7 @@ class KNN: return model, ClassificationMetrics(predictions, labels_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): + def knn_regressor(self, data, outputs, test_size, n_neighbors = 5, weights = "uniform", algorithm = "auto", leaf_size = 30, p = 2, metric = "minkowski", metric_params = None, n_jobs = None): 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) @@ -716,203 +721,203 @@ def random_forest_regressor(data, outputs, test_size, n_estimators="warn", crite class CorrelationTests: - def anova_oneway(*args): #expects arrays of samples + def anova_oneway(self, *args): #expects arrays of samples results = scipy.stats.f_oneway(*args) return {"F-value": results[0], "p-value": results[1]} - def pearson(x, y): + def pearson(self, x, y): results = scipy.stats.pearsonr(x, y) return {"r-value": results[0], "p-value": results[1]} - def spearman(a, b = None, axis = 0, nan_policy = 'propagate'): + def spearman(self, a, b = None, axis = 0, nan_policy = 'propagate'): results = scipy.stats.spearmanr(a, b = b, axis = axis, nan_policy = nan_policy) return {"r-value": results[0], "p-value": results[1]} - def point_biserial(x,y): + def point_biserial(self, x,y): results = scipy.stats.pointbiserialr(x, y) return {"r-value": results[0], "p-value": results[1]} - def kendall(x, y, initial_lexsort = None, nan_policy = 'propagate', method = 'auto'): + def kendall(self, x, y, initial_lexsort = None, nan_policy = 'propagate', method = 'auto'): results = scipy.stats.kendalltau(x, y, initial_lexsort = initial_lexsort, nan_policy = nan_policy, method = method) return {"tau": results[0], "p-value": results[1]} - def kendall_weighted(x, y, rank = True, weigher = None, additive = True): + def kendall_weighted(self, x, y, rank = True, weigher = None, additive = True): results = scipy.stats.weightedtau(x, y, rank = rank, weigher = weigher, additive = additive) return {"tau": results[0], "p-value": results[1]} - def mgc(x, y, compute_distance = None, reps = 1000, workers = 1, is_twosamp = False, random_state = None): + def mgc(self, x, y, compute_distance = None, reps = 1000, workers = 1, is_twosamp = False, random_state = None): results = scipy.stats.multiscale_graphcorr(x, y, compute_distance = compute_distance, reps = reps, workers = workers, is_twosamp = is_twosamp, random_state = random_state) return {"k-value": results[0], "p-value": results[1], "data": results[2]} # unsure if MGC test returns a k value class StatisticalTests: - def ttest_onesample(a, popmean, axis = 0, nan_policy = 'propagate'): + def ttest_onesample(self, a, popmean, axis = 0, nan_policy = 'propagate'): results = scipy.stats.ttest_1samp(a, popmean, axis = axis, nan_policy = nan_policy) return {"t-value": results[0], "p-value": results[1]} - def ttest_independent(a, b, equal = True, nan_policy = 'propagate'): + def ttest_independent(self, a, b, equal = True, nan_policy = 'propagate'): - results = scipt.stats.ttest_ind(a, b, equal_var = equal, nan_policy = nan_policy) + results = scipy.stats.ttest_ind(a, b, equal_var = equal, nan_policy = nan_policy) return {"t-value": results[0], "p-value": results[1]} - def ttest_statistic(o1, o2, equal = True): + def ttest_statistic(self, o1, o2, equal = True): results = scipy.stats.ttest_ind_from_stats(o1["mean"], o1["std"], o1["nobs"], o2["mean"], o2["std"], o2["nobs"], equal_var = equal) return {"t-value": results[0], "p-value": results[1]} - def ttest_related(a, b, axis = 0, nan_policy='propagate'): + def ttest_related(self, a, b, axis = 0, nan_policy='propagate'): results = scipy.stats.ttest_rel(a, b, axis = axis, nan_policy = nan_policy) return {"t-value": results[0], "p-value": results[1]} - def ks_fitness(rvs, cdf, args = (), N = 20, alternative = 'two-sided', mode = 'approx'): + def ks_fitness(self, rvs, cdf, args = (), N = 20, alternative = 'two-sided', mode = 'approx'): results = scipy.stats.kstest(rvs, cdf, args = args, N = N, alternative = alternative, mode = mode) return {"ks-value": results[0], "p-value": results[1]} - def chisquare(f_obs, f_exp = None, ddof = None, axis = 0): + def chisquare(self, f_obs, f_exp = None, ddof = None, axis = 0): results = scipy.stats.chisquare(f_obs, f_exp = f_exp, ddof = ddof, axis = axis) return {"chisquared-value": results[0], "p-value": results[1]} - def powerdivergence(f_obs, f_exp = None, ddof = None, axis = 0, lambda_ = None): + def powerdivergence(self, f_obs, f_exp = None, ddof = None, axis = 0, lambda_ = None): results = scipy.stats.power_divergence(f_obs, f_exp = f_exp, ddof = ddof, axis = axis, lambda_ = lambda_) return {"powerdivergence-value": results[0], "p-value": results[1]} - def ks_twosample(x, y, alternative = 'two_sided', mode = 'auto'): + def ks_twosample(self, x, y, alternative = 'two_sided', mode = 'auto'): results = scipy.stats.ks_2samp(x, y, alternative = alternative, mode = mode) return {"ks-value": results[0], "p-value": results[1]} - def es_twosample(x, y, t = (0.4, 0.8)): + def es_twosample(self, x, y, t = (0.4, 0.8)): results = scipy.stats.epps_singleton_2samp(x, y, t = t) return {"es-value": results[0], "p-value": results[1]} - def mw_rank(x, y, use_continuity = True, alternative = None): + def mw_rank(self, x, y, use_continuity = True, alternative = None): results = scipy.stats.mannwhitneyu(x, y, use_continuity = use_continuity, alternative = alternative) return {"u-value": results[0], "p-value": results[1]} - def mw_tiecorrection(rank_values): + def mw_tiecorrection(self, rank_values): results = scipy.stats.tiecorrect(rank_values) return {"correction-factor": results} - def rankdata(a, method = 'average'): + def rankdata(self, a, method = 'average'): results = scipy.stats.rankdata(a, method = method) return results - def wilcoxon_ranksum(a, b): # this seems to be superceded by Mann Whitney Wilcoxon U Test + def wilcoxon_ranksum(self, a, b): # this seems to be superceded by Mann Whitney Wilcoxon U Test results = scipy.stats.ranksums(a, b) return {"u-value": results[0], "p-value": results[1]} - def wilcoxon_signedrank(x, y = None, method = 'wilcox', correction = False, alternative = 'two-sided'): + def wilcoxon_signedrank(self, x, y = None, zero_method = 'wilcox', correction = False, alternative = 'two-sided'): - results = scipy.stats.wilcoxon(x, y = y, method = method, correction = correction, alternative = alternative) + results = scipy.stats.wilcoxon(x, y = y, zero_method = zero_method, correction = correction, alternative = alternative) return {"t-value": results[0], "p-value": results[1]} - def kw_htest(*args, nan_policy = 'propagate'): + def kw_htest(self, *args, nan_policy = 'propagate'): results = scipy.stats.kruskal(*args, nan_policy = nan_policy) return {"h-value": results[0], "p-value": results[1]} - def friedman_chisquare(*args): + def friedman_chisquare(self, *args): results = scipy.stats.friedmanchisquare(*args) return {"chisquared-value": results[0], "p-value": results[1]} - def bm_wtest(x, y, alternative = 'two-sided', distribution = 't', nan_policy = 'propagate'): + def bm_wtest(self, x, y, alternative = 'two-sided', distribution = 't', nan_policy = 'propagate'): results = scipy.stats.brunnermunzel(x, y, alternative = alternative, distribution = distribution, nan_policy = nan_policy) return {"w-value": results[0], "p-value": results[1]} - def combine_pvalues(pvalues, method = 'fisher', weights = None): + def combine_pvalues(self, pvalues, method = 'fisher', weights = None): results = scipy.stats.combine_pvalues(pvalues, method = method, weights = weights) return {"combined-statistic": results[0], "p-value": results[1]} - def jb_fitness(x): + def jb_fitness(self, x): results = scipy.stats.jarque_bera(x) return {"jb-value": results[0], "p-value": results[1]} - def ab_equality(x, y): + def ab_equality(self, x, y): results = scipy.stats.ansari(x, y) return {"ab-value": results[0], "p-value": results[1]} - def bartlett_variance(*args): + def bartlett_variance(self, *args): results = scipy.stats.bartlett(*args) return {"t-value": results[0], "p-value": results[1]} - def levene_variance(*args, center = 'median', proportiontocut = 0.05): + def levene_variance(self, *args, center = 'median', proportiontocut = 0.05): results = scipy.stats.levene(*args, center = center, proportiontocut = proportiontocut) return {"w-value": results[0], "p-value": results[1]} - def sw_normality(x): + def sw_normality(self, x): results = scipy.stats.shapiro(x) return {"w-value": results[0], "p-value": results[1]} - def shapiro(x): + def shapiro(self, x): return "destroyed by facts and logic" - def ad_onesample(x, dist = 'norm'): + def ad_onesample(self, x, dist = 'norm'): results = scipy.stats.anderson(x, dist = dist) return {"d-value": results[0], "critical-values": results[1], "significance-value": results[2]} - def ad_ksample(samples, midrank = True): + def ad_ksample(self, samples, midrank = True): results = scipy.stats.anderson_ksamp(samples, midrank = midrank) return {"d-value": results[0], "critical-values": results[1], "significance-value": results[2]} - def binomial(x, n = None, p = 0.5, alternative = 'two-sided'): + def binomial(self, x, n = None, p = 0.5, alternative = 'two-sided'): results = scipy.stats.binom_test(x, n = n, p = p, alternative = alternative) return {"p-value": results} - def fk_variance(*args, center = 'median', proportiontocut = 0.05): + def fk_variance(self, *args, center = 'median', proportiontocut = 0.05): results = scipy.stats.fligner(*args, center = center, proportiontocut = proportiontocut) return {"h-value": results[0], "p-value": results[1]} # unknown if the statistic is an h value - def mood_mediantest(*args, ties = 'below', correction = True, lambda_ = 1, nan_policy = 'propagate'): + def mood_mediantest(self, *args, ties = 'below', correction = True, lambda_ = 1, nan_policy = 'propagate'): results = scipy.stats.median_test(*args, ties = ties, correction = correction, lambda_ = lambda_, nan_policy = nan_policy) return {"chisquared-value": results[0], "p-value": results[1], "m-value": results[2], "table": results[3]} - def mood_equalscale(x, y, axis = 0): + def mood_equalscale(self, x, y, axis = 0): results = scipy.stats.mood(x, y, axis = axis) return {"z-score": results[0], "p-value": results[1]} - def skewtest(a, axis = 0, nan_policy = 'propogate'): + def skewtest(self, a, axis = 0, nan_policy = 'propogate'): results = scipy.stats.skewtest(a, axis = axis, nan_policy = nan_policy) return {"z-score": results[0], "p-value": results[1]} - def kurtosistest(a, axis = 0, nan_policy = 'propogate'): + def kurtosistest(self, a, axis = 0, nan_policy = 'propogate'): results = scipy.stats.kurtosistest(a, axis = axis, nan_policy = nan_policy) return {"z-score": results[0], "p-value": results[1]} - def normaltest(a, axis = 0, nan_policy = 'propogate'): + def normaltest(self, a, axis = 0, nan_policy = 'propogate'): results = scipy.stats.normaltest(a, axis = axis, nan_policy = nan_policy) return {"z-score": results[0], "p-value": results[1]} \ No newline at end of file diff --git a/analysis-master/analysis-amd64/build/lib/analysis/analysis.py b/analysis-master/analysis-amd64/build/lib/analysis/analysis.py index 944dd0c7..c13aef90 100644 --- a/analysis-master/analysis-amd64/build/lib/analysis/analysis.py +++ b/analysis-master/analysis-amd64/build/lib/analysis/analysis.py @@ -1,16 +1,37 @@ # Titan Robotics Team 2022: Data Analysis Module # Written by Arthur Lu & Jacob Levine # Notes: -# this should be imported as a python module using 'import analysis' +# this should be imported as a python module using 'from analysis import analysis' # this should be included in the local directory or environment variable # this module has been optimized for multhreaded computing # current benchmark of optimization: 1.33 times faster # setup: -__version__ = "1.1.13.009" +__version__ = "1.2.0.004" # changelog should be viewed using print(analysis.__changelog__) __changelog__ = """changelog: + 1.2.0.004: + - fixed __all__ to reflected the correct functions and classes + - fixed CorrelationTests and StatisticalTests class functions to require self invocation + - added missing math import + - fixed KNN class functions to require self invocation + - fixed Metrics class functions to require self invocation + - various spelling fixes in CorrelationTests and StatisticalTests + 1.2.0.003: + - bug fixes with CorrelationTests and StatisticalTests + - moved glicko2 and trueskill to the metrics subpackage + - moved elo to a new metrics subpackage + 1.2.0.002: + - fixed docs + 1.2.0.001: + - fixed docs + 1.2.0.000: + - cleaned up wild card imports with scipy and sklearn + - added CorrelationTests class + - added StatisticalTests class + - added several correlation tests to CorrelationTests + - added several statistical tests to StatisticalTests 1.1.13.009: - moved elo, glicko2, trueskill functions under class Metrics 1.1.13.008: @@ -261,20 +282,19 @@ __all__ = [ 'z_normalize', 'histo_analysis', 'regression', - 'elo', - 'glicko2', - 'trueskill', + 'Metrics', 'RegressionMetrics', 'ClassificationMetrics', 'kmeans', 'pca', 'decisiontree', - 'knn_classifier', - 'knn_regressor', + 'KNN', 'NaiveBayes', 'SVM', 'random_forest_classifier', 'random_forest_regressor', + 'CorrelationTests', + 'StatisticalTests', # all statistics functions left out due to integration in other functions ] @@ -283,15 +303,17 @@ __all__ = [ # imports (now in alphabetical order! v 1.0.3.006): import csv -from analysis import glicko2 as Glicko2 +from analysis.metrics import elo as Elo +from analysis.metrics import glicko2 as Glicko2 +import math import numba from numba import jit import numpy as np import scipy -from scipy import * +from scipy import optimize, stats import sklearn -from sklearn import * -from analysis import trueskill as Trueskill +from sklearn import preprocessing, pipeline, linear_model, metrics, cluster, decomposition, tree, neighbors, naive_bayes, svm, model_selection, ensemble +from analysis.metrics import trueskill as Trueskill class error(ValueError): pass @@ -450,13 +472,11 @@ def regression(inputs, outputs, args): # inputs, outputs expects N-D array class Metrics: - def elo(starting_score, opposing_score, observed, N, K): + def elo(self, starting_score, opposing_score, observed, N, K): - expected = 1/(1+10**((np.array(opposing_score) - starting_score)/N)) + return Elo.calculate(starting_score, opposing_score, observed, N, K) - return starting_score + K*(np.sum(observed) - np.sum(expected)) - - def glicko2(starting_score, starting_rd, starting_vol, opposing_score, opposing_rd, observations): + def glicko2(self, starting_score, starting_rd, starting_vol, opposing_score, opposing_rd, observations): player = Glicko2.Glicko2(rating = starting_score, rd = starting_rd, vol = starting_vol) @@ -464,7 +484,7 @@ class Metrics: return (player.rating, player.rd, player.vol) - 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)]] + def trueskill(self, teams_data, observations): # teams_data is array of array of tuples ie. [[(mu, sigma), (mu, sigma), (mu, sigma)], [(mu, sigma), (mu, sigma), (mu, sigma)]] team_ratings = [] @@ -569,7 +589,7 @@ def decisiontree(data, labels, test_size = 0.3, criterion = "gini", splitter = " 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 + def knn_classifier(self, 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) model = sklearn.neighbors.KNeighborsClassifier() @@ -578,7 +598,7 @@ class KNN: return model, ClassificationMetrics(predictions, labels_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): + def knn_regressor(self, data, outputs, test_size, n_neighbors = 5, weights = "uniform", algorithm = "auto", leaf_size = 30, p = 2, metric = "minkowski", metric_params = None, n_jobs = None): 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) @@ -697,4 +717,207 @@ def random_forest_regressor(data, outputs, test_size, n_estimators="warn", crite kernel.fit(data_train, outputs_train) predictions = kernel.predict(data_test) - return kernel, RegressionMetrics(predictions, outputs_test) \ No newline at end of file + return kernel, RegressionMetrics(predictions, outputs_test) + +class CorrelationTests: + + def anova_oneway(self, *args): #expects arrays of samples + + results = scipy.stats.f_oneway(*args) + return {"F-value": results[0], "p-value": results[1]} + + def pearson(self, x, y): + + results = scipy.stats.pearsonr(x, y) + return {"r-value": results[0], "p-value": results[1]} + + def spearman(self, a, b = None, axis = 0, nan_policy = 'propagate'): + + results = scipy.stats.spearmanr(a, b = b, axis = axis, nan_policy = nan_policy) + return {"r-value": results[0], "p-value": results[1]} + + def point_biserial(self, x,y): + + results = scipy.stats.pointbiserialr(x, y) + return {"r-value": results[0], "p-value": results[1]} + + def kendall(self, x, y, initial_lexsort = None, nan_policy = 'propagate', method = 'auto'): + + results = scipy.stats.kendalltau(x, y, initial_lexsort = initial_lexsort, nan_policy = nan_policy, method = method) + return {"tau": results[0], "p-value": results[1]} + + def kendall_weighted(self, x, y, rank = True, weigher = None, additive = True): + + results = scipy.stats.weightedtau(x, y, rank = rank, weigher = weigher, additive = additive) + return {"tau": results[0], "p-value": results[1]} + + def mgc(self, x, y, compute_distance = None, reps = 1000, workers = 1, is_twosamp = False, random_state = None): + + results = scipy.stats.multiscale_graphcorr(x, y, compute_distance = compute_distance, reps = reps, workers = workers, is_twosamp = is_twosamp, random_state = random_state) + return {"k-value": results[0], "p-value": results[1], "data": results[2]} # unsure if MGC test returns a k value + +class StatisticalTests: + + def ttest_onesample(self, a, popmean, axis = 0, nan_policy = 'propagate'): + + results = scipy.stats.ttest_1samp(a, popmean, axis = axis, nan_policy = nan_policy) + return {"t-value": results[0], "p-value": results[1]} + + def ttest_independent(self, a, b, equal = True, nan_policy = 'propagate'): + + results = scipy.stats.ttest_ind(a, b, equal_var = equal, nan_policy = nan_policy) + return {"t-value": results[0], "p-value": results[1]} + + def ttest_statistic(self, o1, o2, equal = True): + + results = scipy.stats.ttest_ind_from_stats(o1["mean"], o1["std"], o1["nobs"], o2["mean"], o2["std"], o2["nobs"], equal_var = equal) + return {"t-value": results[0], "p-value": results[1]} + + def ttest_related(self, a, b, axis = 0, nan_policy='propagate'): + + results = scipy.stats.ttest_rel(a, b, axis = axis, nan_policy = nan_policy) + return {"t-value": results[0], "p-value": results[1]} + + def ks_fitness(self, rvs, cdf, args = (), N = 20, alternative = 'two-sided', mode = 'approx'): + + results = scipy.stats.kstest(rvs, cdf, args = args, N = N, alternative = alternative, mode = mode) + return {"ks-value": results[0], "p-value": results[1]} + + def chisquare(self, f_obs, f_exp = None, ddof = None, axis = 0): + + results = scipy.stats.chisquare(f_obs, f_exp = f_exp, ddof = ddof, axis = axis) + return {"chisquared-value": results[0], "p-value": results[1]} + + def powerdivergence(self, f_obs, f_exp = None, ddof = None, axis = 0, lambda_ = None): + + results = scipy.stats.power_divergence(f_obs, f_exp = f_exp, ddof = ddof, axis = axis, lambda_ = lambda_) + return {"powerdivergence-value": results[0], "p-value": results[1]} + + def ks_twosample(self, x, y, alternative = 'two_sided', mode = 'auto'): + + results = scipy.stats.ks_2samp(x, y, alternative = alternative, mode = mode) + return {"ks-value": results[0], "p-value": results[1]} + + def es_twosample(self, x, y, t = (0.4, 0.8)): + + results = scipy.stats.epps_singleton_2samp(x, y, t = t) + return {"es-value": results[0], "p-value": results[1]} + + def mw_rank(self, x, y, use_continuity = True, alternative = None): + + results = scipy.stats.mannwhitneyu(x, y, use_continuity = use_continuity, alternative = alternative) + return {"u-value": results[0], "p-value": results[1]} + + def mw_tiecorrection(self, rank_values): + + results = scipy.stats.tiecorrect(rank_values) + return {"correction-factor": results} + + def rankdata(self, a, method = 'average'): + + results = scipy.stats.rankdata(a, method = method) + return results + + def wilcoxon_ranksum(self, a, b): # this seems to be superceded by Mann Whitney Wilcoxon U Test + + results = scipy.stats.ranksums(a, b) + return {"u-value": results[0], "p-value": results[1]} + + def wilcoxon_signedrank(self, x, y = None, zero_method = 'wilcox', correction = False, alternative = 'two-sided'): + + results = scipy.stats.wilcoxon(x, y = y, zero_method = zero_method, correction = correction, alternative = alternative) + return {"t-value": results[0], "p-value": results[1]} + + def kw_htest(self, *args, nan_policy = 'propagate'): + + results = scipy.stats.kruskal(*args, nan_policy = nan_policy) + return {"h-value": results[0], "p-value": results[1]} + + def friedman_chisquare(self, *args): + + results = scipy.stats.friedmanchisquare(*args) + return {"chisquared-value": results[0], "p-value": results[1]} + + def bm_wtest(self, x, y, alternative = 'two-sided', distribution = 't', nan_policy = 'propagate'): + + results = scipy.stats.brunnermunzel(x, y, alternative = alternative, distribution = distribution, nan_policy = nan_policy) + return {"w-value": results[0], "p-value": results[1]} + + def combine_pvalues(self, pvalues, method = 'fisher', weights = None): + + results = scipy.stats.combine_pvalues(pvalues, method = method, weights = weights) + return {"combined-statistic": results[0], "p-value": results[1]} + + def jb_fitness(self, x): + + results = scipy.stats.jarque_bera(x) + return {"jb-value": results[0], "p-value": results[1]} + + def ab_equality(self, x, y): + + results = scipy.stats.ansari(x, y) + return {"ab-value": results[0], "p-value": results[1]} + + def bartlett_variance(self, *args): + + results = scipy.stats.bartlett(*args) + return {"t-value": results[0], "p-value": results[1]} + + def levene_variance(self, *args, center = 'median', proportiontocut = 0.05): + + results = scipy.stats.levene(*args, center = center, proportiontocut = proportiontocut) + return {"w-value": results[0], "p-value": results[1]} + + def sw_normality(self, x): + + results = scipy.stats.shapiro(x) + return {"w-value": results[0], "p-value": results[1]} + + def shapiro(self, x): + + return "destroyed by facts and logic" + + def ad_onesample(self, x, dist = 'norm'): + + results = scipy.stats.anderson(x, dist = dist) + return {"d-value": results[0], "critical-values": results[1], "significance-value": results[2]} + + def ad_ksample(self, samples, midrank = True): + + results = scipy.stats.anderson_ksamp(samples, midrank = midrank) + return {"d-value": results[0], "critical-values": results[1], "significance-value": results[2]} + + def binomial(self, x, n = None, p = 0.5, alternative = 'two-sided'): + + results = scipy.stats.binom_test(x, n = n, p = p, alternative = alternative) + return {"p-value": results} + + def fk_variance(self, *args, center = 'median', proportiontocut = 0.05): + + results = scipy.stats.fligner(*args, center = center, proportiontocut = proportiontocut) + return {"h-value": results[0], "p-value": results[1]} # unknown if the statistic is an h value + + def mood_mediantest(self, *args, ties = 'below', correction = True, lambda_ = 1, nan_policy = 'propagate'): + + results = scipy.stats.median_test(*args, ties = ties, correction = correction, lambda_ = lambda_, nan_policy = nan_policy) + return {"chisquared-value": results[0], "p-value": results[1], "m-value": results[2], "table": results[3]} + + def mood_equalscale(self, x, y, axis = 0): + + results = scipy.stats.mood(x, y, axis = axis) + return {"z-score": results[0], "p-value": results[1]} + + def skewtest(self, a, axis = 0, nan_policy = 'propogate'): + + results = scipy.stats.skewtest(a, axis = axis, nan_policy = nan_policy) + return {"z-score": results[0], "p-value": results[1]} + + def kurtosistest(self, a, axis = 0, nan_policy = 'propogate'): + + results = scipy.stats.kurtosistest(a, axis = axis, nan_policy = nan_policy) + return {"z-score": results[0], "p-value": results[1]} + + def normaltest(self, a, axis = 0, nan_policy = 'propogate'): + + results = scipy.stats.normaltest(a, axis = axis, nan_policy = nan_policy) + return {"z-score": results[0], "p-value": results[1]} \ No newline at end of file diff --git a/analysis-master/analysis-amd64/build/lib/analysis/metrics/__init__.py b/analysis-master/analysis-amd64/build/lib/analysis/metrics/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/analysis-master/analysis-amd64/build/lib/analysis/metrics/elo.py b/analysis-master/analysis-amd64/build/lib/analysis/metrics/elo.py new file mode 100644 index 00000000..3c8ef2e0 --- /dev/null +++ b/analysis-master/analysis-amd64/build/lib/analysis/metrics/elo.py @@ -0,0 +1,7 @@ +import numpy as np + +def calculate(starting_score, opposing_score, observed, N, K): + + expected = 1/(1+10**((np.array(opposing_score) - starting_score)/N)) + + return starting_score + K*(np.sum(observed) - np.sum(expected)) \ No newline at end of file diff --git a/analysis-master/analysis-amd64/build/lib/analysis/metrics/glicko2.py b/analysis-master/analysis-amd64/build/lib/analysis/metrics/glicko2.py new file mode 100644 index 00000000..66c0df94 --- /dev/null +++ b/analysis-master/analysis-amd64/build/lib/analysis/metrics/glicko2.py @@ -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() \ No newline at end of file diff --git a/analysis-master/analysis-amd64/build/lib/analysis/metrics/trueskill.py b/analysis-master/analysis-amd64/build/lib/analysis/metrics/trueskill.py new file mode 100644 index 00000000..116357df --- /dev/null +++ b/analysis-master/analysis-amd64/build/lib/analysis/metrics/trueskill.py @@ -0,0 +1,907 @@ +from __future__ import absolute_import + +from itertools import chain +import math + +from six import iteritems +from six.moves import map, range, zip +from six import iterkeys + +import copy +try: + from numbers import Number +except ImportError: + Number = (int, long, float, complex) + +inf = float('inf') + +class Gaussian(object): + #: Precision, the inverse of the variance. + pi = 0 + #: Precision adjusted mean, the precision multiplied by the mean. + tau = 0 + + def __init__(self, mu=None, sigma=None, pi=0, tau=0): + if mu is not None: + if sigma is None: + raise TypeError('sigma argument is needed') + elif sigma == 0: + raise ValueError('sigma**2 should be greater than 0') + pi = sigma ** -2 + tau = pi * mu + self.pi = pi + self.tau = tau + + @property + def mu(self): + return self.pi and self.tau / self.pi + + @property + def sigma(self): + return math.sqrt(1 / self.pi) if self.pi else inf + + def __mul__(self, other): + pi, tau = self.pi + other.pi, self.tau + other.tau + return Gaussian(pi=pi, tau=tau) + + def __truediv__(self, other): + pi, tau = self.pi - other.pi, self.tau - other.tau + return Gaussian(pi=pi, tau=tau) + + __div__ = __truediv__ # for Python 2 + + def __eq__(self, other): + return self.pi == other.pi and self.tau == other.tau + + def __lt__(self, other): + return self.mu < other.mu + + def __le__(self, other): + return self.mu <= other.mu + + def __gt__(self, other): + return self.mu > other.mu + + def __ge__(self, other): + return self.mu >= other.mu + + def __repr__(self): + return 'N(mu={:.3f}, sigma={:.3f})'.format(self.mu, self.sigma) + + def _repr_latex_(self): + latex = r'\mathcal{{ N }}( {:.3f}, {:.3f}^2 )'.format(self.mu, self.sigma) + return '$%s$' % latex + +class Matrix(list): + def __init__(self, src, height=None, width=None): + if callable(src): + f, src = src, {} + size = [height, width] + if not height: + def set_height(height): + size[0] = height + size[0] = set_height + if not width: + def set_width(width): + size[1] = width + size[1] = set_width + try: + for (r, c), val in f(*size): + src[r, c] = val + except TypeError: + raise TypeError('A callable src must return an interable ' + 'which generates a tuple containing ' + 'coordinate and value') + height, width = tuple(size) + if height is None or width is None: + raise TypeError('A callable src must call set_height and ' + 'set_width if the size is non-deterministic') + if isinstance(src, list): + is_number = lambda x: isinstance(x, Number) + unique_col_sizes = set(map(len, src)) + everything_are_number = filter(is_number, sum(src, [])) + if len(unique_col_sizes) != 1 or not everything_are_number: + raise ValueError('src must be a rectangular array of numbers') + two_dimensional_array = src + elif isinstance(src, dict): + if not height or not width: + w = h = 0 + for r, c in iterkeys(src): + if not height: + h = max(h, r + 1) + if not width: + w = max(w, c + 1) + if not height: + height = h + if not width: + width = w + two_dimensional_array = [] + for r in range(height): + row = [] + two_dimensional_array.append(row) + for c in range(width): + row.append(src.get((r, c), 0)) + else: + raise TypeError('src must be a list or dict or callable') + super(Matrix, self).__init__(two_dimensional_array) + + @property + def height(self): + return len(self) + + @property + def width(self): + return len(self[0]) + + def transpose(self): + height, width = self.height, self.width + src = {} + for c in range(width): + for r in range(height): + src[c, r] = self[r][c] + return type(self)(src, height=width, width=height) + + def minor(self, row_n, col_n): + height, width = self.height, self.width + if not (0 <= row_n < height): + raise ValueError('row_n should be between 0 and %d' % height) + elif not (0 <= col_n < width): + raise ValueError('col_n should be between 0 and %d' % width) + two_dimensional_array = [] + for r in range(height): + if r == row_n: + continue + row = [] + two_dimensional_array.append(row) + for c in range(width): + if c == col_n: + continue + row.append(self[r][c]) + return type(self)(two_dimensional_array) + + def determinant(self): + height, width = self.height, self.width + if height != width: + raise ValueError('Only square matrix can calculate a determinant') + tmp, rv = copy.deepcopy(self), 1. + for c in range(width - 1, 0, -1): + pivot, r = max((abs(tmp[r][c]), r) for r in range(c + 1)) + pivot = tmp[r][c] + if not pivot: + return 0. + tmp[r], tmp[c] = tmp[c], tmp[r] + if r != c: + rv = -rv + rv *= pivot + fact = -1. / pivot + for r in range(c): + f = fact * tmp[r][c] + for x in range(c): + tmp[r][x] += f * tmp[c][x] + return rv * tmp[0][0] + + def adjugate(self): + height, width = self.height, self.width + if height != width: + raise ValueError('Only square matrix can be adjugated') + if height == 2: + a, b = self[0][0], self[0][1] + c, d = self[1][0], self[1][1] + return type(self)([[d, -b], [-c, a]]) + src = {} + for r in range(height): + for c in range(width): + sign = -1 if (r + c) % 2 else 1 + src[r, c] = self.minor(r, c).determinant() * sign + return type(self)(src, height, width) + + def inverse(self): + if self.height == self.width == 1: + return type(self)([[1. / self[0][0]]]) + return (1. / self.determinant()) * self.adjugate() + + def __add__(self, other): + height, width = self.height, self.width + if (height, width) != (other.height, other.width): + raise ValueError('Must be same size') + src = {} + for r in range(height): + for c in range(width): + src[r, c] = self[r][c] + other[r][c] + return type(self)(src, height, width) + + def __mul__(self, other): + if self.width != other.height: + raise ValueError('Bad size') + height, width = self.height, other.width + src = {} + for r in range(height): + for c in range(width): + src[r, c] = sum(self[r][x] * other[x][c] + for x in range(self.width)) + return type(self)(src, height, width) + + def __rmul__(self, other): + if not isinstance(other, Number): + raise TypeError('The operand should be a number') + height, width = self.height, self.width + src = {} + for r in range(height): + for c in range(width): + src[r, c] = other * self[r][c] + return type(self)(src, height, width) + + def __repr__(self): + return '{}({})'.format(type(self).__name__, super(Matrix, self).__repr__()) + + def _repr_latex_(self): + rows = [' && '.join(['%.3f' % cell for cell in row]) for row in self] + latex = r'\begin{matrix} %s \end{matrix}' % r'\\'.join(rows) + return '$%s$' % latex + +def _gen_erfcinv(erfc, math=math): + def erfcinv(y): + """The inverse function of erfc.""" + if y >= 2: + return -100. + elif y <= 0: + return 100. + zero_point = y < 1 + if not zero_point: + y = 2 - y + t = math.sqrt(-2 * math.log(y / 2.)) + x = -0.70711 * \ + ((2.30753 + t * 0.27061) / (1. + t * (0.99229 + t * 0.04481)) - t) + for i in range(2): + err = erfc(x) - y + x += err / (1.12837916709551257 * math.exp(-(x ** 2)) - x * err) + return x if zero_point else -x + return erfcinv + +def _gen_ppf(erfc, math=math): + erfcinv = _gen_erfcinv(erfc, math) + def ppf(x, mu=0, sigma=1): + return mu - sigma * math.sqrt(2) * erfcinv(2 * x) + return ppf + +def erfc(x): + z = abs(x) + t = 1. / (1. + z / 2.) + r = t * math.exp(-z * z - 1.26551223 + t * (1.00002368 + t * ( + 0.37409196 + t * (0.09678418 + t * (-0.18628806 + t * ( + 0.27886807 + t * (-1.13520398 + t * (1.48851587 + t * ( + -0.82215223 + t * 0.17087277 + ))) + ))) + ))) + return 2. - r if x < 0 else r + +def cdf(x, mu=0, sigma=1): + return 0.5 * erfc(-(x - mu) / (sigma * math.sqrt(2))) + + +def pdf(x, mu=0, sigma=1): + return (1 / math.sqrt(2 * math.pi) * abs(sigma) * + math.exp(-(((x - mu) / abs(sigma)) ** 2 / 2))) + +ppf = _gen_ppf(erfc) + +def choose_backend(backend): + if backend is None: # fallback + return cdf, pdf, ppf + elif backend == 'mpmath': + try: + import mpmath + except ImportError: + raise ImportError('Install "mpmath" to use this backend') + return mpmath.ncdf, mpmath.npdf, _gen_ppf(mpmath.erfc, math=mpmath) + elif backend == 'scipy': + try: + from scipy.stats import norm + except ImportError: + raise ImportError('Install "scipy" to use this backend') + return norm.cdf, norm.pdf, norm.ppf + raise ValueError('%r backend is not defined' % backend) + +def available_backends(): + backends = [None] + for backend in ['mpmath', 'scipy']: + try: + __import__(backend) + except ImportError: + continue + backends.append(backend) + return backends + +class Node(object): + + pass + +class Variable(Node, Gaussian): + + def __init__(self): + self.messages = {} + super(Variable, self).__init__() + + def set(self, val): + delta = self.delta(val) + self.pi, self.tau = val.pi, val.tau + return delta + + def delta(self, other): + pi_delta = abs(self.pi - other.pi) + if pi_delta == inf: + return 0. + return max(abs(self.tau - other.tau), math.sqrt(pi_delta)) + + def update_message(self, factor, pi=0, tau=0, message=None): + message = message or Gaussian(pi=pi, tau=tau) + old_message, self[factor] = self[factor], message + return self.set(self / old_message * message) + + def update_value(self, factor, pi=0, tau=0, value=None): + value = value or Gaussian(pi=pi, tau=tau) + old_message = self[factor] + self[factor] = value * old_message / self + return self.set(value) + + def __getitem__(self, factor): + return self.messages[factor] + + def __setitem__(self, factor, message): + self.messages[factor] = message + + def __repr__(self): + args = (type(self).__name__, super(Variable, self).__repr__(), + len(self.messages), '' if len(self.messages) == 1 else 's') + return '<%s %s with %d connection%s>' % args + + +class Factor(Node): + + def __init__(self, variables): + self.vars = variables + for var in variables: + var[self] = Gaussian() + + def down(self): + return 0 + + def up(self): + return 0 + + @property + def var(self): + assert len(self.vars) == 1 + return self.vars[0] + + def __repr__(self): + args = (type(self).__name__, len(self.vars), + '' if len(self.vars) == 1 else 's') + return '<%s with %d connection%s>' % args + + +class PriorFactor(Factor): + + def __init__(self, var, val, dynamic=0): + super(PriorFactor, self).__init__([var]) + self.val = val + self.dynamic = dynamic + + def down(self): + sigma = math.sqrt(self.val.sigma ** 2 + self.dynamic ** 2) + value = Gaussian(self.val.mu, sigma) + return self.var.update_value(self, value=value) + + +class LikelihoodFactor(Factor): + + def __init__(self, mean_var, value_var, variance): + super(LikelihoodFactor, self).__init__([mean_var, value_var]) + self.mean = mean_var + self.value = value_var + self.variance = variance + + def calc_a(self, var): + return 1. / (1. + self.variance * var.pi) + + def down(self): + # update value. + msg = self.mean / self.mean[self] + a = self.calc_a(msg) + return self.value.update_message(self, a * msg.pi, a * msg.tau) + + def up(self): + # update mean. + msg = self.value / self.value[self] + a = self.calc_a(msg) + return self.mean.update_message(self, a * msg.pi, a * msg.tau) + + +class SumFactor(Factor): + + def __init__(self, sum_var, term_vars, coeffs): + super(SumFactor, self).__init__([sum_var] + term_vars) + self.sum = sum_var + self.terms = term_vars + self.coeffs = coeffs + + def down(self): + vals = self.terms + msgs = [var[self] for var in vals] + return self.update(self.sum, vals, msgs, self.coeffs) + + def up(self, index=0): + coeff = self.coeffs[index] + coeffs = [] + for x, c in enumerate(self.coeffs): + try: + if x == index: + coeffs.append(1. / coeff) + else: + coeffs.append(-c / coeff) + except ZeroDivisionError: + coeffs.append(0.) + vals = self.terms[:] + vals[index] = self.sum + msgs = [var[self] for var in vals] + return self.update(self.terms[index], vals, msgs, coeffs) + + def update(self, var, vals, msgs, coeffs): + pi_inv = 0 + mu = 0 + for val, msg, coeff in zip(vals, msgs, coeffs): + div = val / msg + mu += coeff * div.mu + if pi_inv == inf: + continue + try: + # numpy.float64 handles floating-point error by different way. + # For example, it can just warn RuntimeWarning on n/0 problem + # instead of throwing ZeroDivisionError. So div.pi, the + # denominator has to be a built-in float. + pi_inv += coeff ** 2 / float(div.pi) + except ZeroDivisionError: + pi_inv = inf + pi = 1. / pi_inv + tau = pi * mu + return var.update_message(self, pi, tau) + + +class TruncateFactor(Factor): + + def __init__(self, var, v_func, w_func, draw_margin): + super(TruncateFactor, self).__init__([var]) + self.v_func = v_func + self.w_func = w_func + self.draw_margin = draw_margin + + def up(self): + val = self.var + msg = self.var[self] + div = val / msg + sqrt_pi = math.sqrt(div.pi) + args = (div.tau / sqrt_pi, self.draw_margin * sqrt_pi) + v = self.v_func(*args) + w = self.w_func(*args) + denom = (1. - w) + pi, tau = div.pi / denom, (div.tau + sqrt_pi * v) / denom + return val.update_value(self, pi, tau) + +#: Default initial mean of ratings. +MU = 25. +#: Default initial standard deviation of ratings. +SIGMA = MU / 3 +#: Default distance that guarantees about 76% chance of winning. +BETA = SIGMA / 2 +#: Default dynamic factor. +TAU = SIGMA / 100 +#: Default draw probability of the game. +DRAW_PROBABILITY = .10 +#: A basis to check reliability of the result. +DELTA = 0.0001 + + +def calc_draw_probability(draw_margin, size, env=None): + if env is None: + env = global_env() + return 2 * env.cdf(draw_margin / (math.sqrt(size) * env.beta)) - 1 + + +def calc_draw_margin(draw_probability, size, env=None): + if env is None: + env = global_env() + return env.ppf((draw_probability + 1) / 2.) * math.sqrt(size) * env.beta + + +def _team_sizes(rating_groups): + team_sizes = [0] + for group in rating_groups: + team_sizes.append(len(group) + team_sizes[-1]) + del team_sizes[0] + return team_sizes + + +def _floating_point_error(env): + if env.backend == 'mpmath': + msg = 'Set "mpmath.mp.dps" to higher' + else: + msg = 'Cannot calculate correctly, set backend to "mpmath"' + return FloatingPointError(msg) + + +class Rating(Gaussian): + def __init__(self, mu=None, sigma=None): + if isinstance(mu, tuple): + mu, sigma = mu + elif isinstance(mu, Gaussian): + mu, sigma = mu.mu, mu.sigma + if mu is None: + mu = global_env().mu + if sigma is None: + sigma = global_env().sigma + super(Rating, self).__init__(mu, sigma) + + def __int__(self): + return int(self.mu) + + def __long__(self): + return long(self.mu) + + def __float__(self): + return float(self.mu) + + def __iter__(self): + return iter((self.mu, self.sigma)) + + def __repr__(self): + c = type(self) + args = ('.'.join([c.__module__, c.__name__]), self.mu, self.sigma) + return '%s(mu=%.3f, sigma=%.3f)' % args + + +class TrueSkill(object): + def __init__(self, mu=MU, sigma=SIGMA, beta=BETA, tau=TAU, + draw_probability=DRAW_PROBABILITY, backend=None): + self.mu = mu + self.sigma = sigma + self.beta = beta + self.tau = tau + self.draw_probability = draw_probability + self.backend = backend + if isinstance(backend, tuple): + self.cdf, self.pdf, self.ppf = backend + else: + self.cdf, self.pdf, self.ppf = choose_backend(backend) + + def create_rating(self, mu=None, sigma=None): + if mu is None: + mu = self.mu + if sigma is None: + sigma = self.sigma + return Rating(mu, sigma) + + def v_win(self, diff, draw_margin): + x = diff - draw_margin + denom = self.cdf(x) + return (self.pdf(x) / denom) if denom else -x + + def v_draw(self, diff, draw_margin): + abs_diff = abs(diff) + a, b = draw_margin - abs_diff, -draw_margin - abs_diff + denom = self.cdf(a) - self.cdf(b) + numer = self.pdf(b) - self.pdf(a) + return ((numer / denom) if denom else a) * (-1 if diff < 0 else +1) + + def w_win(self, diff, draw_margin): + x = diff - draw_margin + v = self.v_win(diff, draw_margin) + w = v * (v + x) + if 0 < w < 1: + return w + raise _floating_point_error(self) + + def w_draw(self, diff, draw_margin): + abs_diff = abs(diff) + a, b = draw_margin - abs_diff, -draw_margin - abs_diff + denom = self.cdf(a) - self.cdf(b) + if not denom: + raise _floating_point_error(self) + v = self.v_draw(abs_diff, draw_margin) + return (v ** 2) + (a * self.pdf(a) - b * self.pdf(b)) / denom + + def validate_rating_groups(self, rating_groups): + # check group sizes + if len(rating_groups) < 2: + raise ValueError('Need multiple rating groups') + elif not all(rating_groups): + raise ValueError('Each group must contain multiple ratings') + # check group types + group_types = set(map(type, rating_groups)) + if len(group_types) != 1: + raise TypeError('All groups should be same type') + elif group_types.pop() is Rating: + raise TypeError('Rating cannot be a rating group') + # normalize rating_groups + if isinstance(rating_groups[0], dict): + dict_rating_groups = rating_groups + rating_groups = [] + keys = [] + for dict_rating_group in dict_rating_groups: + rating_group, key_group = [], [] + for key, rating in iteritems(dict_rating_group): + rating_group.append(rating) + key_group.append(key) + rating_groups.append(tuple(rating_group)) + keys.append(tuple(key_group)) + else: + rating_groups = list(rating_groups) + keys = None + return rating_groups, keys + + def validate_weights(self, weights, rating_groups, keys=None): + if weights is None: + weights = [(1,) * len(g) for g in rating_groups] + elif isinstance(weights, dict): + weights_dict, weights = weights, [] + for x, group in enumerate(rating_groups): + w = [] + weights.append(w) + for y, rating in enumerate(group): + if keys is not None: + y = keys[x][y] + w.append(weights_dict.get((x, y), 1)) + return weights + + def factor_graph_builders(self, rating_groups, ranks, weights): + flatten_ratings = sum(map(tuple, rating_groups), ()) + flatten_weights = sum(map(tuple, weights), ()) + size = len(flatten_ratings) + group_size = len(rating_groups) + # create variables + rating_vars = [Variable() for x in range(size)] + perf_vars = [Variable() for x in range(size)] + team_perf_vars = [Variable() for x in range(group_size)] + team_diff_vars = [Variable() for x in range(group_size - 1)] + team_sizes = _team_sizes(rating_groups) + # layer builders + def build_rating_layer(): + for rating_var, rating in zip(rating_vars, flatten_ratings): + yield PriorFactor(rating_var, rating, self.tau) + def build_perf_layer(): + for rating_var, perf_var in zip(rating_vars, perf_vars): + yield LikelihoodFactor(rating_var, perf_var, self.beta ** 2) + def build_team_perf_layer(): + for team, team_perf_var in enumerate(team_perf_vars): + if team > 0: + start = team_sizes[team - 1] + else: + start = 0 + end = team_sizes[team] + child_perf_vars = perf_vars[start:end] + coeffs = flatten_weights[start:end] + yield SumFactor(team_perf_var, child_perf_vars, coeffs) + def build_team_diff_layer(): + for team, team_diff_var in enumerate(team_diff_vars): + yield SumFactor(team_diff_var, + team_perf_vars[team:team + 2], [+1, -1]) + def build_trunc_layer(): + for x, team_diff_var in enumerate(team_diff_vars): + if callable(self.draw_probability): + # dynamic draw probability + team_perf1, team_perf2 = team_perf_vars[x:x + 2] + args = (Rating(team_perf1), Rating(team_perf2), self) + draw_probability = self.draw_probability(*args) + else: + # static draw probability + draw_probability = self.draw_probability + size = sum(map(len, rating_groups[x:x + 2])) + draw_margin = calc_draw_margin(draw_probability, size, self) + if ranks[x] == ranks[x + 1]: # is a tie? + v_func, w_func = self.v_draw, self.w_draw + else: + v_func, w_func = self.v_win, self.w_win + yield TruncateFactor(team_diff_var, + v_func, w_func, draw_margin) + # build layers + return (build_rating_layer, build_perf_layer, build_team_perf_layer, + build_team_diff_layer, build_trunc_layer) + + def run_schedule(self, build_rating_layer, build_perf_layer, + build_team_perf_layer, build_team_diff_layer, + build_trunc_layer, min_delta=DELTA): + if min_delta <= 0: + raise ValueError('min_delta must be greater than 0') + layers = [] + def build(builders): + layers_built = [list(build()) for build in builders] + layers.extend(layers_built) + return layers_built + # gray arrows + layers_built = build([build_rating_layer, + build_perf_layer, + build_team_perf_layer]) + rating_layer, perf_layer, team_perf_layer = layers_built + for f in chain(*layers_built): + f.down() + # arrow #1, #2, #3 + team_diff_layer, trunc_layer = build([build_team_diff_layer, + build_trunc_layer]) + team_diff_len = len(team_diff_layer) + for x in range(10): + if team_diff_len == 1: + # only two teams + team_diff_layer[0].down() + delta = trunc_layer[0].up() + else: + # multiple teams + delta = 0 + for x in range(team_diff_len - 1): + team_diff_layer[x].down() + delta = max(delta, trunc_layer[x].up()) + team_diff_layer[x].up(1) # up to right variable + for x in range(team_diff_len - 1, 0, -1): + team_diff_layer[x].down() + delta = max(delta, trunc_layer[x].up()) + team_diff_layer[x].up(0) # up to left variable + # repeat until to small update + if delta <= min_delta: + break + # up both ends + team_diff_layer[0].up(0) + team_diff_layer[team_diff_len - 1].up(1) + # up the remainder of the black arrows + for f in team_perf_layer: + for x in range(len(f.vars) - 1): + f.up(x) + for f in perf_layer: + f.up() + return layers + + def rate(self, rating_groups, ranks=None, weights=None, min_delta=DELTA): + rating_groups, keys = self.validate_rating_groups(rating_groups) + weights = self.validate_weights(weights, rating_groups, keys) + group_size = len(rating_groups) + if ranks is None: + ranks = range(group_size) + elif len(ranks) != group_size: + raise ValueError('Wrong ranks') + # sort rating groups by rank + by_rank = lambda x: x[1][1] + sorting = sorted(enumerate(zip(rating_groups, ranks, weights)), + key=by_rank) + sorted_rating_groups, sorted_ranks, sorted_weights = [], [], [] + for x, (g, r, w) in sorting: + sorted_rating_groups.append(g) + sorted_ranks.append(r) + # make weights to be greater than 0 + sorted_weights.append(max(min_delta, w_) for w_ in w) + # build factor graph + args = (sorted_rating_groups, sorted_ranks, sorted_weights) + builders = self.factor_graph_builders(*args) + args = builders + (min_delta,) + layers = self.run_schedule(*args) + # make result + rating_layer, team_sizes = layers[0], _team_sizes(sorted_rating_groups) + transformed_groups = [] + for start, end in zip([0] + team_sizes[:-1], team_sizes): + group = [] + for f in rating_layer[start:end]: + group.append(Rating(float(f.var.mu), float(f.var.sigma))) + transformed_groups.append(tuple(group)) + by_hint = lambda x: x[0] + unsorting = sorted(zip((x for x, __ in sorting), transformed_groups), + key=by_hint) + if keys is None: + return [g for x, g in unsorting] + # restore the structure with input dictionary keys + return [dict(zip(keys[x], g)) for x, g in unsorting] + + def quality(self, rating_groups, weights=None): + rating_groups, keys = self.validate_rating_groups(rating_groups) + weights = self.validate_weights(weights, rating_groups, keys) + flatten_ratings = sum(map(tuple, rating_groups), ()) + flatten_weights = sum(map(tuple, weights), ()) + length = len(flatten_ratings) + # a vector of all of the skill means + mean_matrix = Matrix([[r.mu] for r in flatten_ratings]) + # a matrix whose diagonal values are the variances (sigma ** 2) of each + # of the players. + def variance_matrix(height, width): + variances = (r.sigma ** 2 for r in flatten_ratings) + for x, variance in enumerate(variances): + yield (x, x), variance + variance_matrix = Matrix(variance_matrix, length, length) + # the player-team assignment and comparison matrix + def rotated_a_matrix(set_height, set_width): + t = 0 + for r, (cur, _next) in enumerate(zip(rating_groups[:-1], + rating_groups[1:])): + for x in range(t, t + len(cur)): + yield (r, x), flatten_weights[x] + t += 1 + x += 1 + for x in range(x, x + len(_next)): + yield (r, x), -flatten_weights[x] + set_height(r + 1) + set_width(x + 1) + rotated_a_matrix = Matrix(rotated_a_matrix) + a_matrix = rotated_a_matrix.transpose() + # match quality further derivation + _ata = (self.beta ** 2) * rotated_a_matrix * a_matrix + _atsa = rotated_a_matrix * variance_matrix * a_matrix + start = mean_matrix.transpose() * a_matrix + middle = _ata + _atsa + end = rotated_a_matrix * mean_matrix + # make result + e_arg = (-0.5 * start * middle.inverse() * end).determinant() + s_arg = _ata.determinant() / middle.determinant() + return math.exp(e_arg) * math.sqrt(s_arg) + + def expose(self, rating): + k = self.mu / self.sigma + return rating.mu - k * rating.sigma + + def make_as_global(self): + return setup(env=self) + + def __repr__(self): + c = type(self) + if callable(self.draw_probability): + f = self.draw_probability + draw_probability = '.'.join([f.__module__, f.__name__]) + else: + draw_probability = '%.1f%%' % (self.draw_probability * 100) + if self.backend is None: + backend = '' + elif isinstance(self.backend, tuple): + backend = ', backend=...' + else: + backend = ', backend=%r' % self.backend + args = ('.'.join([c.__module__, c.__name__]), self.mu, self.sigma, + self.beta, self.tau, draw_probability, backend) + return ('%s(mu=%.3f, sigma=%.3f, beta=%.3f, tau=%.3f, ' + 'draw_probability=%s%s)' % args) + + +def rate_1vs1(rating1, rating2, drawn=False, min_delta=DELTA, env=None): + if env is None: + env = global_env() + ranks = [0, 0 if drawn else 1] + teams = env.rate([(rating1,), (rating2,)], ranks, min_delta=min_delta) + return teams[0][0], teams[1][0] + + +def quality_1vs1(rating1, rating2, env=None): + if env is None: + env = global_env() + return env.quality([(rating1,), (rating2,)]) + + +def global_env(): + try: + global_env.__trueskill__ + except AttributeError: + # setup the default environment + setup() + return global_env.__trueskill__ + + +def setup(mu=MU, sigma=SIGMA, beta=BETA, tau=TAU, + draw_probability=DRAW_PROBABILITY, backend=None, env=None): + if env is None: + env = TrueSkill(mu, sigma, beta, tau, draw_probability, backend) + global_env.__trueskill__ = env + return env + + +def rate(rating_groups, ranks=None, weights=None, min_delta=DELTA): + return global_env().rate(rating_groups, ranks, weights, min_delta) + + +def quality(rating_groups, weights=None): + return global_env().quality(rating_groups, weights) + + +def expose(rating): + return global_env().expose(rating) \ No newline at end of file diff --git a/analysis-master/analysis-amd64/dist/analysis-1.0.0.12-py3-none-any.whl b/analysis-master/analysis-amd64/dist/analysis-1.0.0.12-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..60e0b51c7e0824323d9fea32c844cadcaeb7528a GIT binary patch literal 32026 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 literal 0 HcmV?d00001 diff --git a/analysis-master/analysis-amd64/dist/analysis-1.0.0.12.tar.gz b/analysis-master/analysis-amd64/dist/analysis-1.0.0.12.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..1ba274315415d3096304b963298c369f7d3b44c2 GIT binary patch literal 21001 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 literal 0 HcmV?d00001 diff --git a/analysis-master/analysis-amd64/setup.py b/analysis-master/analysis-amd64/setup.py index 89a9bdf6..f290c88d 100644 --- a/analysis-master/analysis-amd64/setup.py +++ b/analysis-master/analysis-amd64/setup.py @@ -8,7 +8,7 @@ with open("requirements.txt", 'r') as file: setuptools.setup( name="analysis", - version="1.0.0.011", + version="1.0.0.012", author="The Titan Scouting Team", author_email="titanscout2022@gmail.com", description="analysis package developed by Titan Scouting for The Red Alliance",