Skip to main content

r2rs_stats/traits/
data_set.rs

1// "Whatever you do, work at it with all your heart, as working for the Lord,
2// not for human masters, since you know that you will receive an inheritance
3// from the Lord as a reward. It is the Lord Christ you are serving."
4// (Col 3:23-24)
5
6use std::{f64, fmt::Debug, iter::Sum};
7
8use num_traits::{Float, FromPrimitive, NumAssign};
9use r2rs_base::traits::StatisticalSlice;
10
11pub enum DeviationType {
12    Mean(Option<f64>),
13    Median(Option<f64>),
14    Other(f64),
15}
16
17pub trait StatArray<X> {
18    /// Maxima and Minima
19    ///
20    /// ## Description:
21    ///
22    /// Returns the (regular or *p*arallel) maxima and minima of the input
23    /// values.
24    ///
25    /// ‘pmax*()’ and ‘pmin*()’ take one or more vectors as arguments,
26    /// recycle them to common length and return a single vector giving
27    /// the _‘parallel’_ maxima (or minima) of the argument vectors.
28    ///
29    /// ## Usage:
30    ///
31    /// max(..., na.rm = FALSE)
32    /// min(..., na.rm = FALSE)
33    ///
34    /// pmax(..., na.rm = FALSE)
35    /// pmin(..., na.rm = FALSE)
36    ///
37    /// pmax.int(..., na.rm = FALSE)
38    /// pmin.int(..., na.rm = FALSE)
39    ///
40    /// ## Arguments:
41    ///
42    /// * ...: numeric or character arguments (see Note).
43    /// * na.rm: a logical indicating whether missing values should be
44    ///   removed.
45    ///
46    /// ## Details:
47    ///
48    /// ‘max’ and ‘min’ return the maximum or minimum of _all_ the values
49    /// present in their arguments, as ‘integer’ if all are ‘logical’ or
50    /// ‘integer’, as ‘double’ if all are numeric, and character
51    /// otherwise.
52    ///
53    /// If ‘na.rm’ is ‘FALSE’ an ‘NA’ value in any of the arguments will
54    /// cause a value of ‘NA’ to be returned, otherwise ‘NA’ values are
55    /// ignored.
56    ///
57    /// The minimum and maximum of a numeric empty set are ‘+Inf’ and
58    /// ‘-Inf’ (in this order!) which ensures _transitivity_, e.g.,
59    /// ‘min(x1, min(x2)) == min(x1, x2)’.  For numeric ‘x’ ‘max(x) ==/
60    /// -Inf’ and ‘min(x) == +Inf’ whenever ‘length(x) == 0’ (after
61    /// removing missing values if requested).  However, ‘pmax’ and ‘pmin’
62    /// return ‘NA’ if all the parallel elements are ‘NA’ even for ‘na.rm
63    /// = TRUE’.
64    ///
65    /// ‘pmax’ and ‘pmin’ take one or more vectors (or matrices) as
66    /// arguments and return a single vector giving the ‘parallel’ maxima
67    /// (or minima) of the vectors.  The first element of the result is
68    /// the maximum (minimum) of the first elements of all the arguments,
69    /// the second element of the result is the maximum (minimum) of the
70    /// second elements of all the arguments and so on.  Shorter inputs
71    /// (of non-zero length) are recycled if necessary.  Attributes (see
72    /// ‘attributes’: such as ‘names’ or ‘dim’) are copied from the first
73    /// argument (if applicable, e.g., _not_ for an ‘S4’ object).
74    ///
75    /// ‘pmax.int’ and ‘pmin.int’ are faster internal versions only used
76    /// when all arguments are atomic vectors and there are no classes:
77    /// they drop all attributes.  (Note that all versions fail for raw
78    /// and complex vectors since these have no ordering.)
79    ///
80    /// ‘max’ and ‘min’ are generic functions: methods can be defined for
81    /// them individually or via the ‘Summary’ group generic.  For this to
82    /// work properly, the arguments ‘...’ should be unnamed, and dispatch
83    /// is on the first argument.
84    ///
85    /// By definition the min/max of a numeric vector containing an ‘NaN’
86    /// is ‘NaN’, except that the min/max of any vector containing an ‘NA’
87    /// is ‘NA’ even if it also contains an ‘NaN’.  Note that ‘max(NA,
88    /// Inf) == NA’ even though the maximum would be ‘Inf’ whatever the
89    /// missing value actually is.
90    ///
91    /// Character versions are sorted lexicographically, and this depends
92    /// on the collating sequence of the locale in use: the help for
93    /// ‘Comparison’ gives details.  The max/min of an empty character
94    /// vector is defined to be character ‘NA’.  (One could argue that as
95    /// ‘""’ is the smallest character element, the maximum should be
96    /// ‘""’, but there is no obvious candidate for the minimum.)
97    ///
98    /// ## Value:
99    ///
100    /// For ‘min’ or ‘max’, a length-one vector.  For ‘pmin’ or ‘pmax’, a
101    /// vector of length the longest of the input vectors, or length zero
102    /// if one of the inputs had zero length.
103    ///
104    /// The type of the result will be that of the highest of the inputs
105    /// in the hierarchy integer < double < character.
106    ///
107    /// For ‘min’ and ‘max’ if there are only numeric inputs and all are
108    /// empty (after possible removal of ‘NA’s), the result is double
109    /// (‘Inf’ or ‘-Inf’).
110    ///
111    /// ## S4 methods:
112    ///
113    /// ‘max’ and ‘min’ are part of the S4 ‘Summary’ group generic.
114    /// Methods for them must use the signature ‘x, ..., na.rm’.
115    ///
116    /// ## Note:
117    ///
118    /// ‘Numeric’ arguments are vectors of type integer and numeric, and
119    /// logical (coerced to integer).  For historical reasons, ‘NULL’ is
120    /// accepted as equivalent to ‘integer(0)’.
121    ///
122    /// ‘pmax’ and ‘pmin’ will also work on classed S3 or S4 objects with
123    /// appropriate methods for comparison, ‘is.na’ and ‘rep’ (if
124    /// recycling of arguments is needed).
125    ///
126    /// ## References:
127    ///
128    /// Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) _The New S
129    /// Language_.  Wadsworth & Brooks/Cole.
130    ///
131    /// ## See Also:
132    ///
133    /// ‘range’ (_both_ min and max) and ‘which.min’ (‘which.max’) for the
134    /// _arg min_, i.e., the location where an extreme value occurs.
135    ///
136    /// ‘plotmath’ for the use of ‘min’ in plot annotation.
137    ///
138    /// ## Examples:
139    ///
140    /// ```r
141    /// require(stats); require(graphics)
142    ///  min(5:1, pi) #-> one number
143    /// pmin(5:1, pi) #->  5  numbers
144    ///
145    /// x <- sort(rnorm(100));  cH <- 1.35
146    /// pmin(cH, quantile(x)) # no names
147    /// pmin(quantile(x), cH) # has names
148    /// plot(x, pmin(cH, pmax(-cH, x)), type = "b", main =  "Huber's function")
149    ///
150    /// cut01 <- function(x) pmax(pmin(x, 1), 0)
151    /// curve( x^2 - 1/4, -1.4, 1.5, col = 2)
152    /// curve(cut01(x^2 - 1/4), col = "blue", add = TRUE, n = 500)
153    /// ## pmax(), pmin() preserve attributes of *first* argument
154    /// D <- diag(x = (3:1)/4) ; n0 <- numeric()
155    /// stopifnot(identical(D,  cut01(D) ),
156    /// identical(n0, cut01(n0)),
157    /// identical(n0, cut01(NULL)),
158    /// identical(n0, pmax(3:1, n0, 2)),
159    /// identical(n0, pmax(n0, 4)))
160    /// ```
161    fn min(&self) -> X;
162
163    ///` Maxima and Minima
164    ///
165    /// ## Description:
166    ///
167    /// Returns the (regular or *p*arallel) maxima and minima of the input
168    /// values.
169    ///
170    /// ‘pmax*()’ and ‘pmin*()’ take one or more vectors as arguments,
171    /// recycle them to common length and return a single vector giving
172    /// the _‘parallel’_ maxima (or minima) of the argument vectors.
173    ///
174    /// ## Usage:
175    ///
176    /// max(..., na.rm = FALSE)
177    /// min(..., na.rm = FALSE)
178    ///
179    /// pmax(..., na.rm = FALSE)
180    /// pmin(..., na.rm = FALSE)
181    ///
182    /// pmax.int(..., na.rm = FALSE)
183    /// pmin.int(..., na.rm = FALSE)
184    ///
185    /// ## Arguments:
186    ///
187    /// * ...: numeric or character arguments (see Note).
188    /// * na.rm: a logical indicating whether missing values should be
189    ///   removed.
190    ///
191    /// ## Details:
192    ///
193    /// ‘max’ and ‘min’ return the maximum or minimum of _all_ the values
194    /// present in their arguments, as ‘integer’ if all are ‘logical’ or
195    /// ‘integer’, as ‘double’ if all are numeric, and character
196    /// otherwise.
197    ///
198    /// If ‘na.rm’ is ‘FALSE’ an ‘NA’ value in any of the arguments will
199    /// cause a value of ‘NA’ to be returned, otherwise ‘NA’ values are
200    /// ignored.
201    ///
202    /// The minimum and maximum of a numeric empty set are ‘+Inf’ and
203    /// ‘-Inf’ (in this order!) which ensures _transitivity_, e.g.,
204    /// ‘min(x1, min(x2)) == min(x1, x2)’.  For numeric ‘x’ ‘max(x) ==/
205    /// -Inf’ and ‘min(x) == +Inf’ whenever ‘length(x) == 0’ (after
206    /// removing missing values if requested).  However, ‘pmax’ and ‘pmin’
207    /// return ‘NA’ if all the parallel elements are ‘NA’ even for ‘na.rm
208    /// = TRUE’.
209    ///
210    /// ‘pmax’ and ‘pmin’ take one or more vectors (or matrices) as
211    /// arguments and return a single vector giving the ‘parallel’ maxima
212    /// (or minima) of the vectors.  The first element of the result is
213    /// the maximum (minimum) of the first elements of all the arguments,
214    /// the second element of the result is the maximum (minimum) of the
215    /// second elements of all the arguments and so on.  Shorter inputs
216    /// (of non-zero length) are recycled if necessary.  Attributes (see
217    /// ‘attributes’: such as ‘names’ or ‘dim’) are copied from the first
218    /// argument (if applicable, e.g., _not_ for an ‘S4’ object).
219    ///
220    /// ‘pmax.int’ and ‘pmin.int’ are faster internal versions only used
221    /// when all arguments are atomic vectors and there are no classes:
222    /// they drop all attributes.  (Note that all versions fail for raw
223    /// and complex vectors since these have no ordering.)
224    ///
225    /// ‘max’ and ‘min’ are generic functions: methods can be defined for
226    /// them individually or via the ‘Summary’ group generic.  For this to
227    /// work properly, the arguments ‘...’ should be unnamed, and dispatch
228    /// is on the first argument.
229    ///
230    /// By definition the min/max of a numeric vector containing an ‘NaN’
231    /// is ‘NaN’, except that the min/max of any vector containing an ‘NA’
232    /// is ‘NA’ even if it also contains an ‘NaN’.  Note that ‘max(NA,
233    /// Inf) == NA’ even though the maximum would be ‘Inf’ whatever the
234    /// missing value actually is.
235    ///
236    /// Character versions are sorted lexicographically, and this depends
237    /// on the collating sequence of the locale in use: the help for
238    /// ‘Comparison’ gives details.  The max/min of an empty character
239    /// vector is defined to be character ‘NA’.  (One could argue that as
240    /// ‘""’ is the smallest character element, the maximum should be
241    /// ‘""’, but there is no obvious candidate for the minimum.)
242    ///
243    /// ## Value:
244    ///
245    /// For ‘min’ or ‘max’, a length-one vector.  For ‘pmin’ or ‘pmax’, a
246    /// vector of length the longest of the input vectors, or length zero
247    /// if one of the inputs had zero length.
248    ///
249    /// The type of the result will be that of the highest of the inputs
250    /// in the hierarchy integer < double < character.
251    ///
252    /// For ‘min’ and ‘max’ if there are only numeric inputs and all are
253    /// empty (after possible removal of ‘NA’s), the result is double
254    /// (‘Inf’ or ‘-Inf’).
255    ///
256    /// ## S4 methods:
257    ///
258    /// ‘max’ and ‘min’ are part of the S4 ‘Summary’ group generic.
259    /// Methods for them must use the signature ‘x, ..., na.rm’.
260    ///
261    /// ## Note:
262    ///
263    /// ‘Numeric’ arguments are vectors of type integer and numeric, and
264    /// logical (coerced to integer).  For historical reasons, ‘NULL’ is
265    /// accepted as equivalent to ‘integer(0)’.
266    ///
267    /// ‘pmax’ and ‘pmin’ will also work on classed S3 or S4 objects with
268    /// appropriate methods for comparison, ‘is.na’ and ‘rep’ (if
269    /// recycling of arguments is needed).
270    ///
271    /// ## References:
272    ///
273    /// Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) _The New S
274    /// Language_.  Wadsworth & Brooks/Cole.
275    ///
276    /// ## See Also:
277    ///
278    /// ‘range’ (_both_ min and max) and ‘which.min’ (‘which.max’) for the
279    /// _arg min_, i.e., the location where an extreme value occurs.
280    ///
281    /// ‘plotmath’ for the use of ‘min’ in plot annotation.
282    ///
283    /// ## Examples:
284    ///
285    /// ```r
286    /// require(stats); require(graphics)
287    ///  min(5:1, pi) #-> one number
288    /// pmin(5:1, pi) #->  5  numbers
289    ///
290    /// x <- sort(rnorm(100));  cH <- 1.35
291    /// pmin(cH, quantile(x)) # no names
292    /// pmin(quantile(x), cH) # has names
293    /// plot(x, pmin(cH, pmax(-cH, x)), type = "b", main =  "Huber's function")
294    ///
295    /// cut01 <- function(x) pmax(pmin(x, 1), 0)
296    /// curve( x^2 - 1/4, -1.4, 1.5, col = 2)
297    /// curve(cut01(x^2 - 1/4), col = "blue", add = TRUE, n = 500)
298    /// ## pmax(), pmin() preserve attributes of *first* argument
299    /// D <- diag(x = (3:1)/4) ; n0 <- numeric()
300    /// stopifnot(identical(D,  cut01(D) ),
301    /// identical(n0, cut01(n0)),
302    /// identical(n0, cut01(NULL)),
303    /// identical(n0, pmax(3:1, n0, 2)),
304    /// identical(n0, pmax(n0, 4)))
305    /// ````
306    fn max(&self) -> X;
307
308    /// Sample Ranks
309    ///
310    /// ## Description:
311    ///
312    /// Returns the sample ranks of the values in a vector.  Ties (i.e.,
313    /// equal values) and missing values can be handled in several ways.
314    ///
315    /// ## Usage:
316    ///
317    /// rank(x, na.last = TRUE,
318    /// ties.method = c("average", "first", "last", "random", "max", "min"))
319    ///
320    /// ## Arguments:
321    ///
322    /// * x: a numeric, complex, character or logical vector.
323    /// * na.last: a logical or character string controlling the treatment of
324    ///   ‘NA’s. If ‘TRUE’, missing values in the data are put last; if
325    ///   ‘FALSE’, they are put first; if ‘NA’, they are removed; if
326    ///   ‘"keep"’ they are kept with rank ‘NA’.
327    /// * ties.method: a character string specifying how ties are treated, see
328    ///   ‘Details’; can be abbreviated.
329    ///
330    /// ## Details:
331    ///
332    /// If all components are different (and no ‘NA’s), the ranks are well
333    /// defined, with values in ‘seq_along(x)’.  With some values equal
334    /// (called ‘ties’), the argument ‘ties.method’ determines the result
335    /// at the corresponding indices.  The ‘"first"’ method results in a
336    /// permutation with increasing values at each index set of ties, and
337    /// analogously ‘"last"’ with decreasing values.  The ‘"random"’
338    /// method puts these in random order whereas the default,
339    /// ‘"average"’, replaces them by their mean, and ‘"max"’ and ‘"min"’
340    /// replaces them by their maximum and minimum respectively, the
341    /// latter being the typical sports ranking.
342    ///
343    /// ‘NA’ values are never considered to be equal: for ‘na.last = TRUE’
344    /// and ‘na.last = FALSE’ they are given distinct ranks in the order
345    /// in which they occur in ‘x’.
346    ///
347    /// *NB*: ‘rank’ is not itself generic but ‘xtfrm’ is, and
348    /// ‘rank(xtfrm(x), ....)’ will have the desired result if there is a
349    /// ‘xtfrm’ method.  Otherwise, ‘rank’ will make use of ‘==’, ‘>’,
350    /// ‘is.na’ and extraction methods for classed objects, possibly
351    /// rather slowly.
352    ///
353    /// ## Value:
354    ///
355    /// A numeric vector of the same length as ‘x’ with names copied from
356    /// ‘x’ (unless ‘na.last = NA’, when missing values are removed).  The
357    /// vector is of integer type unless ‘x’ is a long vector or
358    /// ‘ties.method = "average"’ when it is of double type (whether or
359    /// not there are any ties).
360    ///
361    /// ## References:
362    ///
363    /// Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) _The New S
364    /// Language_.  Wadsworth & Brooks/Cole.
365    ///
366    /// ## See Also:
367    ///
368    /// ‘order’ and ‘sort’; ‘xtfrm’, see above.
369    ///
370    /// ## Examples:
371    ///
372    /// ```r
373    /// (r1 <- rank(x1 <- c(3, 1, 4, 15, 92)))
374    /// x2 <- c(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5)
375    /// names(x2) <- letters[1:11]
376    /// (r2 <- rank(x2)) # ties are averaged
377    ///
378    /// ## rank() is "idempotent": rank(rank(x)) == rank(x) :
379    /// stopifnot(rank(r1) == r1, rank(r2) == r2)
380    ///
381    /// ## ranks without averaging
382    /// rank(x2, ties.method= "first")  # first occurrence wins
383    /// rank(x2, ties.method= "last")   #  last occurrence wins
384    /// rank(x2, ties.method= "random") # ties broken at random
385    /// rank(x2, ties.method= "random") # and again
386    ///
387    /// ## keep ties ties, no average
388    /// (rma <- rank(x2, ties.method= "max"))  # as used classically
389    /// (rmi <- rank(x2, ties.method= "min"))  # as in Sports
390    /// stopifnot(rma + rmi == round(r2 + r2))
391    ///
392    /// ## Comparing all tie.methods:
393    /// tMeth <- eval(formals(rank)$ties.method)
394    /// rx2 <- sapply(tMeth, function(M) rank(x2, ties.method=M))
395    /// cbind(x2, rx2)
396    /// ## ties.method's does not matter w/o ties:
397    /// x <- sample(47)
398    /// rx <- sapply(tMeth, function(MM) rank(x, ties.method=MM))
399    /// stopifnot(all(rx[,1] == rx))
400    /// ```
401    fn ranks(&self) -> Vec<f64>;
402
403    /// Arithmetic Mean
404    ///
405    /// ## Description:
406    ///
407    /// Generic function for the (trimmed) arithmetic mean.
408    ///
409    /// ## Usage:
410    ///
411    /// mean(x, ...)
412    ///
413    /// ## Default S3 method:
414    /// mean(x, trim = 0, na.rm = FALSE, ...)
415    ///
416    /// ## Arguments:
417    ///
418    /// * x: An R object.  Currently there are methods for numeric/logical
419    ///   vectors and date, date-time and time interval objects.
420    ///   Complex vectors are allowed for ‘trim = 0’, only.
421    /// * trim: the fraction (0 to 0.5) of observations to be trimmed from
422    ///   each end of ‘x’ before the mean is computed.  Values of trim
423    ///   outside that range are taken as the nearest endpoint.
424    /// * na.rm: a logical evaluating to ‘TRUE’ or ‘FALSE’ indicating whether
425    ///   ‘NA’ values should be stripped before the computation
426    ///   proceeds.
427    /// * ...: further arguments passed to or from other methods.
428    ///
429    /// ## Value:
430    ///
431    /// If ‘trim’ is zero (the default), the arithmetic mean of the values
432    /// in ‘x’ is computed, as a numeric or complex vector of length one.
433    /// If ‘x’ is not logical (coerced to numeric), numeric (including
434    /// integer) or complex, ‘NA_real_’ is returned, with a warning.
435    ///
436    /// If ‘trim’ is non-zero, a symmetrically trimmed mean is computed
437    /// with a fraction of ‘trim’ observations deleted from each end
438    /// before the mean is computed.
439    ///
440    /// ## References:
441    ///
442    /// Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) _The New S
443    /// Language_.  Wadsworth & Brooks/Cole.
444    ///
445    /// ## See Also:
446    ///
447    /// ‘weighted.mean’, ‘mean.POSIXct’, ‘colMeans’ for row and column
448    /// means.
449    ///
450    /// ## Examples:
451    ///
452    /// ```r
453    /// x <- c(0:10, 50)
454    /// xm <- mean(x)
455    /// c(xm, mean(x, trim = 0.10))
456    /// ```
457    fn mean(&self) -> X;
458
459    /// Median Value
460    ///
461    /// ## Description:
462    ///
463    /// Compute the sample median.
464    ///
465    /// ## Usage:
466    ///
467    /// median(x, na.rm = FALSE, ...)
468    ///
469    /// ## Arguments:
470    ///
471    /// * x: an object for which a method has been defined, or a numeric
472    ///   vector containing the values whose median is to be computed.
473    /// * na.rm: a logical value indicating whether ‘NA’ values should be
474    ///   stripped before the computation proceeds.
475    /// * ...: potentially further arguments for methods; not used in the
476    ///   default method.
477    ///
478    /// ## Details:
479    ///
480    /// This is a generic function for which methods can be written.
481    /// However, the default method makes use of ‘is.na’, ‘sort’ and
482    /// ‘mean’ from package ‘base’ all of which are generic, and so the
483    /// default method will work for most classes (e.g., ‘"Date"’) for
484    /// which a median is a reasonable concept.
485    ///
486    /// ## Value:
487    ///
488    /// The default method returns a length-one object of the same type as
489    /// ‘x’, except when ‘x’ is logical or integer of even length, when
490    /// the result will be double.
491    ///
492    /// If there are no values or if ‘na.rm = FALSE’ and there are ‘NA’
493    /// values the result is ‘NA’ of the same type as ‘x’ (or more
494    /// generally the result of ‘x\[NA_integer_\]’).
495    ///
496    /// ## References:
497    ///
498    /// Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) _The New S
499    /// Language_.  Wadsworth & Brooks/Cole.
500    ///
501    /// ## See Also:
502    ///
503    /// ‘quantile’ for general quantiles.
504    ///
505    /// ## Examples:
506    ///
507    /// ```r
508    /// median(1:4) # = 2.5 [even number]
509    /// median(c(1:3, 100, 1000))  # = 3 [odd, robust]
510    /// ```
511    fn median(&self) -> X;
512
513    /// Cumulative Sums, Products, and Extremes
514    ///
515    /// ## Description:
516    ///
517    /// Returns a vector whose elements are the cumulative sums, products,
518    /// minima or maxima of the elements of the argument.
519    ///
520    /// ## Usage:
521    ///
522    /// cumsum(x)
523    /// cumprod(x)
524    /// cummax(x)
525    /// cummin(x)
526    ///
527    /// ## Arguments:
528    ///
529    /// * x: a numeric or complex (not ‘cummin’ or ‘cummax’) object, or an
530    ///   object that can be coerced to one of these.
531    ///
532    /// ## Details:
533    ///
534    /// These are generic functions: methods can be defined for them
535    /// individually or via the ‘Math’ group generic.
536    ///
537    /// ## Value:
538    ///
539    /// A vector of the same length and type as ‘x’ (after coercion),
540    /// except that ‘cumprod’ returns a numeric vector for integer input
541    /// (for consistency with ‘*’).  Names are preserved.
542    ///
543    /// An ‘NA’ value in ‘x’ causes the corresponding and following
544    /// elements of the return value to be ‘NA’, as does integer overflow
545    /// in ‘cumsum’ (with a warning).
546    ///
547    /// ## S4 methods:
548    ///
549    /// ‘cumsum’ and ‘cumprod’ are S4 generic functions: methods can be
550    /// defined for them individually or via the ‘Math’ group generic.
551    /// ‘cummax’ and ‘cummin’ are individually S4 generic functions.
552    ///
553    /// ## References:
554    ///
555    /// Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) _The New S
556    /// Language_.  Wadsworth & Brooks/Cole. (‘cumsum’ only.)
557    ///
558    /// ## Examples:
559    ///
560    /// ```r
561    /// cumsum(1:10)
562    /// cumprod(1:10)
563    /// cummin(c(3:1, 2:0, 4:2))
564    /// cummax(c(3:1, 2:0, 4:2))
565    /// ```
566    fn cumsum(&self) -> Vec<X>;
567    fn cumprod(&self) -> Vec<X>;
568    fn cummax(&self) -> Vec<X>;
569    fn cummin(&self) -> Vec<X>;
570
571    /// Median Absolute Deviation
572    ///
573    /// ## Description:
574    ///
575    /// Compute the median absolute deviation, i.e., the (lo-/hi-) median
576    /// of the absolute deviations from the median, and (by default)
577    /// adjust by a factor for asymptotically normal consistency.
578    ///
579    /// ## Usage:
580    ///
581    /// mad(x, center = median(x), constant = 1.4826, na.rm = FALSE,
582    /// low = FALSE, high = FALSE)
583    ///
584    /// ## Arguments:
585    ///
586    /// * x: a numeric vector.
587    /// * center: Optionally, the centre: defaults to the median.
588    /// * constant: scale factor.
589    /// * na.rm: if ‘TRUE’ then ‘NA’ values are stripped from ‘x’ before
590    ///   computation takes place.
591    /// * low: if ‘TRUE’, compute the ‘lo-median’, i.e., for even sample
592    ///   size, do not average the two middle values, but take the
593    ///   smaller one.
594    /// * high: if ‘TRUE’, compute the ‘hi-median’, i.e., take the larger of
595    ///   the two middle values for even sample size.
596    ///
597    /// ## Details:
598    ///
599    /// The actual value calculated is ‘constant * cMedian(abs(x -
600    /// center))’ with the default value of ‘center’ being ‘median(x)’,
601    /// and ‘cMedian’ being the usual, the ‘low’ or ‘high’ median, see the
602    /// arguments description for ‘low’ and ‘high’ above.
603    ///
604    /// In the case of n = 1 non-missing values and default ‘center’, the
605    /// result is ‘0’, consistent with “no deviation from the center”.
606    ///
607    /// The default ‘constant = 1.4826’ $(\text{approximately} 1/ \Phi^(-1)(3/4) = ‘1/\text{qnorm}(3/4)’)$
608    /// ensures consistency, i.e.,
609    ///
610    /// $E\[mad(X_1,...,X_n)\] = \sigma$
611    ///
612    /// for $X_i$ distributed as $N(\mu, \sigma^2)$ and large n.
613    ///
614    /// If ‘na.rm’ is ‘TRUE’ then ‘NA’ values are stripped from ‘x’ before
615    /// computation takes place.  If this is not done then an ‘NA’ value
616    /// in ‘x’ will cause ‘mad’ to return ‘NA’.
617    ///
618    /// ## See Also:
619    ///
620    /// ‘IQR’ which is simpler but less robust, ‘median’, ‘var’.
621    ///
622    /// ## Examples:
623    ///
624    /// ```r
625    /// mad(c(1:9))
626    /// print(mad(c(1:9),constant = 1)) ==
627    ///  mad(c(1:8, 100), constant = 1)  # = 2 ; TRUE
628    /// x <- c(1,2,3,5,7,8)
629    /// sort(abs(x - median(x)))
630    /// c(mad(x, constant = 1),
631    ///   mad(x, constant = 1, low = TRUE),
632    ///   mad(x, constant = 1, high = TRUE))
633    /// ```
634    fn mad(&self, deviation_type: DeviationType) -> X;
635
636    fn wmad(&self, w: &Self) -> X;
637}
638
639impl<X> StatArray<X> for Vec<X>
640where
641    X: Float + Sum + NumAssign + FromPrimitive + Debug,
642{
643    fn min(&self) -> X {
644        self.as_slice().min()
645    }
646
647    fn max(&self) -> X {
648        self.as_slice().max()
649    }
650
651    fn ranks(&self) -> Vec<f64> {
652        self.as_slice().ranks()
653    }
654
655    fn mean(&self) -> X {
656        self.as_slice().mean()
657    }
658
659    fn median(&self) -> X {
660        self.as_slice().median()
661    }
662
663    fn cumsum(&self) -> Vec<X> {
664        self.as_slice().cumsum()
665    }
666    fn cumprod(&self) -> Vec<X> {
667        self.as_slice().cumprod()
668    }
669    fn cummax(&self) -> Vec<X> {
670        self.as_slice().cummax()
671    }
672    fn cummin(&self) -> Vec<X> {
673        self.as_slice().cummin()
674    }
675
676    fn mad(&self, deviation_type: DeviationType) -> X {
677        self.as_slice().mad(deviation_type)
678    }
679
680    fn wmad(&self, w: &Self) -> X {
681        self.as_slice().wmad(&w.as_slice())
682    }
683}
684
685impl<X> StatArray<X> for &[X]
686where
687    X: Float + Sum + NumAssign + FromPrimitive + Debug,
688{
689    fn min(&self) -> X {
690        *self
691            .iter()
692            .min_by(|a, b| a.partial_cmp(b).unwrap())
693            .unwrap_or(&X::nan())
694    }
695
696    fn max(&self) -> X {
697        *self
698            .iter()
699            .max_by(|a, b| a.partial_cmp(b).unwrap())
700            .unwrap_or(&X::nan())
701    }
702
703    fn ranks(&self) -> Vec<f64> {
704        let mut ret = vec![0.0; self.len()];
705        let mut sorted_x = self.iter().collect::<Vec<_>>();
706        sorted_x.sort_by(|a, b| a.partial_cmp(b).unwrap());
707
708        let mut current = 1.0;
709        for &sorted_xi in sorted_x.into_iter() {
710            let mut found = false;
711            for (pos, &xi) in self.iter().enumerate() {
712                if !found && ret[pos] == 0.0 && sorted_xi == xi {
713                    ret[pos] = current;
714                    current += 1.0;
715                    found = true
716                }
717            }
718        }
719        ret
720    }
721
722    fn mean(&self) -> X {
723        let weight = 1.0 / self.len() as f64;
724        self.iter()
725            .map(|xi| X::from_f64(weight).unwrap() * *xi)
726            .sum()
727    }
728
729    fn median(&self) -> X {
730        if self.is_empty() {
731            X::nan()
732        } else if self.len() == 1 {
733            self[0]
734        } else {
735            let x_ranks = self.ranks();
736            let median_ranks = if (self.len()) % 2 == 0 {
737                vec![(self.len() / 2), (self.len() / 2) + 1]
738            } else {
739                vec![(self.len() / 2) + 1]
740            };
741            median_ranks
742                .iter()
743                .map(|&median_rank| {
744                    self[x_ranks
745                        .iter()
746                        .position(|&x_rank_i| x_rank_i as usize == median_rank)
747                        .unwrap()]
748                })
749                .sum::<X>()
750                / X::from_usize(median_ranks.len()).unwrap()
751        }
752    }
753
754    fn cumsum(&self) -> Vec<X> {
755        let mut accumulator = X::zero();
756        self.iter()
757            .map(|&x_i| {
758                accumulator = accumulator + x_i;
759                accumulator
760            })
761            .collect()
762    }
763
764    fn cumprod(&self) -> Vec<X> {
765        let mut accumulator = X::zero();
766        self.iter()
767            .map(|&x_i| {
768                accumulator = accumulator * x_i;
769                accumulator
770            })
771            .collect()
772    }
773
774    fn cummax(&self) -> Vec<X> {
775        let mut accumulator = X::zero();
776        self.iter()
777            .map(|&x_i| {
778                accumulator = accumulator.max(x_i);
779                accumulator
780            })
781            .collect()
782    }
783
784    fn cummin(&self) -> Vec<X> {
785        let mut accumulator = X::zero();
786        self.iter()
787            .map(|&x_i| {
788                accumulator = accumulator.min(x_i);
789                accumulator
790            })
791            .collect()
792    }
793
794    fn mad(&self, deviation_type: DeviationType) -> X {
795        let (constant, center) = match deviation_type {
796            DeviationType::Mean(center_opt) => (
797                1.253,
798                center_opt
799                    .map(|c| X::from_f64(c).unwrap())
800                    .unwrap_or(self.mean()),
801            ),
802            DeviationType::Median(center_opt) => (
803                1.4826,
804                center_opt
805                    .map(|c| X::from_f64(c).unwrap())
806                    .unwrap_or(self.median()),
807            ),
808            DeviationType::Other(center) => (1.0, X::from_f64(center).unwrap()),
809        };
810        X::from_f64(constant).unwrap()
811            * self
812                .iter()
813                .copied()
814                .map(|x_i| (x_i - center).abs())
815                .collect::<Vec<_>>()
816                .median()
817    }
818
819    fn wmad(&self, w: &Self) -> X {
820        let mut o = (0..self.len()).collect::<Vec<_>>();
821        o.sort_by(|&index1, &index2| self[index1].partial_cmp(&self[index2]).unwrap());
822
823        let x = o.iter().map(|&i| self[i].abs()).collect::<Vec<_>>();
824        let w = o.iter().map(|&i| w[i]).collect::<Vec<_>>();
825        let p = w
826            .cumsum()
827            .into_iter()
828            .map(|i| i / w.iter().cloned().sum::<X>())
829            .collect::<Vec<_>>();
830        let n = p
831            .iter()
832            .copied()
833            .filter(|&p_i| p_i < X::from_f64(0.5).unwrap())
834            .count();
835        if p[n + 1] > X::from_f64(0.5).unwrap() {
836            x[n + 1] / X::from_f64(0.6745).unwrap()
837        } else {
838            (x[n + 1] + x[n + 2]) / X::from_f64(2.0 * 0.6745).unwrap()
839        }
840    }
841}