1 | //! Univariate analysis |
2 | |
3 | mod bootstrap; |
4 | mod percentiles; |
5 | mod resamples; |
6 | mod sample; |
7 | |
8 | pub mod kde; |
9 | pub mod mixed; |
10 | pub mod outliers; |
11 | |
12 | use crate::stats::float::Float; |
13 | use crate::stats::tuple::{Tuple, TupledDistributionsBuilder}; |
14 | #[cfg (feature = "rayon" )] |
15 | use rayon::prelude::*; |
16 | use std::cmp; |
17 | |
18 | use self::resamples::Resamples; |
19 | |
20 | pub use self::percentiles::Percentiles; |
21 | pub use self::sample::Sample; |
22 | |
23 | /// Performs a two-sample bootstrap |
24 | /// |
25 | /// - Multithreaded |
26 | /// - Time: `O(nresamples)` |
27 | /// - Memory: `O(nresamples)` |
28 | #[cfg_attr (feature = "cargo-clippy" , allow(clippy::cast_lossless))] |
29 | pub fn bootstrap<A, B, T, S>( |
30 | a: &Sample<A>, |
31 | b: &Sample<B>, |
32 | nresamples: usize, |
33 | statistic: S, |
34 | ) -> T::Distributions |
35 | where |
36 | A: Float, |
37 | B: Float, |
38 | S: Fn(&Sample<A>, &Sample<B>) -> T + Sync, |
39 | T: Tuple + Send, |
40 | T::Distributions: Send, |
41 | T::Builder: Send, |
42 | { |
43 | let nresamples_sqrt = (nresamples as f64).sqrt().ceil() as usize; |
44 | let per_chunk = (nresamples + nresamples_sqrt - 1) / nresamples_sqrt; |
45 | |
46 | #[cfg (feature = "rayon" )] |
47 | { |
48 | (0..nresamples_sqrt) |
49 | .into_par_iter() |
50 | .map_init( |
51 | || (Resamples::new(a), Resamples::new(b)), |
52 | |(a_resamples, b_resamples), i| { |
53 | let start = i * per_chunk; |
54 | let end = cmp::min((i + 1) * per_chunk, nresamples); |
55 | let a_resample = a_resamples.next(); |
56 | |
57 | let mut sub_distributions: T::Builder = |
58 | TupledDistributionsBuilder::new(end - start); |
59 | |
60 | for _ in start..end { |
61 | let b_resample = b_resamples.next(); |
62 | sub_distributions.push(statistic(a_resample, b_resample)); |
63 | } |
64 | sub_distributions |
65 | }, |
66 | ) |
67 | .reduce( |
68 | || T::Builder::new(0), |
69 | |mut a, mut b| { |
70 | a.extend(&mut b); |
71 | a |
72 | }, |
73 | ) |
74 | .complete() |
75 | } |
76 | #[cfg (not(feature = "rayon" ))] |
77 | { |
78 | let mut a_resamples = Resamples::new(a); |
79 | let mut b_resamples = Resamples::new(b); |
80 | (0..nresamples_sqrt) |
81 | .map(|i| { |
82 | let start = i * per_chunk; |
83 | let end = cmp::min((i + 1) * per_chunk, nresamples); |
84 | let a_resample = a_resamples.next(); |
85 | |
86 | let mut sub_distributions: T::Builder = |
87 | TupledDistributionsBuilder::new(end - start); |
88 | |
89 | for _ in start..end { |
90 | let b_resample = b_resamples.next(); |
91 | sub_distributions.push(statistic(a_resample, b_resample)); |
92 | } |
93 | sub_distributions |
94 | }) |
95 | .fold(T::Builder::new(0), |mut a, mut b| { |
96 | a.extend(&mut b); |
97 | a |
98 | }) |
99 | .complete() |
100 | } |
101 | } |
102 | |