ソースを参照

Initial helpers version: continues_statistic, ringbuffer, data_collector

master
Dirk Alders 4年前
コミット
1819df790c
1個のファイルの変更148行の追加0行の削除
  1. 148
    0
      __init__.py

+ 148
- 0
__init__.py ファイルの表示

@@ -0,0 +1,148 @@
1
+import numbers
2
+import os
3
+import time
4
+
5
+
6
+class continues_statistic(dict):
7
+    KEY_SINGLE_VALUE = '_'
8
+    KEY_MEAN_VALUE = 'mean_val'
9
+    KEY_MIN_VALUE = 'min_val'
10
+    KEY_MAX_VALUE = 'max_val'
11
+    KEY_NUM_VALUES = 'num_val'
12
+    """
13
+    Value can be a single single numeric value: continues_statistic(num) or multivalue statistic: continues_statistic(val_a=continues_statistic(num_a), val_b=continues_statistic(num_b)). 
14
+    """
15
+    def __init__(self, *args, **kwargs):
16
+        if len(args) == 1 and isinstance(args[0], numbers.Number):
17
+            dict.__init__(self)
18
+            self[self.KEY_SINGLE_VALUE] = {
19
+                self.KEY_MIN_VALUE: args[0],
20
+                self.KEY_MEAN_VALUE: args[0],
21
+                self.KEY_MAX_VALUE: args[0],
22
+                self.KEY_NUM_VALUES: 1,
23
+            }
24
+        else:
25
+            for key in kwargs:
26
+                if isinstance(kwargs[key], numbers.Number):
27
+                    kwargs[key] = continues_statistic(kwargs[key])
28
+            dict.__init__(self, *args, **kwargs)
29
+            for key in self:
30
+                if type(self[key]) is not continues_statistic:
31
+                    data = continues_statistic()
32
+                    if key == self.KEY_SINGLE_VALUE:
33
+                        data[self.KEY_SINGLE_VALUE] = self[key]
34
+                    else:
35
+                        data[self.KEY_SINGLE_VALUE] = self[key][self.KEY_SINGLE_VALUE]
36
+                    self[key] = data
37
+
38
+    @property
39
+    def __multivalue__(self):
40
+        if len(self.keys()) == 0:
41
+            raise AttributeError('No data stored in continues statistic')
42
+        elif len(self.keys()) == 1:
43
+            if list(self.keys())[0] != self.KEY_SINGLE_VALUE:
44
+                raise AttributeError("The single value key needs to be %s." % self.KEY_SINGLE_VALUE)
45
+            return False
46
+        return True
47
+
48
+    def __add__(self, other):
49
+        rv = continues_statistic(self)
50
+        if self.__multivalue__:
51
+            if self.__multivalue__ != other.__multivalue__ or self.keys() != other.keys():
52
+                raise AttributeError("Instances are incompatible")
53
+            else:
54
+                for key in rv:
55
+                    rv[key] += other[key]
56
+        else:
57
+            rv[self.KEY_SINGLE_VALUE][self.KEY_MEAN_VALUE] = (self[self.KEY_SINGLE_VALUE][self.KEY_MEAN_VALUE] * self[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES] + other[self.KEY_SINGLE_VALUE][self.KEY_MEAN_VALUE] * other[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES]) / (self[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES] + other[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES])
58
+            rv[self.KEY_SINGLE_VALUE][self.KEY_MIN_VALUE] = min(self[self.KEY_SINGLE_VALUE][self.KEY_MIN_VALUE], other[self.KEY_SINGLE_VALUE][self.KEY_MIN_VALUE])
59
+            rv[self.KEY_SINGLE_VALUE][self.KEY_MAX_VALUE] = max(self[self.KEY_SINGLE_VALUE][self.KEY_MAX_VALUE], other[self.KEY_SINGLE_VALUE][self.KEY_MAX_VALUE])
60
+            rv[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES] = self[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES]+other[self.KEY_SINGLE_VALUE][self.KEY_NUM_VALUES]
61
+        return rv
62
+    
63
+    def __str__(self):
64
+        output_for_value = "mean=%%(%s)s, min=%%(%s)s, max=%%(%s)s, num=%%(%s)s" % (self.KEY_MEAN_VALUE, self.KEY_MIN_VALUE, self.KEY_MAX_VALUE, self.KEY_NUM_VALUES)
65
+        if self.__multivalue__:
66
+            rv = ""
67
+            for key in self:
68
+                rv += key + ': ' + str(self[key]) + "\n"
69
+            return rv
70
+        else:
71
+            return output_for_value % self[self.KEY_SINGLE_VALUE]
72
+
73
+
74
+class ringbuffer(list):
75
+    def __init__(self, *args, **kwargs):
76
+        self.__max_length__ = kwargs.pop('length')
77
+        list.__init__(self, *args, **kwargs)
78
+        self.__reduce_list__()
79
+
80
+    def __reduce_list__(self):
81
+        while len(self) > self.__max_length__:
82
+            self.pop(0)
83
+
84
+    def append(self, *args, **kwargs):
85
+        rv = list.append(self, *args, **kwargs)
86
+        self.__reduce_list__()
87
+        return rv
88
+
89
+
90
+class data_collector(object):
91
+    def __init__(self, bufferlength):
92
+        self.__current_data_rinbuffer__ = ringbuffer(length=3)
93
+        #
94
+        self.__continues_statistic__ = None
95
+        self.__yesterdays_statistic__ = None
96
+        self.__measurement_day__ = None
97
+        #
98
+        self.__ringbuffer__ = ringbuffer(length=bufferlength)
99
+
100
+    def __process_continues_statistic__(self, **kwargs):
101
+        # rotate continues_statistic day by day
102
+        today = time.strftime('%Y' + os.path.sep + '%m' + os.path.sep + '%d')
103
+        if self.__measurement_day__ is None:
104
+            self.__measurement_day__ = today
105
+        if self.__measurement_day__ != today:
106
+            self.__yesterdays_statistic__ = self.__continues_statistic__
107
+            self.__continues_statistic__ = None
108
+            self.__measurement_day__ = None
109
+        # Set or update continues statistic
110
+        if self.__continues_statistic__ is None:
111
+            self.__continues_statistic__ = continues_statistic(**kwargs)
112
+        else:
113
+            self.__continues_statistic__ += continues_statistic(**kwargs)
114
+
115
+
116
+    def add_data(self, **kwargs):
117
+        self.__current_data_rinbuffer__.append(kwargs)
118
+        self.__process_continues_statistic__(**kwargs)
119
+        self.__ringbuffer__.append(kwargs)
120
+
121
+    @property
122
+    def current(self):
123
+        if len(self.__current_data_rinbuffer__) == 0:
124
+            return None
125
+        elif  len(self.__current_data_rinbuffer__) < 3:
126
+            return self.__current_data_rinbuffer__[-1]
127
+        else:
128
+            rv = {}
129
+            for key in self.__current_data_rinbuffer__[0]:
130
+                data = []
131
+                for entry in self.__current_data_rinbuffer__:
132
+                    data.append(entry[key])
133
+                else:
134
+                    data.sort()
135
+                    rv[key] = data[1]
136
+            return rv
137
+
138
+    @property
139
+    def todays_statistic(self):
140
+        return self.__continues_statistic__
141
+
142
+    @property
143
+    def yesterdays_statistic(self):
144
+        return self.__yesterdays_statistic__
145
+
146
+    @property
147
+    def databuffer(self):
148
+        return self.__ringbuffer__[:]

読み込み中…
キャンセル
保存