mod error;
mod exp;
pub mod interpolate;
mod power;
mod scale;
use std::fmt;
use augurs_core::Forecast;
pub use error::Error;
pub use exp::{Log, Logit};
pub use interpolate::{InterpolateExt, LinearInterpolator};
pub use power::{BoxCox, YeoJohnson};
pub use scale::{MinMaxScaler, StandardScaleParams, StandardScaler};
#[derive(Debug, Default)]
pub struct Pipeline {
transformers: Vec<Box<dyn Transformer>>,
is_fitted: bool,
}
impl Pipeline {
pub fn new(transformers: Vec<Box<dyn Transformer>>) -> Self {
Self {
transformers,
is_fitted: false,
}
}
pub fn is_fitted(&self) -> bool {
self.is_fitted
}
fn fit_transform_inner(&mut self, input: &mut [f64]) -> Result<(), Error> {
for t in self.transformers.iter_mut() {
t.fit_transform(input)?;
}
self.is_fitted = true;
Ok(())
}
pub(crate) fn inverse_transform_forecast(&self, forecast: &mut Forecast) -> Result<(), Error> {
for t in self.transformers.iter().rev() {
t.inverse_transform(&mut forecast.point)?;
if let Some(intervals) = forecast.intervals.as_mut() {
t.inverse_transform(&mut intervals.lower)?;
t.inverse_transform(&mut intervals.upper)?;
}
}
Ok(())
}
}
impl Transformer for Pipeline {
fn fit(&mut self, input: &[f64]) -> Result<(), Error> {
if self.transformers.is_empty() {
return Ok(());
}
let mut input = input.to_vec();
self.fit_transform_inner(&mut input)?;
Ok(())
}
fn fit_transform(&mut self, input: &mut [f64]) -> Result<(), Error> {
self.fit_transform_inner(input)?;
Ok(())
}
fn transform(&self, input: &mut [f64]) -> Result<(), Error> {
for t in self.transformers.iter() {
t.transform(input)?;
}
Ok(())
}
fn inverse_transform(&self, input: &mut [f64]) -> Result<(), Error> {
for t in self.transformers.iter().rev() {
t.inverse_transform(input)?;
}
Ok(())
}
}
pub trait Transformer: fmt::Debug + Sync + Send {
fn fit(&mut self, data: &[f64]) -> Result<(), Error>;
fn transform(&self, data: &mut [f64]) -> Result<(), Error>;
fn inverse_transform(&self, data: &mut [f64]) -> Result<(), Error>;
fn fit_transform(&mut self, data: &mut [f64]) -> Result<(), Error> {
self.fit(data)?;
self.transform(data)?;
Ok(())
}
fn boxed(self) -> Box<dyn Transformer>
where
Self: Sized + 'static,
{
Box::new(self)
}
}