ararpy 0.0.1a1__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.
ararpy/calc/arr.py ADDED
@@ -0,0 +1,490 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: UTF-8 -*-
3
+ """
4
+ # ==========================================
5
+ # Copyright 2023 Yang
6
+ # ararpy - calc - arr
7
+ # ==========================================
8
+ #
9
+ # Basic functions related to array-like objects
10
+ # List, np.array, pd.DataFrame
11
+ #
12
+ """
13
+
14
+ # === Internal import ===
15
+ import traceback
16
+
17
+ from ..calc import err
18
+ # === External import ===
19
+ import re
20
+ import numpy as np
21
+ from scipy.stats import distributions
22
+ # import pandas as pd
23
+ # import decimal
24
+ # from math import exp, log, cos, acos, ceil, sqrt, atan, sin, gamma
25
+ # from typing import List, Any
26
+ # from scipy.optimize import fsolve
27
+
28
+
29
+ # =======================
30
+ # Error propagation for array-like objects
31
+ # =======================
32
+ def mul(*args):
33
+ """
34
+ Parameters
35
+ ----------
36
+ args :
37
+ 2D array like objects of numbers
38
+ lists: [[1, 2, 3], [1, 2, 3]], [[3, 4, 5], [3, 4, 5]]
39
+ np.array([[1, 2, 3], [1, 2, 3]]), np.array([[3, 4, 5], [3, 4, 5]])
40
+ pd.DataFrame([[1, 1], [2, 2], [3, 3]]), pd.DataFrame([[3, 3], [4, 4], [5, 5]])
41
+
42
+ Returns
43
+ -------
44
+ 2D list, [values, errors]
45
+ """
46
+ n = np.shape([args])[-1]
47
+ k0, k1 = [1] * n, [0] * n
48
+ k2 = []
49
+ for i in range(n):
50
+ for arg in args:
51
+ k0[i] = np.multiply(k0[i], arg[0][i])
52
+ k1[i] = k1[i] + np.divide(arg[1][i] ** 2, arg[0][i] ** 2)
53
+ k2.append(abs(k0[i]) * k1[i] ** .5)
54
+ return [k0, k2]
55
+
56
+
57
+ def div(a, b):
58
+ """
59
+ Y = a / b
60
+ Parameters
61
+ ----------
62
+ a : two dimensional array like objects of numbers
63
+ b : two dimensional array like objects of numbers
64
+ lists: [[1, 2, 3], [1, 2, 3]], [[3, 4, 5], [3, 4, 5]]
65
+ np.array([[1, 2, 3], [1, 2, 3]]), np.array([[3, 4, 5], [3, 4, 5]])
66
+ pd.DataFrame([[1, 1], [2, 2], [3, 3]]), pd.DataFrame([[3, 3], [4, 4], [5, 5]])
67
+
68
+ Returns
69
+ -------
70
+ [values, errors]
71
+ """
72
+ n = np.shape([a, b])[-1]
73
+ k0, k1 = [], []
74
+ for i in range(n):
75
+ k0.append(np.divide(a[0][i], b[0][i]))
76
+ k1.append(
77
+ (np.divide(a[1][i] ** 2, b[0][i] ** 2) +
78
+ np.divide(a[0][i] ** 2 * b[1][i] ** 2, b[0][i] ** 4)) ** .5)
79
+ return [k0, k1]
80
+
81
+
82
+ def rec(a):
83
+ """
84
+ Parameters
85
+ ----------
86
+ a :
87
+ 2D array like objects of numbers
88
+
89
+ Returns
90
+ -------
91
+ 2D list, [values, errors]
92
+ """
93
+ try:
94
+ n = np.shape(a)[1]
95
+ k0, k1 = [], []
96
+ for i in range(n):
97
+ k0.append(np.divide(1, a[0][i]))
98
+ k1.append(err.rec((a[0][i], a[1][i])))
99
+ return [k0, k1]
100
+ except IndexError:
101
+ return [1 / a[0], err.rec(a)]
102
+
103
+
104
+ def add(*args):
105
+ """ For y = x1 + x2 + ...
106
+ Parameters
107
+ ----------
108
+ args : two dimensional lists, or tuple of two list
109
+ [x1, sx1], [x2, sx2], ...
110
+
111
+ Returns
112
+ -------
113
+ list
114
+ """
115
+ n = np.shape(args)[-1]
116
+ k0, k1 = [], []
117
+ for i in range(n):
118
+ k0.append(sum([arg[0][i] for arg in args]))
119
+ k1.append(err.add(*[arg[1][i] for arg in args]))
120
+ return [k0, k1]
121
+
122
+
123
+ def sub(*args):
124
+ """ For y = x1 - x2 - ...
125
+ Parameters
126
+ ----------
127
+ args : two dimensional lists, or tuple of two list
128
+ [x1, sx1], [x2, sx2], ...
129
+
130
+ Returns
131
+ -------
132
+
133
+ """
134
+ n = np.shape(args)[-1]
135
+ k0, k1 = [], []
136
+ for i in range(n):
137
+ k0.append(sum([arg[0][i] * [-1, 1][index == 0] for index, arg in enumerate(args)]))
138
+ k1.append(err.add(*[arg[1][i] for arg in args]))
139
+ return [k0, k1]
140
+
141
+
142
+ def cor(sx: list, sy: list, sz: list):
143
+ """
144
+ Parameters
145
+ ----------
146
+ sx
147
+ sy
148
+ sz
149
+
150
+ Returns
151
+ -------
152
+
153
+ """
154
+ n = np.shape([sx, sy, sz])[-1]
155
+ return [err.cor(sx[i], sy[i], sz[i]) for i in range(n)]
156
+
157
+
158
+ def mul_factor(a, factor, isRelative: bool = False):
159
+ """ a × factor
160
+ Parameters
161
+ ----------
162
+ a :
163
+ factor : two dimensional list
164
+ isRelative : if the error of factor is relative
165
+
166
+ Returns
167
+ -------
168
+
169
+ """
170
+ f, sf = np.array(factor)
171
+ if isRelative:
172
+ sf = f * sf * 100
173
+ return mul(a, (f, sf))
174
+
175
+
176
+ def rec_factor(factor, isRelative: bool = False):
177
+ """ 1 / factor
178
+ Parameters
179
+ ----------
180
+ factor : two dimensional list
181
+ isRelative : if the error of factor is relative
182
+
183
+ Returns
184
+ -------
185
+
186
+ """
187
+ f, sf = np.array(factor)
188
+ if isRelative:
189
+ sf = f * sf * 100
190
+ return rec((f, sf))
191
+
192
+
193
+ # =======================
194
+ # Basic functions for array-like objects
195
+ # =======================
196
+ def partial(a: list, rows=None, cols=None):
197
+ """ Get partial object from a two dimensional list according to the given rows and cols.
198
+
199
+ Parameters
200
+ ----------
201
+ a : two dimensional array-like object with shape of (m, n)
202
+ rows :
203
+ rows index like [1, 2, ...], or int
204
+ cols :
205
+ cols index like [0 ,1, ...], or int
206
+
207
+ Returns
208
+ -------
209
+ array-like object, if rows or cols is int, one dimensional list will be returned
210
+ """
211
+ res = []
212
+ try:
213
+ (m, n) = np.shape(a)
214
+ except ValueError:
215
+ # ValueError, the requested array has an inhomogeneous shape
216
+ return partial(homo(a), rows=rows, cols=cols)
217
+ if rows is None:
218
+ rows = list(range(n))
219
+ if cols is None:
220
+ cols = list(range(m))
221
+ if isinstance(cols, list):
222
+ res = [a[i] for i in cols]
223
+ elif isinstance(cols, int):
224
+ res = a[cols]
225
+ if isinstance(rows, list):
226
+ if isinstance(cols, list):
227
+ res = [[i[j] for j in rows] for i in res]
228
+ else:
229
+ res = [res[i] for i in rows]
230
+ elif isinstance(rows, int):
231
+ res = res[rows]
232
+ return res
233
+
234
+
235
+ def array_as_float(p_object):
236
+ """ Get array of floats from list like object
237
+ Parameters
238
+ ----------
239
+ p_object
240
+
241
+ Returns
242
+ -------
243
+
244
+ """
245
+ try:
246
+ return np.array(p_object, dtype=np.float64)
247
+ except ValueError as e:
248
+ item = str(e).split('could not convert string to float: ')
249
+ return array_as_float(replace(p_object, item[1][1:-1], np.nan))
250
+
251
+
252
+ def replace(array, old, new):
253
+ """ Replace all old items with new items in a array
254
+
255
+ Parameters
256
+ ----------
257
+ array
258
+ old : function or object
259
+ new
260
+
261
+ Returns
262
+ -------
263
+
264
+ """
265
+ if np.iterable(array) and not isinstance(array, str):
266
+ res = [replace(i, old, new) for i in array]
267
+ else:
268
+ if callable(old):
269
+ if old(array):
270
+ res = new
271
+ else:
272
+ res = old
273
+ elif array in [old]:
274
+ res = new
275
+ else:
276
+ res = array
277
+ return res
278
+
279
+
280
+ def remove(array, old):
281
+ """ Remove all old items
282
+
283
+ Parameters
284
+ ----------
285
+ array : n dimensional list
286
+ old : tuple, like (None, ), (None, np.nan)
287
+
288
+ Returns
289
+ -------
290
+
291
+ """
292
+ if is_oneD(array):
293
+ res = []
294
+ for each in array:
295
+ if each in old:
296
+ continue
297
+ res.append(each)
298
+ else:
299
+ res = [remove(each, old=old) for each in array]
300
+ return res
301
+
302
+
303
+ def merge(*args):
304
+ """ Merge list objects, one dimensional or two dimensional list should be passed in.
305
+
306
+ Parameters
307
+ ----------
308
+ args : one or two dimensional list
309
+
310
+ Returns
311
+ -------
312
+
313
+ """
314
+ res = []
315
+ for arg in args:
316
+ if is_oneD(arg):
317
+ res.append(arg)
318
+ else:
319
+ res = res + arg
320
+ return res
321
+
322
+
323
+ def is_empty(a):
324
+ """ Check if a list is empty. Return True if it is empty, or it is not a list,
325
+ or all items in it are '', None or np.nan.
326
+
327
+ Parameters
328
+ ----------
329
+ a : list
330
+
331
+ Returns
332
+ -------
333
+ bool. True if a is empty or is not a instance of list
334
+ """
335
+ if not isinstance(a, list) or a == [] or len(a) == 0:
336
+ return True
337
+ for i in a:
338
+ if i not in ['', None, np.nan]:
339
+ return False
340
+ return True
341
+
342
+
343
+ def ndim(obj):
344
+ """
345
+
346
+ Parameters
347
+ ----------
348
+ obj
349
+
350
+ Returns
351
+ -------
352
+
353
+ """
354
+ if np.iterable(obj) and not isinstance(obj, str):
355
+ if len(obj) == 0:
356
+ return 1
357
+ return max([ndim(i) for i in obj]) + 1
358
+ return 0
359
+
360
+
361
+ def is_oneD(obj):
362
+ """ Check if a list-like object is one dimensional
363
+ Parameters
364
+ ----------
365
+ obj
366
+
367
+ Returns
368
+ -------
369
+
370
+ """
371
+ try:
372
+ return ndim(obj) == 1
373
+ except (ValueError, AttributeError):
374
+ return False
375
+
376
+
377
+ def is_twoD(obj):
378
+ """ Check if a list-like object is two dimensional
379
+ Parameters
380
+ ----------
381
+ obj
382
+
383
+ Returns
384
+ -------
385
+
386
+ """
387
+ try:
388
+ return ndim(obj) == 2
389
+ except (ValueError, AttributeError):
390
+ return False
391
+
392
+
393
+ def is_homo(obj):
394
+ """ Check if the requested obj is homogeneous
395
+
396
+ Parameters
397
+ ----------
398
+ obj
399
+
400
+ Returns
401
+ -------
402
+
403
+ """
404
+ try:
405
+ np.shape(obj)
406
+ except (ValueError, AttributeError):
407
+ return False
408
+ else:
409
+ return True
410
+
411
+
412
+ def homo(obj):
413
+ """ Get a homogeneous two dimensional list. If the passed list object is inhomogeneous,
414
+ np.nan will be added to make it homogeneous.
415
+
416
+ Parameters
417
+ ----------
418
+ obj : two dimensional list
419
+
420
+ Returns
421
+ -------
422
+
423
+ """
424
+ if not is_twoD(obj):
425
+ return obj
426
+ try:
427
+ np.shape(obj)
428
+ except (ValueError, AttributeError):
429
+ pass
430
+ else:
431
+ return obj
432
+ length = max(len(i) for i in obj)
433
+ return [i if len(i) == length else i + [np.nan] * (length - len(i)) for i in obj]
434
+
435
+
436
+ def transpose(obj, ignore: bool = True):
437
+ """ Get the transpose of a list-like object
438
+ Parameters
439
+ ----------
440
+ obj : two dimensional list-like object
441
+ ignore : return obj if ingore error is true
442
+
443
+ Returns
444
+ -------
445
+
446
+ """
447
+ try:
448
+ if not is_twoD(obj):
449
+ raise ValueError("The requested object is not two dimensional.")
450
+ obj = obj if is_homo(obj) else homo(obj)
451
+ m, n = np.shape(obj)
452
+ return [[obj[i][j] for i in range(m)] for j in range(n)]
453
+ except (ValueError, TypeError):
454
+ # print(traceback.format_exc())
455
+ if ignore:
456
+ return obj
457
+
458
+
459
+ # =======================
460
+ # Weighted mean
461
+ # =======================
462
+ def wtd_mean(a: list, e: list, sf: int = 1, adjust_error: bool = True):
463
+ """
464
+ :param a: x
465
+ :param e: error
466
+ :param sf: sigma number for age error, default = 1
467
+ :param adjust_error: adjust error by multiply Sqrt(MSWD)
468
+ :return: error-weighted mean value | error in 1 sigma | number of data points | MSWD | Chisq | P value
469
+ """
470
+ a, e = np.array([a, e])
471
+ e = e / sf # change error to 1 sigma
472
+ k2 = a.size
473
+ df = k2 - 1
474
+ if k2 == 0:
475
+ return np.nan, np.nan, 0, np.nan, np.nan, np.nan
476
+ wt = 1 / e ** 2
477
+ k0 = sum(a * wt) / sum(wt) # error weighting
478
+ k4 = sum((a - k0) ** 2 * wt) # Chi square
479
+ k3 = k4 / df # MSWD mentioned in Min et al., 2000
480
+ if adjust_error:
481
+ k1 = (k3 / sum(wt)) ** .5
482
+ else:
483
+ k1 = (1 / sum(wt)) ** .5
484
+ k5 = distributions.chi2.sf(k4, df)
485
+ return k0, k1, k2, k3, k4, k5
486
+
487
+
488
+ if __name__ == '__main__':
489
+ pass
490
+
ararpy/calc/basic.py ADDED
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: UTF-8 -*-
3
+ """
4
+ # ==========================================
5
+ # Copyright 2023 Yang
6
+ # ararpy - calc - basic
7
+ # ==========================================
8
+ #
9
+ #
10
+ #
11
+ """
12
+ import copy
13
+
14
+
15
+ def get_datetime(t_year: int, t_month: int, t_day: int, t_hour: int, t_min: int, t_seconds: int = 0, base=None):
16
+ """
17
+ :param t_year: int
18
+ :param t_month: int
19
+ :param t_day: int
20
+ :param t_hour: int
21
+ :param t_min: int
22
+ :param t_seconds: int, default == 0
23
+ :param base: base time [y, m, d, h, m]
24
+ :return: seconds since 1970-1-1 8:00
25
+ """
26
+ t_year, t_month, t_day, t_hour, t_min, t_seconds = \
27
+ int(t_year), int(t_month), int(t_day), int(t_hour), int(t_min), int(t_seconds)
28
+ if base is None:
29
+ base = [1970, 1, 1, 8, 0]
30
+ base_year, base_mouth, base_day, base_hour, base_min = base
31
+ if t_year % 4 == 0 and t_year % 100 != 0 or t_year % 400 == 0:
32
+ days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
33
+ else:
34
+ days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
35
+ delta_seconds = ((((t_year - base_year) * 365 + ((t_year + 1 - base_year) - (t_year + 1 - base_year) % 4) / 4 +
36
+ sum(days[base_mouth - 1:t_month - 1]) + t_day - base_day) * 24 + t_hour - base_hour) * 60 +
37
+ t_min - base_min) * 60 + t_seconds
38
+ return delta_seconds
39
+
40
+
41
+ def merge_dicts(a: dict, b: dict):
42
+ """
43
+ a and b, two dictionary. Return updated a
44
+ For example:
45
+ a = {"1": 1, "2": {"1": 1, "2": 2, "3": 3, "5": {}, "6": [1, 2]}}
46
+ b = {"1": 'b', "2": {"1": 'b', "2": 'b', "3": 'b', "4": 'b', "5": {"1": 'b'}, "6": [1, 2, 3]}}
47
+ Will return {'1': 1, '2': {'1': 1, '2': 2, '3': 3, '5': {'1': 'b'}, '6': [1, 2], '4': 'b'}}
48
+ """
49
+ res = copy.deepcopy(a)
50
+ for key, val in b.items():
51
+ if key not in res.keys():
52
+ res[key] = val
53
+ elif isinstance(val, dict):
54
+ res[key] = merge_dicts(res[key], val)
55
+ else:
56
+ continue
57
+ return res