radiate-gp 1.3.1

Extensions for radiate. Genetic Programming implementations for graphs (neural networks) and trees.
Documentation
use radiate_core::random_provider;
use radiate_utils::{Float, Matrix};

#[derive(Default, Clone)]
pub struct DataSet<T> {
    features: Matrix<T>,
    labels: Matrix<T>,
}

impl<T> DataSet<T> {
    pub fn new(inputs: Vec<Vec<T>>, outputs: Vec<Vec<T>>) -> Self {
        let features = Matrix::from(inputs);
        let labels = Matrix::from(outputs);

        DataSet { features, labels }
    }

    pub fn iter(&self) -> impl Iterator<Item = (&[T], &[T])> {
        self.features.iter().zip(self.labels.iter())
    }

    pub fn len(&self) -> usize {
        self.features.rows()
    }

    pub fn is_empty(&self) -> bool {
        self.features.is_empty()
    }

    pub fn shape(&self) -> (usize, usize, usize) {
        let num_samples = self.features.rows();
        let input_dim = if num_samples > 0 {
            self.features.cols()
        } else {
            0
        };
        let output_dim = if num_samples > 0 {
            self.labels.cols()
        } else {
            0
        };

        (num_samples, input_dim, output_dim)
    }

    pub fn append(mut self, features: Vec<T>, labels: Vec<T>) -> Self {
        self.features.append_row(features);
        self.labels.append_row(labels);
        self
    }
}

impl<T: Clone> DataSet<T> {
    #[inline]
    pub fn features(&self) -> Vec<Vec<T>> {
        (0..self.features.rows())
            .map(|i| self.features.row(i).to_vec())
            .collect()
    }

    #[inline]
    pub fn labels(&self) -> Vec<Vec<T>> {
        (0..self.labels.rows())
            .map(|i| self.labels.row(i).to_vec())
            .collect()
    }

    pub fn shuffle(self) -> Self {
        let mut indices: Vec<usize> = (0..self.len()).collect();
        random_provider::shuffle(&mut indices);

        let features = self.features.sort_by_indices(&indices);
        let labels = self.labels.sort_by_indices(&indices);

        DataSet { features, labels }
    }

    #[inline]
    pub fn split(self, ratio: f32) -> (Self, Self) {
        let ratio = ratio.clamp(0.0, 1.0);
        let split = (self.len() as f32 * ratio).round() as usize;
        let (features_left, features_right) = self.features.split_at_row(split);
        let (labels_left, labels_right) = self.labels.split_at_row(split);

        (
            DataSet {
                features: features_left,
                labels: labels_left,
            },
            DataSet {
                features: features_right,
                labels: labels_right,
            },
        )
    }
}

impl<F: Float> DataSet<F> {
    pub fn standardize(mut self) -> Self {
        self.features.standardize();
        self
    }

    pub fn normalize(mut self) -> Self {
        self.features.normalize();
        self
    }
}

impl<T> From<(Vec<Vec<T>>, Vec<Vec<T>>)> for DataSet<T> {
    fn from(data: (Vec<Vec<T>>, Vec<Vec<T>>)) -> Self {
        DataSet::new(data.0, data.1)
    }
}

impl<T> From<(Matrix<T>, Matrix<T>)> for DataSet<T> {
    fn from(data: (Matrix<T>, Matrix<T>)) -> Self {
        DataSet {
            features: data.0,
            labels: data.1,
        }
    }
}