blob: f3fcd6ad62f3679bcbb8e237b34a3b5b07f64433 [file] [log] [blame]
koder aka kdanilov6c491062015-04-09 22:33:13 +03001import math
2import itertools
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +03003
4try:
5 from numpy import array, linalg
6 from scipy.optimize import leastsq
7 from numpy.polynomial.chebyshev import chebfit, chebval
8except ImportError:
9 no_numpy = True
koder aka kdanilov6c491062015-04-09 22:33:13 +030010
11
12def med_dev(vals):
13 med = sum(vals) / len(vals)
14 dev = ((sum(abs(med - i) ** 2.0 for i in vals) / len(vals)) ** 0.5)
15 return med, dev
16
17
koder aka kdanilove87ae652015-04-20 02:14:35 +030018def round_3_digit(val):
19 return round_deviation((val, val / 10.0))[0]
20
21
koder aka kdanilov6c491062015-04-09 22:33:13 +030022def round_deviation(med_dev):
23 med, dev = med_dev
24
25 if dev < 1E-7:
26 return med_dev
27
28 dev_div = 10.0 ** (math.floor(math.log10(dev)) - 1)
29 dev = int(dev / dev_div) * dev_div
30 med = int(med / dev_div) * dev_div
31 return (type(med_dev[0])(med),
32 type(med_dev[1])(dev))
33
34
35def groupby_globally(data, key_func):
36 grouped = {}
37 grouped_iter = itertools.groupby(data, key_func)
38
39 for (bs, cache_tp, act, conc), curr_data_it in grouped_iter:
40 key = (bs, cache_tp, act, conc)
41 grouped.setdefault(key, []).extend(curr_data_it)
42
43 return grouped
44
45
46def approximate_curve(x, y, xnew, curved_coef):
47 """returns ynew - y values of some curve approximation"""
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030048 if no_numpy:
49 return None
50
koder aka kdanilov6c491062015-04-09 22:33:13 +030051 return chebval(xnew, chebfit(x, y, curved_coef))
52
53
54def approximate_line(x, y, xnew, relative_dist=False):
Ved-vampir03166442015-04-10 17:28:23 +030055 """ x, y - test data, xnew - dots, where we want find approximation
56 if not relative_dist distance = y - newy
57 returns ynew - y values of linear approximation"""
koder aka kdanilov66839a92015-04-11 13:22:31 +030058
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030059 if no_numpy:
60 return None
61
Ved-vampir03166442015-04-10 17:28:23 +030062 # convert to numpy.array (don't work without it)
63 ox = array(x)
64 oy = array(y)
koder aka kdanilov66839a92015-04-11 13:22:31 +030065
Ved-vampir03166442015-04-10 17:28:23 +030066 # set approximation function
koder aka kdanilov66839a92015-04-11 13:22:31 +030067 def func_line(tpl, x):
68 return tpl[0] * x + tpl[1]
69
70 def error_func_rel(tpl, x, y):
71 return 1.0 - y / func_line(tpl, x)
72
73 def error_func_abs(tpl, x, y):
74 return y - func_line(tpl, x)
75
Ved-vampir03166442015-04-10 17:28:23 +030076 # choose distance mode
koder aka kdanilov66839a92015-04-11 13:22:31 +030077 error_func = error_func_rel if relative_dist else error_func_abs
78
79 tpl_initial = tuple(linalg.solve([[ox[0], 1.0], [ox[1], 1.0]],
80 oy[:2]))
81
Ved-vampir03166442015-04-10 17:28:23 +030082 # find line
koder aka kdanilov66839a92015-04-11 13:22:31 +030083 tpl_final, success = leastsq(error_func,
84 tpl_initial[:],
85 args=(ox, oy))
86
Ved-vampir03166442015-04-10 17:28:23 +030087 # if error
88 if success not in range(1, 5):
89 raise ValueError("No line for this dots")
koder aka kdanilov66839a92015-04-11 13:22:31 +030090
Ved-vampir03166442015-04-10 17:28:23 +030091 # return new dots
koder aka kdanilov66839a92015-04-11 13:22:31 +030092 return func_line(tpl_final, array(xnew))
koder aka kdanilov6c491062015-04-09 22:33:13 +030093
94
95def difference(y, ynew):
96 """returns average and maximum relative and
Ved-vampir03166442015-04-10 17:28:23 +030097 absolute differences between y and ynew
98 result may contain None values for y = 0
99 return value - tuple:
100 [(abs dif, rel dif) * len(y)],
101 (abs average, abs max),
102 (rel average, rel max)"""
koder aka kdanilov66839a92015-04-11 13:22:31 +0300103
104 abs_dlist = []
105 rel_dlist = []
106
Ved-vampir03166442015-04-10 17:28:23 +0300107 for y1, y2 in zip(y, ynew):
108 # absolute
koder aka kdanilov66839a92015-04-11 13:22:31 +0300109 abs_dlist.append(y1 - y2)
Ved-vampir03166442015-04-10 17:28:23 +0300110
koder aka kdanilov66839a92015-04-11 13:22:31 +0300111 if y1 > 1E-6:
112 rel_dlist.append(abs(abs_dlist[-1] / y1))
113 else:
114 raise ZeroDivisionError("{0!r} is too small".format(y1))
115
116 da_avg = sum(abs_dlist) / len(abs_dlist)
117 dr_avg = sum(rel_dlist) / len(rel_dlist)
118
119 return (zip(abs_dlist, rel_dlist),
120 (da_avg, max(abs_dlist)), (dr_avg, max(rel_dlist))
121 )
koder aka kdanilov6c491062015-04-09 22:33:13 +0300122
123
124def calculate_distribution_properties(data):
125 """chi, etc"""
126
127
128def minimal_measurement_amount(data, max_diff, req_probability):
129 """
130 should returns amount of measurements to get results (avg and deviation)
131 with error less, that max_diff in at least req_probability% cases
132 """