(index<- ) ./libtest/stats.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Fri May 9 13:02:28 2014
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![allow(missing_doc)]
12
13 use std::hash::Hash;
14 use std::io;
15 use std::mem;
16 use std::num;
17 use std::num::Zero;
18 use collections::hashmap;
19 use std::fmt::Show;
20
21 fn local_cmp<T:Float>(x: T, y: T) -> Ordering {
22 // arbitrarily decide that NaNs are larger than everything.
23 if y.is_nan() {
24 Less
25 } else if x.is_nan() {
26 Greater
27 } else if x < y {
28 Less
29 } else if x == y {
30 Equal
31 } else {
32 Greater
33 }
34 }
35
36 fn local_sort<T: Float>(v: &mut [T]) {
37 v.sort_by(|x: &T, y: &T| local_cmp(*x, *y));
38 }
39
40 /// Trait that provides simple descriptive statistics on a univariate set of numeric samples.
41 pub trait Stats <T: Float + FromPrimitive>{
42
43 /// Sum of the samples.
44 ///
45 /// Note: this method sacrifices performance at the altar of accuracy
46 /// Depends on IEEE-754 arithmetic guarantees. See proof of correctness at:
47 /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates"]
48 /// (http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps)
49 /// *Discrete & Computational Geometry 18*, 3 (Oct 1997), 305-363, Shewchuk J.R.
50 fn sum(self) -> T;
51
52 /// Minimum value of the samples.
53 fn min(self) -> T;
54
55 /// Maximum value of the samples.
56 fn max(self) -> T;
57
58 /// Arithmetic mean (average) of the samples: sum divided by sample-count.
59 ///
60 /// See: https://en.wikipedia.org/wiki/Arithmetic_mean
61 fn mean(self) -> T;
62
63 /// Median of the samples: value separating the lower half of the samples from the higher half.
64 /// Equal to `self.percentile(50.0)`.
65 ///
66 /// See: https://en.wikipedia.org/wiki/Median
67 fn median(self) -> T;
68
69 /// Variance of the samples: bias-corrected mean of the squares of the differences of each
70 /// sample from the sample mean. Note that this calculates the _sample variance_ rather than the
71 /// population variance, which is assumed to be unknown. It therefore corrects the `(n-1)/n`
72 /// bias that would appear if we calculated a population variance, by dividing by `(n-1)` rather
73 /// than `n`.
74 ///
75 /// See: https://en.wikipedia.org/wiki/Variance
76 fn var(self) -> T;
77
78 /// Standard deviation: the square root of the sample variance.
79 ///
80 /// Note: this is not a robust statistic for non-normal distributions. Prefer the
81 /// `median_abs_dev` for unknown distributions.
82 ///
83 /// See: https://en.wikipedia.org/wiki/Standard_deviation
84 fn std_dev(self) -> T;
85
86 /// Standard deviation as a percent of the mean value. See `std_dev` and `mean`.
87 ///
88 /// Note: this is not a robust statistic for non-normal distributions. Prefer the
89 /// `median_abs_dev_pct` for unknown distributions.
90 fn std_dev_pct(self) -> T;
91
92 /// Scaled median of the absolute deviations of each sample from the sample median. This is a
93 /// robust (distribution-agnostic) estimator of sample variability. Use this in preference to
94 /// `std_dev` if you cannot assume your sample is normally distributed. Note that this is scaled
95 /// by the constant `1.4826` to allow its use as a consistent estimator for the standard
96 /// deviation.
97 ///
98 /// See: http://en.wikipedia.org/wiki/Median_absolute_deviation
99 fn median_abs_dev(self) -> T;
100
101 /// Median absolute deviation as a percent of the median. See `median_abs_dev` and `median`.
102 fn median_abs_dev_pct(self) -> T;
103
104 /// Percentile: the value below which `pct` percent of the values in `self` fall. For example,
105 /// percentile(95.0) will return the value `v` such that 95% of the samples `s` in `self`
106 /// satisfy `s <= v`.
107 ///
108 /// Calculated by linear interpolation between closest ranks.
109 ///
110 /// See: http://en.wikipedia.org/wiki/Percentile
111 fn percentile(self, pct: T) -> T;
112
113 /// Quartiles of the sample: three values that divide the sample into four equal groups, each
114 /// with 1/4 of the data. The middle value is the median. See `median` and `percentile`. This
115 /// function may calculate the 3 quartiles more efficiently than 3 calls to `percentile`, but
116 /// is otherwise equivalent.
117 ///
118 /// See also: https://en.wikipedia.org/wiki/Quartile
119 fn quartiles(self) -> (T,T,T);
120
121 /// Inter-quartile range: the difference between the 25th percentile (1st quartile) and the 75th
122 /// percentile (3rd quartile). See `quartiles`.
123 ///
124 /// See also: https://en.wikipedia.org/wiki/Interquartile_range
125 fn iqr(self) -> T;
126 }
127
128 /// Extracted collection of all the summary statistics of a sample set.
129 #[deriving(Clone, Eq)]
130 #[allow(missing_doc)]
131 pub struct Summary<T> {
132 pub sum: T,
133 pub min: T,
134 pub max: T,
135 pub mean: T,
136 pub median: T,
137 pub var: T,
138 pub std_dev: T,
139 pub std_dev_pct: T,
140 pub median_abs_dev: T,
141 pub median_abs_dev_pct: T,
142 pub quartiles: (T,T,T),
143 pub iqr: T,
144 }
145
146 impl<T: Float + FromPrimitive> Summary<T> {
147
148 /// Construct a new summary of a sample set.
149 pub fn new(samples: &[T]) -> Summary<T> {
150 Summary {
151 sum: samples.sum(),
152 min: samples.min(),
153 max: samples.max(),
154 mean: samples.mean(),
155 median: samples.median(),
156 var: samples.var(),
157 std_dev: samples.std_dev(),
158 std_dev_pct: samples.std_dev_pct(),
159 median_abs_dev: samples.median_abs_dev(),
160 median_abs_dev_pct: samples.median_abs_dev_pct(),
161 quartiles: samples.quartiles(),
162 iqr: samples.iqr()
163 }
164 }
165 }
166
167 impl<'a,T: Float + FromPrimitive> Stats<T> for &'a [T] {
168
169 // FIXME #11059 handle NaN, inf and overflow
170 #[allow(deprecated_owned_vector)]
171 fn sum(self) -> T {
172 let mut partials = vec![];
173
174 for &mut x in self.iter() {
175 let mut j = 0;
176 // This inner loop applies `hi`/`lo` summation to each
177 // partial so that the list of partial sums remains exact.
178 for i in range(0, partials.len()) {
179 let mut y = *partials.get(i);
180 if num::abs(x) < num::abs(y) {
181 mem::swap(&mut x, &mut y);
182 }
183 // Rounded `x+y` is stored in `hi` with round-off stored in
184 // `lo`. Together `hi+lo` are exactly equal to `x+y`.
185 let hi = x + y;
186 let lo = y - (hi - x);
187 if !lo.is_zero() {
188 *partials.get_mut(j) = lo;
189 j += 1;
190 }
191 x = hi;
192 }
193 if j >= partials.len() {
194 partials.push(x);
195 } else {
196 *partials.get_mut(j) = x;
197 partials.truncate(j+1);
198 }
199 }
200 let zero: T = Zero::zero();
201 partials.iter().fold(zero, |p, q| p + *q)
202 }
203
204 fn min(self) -> T {
205 assert!(self.len() != 0);
206 self.iter().fold(self[0], |p, q| p.min(*q))
207 }
208
209 fn max(self) -> T {
210 assert!(self.len() != 0);
211 self.iter().fold(self[0], |p, q| p.max(*q))
212 }
213
214 fn mean(self) -> T {
215 assert!(self.len() != 0);
216 self.sum() / FromPrimitive::from_uint(self.len()).unwrap()
217 }
218
219 fn median(self) -> T {
220 self.percentile(FromPrimitive::from_uint(50).unwrap())
221 }
222
223 fn var(self) -> T {
224 if self.len() < 2 {
225 Zero::zero()
226 } else {
227 let mean = self.mean();
228 let mut v: T = Zero::zero();
229 for s in self.iter() {
230 let x = *s - mean;
231 v = v + x*x;
232 }
233 // NB: this is _supposed to be_ len-1, not len. If you
234 // change it back to len, you will be calculating a
235 // population variance, not a sample variance.
236 let denom = FromPrimitive::from_uint(self.len()-1).unwrap();
237 v/denom
238 }
239 }
240
241 fn std_dev(self) -> T {
242 self.var().sqrt()
243 }
244
245 fn std_dev_pct(self) -> T {
246 let hundred = FromPrimitive::from_uint(100).unwrap();
247 (self.std_dev() / self.mean()) * hundred
248 }
249
250 fn median_abs_dev(self) -> T {
251 let med = self.median();
252 let abs_devs: Vec<T> = self.iter().map(|&v| num::abs(med - v)).collect();
253 // This constant is derived by smarter statistics brains than me, but it is
254 // consistent with how R and other packages treat the MAD.
255 let number = FromPrimitive::from_f64(1.4826).unwrap();
256 abs_devs.as_slice().median() * number
257 }
258
259 fn median_abs_dev_pct(self) -> T {
260 let hundred = FromPrimitive::from_uint(100).unwrap();
261 (self.median_abs_dev() / self.median()) * hundred
262 }
263
264 fn percentile(self, pct: T) -> T {
265 let mut tmp = Vec::from_slice(self);
266 local_sort(tmp.as_mut_slice());
267 percentile_of_sorted(tmp.as_slice(), pct)
268 }
269
270 fn quartiles(self) -> (T,T,T) {
271 let mut tmp = Vec::from_slice(self);
272 local_sort(tmp.as_mut_slice());
273 let first = FromPrimitive::from_uint(25).unwrap();
274 let a = percentile_of_sorted(tmp.as_slice(), first);
275 let secound = FromPrimitive::from_uint(50).unwrap();
276 let b = percentile_of_sorted(tmp.as_slice(), secound);
277 let third = FromPrimitive::from_uint(75).unwrap();
278 let c = percentile_of_sorted(tmp.as_slice(), third);
279 (a,b,c)
280 }
281
282 fn iqr(self) -> T {
283 let (a,_,c) = self.quartiles();
284 c - a
285 }
286 }
287
288
289 // Helper function: extract a value representing the `pct` percentile of a sorted sample-set, using
290 // linear interpolation. If samples are not sorted, return nonsensical value.
291 fn percentile_of_sorted<T: Float + FromPrimitive>(sorted_samples: &[T],
292 pct: T) -> T {
293 assert!(sorted_samples.len() != 0);
294 if sorted_samples.len() == 1 {
295 return sorted_samples[0];
296 }
297 let zero: T = Zero::zero();
298 assert!(zero <= pct);
299 let hundred = FromPrimitive::from_uint(100).unwrap();
300 assert!(pct <= hundred);
301 if pct == hundred {
302 return sorted_samples[sorted_samples.len() - 1];
303 }
304 let length = FromPrimitive::from_uint(sorted_samples.len() - 1).unwrap();
305 let rank = (pct / hundred) * length;
306 let lrank = rank.floor();
307 let d = rank - lrank;
308 let n = lrank.to_uint().unwrap();
309 let lo = sorted_samples[n];
310 let hi = sorted_samples[n+1];
311 lo + (hi - lo) * d
312 }
313
314
315 /// Winsorize a set of samples, replacing values above the `100-pct` percentile and below the `pct`
316 /// percentile with those percentiles themselves. This is a way of minimizing the effect of
317 /// outliers, at the cost of biasing the sample. It differs from trimming in that it does not
318 /// change the number of samples, just changes the values of those that are outliers.
319 ///
320 /// See: http://en.wikipedia.org/wiki/Winsorising
321 pub fn winsorize<T: Float + FromPrimitive>(samples: &mut [T], pct: T) {
322 let mut tmp = Vec::from_slice(samples);
323 local_sort(tmp.as_mut_slice());
324 let lo = percentile_of_sorted(tmp.as_slice(), pct);
325 let hundred: T = FromPrimitive::from_uint(100).unwrap();
326 let hi = percentile_of_sorted(tmp.as_slice(), hundred-pct);
327 for samp in samples.mut_iter() {
328 if *samp > hi {
329 *samp = hi
330 } else if *samp < lo {
331 *samp = lo
332 }
333 }
334 }
335
336 /// Render writes the min, max and quartiles of the provided `Summary` to the provided `Writer`.
337 pub fn write_5_number_summary<T: Float + Show>(w: &mut io::Writer,
338 s: &Summary<T>) -> io::IoResult<()> {
339 let (q1,q2,q3) = s.quartiles;
340 write!(w, "(min={}, q1={}, med={}, q3={}, max={})",
341 s.min,
342 q1,
343 q2,
344 q3,
345 s.max)
346 }
347
348 /// Render a boxplot to the provided writer. The boxplot shows the min, max and quartiles of the
349 /// provided `Summary` (thus includes the mean) and is scaled to display within the range of the
350 /// nearest multiple-of-a-power-of-ten above and below the min and max of possible values, and
351 /// target `width_hint` characters of display (though it will be wider if necessary).
352 ///
353 /// As an example, the summary with 5-number-summary `(min=15, q1=17, med=20, q3=24, max=31)` might
354 /// display as:
355 ///
356 /// ~~~~ignore
357 /// 10 | [--****#******----------] | 40
358 /// ~~~~
359
360 pub fn write_boxplot<T: Float + Show + FromPrimitive>(
361 w: &mut io::Writer,
362 s: &Summary<T>,
363 width_hint: uint)
364 -> io::IoResult<()> {
365
366 let (q1,q2,q3) = s.quartiles;
367
368 // the .abs() handles the case where numbers are negative
369 let ten: T = FromPrimitive::from_uint(10).unwrap();
370 let lomag = ten.powf(s.min.abs().log10().floor());
371 let himag = ten.powf(s.max.abs().log10().floor());
372
373 // need to consider when the limit is zero
374 let zero: T = Zero::zero();
375 let lo = if lomag.is_zero() {
376 zero
377 } else {
378 (s.min / lomag).floor() * lomag
379 };
380
381 let hi = if himag.is_zero() {
382 zero
383 } else {
384 (s.max / himag).ceil() * himag
385 };
386
387 let range = hi - lo;
388
389 let lostr = lo.to_str();
390 let histr = hi.to_str();
391
392 let overhead_width = lostr.len() + histr.len() + 4;
393 let range_width = width_hint - overhead_width;
394 let range_float = FromPrimitive::from_uint(range_width).unwrap();
395 let char_step = range / range_float;
396
397 try!(write!(w, "{} |", lostr));
398
399 let mut c = 0;
400 let mut v = lo;
401
402 while c < range_width && v < s.min {
403 try!(write!(w, " "));
404 v = v + char_step;
405 c += 1;
406 }
407 try!(write!(w, "["));
408 c += 1;
409 while c < range_width && v < q1 {
410 try!(write!(w, "-"));
411 v = v + char_step;
412 c += 1;
413 }
414 while c < range_width && v < q2 {
415 try!(write!(w, "*"));
416 v = v + char_step;
417 c += 1;
418 }
419 try!(write!(w, r"\#"));
420 c += 1;
421 while c < range_width && v < q3 {
422 try!(write!(w, "*"));
423 v = v + char_step;
424 c += 1;
425 }
426 while c < range_width && v < s.max {
427 try!(write!(w, "-"));
428 v = v + char_step;
429 c += 1;
430 }
431 try!(write!(w, "]"));
432 while c < range_width {
433 try!(write!(w, " "));
434 v = v + char_step;
435 c += 1;
436 }
437
438 try!(write!(w, "| {}", histr));
439 Ok(())
440 }
441
442 /// Returns a HashMap with the number of occurrences of every element in the
443 /// sequence that the iterator exposes.
444 pub fn freq_count<T: Iterator<U>, U: TotalEq+Hash>(mut iter: T) -> hashmap::HashMap<U, uint> {
445 let mut map: hashmap::HashMap<U,uint> = hashmap::HashMap::new();
446 for elem in iter {
447 map.insert_or_update_with(elem, 1, |_, count| *count += 1);
448 }
449 map
450 }
451
452 // Test vectors generated from R, using the script src/etc/stat-test-vectors.r.
453
454 #[cfg(test)]
455 mod tests {
456 use stats::Stats;
457 use stats::Summary;
458 use stats::write_5_number_summary;
459 use stats::write_boxplot;
460 use std::io;
461 use std::str;
462 use std::f64;
463
464 macro_rules! assert_approx_eq(
465 ($a:expr, $b:expr) => ({
466 let (a, b) = (&$a, &$b);
467 assert!((*a - *b).abs() < 1.0e-6,
468 "{} is not approximately equal to {}", *a, *b);
469 })
470 )
471
472 fn check(samples: &[f64], summ: &Summary<f64>) {
473
474 let summ2 = Summary::new(samples);
475
476 let mut w = io::stdout();
477 let w = &mut w as &mut io::Writer;
478 (write!(w, "\n")).unwrap();
479 write_5_number_summary(w, &summ2).unwrap();
480 (write!(w, "\n")).unwrap();
481 write_boxplot(w, &summ2, 50).unwrap();
482 (write!(w, "\n")).unwrap();
483
484 assert_eq!(summ.sum, summ2.sum);
485 assert_eq!(summ.min, summ2.min);
486 assert_eq!(summ.max, summ2.max);
487 assert_eq!(summ.mean, summ2.mean);
488 assert_eq!(summ.median, summ2.median);
489
490 // We needed a few more digits to get exact equality on these
491 // but they're within float epsilon, which is 1.0e-6.
492 assert_approx_eq!(summ.var, summ2.var);
493 assert_approx_eq!(summ.std_dev, summ2.std_dev);
494 assert_approx_eq!(summ.std_dev_pct, summ2.std_dev_pct);
495 assert_approx_eq!(summ.median_abs_dev, summ2.median_abs_dev);
496 assert_approx_eq!(summ.median_abs_dev_pct, summ2.median_abs_dev_pct);
497
498 assert_eq!(summ.quartiles, summ2.quartiles);
499 assert_eq!(summ.iqr, summ2.iqr);
500 }
501
502 #[test]
503 fn test_min_max_nan() {
504 let xs = &[1.0, 2.0, f64::NAN, 3.0, 4.0];
505 let summary = Summary::new(xs);
506 assert_eq!(summary.min, 1.0);
507 assert_eq!(summary.max, 4.0);
508 }
509
510 #[test]
511 fn test_norm2() {
512 let val = &[
513 958.0000000000,
514 924.0000000000,
515 ];
516 let summ = &Summary {
517 sum: 1882.0000000000,
518 min: 924.0000000000,
519 max: 958.0000000000,
520 mean: 941.0000000000,
521 median: 941.0000000000,
522 var: 578.0000000000,
523 std_dev: 24.0416305603,
524 std_dev_pct: 2.5549022912,
525 median_abs_dev: 25.2042000000,
526 median_abs_dev_pct: 2.6784484591,
527 quartiles: (932.5000000000,941.0000000000,949.5000000000),
528 iqr: 17.0000000000,
529 };
530 check(val, summ);
531 }
532 #[test]
533 fn test_norm10narrow() {
534 let val = &[
535 966.0000000000,
536 985.0000000000,
537 1110.0000000000,
538 848.0000000000,
539 821.0000000000,
540 975.0000000000,
541 962.0000000000,
542 1157.0000000000,
543 1217.0000000000,
544 955.0000000000,
545 ];
546 let summ = &Summary {
547 sum: 9996.0000000000,
548 min: 821.0000000000,
549 max: 1217.0000000000,
550 mean: 999.6000000000,
551 median: 970.5000000000,
552 var: 16050.7111111111,
553 std_dev: 126.6914010938,
554 std_dev_pct: 12.6742097933,
555 median_abs_dev: 102.2994000000,
556 median_abs_dev_pct: 10.5408964451,
557 quartiles: (956.7500000000,970.5000000000,1078.7500000000),
558 iqr: 122.0000000000,
559 };
560 check(val, summ);
561 }
562 #[test]
563 fn test_norm10medium() {
564 let val = &[
565 954.0000000000,
566 1064.0000000000,
567 855.0000000000,
568 1000.0000000000,
569 743.0000000000,
570 1084.0000000000,
571 704.0000000000,
572 1023.0000000000,
573 357.0000000000,
574 869.0000000000,
575 ];
576 let summ = &Summary {
577 sum: 8653.0000000000,
578 min: 357.0000000000,
579 max: 1084.0000000000,
580 mean: 865.3000000000,
581 median: 911.5000000000,
582 var: 48628.4555555556,
583 std_dev: 220.5186059170,
584 std_dev_pct: 25.4846418487,
585 median_abs_dev: 195.7032000000,
586 median_abs_dev_pct: 21.4704552935,
587 quartiles: (771.0000000000,911.5000000000,1017.2500000000),
588 iqr: 246.2500000000,
589 };
590 check(val, summ);
591 }
592 #[test]
593 fn test_norm10wide() {
594 let val = &[
595 505.0000000000,
596 497.0000000000,
597 1591.0000000000,
598 887.0000000000,
599 1026.0000000000,
600 136.0000000000,
601 1580.0000000000,
602 940.0000000000,
603 754.0000000000,
604 1433.0000000000,
605 ];
606 let summ = &Summary {
607 sum: 9349.0000000000,
608 min: 136.0000000000,
609 max: 1591.0000000000,
610 mean: 934.9000000000,
611 median: 913.5000000000,
612 var: 239208.9888888889,
613 std_dev: 489.0899599142,
614 std_dev_pct: 52.3146817750,
615 median_abs_dev: 611.5725000000,
616 median_abs_dev_pct: 66.9482758621,
617 quartiles: (567.2500000000,913.5000000000,1331.2500000000),
618 iqr: 764.0000000000,
619 };
620 check(val, summ);
621 }
622 #[test]
623 fn test_norm25verynarrow() {
624 let val = &[
625 991.0000000000,
626 1018.0000000000,
627 998.0000000000,
628 1013.0000000000,
629 974.0000000000,
630 1007.0000000000,
631 1014.0000000000,
632 999.0000000000,
633 1011.0000000000,
634 978.0000000000,
635 985.0000000000,
636 999.0000000000,
637 983.0000000000,
638 982.0000000000,
639 1015.0000000000,
640 1002.0000000000,
641 977.0000000000,
642 948.0000000000,
643 1040.0000000000,
644 974.0000000000,
645 996.0000000000,
646 989.0000000000,
647 1015.0000000000,
648 994.0000000000,
649 1024.0000000000,
650 ];
651 let summ = &Summary {
652 sum: 24926.0000000000,
653 min: 948.0000000000,
654 max: 1040.0000000000,
655 mean: 997.0400000000,
656 median: 998.0000000000,
657 var: 393.2066666667,
658 std_dev: 19.8294393937,
659 std_dev_pct: 1.9888308788,
660 median_abs_dev: 22.2390000000,
661 median_abs_dev_pct: 2.2283567134,
662 quartiles: (983.0000000000,998.0000000000,1013.0000000000),
663 iqr: 30.0000000000,
664 };
665 check(val, summ);
666 }
667 #[test]
668 fn test_exp10a() {
669 let val = &[
670 23.0000000000,
671 11.0000000000,
672 2.0000000000,
673 57.0000000000,
674 4.0000000000,
675 12.0000000000,
676 5.0000000000,
677 29.0000000000,
678 3.0000000000,
679 21.0000000000,
680 ];
681 let summ = &Summary {
682 sum: 167.0000000000,
683 min: 2.0000000000,
684 max: 57.0000000000,
685 mean: 16.7000000000,
686 median: 11.5000000000,
687 var: 287.7888888889,
688 std_dev: 16.9643416875,
689 std_dev_pct: 101.5828843560,
690 median_abs_dev: 13.3434000000,
691 median_abs_dev_pct: 116.0295652174,
692 quartiles: (4.2500000000,11.5000000000,22.5000000000),
693 iqr: 18.2500000000,
694 };
695 check(val, summ);
696 }
697 #[test]
698 fn test_exp10b() {
699 let val = &[
700 24.0000000000,
701 17.0000000000,
702 6.0000000000,
703 38.0000000000,
704 25.0000000000,
705 7.0000000000,
706 51.0000000000,
707 2.0000000000,
708 61.0000000000,
709 32.0000000000,
710 ];
711 let summ = &Summary {
712 sum: 263.0000000000,
713 min: 2.0000000000,
714 max: 61.0000000000,
715 mean: 26.3000000000,
716 median: 24.5000000000,
717 var: 383.5666666667,
718 std_dev: 19.5848580967,
719 std_dev_pct: 74.4671410520,
720 median_abs_dev: 22.9803000000,
721 median_abs_dev_pct: 93.7971428571,
722 quartiles: (9.5000000000,24.5000000000,36.5000000000),
723 iqr: 27.0000000000,
724 };
725 check(val, summ);
726 }
727 #[test]
728 fn test_exp10c() {
729 let val = &[
730 71.0000000000,
731 2.0000000000,
732 32.0000000000,
733 1.0000000000,
734 6.0000000000,
735 28.0000000000,
736 13.0000000000,
737 37.0000000000,
738 16.0000000000,
739 36.0000000000,
740 ];
741 let summ = &Summary {
742 sum: 242.0000000000,
743 min: 1.0000000000,
744 max: 71.0000000000,
745 mean: 24.2000000000,
746 median: 22.0000000000,
747 var: 458.1777777778,
748 std_dev: 21.4050876611,
749 std_dev_pct: 88.4507754589,
750 median_abs_dev: 21.4977000000,
751 median_abs_dev_pct: 97.7168181818,
752 quartiles: (7.7500000000,22.0000000000,35.0000000000),
753 iqr: 27.2500000000,
754 };
755 check(val, summ);
756 }
757 #[test]
758 fn test_exp25() {
759 let val = &[
760 3.0000000000,
761 24.0000000000,
762 1.0000000000,
763 19.0000000000,
764 7.0000000000,
765 5.0000000000,
766 30.0000000000,
767 39.0000000000,
768 31.0000000000,
769 13.0000000000,
770 25.0000000000,
771 48.0000000000,
772 1.0000000000,
773 6.0000000000,
774 42.0000000000,
775 63.0000000000,
776 2.0000000000,
777 12.0000000000,
778 108.0000000000,
779 26.0000000000,
780 1.0000000000,
781 7.0000000000,
782 44.0000000000,
783 25.0000000000,
784 11.0000000000,
785 ];
786 let summ = &Summary {
787 sum: 593.0000000000,
788 min: 1.0000000000,
789 max: 108.0000000000,
790 mean: 23.7200000000,
791 median: 19.0000000000,
792 var: 601.0433333333,
793 std_dev: 24.5161851301,
794 std_dev_pct: 103.3565983562,
795 median_abs_dev: 19.2738000000,
796 median_abs_dev_pct: 101.4410526316,
797 quartiles: (6.0000000000,19.0000000000,31.0000000000),
798 iqr: 25.0000000000,
799 };
800 check(val, summ);
801 }
802 #[test]
803 fn test_binom25() {
804 let val = &[
805 18.0000000000,
806 17.0000000000,
807 27.0000000000,
808 15.0000000000,
809 21.0000000000,
810 25.0000000000,
811 17.0000000000,
812 24.0000000000,
813 25.0000000000,
814 24.0000000000,
815 26.0000000000,
816 26.0000000000,
817 23.0000000000,
818 15.0000000000,
819 23.0000000000,
820 17.0000000000,
821 18.0000000000,
822 18.0000000000,
823 21.0000000000,
824 16.0000000000,
825 15.0000000000,
826 31.0000000000,
827 20.0000000000,
828 17.0000000000,
829 15.0000000000,
830 ];
831 let summ = &Summary {
832 sum: 514.0000000000,
833 min: 15.0000000000,
834 max: 31.0000000000,
835 mean: 20.5600000000,
836 median: 20.0000000000,
837 var: 20.8400000000,
838 std_dev: 4.5650848842,
839 std_dev_pct: 22.2037202539,
840 median_abs_dev: 5.9304000000,
841 median_abs_dev_pct: 29.6520000000,
842 quartiles: (17.0000000000,20.0000000000,24.0000000000),
843 iqr: 7.0000000000,
844 };
845 check(val, summ);
846 }
847 #[test]
848 fn test_pois25lambda30() {
849 let val = &[
850 27.0000000000,
851 33.0000000000,
852 34.0000000000,
853 34.0000000000,
854 24.0000000000,
855 39.0000000000,
856 28.0000000000,
857 27.0000000000,
858 31.0000000000,
859 28.0000000000,
860 38.0000000000,
861 21.0000000000,
862 33.0000000000,
863 36.0000000000,
864 29.0000000000,
865 37.0000000000,
866 32.0000000000,
867 34.0000000000,
868 31.0000000000,
869 39.0000000000,
870 25.0000000000,
871 31.0000000000,
872 32.0000000000,
873 40.0000000000,
874 24.0000000000,
875 ];
876 let summ = &Summary {
877 sum: 787.0000000000,
878 min: 21.0000000000,
879 max: 40.0000000000,
880 mean: 31.4800000000,
881 median: 32.0000000000,
882 var: 26.5933333333,
883 std_dev: 5.1568724372,
884 std_dev_pct: 16.3814245145,
885 median_abs_dev: 5.9304000000,
886 median_abs_dev_pct: 18.5325000000,
887 quartiles: (28.0000000000,32.0000000000,34.0000000000),
888 iqr: 6.0000000000,
889 };
890 check(val, summ);
891 }
892 #[test]
893 fn test_pois25lambda40() {
894 let val = &[
895 42.0000000000,
896 50.0000000000,
897 42.0000000000,
898 46.0000000000,
899 34.0000000000,
900 45.0000000000,
901 34.0000000000,
902 49.0000000000,
903 39.0000000000,
904 28.0000000000,
905 40.0000000000,
906 35.0000000000,
907 37.0000000000,
908 39.0000000000,
909 46.0000000000,
910 44.0000000000,
911 32.0000000000,
912 45.0000000000,
913 42.0000000000,
914 37.0000000000,
915 48.0000000000,
916 42.0000000000,
917 33.0000000000,
918 42.0000000000,
919 48.0000000000,
920 ];
921 let summ = &Summary {
922 sum: 1019.0000000000,
923 min: 28.0000000000,
924 max: 50.0000000000,
925 mean: 40.7600000000,
926 median: 42.0000000000,
927 var: 34.4400000000,
928 std_dev: 5.8685603004,
929 std_dev_pct: 14.3978417577,
930 median_abs_dev: 5.9304000000,
931 median_abs_dev_pct: 14.1200000000,
932 quartiles: (37.0000000000,42.0000000000,45.0000000000),
933 iqr: 8.0000000000,
934 };
935 check(val, summ);
936 }
937 #[test]
938 fn test_pois25lambda50() {
939 let val = &[
940 45.0000000000,
941 43.0000000000,
942 44.0000000000,
943 61.0000000000,
944 51.0000000000,
945 53.0000000000,
946 59.0000000000,
947 52.0000000000,
948 49.0000000000,
949 51.0000000000,
950 51.0000000000,
951 50.0000000000,
952 49.0000000000,
953 56.0000000000,
954 42.0000000000,
955 52.0000000000,
956 51.0000000000,
957 43.0000000000,
958 48.0000000000,
959 48.0000000000,
960 50.0000000000,
961 42.0000000000,
962 43.0000000000,
963 42.0000000000,
964 60.0000000000,
965 ];
966 let summ = &Summary {
967 sum: 1235.0000000000,
968 min: 42.0000000000,
969 max: 61.0000000000,
970 mean: 49.4000000000,
971 median: 50.0000000000,
972 var: 31.6666666667,
973 std_dev: 5.6273143387,
974 std_dev_pct: 11.3913245723,
975 median_abs_dev: 4.4478000000,
976 median_abs_dev_pct: 8.8956000000,
977 quartiles: (44.0000000000,50.0000000000,52.0000000000),
978 iqr: 8.0000000000,
979 };
980 check(val, summ);
981 }
982 #[test]
983 fn test_unif25() {
984 let val = &[
985 99.0000000000,
986 55.0000000000,
987 92.0000000000,
988 79.0000000000,
989 14.0000000000,
990 2.0000000000,
991 33.0000000000,
992 49.0000000000,
993 3.0000000000,
994 32.0000000000,
995 84.0000000000,
996 59.0000000000,
997 22.0000000000,
998 86.0000000000,
999 76.0000000000,
1000 31.0000000000,
1001 29.0000000000,
1002 11.0000000000,
1003 41.0000000000,
1004 53.0000000000,
1005 45.0000000000,
1006 44.0000000000,
1007 98.0000000000,
1008 98.0000000000,
1009 7.0000000000,
1010 ];
1011 let summ = &Summary {
1012 sum: 1242.0000000000,
1013 min: 2.0000000000,
1014 max: 99.0000000000,
1015 mean: 49.6800000000,
1016 median: 45.0000000000,
1017 var: 1015.6433333333,
1018 std_dev: 31.8691595957,
1019 std_dev_pct: 64.1488719719,
1020 median_abs_dev: 45.9606000000,
1021 median_abs_dev_pct: 102.1346666667,
1022 quartiles: (29.0000000000,45.0000000000,79.0000000000),
1023 iqr: 50.0000000000,
1024 };
1025 check(val, summ);
1026 }
1027
1028 #[test]
1029 fn test_boxplot_nonpositive() {
1030 #[allow(deprecated_owned_vector)]
1031 fn t(s: &Summary<f64>, expected: ~str) {
1032 use std::io::MemWriter;
1033 let mut m = MemWriter::new();
1034 write_boxplot(&mut m as &mut io::Writer, s, 30).unwrap();
1035 let out = str::from_utf8(m.unwrap().as_slice()).unwrap().to_owned();
1036 assert_eq!(out, expected);
1037 }
1038
1039 t(&Summary::new([-2.0, -1.0]), "-2 |[------******#*****---]| -1".to_owned());
1040 t(&Summary::new([0.0, 2.0]), "0 |[-------*****#*******---]| 2".to_owned());
1041 t(&Summary::new([-2.0, 0.0]), "-2 |[------******#******---]| 0".to_owned());
1042
1043 }
1044 #[test]
1045 fn test_sum_f64s() {
1046 assert_eq!([0.5, 3.2321, 1.5678].sum(), 5.2999);
1047 }
1048 #[test]
1049 fn test_sum_f64_between_ints_that_sum_to_0() {
1050 assert_eq!([1e30, 1.2, -1e30].sum(), 1.2);
1051 }
1052 }
1053
1054 #[cfg(test)]
1055 mod bench {
1056 use Bencher;
1057 use stats::Stats;
1058
1059 #[bench]
1060 pub fn sum_three_items(b: &mut Bencher) {
1061 b.iter(|| {
1062 [1e20, 1.5, -1e20].sum();
1063 })
1064 }
1065 #[bench]
1066 pub fn sum_many_f64(b: &mut Bencher) {
1067 let nums = [-1e30, 1e60, 1e30, 1.0, -1e60];
1068 let v = Vec::from_fn(500, |i| nums[i%5]);
1069
1070 b.iter(|| {
1071 v.as_slice().sum();
1072 })
1073 }
1074 }
libtest/stats.rs:290:78-290:78 -fn- definition:
// linear interpolation. If samples are not sorted, return nonsensical value.
fn percentile_of_sorted<T: Float + FromPrimitive>(sorted_samples: &[T],
pct: T) -> T {
references:- 6273: let first = FromPrimitive::from_uint(25).unwrap();
274: let a = percentile_of_sorted(tmp.as_slice(), first);
275: let secound = FromPrimitive::from_uint(50).unwrap();
--
325: let hundred: T = FromPrimitive::from_uint(100).unwrap();
326: let hi = percentile_of_sorted(tmp.as_slice(), hundred-pct);
327: for samp in samples.mut_iter() {
libtest/stats.rs:35:1-35:1 -fn- definition:
fn local_sort<T: Float>(v: &mut [T]) {
v.sort_by(|x: &T, y: &T| local_cmp(*x, *y));
}
references:- 3271: let mut tmp = Vec::from_slice(self);
272: local_sort(tmp.as_mut_slice());
273: let first = FromPrimitive::from_uint(25).unwrap();
--
322: let mut tmp = Vec::from_slice(samples);
323: local_sort(tmp.as_mut_slice());
324: let lo = percentile_of_sorted(tmp.as_slice(), pct);
libtest/stats.rs:320:50-320:50 -fn- definition:
/// See: http://en.wikipedia.org/wiki/Winsorising
pub fn winsorize<T: Float + FromPrimitive>(samples: &mut [T], pct: T) {
let mut tmp = Vec::from_slice(samples);
references:- 2libtest/lib.rs:
1290: stats::winsorize(samples, 5.0);
1291: let summ5 = stats::Summary::new(samples);
libtest/stats.rs:130:22-130:22 -struct- definition:
pub struct Summary<T> {
pub sum: T,
pub min: T,
references:- 18149: pub fn new(samples: &[T]) -> Summary<T> {
150: Summary {
151: sum: samples.sum(),
--
361: w: &mut io::Writer,
362: s: &Summary<T>,
363: width_hint: uint)
libtest/lib.rs:
415: pub struct BenchSamples {
416: ns_iter_summ: stats::Summary<f64>,
417: mb_s: uint,
--
1251: // This is a more statistics-driven benchmark algorithm
1252: pub fn auto_bench(&mut self, f: |&mut Bencher|) -> stats::Summary<f64> {
libtest/stats.rs:
146: impl<T: Float + FromPrimitive> Summary<T> {