summaryrefslogtreecommitdiff
path: root/stats.py
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2015-08-25 21:57:46 +0200
committerFlorian Jung <flo@windfisch.org>2015-08-25 21:57:46 +0200
commite1c27fad9b0cb29d13bceeebf98824a47d26371c (patch)
treec5600ae8fba7fe22a2685986d23357a046982ab3 /stats.py
parent5b91b2732ed339a1c2559e06833cc4f1daec01ae (diff)
analyze stats
Diffstat (limited to 'stats.py')
-rw-r--r--stats.py135
1 files 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))