Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

ENH: train_size and test_size in ShuffleSplit (#721) #757

Closed
wants to merge 8 commits into from

5 participants

David Marek Olivier Grisel Mathieu Blondel Gael Varoquaux Andreas Mueller
David Marek

#721

  • I have deprecated arguments test_fraction and train_fraction in ShuffleSplit and train_test_split and renamed them to test_size and train_size.
  • I have also modified documentation and tests (added one more to test deprecation warning).
  • I had to rewrite the argument checking a little to take in account that these values can now be integers.

The deprecation warning is: "test_fraction is deprecated in 0.11, use test_size instead." Is it correct? I am not sure which version should be there.

davidmarek added some commits
David Marek davidmarek ENH: train_size and test_size in ShuffleSplit (#721)
* renamed test_fraction and train_fraction to test_size and train_size
* deprecated test_fraction and train_fraction
* added tests for checking deprecation warnings
* modified documentation
7443113
David Marek davidmarek TEST: Added more tests for ShuffleSplit e73786f
Olivier Grisel
Owner

Can you please add a test where test_size is an integer and another where it is a long or a np.int(10) for instance?

Olivier Grisel
Owner

I meant np.int32(10).

Mathieu Blondel
Owner

Until now our policy was to give users two releases before removing deprecated features. So, since the current release is 0.10, test_fraction should be removed in 0.12.

Olivier Grisel
Owner

I forgot to answer the question about deprecation version numbers... Yes: deprecated in 0.11 and scheduled for removal in 0.12.

Olivier Grisel
Owner

Also @davidmarek can you please update the doc/whats_new.rst file to document this API change. Please also add a note on your other contribution on the new p parameter for the neighbors module.

David Marek

@ogrisel I have added new test for ShuffleSplit. It works for long and np.int32 but the error checking is only for int and float. Are there any helper functions to distinguish between integers and floating point numbers? StratifiedShuffleSplit contains very similar error checking in current code.

Olivier Grisel
Owner

I think numpy or scipy do have such helper functions for checking "type families". I cannot remember the exact name though.

Gael Varoquaux

If you have numpy arrays, you can check the 'kind' attribute of their dtype, which is 'i' for integers, and 'f' for floats.

David Marek

Thanks, I haven't known it's sufficient to test numpy types against np.integer and np.floating. I wasn't sure if there is something like this:

def isinteger(n):
    return isinstance(n, (int, long, numpy.integer)) # Should return True <=> n is integer

def isfloating(n):
    return isinstance(n, (float, numpy.floating)) # Should return True <=> n is floating point number

I think I'll just extend the types that are checked.

David Marek

Ok, I have added some error checking and another test. To be honest I don't like that there are arguments that can be int or float numbers and what happens depends on type of these arguments. I think it isn't very pythonic. It's not possible to use ducktyping with these arguments. But given that the code must be backward compatible, I think it's good to go.

Olivier Grisel
Owner

I agree that the magic behavior might not be such a good idea but I don't see any alternative API that would be as lightweight as this one. Any suggestion? Or shall we keep this?

David Marek

I don't want to break existing code so I think we should keep it. Another alternative is to have two arguments, one for each type. One would be n_test, second test_fraction. Then the code could look something like this:

def __init__(self, n, ..., test_fraction=0.1, train_fraction=None ..., n_test=None, n_train=None):
    if n_test is None:
        n_test = ceil(n * test_fraction)

    if n_train is None:
        if train_fraction is not None:
            n_train = floor(n * train_fraction)
        else:
            n_train = n - n_test

    if n_test + n_train > n:
        raise ValueError(...)

The difference? We don't have to check types, so we can use ducktyping.

In train_test_split the arguments must be given as key=value, so there won't be any problem with wrong argument order. The only problem I can see would be with ShuffleSplit and other classes, where user can create a new instance by something like ss = ShuffleSplit(n, 10, 0.2, 0.3)

Olivier Grisel
Owner

Indeed the positional arguments handling can be an issue. Any further opinion? I am a bit undecided on the whole issue now.

Mathieu Blondel
Owner

Personally, I like that we can use both float and int: it's natural to express sizes either as an integer or a percentage. There are many places in scikit-learn where parameters accept several types and also we have a policy of avoiding mutually exclusive parameters.

Gael Varoquaux
sklearn/tests/test_cross_validation.py
((27 lines not shown))
+ "for removal in 0.12, use test_size instead",
+ "train_fraction is deprecated in 0.11 and scheduled "
+ "for removal in 0.12, use train_size instead")
+
+ cval.ShuffleSplit(10, 3, test_fraction=0.1)
+ cval.ShuffleSplit(10, 3, train_fraction=0.1)
+ cval.train_test_split(range(3), test_fraction=0.1)
+ cval.train_test_split(range(3), train_fraction=0.1)
+ assert len(warn_queue) == 4
+ assert warn_queue[0] == expected_message[0]
+ assert warn_queue[1] == expected_message[1]
+ assert warn_queue[2] == expected_message[0]
+ assert warn_queue[3] == expected_message[1]
+
+ # restore default behavior
+ warnings.warn = warnings_warn
Olivier Grisel Owner
ogrisel added a note

You could use the:

with warnings.catch_warnings(record=True) as w:
    # do stuff
    assert_equal(len(w), 4)
    assert_equal(expected_message[0], w[0])
    #...

In particular it's important to use assert_equal(a, b) rather than assert a == b to get meaningful failure messages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Andreas Mueller
Owner

I agree with Matthieu and Gael.
There are certainly arguments for and against this method but there is a pretty clear policy in sklearn atm.

Andreas Mueller
Owner

I think instead of checking more types you should use kind as Gael suggested:
np.asarray(x).dtype.kind == 'i'

David Marek

Thanks for the review. I agree np.asarray(..).dtype.kind is the best way to handle int and float.

I have found few questionable parts of code:

  • Bootstrap api differs from ShuffleSplit and StratifiedShuffleSplit (it uses n_train and n_test which can be int or float).
  • test_warn_on_equidistant in test_neighbors.py uses assert instead of assert_equal (I was inspired by this function when I wrote my tests)
Olivier Grisel
Owner

I agree that Bootstrap should be updated too. Such API changes should be documented in the doc/whats_new.rst file as well.

The neighbors test improvements you suggests are good but should be handled in a separate pull request as they are unrelated.

Gael Varoquaux

Merging this. Will also modify the Bootstrap API and fix neighbors tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 4, 2012
  1. David Marek

    ENH: train_size and test_size in ShuffleSplit (#721)

    davidmarek authored
    * renamed test_fraction and train_fraction to test_size and train_size
    * deprecated test_fraction and train_fraction
    * added tests for checking deprecation warnings
    * modified documentation
  2. David Marek
Commits on Apr 5, 2012
  1. David Marek
  2. David Marek
  3. David Marek
Commits on Apr 10, 2012
  1. David Marek
Commits on Apr 15, 2012
  1. David Marek
  2. David Marek
This page is out of date. Refresh to see the latest.
8 doc/modules/cross_validation.rst
View
@@ -33,7 +33,7 @@ We can now quickly sample a training set while holding out 40% of the
data for testing (evaluating) our classifier::
>>> X_train, X_test, y_train, y_test = cross_validation.train_test_split(
- ... iris.data, iris.target, test_fraction=0.4, random_state=0)
+ ... iris.data, iris.target, test_size=0.4, random_state=0)
>>> X_train.shape, y_train.shape
((90, 4), (90,))
@@ -103,7 +103,7 @@ validation iterator instead, for instance::
>>> n_samples = iris.data.shape[0]
>>> cv = cross_validation.ShuffleSplit(n_samples, n_iterations=3,
- ... test_fraction=0.3, random_state=0)
+ ... test_size=0.3, random_state=0)
>>> cross_validation.cross_val_score(clf, iris.data, iris.target, cv=cv)
... # doctest: +ELLIPSIS
@@ -339,12 +339,12 @@ generator.
Here is a usage example::
- >>> ss = cross_validation.ShuffleSplit(5, n_iterations=3, test_fraction=0.25,
+ >>> ss = cross_validation.ShuffleSplit(5, n_iterations=3, test_size=0.25,
... random_state=0)
>>> len(ss)
3
>>> print ss # doctest: +ELLIPSIS
- ShuffleSplit(5, n_iterations=3, test_fraction=0.25, indices=True, ...)
+ ShuffleSplit(5, n_iterations=3, test_size=0.25, indices=True, ...)
>>> for train_index, test_index in ss:
... print train_index, test_index
12 doc/whats_new.rst
View
@@ -82,6 +82,9 @@ Changelog
``shrink_threshold`` parameter, which implements shrunken centroid
classification, by `Robert Layton`_.
+ - Classes in :ref:`neighbors` now support arbitrary Minkowski metric for
+ nearest neighbors searches. The metric can be specified by argument ``p``.
+
API changes summary
-------------------
@@ -153,6 +156,15 @@ API changes summary
difficult to be Cythonized. If you are interested, you can look in the
history codes by git.
+ - Options in class :class:`ShuffleSplit` are now consistent with
+ :class:`StratifiedShuffleSplit`. Options ``test_fraction`` and
+ ``train_fraction`` are deprecated and renamed to ``test_size`` and
+ ``train_size`` and can accept both ``float`` and ``int``.
+
+ - Argument ``p`` added to classes in :ref:`neighbors` to specify an
+ arbitrary Minkowski metric for nearest neighbors searches.
+
+
.. _changes_0_10:
0.10
197 sklearn/cross_validation.py
View
@@ -11,6 +11,7 @@
from itertools import combinations
from math import ceil, floor, factorial
import operator
+import warnings
import numpy as np
import scipy.sparse as sp
@@ -686,14 +687,16 @@ class ShuffleSplit(object):
n_iterations : int (default 10)
Number of re-shuffling & splitting iterations.
- test_fraction : float (default 0.1)
- Should be between 0.0 and 1.0 and represent the proportion of
- the dataset to include in the test split.
+ test_size : float (default 0.1) or int
+ If float, should be between 0.0 and 1.0 and represent the
+ proportion of the dataset to include in the test split. If
+ int, represents the absolute number of test samples.
- train_fraction : float or None (default is None)
- Should be between 0.0 and 1.0 and represent the proportion of
- the dataset to include in the train split. If None, the value is
- automatically set to the complement of the test fraction.
+ train_size : float, int, or None (default is None)
+ If float, should be between 0.0 and 1.0 and represent the
+ proportion of the dataset to include in the train split. If
+ int, represents the absolute number of train samples. If None,
+ the value is automatically set to the complement of the test fraction.
indices : boolean, optional (default True)
Return train/test split as arrays of indices, rather than a boolean
@@ -707,12 +710,12 @@ class ShuffleSplit(object):
--------
>>> from sklearn import cross_validation
>>> rs = cross_validation.ShuffleSplit(4, n_iterations=3,
- ... test_fraction=.25, random_state=0)
+ ... test_size=.25, random_state=0)
>>> len(rs)
3
>>> print rs
... # doctest: +ELLIPSIS
- ShuffleSplit(4, n_iterations=3, test_fraction=0.25, indices=True, ...)
+ ShuffleSplit(4, n_iterations=3, test_size=0.25, indices=True, ...)
>>> for train_index, test_index in rs:
... print "TRAIN:", train_index, "TEST:", test_index
...
@@ -721,7 +724,7 @@ class ShuffleSplit(object):
TRAIN: [0 2 1] TEST: [3]
>>> rs = cross_validation.ShuffleSplit(4, n_iterations=3,
- ... train_fraction=0.5, test_fraction=.25, random_state=0)
+ ... train_size=0.5, test_size=.25, random_state=0)
>>> for train_index, test_index in rs:
... print "TRAIN:", train_index, "TEST:", test_index
...
@@ -734,36 +737,39 @@ class ShuffleSplit(object):
Bootstrap: cross-validation using re-sampling with replacement.
"""
- def __init__(self, n, n_iterations=10, test_fraction=0.1,
- train_fraction=None, indices=True, random_state=None):
+ def __init__(self, n, n_iterations=10, test_size=0.1,
+ train_size=None, indices=True, random_state=None,
+ test_fraction=None, train_fraction=None):
self.n = n
self.n_iterations = n_iterations
- self.test_fraction = test_fraction
- self.train_fraction = train_fraction
+
+ if test_fraction is not None:
+ warnings.warn(
+ "test_fraction is deprecated in 0.11 and scheduled for "
+ "removal in 0.12, use test_size instead")
+ test_size = test_fraction
+ if train_fraction is not None:
+ warnings.warn(
+ "train_fraction is deprecated in 0.11 and scheduled for "
+ "removal in 0.12, use train_size instead")
+ train_size = train_fraction
+
+ self.test_size = test_size
+ self.train_size = train_size
self.random_state = random_state
self.indices = indices
- if test_fraction >= 1.0:
- raise ValueError(
- "test_fraction=%f should be smaller than 1.0" % test_fraction)
- if (train_fraction is not None
- and train_fraction + test_fraction > 1.0):
- raise ValueError(
- 'The sum of train_fraction=%f and test_fraction=%f '
- 'should be smaller or equal than 1.0' %
- (train_fraction, test_fraction))
+
+ self.n_train, self.n_test = _validate_shuffle_split(n,
+ test_size,
+ train_size)
def __iter__(self):
rng = check_random_state(self.random_state)
- n_test = ceil(self.test_fraction * self.n)
- if self.train_fraction is None:
- n_train = self.n - n_test
- else:
- n_train = floor(self.train_fraction * self.n)
for i in range(self.n_iterations):
# random partition
permutation = rng.permutation(self.n)
- ind_test = permutation[:n_test]
- ind_train = permutation[n_test:n_test + n_train]
+ ind_test = permutation[:self.n_test]
+ ind_train = permutation[self.n_test:self.n_test + self.n_train]
if self.indices:
yield ind_train, ind_test
@@ -775,12 +781,12 @@ def __iter__(self):
yield train_mask, test_mask
def __repr__(self):
- return ('%s(%d, n_iterations=%d, test_fraction=%s, indices=%s, '
+ return ('%s(%d, n_iterations=%d, test_size=%s, indices=%s, '
'random_state=%s)' % (
self.__class__.__name__,
self.n,
self.n_iterations,
- str(self.test_fraction),
+ str(self.test_size),
self.indices,
self.random_state,
))
@@ -789,57 +795,72 @@ def __len__(self):
return self.n_iterations
-def _validate_stratified_shuffle_split(y, test_size, train_size):
- y = unique(y, return_inverse=True)[1]
- if np.min(np.bincount(y)) < 2:
- raise ValueError("The least populated class in y has only 1"
- " member, which is too few. The minimum"
- " number of labels for any class cannot"
- " be less than 2.")
-
- if isinstance(test_size, float) and test_size >= 1.:
- raise ValueError(
- 'test_size=%f should be smaller '
- 'than 1.0 or be an integer' % test_size)
- elif isinstance(test_size, int) and test_size >= y.size:
- raise ValueError(
- 'test_size=%d should be smaller '
- 'than the number of samples %d' % (test_size, y.size))
+def _validate_shuffle_split(n, test_size, train_size):
+ if np.asarray(test_size).dtype.kind == 'f':
+ if test_size >= 1.:
+ raise ValueError(
+ 'test_size=%f should be smaller '
+ 'than 1.0 or be an integer' % test_size)
+ elif np.asarray(test_size).dtype.kind == 'i':
+ if test_size >= n:
+ raise ValueError(
+ 'test_size=%d should be smaller '
+ 'than the number of samples %d' % (test_size, n))
+ else:
+ raise ValueError("Invalid value for test_size: %r" % test_size)
if train_size is not None:
- if isinstance(train_size, float) and train_size >= 1.:
- raise ValueError("train_size=%f should be smaller "
- "than 1.0 or be an integer" % train_size)
- elif isinstance(train_size, int) and train_size >= y.size:
- raise ValueError("train_size=%d should be smaller "
- "than the number of samples %d" %
- (train_size, y.size))
-
- if isinstance(test_size, float):
- n_test = ceil(test_size * y.size)
+ if np.asarray(train_size).dtype.kind == 'f':
+ if train_size >= 1.:
+ raise ValueError("train_size=%f should be smaller "
+ "than 1.0 or be an integer" % train_size)
+ elif np.asarray(test_size).dtype.kind == 'f' and \
+ train_size + test_size > 1.:
+ raise ValueError('The sum of test_size and train_size = %f, '
+ 'should be smaller than 1.0. Reduce '
+ 'test_size and/or train_size.' %
+ (train_size + test_size))
+ elif np.asarray(train_size).dtype.kind == 'i':
+ if train_size >= n:
+ raise ValueError("train_size=%d should be smaller "
+ "than the number of samples %d" %
+ (train_size, n))
+ else:
+ raise ValueError("Invalid value for train_size: %r" % train_size)
+
+ if np.asarray(test_size).dtype.kind == 'f':
+ n_test = ceil(test_size * n)
else:
n_test = float(test_size)
if train_size is None:
- if isinstance(test_size, float):
- n_train = y.size - n_test
- else:
- n_train = float(y.size - test_size)
+ n_train = n - n_test
else:
- if isinstance(train_size, float):
- n_train = floor(train_size * y.size)
+ if np.asarray(train_size).dtype.kind == 'f':
+ n_train = floor(train_size * n)
else:
n_train = float(train_size)
- if n_train + n_test > y.size:
- raise ValueError('The sum of n_train and n_test = %d, should '
- 'be smaller than the number of samples %d. '
- 'Reduce test_size and/or train_size.' %
- (n_train + n_test, y.size))
+ if n_train + n_test > n:
+ raise ValueError('The sum of train_size and test_size = %d, '
+ 'should be smaller than the number of '
+ 'samples %d. Reduce test_size and/or '
+ 'train_size.' % (n_train + n_test, n))
return n_train, n_test
+def _validate_stratified_shuffle_split(y, test_size, train_size):
+ y = unique(y, return_inverse=True)[1]
+ if np.min(np.bincount(y)) < 2:
+ raise ValueError("The least populated class in y has only 1"
+ " member, which is too few. The minimum"
+ " number of labels for any class cannot"
+ " be less than 2.")
+
+ return _validate_shuffle_split(y.size, test_size, train_size)
+
+
class StratifiedShuffleSplit(object):
"""Stratified ShuffleSplit cross validation iterator
@@ -1184,14 +1205,16 @@ def train_test_split(*arrays, **options):
Python lists or tuples occurring in arrays are converted to 1D numpy
arrays.
- test_fraction : float (default 0.25)
- Should be between 0.0 and 1.0 and represent the proportion of
- the dataset to include in the test split.
+ test_size : float (default 0.25) or int
+ If float, should be between 0.0 and 1.0 and represent the
+ proportion of the dataset to include in the test split. If
+ int, represents the absolute number of test samples.
- train_fraction : float or None (default is None)
- Should be between 0.0 and 1.0 and represent the proportion of
- the dataset to include in the train split. If None, the value is
- automatically set to the complement of the test fraction.
+ train_size : float, int, or None (default is None)
+ If float, should be between 0.0 and 1.0 and represent the
+ proportion of the dataset to include in the train split. If
+ int, represents the absolute number of train samples. If None,
+ the value is automatically set to the complement of the test fraction.
random_state : int or RandomState
Pseudo-random number generator state used for random sampling.
@@ -1214,7 +1237,7 @@ def train_test_split(*arrays, **options):
[0, 1, 2, 3, 4]
>>> a_train, a_test, b_train, b_test = train_test_split(
- ... a, b, test_fraction=0.33, random_state=42)
+ ... a, b, test_size=0.33, random_state=42)
...
>>> a_train
array([[4, 5],
@@ -1233,15 +1256,29 @@ def train_test_split(*arrays, **options):
if n_arrays == 0:
raise ValueError("At least one array required as input")
- test_fraction = options.pop('test_fraction', 0.25)
+ test_fraction = options.pop('test_fraction', None)
+ if test_fraction is not None:
+ warnings.warn(
+ "test_fraction is deprecated in 0.11 and scheduled for "
+ "removal in 0.12, use test_size instead")
+ else:
+ test_fraction = 0.25
+
train_fraction = options.pop('train_fraction', None)
+ if train_fraction is not None:
+ warnings.warn(
+ "train_fraction is deprecated in 0.11 and scheduled for "
+ "removal in 0.12, use train_size instead")
+
+ test_size = options.pop('test_size', test_fraction)
+ train_size = options.pop('train_size', train_fraction)
random_state = options.pop('random_state', None)
options['sparse_format'] = 'csr'
arrays = check_arrays(*arrays, **options)
n_samples = arrays[0].shape[0]
- cv = ShuffleSplit(n_samples, test_fraction=test_fraction,
- train_fraction=train_fraction,
+ cv = ShuffleSplit(n_samples, test_size=test_size,
+ train_size=train_size,
random_state=random_state,
indices=True)
train, test = iter(cv).next()
57 sklearn/tests/test_cross_validation.py
View
@@ -1,9 +1,10 @@
"""Test the cross_validation module"""
+import warnings
import numpy as np
from scipy.sparse import coo_matrix
-from nose.tools import assert_true
+from nose.tools import assert_true, assert_equal
from nose.tools import assert_raises
from ..base import BaseEstimator
@@ -91,6 +92,20 @@ def test_shuffle_kfold():
assert_array_equal(all_folds, ind)
+def test_shuffle_split():
+ ss1 = cval.ShuffleSplit(10, test_size=0.2, random_state=0)
+ ss2 = cval.ShuffleSplit(10, test_size=2, random_state=0)
+ ss3 = cval.ShuffleSplit(10, test_size=np.int32(2), random_state=0)
+ ss4 = cval.ShuffleSplit(10, test_size=long(2), random_state=0)
+ for t1, t2, t3, t4 in zip(ss1, ss2, ss3, ss4):
+ assert_array_equal(t1[0], t2[0])
+ assert_array_equal(t2[0], t3[0])
+ assert_array_equal(t3[0], t4[0])
+ assert_array_equal(t1[1], t2[1])
+ assert_array_equal(t2[1], t3[1])
+ assert_array_equal(t3[1], t4[1])
+
+
def test_stratified_shuffle_split():
y = np.asarray([0, 1, 1, 1, 2, 2, 2])
# Check that error is raised if there is a class with only one sample
@@ -133,14 +148,46 @@ def test_cross_val_score():
def test_train_test_split_errors():
assert_raises(ValueError, cval.train_test_split)
assert_raises(ValueError, cval.train_test_split, range(3),
- train_fraction=1.1)
+ train_size=1.1)
+ assert_raises(ValueError, cval.train_test_split, range(3),
+ test_size=0.6, train_size=0.6)
assert_raises(ValueError, cval.train_test_split, range(3),
- test_fraction=0.6, train_fraction=0.6)
+ test_size=np.float32(0.6), train_size=np.float32(0.6))
+ assert_raises(ValueError, cval.train_test_split, range(3),
+ test_size="wrong_type")
+ assert_raises(ValueError, cval.train_test_split, range(3),
+ test_size=2, train_size=4)
assert_raises(TypeError, cval.train_test_split, range(3),
some_argument=1.1)
assert_raises(ValueError, cval.train_test_split, range(3), range(42))
+def test_shuffle_split_warnings():
+ # change warnings.warn to catch the message
+ warn_queue = []
+ warnings_warn = warnings.warn
+ warnings.warn = lambda msg: warn_queue.append(msg)
+
+ expected_message = ("test_fraction is deprecated in 0.11 and scheduled "
+ "for removal in 0.12, use test_size instead",
+ "train_fraction is deprecated in 0.11 and scheduled "
+ "for removal in 0.12, use train_size instead")
+
+ cval.ShuffleSplit(10, 3, test_fraction=0.1)
+ cval.ShuffleSplit(10, 3, train_fraction=0.1)
+ cval.train_test_split(range(3), test_fraction=0.1)
+ cval.train_test_split(range(3), train_fraction=0.1)
+
+ assert_equal(len(warn_queue), 4)
+ assert_equal(warn_queue[0], expected_message[0])
+ assert_equal(warn_queue[1], expected_message[1])
+ assert_equal(warn_queue[2], expected_message[0])
+ assert_equal(warn_queue[3], expected_message[1])
+
+ # restore default behavior
+ warnings.warn = warnings_warn
+
+
def test_train_test_split():
X = np.arange(100).reshape((10, 10))
X_s = coo_matrix(X)
@@ -287,6 +334,10 @@ def test_shufflesplit_errors():
assert_raises(ValueError, cval.ShuffleSplit, 10, test_fraction=1.0)
assert_raises(ValueError, cval.ShuffleSplit, 10, test_fraction=0.1,
train_fraction=0.95)
+ assert_raises(ValueError, cval.ShuffleSplit, 10, test_size=11)
+ assert_raises(ValueError, cval.ShuffleSplit, 10, test_size=10)
+ assert_raises(ValueError, cval.ShuffleSplit, 10, test_size=8,
+ train_size=3)
def test_shufflesplit_reproducible():
Something went wrong with that request. Please try again.