<filename>cross_validation/data_splitters.py
#!/usr/bin/env python3

"""
Provides the class DataSplitter, which handles how data to be cross validated
is split into training and testing data sets.

The DataSplitter class is an abstract base class that defines the interface
that all data splitters should provide. Exemplar data splitters inheriting from
DataSplitter are included here for convenience and as a reference.
"""

from __future__ import print_function, division

from abc import ABC, abstractmethod


__all__ = [
    'DataSplitter',
    'SingleFold',
    'LeaveOneOut',
    'LeaveOneIn',
]


class DataSplitter(ABC):
    """
    Defines a data splitter: an object that takes parameters of the data being
    cross-validated and produces an iterable of training and testing dataset
    pairs, to be used as training and testing data in each fold of the
    cross-validation loop.

    An object of this class should satisfy two properties:
    1. It should be iterable, producing a tuple of the format
       ``(training_indices, test_indices)``. training_indices and test_indices
       will be used *only* for indexing an array, and so could be a list, an
       array or even a slice or an IndexExpression.
    2. It should provide a property called ``num_folds``, which is the number
       of folds the cross validation loop must iterate over.

    The data splitter can take any number of parameters for initialization, in
    order to figure out how to spit the data's indices. Chief among these might
    be the total number of data points being used for cross-validation, the
    number of folds desired and/or the explicit number of training and testing
    data points in each fold.
    """

    @property
    @abstractmethod
    def num_folds(self):
        raise NotImplementedError

    @abstractmethod
    def __iter__(self): #pragma: no cover
        while False:
            yield None


class SingleFold(DataSplitter):
    """
    The simplest data splitter. Creates a single fold by splitting the data
    into a training set and a testing set.

    Parameters
    ----------
    data_size: integer
        Total number of data points being used for cross validation
    training_size: integer
        Number of training points. Should be at most data_size - 1
    """

    def __init__(self, data_size, training_size):
        self._data_size = data_size
        self._training_size = training_size

    @property
    def num_folds(self):
        return 1

    def __iter__(self):
        yield (slice(self._training_size),
               slice(self._training_size, self._data_size))


class KFold(DataSplitter):
    """
    Data splitter for K-fold cross validation. Creates K folds by partitioning
    the data into K parts, each with roughly the same number of elements. In
    each fold, the training set consists of all but one partition, which is
    reserved for testing. The test partition iterates over folds.

    Parameters
    ----------
    data_size: integer
        Total number of data points being used for cross validation
    K: integer
        Number of folds desired
    randomize: boolean (optional)
        Decides whether or not index sets are to be randomized (default: False)
    """

    def __init__(self, data_size, K, randomize=False):
        self._data_size = data_size
        self._K = K

        self._num_per_fold = data_size // K
        self._num_extra = data_size % K

        if randomize:
            import numpy as np
            self._indices = list(np.random.permutation(data_size))
        else:
            self._indices = list(range(data_size))

    @property
    def num_folds(self):
        return self._K

    def __iter__(self):
        for i in range(self._K):
            if i < self._num_extra:
                yield (self._indices[: i*(self._num_per_fold + 1)]
                       + self._indices[(i + 1)*(self._num_per_fold + 1) :],
                       self._indices[i*(self._num_per_fold + 1)
                                     : (i + 1)*(self._num_per_fold + 1)])
            else:
                yield (self._indices[: i*self._num_per_fold + self._num_extra]
                       + self._indices[((i + 1)*self._num_per_fold
                                        + self._num_extra) :],
                       self._indices[(i*self._num_per_fold + self._num_extra)
                                     : ((i + 1)*self._num_per_fold
                                        + self._num_extra)])


class LeaveOneOut(DataSplitter):
    """
    Defines a data splitter that uses all but one of the data elements as
    training data and uses the remaining one element as testing data. Folds are
    generated by choosing which testing element is left out. Consequently, the
    number of folds is equal to the total number of data points used for
    cross validation.

    Parameters
    ----------
    data_size: integer
        Total number of data points being used for cross validation
    """

    def __init__(self, data_size):
        self._data_size = data_size

    @property
    def num_folds(self):
        return self._data_size

    def __iter__(self):
        for i in range(self._data_size):
            yield ([j for j in range(self._data_size) if j != i], [i, ])


class LeaveOneIn(DataSplitter):
    """
    The opposite of leave-one-out cross validation. Uses one training point
    and all the remaining data points as testing points.

    Parameters
    ----------
    data_size: integer
        Total number of data points being used for cross validation

    See Also
    --------
    LeaveOneOut
    """

    def __init__(self, data_size):
        self._data_size = data_size

    @property
    def num_folds(self):
        return self._data_size

    def __iter__(self):
        for i in range(self._data_size):
            yield ([i, ], [j for j in range(self._data_size) if j != i])

<filename>cross_validation/data_splitters.py
#!/usr/bin/env python3

"""
Provides the class DataSplitter, which handles how data to be cross validated
is split into training and testing data sets.

The DataSplitter class is an abstract base class that defines the interface
that all data splitters should provide. Exemplar data splitters inheriting from
DataSplitter are included here for convenience and as a reference.
"""

from __future__ import print_function, division

from abc import ABC, abstractmethod


__all__ = [
    'DataSplitter',
    'SingleFold',
    'LeaveOneOut',
    'LeaveOneIn',
]


class DataSplitter(ABC):
    """
    Defines a data splitter: an object that takes parameters of the data being
    cross-validated and produces an iterable of training and testing dataset
    pairs, to be used as training and testing data in each fold of the
    cross-validation loop.

    An object of this class should satisfy two properties:
    1. It should be iterable, producing a tuple of the format
       ``(training_indices, test_indices)``. training_indices and test_indices
       will be used *only* for indexing an array, and so could be a list, an
       array or even a slice or an IndexExpression.
    2. It should provide a property called ``num_folds``, which is the number
       of folds the cross validation loop must iterate over.

    The data splitter can take any number of parameters for initialization, in
    order to figure out how to spit the data's indices. Chief among these might
    be the total number of data points being used for cross-validation, the
    number of folds desired and/or the explicit number of training and testing
    data points in each fold.
    """

    @property
    @abstractmethod
    def num_folds(self):
        raise NotImplementedError

    @abstractmethod
    def __iter__(self): #pragma: no cover
        while False:
            yield None


class SingleFold(DataSplitter):
    """
    The simplest data splitter. Creates a single fold by splitting the data
    into a training set and a testing set.

    Parameters
    ----------
    data_size: integer
        Total number of data points being used for cross validation
    training_size: integer
        Number of training points. Should be at most data_size - 1
    """

    def __init__(self, data_size, training_size):
        self._data_size = data_size
        self._training_size = training_size

    @property
    def num_folds(self):
        return 1

    def __iter__(self):
        yield (slice(self._training_size),
               slice(self._training_size, self._data_size))


class KFold(DataSplitter):
    """
    Data splitter for K-fold cross validation. Creates K folds by partitioning
    the data into K parts, each with roughly the same number of elements. In
    each fold, the training set consists of all but one partition, which is
    reserved for testing. The test partition iterates over folds.

    Parameters
    ----------
    data_size: integer
        Total number of data points being used for cross validation
    K: integer
        Number of folds desired
    randomize: boolean (optional)
        Decides whether or not index sets are to be randomized (default: False)
    """

    def __init__(self, data_size, K, randomize=False):
        self._data_size = data_size
        self._K = K

        self._num_per_fold = data_size // K
        self._num_extra = data_size % K

        if randomize:
            import numpy as np
            self._indices = list(np.random.permutation(data_size))
        else:
            self._indices = list(range(data_size))

    @property
    def num_folds(self):
        return self._K

    def __iter__(self):
        for i in range(self._K):
            if i < self._num_extra:
                yield (self._indices[: i*(self._num_per_fold + 1)]
                       + self._indices[(i + 1)*(self._num_per_fold + 1) :],
                       self._indices[i*(self._num_per_fold + 1)
                                     : (i + 1)*(self._num_per_fold + 1)])
            else:
                yield (self._indices[: i*self._num_per_fold + self._num_extra]
                       + self._indices[((i + 1)*self._num_per_fold
                                        + self._num_extra) :],
                       self._indices[(i*self._num_per_fold + self._num_extra)
                                     : ((i + 1)*self._num_per_fold
                                        + self._num_extra)])


class LeaveOneOut(DataSplitter):
    """
    Defines a data splitter that uses all but one of the data elements as
    training data and uses the remaining one element as testing data. Folds are
    generated by choosing which testing element is left out. Consequently, the
    number of folds is equal to the total number of data points used for
    cross validation.

    Parameters
    ----------
    data_size: integer
        Total number of data points being used for cross validation
    """

    def __init__(self, data_size):
        self._data_size = data_size

    @property
    def num_folds(self):
        return self._data_size

    def __iter__(self):
        for i in range(self._data_size):
            yield ([j for j in range(self._data_size) if j != i], [i, ])


class LeaveOneIn(DataSplitter):
    """
    The opposite of leave-one-out cross validation. Uses one training point
    and all the remaining data points as testing points.

    Parameters
    ----------
    data_size: integer
        Total number of data points being used for cross validation

    See Also
    --------
    LeaveOneOut
    """

    def __init__(self, data_size):
        self._data_size = data_size

    @property
    def num_folds(self):
        return self._data_size

    def __iter__(self):
        for i in range(self._data_size):
            yield ([i, ], [j for j in range(self._data_size) if j != i])

#!/usr/bin/env python3 Provides the class DataSplitter, which handles how data to be cross validated is split into training and testing data sets.  The DataSplitter class is an abstract base class that defines the interface that all data splitters should provide. Exemplar data splitters inheriting from DataSplitter are included here for convenience and as a reference. Defines a data splitter: an object that takes parameters of the data being     cross-validated and produces an iterable of training and testing dataset     pairs, to be used as training and testing data in each fold of the     cross-validation loop.      An object of this class should satisfy two properties:     1. It should be iterable, producing a tuple of the format        ``(training_indices, test_indices)``. training_indices and test_indices        will be used *only* for indexing an array, and so could be a list, an        array or even a slice or an IndexExpression.     2. It should provide a property called ``num_folds``, which is the number        of folds the cross validation loop must iterate over.      The data splitter can take any number of parameters for initialization, in     order to figure out how to spit the data's indices. Chief among these might     be the total number of data points being used for cross-validation, the     number of folds desired and/or the explicit number of training and testing     data points in each fold. #pragma: no cover The simplest data splitter. Creates a single fold by splitting the data     into a training set and a testing set.      Parameters     ----------     data_size: integer         Total number of data points being used for cross validation     training_size: integer         Number of training points. Should be at most data_size - 1 Data splitter for K-fold cross validation. Creates K folds by partitioning     the data into K parts, each with roughly the same number of elements. In     each fold, the training set consists of all but one partition, which is     reserved for testing. The test partition iterates over folds.      Parameters     ----------     data_size: integer         Total number of data points being used for cross validation     K: integer         Number of folds desired     randomize: boolean (optional)         Decides whether or not index sets are to be randomized (default: False) Defines a data splitter that uses all but one of the data elements as     training data and uses the remaining one element as testing data. Folds are     generated by choosing which testing element is left out. Consequently, the     number of folds is equal to the total number of data points used for     cross validation.      Parameters     ----------     data_size: integer         Total number of data points being used for cross validation The opposite of leave-one-out cross validation. Uses one training point     and all the remaining data points as testing points.      Parameters     ----------     data_size: integer         Total number of data points being used for cross validation      See Also     --------     LeaveOneOut