aboutsummaryrefslogtreecommitdiff
path: root/src/estimate.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/estimate.rs')
-rwxr-xr-xsrc/estimate.rs184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/estimate.rs b/src/estimate.rs
new file mode 100755
index 0000000..8a79d27
--- /dev/null
+++ b/src/estimate.rs
@@ -0,0 +1,184 @@
+use std::fmt;
+
+use crate::stats::Distribution;
+
+#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize, Debug)]
+pub enum Statistic {
+ Mean,
+ Median,
+ MedianAbsDev,
+ Slope,
+ StdDev,
+ Typical,
+}
+
+impl fmt::Display for Statistic {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ Statistic::Mean => f.pad("mean"),
+ Statistic::Median => f.pad("median"),
+ Statistic::MedianAbsDev => f.pad("MAD"),
+ Statistic::Slope => f.pad("slope"),
+ Statistic::StdDev => f.pad("SD"),
+ Statistic::Typical => f.pad("typical"),
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Deserialize, Serialize, Debug)]
+pub struct ConfidenceInterval {
+ pub confidence_level: f64,
+ pub lower_bound: f64,
+ pub upper_bound: f64,
+}
+
+#[derive(Clone, PartialEq, Deserialize, Serialize, Debug)]
+pub struct Estimate {
+ /// The confidence interval for this estimate
+ pub confidence_interval: ConfidenceInterval,
+ ///
+ pub point_estimate: f64,
+ /// The standard error of this estimate
+ pub standard_error: f64,
+}
+
+pub fn build_estimates(
+ distributions: &Distributions,
+ points: &PointEstimates,
+ cl: f64,
+) -> Estimates {
+ let to_estimate = |point_estimate, distribution: &Distribution<f64>| {
+ let (lb, ub) = distribution.confidence_interval(cl);
+
+ Estimate {
+ confidence_interval: ConfidenceInterval {
+ confidence_level: cl,
+ lower_bound: lb,
+ upper_bound: ub,
+ },
+ point_estimate,
+ standard_error: distribution.std_dev(None),
+ }
+ };
+
+ Estimates {
+ mean: to_estimate(points.mean, &distributions.mean),
+ median: to_estimate(points.median, &distributions.median),
+ median_abs_dev: to_estimate(points.median_abs_dev, &distributions.median_abs_dev),
+ slope: None,
+ std_dev: to_estimate(points.std_dev, &distributions.std_dev),
+ }
+}
+
+pub fn build_change_estimates(
+ distributions: &ChangeDistributions,
+ points: &ChangePointEstimates,
+ cl: f64,
+) -> ChangeEstimates {
+ let to_estimate = |point_estimate, distribution: &Distribution<f64>| {
+ let (lb, ub) = distribution.confidence_interval(cl);
+
+ Estimate {
+ confidence_interval: ConfidenceInterval {
+ confidence_level: cl,
+ lower_bound: lb,
+ upper_bound: ub,
+ },
+ point_estimate,
+ standard_error: distribution.std_dev(None),
+ }
+ };
+
+ ChangeEstimates {
+ mean: to_estimate(points.mean, &distributions.mean),
+ median: to_estimate(points.median, &distributions.median),
+ }
+}
+
+pub struct PointEstimates {
+ pub mean: f64,
+ pub median: f64,
+ pub median_abs_dev: f64,
+ pub std_dev: f64,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct Estimates {
+ pub mean: Estimate,
+ pub median: Estimate,
+ pub median_abs_dev: Estimate,
+ pub slope: Option<Estimate>,
+ pub std_dev: Estimate,
+}
+impl Estimates {
+ pub fn typical(&self) -> &Estimate {
+ self.slope.as_ref().unwrap_or(&self.mean)
+ }
+ pub fn get(&self, stat: Statistic) -> Option<&Estimate> {
+ match stat {
+ Statistic::Mean => Some(&self.mean),
+ Statistic::Median => Some(&self.median),
+ Statistic::MedianAbsDev => Some(&self.median_abs_dev),
+ Statistic::Slope => self.slope.as_ref(),
+ Statistic::StdDev => Some(&self.std_dev),
+ Statistic::Typical => Some(self.typical()),
+ }
+ }
+}
+
+pub struct Distributions {
+ pub mean: Distribution<f64>,
+ pub median: Distribution<f64>,
+ pub median_abs_dev: Distribution<f64>,
+ pub slope: Option<Distribution<f64>>,
+ pub std_dev: Distribution<f64>,
+}
+impl Distributions {
+ pub fn typical(&self) -> &Distribution<f64> {
+ self.slope.as_ref().unwrap_or(&self.mean)
+ }
+ pub fn get(&self, stat: Statistic) -> Option<&Distribution<f64>> {
+ match stat {
+ Statistic::Mean => Some(&self.mean),
+ Statistic::Median => Some(&self.median),
+ Statistic::MedianAbsDev => Some(&self.median_abs_dev),
+ Statistic::Slope => self.slope.as_ref(),
+ Statistic::StdDev => Some(&self.std_dev),
+ Statistic::Typical => Some(self.typical()),
+ }
+ }
+}
+
+pub struct ChangePointEstimates {
+ pub mean: f64,
+ pub median: f64,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct ChangeEstimates {
+ pub mean: Estimate,
+ pub median: Estimate,
+}
+impl ChangeEstimates {
+ pub fn get(&self, stat: Statistic) -> &Estimate {
+ match stat {
+ Statistic::Mean => &self.mean,
+ Statistic::Median => &self.median,
+ _ => panic!("Unexpected statistic"),
+ }
+ }
+}
+
+pub struct ChangeDistributions {
+ pub mean: Distribution<f64>,
+ pub median: Distribution<f64>,
+}
+impl ChangeDistributions {
+ pub fn get(&self, stat: Statistic) -> &Distribution<f64> {
+ match stat {
+ Statistic::Mean => &self.mean,
+ Statistic::Median => &self.median,
+ _ => panic!("Unexpected statistic"),
+ }
+ }
+}