use crate::error::Error;
use crate::machine_learning::{
DBSCAN, DecisionTree, IsolationForest, KMeans, KNN, LDA, LinearRegression, LinearSVC,
LogisticRegression, MeanShift, SVC,
};
use ndarray::{Array1, ArrayBase, Data, Ix1, Ix2};
use std::hash::Hash;
pub trait Fit<D> {
fn fit(&mut self, data: D) -> Result<&mut Self, Error>;
}
pub trait Predict<X> {
type Output;
fn predict(&self, input: X) -> Result<Self::Output, Error>;
}
impl<'a, S> Fit<(&'a ArrayBase<S, Ix2>, &'a ArrayBase<S, Ix1>)> for LinearRegression
where
S: Data<Elem = f64>,
{
fn fit(
&mut self,
data: (&'a ArrayBase<S, Ix2>, &'a ArrayBase<S, Ix1>),
) -> Result<&mut Self, Error> {
let (x, y) = data;
self.fit(x, y)
}
}
impl<'a, S> Fit<(&'a ArrayBase<S, Ix2>, &'a ArrayBase<S, Ix1>)> for LogisticRegression
where
S: Data<Elem = f64>,
{
fn fit(
&mut self,
data: (&'a ArrayBase<S, Ix2>, &'a ArrayBase<S, Ix1>),
) -> Result<&mut Self, Error> {
let (x, y) = data;
self.fit(x, y)
}
}
impl<'a, S> Fit<(&'a ArrayBase<S, Ix2>, &'a ArrayBase<S, Ix1>)> for DecisionTree
where
S: Data<Elem = f64> + Send + Sync,
{
fn fit(
&mut self,
data: (&'a ArrayBase<S, Ix2>, &'a ArrayBase<S, Ix1>),
) -> Result<&mut Self, Error> {
let (x, y) = data;
self.fit(x, y)
}
}
impl<'a, S> Fit<(&'a ArrayBase<S, Ix2>, &'a ArrayBase<S, Ix1>)> for LinearSVC
where
S: Data<Elem = f64> + Send + Sync,
{
fn fit(
&mut self,
data: (&'a ArrayBase<S, Ix2>, &'a ArrayBase<S, Ix1>),
) -> Result<&mut Self, Error> {
let (x, y) = data;
self.fit(x, y)
}
}
impl<'a, S> Fit<(&'a ArrayBase<S, Ix2>, &'a ArrayBase<S, Ix1>)> for SVC
where
S: Data<Elem = f64> + Send + Sync,
{
fn fit(
&mut self,
data: (&'a ArrayBase<S, Ix2>, &'a ArrayBase<S, Ix1>),
) -> Result<&mut Self, Error> {
let (x, y) = data;
self.fit(x, y)
}
}
impl<'a, T, S1, S2> Fit<(&'a ArrayBase<S1, Ix2>, &'a ArrayBase<S2, Ix1>)> for KNN<T>
where
T: Clone + Hash + Eq,
S1: Data<Elem = f64>,
S2: Data<Elem = T>,
{
fn fit(
&mut self,
data: (&'a ArrayBase<S1, Ix2>, &'a ArrayBase<S2, Ix1>),
) -> Result<&mut Self, Error> {
let (x, y) = data;
self.fit(x, y)
}
}
impl<'a, S1, S2> Fit<(&'a ArrayBase<S1, Ix2>, &'a ArrayBase<S2, Ix1>)> for LDA
where
S1: Data<Elem = f64>,
S2: Data<Elem = i32>,
{
fn fit(
&mut self,
data: (&'a ArrayBase<S1, Ix2>, &'a ArrayBase<S2, Ix1>),
) -> Result<&mut Self, Error> {
let (x, y) = data;
self.fit(x, y)
}
}
impl<'a, S> Fit<&'a ArrayBase<S, Ix2>> for KMeans
where
S: Data<Elem = f64>,
{
fn fit(&mut self, data: &'a ArrayBase<S, Ix2>) -> Result<&mut Self, Error> {
self.fit(data)
}
}
impl<'a, S> Fit<&'a ArrayBase<S, Ix2>> for DBSCAN
where
S: Data<Elem = f64> + Send + Sync,
{
fn fit(&mut self, data: &'a ArrayBase<S, Ix2>) -> Result<&mut Self, Error> {
self.fit(data)
}
}
impl<'a, S> Fit<&'a ArrayBase<S, Ix2>> for MeanShift
where
S: Data<Elem = f64> + Send + Sync,
{
fn fit(&mut self, data: &'a ArrayBase<S, Ix2>) -> Result<&mut Self, Error> {
self.fit(data)
}
}
impl<'a, S> Fit<&'a ArrayBase<S, Ix2>> for IsolationForest
where
S: Data<Elem = f64> + Send + Sync,
{
fn fit(&mut self, data: &'a ArrayBase<S, Ix2>) -> Result<&mut Self, Error> {
self.fit(data)
}
}
impl<'a, S> Predict<&'a ArrayBase<S, Ix2>> for LinearRegression
where
S: Data<Elem = f64>,
{
type Output = Array1<f64>;
fn predict(&self, input: &'a ArrayBase<S, Ix2>) -> Result<Self::Output, Error> {
self.predict(input)
}
}
impl<'a, S> Predict<&'a ArrayBase<S, Ix2>> for LogisticRegression
where
S: Data<Elem = f64>,
{
type Output = Array1<i32>;
fn predict(&self, input: &'a ArrayBase<S, Ix2>) -> Result<Self::Output, Error> {
self.predict(input)
}
}
impl<'a, S> Predict<&'a ArrayBase<S, Ix2>> for DecisionTree
where
S: Data<Elem = f64> + Send + Sync,
{
type Output = Array1<f64>;
fn predict(&self, input: &'a ArrayBase<S, Ix2>) -> Result<Self::Output, Error> {
self.predict(input)
}
}
impl<'a, S> Predict<&'a ArrayBase<S, Ix2>> for LinearSVC
where
S: Data<Elem = f64>,
{
type Output = Array1<f64>;
fn predict(&self, input: &'a ArrayBase<S, Ix2>) -> Result<Self::Output, Error> {
self.predict(input)
}
}
impl<'a, S> Predict<&'a ArrayBase<S, Ix2>> for SVC
where
S: Data<Elem = f64> + Send + Sync,
{
type Output = Array1<f64>;
fn predict(&self, input: &'a ArrayBase<S, Ix2>) -> Result<Self::Output, Error> {
self.predict(input)
}
}
impl<'a, S> Predict<&'a ArrayBase<S, Ix2>> for KMeans
where
S: Data<Elem = f64>,
{
type Output = Array1<usize>;
fn predict(&self, input: &'a ArrayBase<S, Ix2>) -> Result<Self::Output, Error> {
self.predict(input)
}
}
impl<'a, S> Predict<&'a ArrayBase<S, Ix2>> for MeanShift
where
S: Data<Elem = f64> + Sync,
{
type Output = Array1<usize>;
fn predict(&self, input: &'a ArrayBase<S, Ix2>) -> Result<Self::Output, Error> {
self.predict(input)
}
}
impl<'a, S> Predict<&'a ArrayBase<S, Ix2>> for IsolationForest
where
S: Data<Elem = f64>,
{
type Output = Array1<f64>;
fn predict(&self, input: &'a ArrayBase<S, Ix2>) -> Result<Self::Output, Error> {
self.predict(input)
}
}
impl<'a, T, S> Predict<&'a ArrayBase<S, Ix2>> for KNN<T>
where
T: Clone + Hash + Eq,
S: Data<Elem = f64>,
{
type Output = Array1<T>;
fn predict(&self, input: &'a ArrayBase<S, Ix2>) -> Result<Self::Output, Error> {
self.predict(input)
}
}
impl<'a, S> Predict<&'a ArrayBase<S, Ix2>> for LDA
where
S: Data<Elem = f64>,
{
type Output = Array1<i32>;
fn predict(&self, input: &'a ArrayBase<S, Ix2>) -> Result<Self::Output, Error> {
self.predict(input)
}
}
impl<'a, S> Predict<&'a ArrayBase<S, Ix2>> for DBSCAN
where
S: Data<Elem = f64> + Send + Sync,
{
type Output = Array1<isize>;
fn predict(&self, input: &'a ArrayBase<S, Ix2>) -> Result<Self::Output, Error> {
self.predict(input)
}
}
#[cfg(test)]
mod tests {
use super::*;
use ndarray::{Array1, Array2};
#[test]
fn fit_and_predict_through_traits() {
let x = Array2::from_shape_vec((3, 1), vec![1.0, 2.0, 3.0]).unwrap();
let y = Array1::from_vec(vec![2.0, 4.0, 6.0]);
let mut model = LinearRegression::new(true, 0.05, 5000, 1e-9).unwrap();
Fit::fit(&mut model, (&x, &y)).unwrap();
let preds = Predict::predict(&model, &x).unwrap();
assert_eq!(preds.len(), 3);
for (p, t) in preds.iter().zip(y.iter()) {
assert!((p - t).abs() < 0.5);
}
}
}