pygeodesy 24.5.6__py2.py3-none-any.whl → 24.5.15__py2.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.
Files changed (51) hide show
  1. {PyGeodesy-24.5.6.dist-info → PyGeodesy-24.5.15.dist-info}/METADATA +4 -4
  2. {PyGeodesy-24.5.6.dist-info → PyGeodesy-24.5.15.dist-info}/RECORD +51 -50
  3. pygeodesy/__init__.py +18 -14
  4. pygeodesy/__main__.py +9 -10
  5. pygeodesy/albers.py +2 -2
  6. pygeodesy/auxilats/__main__.py +7 -10
  7. pygeodesy/auxilats/auxLat.py +2 -1
  8. pygeodesy/basics.py +161 -165
  9. pygeodesy/booleans.py +4 -4
  10. pygeodesy/constants.py +8 -6
  11. pygeodesy/datums.py +9 -8
  12. pygeodesy/ecef.py +5 -4
  13. pygeodesy/elevations.py +2 -2
  14. pygeodesy/ellipsoidalBaseDI.py +7 -5
  15. pygeodesy/elliptic.py +10 -7
  16. pygeodesy/errors.py +6 -6
  17. pygeodesy/etm.py +3 -2
  18. pygeodesy/fmath.py +14 -13
  19. pygeodesy/fstats.py +281 -219
  20. pygeodesy/fsums.py +133 -104
  21. pygeodesy/geodesicw.py +14 -14
  22. pygeodesy/geodesicx/__main__.py +4 -4
  23. pygeodesy/geodesicx/gxarea.py +4 -4
  24. pygeodesy/geodsolve.py +3 -2
  25. pygeodesy/geoids.py +6 -6
  26. pygeodesy/heights.py +4 -4
  27. pygeodesy/internals.py +571 -0
  28. pygeodesy/interns.py +5 -202
  29. pygeodesy/iters.py +3 -2
  30. pygeodesy/karney.py +4 -4
  31. pygeodesy/ktm.py +7 -7
  32. pygeodesy/lazily.py +139 -217
  33. pygeodesy/mgrs.py +3 -2
  34. pygeodesy/named.py +13 -10
  35. pygeodesy/nvectorBase.py +4 -3
  36. pygeodesy/osgr.py +14 -12
  37. pygeodesy/points.py +5 -5
  38. pygeodesy/props.py +7 -7
  39. pygeodesy/rhumb/bases.py +3 -2
  40. pygeodesy/rhumb/solve.py +2 -2
  41. pygeodesy/solveBase.py +3 -2
  42. pygeodesy/streprs.py +5 -4
  43. pygeodesy/trf.py +4 -4
  44. pygeodesy/units.py +15 -17
  45. pygeodesy/ups.py +7 -6
  46. pygeodesy/utily.py +4 -4
  47. pygeodesy/utm.py +5 -4
  48. pygeodesy/utmupsBase.py +4 -3
  49. pygeodesy/vector3dBase.py +2 -1
  50. {PyGeodesy-24.5.6.dist-info → PyGeodesy-24.5.15.dist-info}/WHEEL +0 -0
  51. {PyGeodesy-24.5.6.dist-info → PyGeodesy-24.5.15.dist-info}/top_level.txt +0 -0
pygeodesy/fstats.py CHANGED
@@ -7,43 +7,37 @@ L{pygeodesy.Fsum}, precision floating point summation.
7
7
  # make sure int/int division yields float quotient, see .basics
8
8
  from __future__ import division as _; del _ # PYCHOK semicolon
9
9
 
10
- from pygeodesy.basics import isodd, islistuple, _xinstanceof, \
11
- _xsubclassof, _zip
12
- from pygeodesy.constants import _0_0, _2_0, _3_0, _4_0, _6_0
13
- from pygeodesy.errors import _AssertionError, _xError
14
- from pygeodesy.fmath import hypot2, sqrt
15
- from pygeodesy.fsums import _Float, _2float, Fsum, _iadd_op_, \
16
- _isAn, _Fsum_Fsum2Tuple_types, Fmt
17
- from pygeodesy.interns import NN, _invalid_, _other_, _SPACE_
10
+ from pygeodesy.basics import isscalar, isodd, _xinstanceof, \
11
+ _xiterable, _xsubclassof, _zip
12
+ from pygeodesy.constants import _0_0, _1_0, _2_0, _3_0, _4_0, _6_0
13
+ from pygeodesy.errors import _AssertionError, _ValueError, _xError
14
+ from pygeodesy.fmath import Fsqrt, Fmt
15
+ from pygeodesy.fsums import _2finite, Fsum, _iadd_op_, _isFsumTuple
16
+ from pygeodesy.interns import NN, _odd_, _SPACE_
18
17
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY
19
18
  from pygeodesy.named import _Named, _NotImplemented, property_RO
20
19
  # from pygeodesy.props import property_RO # from .named
21
- # from pygeodesy.streprs import Fmt # from .fsums
22
-
23
- # from math import sqrt # from .fmath
20
+ # from pygeodesy.streprs import Fmt # from .fmath
24
21
 
25
22
  __all__ = _ALL_LAZY.fstats
26
- __version__ = '24.05.06'
27
-
28
- _Floats = _Fsum_Fsum2Tuple_types + (_Float,)
29
- _Scalar = _Floats + (int,) # XXX basics._Ints is ABCMeta in Python 2
30
- try:
31
- _Scalar += (long,)
32
- except NameError: # Python 3+
33
- pass
23
+ __version__ = '24.05.10'
34
24
 
35
25
 
36
26
  def _2Floats(**xs):
37
27
  '''(INTERNAL) Yield each value as C{float} or L{Fsum}.
38
28
  '''
39
29
  try:
40
- _s, xs = xs.popitem()
41
- except Exception as x:
42
- raise _AssertionError(xs=xs, cause=x)
30
+ name, xs = xs.popitem()
31
+ except Exception as X:
32
+ raise _AssertionError(xs=xs, cause=X)
43
33
 
44
- for i, x in enumerate(xs): # don't unravel Fsums
45
- yield x if _isAn(x, _Floats) else \
46
- _2float(index=i, **{_s: x})
34
+ try:
35
+ i = None
36
+ for i, x in enumerate(_xiterable(xs)): # don't unravel Fsums
37
+ yield x._Fsum if _isFsumTuple(x) else _2finite(x)
38
+ except Exception as X:
39
+ raise _xError(X, name, xs) if i is None else \
40
+ _xError(X, Fmt.INDEX(name, i), x)
47
41
 
48
42
 
49
43
  def _sampled(n, sample):
@@ -58,9 +52,11 @@ class _FstatsNamed(_Named):
58
52
  _n = 0
59
53
 
60
54
  def __add__(self, other):
61
- '''Sum of this and a scalar, an L{Fsum} or an other instance.
55
+ '''Sum of this and an other instance or a C{scalar} or an
56
+ L{Fsum}, L{Fsum2Tuple} or
57
+ .
62
58
  '''
63
- f = self.fcopy(name=self.__add__.__name__) # PYCHOK expected
59
+ f = self.copy(name=self.__add__.__name__) # PYCHOK expected
64
60
  f += other
65
61
  return f
66
62
 
@@ -73,7 +69,7 @@ class _FstatsNamed(_Named):
73
69
  return _NotImplemented(self)
74
70
 
75
71
  def __len__(self):
76
- '''Return the I{total} number of accumulated values (C{int}).
72
+ '''Return the I{total} number of accumulated C{Scalars} (C{int}).
77
73
  '''
78
74
  return self._n
79
75
 
@@ -90,14 +86,14 @@ class _FstatsNamed(_Named):
90
86
  n = _SPACE_(self.classname, n) if n else self.classname
91
87
  return Fmt.SQUARE(n, len(self))
92
88
 
93
- def fcopy(self, deep=False, name=NN):
89
+ def copy(self, deep=False, name=NN):
94
90
  '''Copy this instance, C{shallow} or B{C{deep}}.
95
91
  '''
96
- n = name or self.fcopy.__name__
92
+ n = name or self.copy.__name__
97
93
  f = _Named.copy(self, deep=deep, name=n)
98
94
  return self._copy(f, self) # PYCHOK expected
99
95
 
100
- copy = fcopy
96
+ fcopy = copy # for backward compatibility
101
97
 
102
98
 
103
99
  class _FstatsBase(_FstatsNamed):
@@ -105,13 +101,13 @@ class _FstatsBase(_FstatsNamed):
105
101
  '''
106
102
  _Ms = ()
107
103
 
108
- def _copy(self, c, s):
104
+ def _copy(self, d, s):
109
105
  '''(INTERNAL) Copy C{B{c} = B{s}}.
110
106
  '''
111
- _xinstanceof(self.__class__, c=c, s=s)
112
- c._Ms = tuple(M.fcopy() for M in s._Ms) # deep=False
113
- c._n = s._n
114
- return c
107
+ _xinstanceof(self.__class__, d=d, s=s)
108
+ d._Ms = tuple(M.copy() for M in s._Ms) # deep=False
109
+ d._n = s._n
110
+ return d
115
111
 
116
112
  def fadd(self, xs, sample=False): # PYCHOK no cover
117
113
  '''I{Must be overloaded}.'''
@@ -120,84 +116,84 @@ class _FstatsBase(_FstatsNamed):
120
116
  def fadd_(self, *xs, **sample):
121
117
  '''Accumulate and return the current count.
122
118
 
123
- @see: Method C{fadd}.
119
+ @see: Method C{fadd} for further details.
124
120
  '''
125
121
  return self.fadd(xs, **sample)
126
122
 
127
123
  def fmean(self, xs=None):
128
124
  '''Accumulate and return the current mean.
129
125
 
130
- @kwarg xs: Iterable with additional values (C{Scalar}s).
126
+ @kwarg xs: Iterable of additional values (each C{scalar} or
127
+ an L{Fsum} or L{Fsum2Tuple} instance).
131
128
 
132
129
  @return: Current, running mean (C{float}).
133
130
 
134
131
  @see: Method C{fadd}.
135
132
  '''
136
- if xs:
137
- self.fadd(xs)
138
- return self._M1.fsum()
133
+ return float(self._Mean(xs))
139
134
 
140
135
  def fmean_(self, *xs):
141
136
  '''Accumulate and return the current mean.
142
137
 
143
- @see: Method C{fmean}.
138
+ @see: Method C{fmean} for further details.
144
139
  '''
145
140
  return self.fmean(xs)
146
141
 
147
- def fstdev(self, xs=None, sample=False):
142
+ def fstdev(self, xs=None, **sample):
148
143
  '''Accumulate and return the current standard deviation.
149
144
 
150
- @kwarg xs: Iterable with additional values (C{Scalar}).
151
- @kwarg sample: Return the I{sample} instead of the entire
152
- I{population} standard deviation (C{bool}).
145
+ @arg xs: Iterable of additional values (each C{scalar} or an
146
+ L{Fsum} or L{Fsum2Tuple} instance).
147
+ @kwarg sample: Use C{B{sample}=True} for the I{sample} deviation
148
+ instead of the I{population} deviation (C{bool}).
153
149
 
154
150
  @return: Current, running (sample) standard deviation (C{float}).
155
151
 
156
152
  @see: Method C{fadd}.
157
153
  '''
158
- v = self.fvariance(xs, sample=sample)
159
- return sqrt(v) if v > 0 else _0_0
154
+ return float(self._Stdev(xs, **sample))
160
155
 
161
156
  def fstdev_(self, *xs, **sample):
162
157
  '''Accumulate and return the current standard deviation.
163
158
 
164
- @see: Method C{fstdev}.
159
+ @see: Method C{fstdev} for further details.
165
160
  '''
166
161
  return self.fstdev(xs, **sample)
167
162
 
168
- def fvariance(self, xs=None, sample=False):
163
+ def fvariance(self, xs=None, **sample):
169
164
  '''Accumulate and return the current variance.
170
165
 
171
- @kwarg xs: Iterable with additional values (C{Scalar}s).
172
- @kwarg sample: Return the I{sample} instead of the entire
173
- I{population} variance (C{bool}).
166
+ @arg xs: Iterable of additional values (each C{scalar} or an
167
+ L{Fsum} or L{Fsum2Tuple} instance).
168
+ @kwarg sample: Use C{B{sample}=True} for the I{sample} variance
169
+ instead of the I{population} variance (C{bool}).
174
170
 
175
171
  @return: Current, running (sample) variance (C{float}).
176
172
 
177
173
  @see: Method C{fadd}.
178
174
  '''
179
- n = self.fadd(xs, sample=sample)
180
- return _Float(self._M2 / _Float(n)) if n > 0 else _0_0
175
+ return float(self._Variance(xs, **sample))
181
176
 
182
177
  def fvariance_(self, *xs, **sample):
183
178
  '''Accumulate and return the current variance.
184
179
 
185
- @see: Method C{fvariance}.
180
+ @see: Method C{fvariance} for further details.
186
181
  '''
187
182
  return self.fvariance(xs, **sample)
188
183
 
189
184
  def _iadd_other(self, other):
190
- '''(INTERNAL) Add Scalar or Scalars.
191
- '''
192
- if _isAn(other, _Scalar):
193
- self.fadd_(other)
194
- else:
195
- try:
196
- if not islistuple(other):
197
- raise TypeError(_SPACE_(_invalid_, _other_))
185
+ '''(INTERNAL) Add one or several values.
186
+ '''
187
+ try:
188
+ if _isFsumTuple(other):
189
+ self.fadd_(other._Fsum)
190
+ elif isscalar(other):
191
+ self.fadd_(_2finite(other))
192
+ elif _xiterable(other):
198
193
  self.fadd(other)
199
- except Exception as x:
200
- raise _xError(x, _SPACE_(self, _iadd_op_, repr(other)))
194
+ except Exception as X:
195
+ t = _SPACE_(self, _iadd_op_, repr(other))
196
+ raise _xError(X, t)
201
197
 
202
198
  @property_RO
203
199
  def _M1(self):
@@ -209,6 +205,25 @@ class _FstatsBase(_FstatsNamed):
209
205
  '''(INTERNAL) get the 2nd Moment accumulator.'''
210
206
  return self._Ms[1]
211
207
 
208
+ def _Mean(self, xs=None):
209
+ '''(INTERNAL) Return the current mean as L{Fsum}.
210
+ '''
211
+ if xs:
212
+ self.fadd(xs)
213
+ return self._M1 # .copy()
214
+
215
+ def _Stdev(self, xs=None, **sample):
216
+ '''(INTERNAL) Return the current (sample) standard deviation as L{Fsum}.
217
+ '''
218
+ V = self._Variance(xs, **sample)
219
+ return Fsqrt(V) if V > 0 else _0_0
220
+
221
+ def _Variance(self, xs=None, **sample):
222
+ '''(INTERNAL) Return the current (sample) variance as L{Fsum}.
223
+ '''
224
+ n = self.fadd(xs, **sample)
225
+ return (self._M2 / n) if n > 0 else _0_0
226
+
212
227
 
213
228
  class Fcook(_FstatsBase):
214
229
  '''U{Cook<https://www.JohnDCook.com/blog/skewness_kurtosis>}'s
@@ -222,7 +237,8 @@ class Fcook(_FstatsBase):
222
237
  def __init__(self, xs=None, name=NN):
223
238
  '''New L{Fcook} stats accumulator.
224
239
 
225
- @kwarg xs: Iterable with initial values (C{Scalar}s).
240
+ @arg xs: Iterable of additional values (each C{scalar} or
241
+ an L{Fsum} or L{Fsum2Tuple} instance).
226
242
  @kwarg name: Optional name (C{str}).
227
243
 
228
244
  @see: Method L{Fcook.fadd}.
@@ -236,18 +252,19 @@ class Fcook(_FstatsBase):
236
252
  def __iadd__(self, other):
237
253
  '''Add B{C{other}} to this L{Fcook} instance.
238
254
 
239
- @arg other: An L{Fcook} instance or C{Scalar}s, meaning
240
- one or more C{scalar} or L{Fsum} instances.
255
+ @arg other: An L{Fcook} instance or value or iterable
256
+ of values (each C{scalar} or an L{Fsum}
257
+ or L{Fsum2Tuple} instance).
241
258
 
242
259
  @return: This instance, updated (L{Fcook}).
243
260
 
244
- @raise TypeError: Invalid B{C{other}} type.
261
+ @raise TypeError: Invalid B{C{other}}.
245
262
 
246
- @raise ValueError: Invalid B{C{other}}.
263
+ @raise ValueError: Invalid or non-finite B{C{other}}.
247
264
 
248
265
  @see: Method L{Fcook.fadd}.
249
266
  '''
250
- if _isAn(other, Fcook):
267
+ if isinstance(other, Fcook):
251
268
  nb = len(other)
252
269
  if nb > 0:
253
270
  na = len(self)
@@ -256,9 +273,9 @@ class Fcook(_FstatsBase):
256
273
  B1, B2, B3, B4 = other._Ms
257
274
 
258
275
  n = na + nb
259
- n_ = _Float(n)
276
+ _n = _1_0 / n
260
277
  D = A1 - B1 # b1 - a1
261
- Dn = D / n_
278
+ Dn = D * _n
262
279
  Dn2 = Dn**2 # d**2 / n**2
263
280
  nab = na * nb
264
281
  Dn3 = Dn2 * (D * nab)
@@ -271,16 +288,16 @@ class Fcook(_FstatsBase):
271
288
  A4 += (Dn * Dn3) * (na2 - nab + nb2) # d**4 / n**3
272
289
 
273
290
  A3 += B3
274
- A3 += (A2 * na - (B2 * nb)) * (Dn * _3_0)
291
+ A3 += (A2 * na - (B2 * nb)) * (Dn * _3_0)
275
292
  A3 += Dn3 * (na - nb)
276
293
 
277
294
  A2 += B2
278
- A2 += Dn2 * (nab / n_)
295
+ A2 += Dn2 * (nab * _n)
279
296
 
280
297
  B1n = B1 * nb # if other is self
281
298
  A1 *= na
282
299
  A1 += B1n
283
- A1 *= 1 / n_ # /= chokes PyChecker
300
+ A1 *= _n
284
301
 
285
302
  # self._Ms = A1, A2, A3, A4
286
303
  self._n = n
@@ -293,18 +310,18 @@ class Fcook(_FstatsBase):
293
310
  def fadd(self, xs, sample=False):
294
311
  '''Accumulate and return the current count.
295
312
 
296
- @arg xs: Iterable with additional values (C{Scalar}s,
297
- meaning C{scalar} or L{Fsum} instances).
298
- @kwarg sample: Return the I{sample} instead of the entire
299
- I{population} count (C{bool}).
313
+ @arg xs: Iterable of additional values (each C{scalar} or an
314
+ L{Fsum} or L{Fsum2Tuple} instance).
315
+ @kwarg sample: Use C{B{sample}=True} for the I{sample} count
316
+ instead of the I{population} count (C{bool}).
300
317
 
301
318
  @return: Current, running (sample) count (C{int}).
302
319
 
303
320
  @raise OverflowError: Partial C{2sum} overflow.
304
321
 
305
- @raise TypeError: Non-scalar B{C{xs}} value.
322
+ @raise TypeError: Invalid B{C{xs}}.
306
323
 
307
- @raise ValueError: Invalid or non-finite B{C{xs}} value.
324
+ @raise ValueError: Invalid or non-finite B{C{xs}}.
308
325
 
309
326
  @see: U{online_kurtosis<https://WikiPedia.org/wiki/
310
327
  Algorithms_for_calculating_variance>}.
@@ -312,7 +329,7 @@ class Fcook(_FstatsBase):
312
329
  n = self._n
313
330
  if xs:
314
331
  M1, M2, M3, M4 = self._Ms
315
- for x in _2Floats(xs=xs):
332
+ for x in _2Floats(xs=xs): # PYCHOK yield
316
333
  n1 = n
317
334
  n += 1
318
335
  D = x - M1
@@ -342,38 +359,38 @@ class Fcook(_FstatsBase):
342
359
  self._n = n
343
360
  return _sampled(n, sample)
344
361
 
345
- def fjb(self, xs=None, sample=True, excess=True):
362
+ def fjb(self, xs=None, excess=True, sample=True):
346
363
  '''Accumulate and compute the current U{Jarque-Bera
347
364
  <https://WikiPedia.org/wiki/Jarque–Bera_test>} normality.
348
365
 
349
- @kwarg xs: Iterable with additional values (C{Scalar}s).
350
- @kwarg sample: Return the I{sample} normality (C{bool}), default.
351
- @kwarg excess: Return the I{excess} kurtosis (C{bool}), default.
366
+ @kwarg xs: Iterable of additional values (each C{scalar} or an
367
+ L{Fsum} or L{Fsum2Tuple}).
368
+ @kwarg excess: Apply the I{excess} kurtosis (C{bool}), default.
369
+ @kwarg sample: Use C{B{sample}=False} for the I{population}
370
+ normality instead of the I{sample} one (C{bool}).
352
371
 
353
372
  @return: Current, running (sample) Jarque-Bera normality (C{float}).
354
373
 
355
374
  @see: Method L{Fcook.fadd}.
356
375
  '''
357
- n = self.fadd(xs, sample=sample)
358
- k = self.fkurtosis(sample=sample, excess=excess) / _2_0
359
- s = self.fskewness(sample=sample)
360
- return n * hypot2(k, s) / _6_0
376
+ return float(self._JarqueBera(xs, excess, sample=sample))
361
377
 
362
378
  def fjb_(self, *xs, **sample_excess):
363
379
  '''Accumulate and compute the current U{Jarque-Bera
364
380
  <https://WikiPedia.org/wiki/Jarque–Bera_test>} normality.
365
381
 
366
- @see: Method L{Fcook.fjb}.
382
+ @see: Method L{Fcook.fjb} for further details.
367
383
  '''
368
384
  return self.fjb(xs, **sample_excess)
369
385
 
370
- def fkurtosis(self, xs=None, sample=False, excess=True):
386
+ def fkurtosis(self, xs=None, excess=True, **sample):
371
387
  '''Accumulate and return the current kurtosis.
372
388
 
373
- @kwarg xs: Iterable with additional values (C{Scalar}s).
374
- @kwarg sample: Return the I{sample} instead of the entire
375
- I{population} kurtosis (C{bool}).
389
+ @arg xs: Iterable of additional values (each C{scalar} or an
390
+ L{Fsum} or L{Fsum2Tuple} instance).
376
391
  @kwarg excess: Return the I{excess} kurtosis (C{bool}), default.
392
+ @kwarg sample: Use C{B{sample}=True} for the I{sample} kurtosis
393
+ instead of the I{population} kurtosis (C{bool}).
377
394
 
378
395
  @return: Current, running (sample) kurtosis or I{excess} kurtosis (C{float}).
379
396
 
@@ -382,32 +399,21 @@ class Fcook(_FstatsBase):
382
399
 
383
400
  @see: Method L{Fcook.fadd}.
384
401
  '''
385
- k, n = _0_0, self.fadd(xs, sample=sample)
386
- if n > 0:
387
- _, M2, _, M4 = self._Ms
388
- m2 = _Float(M2 * M2)
389
- if m2:
390
- K, x = (M4 * (n / m2)), _3_0
391
- if sample and 2 < n < len(self):
392
- d = _Float((n - 1) * (n - 2))
393
- K *= (n + 1) * (n + 2) / d
394
- x *= n**2 / d
395
- if excess:
396
- K -= x
397
- k = K.fsum()
398
- return k
402
+ n = self.fadd(xs, **sample)
403
+ return float(self._Kurtosis(n, excess, **sample))
399
404
 
400
- def fkurtosis_(self, *xs, **sample_excess):
405
+ def fkurtosis_(self, *xs, **excess_sample):
401
406
  '''Accumulate and return the current kurtosis.
402
407
 
403
- @see: Method L{Fcook.fkurtosis}.
408
+ @see: Method L{Fcook.fkurtosis} for further details.
404
409
  '''
405
- return self.fkurtosis(xs, **sample_excess)
410
+ return self.fkurtosis(xs, **excess_sample)
406
411
 
407
412
  def fmedian(self, xs=None):
408
413
  '''Accumulate and return the current median.
409
414
 
410
- @kwarg xs: Iterable with additional values (C{Scalar}s).
415
+ @arg xs: Iterable of additional values (each C{scalar} or an
416
+ L{Fsum} or L{Fsum2Tuple} instance).
411
417
 
412
418
  @return: Current, running median (C{float}).
413
419
 
@@ -416,24 +422,22 @@ class Fcook(_FstatsBase):
416
422
  https://TowardsDataScience.com/skewness-kurtosis-simplified-1338e094fc85>}
417
423
  and method L{Fcook.fadd}.
418
424
  '''
419
- # skewness = 3 * (mean - median) / stdev, i.e.
420
- # median = mean - skewness * stdef / 3
421
- m = _Float(self._M1) if xs is None else self.fmean(xs)
422
- return m - self.fskewness() * self.fstdev() / _3_0
425
+ return float(self._Median(xs))
423
426
 
424
427
  def fmedian_(self, *xs):
425
428
  '''Accumulate and return the current median.
426
429
 
427
- @see: Method L{Fcook.fmedian}.
430
+ @see: Method L{Fcook.fmedian} for further details.
428
431
  '''
429
432
  return self.fmedian(xs)
430
433
 
431
- def fskewness(self, xs=None, sample=False):
434
+ def fskewness(self, xs=None, **sample):
432
435
  '''Accumulate and return the current skewness.
433
436
 
434
- @kwarg xs: Iterable with additional values (C{Scalar}s).
435
- @kwarg sample: Return the I{sample} instead of the entire
436
- I{population} skewness (C{bool}).
437
+ @arg xs: Iterable of additional values (each C{scalar} or an
438
+ L{Fsum} or L{Fsum2Tuple} instance).
439
+ @kwarg sample: Use C{B{sample}=True} for the I{sample} skewness
440
+ instead of the I{population} skewness (C{bool}).
437
441
 
438
442
  @return: Current, running (sample) skewness (C{float}).
439
443
 
@@ -442,29 +446,70 @@ class Fcook(_FstatsBase):
442
446
 
443
447
  @see: Method L{Fcook.fadd}.
444
448
  '''
445
- s, n = _0_0, self.fadd(xs, sample=sample)
446
- if n > 0:
447
- _, M2, M3, _ = self._Ms
448
- m = _Float(M2**3)
449
- if m > 0:
450
- S = M3 * sqrt(_Float(n) / m)
451
- if sample and 1 < n < len(self):
452
- S *= (n + 1) / _Float(n - 1)
453
- s = S.fsum()
454
- return s
449
+ n = self.fadd(xs, **sample)
450
+ return float(self._Skewness(n, **sample))
455
451
 
456
452
  def fskewness_(self, *xs, **sample):
457
453
  '''Accumulate and return the current skewness.
458
454
 
459
- @see: Method L{Fcook.fskewness}.
455
+ @see: Method L{Fcook.fskewness} for further details.
460
456
  '''
461
457
  return self.fskewness(xs, **sample)
462
458
 
459
+ def _JarqueBera(self, xs, excess, **sample):
460
+ '''(INTERNAL) Return the (sample) Jarque-Bera normality as L{Fsum}.
461
+ '''
462
+ N, n = _0_0, self.fadd(xs, **sample)
463
+ if n > 0:
464
+ K = self._Kurtosis(n, excess, **sample) / _2_0
465
+ S = self._Skewness(n, **sample)
466
+ N = (K**2 + S**2) * (n / _6_0) # Fpowers(2, K, S) * ...
467
+ return N
468
+
469
+ def _Kurtosis(self, n, excess, sample=False):
470
+ '''(INTERNAL) Return the (sample) kurtosis as L{Fsum} or C{0.0}.
471
+ '''
472
+ K = _0_0
473
+ if n > 0:
474
+ _, M2, _, M4 = self._Ms
475
+ M = M2**2
476
+ if M > 0:
477
+ K, x = M.rdiv(M4 * n, raiser=False), _3_0
478
+ if sample and 2 < n < len(self):
479
+ d = (n - 1) * (n - 2)
480
+ K *= (n + 1) * (n + 2) / d
481
+ x *= n**2 / d
482
+ if excess:
483
+ K -= x
484
+ return K
485
+
486
+ def _Median(self, xs=None):
487
+ '''(INTERNAL) Return the median as L{Fsum}.
488
+ '''
489
+ # skewness = 3 * (mean - median) / stdev, i.e.
490
+ # median = mean - (skewness * stdef) / 3
491
+ return self._Mean(xs) - (self._Skewness(self._n) *
492
+ self._Stdev()) / _3_0
493
+
494
+ def _Skewness(self, n, sample=False):
495
+ '''(INTERNAL) Return the (sample) skewness as L{Fsum} or C{0.0}.
496
+ '''
497
+ S = _0_0
498
+ if n > 0:
499
+ _, M2, M3, _ = self._Ms
500
+ M = M2**3
501
+ if M > 0:
502
+ M = M.rdiv(n, raiser=False)
503
+ S = M3 * Fsqrt(M, raiser=False)
504
+ if sample and 1 < n < len(self):
505
+ S *= (n + 1) / (n - 1)
506
+ return S
507
+
463
508
  def toFwelford(self, name=NN):
464
509
  '''Return an L{Fwelford} equivalent.
465
510
  '''
466
511
  f = Fwelford(name=name or self.name)
467
- f._Ms = self._M1.fcopy(), self._M2.fcopy() # deep=False
512
+ f._Ms = self._M1.copy(), self._M2.copy() # deep=False
468
513
  f._n = self._n
469
514
  return f
470
515
 
@@ -478,7 +523,8 @@ class Fwelford(_FstatsBase):
478
523
  def __init__(self, xs=None, name=NN):
479
524
  '''New L{Fwelford} stats accumulator.
480
525
 
481
- @kwarg xs: Iterable with initial values (C{Scalar}s).
526
+ @arg xs: Iterable of initial values (each C{scalar} or an
527
+ L{Fsum} or L{Fsum2Tuple} instance).
482
528
  @kwarg name: Optional name (C{str}).
483
529
 
484
530
  @see: Method L{Fwelford.fadd}.
@@ -492,19 +538,20 @@ class Fwelford(_FstatsBase):
492
538
  def __iadd__(self, other):
493
539
  '''Add B{C{other}} to this L{Fwelford} instance.
494
540
 
495
- @arg other: An L{Fwelford} or L{Fcook} instance or C{Scalar}s,
496
- meaning one or more C{scalar} or L{Fsum} instances.
541
+ @arg other: An L{Fwelford} or L{Fcook} instance or value
542
+ or an iterable of values (each C{scalar} or
543
+ an L{Fsum} or L{Fsum2Tuple} instance).
497
544
 
498
545
  @return: This instance, updated (L{Fwelford}).
499
546
 
500
- @raise TypeError: Invalid B{C{other}} type.
547
+ @raise TypeError: Invalid B{C{other}}.
501
548
 
502
549
  @raise ValueError: Invalid B{C{other}}.
503
550
 
504
551
  @see: Method L{Fwelford.fadd} and U{Parallel algorithm<https//
505
552
  WikiPedia.org/wiki/Algorithms_for_calculating_variance>}.
506
553
  '''
507
- if _isAn(other, Fwelford):
554
+ if isinstance(other, Fwelford):
508
555
  nb = len(other)
509
556
  if nb > 0:
510
557
  na = len(self)
@@ -513,25 +560,25 @@ class Fwelford(_FstatsBase):
513
560
  M_, S_ = other._Ms
514
561
 
515
562
  n = na + nb
516
- n_ = _Float(n)
563
+ _n = _1_0 / n
517
564
 
518
565
  D = M_ - M
519
566
  D *= D # D**2
520
- D *= na * nb / n_
567
+ D *= na * nb * _n
521
568
  S += D
522
569
  S += S_
523
570
 
524
571
  Mn = M_ * nb # if other is self
525
572
  M *= na
526
573
  M += Mn
527
- M *= 1 / n_ # /= chokes PyChecker
574
+ M *= _n
528
575
 
529
576
  # self._Ms = M, S
530
577
  self._n = n
531
578
  else:
532
579
  self._copy(self, other)
533
580
 
534
- elif _isAn(other, Fcook):
581
+ elif isinstance(other, Fcook):
535
582
  self += other.toFwelford()
536
583
  else:
537
584
  self._iadd_other(other)
@@ -540,23 +587,23 @@ class Fwelford(_FstatsBase):
540
587
  def fadd(self, xs, sample=False):
541
588
  '''Accumulate and return the current count.
542
589
 
543
- @arg xs: Iterable with additional values (C{Scalar}s,
544
- meaning C{scalar} or L{Fsum} instances).
545
- @kwarg sample: Return the I{sample} instead of the entire
546
- I{population} count (C{bool}).
590
+ @arg xs: Iterable of additional values (each C{scalar} or an
591
+ L{Fsum} or L{Fsum2Tuple} instance).
592
+ @kwarg sample: Use C{B{sample}=True} for the I{sample} count
593
+ instead of the I{population} count (C{bool}).
547
594
 
548
595
  @return: Current, running (sample) count (C{int}).
549
596
 
550
597
  @raise OverflowError: Partial C{2sum} overflow.
551
598
 
552
- @raise TypeError: Non-scalar B{C{xs}} value.
599
+ @raise TypeError: Invalid B{C{xs}}.
553
600
 
554
- @raise ValueError: Invalid or non-finite B{C{xs}} value.
601
+ @raise ValueError: Invalid or non-finite B{C{xs}}.
555
602
  '''
556
603
  n = self._n
557
604
  if xs:
558
605
  M, S = self._Ms
559
- for x in _2Floats(xs=xs):
606
+ for x in _2Floats(xs=xs): # PYCHOK yield
560
607
  n += 1
561
608
  D = x - M
562
609
  M += D / n
@@ -575,14 +622,16 @@ class Flinear(_FstatsNamed):
575
622
  def __init__(self, xs=None, ys=None, Fstats=Fwelford, name=NN):
576
623
  '''New L{Flinear} regression accumulator.
577
624
 
578
- @kwarg xs: Iterable with initial C{x} values (C{Scalar}s).
579
- @kwarg ys: Iterable with initial C{y} values (C{Scalar}s).
580
- @kwarg Fstats: Stats class for C{x} and C{y} values (L{Fcook}
581
- or L{Fwelford}).
625
+ @kwarg xs: Iterable of initial C{x} values (each C{scalar} or
626
+ an L{Fsum} or L{Fsum2Tuple} instance).
627
+ @kwarg ys: Iterable of initial C{y} values (each C{scalar} or
628
+ an L{Fsum} or L{Fsum2Tuple} instance).
629
+ @kwarg Fstats: Class for C{xs} and C{ys} values (L{Fcook} or
630
+ L{Fwelford}).
582
631
  @kwarg name: Optional name (C{str}).
583
632
 
584
- @raise TypeError: Invalid B{C{Fs}}, not L{Fcook} or
585
- L{Fwelford}.
633
+ @raise TypeError: B{C{Fstats}} not L{Fcook} or L{Fwelford}.
634
+
586
635
  @see: Method L{Flinear.fadd}.
587
636
  '''
588
637
  _xsubclassof(Fcook, Fwelford, Fstats=Fstats)
@@ -598,8 +647,8 @@ class Flinear(_FstatsNamed):
598
647
  def __iadd__(self, other):
599
648
  '''Add B{C{other}} to this instance.
600
649
 
601
- @arg other: An L{Flinear} instance or C{Scalar} pairs,
602
- meaning C{scalar} or L{Fsum} instances.
650
+ @arg other: An L{Flinear} instance or an iterable of
651
+ C{x_ys} values, see method C{fadd_}.
603
652
 
604
653
  @return: This instance, updated (L{Flinear}).
605
654
 
@@ -611,129 +660,142 @@ class Flinear(_FstatsNamed):
611
660
 
612
661
  @see: Method L{Flinear.fadd_}.
613
662
  '''
614
- if _isAn(other, Flinear):
663
+ if isinstance(other, Flinear):
615
664
  if len(other) > 0:
616
665
  if len(self) > 0:
617
- n = other._n
618
- S = other._S
619
- X = other._X
620
- Y = other._Y
621
- D = (X._M1 - self._X._M1) * \
622
- (Y._M1 - self._Y._M1) * \
623
- (n * self._n / _Float(n + self._n))
666
+ n = other._n
667
+ D = (other._X._M1 - self._X._M1) * \
668
+ (other._Y._M1 - self._Y._M1) * \
669
+ (n * self._n / (self._n + n))
670
+ self._S += other._S + D
671
+ self._X += other._X
672
+ self._Y += other._Y
624
673
  self._n += n
625
- self._S += S + D
626
- self._X += X
627
- self._Y += Y
628
674
  else:
629
675
  self._copy(self, other)
630
676
  else:
631
677
  try:
632
- if not islistuple(other):
633
- raise TypeError(_SPACE_(_invalid_, _other_))
634
- elif isodd(len(other)):
635
- raise ValueError(Fmt.PAREN(isodd=Fmt.PAREN(len=_other_)))
636
- self.fadd_(*other)
637
- except Exception as x:
638
- raise _xError(x, _SPACE_(self, _iadd_op_, repr(other)))
678
+ if _xiterable(other):
679
+ self.fadd_(*other)
680
+ except Exception as X:
681
+ op = _SPACE_(self, _iadd_op_, repr(other))
682
+ raise _xError(X, op)
639
683
  return self
640
684
 
641
- def _copy(self, c, s):
642
- '''(INTERNAL) Copy C{B{c} = B{s}}.
685
+ def _copy(self, d, s):
686
+ '''(INTERNAL) Copy C{B{d} = B{s}}.
687
+ '''
688
+ _xinstanceof(Flinear, d=d, s=s)
689
+ d._S = s._S.copy(deep=False)
690
+ d._X = s._X.copy(deep=False)
691
+ d._Y = s._Y.copy(deep=False)
692
+ d._n = s._n
693
+ return d
694
+
695
+ def _Correlation(self, **sample):
696
+ '''(INTERNAL) Return the current (sample) correlation as L{Fsum}.
643
697
  '''
644
- _xinstanceof(Flinear, c=c, s=s)
645
- c._n = s._n
646
- c._S = s._S.fcopy(deep=False)
647
- c._X = s._X.fcopy(deep=False)
648
- c._Y = s._Y.fcopy(deep=False)
649
- return c
698
+ return self._Sampled(self._X._Stdev(**sample) *
699
+ self._Y._Stdev(**sample), **sample)
650
700
 
651
701
  def fadd(self, xs, ys, sample=False):
652
702
  '''Accumulate and return the current count.
653
703
 
654
- @arg xs: Iterable with additional C{x} values (C{Scalar}s),
655
- meaning C{scalar} or L{Fsum} instances).
656
- @arg ys: Iterable with additional C{y} values (C{Scalar}s,
657
- meaning C{scalar} or L{Fsum} instances).
658
- @kwarg sample: Return the I{sample} instead of the entire
659
- I{population} count (C{bool}).
704
+ @arg xs: Iterable of additional C{x} values (each C{scalar}
705
+ or an L{Fsum} or L{Fsum2Tuple} instance).
706
+ @arg ys: Iterable of additional C{y} values (each C{scalar}
707
+ or an L{Fsum} or L{Fsum2Tuple} instance).
708
+ @kwarg sample: Use C{B{sample}=True} for the I{sample} count
709
+ instead of the I{population} count (C{bool}).
660
710
 
661
711
  @return: Current, running (sample) count (C{int}).
662
712
 
663
713
  @raise OverflowError: Partial C{2sum} overflow.
664
714
 
665
- @raise TypeError: Non-scalar B{C{xs}} or B{C{ys}} value.
715
+ @raise TypeError: Invalid B{C{xs}} or B{C{ys}}.
666
716
 
667
- @raise ValueError: Invalid or non-finite B{C{xs}} or B{C{ys}} value.
717
+ @raise ValueError: Invalid or non-finite B{C{xs}} or B{C{ys}}.
668
718
  '''
669
719
  n = self._n
670
720
  if xs and ys:
671
721
  S = self._S
672
722
  X = self._X
673
723
  Y = self._Y
674
- for x, y in _zip(_2Floats(xs=xs), _2Floats(ys=ys)): # strict=True
724
+ for x, y in _zip(_2Floats(xs=xs), _2Floats(ys=ys)): # PYCHOK strict=True
675
725
  n1 = n
676
726
  n += 1
677
727
  if n1 > 0:
678
- S += (X._M1 - x) * (Y._M1 - y) * (n1 / _Float(n))
728
+ S += (X._M1 - x) * (Y._M1 - y) * (n1 / n)
679
729
  X += x
680
730
  Y += y
681
- self._n = n
731
+ self._n = n
682
732
  return _sampled(n, sample)
683
733
 
684
734
  def fadd_(self, *x_ys, **sample):
685
735
  '''Accumulate and return the current count.
686
736
 
687
- @arg x_ys: Individual, alternating C{x, y, x, y, ...}
688
- positional values (C{Scalar}s).
737
+ @arg x_ys: Individual, alternating C{x, y, x, y, ...} values
738
+ (each C{scalar} or an L{Fsum} or L{Fsum2Tuple}
739
+ instance).
689
740
 
690
- @see: Method C{Flinear.fadd}.
741
+ @see: Method C{Flinear.fadd} for further details.
691
742
  '''
743
+ if isodd(len(x_ys)):
744
+ t = _SPACE_(_odd_, len.__name__)
745
+ raise _ValueError(t, len(x_ys))
692
746
  return self.fadd(x_ys[0::2], x_ys[1::2], **sample)
693
747
 
694
- def fcorrelation(self, sample=False):
748
+ def fcorrelation(self, **sample):
695
749
  '''Return the current, running (sample) correlation (C{float}).
696
750
 
697
- @kwarg sample: Return the I{sample} instead of the entire
698
- I{population} correlation (C{bool}).
751
+ @kwarg sample: Use C{B{sample}=True} for the I{sample} correlation
752
+ instead of the I{population} correlation (C{bool}).
699
753
  '''
700
- return self._sampled(self.x.fstdev(sample=sample) *
701
- self.y.fstdev(sample=sample), sample)
754
+ return float(self._Correlation(**sample))
702
755
 
703
- def fintercept(self, sample=False):
756
+ def fintercept(self, **sample):
704
757
  '''Return the current, running (sample) intercept (C{float}).
705
758
 
706
- @kwarg sample: Return the I{sample} instead of the entire
707
- I{population} intercept (C{bool}).
759
+ @kwarg sample: Use C{B{sample}=True} for the I{sample} intercept
760
+ instead of the I{population} intercept (C{bool}).
708
761
  '''
709
- return _Float(self.y._M1 -
710
- (self.x._M1 * self.fslope(sample=sample)))
762
+ return float(self._Intercept(**sample))
711
763
 
712
- def fslope(self, sample=False):
764
+ def fslope(self, **sample):
713
765
  '''Return the current, running (sample) slope (C{float}).
714
766
 
715
- @kwarg sample: Return the I{sample} instead of the entire
716
- I{population} slope (C{bool}).
767
+ @kwarg sample: Use C{B{sample}=True} for the I{sample} slope
768
+ instead of the I{population} slope (C{bool}).
717
769
  '''
718
- return self._sampled(self.x.fvariance(sample=sample), sample)
770
+ return float(self._Slope(**sample))
719
771
 
720
- def _sampled(self, t, sample):
772
+ def _Intercept(self, **sample):
773
+ '''(INTERNAL) Return the current (sample) intercept as L{Fsum}.
774
+ '''
775
+ return self._Y._M1 - self._X._M1 * self._Slope(**sample)
776
+
777
+ def _Sampled(self, T, sample=False):
721
778
  '''(INTERNAL) Compute the sampled or entire population result.
722
779
  '''
723
- t *= _Float(_sampled(self._n, sample))
724
- return _Float(self._S / t) if t else _0_0
780
+ T *= _sampled(self._n, sample)
781
+ return self._S.copy().fdiv(T, raiser=False) if T else T
782
+
783
+ def _Slope(self, **sample):
784
+ '''(INTERNAL) Return the current (sample) slope as L{Fsum}.
785
+ '''
786
+ return self._Sampled(self._X._Variance(**sample), **sample)
725
787
 
726
788
  @property_RO
727
789
  def x(self):
728
790
  '''Get the C{x} accumulator (L{Fcook} or L{Fwelford}).
729
791
  '''
730
- return self._X
792
+ return self._X # .copy()
731
793
 
732
794
  @property_RO
733
795
  def y(self):
734
796
  '''Get the C{y} accumulator (L{Fcook} or L{Fwelford}).
735
797
  '''
736
- return self._Y
798
+ return self._Y # .copy()
737
799
 
738
800
 
739
801
  __all__ += _ALL_DOCS(_FstatsBase, _FstatsNamed)