aggregationslib 0.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,186 @@
1
+ import math
2
+ import warnings
3
+ from decimal import Decimal
4
+
5
+ import numpy as np
6
+ from pynverse.inverse import inversefunc
7
+
8
+
9
+ # 1 Arithmetic aggregation
10
+ def arithmetic(y):
11
+ """
12
+ Arithmetic aggregation
13
+ :param y: 1 dimensional array
14
+ :return: aggregation value
15
+ """
16
+ if np.ndim(y) != 1:
17
+ raise ValueError("y must be 1 dimensional array")
18
+ return np.mean(y)
19
+
20
+
21
+ # 2
22
+ def quadratic(y):
23
+ if np.ndim(y) != 1:
24
+ raise ValueError("y must be 1 dimensional array")
25
+ y = np.array(y)
26
+ size = len(y)
27
+ with np.errstate(divide='ignore'):
28
+ return np.sqrt(np.sum(y ** 2) / size)
29
+
30
+
31
+ # 3
32
+ def geometric(y):
33
+ if np.ndim(y) != 1:
34
+ raise ValueError("y must be 1 dimensional array")
35
+
36
+ size = len(y)
37
+ wk = 1 / size
38
+ with np.errstate(divide='ignore'):
39
+ return np.prod(y ** wk)
40
+
41
+
42
+ # 4
43
+ def harmonic(y):
44
+ if np.ndim(y) != 1:
45
+ raise ValueError("y must be 1 dimensional array")
46
+ if type(y).__module__ != np.__name__:
47
+ y = np.array(y)
48
+ size = len(y)
49
+ return size / (np.sum(1 / y))
50
+
51
+
52
+ # 5
53
+ def power(y, r=1):
54
+ if np.ndim(y) != 1:
55
+ raise ValueError("y must be 1 dimensional array")
56
+ if r == 0:
57
+ raise ValueError("parameter r cannot be equal to 0 ")
58
+ # If one 0 occur in array then mean is 0
59
+ if 0 in y and r < 0:
60
+ return 0
61
+ else:
62
+ result = (np.sum(y ** r) / y.shape[0]) ** (1 / r)
63
+ return result
64
+
65
+
66
+ # 6
67
+ def exponential(y, r=1):
68
+ if np.ndim(y) != 1:
69
+ raise ValueError("y must be 1 dimensional array")
70
+ if r == 0:
71
+ raise ValueError("parameter r should be != 0 ")
72
+ size = len(y)
73
+ y = np.array(y)
74
+ with np.errstate(divide='ignore'):
75
+ return (1 / r) * np.lib.scimath.log(np.sum(np.exp(y * r)) / size)
76
+
77
+
78
+ # 7
79
+ def lehmer(y, r=0):
80
+ if np.ndim(y) != 1:
81
+ raise ValueError("y must be 1 dimensional array")
82
+ # if array and r below 0 return 0. 0 to power of 0.
83
+ if 0 in y and r - 1 <= 0:
84
+ return 0
85
+ else:
86
+ r2 = (r - 1)
87
+ nominator = np.sum(y ** r)
88
+ with np.errstate(divide='ignore'): #
89
+ denominator = np.sum(y ** r2)
90
+ if denominator == 0:
91
+ return 0
92
+ else:
93
+ return nominator / denominator
94
+
95
+
96
+ # 8
97
+ def arithmetic_min(y, p=0):
98
+ if np.ndim(y) != 1:
99
+ raise ValueError("y must be 1 dimensional array")
100
+ min = np.min(y)
101
+ return p * np.mean(y) + (1 - p) * min
102
+
103
+
104
+ # 9
105
+ def arithmetic_max(y, p=0):
106
+ if np.ndim(y) != 1:
107
+ raise ValueError("y must be 1 dimensional array")
108
+ max = np.max(y)
109
+ return p * np.mean(y) + (1 - p) * max
110
+
111
+
112
+ # 10
113
+ def median(y):
114
+ if np.ndim(y) != 1:
115
+ raise ValueError("y must be 1 dimensional array")
116
+ return np.median(y)
117
+
118
+
119
+ # 11
120
+ def olimpic(y):
121
+ if np.ndim(y) != 1:
122
+ raise ValueError("y must be 1 dimensional array")
123
+ # b = np.max(a, 0) # max
124
+ # c = np.min(a, 0) # min
125
+ if len(y) < 3:
126
+ return np.mean(y)
127
+ else:
128
+ d = np.sort(y)[1:-1]
129
+ return np.mean(d)
130
+
131
+
132
+ def exponential2(y, p=0, q=0):
133
+ if np.ndim(y) != 1:
134
+ raise ValueError("y must be 1 dimensional array")
135
+ y = np.array(y)
136
+ mean = np.mean(p ** (q ** y))
137
+ firstlog = math.log(mean, p)
138
+ result = math.log(firstlog, q)
139
+ return result
140
+
141
+
142
+ def exponential3(y, p=0, q=0):
143
+ if np.ndim(y) != 1:
144
+ raise ValueError("y must be 1 dimensional array")
145
+ y = np.array(y)
146
+ result = (1 / q) * math.log(np.mean(p ** (q * y)), p)
147
+ return result
148
+
149
+
150
+ def sin_aggregation(y):
151
+ '''
152
+
153
+ :param y:
154
+ :return:
155
+ '''
156
+ # Check if 1 dimensional array
157
+ if np.ndim(y) != 1:
158
+ raise ValueError("y must be 1 dimensional array")
159
+ n = len(y)
160
+ return math.asin(np.sum(np.sin(y)) / n)
161
+
162
+
163
+ def quasi_arithmeric(y, function):
164
+ """
165
+ Quasi arithmetic mean.
166
+
167
+ If function f(x)=x to then quasi-arithmetic mean is aritmetic mean.
168
+ If function f(x)=x^p (p != 0) then quasi-arithmetic mean is power mean to p power.
169
+ If function f(x)=log x then quasi-arithmetic mean is geometric mean.
170
+
171
+ :param y: 1 dimmensional array
172
+ :param function: function which maps an interval I of the real line to the real numbers, and is both continuous and injective
173
+ :return: aggregation value
174
+ """
175
+ # Check if 1 dimensional array
176
+ if np.ndim(y) != 1:
177
+ raise ValueError("y must be 1 dimensional array")
178
+ n = len(y)
179
+ apply_func = np.array([function(x) for x in y])
180
+ value = np.sum(apply_func) / n
181
+ return inversefunc(function, value)
182
+
183
+
184
+ if __name__ == "__main__":
185
+ print(quasi_arithmeric.__str__())
186
+ print(arithmetic_min([0.2, 0.4, 0.6], 0))
@@ -0,0 +1,638 @@
1
+ import itertools
2
+ import math
3
+
4
+ import numpy as np
5
+ import re
6
+
7
+
8
+ class A_mn:
9
+ """
10
+ Minimum
11
+ """
12
+
13
+ name = 'mn'
14
+
15
+ def __init__(self):
16
+ pass
17
+
18
+ def __call__(self, array):
19
+ if np.ndim(array) != 1:
20
+ raise ValueError("y must be 1 dimensional array")
21
+ return np.min(array)
22
+
23
+ def __repr__(self):
24
+ return f"A_mn()"
25
+
26
+ def __str__(self):
27
+ return f"A_mn"
28
+
29
+ def toLatex(self, params: str):
30
+ return f"A_{{mn}}({params})"
31
+
32
+
33
+ class A_mx:
34
+ """
35
+ Maximum
36
+ """
37
+
38
+ name = 'mx'
39
+
40
+ def __init__(self):
41
+ pass
42
+
43
+ def __call__(self, array):
44
+ if np.ndim(array) != 1:
45
+ raise ValueError("y must be 1 dimensional array")
46
+ return np.max(array)
47
+
48
+ def __repr__(self):
49
+ return f"A_mx()"
50
+
51
+ def __str__(self):
52
+ return f"A_mx"
53
+
54
+ def toLatex(self, params: str):
55
+ return f"A_{{mx}}({params})"
56
+
57
+ class A_pr:
58
+ """
59
+ Product
60
+ """
61
+
62
+ name = 'pr'
63
+
64
+ def __init__(self):
65
+ pass
66
+
67
+ def __call__(self, array):
68
+ return np.prod(array, axis=0)
69
+
70
+ def __repr__(self):
71
+ return f"A_pr()"
72
+
73
+ def __str__(self):
74
+ return f"A_pr"
75
+
76
+ def toLatex(self, params: str):
77
+ return f"A_{{pr}}({params})"
78
+
79
+ class A_ar:
80
+ """
81
+ Arithmetic mean
82
+ """
83
+
84
+ name = 'ar'
85
+
86
+ def __init__(self):
87
+ pass
88
+
89
+ def __call__(self, array):
90
+ """
91
+ Arithmetic aggregation
92
+ :param y: 1 dimensional array
93
+ :return: aggregation value
94
+ """
95
+ if np.ndim(array) != 1:
96
+ raise ValueError("y must be 1 dimensional array")
97
+ return np.mean(array)
98
+
99
+ def __repr__(self):
100
+ return f"A_ar()"
101
+
102
+ def __str__(self):
103
+ return f"A_ar"
104
+
105
+ def toLatex(self, params: str):
106
+ return f"A_{{ar}}({params})"
107
+
108
+
109
+ class A_qd:
110
+ """
111
+ Quadratic mean
112
+ """
113
+
114
+ name = 'qd'
115
+
116
+ def __init__(self):
117
+ pass
118
+
119
+ def __call__(self, array):
120
+ if np.ndim(array) != 1:
121
+ raise ValueError("y must be 1 dimensional array")
122
+ y = np.array(array)
123
+ size = len(y)
124
+ with np.errstate(divide='ignore'):
125
+ return np.sqrt(np.sum(y ** 2) / size)
126
+
127
+ def __repr__(self):
128
+ return f"A_qd()"
129
+
130
+ def __str__(self):
131
+ return f"A_qd"
132
+
133
+ def toLatex(self, params: str):
134
+ return f"A_{{qd}}({params})"
135
+
136
+
137
+ class A_gm:
138
+ """
139
+ Geometric mean
140
+ """
141
+
142
+ name = 'gm'
143
+
144
+ def __init__(self):
145
+ pass
146
+
147
+ def __call__(self, array):
148
+ if np.ndim(array) != 1:
149
+ raise ValueError("y must be 1 dimensional array")
150
+ size = len(array)
151
+ wk = 1 / size
152
+ with np.errstate(divide='ignore'):
153
+ return np.prod(array ** wk)
154
+
155
+ def __repr__(self):
156
+ return f"A_gm()"
157
+
158
+ def __str__(self):
159
+ return f"A_gm"
160
+
161
+ def toLatex(self, params: str):
162
+ return f"A_{{gm}}({params})"
163
+
164
+
165
+
166
+ class A_hm:
167
+ """
168
+ Harmonic mean
169
+ """
170
+
171
+ name = 'hm'
172
+
173
+ def __init__(self):
174
+ pass
175
+
176
+ def __call__(self, array):
177
+ if np.ndim(array) != 1:
178
+ raise ValueError("y must be 1 dimensional array")
179
+ y = np.array(array)
180
+ size = len(y)
181
+ return size / (np.sum(1 / y))
182
+
183
+ def __repr__(self):
184
+ return f"A_hm()"
185
+
186
+ def __str__(self):
187
+ return f"A_hm"
188
+
189
+ def toLatex(self, params: str):
190
+ return f"A_{{hm}}({params})"
191
+
192
+
193
+ class A_pw:
194
+ """
195
+ Power mean
196
+ """
197
+
198
+ name = 'pw'
199
+
200
+ valid_params = ["r"]
201
+
202
+ def __init__(self, r):
203
+ self.__r = r
204
+
205
+ def __call__(self, array):
206
+ if np.ndim(array) != 1:
207
+ raise ValueError("y must be 1 dimensional array")
208
+ if self.__r == 0:
209
+ raise ValueError("parameter r cannot be equal to 0 ")
210
+ # If one 0 occur in array then mean is 0
211
+ if 0 in array and self.__r < 0:
212
+ return 0
213
+ else:
214
+ result = (np.sum(array ** self.__r) / array.shape[0]) ** (1 / self.__r)
215
+ return result
216
+
217
+ def __repr__(self):
218
+ return f"A_pw(r={self.__r})"
219
+
220
+ def __str__(self):
221
+ return f"A_pw({self.__r})"
222
+
223
+ def toLatex(self, params: str):
224
+ return f"A_{{pw}}^{{{self.__r}}}({params})"
225
+
226
+
227
+ class A_ex:
228
+ """
229
+ Exponential mean
230
+ """
231
+
232
+ name = 'ex'
233
+
234
+ valid_params = ["r"]
235
+
236
+ def __init__(self, r):
237
+ self.__r = r
238
+
239
+ def __call__(self, array):
240
+ if np.ndim(array) != 1:
241
+ raise ValueError("y must be 1 dimensional array")
242
+ if self.__r == 0:
243
+ raise ValueError("parameter r should be != 0 ")
244
+ size = len(array)
245
+ y = np.array(array)
246
+ with np.errstate(divide='ignore'):
247
+ return (1 / self.__r) * np.lib.scimath.log(np.sum(np.exp(y * self.__r)) / size)
248
+
249
+ def __repr__(self):
250
+ return f"A_ex(r={self.__r})"
251
+
252
+ def __str__(self):
253
+ return f"A_ex({self.__r})"
254
+
255
+ def toLatex(self, params: str):
256
+ return f"A_{{ex}}^{{{self.__r}}}({params})"
257
+
258
+
259
+
260
+ class A_ex2:
261
+ """
262
+ Exponential2 mean
263
+ """
264
+
265
+ name = 'ex2'
266
+ valid_params = ["p", "q"]
267
+
268
+ def __init__(self, p, q):
269
+ self.__p = p
270
+ self.__q = q
271
+
272
+ def __call__(self, array):
273
+ if np.ndim(array) != 1:
274
+ raise ValueError("y must be 1 dimensional array")
275
+ y = np.array(array)
276
+ mean = np.mean(self.__p ** (self.__q ** y))
277
+ firstlog = math.log(mean, self.__p)
278
+ result = math.log(firstlog, self.__q)
279
+ return result
280
+
281
+ def __repr__(self):
282
+ return f"A_ex2(p={self.__p}, q={self.__q})"
283
+
284
+ def __str__(self):
285
+ return f"A_ex2({self.__p}, {self.__q})"
286
+
287
+ def toLatex(self, params: str):
288
+ return f"A_{{ex2}}^{{p={self.__p}, q={self.__q}}}({params})"
289
+
290
+
291
+ class A_ex3:
292
+ """
293
+ Exponential3 mean
294
+ """
295
+
296
+ name = 'ex3'
297
+ valid_params = ["p", "q"]
298
+
299
+ def __init__(self, p, q):
300
+ self.__p = p
301
+ self.__q = q
302
+
303
+ def __call__(self, array):
304
+ if np.ndim(array) != 1:
305
+ raise ValueError("y must be 1 dimensional array")
306
+ y = np.array(array)
307
+ result = (1 / self.__q) * math.log(np.mean(self.__p ** (self.__q * y)), self.__p)
308
+ return result
309
+
310
+ def __repr__(self):
311
+ return f"A_ex3(p={self.__p}, q={self.__q})"
312
+
313
+ def __str__(self):
314
+ return f"A_ex3({self.__p}, {self.__q})"
315
+
316
+ def toLatex(self, params: str):
317
+ return f"A_{{ex3}}^{{p={self.__p}, q={self.__q}}}({params})"
318
+
319
+
320
+ class A_lm:
321
+ """
322
+ Lehmer mean
323
+ """
324
+
325
+ name = 'lm'
326
+ valid_params = ["r"]
327
+
328
+ def __init__(self, r):
329
+ self.__r = r
330
+
331
+ def __call__(self, array):
332
+ if np.ndim(array) != 1:
333
+ raise ValueError("y must be 1 dimensional array")
334
+ # if array and r below 0 return 0. 0 to power of 0.
335
+ if 0 in array and self.__r - 1 <= 0:
336
+ return 0
337
+ else:
338
+ r2 = (self.__r - 1)
339
+ nominator = np.sum(array ** self.__r)
340
+ with np.errstate(divide='ignore'): #
341
+ denominator = np.sum(array ** r2)
342
+ if denominator == 0:
343
+ return 0
344
+ else:
345
+ return nominator / denominator
346
+
347
+ def __repr__(self):
348
+ return f"A_lm(r={self.__r})"
349
+
350
+ def __str__(self):
351
+ return f"A_lm({self.__r})"
352
+
353
+ def toLatex(self, params: str):
354
+ return f"A_{{lm}}^{{r={self.__r}}}({params})"
355
+
356
+
357
+ class A_amn:
358
+ """
359
+ Arithmetic minimum mean
360
+ """
361
+
362
+ name = 'amn'
363
+ valid_params = ["p"]
364
+
365
+ def __init__(self, p):
366
+ self.__p = p
367
+
368
+ def __call__(self, array):
369
+ if np.ndim(array) != 1:
370
+ raise ValueError("y must be 1 dimensional array")
371
+ min_val = np.min(array)
372
+ return self.__p * np.mean(array) + (1 - self.__p) * min_val
373
+
374
+ def __repr__(self):
375
+ return f"A_amn(p={self.__p})"
376
+
377
+ def __str__(self):
378
+ return f"A_amn({self.__p})"
379
+
380
+ def toLatex(self, params: str):
381
+ return f"A_{{amn}}^{{p={self.__p}}}({params})"
382
+
383
+
384
+ class A_amx:
385
+ """
386
+ Arithmetic maximum mean
387
+ """
388
+
389
+ name = 'amx'
390
+ valid_params = ["p"]
391
+
392
+ def __init__(self, p):
393
+ self.__p = p
394
+
395
+ def __call__(self, array):
396
+ if np.ndim(array) != 1:
397
+ raise ValueError("y must be 1 dimensional array")
398
+ max_val = np.max(array)
399
+ return self.__p * np.mean(array) + (1 - self.__p) * max_val
400
+
401
+ def __repr__(self):
402
+ return f"A_amx(p={self.__p})"
403
+
404
+ def __str__(self):
405
+ return f"A_amx({self.__p})"
406
+
407
+ def toLatex(self, params: str):
408
+ return f"A_{{amx}}^{{p={self.__p}}}({params})"
409
+
410
+
411
+ class A_md:
412
+ """
413
+ Median (Ordered weighted aggregation)
414
+ """
415
+
416
+ name = 'md'
417
+
418
+ def __init__(self):
419
+ pass
420
+
421
+ def __call__(self, array):
422
+ if np.ndim(array) != 1:
423
+ raise ValueError("y must be 1 dimensional array")
424
+ return np.median(array)
425
+
426
+ def __repr__(self):
427
+ return f"A_md()"
428
+
429
+ def __str__(self):
430
+ return f"A_md"
431
+
432
+ def toLatex(self, params: str):
433
+ return f"A_{{md}}({params})"
434
+
435
+
436
+ class A_ol:
437
+ """
438
+ Olimpic mean
439
+ """
440
+
441
+ name = 'ol'
442
+
443
+ def __init__(self):
444
+ pass
445
+
446
+ def __call__(self, array):
447
+ if np.ndim(array) != 1:
448
+ raise ValueError("y must be 1 dimensional array")
449
+ if len(array) < 3:
450
+ return np.mean(array)
451
+ else:
452
+ d = np.sort(array)[1:-1]
453
+ return np.mean(d)
454
+
455
+ def __repr__(self):
456
+ return f"A_ol()"
457
+
458
+ def __str__(self):
459
+ return f"A_ol"
460
+
461
+ def toLatex(self, params: str):
462
+ return f"A_{{ol}}({params})"
463
+
464
+
465
+ class A_oln:
466
+ """
467
+ Generalized olimpic mean
468
+ """
469
+
470
+ name = 'oln'
471
+ valid_params = ['n']
472
+
473
+ def __init__(self, n):
474
+ self.__n = n
475
+
476
+ def __call__(self, array):
477
+ if np.ndim(array) != 1:
478
+ raise ValueError("y must be 1 dimensional array")
479
+ if len(array) <= self.__n * 2:
480
+ return np.mean(array)
481
+ else:
482
+ d = np.sort(array)[self.__n:-self.__n]
483
+ return np.mean(d)
484
+
485
+ def __repr__(self):
486
+ return f"A_oln(n={self.__n})"
487
+
488
+ def __str__(self):
489
+ return f"A_oln({self.__n})"
490
+
491
+ def toLatex(self, params: str):
492
+ return f"A_{{oln}}^{{n={self.__n}}}({params})"
493
+
494
+
495
+ # TODO test this aggregation
496
+ class A_lo:
497
+ """
498
+ Generalized logarithmic mean
499
+ If large number of arguments its numerically unstable
500
+ """
501
+
502
+ name = 'lo'
503
+
504
+ def __init__(self):
505
+ pass
506
+
507
+ def __call__(self, array):
508
+ if np.ndim(array) != 1:
509
+ raise ValueError("y must be 1 dimensional array")
510
+ fact = math.factorial(len(array) - 1)
511
+ sum_ = 0
512
+ for i in range(len(array)):
513
+ prod_ = 1
514
+ for j in range(len(array)):
515
+ if i != j:
516
+ if array[j] == 0: return 0
517
+ prod_ *= math.log(array[i] / array[j])
518
+ sum_ += array[i] / prod_
519
+ return fact * sum_
520
+
521
+ def __repr__(self):
522
+ return f"A_lo()"
523
+
524
+ def __str__(self):
525
+ return f"A_lo"
526
+
527
+ def toLatex(self, params: str):
528
+ return f"A_{{lo}}({params})"
529
+
530
+
531
+ class Combine2Aggregations:
532
+ def __init__(self, aggregation_function1, aggregation_function2, p=0.5):
533
+ self.__agg1 = aggregation_function1
534
+ self.__agg2 = aggregation_function2
535
+ self.__p = p
536
+
537
+ def __call__(self, array):
538
+ if np.ndim(array) != 1:
539
+ raise ValueError("y must be 1 dimensional array")
540
+ return self.__p * self.__agg1(array) + (1 - self.__p) * self.__agg2(array)
541
+
542
+ def __str__(self):
543
+ pattern = r'A_(.*?)\('
544
+ params_pattern = r'\((.*?)\)'
545
+
546
+ agg1 = re.search(pattern, self.__agg1.__repr__()).group(1)
547
+ agg2 = re.search(pattern, self.__agg2.__repr__()).group(1)
548
+ result = f"A_{agg1}{agg2}({self.__p}"
549
+
550
+ agg1_param = re.search(params_pattern, self.__agg1.__str__())
551
+ if agg1_param is not None:
552
+ agg1_param = agg1_param.group(1)
553
+ result += f", {agg1_param}"
554
+
555
+ agg2_param = re.search(params_pattern, self.__agg2.__str__())
556
+ if agg2_param is not None:
557
+ agg2_param = agg2_param.group(1)
558
+ result += f", {agg2_param}"
559
+ result += ")"
560
+ return result
561
+
562
+ def __repr__(self):
563
+ pattern = r'A_(.*?)\('
564
+ params_pattern = r'\((.*?)\)'
565
+
566
+ agg1 = re.search(pattern, self.__agg1.__repr__()).group(1)
567
+ agg2 = re.search(pattern, self.__agg2.__repr__()).group(1)
568
+ result = f"A_{agg1}{agg2}(p={self.__p}"
569
+
570
+ agg1_param = re.search(params_pattern, self.__agg1.__repr__()).group(1)
571
+ if agg1_param != "":
572
+ result += f", {agg1_param}"
573
+
574
+ agg2_param = re.search(params_pattern, self.__agg2.__repr__()).group(1)
575
+ if agg2_param != "":
576
+ result += f", {agg2_param}"
577
+ result += ")"
578
+ return result
579
+
580
+ def toLatex(self, params: str):
581
+ pqrn = f"{self.__p}"
582
+
583
+ # Inicjalizacja słownika dla wartości p, q, r, n
584
+ values = {'p': [], 'q': [], 'r': [], 'n': []}
585
+
586
+ # Iteracja po agregatorach
587
+ for agg in [self.__agg1, self.__agg2]:
588
+ for attr in values.keys():
589
+ # Pobranie wartości atrybutu dla danego agregatora, jeśli istnieje
590
+ value = getattr(agg, f'__{attr}', None)
591
+ if value is not None:
592
+ values[attr].append(str(value))
593
+
594
+ # Dodanie wartości do pqrn
595
+ for attr, val_list in values.items():
596
+ if val_list:
597
+ pqrn += f" {attr}= {', '.join(val_list)}"
598
+
599
+ return f"A_{{{self.__agg1.name},{self.__agg2.name}}}^{{{pqrn}}}({params})"
600
+
601
+
602
+ if __name__ == "__main__":
603
+ # example data
604
+ data = [0.2, 0.6, 0.7]
605
+ # configure function parameters
606
+ func1 = A_amn(p=0.5)
607
+ # use aggregation funciton
608
+ print(func1(data))
609
+
610
+ # Combine two aggregations - arithmetic mean and minimum
611
+ func2 = Combine2Aggregations(A_ar(), min)
612
+ # use combination of aggregation funciton
613
+ print(func2(data))
614
+
615
+ func1 = A_amn(p=0.5)
616
+ print(func1)
617
+
618
+ func2 = Combine2Aggregations(A_ar(), A_md())
619
+ print(func2)
620
+
621
+ func3 = Combine2Aggregations(A_ar(), A_pw(r=3))
622
+ print(func3.__repr__()) # function parameters are printed in order: func1, func2
623
+
624
+ aggregation_functions = []
625
+ ex_params = [0.2, 0.5, 1, 2, 3, 5]
626
+ for param in ex_params:
627
+ aggregation_functions.append(A_ex(param))
628
+
629
+ aggregation_functions += [A_mn(), A_mx(), A_ar(), A_md(),
630
+ A_ol()]
631
+
632
+ combinations = []
633
+ for func1, func2 in itertools.combinations(aggregation_functions, 2):
634
+ for p in range(1, 10):
635
+ combinations.append(Combine2Aggregations(func1, func2, p=p / 10))
636
+
637
+ for x in combinations:
638
+ print(x.__repr__())
File without changes
@@ -0,0 +1,5 @@
1
+ def product(y):
2
+ _prod = 1
3
+ for x in y:
4
+ _prod *= x
5
+ return _prod
@@ -0,0 +1,256 @@
1
+ import logging
2
+ import numbers
3
+ import warnings
4
+
5
+ from decimal import Decimal
6
+
7
+ # 1 Arithmetic aggregation
8
+ import numpy as np
9
+
10
+
11
+ def arithmetic(y):
12
+ """
13
+ Arithmetic aggregation
14
+ :param y: 1 dimensional array
15
+ :return: aggregation value
16
+ """
17
+ _sum = Decimal('0')
18
+ n_elems = len(y)
19
+ for num in y:
20
+ try:
21
+ _sum += num
22
+ except:
23
+ _sum += Decimal(str(num))
24
+ warnings.warn("Numbers in iterable are converted to Decimal automatically.")
25
+ return _sum / n_elems
26
+
27
+
28
+ # 2
29
+ def quadratic(y):
30
+ n = len(y)
31
+ _sum = Decimal('0')
32
+ for num in y:
33
+ try:
34
+ _sum += num ** 2
35
+ except:
36
+ _sum += Decimal(str(num)) ** 2
37
+ warnings.warn("Numbers in iterable are converted to Decimal automatically.")
38
+ return Decimal.sqrt(_sum / n)
39
+
40
+
41
+ # 3
42
+ def geometric(y):
43
+ """
44
+ y should contain only positive numbers [0, inf]
45
+ :param y:
46
+ :return:
47
+ """
48
+ _prod = Decimal('1')
49
+ n = Decimal(len(y))
50
+
51
+ for num in y:
52
+ try:
53
+ _prod *= num ** (1 / n)
54
+ except:
55
+ _prod *= Decimal(str(num)) ** (1 / n)
56
+ warnings.warn("Numbers in iterable are converted to Decimal automatically.")
57
+ return _prod
58
+
59
+
60
+ # 4
61
+ def harmonic(y):
62
+ """
63
+ WARNING if sum of denominator is 0 eg. [-10, 0 ,10] then function return 0.
64
+ WARNING if y cointains 0 then return 0.
65
+ :param y:
66
+ :return:
67
+ """
68
+ n = Decimal(len(y))
69
+
70
+ y_dec = []
71
+ for x in y:
72
+ if isinstance(x, numbers.Number):
73
+ val = Decimal(str(x))
74
+ y_dec.append(val)
75
+ else:
76
+ raise ValueError("y should contain numbers in 1D iterable object.")
77
+
78
+ _sum = Decimal('0')
79
+ for num in y_dec:
80
+ if num == 0:
81
+ warnings.warn("y contains 0 for hearmonic(" + str(y) + ")")
82
+ return Decimal('0')
83
+ _sum += Decimal('1') / num
84
+
85
+
86
+ if _sum == 0:
87
+ warnings.warn("sum of denominator is equal to 0 for hearmonic(" + str(y) + ")")
88
+ return Decimal('0')
89
+ return n / _sum
90
+
91
+
92
+ # 5
93
+ def power(y, r=1):
94
+ if r == 0:
95
+ raise ValueError("parameter r cannot be equal to 0 ")
96
+ # If one 0 occur in array then mean is 0
97
+ if 0 in y and r < 0:
98
+ return 0
99
+ else:
100
+ n = Decimal(len(y))
101
+
102
+ _sum = Decimal('0')
103
+ for num in y:
104
+ try:
105
+ _sum += num ** r
106
+ except:
107
+ _sum += Decimal(str(num)) ** r
108
+ warnings.warn("Numbers in iterable are converted to Decimal automatically.")
109
+
110
+ return (_sum / n) ** (1 / Decimal(r))
111
+
112
+
113
+ # 6
114
+ def exponential(y, r=1):
115
+ """
116
+ Mean is given by equation:
117
+ $A_6^{(r)}(x_1,...,x_n)= \frac{1}{r}\ln
118
+ \Big(\frac{1}{n} \sum \limits_{k=1}^{n} e^{rx_k}\Big)$, where
119
+ $r \in \mathbb{R}$, $r \neq 0$
120
+
121
+ :param y: array of values
122
+ :param r: r != 0
123
+ :return: value of exponential mean
124
+ """
125
+ size = Decimal(str(len(y)))
126
+ r = Decimal(r)
127
+ if r == 0:
128
+ raise ValueError("parameter r should be != 0 ")
129
+
130
+ # Convert y to Decimal
131
+ y_dec = []
132
+ for x in y:
133
+ if isinstance(x, numbers.Number):
134
+ val = Decimal(str(x))
135
+ y_dec.append(val)
136
+ else:
137
+ raise ValueError("y should contain numbers in 1D iterable object.")
138
+
139
+ _sum = Decimal('0')
140
+ for idx, num in enumerate(y_dec):
141
+ _sum += (num * r).exp()
142
+
143
+ # # Comparasion to numpy
144
+ # # np_sum = np.sum(np.exp(y * int(r)))
145
+ # # np_sum_log = np.lib.scimath.log(np_sum / len(y))
146
+
147
+ return (1 / r) * (_sum / size).ln()
148
+
149
+
150
+ # 7
151
+ def lehmer(y, r=0):
152
+ r = Decimal(r)
153
+ if 0 in y and r - 1 <= 0:
154
+ return 0
155
+ else:
156
+ r2 = (r - 1)
157
+ _nominator = Decimal('0')
158
+ _denominator = Decimal('0')
159
+ for num in y:
160
+ try:
161
+ _nominator += num ** r
162
+ _denominator += num ** r2
163
+ except:
164
+ _nominator += Decimal(str(num)) ** r
165
+ _denominator += Decimal(str(num)) ** r2
166
+ warnings.warn("Numbers in iterable are converted to Decimal automatically.")
167
+
168
+ if _denominator == 0:
169
+ return 0
170
+ else:
171
+ return _nominator / _denominator
172
+
173
+
174
+ # 8
175
+ def arithmetic_min(y, p=0):
176
+ p = Decimal(p)
177
+ _min = Decimal(min(y))
178
+ return p * arithmetic(y) + (1 - p) * _min
179
+
180
+
181
+ # 9
182
+ def arithmetic_max(y, p=0):
183
+ p = Decimal(p)
184
+ _max = Decimal(max(y))
185
+ return p * arithmetic(y) + (1 - p) * _max
186
+
187
+
188
+ # 10
189
+ def median(y):
190
+ n = len(y)
191
+ if n % 2 == 0:
192
+ return arithmetic([y[(n / 2) - 1], y[n / 2]])
193
+ else:
194
+ return y[n // 2]
195
+
196
+
197
+ # 11
198
+ def olimpic(y):
199
+ if len(y) < 3:
200
+ return arithmetic(y)
201
+ else:
202
+ d = sorted(y)
203
+ d = d[1:-1]
204
+ return arithmetic(d)
205
+
206
+
207
+ def exponential2(y, p=0, q=0):
208
+ pass
209
+
210
+
211
+ def exponential3(y, p=0, q=0):
212
+ pass
213
+
214
+
215
+ def sin_aggregation(y):
216
+ pass
217
+
218
+
219
+ def quasi_arithmeric(y, function):
220
+ pass
221
+
222
+
223
+ if __name__ == "__main__":
224
+ y = [-10, -22, 10]
225
+ # 1
226
+ print(arithmetic(y))
227
+
228
+ # 2
229
+ print(quadratic(y))
230
+
231
+ # 3
232
+ print(geometric(y))
233
+
234
+ # # 4
235
+ print(harmonic(y))
236
+
237
+ # 5
238
+ print(power(y, r=1))
239
+
240
+ # 6
241
+ print(exponential(y, r=1))
242
+
243
+ # 7
244
+ print(lehmer(y, r=0))
245
+
246
+ # 8
247
+ print(arithmetic_min(y, p=0))
248
+
249
+ # 9
250
+ print(arithmetic_max(y, p=0))
251
+
252
+ # 10
253
+ print(median(y))
254
+
255
+ # 11
256
+ print(olimpic(y))
File without changes
@@ -0,0 +1,8 @@
1
+ import math
2
+
3
+ import aggregation
4
+
5
+ array = [1, 2, 3, 4]
6
+ print(aggregation.sin_aggregation(array))
7
+ print(aggregation.quasi_arithmeric(array,math.sin))
8
+
@@ -0,0 +1,25 @@
1
+ import math
2
+
3
+ import numpy as np
4
+
5
+
6
+ def exponential(y, r=1):
7
+ """
8
+ Mean is given by equation:
9
+ $A_6^{(r)}(x_1,...,x_n)= \frac{1}{r}\ln
10
+ \Big(\frac{1}{n} \sum \limits_{k=1}^{n} e^{rx_k}\Big)$, where
11
+ $r \in \mathbb{R}$, $r \neq 0$
12
+
13
+ :param y: array of values
14
+ :param r: r != 0
15
+ :return: value of exponential mean
16
+ """
17
+ size = len(y)
18
+ if r == 0:
19
+ raise ValueError("parameter r should be != 0 ")
20
+
21
+ _sum = 0
22
+ for idx, num in enumerate(y):
23
+ _sum += math.exp(num * r)
24
+
25
+ return (1 / r) * math.log(_sum / size)
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.2
2
+ Name: aggregationslib
3
+ Version: 0.0.0
4
+ Summary: Python implementation of Arithmetic, quasi arithmetic and other aggregating functions
5
+ Home-page: https://github.com/wgalka/Means
6
+ Download-URL: https://github.com/wgalka/Means/archive/refs/tags/v0.0.3.tar.gz
7
+ Author: wgalka
8
+ License: TO DOO
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.13
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: numpy>=2.2.2
15
+ Requires-Dist: pynverse
16
+ Provides-Extra: test
17
+ Requires-Dist: pytest>=8.3.4; extra == "test"
18
+ Dynamic: author
19
+ Dynamic: classifier
20
+ Dynamic: description
21
+ Dynamic: description-content-type
22
+ Dynamic: download-url
23
+ Dynamic: home-page
24
+ Dynamic: license
25
+ Dynamic: provides-extra
26
+ Dynamic: requires-dist
27
+ Dynamic: requires-python
28
+ Dynamic: summary
29
+
30
+ # Means
31
+ Means, Aggregation functions...
32
+
33
+ Aggregations functions are:
34
+ - Conjuctive - the final aggregated value will always be influenced by the smallest value among the inputs.
35
+ - Disjnuctive - the aggregated value will always be influenced by the largest value among the inputs.
36
+
37
+ #### Example 1:
38
+
39
+ ```pycon
40
+ # example data
41
+ data = [0.2, 0.6, 0.7]
42
+ # configure function parameters
43
+ func1 = A_amn(p=0.5)
44
+ # use aggregation funciton
45
+ print(func1(data))
46
+
47
+ # Combine two aggregations - arithmetic mean and minimum
48
+ func2 = Combine2Aggregations(A_ar(), min)
49
+ # use combination of aggregation funciton
50
+ print(func2(data))
51
+ ```
52
+
53
+ #### Example2:
54
+ To get information about aggregation function you can use `__str__()` or '__repr__()' methods.
55
+
56
+ ```pycon
57
+ func1 = A_amn(p=0.5)
58
+ print(func1)
59
+ >>>A_amn(0.5)
60
+
61
+ func2 = Combine2Aggregations(A_ar(), A_md())
62
+ print(func2)
63
+ >>>A_armd
64
+
65
+ func3 = Combine2Aggregations(A_ar(), A_pw(r=3))
66
+ print(func3.__repr__()) # function parameters are printed in order: func1, func2
67
+ >>>A_arpw(r=3)
68
+ ```
69
+
70
+ `exponential(y, r=1)` is given by equation
71
+
72
+ $$
73
+ A_6^{(r)}(x_1,...,x_n)= \frac{1}{r}\ln
74
+ \Big(\frac{1}{n} \sum \limits_{k=1}^{n} e^{rx_k}\Big), where
75
+ r \in \mathbb{R}, r \neq 0
76
+ $$
77
+
78
+
79
+ # A_ar - Arithmetic mean
80
+
81
+
82
+ # A_qd - Quadratic mean
83
+
84
+
85
+ # A_gm - Geometric mean
86
+
87
+
88
+ # A_hm - Harmonic mean
89
+
90
+
91
+ # A_pw - Power mean
92
+
93
+
94
+ # A_ex, A_ex2, A_ex3 - Exponential mean
95
+
96
+
97
+ # A_lm - Lehmer mean
98
+
99
+
100
+ # A_amn - Arithmetic minimum mean
101
+
102
+
103
+ # A_amx - Arithmetic maximum mean
104
+
105
+
106
+ # A_md - Median - ordered weighted aggregation
107
+
108
+
109
+ # A_ol - Olimpic aggregation
110
+
111
+ # A_oln - Olimpic aggregation
112
+ We can specify how many greatest and smallest records remove
113
+
114
+ # A_ln - Logaritmic aggregation
115
+
116
+ https://www.researchgate.net/publication/228886844_Logarithmic_mean_for_several_arguments
117
+
118
+ $$
119
+ L\left(x_1, x_2, \ldots, x_n\right)=(n-1) ! \sum_{i=1}^n \frac{x_i}{\prod_{\substack{j=1 \\ j \neq i}}^n \log \left(x_i / x_j\right)}
120
+ $$
121
+
122
+ # Combine2Aggregations - Combine aggregation functions
123
+ Amn, Amx, Aar , Aex , Amd,
124
+ Aow1, Aow1
@@ -0,0 +1,13 @@
1
+ aggregationslib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ aggregationslib/aggregation.py,sha256=xByHAEHVtu3PdnK21dJz9bayKqEO9_8xPjDGQytMpSY,4565
3
+ aggregationslib/aggregations.py,sha256=CPkielX2iM_wVXN3z0SfNE4Dxs1HMeX3R5h9kx2la0U,14644
4
+ aggregationslib/decimalaggregations.py,sha256=FYwro4KcojPH7ZMAEcKoE7MHN_1ojaTDY0UkEAzJN0M,5351
5
+ aggregationslib/example.py,sha256=4y3caiSBq4jkqz88Qan1m0LB389TXvlf7VSOPC_1Cj4,149
6
+ aggregationslib/purepython.py,sha256=Ov7AuBHLzoebS7HwTsDo8Ceed5pMzn3i71uevHnHbno,557
7
+ aggregationslib/conjuctive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ aggregationslib/conjuctive/purepython.py,sha256=f7YOyrEvaTiBhWDyJrKPbWrym2PGFYIkTqfE2u1lOvk,82
9
+ aggregationslib/disjunctive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ aggregationslib-0.0.0.dist-info/METADATA,sha256=VMvpYwwRkLWSCFfusZVJK_SlVcrEO7SnWrWfAY9_mec,2977
11
+ aggregationslib-0.0.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
12
+ aggregationslib-0.0.0.dist-info/top_level.txt,sha256=aAqYX4rNyBs40QOh2hc-jTE08IsMq0haGyyy7-GSdUQ,16
13
+ aggregationslib-0.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.8.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ aggregationslib