use crate::error::{DatarustError, Result};
use crate::matrix::{Matrix, StrMatrix};
pub trait Estimator {}
#[derive(Debug, Clone, PartialEq)]
pub enum ParamValue {
Float(f64),
Int(usize),
Bool(bool),
}
pub trait Params {
fn get_params(&self) -> Vec<(&'static str, ParamValue)>;
fn set_params(&mut self, name: &str, value: ParamValue) -> Result<()>;
}
pub trait Transformer: Estimator {
fn name(&self) -> &'static str;
fn fit(&mut self, x: &Matrix) -> Result<()>;
fn transform(&self, x: &Matrix) -> Result<Matrix>;
fn fit_transform(&mut self, x: &Matrix) -> Result<Matrix> {
self.fit(x)?;
self.transform(x)
}
fn fit_with_target(&mut self, x: &Matrix, _y: &[f64]) -> Result<()> {
self.fit(x)
}
fn inverse_transform(&self, _x: &Matrix) -> Result<Matrix> {
Err(DatarustError::InvalidInput(format!(
"{} does not support inverse_transform",
Transformer::name(self)
)))
}
fn is_fitted(&self) -> bool;
}
pub trait FeatureNames {
fn feature_names_out(&self, input_features: Option<&[String]>) -> Vec<String>;
}
pub fn default_input_names(n: usize) -> Vec<String> {
(0..n).map(|i| format!("x{}", i)).collect()
}
pub trait CategoricalTransformer: Estimator {
fn name(&self) -> &'static str;
fn fit(&mut self, x: &StrMatrix) -> Result<()>;
fn transform(&self, x: &StrMatrix) -> Result<Matrix>;
fn fit_transform(&mut self, x: &StrMatrix) -> Result<Matrix> {
self.fit(x)?;
self.transform(x)
}
fn inverse_transform(&self, _y: &Matrix) -> Result<StrMatrix> {
Err(DatarustError::InvalidInput(format!(
"{} does not support inverse_transform",
CategoricalTransformer::name(self)
)))
}
fn is_fitted(&self) -> bool;
}
pub trait TargetTransformer: Estimator {
fn name(&self) -> &'static str;
fn fit(&mut self, x: &StrMatrix, y: &[f64]) -> Result<()>;
fn transform(&self, x: &StrMatrix) -> Result<Matrix>;
fn fit_transform(&mut self, x: &StrMatrix, y: &[f64]) -> Result<Matrix> {
self.fit(x, y)?;
self.transform(x)
}
fn inverse_transform(&self, _y: &Matrix) -> Result<StrMatrix> {
Err(DatarustError::InvalidInput(format!(
"{} does not support inverse_transform",
TargetTransformer::name(self)
)))
}
fn is_fitted(&self) -> bool;
}
pub trait Predictor: Estimator {
fn fit(&mut self, x: &Matrix, y: &[f64]) -> Result<()>;
fn predict(&self, x: &Matrix) -> Result<Vec<f64>>;
fn fit_predict(&mut self, x: &Matrix, y: &[f64]) -> Result<Vec<f64>> {
self.fit(x, y)?;
self.predict(x)
}
fn is_fitted(&self) -> bool;
}
pub trait Regressor: Predictor {
fn name(&self) -> &'static str;
fn score(&self, x: &Matrix, y: &[f64]) -> Result<f64> {
let prediction = Predictor::predict(self, x)?;
crate::metrics::regression::r2_score(y, &prediction)
}
}
pub trait Classifier: Predictor {
fn score(&self, x: &Matrix, y: &[f64]) -> Result<f64> {
let prediction = self.predict(x)?;
crate::metrics::classification::accuracy_score(y, &prediction)
}
}
pub trait PredictProba: Classifier {
fn predict_proba(&self, x: &Matrix) -> Result<Matrix>;
}
pub trait LabelTransformer: Estimator {
fn name(&self) -> &'static str;
fn fit(&mut self, x: &[String]) -> Result<()>;
fn transform(&self, x: &[String]) -> Result<Vec<usize>>;
fn inverse_transform(&self, x: &[usize]) -> Result<Vec<String>>;
fn fit_transform(&mut self, x: &[String]) -> Result<Vec<usize>> {
self.fit(x)?;
self.transform(x)
}
fn is_fitted(&self) -> bool;
}
pub trait Clusterer: Estimator {
fn name(&self) -> &'static str;
fn fit(&mut self, x: &Matrix) -> Result<()>;
fn predict(&self, x: &Matrix) -> Result<Vec<usize>>;
fn fit_predict(&mut self, x: &Matrix) -> Result<Vec<usize>> {
self.fit(x)?;
self.predict(x)
}
fn fit_transform(&mut self, x: &Matrix) -> Result<Matrix> {
let labels = self.fit_predict(x)?;
let k = self.n_clusters();
let n = x.nrows();
let mut data = vec![0.0; n * k];
for (i, &label) in labels.iter().enumerate() {
data[i * k + label] = 1.0;
}
Matrix::from_flat(n, k, data)
}
fn n_clusters(&self) -> usize;
fn is_fitted(&self) -> bool;
}
macro_rules! impl_estimator_from_transformer {
($($ty:path),+ $(,)?) => {
$(
impl Estimator for $ty {}
)+
};
}
impl_estimator_from_transformer!(
crate::scaler::StandardScaler,
crate::scaler::MinMaxScaler,
crate::scaler::MaxAbsScaler,
crate::scaler::RobustScaler,
crate::scaler::Normalizer,
crate::scaler::Binarizer,
crate::scaler::KBinsDiscretizer,
crate::scaler::QuantileTransformer,
crate::scaler::PowerTransformer,
crate::polynomial::PolynomialFeatures,
crate::selection::VarianceThreshold,
crate::selection::SelectKBest,
crate::decomposition::PCA,
crate::decomposition::TruncatedSVD,
crate::imputer::SimpleImputer,
crate::imputer::KnnImputer,
crate::function_transformer::FunctionTransformer,
crate::transformer_kind::TransformerKind,
crate::pipeline::Pipeline,
);
macro_rules! impl_estimator_from_categorical_transformer {
($($ty:path),+ $(,)?) => {
$(
impl Estimator for $ty {}
)+
};
}
impl_estimator_from_categorical_transformer!(
crate::encoder::OneHotEncoder,
crate::encoder::OrdinalEncoder,
crate::encoder::FrequencyEncoder,
crate::categorical_kind::CategoricalTransformerKind,
);
macro_rules! impl_estimator_from_target_transformer {
($($ty:path),+ $(,)?) => {
$(
impl Estimator for $ty {}
)+
};
}
impl_estimator_from_target_transformer!(
crate::encoder::TargetEncoder,
crate::target_kind::TargetTransformerKind,
);
impl Estimator for crate::encoder::LabelEncoder {}
macro_rules! impl_estimator_from_clusterer {
($($ty:path),+ $(,)?) => {
$(
impl Estimator for $ty {}
)+
};
}
impl_estimator_from_clusterer!(crate::cluster::KMeans,);