blob: a02033d5ecafb263aca332823ede806c34cd0b55 [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 kdanilov7e0f7cf2015-05-01 17:24:35 +030022def round_deviation_p(med_dev):
23 med, dev = med_dev
24 med, dev = round_deviation((med, med * dev))
25 return [med, float(dev) / med]
26
27
koder aka kdanilov6c491062015-04-09 22:33:13 +030028def round_deviation(med_dev):
29 med, dev = med_dev
30
31 if dev < 1E-7:
32 return med_dev
33
34 dev_div = 10.0 ** (math.floor(math.log10(dev)) - 1)
35 dev = int(dev / dev_div) * dev_div
36 med = int(med / dev_div) * dev_div
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +030037 return [type(med_dev[0])(med),
38 type(med_dev[1])(dev)]
koder aka kdanilov6c491062015-04-09 22:33:13 +030039
40
41def groupby_globally(data, key_func):
42 grouped = {}
43 grouped_iter = itertools.groupby(data, key_func)
44
45 for (bs, cache_tp, act, conc), curr_data_it in grouped_iter:
46 key = (bs, cache_tp, act, conc)
47 grouped.setdefault(key, []).extend(curr_data_it)
48
49 return grouped
50
51
52def approximate_curve(x, y, xnew, curved_coef):
53 """returns ynew - y values of some curve approximation"""
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030054 if no_numpy:
55 return None
56
koder aka kdanilov6c491062015-04-09 22:33:13 +030057 return chebval(xnew, chebfit(x, y, curved_coef))
58
59
60def approximate_line(x, y, xnew, relative_dist=False):
Ved-vampir03166442015-04-10 17:28:23 +030061 """ x, y - test data, xnew - dots, where we want find approximation
62 if not relative_dist distance = y - newy
63 returns ynew - y values of linear approximation"""
koder aka kdanilov66839a92015-04-11 13:22:31 +030064
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030065 if no_numpy:
66 return None
67
Ved-vampir03166442015-04-10 17:28:23 +030068 # convert to numpy.array (don't work without it)
69 ox = array(x)
70 oy = array(y)
koder aka kdanilov66839a92015-04-11 13:22:31 +030071
Ved-vampir03166442015-04-10 17:28:23 +030072 # set approximation function
koder aka kdanilov66839a92015-04-11 13:22:31 +030073 def func_line(tpl, x):
74 return tpl[0] * x + tpl[1]
75
76 def error_func_rel(tpl, x, y):
77 return 1.0 - y / func_line(tpl, x)
78
79 def error_func_abs(tpl, x, y):
80 return y - func_line(tpl, x)
81
Ved-vampir03166442015-04-10 17:28:23 +030082 # choose distance mode
koder aka kdanilov66839a92015-04-11 13:22:31 +030083 error_func = error_func_rel if relative_dist else error_func_abs
84
85 tpl_initial = tuple(linalg.solve([[ox[0], 1.0], [ox[1], 1.0]],
86 oy[:2]))
87
Ved-vampir03166442015-04-10 17:28:23 +030088 # find line
koder aka kdanilov66839a92015-04-11 13:22:31 +030089 tpl_final, success = leastsq(error_func,
90 tpl_initial[:],
91 args=(ox, oy))
92
Ved-vampir03166442015-04-10 17:28:23 +030093 # if error
94 if success not in range(1, 5):
95 raise ValueError("No line for this dots")
koder aka kdanilov66839a92015-04-11 13:22:31 +030096
Ved-vampir03166442015-04-10 17:28:23 +030097 # return new dots
koder aka kdanilov66839a92015-04-11 13:22:31 +030098 return func_line(tpl_final, array(xnew))
koder aka kdanilov6c491062015-04-09 22:33:13 +030099
100
101def difference(y, ynew):
102 """returns average and maximum relative and
Ved-vampir03166442015-04-10 17:28:23 +0300103 absolute differences between y and ynew
104 result may contain None values for y = 0
105 return value - tuple:
106 [(abs dif, rel dif) * len(y)],
107 (abs average, abs max),
108 (rel average, rel max)"""
koder aka kdanilov66839a92015-04-11 13:22:31 +0300109
110 abs_dlist = []
111 rel_dlist = []
112
Ved-vampir03166442015-04-10 17:28:23 +0300113 for y1, y2 in zip(y, ynew):
114 # absolute
koder aka kdanilov66839a92015-04-11 13:22:31 +0300115 abs_dlist.append(y1 - y2)
Ved-vampir03166442015-04-10 17:28:23 +0300116
koder aka kdanilov66839a92015-04-11 13:22:31 +0300117 if y1 > 1E-6:
118 rel_dlist.append(abs(abs_dlist[-1] / y1))
119 else:
120 raise ZeroDivisionError("{0!r} is too small".format(y1))
121
122 da_avg = sum(abs_dlist) / len(abs_dlist)
123 dr_avg = sum(rel_dlist) / len(rel_dlist)
124
125 return (zip(abs_dlist, rel_dlist),
126 (da_avg, max(abs_dlist)), (dr_avg, max(rel_dlist))
127 )
koder aka kdanilov6c491062015-04-09 22:33:13 +0300128
129
130def calculate_distribution_properties(data):
131 """chi, etc"""
132
133
134def minimal_measurement_amount(data, max_diff, req_probability):
135 """
136 should returns amount of measurements to get results (avg and deviation)
137 with error less, that max_diff in at least req_probability% cases
138 """