From e1c27fad9b0cb29d13bceeebf98824a47d26371c Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 21:57:46 +0200 Subject: analyze stats --- stats.py | 135 +++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 29 deletions(-) diff --git a/stats.py b/stats.py index aed7b42..fec5825 100644 --- a/stats.py +++ b/stats.py @@ -1,43 +1,86 @@ import time from collections import defaultdict import pickle +from functools import reduce + +def flatten(l): + return reduce(lambda a,b:a+b, l) + +def quantile(values, q): + if not isinstance(values, list): + return quantile(flatten(map(lambda x : [x[0]]*x[1], sorted(values.items(),key=lambda x:x[0]))), q) + else: + return values[ int(len(values)*q) ] + +def avg(values): + if isinstance(values, list): + return sum(values)/len(values) + else: + return int(sum(map( lambda x : x[0]*x[1], values.items() )) / sum(map(lambda x : x[1], values.items()))) + +def stddev(values): + a=avg(values) + return avg(list(map(lambda v : (v-a)**2, values))) + +def normalize(values): + a=avg(values) + return [x/a for x in values] + +class StatData(): + pass + +def return_empty_list(): + return [] + +def return_zero(): + return 0 + +def return_defaultdict_with_zeros(): + return defaultdict(return_zero) class Stats: - def __init__(self,c): + def __init__(self,c,data=None): self.c = c - self.min_mass = 0 - self.max_mass = 0 - self.current_mass = 0 - - self.mass_history = [] - self.pos_history = [] - self.cell_aggressivity = {} - self.cell_split_frequency = {} - self.cell_defensiveness = {} - - self.size_vs_speed = defaultdict(lambda : defaultdict(lambda : 0)) - self.size_vs_visible_window = defaultdict(lambda : []) - self.mass_vs_visible_window = defaultdict(lambda : []) + + if data == None: + self.data = StatData() + self.data.version = 1 + + self.data.min_mass = 0 + self.data.max_mass = 0 + self.data.current_mass = 0 + + self.data.mass_history = [] + self.data.pos_history = [] + self.data.cell_aggressivity = {} + self.data.cell_split_frequency = {} + self.data.cell_defensiveness = {} + + self.data.size_vs_speed = defaultdict(return_defaultdict_with_zeros) + self.data.size_vs_visible_window = defaultdict(return_empty_list) + self.data.mass_vs_visible_window = defaultdict(return_empty_list) + else: + self.data = data def log_mass(self, mass): - self.mass_history.append((time.time(), mass)) - self.current_mass = mass - if mass > self.max_mass: - self.max_mass = mass - if mass < self.min_mass: - self.min_mass = mass + self.data.mass_history.append((time.time(), mass)) + self.data.current_mass = mass + if mass > self.data.max_mass: + self.data.max_mass = mass + if mass < self.data.min_mass: + self.data.min_mass = mass def log_pos(self, pos): - self.pos_history.append((time.time(), (pos[0], pos[1]))) + self.data.pos_history.append((time.time(), (pos[0], pos[1]))) def update_cell_aggressivity(self, cell, value): - self.cell_aggressivity[cell] = value + self.data.cell_aggressivity[cell] = value def update_cell_split_frequency(self, cell, value): - self.cell_split_frequency[cell] = value + self.data.cell_split_frequency[cell] = value def update_cell_defensiveness(self, cell, value): - self.cell_defensiveness[cell] = value + self.data.cell_defensiveness[cell] = value def get_last_steps(self, list, steps = 10): return list[-steps:] @@ -60,16 +103,50 @@ class Stats: cellspeed += (cell.poslog[-i] - cell.poslog[-i-1]).len() / n cellspeed = int(cellspeed) - self.size_vs_speed[cell.size][cellspeed] += 1 + self.data.size_vs_speed[cell.size][cellspeed] += 1 visible_width = max( map(lambda cell : cell.pos.x - cell.size, cells) ) - min( map(lambda cell : cell.pos.x + cell.size, cells) ) visible_height = max( map(lambda cell : cell.pos.y - cell.size, cells) ) - min( map(lambda cell : cell.pos.y + cell.size, cells) ) - self.size_vs_visible_window[own_total_size].append((visible_width,visible_height)) - self.mass_vs_visible_window[own_total_mass].append((visible_width,visible_height)) + self.data.size_vs_visible_window[own_total_size].append((visible_width,visible_height)) + self.data.mass_vs_visible_window[own_total_mass].append((visible_width,visible_height)) def save(self,filename): - pickle.dump(self, open(filename,"wb")) + pickle.dump(self.data, open(filename,"wb")) def load(filename): - return pickle.load(open(filename,"rb")) + return Stats(None, pickle.load(open(filename,"rb"))) + + + def analyze_speed(self): + results=[] + for size, values in sorted(self.data.size_vs_speed.items(), key=lambda x : x[0]): + minimum = quantile(values, 0.2) + average = quantile(values, 0.5) + maximum = quantile(values, 0.8) + + results += [(size,maximum,average,minimum,False,False,False,len(values))] + + # mark outliers + for i in range(1, len(results)-1): + for j in range(1,4): + if abs(results[i][j] - results[i-1][j]) > 2 and abs(results[i][j] - results[i+1][j]) > 2: + tmp = list(results[i]) + tmp[j+3] = True + results[i] = tuple(tmp) + + coeff_vs_stddev = [] + for coeff in [x/100 for x in range(10,100,1)]: + products = [] + for size, maximum, average, minimum, maxoutlier, avgoutlier, minoutlier, ndata in results: + if not maxoutlier: + products += [size**coeff * maximum] + + coeff_vs_stddev += [(coeff, avg(products), stddev(normalize(products)))] + + best = min(coeff_vs_stddev, key=lambda v:v[2]) + print("size**"+str(best[0])+" * speed = "+str(best[1]) ) + + print("size\tcalc\tmax\tavg\tmin\t\tndata") + for size, maximum, average, minimum, maxoutlier, avgoutlier, minoutlier, ndata in results: + print(str(size) + ":\t" + "%.1f" % (best[1] / size**best[0]) + "\t" + ("*" if maxoutlier else "") + str(maximum) + "\t" + ("*" if avgoutlier else "") + str(average) + "\t" + ("*" if minoutlier else "") + str(minimum) + "\t\t" + str(ndata)) -- cgit v1.2.1