2011-11-30 18:05:10 +08:00
|
|
|
"""
|
2013-06-27 21:09:16 +08:00
|
|
|
The :mod:`sklearn.utils` module includes various utilities.
|
2011-11-30 18:05:10 +08:00
|
|
|
"""
|
2019-01-08 09:43:49 +08:00
|
|
|
from collections.abc import Sequence
|
2018-06-20 23:20:33 +08:00
|
|
|
import numbers
|
2018-07-20 12:39:53 +08:00
|
|
|
import platform
|
2018-08-25 11:54:30 +08:00
|
|
|
import struct
|
2013-03-11 05:14:10 +08:00
|
|
|
|
2018-11-20 07:53:52 +08:00
|
|
|
import warnings
|
2011-01-20 20:47:30 +08:00
|
|
|
import numpy as np
|
2012-08-15 06:33:41 +08:00
|
|
|
from scipy.sparse import issparse
|
2011-01-20 20:47:30 +08:00
|
|
|
|
2012-01-17 09:30:59 +08:00
|
|
|
from .murmurhash import murmurhash3_32
|
2018-11-20 07:53:52 +08:00
|
|
|
from .class_weight import compute_class_weight, compute_sample_weight
|
|
|
|
|
from . import _joblib
|
|
|
|
|
from ..exceptions import DataConversionWarning
|
|
|
|
|
from .deprecation import deprecated
|
2014-07-20 19:31:45 +08:00
|
|
|
from .validation import (as_float_array,
|
2015-05-01 00:48:52 +08:00
|
|
|
assert_all_finite,
|
2014-07-20 19:31:45 +08:00
|
|
|
check_random_state, column_or_1d, check_array,
|
2014-12-29 13:02:35 +08:00
|
|
|
check_consistent_length, check_X_y, indexable,
|
2015-06-06 02:45:45 +08:00
|
|
|
check_symmetric)
|
2018-05-25 10:04:05 +08:00
|
|
|
from .. import get_config
|
2015-06-06 02:45:45 +08:00
|
|
|
|
2018-11-20 07:53:52 +08:00
|
|
|
|
|
|
|
|
# Do not deprecate parallel_backend and register_parallel_backend as they are
|
|
|
|
|
# needed to tune `scikit-learn` behavior and have different effect if called
|
|
|
|
|
# from the vendored version or or the site-package version. The other are
|
|
|
|
|
# utilities that are independent of scikit-learn so they are not part of
|
|
|
|
|
# scikit-learn public API.
|
|
|
|
|
parallel_backend = _joblib.parallel_backend
|
|
|
|
|
register_parallel_backend = _joblib.register_parallel_backend
|
|
|
|
|
|
|
|
|
|
# deprecate the joblib API in sklearn in favor of using directly joblib
|
|
|
|
|
msg = ("deprecated in version 0.20.1 to be removed in version 0.23. "
|
|
|
|
|
"Please import this functionality directly from joblib, which can "
|
|
|
|
|
"be installed with: pip install joblib.")
|
|
|
|
|
deprecate = deprecated(msg)
|
|
|
|
|
|
|
|
|
|
delayed = deprecate(_joblib.delayed)
|
|
|
|
|
cpu_count = deprecate(_joblib.cpu_count)
|
|
|
|
|
hash = deprecate(_joblib.hash)
|
|
|
|
|
effective_n_jobs = deprecate(_joblib.effective_n_jobs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# for classes, deprecated will change the object in _joblib module so we need
|
|
|
|
|
# to subclass them.
|
|
|
|
|
@deprecate
|
|
|
|
|
class Memory(_joblib.Memory):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@deprecate
|
|
|
|
|
class Parallel(_joblib.Parallel):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2014-07-20 19:31:45 +08:00
|
|
|
__all__ = ["murmurhash3_32", "as_float_array",
|
|
|
|
|
"assert_all_finite", "check_array",
|
2014-04-28 10:17:05 +08:00
|
|
|
"check_random_state",
|
2015-02-01 10:26:41 +08:00
|
|
|
"compute_class_weight", "compute_sample_weight",
|
2014-07-20 19:31:45 +08:00
|
|
|
"column_or_1d", "safe_indexing",
|
2015-02-17 11:19:03 +08:00
|
|
|
"check_consistent_length", "check_X_y", 'indexable',
|
2018-07-18 00:02:11 +08:00
|
|
|
"check_symmetric", "indices_to_mask", "deprecated",
|
2018-07-20 01:18:51 +08:00
|
|
|
"cpu_count", "Parallel", "Memory", "delayed", "parallel_backend",
|
2018-10-26 17:00:01 +08:00
|
|
|
"register_parallel_backend", "hash", "effective_n_jobs",
|
|
|
|
|
"resample", "shuffle"]
|
2012-12-22 20:02:50 +08:00
|
|
|
|
2018-07-20 12:39:53 +08:00
|
|
|
IS_PYPY = platform.python_implementation() == 'PyPy'
|
2018-08-25 11:54:30 +08:00
|
|
|
_IS_32BIT = 8 * struct.calcsize("P") == 32
|
2018-07-20 12:39:53 +08:00
|
|
|
|
2013-06-04 01:19:55 +08:00
|
|
|
|
2017-03-30 20:21:51 +08:00
|
|
|
class Bunch(dict):
|
|
|
|
|
"""Container object for datasets
|
|
|
|
|
|
|
|
|
|
Dictionary-like object that exposes its keys as attributes.
|
|
|
|
|
|
|
|
|
|
>>> b = Bunch(a=1, b=2)
|
|
|
|
|
>>> b['b']
|
|
|
|
|
2
|
|
|
|
|
>>> b.b
|
|
|
|
|
2
|
|
|
|
|
>>> b.a = 3
|
|
|
|
|
>>> b['a']
|
|
|
|
|
3
|
|
|
|
|
>>> b.c = 6
|
|
|
|
|
>>> b['c']
|
|
|
|
|
6
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
2019-01-11 05:27:06 +08:00
|
|
|
super().__init__(kwargs)
|
2017-03-30 20:21:51 +08:00
|
|
|
|
|
|
|
|
def __setattr__(self, key, value):
|
|
|
|
|
self[key] = value
|
|
|
|
|
|
|
|
|
|
def __dir__(self):
|
|
|
|
|
return self.keys()
|
|
|
|
|
|
|
|
|
|
def __getattr__(self, key):
|
|
|
|
|
try:
|
|
|
|
|
return self[key]
|
|
|
|
|
except KeyError:
|
|
|
|
|
raise AttributeError(key)
|
|
|
|
|
|
|
|
|
|
def __setstate__(self, state):
|
|
|
|
|
# Bunch pickles generated with scikit-learn 0.16.* have an non
|
|
|
|
|
# empty __dict__. This causes a surprising behaviour when
|
|
|
|
|
# loading these pickles scikit-learn 0.17: reading bunch.key
|
|
|
|
|
# uses __dict__ but assigning to bunch.key use __setattr__ and
|
|
|
|
|
# only changes bunch['key']. More details can be found at:
|
|
|
|
|
# https://github.com/scikit-learn/scikit-learn/issues/6196.
|
|
|
|
|
# Overriding __setstate__ to be a noop has the effect of
|
|
|
|
|
# ignoring the pickled __dict__
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2012-01-13 14:31:45 +08:00
|
|
|
def safe_mask(X, mask):
|
2012-01-13 18:28:55 +08:00
|
|
|
"""Return a mask which is safe to use on X.
|
2012-01-13 14:31:45 +08:00
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2012-09-18 17:13:33 +08:00
|
|
|
X : {array-like, sparse matrix}
|
|
|
|
|
Data on which to apply mask.
|
2012-01-13 14:31:45 +08:00
|
|
|
|
2016-11-25 17:59:22 +08:00
|
|
|
mask : array
|
2012-09-18 17:13:33 +08:00
|
|
|
Mask to be used on X.
|
2012-01-13 14:31:45 +08:00
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
mask
|
|
|
|
|
"""
|
2013-07-11 21:54:13 +08:00
|
|
|
mask = np.asarray(mask)
|
2017-09-04 16:00:15 +08:00
|
|
|
if np.issubdtype(mask.dtype, np.signedinteger):
|
2012-08-27 19:35:17 +08:00
|
|
|
return mask
|
|
|
|
|
|
2012-01-13 14:31:45 +08:00
|
|
|
if hasattr(X, "toarray"):
|
|
|
|
|
ind = np.arange(mask.shape[0])
|
|
|
|
|
mask = ind[mask]
|
|
|
|
|
return mask
|
|
|
|
|
|
|
|
|
|
|
2015-09-21 06:47:14 +08:00
|
|
|
def axis0_safe_slice(X, mask, len_mask):
|
|
|
|
|
"""
|
|
|
|
|
This mask is safer than safe_mask since it returns an
|
|
|
|
|
empty array, when a sparse matrix is sliced with a boolean mask
|
|
|
|
|
with all False, instead of raising an unhelpful error in older
|
|
|
|
|
versions of SciPy.
|
|
|
|
|
|
|
|
|
|
See: https://github.com/scipy/scipy/issues/5361
|
|
|
|
|
|
|
|
|
|
Also note that we can avoid doing the dot product by checking if
|
|
|
|
|
the len_mask is not zero in _huber_loss_and_gradient but this
|
|
|
|
|
is not going to be the bottleneck, since the number of outliers
|
|
|
|
|
and non_outliers are typically non-zero and it makes the code
|
|
|
|
|
tougher to follow.
|
2018-07-22 13:23:11 +08:00
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
X : {array-like, sparse matrix}
|
|
|
|
|
Data on which to apply mask.
|
|
|
|
|
|
|
|
|
|
mask : array
|
|
|
|
|
Mask to be used on X.
|
|
|
|
|
|
|
|
|
|
len_mask : int
|
|
|
|
|
The length of the mask.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
mask
|
2015-09-21 06:47:14 +08:00
|
|
|
"""
|
|
|
|
|
if len_mask != 0:
|
|
|
|
|
return X[safe_mask(X, mask), :]
|
|
|
|
|
return np.zeros(shape=(0, X.shape[1]))
|
|
|
|
|
|
|
|
|
|
|
2014-04-28 10:17:05 +08:00
|
|
|
def safe_indexing(X, indices):
|
|
|
|
|
"""Return items or rows from X using indices.
|
|
|
|
|
|
|
|
|
|
Allows simple indexing of lists or arrays.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2017-06-08 21:31:26 +08:00
|
|
|
X : array-like, sparse-matrix, list, pandas.DataFrame, pandas.Series.
|
2014-04-28 10:17:05 +08:00
|
|
|
Data from which to sample rows or items.
|
2017-06-08 21:31:26 +08:00
|
|
|
indices : array-like of int
|
2014-04-28 10:17:05 +08:00
|
|
|
Indices according to which X will be subsampled.
|
2017-06-08 21:31:26 +08:00
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
subset
|
|
|
|
|
Subset of X on first axis
|
2017-07-20 20:10:46 +08:00
|
|
|
|
|
|
|
|
Notes
|
|
|
|
|
-----
|
|
|
|
|
CSR, CSC, and LIL sparse matrices are supported. COO sparse matrices are
|
|
|
|
|
not supported.
|
2014-04-28 10:17:05 +08:00
|
|
|
"""
|
2014-07-18 16:02:14 +08:00
|
|
|
if hasattr(X, "iloc"):
|
2017-08-08 16:21:09 +08:00
|
|
|
# Work-around for indexing with read-only indices in pandas
|
|
|
|
|
indices = indices if indices.flags.writeable else indices.copy()
|
2014-07-18 16:02:14 +08:00
|
|
|
# Pandas Dataframes and Series
|
2015-05-06 07:26:35 +08:00
|
|
|
try:
|
|
|
|
|
return X.iloc[indices]
|
|
|
|
|
except ValueError:
|
|
|
|
|
# Cython typed memoryviews internally used in pandas do not support
|
|
|
|
|
# readonly buffers.
|
|
|
|
|
warnings.warn("Copying input dataframe for slicing.",
|
2015-11-23 19:03:06 +08:00
|
|
|
DataConversionWarning)
|
2015-05-06 07:26:35 +08:00
|
|
|
return X.copy().iloc[indices]
|
2014-07-18 16:02:14 +08:00
|
|
|
elif hasattr(X, "shape"):
|
2014-08-07 17:45:21 +08:00
|
|
|
if hasattr(X, 'take') and (hasattr(indices, 'dtype') and
|
|
|
|
|
indices.dtype.kind == 'i'):
|
|
|
|
|
# This is often substantially faster than X[indices]
|
|
|
|
|
return X.take(indices, axis=0)
|
|
|
|
|
else:
|
|
|
|
|
return X[indices]
|
2014-04-28 10:17:05 +08:00
|
|
|
else:
|
|
|
|
|
return [X[idx] for idx in indices]
|
|
|
|
|
|
|
|
|
|
|
2011-05-21 20:32:43 +08:00
|
|
|
def resample(*arrays, **options):
|
2011-05-21 20:46:16 +08:00
|
|
|
"""Resample arrays or sparse matrices in a consistent way
|
2011-05-17 15:49:05 +08:00
|
|
|
|
2011-05-21 20:32:43 +08:00
|
|
|
The default strategy implements one step of the bootstrapping
|
|
|
|
|
procedure.
|
|
|
|
|
|
2011-05-17 15:49:05 +08:00
|
|
|
Parameters
|
|
|
|
|
----------
|
2015-04-10 01:16:59 +08:00
|
|
|
*arrays : sequence of indexable data-structures
|
|
|
|
|
Indexable data-structures can be arrays, lists, dataframes or scipy
|
|
|
|
|
sparse matrices with consistent first dimension.
|
2011-05-17 15:49:05 +08:00
|
|
|
|
2018-07-22 13:23:11 +08:00
|
|
|
Other Parameters
|
|
|
|
|
----------------
|
2011-05-21 20:32:43 +08:00
|
|
|
replace : boolean, True by default
|
|
|
|
|
Implements resampling with replacement. If False, this will implement
|
|
|
|
|
(sliced) random permutations.
|
|
|
|
|
|
|
|
|
|
n_samples : int, None by default
|
|
|
|
|
Number of samples to generate. If left to None this is
|
|
|
|
|
automatically set to the first dimension of the arrays.
|
2016-04-02 14:58:40 +08:00
|
|
|
If replace is False it should not be larger than the length of
|
|
|
|
|
arrays.
|
2011-05-21 20:32:43 +08:00
|
|
|
|
2017-04-06 08:43:21 +08:00
|
|
|
random_state : int, RandomState instance or None, optional (default=None)
|
|
|
|
|
The seed of the pseudo random number generator to use when shuffling
|
|
|
|
|
the data. If int, random_state is the seed used by the random number
|
|
|
|
|
generator; If RandomState instance, random_state is the random number
|
|
|
|
|
generator; If None, the random number generator is the RandomState
|
|
|
|
|
instance used by `np.random`.
|
2011-05-17 15:49:05 +08:00
|
|
|
|
2011-12-23 02:34:33 +08:00
|
|
|
Returns
|
|
|
|
|
-------
|
2015-04-10 01:16:59 +08:00
|
|
|
resampled_arrays : sequence of indexable data-structures
|
2017-11-18 00:22:05 +08:00
|
|
|
Sequence of resampled copies of the collections. The original arrays
|
|
|
|
|
are not impacted.
|
2011-05-17 15:49:05 +08:00
|
|
|
|
2011-12-23 02:47:49 +08:00
|
|
|
Examples
|
|
|
|
|
--------
|
2011-05-17 15:49:05 +08:00
|
|
|
It is possible to mix sparse and dense arrays in the same run::
|
|
|
|
|
|
2015-04-10 01:16:59 +08:00
|
|
|
>>> X = np.array([[1., 0.], [2., 1.], [0., 0.]])
|
2011-05-17 15:49:05 +08:00
|
|
|
>>> y = np.array([0, 1, 2])
|
|
|
|
|
|
|
|
|
|
>>> from scipy.sparse import coo_matrix
|
|
|
|
|
>>> X_sparse = coo_matrix(X)
|
|
|
|
|
|
2011-09-02 17:00:02 +08:00
|
|
|
>>> from sklearn.utils import resample
|
2011-05-21 20:32:43 +08:00
|
|
|
>>> X, X_sparse, y = resample(X, X_sparse, y, random_state=0)
|
2011-05-17 15:49:05 +08:00
|
|
|
>>> X
|
2018-03-27 13:44:40 +08:00
|
|
|
array([[1., 0.],
|
|
|
|
|
[2., 1.],
|
|
|
|
|
[1., 0.]])
|
2011-05-17 15:49:05 +08:00
|
|
|
|
2012-03-13 03:57:32 +08:00
|
|
|
>>> X_sparse # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
|
|
|
|
|
<3x2 sparse matrix of type '<... 'numpy.float64'>'
|
2011-05-21 20:32:43 +08:00
|
|
|
with 4 stored elements in Compressed Sparse Row format>
|
2011-05-17 15:49:05 +08:00
|
|
|
|
|
|
|
|
>>> X_sparse.toarray()
|
2018-03-27 13:44:40 +08:00
|
|
|
array([[1., 0.],
|
|
|
|
|
[2., 1.],
|
|
|
|
|
[1., 0.]])
|
2011-05-17 15:49:05 +08:00
|
|
|
|
|
|
|
|
>>> y
|
2011-05-21 20:32:43 +08:00
|
|
|
array([0, 1, 0])
|
|
|
|
|
|
|
|
|
|
>>> resample(y, n_samples=2, random_state=0)
|
|
|
|
|
array([0, 1])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
See also
|
|
|
|
|
--------
|
2011-09-02 17:00:02 +08:00
|
|
|
:func:`sklearn.utils.shuffle`
|
2011-05-17 15:49:05 +08:00
|
|
|
"""
|
2011-05-18 00:44:01 +08:00
|
|
|
random_state = check_random_state(options.pop('random_state', None))
|
2011-05-21 20:32:43 +08:00
|
|
|
replace = options.pop('replace', True)
|
|
|
|
|
max_n_samples = options.pop('n_samples', None)
|
2011-05-18 00:44:01 +08:00
|
|
|
if options:
|
|
|
|
|
raise ValueError("Unexpected kw arguments: %r" % options.keys())
|
2011-05-17 15:49:05 +08:00
|
|
|
|
2011-05-18 00:44:01 +08:00
|
|
|
if len(arrays) == 0:
|
2011-05-18 08:15:50 +08:00
|
|
|
return None
|
2011-05-17 15:49:05 +08:00
|
|
|
|
2011-05-18 00:44:01 +08:00
|
|
|
first = arrays[0]
|
2011-05-17 15:49:05 +08:00
|
|
|
n_samples = first.shape[0] if hasattr(first, 'shape') else len(first)
|
|
|
|
|
|
2011-05-21 20:32:43 +08:00
|
|
|
if max_n_samples is None:
|
|
|
|
|
max_n_samples = n_samples
|
2016-04-02 14:58:40 +08:00
|
|
|
elif (max_n_samples > n_samples) and (not replace):
|
2017-02-09 08:01:11 +08:00
|
|
|
raise ValueError("Cannot sample %d out of arrays with dim %d "
|
2016-04-02 14:58:40 +08:00
|
|
|
"when replace is False" % (max_n_samples,
|
|
|
|
|
n_samples))
|
2011-05-21 20:32:43 +08:00
|
|
|
|
2014-07-20 19:31:45 +08:00
|
|
|
check_consistent_length(*arrays)
|
2011-05-22 06:29:51 +08:00
|
|
|
|
2011-05-21 20:32:43 +08:00
|
|
|
if replace:
|
|
|
|
|
indices = random_state.randint(0, n_samples, size=(max_n_samples,))
|
|
|
|
|
else:
|
2011-05-21 20:46:16 +08:00
|
|
|
indices = np.arange(n_samples)
|
2011-05-21 20:32:43 +08:00
|
|
|
random_state.shuffle(indices)
|
2011-05-21 20:46:16 +08:00
|
|
|
indices = indices[:max_n_samples]
|
2011-05-21 20:32:43 +08:00
|
|
|
|
2015-04-10 01:16:59 +08:00
|
|
|
# convert sparse matrices to CSR for row-based indexing
|
|
|
|
|
arrays = [a.tocsr() if issparse(a) else a for a in arrays]
|
|
|
|
|
resampled_arrays = [safe_indexing(a, indices) for a in arrays]
|
2011-05-21 20:32:43 +08:00
|
|
|
if len(resampled_arrays) == 1:
|
2011-05-18 08:15:50 +08:00
|
|
|
# syntactic sugar for the unit argument case
|
2011-05-21 20:32:43 +08:00
|
|
|
return resampled_arrays[0]
|
2011-05-18 08:15:50 +08:00
|
|
|
else:
|
2011-05-21 20:32:43 +08:00
|
|
|
return resampled_arrays
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def shuffle(*arrays, **options):
|
|
|
|
|
"""Shuffle arrays or sparse matrices in a consistent way
|
|
|
|
|
|
2011-12-21 23:11:16 +08:00
|
|
|
This is a convenience alias to ``resample(*arrays, replace=False)`` to do
|
2011-05-21 20:46:16 +08:00
|
|
|
random permutations of the collections.
|
2011-05-21 20:32:43 +08:00
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2015-04-10 01:16:59 +08:00
|
|
|
*arrays : sequence of indexable data-structures
|
|
|
|
|
Indexable data-structures can be arrays, lists, dataframes or scipy
|
|
|
|
|
sparse matrices with consistent first dimension.
|
2011-05-21 20:32:43 +08:00
|
|
|
|
2018-07-22 13:23:11 +08:00
|
|
|
Other Parameters
|
|
|
|
|
----------------
|
2017-04-06 08:43:21 +08:00
|
|
|
random_state : int, RandomState instance or None, optional (default=None)
|
|
|
|
|
The seed of the pseudo random number generator to use when shuffling
|
|
|
|
|
the data. If int, random_state is the seed used by the random number
|
|
|
|
|
generator; If RandomState instance, random_state is the random number
|
|
|
|
|
generator; If None, the random number generator is the RandomState
|
|
|
|
|
instance used by `np.random`.
|
2011-05-21 20:32:43 +08:00
|
|
|
|
2011-05-21 20:46:16 +08:00
|
|
|
n_samples : int, None by default
|
|
|
|
|
Number of samples to generate. If left to None this is
|
|
|
|
|
automatically set to the first dimension of the arrays.
|
|
|
|
|
|
2011-12-23 02:34:33 +08:00
|
|
|
Returns
|
|
|
|
|
-------
|
2015-04-10 01:16:59 +08:00
|
|
|
shuffled_arrays : sequence of indexable data-structures
|
2017-11-18 00:22:05 +08:00
|
|
|
Sequence of shuffled copies of the collections. The original arrays
|
|
|
|
|
are not impacted.
|
2011-05-21 20:32:43 +08:00
|
|
|
|
2011-12-23 02:47:49 +08:00
|
|
|
Examples
|
|
|
|
|
--------
|
2011-05-21 20:32:43 +08:00
|
|
|
It is possible to mix sparse and dense arrays in the same run::
|
|
|
|
|
|
2015-04-10 01:16:59 +08:00
|
|
|
>>> X = np.array([[1., 0.], [2., 1.], [0., 0.]])
|
2011-05-21 20:32:43 +08:00
|
|
|
>>> y = np.array([0, 1, 2])
|
|
|
|
|
|
|
|
|
|
>>> from scipy.sparse import coo_matrix
|
|
|
|
|
>>> X_sparse = coo_matrix(X)
|
|
|
|
|
|
2011-09-02 17:00:02 +08:00
|
|
|
>>> from sklearn.utils import shuffle
|
2011-05-21 20:32:43 +08:00
|
|
|
>>> X, X_sparse, y = shuffle(X, X_sparse, y, random_state=0)
|
|
|
|
|
>>> X
|
2018-03-27 13:44:40 +08:00
|
|
|
array([[0., 0.],
|
|
|
|
|
[2., 1.],
|
|
|
|
|
[1., 0.]])
|
2011-05-21 20:32:43 +08:00
|
|
|
|
2012-05-16 03:18:30 +08:00
|
|
|
>>> X_sparse # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
|
2012-03-13 03:57:32 +08:00
|
|
|
<3x2 sparse matrix of type '<... 'numpy.float64'>'
|
2011-05-21 20:32:43 +08:00
|
|
|
with 3 stored elements in Compressed Sparse Row format>
|
|
|
|
|
|
|
|
|
|
>>> X_sparse.toarray()
|
2018-03-27 13:44:40 +08:00
|
|
|
array([[0., 0.],
|
|
|
|
|
[2., 1.],
|
|
|
|
|
[1., 0.]])
|
2011-05-21 20:32:43 +08:00
|
|
|
|
|
|
|
|
>>> y
|
|
|
|
|
array([2, 1, 0])
|
|
|
|
|
|
2011-05-21 20:46:16 +08:00
|
|
|
>>> shuffle(y, n_samples=2, random_state=0)
|
|
|
|
|
array([0, 1])
|
|
|
|
|
|
2011-05-21 20:32:43 +08:00
|
|
|
See also
|
|
|
|
|
--------
|
2011-09-02 17:00:02 +08:00
|
|
|
:func:`sklearn.utils.resample`
|
2011-05-21 20:32:43 +08:00
|
|
|
"""
|
|
|
|
|
options['replace'] = False
|
|
|
|
|
return resample(*arrays, **options)
|
2011-07-17 01:48:08 +08:00
|
|
|
|
|
|
|
|
|
2012-08-15 18:03:59 +08:00
|
|
|
def safe_sqr(X, copy=True):
|
2012-08-15 06:33:41 +08:00
|
|
|
"""Element wise squaring of array-likes and sparse matrices.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
X : array like, matrix, sparse matrix
|
|
|
|
|
|
2014-12-29 11:18:45 +08:00
|
|
|
copy : boolean, optional, default True
|
|
|
|
|
Whether to create a copy of X and operate on it or to perform
|
|
|
|
|
inplace computation (default behaviour).
|
|
|
|
|
|
2012-08-15 06:33:41 +08:00
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
X ** 2 : element wise square
|
|
|
|
|
"""
|
2015-08-25 07:52:40 +08:00
|
|
|
X = check_array(X, accept_sparse=['csr', 'csc', 'coo'], ensure_2d=False)
|
2012-08-15 06:33:41 +08:00
|
|
|
if issparse(X):
|
2012-08-15 18:03:59 +08:00
|
|
|
if copy:
|
|
|
|
|
X = X.copy()
|
|
|
|
|
X.data **= 2
|
2012-08-15 06:33:41 +08:00
|
|
|
else:
|
2012-08-15 18:03:59 +08:00
|
|
|
if copy:
|
|
|
|
|
X = X ** 2
|
|
|
|
|
else:
|
|
|
|
|
X **= 2
|
|
|
|
|
return X
|
2012-08-15 06:33:41 +08:00
|
|
|
|
|
|
|
|
|
2018-10-31 21:32:19 +08:00
|
|
|
def gen_batches(n, batch_size, min_batch_size=0):
|
2013-07-29 21:04:31 +08:00
|
|
|
"""Generator to create slices containing batch_size elements, from 0 to n.
|
|
|
|
|
|
|
|
|
|
The last slice may contain less than batch_size elements, when batch_size
|
|
|
|
|
does not divide n.
|
|
|
|
|
|
2018-07-22 13:23:11 +08:00
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
n : int
|
|
|
|
|
batch_size : int
|
|
|
|
|
Number of element in each batch
|
2018-10-31 21:32:19 +08:00
|
|
|
min_batch_size : int, default=0
|
|
|
|
|
Minimum batch size to produce.
|
2018-07-22 13:23:11 +08:00
|
|
|
|
|
|
|
|
Yields
|
|
|
|
|
------
|
|
|
|
|
slice of batch_size elements
|
|
|
|
|
|
2013-07-29 21:04:31 +08:00
|
|
|
Examples
|
|
|
|
|
--------
|
|
|
|
|
>>> from sklearn.utils import gen_batches
|
|
|
|
|
>>> list(gen_batches(7, 3))
|
|
|
|
|
[slice(0, 3, None), slice(3, 6, None), slice(6, 7, None)]
|
|
|
|
|
>>> list(gen_batches(6, 3))
|
|
|
|
|
[slice(0, 3, None), slice(3, 6, None)]
|
|
|
|
|
>>> list(gen_batches(2, 3))
|
|
|
|
|
[slice(0, 2, None)]
|
2018-10-31 21:32:19 +08:00
|
|
|
>>> list(gen_batches(7, 3, min_batch_size=0))
|
|
|
|
|
[slice(0, 3, None), slice(3, 6, None), slice(6, 7, None)]
|
|
|
|
|
>>> list(gen_batches(7, 3, min_batch_size=2))
|
|
|
|
|
[slice(0, 3, None), slice(3, 7, None)]
|
2013-07-29 21:04:31 +08:00
|
|
|
"""
|
|
|
|
|
start = 0
|
|
|
|
|
for _ in range(int(n // batch_size)):
|
|
|
|
|
end = start + batch_size
|
2018-10-31 21:32:19 +08:00
|
|
|
if end + min_batch_size > n:
|
|
|
|
|
continue
|
2013-07-29 21:04:31 +08:00
|
|
|
yield slice(start, end)
|
|
|
|
|
start = end
|
|
|
|
|
if start < n:
|
|
|
|
|
yield slice(start, n)
|
|
|
|
|
|
|
|
|
|
|
2013-10-28 00:51:33 +08:00
|
|
|
def gen_even_slices(n, n_packs, n_samples=None):
|
2011-07-17 01:48:08 +08:00
|
|
|
"""Generator to create n_packs slices going up to n.
|
|
|
|
|
|
2018-07-22 13:23:11 +08:00
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
n : int
|
|
|
|
|
n_packs : int
|
|
|
|
|
Number of slices to generate.
|
|
|
|
|
n_samples : int or None (default = None)
|
|
|
|
|
Number of samples. Pass n_samples when the slices are to be used for
|
|
|
|
|
sparse matrix indexing; slicing off-the-end raises an exception, while
|
|
|
|
|
it works for NumPy arrays.
|
|
|
|
|
|
|
|
|
|
Yields
|
|
|
|
|
------
|
|
|
|
|
slice
|
2013-10-28 00:51:33 +08:00
|
|
|
|
2011-07-17 01:48:08 +08:00
|
|
|
Examples
|
2011-07-23 00:28:19 +08:00
|
|
|
--------
|
2011-09-02 17:00:02 +08:00
|
|
|
>>> from sklearn.utils import gen_even_slices
|
2011-07-19 03:48:53 +08:00
|
|
|
>>> list(gen_even_slices(10, 1))
|
2011-07-17 01:48:08 +08:00
|
|
|
[slice(0, 10, None)]
|
2011-07-19 03:48:53 +08:00
|
|
|
>>> list(gen_even_slices(10, 10)) #doctest: +ELLIPSIS
|
|
|
|
|
[slice(0, 1, None), slice(1, 2, None), ..., slice(9, 10, None)]
|
|
|
|
|
>>> list(gen_even_slices(10, 5)) #doctest: +ELLIPSIS
|
|
|
|
|
[slice(0, 2, None), slice(2, 4, None), ..., slice(8, 10, None)]
|
|
|
|
|
>>> list(gen_even_slices(10, 3))
|
2011-07-17 01:48:08 +08:00
|
|
|
[slice(0, 4, None), slice(4, 7, None), slice(7, 10, None)]
|
|
|
|
|
"""
|
|
|
|
|
start = 0
|
2015-05-21 03:29:25 +08:00
|
|
|
if n_packs < 1:
|
2015-10-19 23:31:36 +08:00
|
|
|
raise ValueError("gen_even_slices got n_packs=%s, must be >=1"
|
|
|
|
|
% n_packs)
|
2011-07-17 01:48:08 +08:00
|
|
|
for pack_num in range(n_packs):
|
|
|
|
|
this_n = n // n_packs
|
|
|
|
|
if pack_num < n % n_packs:
|
|
|
|
|
this_n += 1
|
|
|
|
|
if this_n > 0:
|
|
|
|
|
end = start + this_n
|
2013-10-28 00:51:33 +08:00
|
|
|
if n_samples is not None:
|
|
|
|
|
end = min(n_samples, end)
|
2011-07-17 01:48:08 +08:00
|
|
|
yield slice(start, end, None)
|
|
|
|
|
start = end
|
2011-11-09 17:35:52 +08:00
|
|
|
|
|
|
|
|
|
2013-03-11 05:14:10 +08:00
|
|
|
def tosequence(x):
|
2017-07-12 00:42:10 +08:00
|
|
|
"""Cast iterable x to a Sequence, avoiding a copy if possible.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
x : iterable
|
|
|
|
|
"""
|
2013-03-11 05:14:10 +08:00
|
|
|
if isinstance(x, np.ndarray):
|
|
|
|
|
return np.asarray(x)
|
|
|
|
|
elif isinstance(x, Sequence):
|
|
|
|
|
return x
|
|
|
|
|
else:
|
|
|
|
|
return list(x)
|
[MRG] Remove heavy memory footprint in BaseBagging due to OOB scoring (#7118)
* Remove heavy memory footprint for OOB scoring from bagging.
- Remove `estimators_samples` attribute from `BaseBagging`
- Add method `_get_estimators_samples` to `BaseBagging` that
returns a generator producing sample indices on demand.
- Slight refactor of `_parallel_build_estimators()` to
isolate and group lines accessing random state.
* Replaced `BaseBagging.estimators_samples_` attribute with property.
- Accessing `BaseBagging.estimators_samples_` now triggers call to
`BaseBagging._get_estimators_samples` as well as deprecation
warning for release 0.20.
- This should make the fix for the OOB memory issue fully backwards
compatible.
* Remove print statement.
* Added test, made new method more general.
- Added test to `test_bagging.py` to ensure that indices generated
on the fly are identical to indices generated at fit time.
- Refactored `_get_estimators_samples()` to `_get_estimators_indices()`,
now both feature and samples indices are returned.
- Refactored `estimators_samples_()` to deal with above.
* Rename index generating functions and arguments.
* `estimators_samples_()` returns list instead of generator
* Removed `estimators_samples_` deprection warning.
* Actually removed `estimators_samples_` deprecation warning.
* New mask generation function, new bagging test, new BaseBagging attributes.
- Added new private function in bagging.py that converts indices to
a boolean mask.
- Added new bagging test to make sure identical OOB scores are generated
when the same estimator if fit with fixed random state and identical
training data.
- Added new private attributes `BaseBagging._max_features` and
`BaseBagging._max_samples` to store validated input values.
* Streamlined code, improved `estimators_samples_()` documentation.
- Removed `max_samples` argument from `_parallel_build_estimators()`,
this value is now accessed via `ensemble._max_samples`.
- Removed validation of `ensemble.max_features` and `max_samples`,
instead use `ensemble._max_features` and `ensemble._max_samples`
which are assumed to be already validated.
- Removed unnecessary `samples` variable from `_parallel_build_estimators()`.
- Changed the way `random_state` is generated in `_parallel_build_estimators()`
and `BaseBagging._get_estimators_data_draws()` to direct numpy method to
reflect that seeds created in `BaseBagging._fit()` are trustworthy.
- Due to above removed generation of new seed for each estimator in
`_parallel_build_estimators()` and `BaseBagging._get_estimators_data_draws()`.
- Added documentation to `BaseBagging.estimators_samples_()` property
indicating the reason it's generated dynamically and the associated performance
penalty.
- Returned `BaggingClassifier._set_oob_score()` and `BaggingRegressor._set_oob_score()`
to directly accessing `self.estimators_samples_`.
* Streamlined code, improved `estimators_samples_()` documentation.
- Removed `max_samples` argument from `_parallel_build_estimators()`,
this value is now accessed via `ensemble._max_samples`.
- Removed validation of `ensemble.max_features` and `max_samples`,
instead use `ensemble._max_features` and `ensemble._max_samples`
which are assumed to be already validated.
- Removed unnecessary `samples` variable from `_parallel_build_estimators()`.
- Changed the way `random_state` is generated in `_parallel_build_estimators()`
and `BaseBagging._get_estimators_data_draws()` to direct numpy method to
reflect that seeds created in `BaseBagging._fit()` are trustworthy.
- Due to above removed generation of new seed for each estimator in
`_parallel_build_estimators()` and `BaseBagging._get_estimators_data_draws()`.
- Added documentation to `BaseBagging.estimators_samples_()` property
indicating the reason it's generated dynamically and the associated performance
penalty.
- Returned `BaggingClassifier._set_oob_score()` and `BaggingRegressor._set_oob_score()`
to directly accessing `self.estimators_samples_`.
* PEP8, remove optional arguments, add public function to utils.
- Update indentation and line length to conform to PEP8.
- Update `estimators_samples_()` docstring to conform to PEP8 and
PEP257.
- Remove optional arguments to `BaseBagging._get_estimators_data_draws()`,
rename to `BaseBagging._get_estimators_indices()`.
- Remove optional arguments from `_generate_mask_from_indices()`,
move to `utils.metaestimators`, rename to `indices_to_mask()`.
* Add indices_to_mask to __all__ in utils.metaestimators
* Move utils function, new test for `estimators_samples` correctness.
- Moved `indices_to_mask` from `utils.metaestimators` to `utils.validation`
- Added new test to `ensemble.test_bagging` to make sure refitting
an individual estimator from the bagging ensemble using the corresponding
samples identified in `BaseBagging.estimators_samples` returns the same model.
* Adjust/remove tests, move `indices_to_mask` to `utils.__init__`.
- Remove test_bagging.test_consistent_index_sampling
- Update formatting checks in test_bagging.test_estimators_samples
to make sure each mask is numpy boolean array
- Move indices_to_mask from utils.validation to utils.__init__
* update class docstring for `estimators_samples_`
- Updated class docstring of `estimators_samples_` attribute for `BaggingClassifier` and `BaggingRegressor` to indicate that samples are identified with boolean masks.
* PEP8, made `max_samples` arg optional in _fit()
- Fixed PEP8 issues.
- Gave `max_samples` argument of `BaseBagging._fit()` a default
value of `None` as indicated in the docstring. Added code to
check for and process `None` value.
- Added a few more comments to `_fit()`.
* 2 new `max_samples` consistency tests, update whats_new.rst
* Minor change
* Update whats_new.rst
2016-08-23 14:59:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def indices_to_mask(indices, mask_length):
|
|
|
|
|
"""Convert list of indices to boolean mask.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
indices : list-like
|
|
|
|
|
List of integers treated as indices.
|
|
|
|
|
mask_length : int
|
|
|
|
|
Length of boolean mask to be generated.
|
2018-03-05 14:59:31 +08:00
|
|
|
This parameter must be greater than max(indices)
|
[MRG] Remove heavy memory footprint in BaseBagging due to OOB scoring (#7118)
* Remove heavy memory footprint for OOB scoring from bagging.
- Remove `estimators_samples` attribute from `BaseBagging`
- Add method `_get_estimators_samples` to `BaseBagging` that
returns a generator producing sample indices on demand.
- Slight refactor of `_parallel_build_estimators()` to
isolate and group lines accessing random state.
* Replaced `BaseBagging.estimators_samples_` attribute with property.
- Accessing `BaseBagging.estimators_samples_` now triggers call to
`BaseBagging._get_estimators_samples` as well as deprecation
warning for release 0.20.
- This should make the fix for the OOB memory issue fully backwards
compatible.
* Remove print statement.
* Added test, made new method more general.
- Added test to `test_bagging.py` to ensure that indices generated
on the fly are identical to indices generated at fit time.
- Refactored `_get_estimators_samples()` to `_get_estimators_indices()`,
now both feature and samples indices are returned.
- Refactored `estimators_samples_()` to deal with above.
* Rename index generating functions and arguments.
* `estimators_samples_()` returns list instead of generator
* Removed `estimators_samples_` deprection warning.
* Actually removed `estimators_samples_` deprecation warning.
* New mask generation function, new bagging test, new BaseBagging attributes.
- Added new private function in bagging.py that converts indices to
a boolean mask.
- Added new bagging test to make sure identical OOB scores are generated
when the same estimator if fit with fixed random state and identical
training data.
- Added new private attributes `BaseBagging._max_features` and
`BaseBagging._max_samples` to store validated input values.
* Streamlined code, improved `estimators_samples_()` documentation.
- Removed `max_samples` argument from `_parallel_build_estimators()`,
this value is now accessed via `ensemble._max_samples`.
- Removed validation of `ensemble.max_features` and `max_samples`,
instead use `ensemble._max_features` and `ensemble._max_samples`
which are assumed to be already validated.
- Removed unnecessary `samples` variable from `_parallel_build_estimators()`.
- Changed the way `random_state` is generated in `_parallel_build_estimators()`
and `BaseBagging._get_estimators_data_draws()` to direct numpy method to
reflect that seeds created in `BaseBagging._fit()` are trustworthy.
- Due to above removed generation of new seed for each estimator in
`_parallel_build_estimators()` and `BaseBagging._get_estimators_data_draws()`.
- Added documentation to `BaseBagging.estimators_samples_()` property
indicating the reason it's generated dynamically and the associated performance
penalty.
- Returned `BaggingClassifier._set_oob_score()` and `BaggingRegressor._set_oob_score()`
to directly accessing `self.estimators_samples_`.
* Streamlined code, improved `estimators_samples_()` documentation.
- Removed `max_samples` argument from `_parallel_build_estimators()`,
this value is now accessed via `ensemble._max_samples`.
- Removed validation of `ensemble.max_features` and `max_samples`,
instead use `ensemble._max_features` and `ensemble._max_samples`
which are assumed to be already validated.
- Removed unnecessary `samples` variable from `_parallel_build_estimators()`.
- Changed the way `random_state` is generated in `_parallel_build_estimators()`
and `BaseBagging._get_estimators_data_draws()` to direct numpy method to
reflect that seeds created in `BaseBagging._fit()` are trustworthy.
- Due to above removed generation of new seed for each estimator in
`_parallel_build_estimators()` and `BaseBagging._get_estimators_data_draws()`.
- Added documentation to `BaseBagging.estimators_samples_()` property
indicating the reason it's generated dynamically and the associated performance
penalty.
- Returned `BaggingClassifier._set_oob_score()` and `BaggingRegressor._set_oob_score()`
to directly accessing `self.estimators_samples_`.
* PEP8, remove optional arguments, add public function to utils.
- Update indentation and line length to conform to PEP8.
- Update `estimators_samples_()` docstring to conform to PEP8 and
PEP257.
- Remove optional arguments to `BaseBagging._get_estimators_data_draws()`,
rename to `BaseBagging._get_estimators_indices()`.
- Remove optional arguments from `_generate_mask_from_indices()`,
move to `utils.metaestimators`, rename to `indices_to_mask()`.
* Add indices_to_mask to __all__ in utils.metaestimators
* Move utils function, new test for `estimators_samples` correctness.
- Moved `indices_to_mask` from `utils.metaestimators` to `utils.validation`
- Added new test to `ensemble.test_bagging` to make sure refitting
an individual estimator from the bagging ensemble using the corresponding
samples identified in `BaseBagging.estimators_samples` returns the same model.
* Adjust/remove tests, move `indices_to_mask` to `utils.__init__`.
- Remove test_bagging.test_consistent_index_sampling
- Update formatting checks in test_bagging.test_estimators_samples
to make sure each mask is numpy boolean array
- Move indices_to_mask from utils.validation to utils.__init__
* update class docstring for `estimators_samples_`
- Updated class docstring of `estimators_samples_` attribute for `BaggingClassifier` and `BaggingRegressor` to indicate that samples are identified with boolean masks.
* PEP8, made `max_samples` arg optional in _fit()
- Fixed PEP8 issues.
- Gave `max_samples` argument of `BaseBagging._fit()` a default
value of `None` as indicated in the docstring. Added code to
check for and process `None` value.
- Added a few more comments to `_fit()`.
* 2 new `max_samples` consistency tests, update whats_new.rst
* Minor change
* Update whats_new.rst
2016-08-23 14:59:32 +08:00
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
mask : 1d boolean nd-array
|
|
|
|
|
Boolean array that is True where indices are present, else False.
|
2018-03-05 14:59:31 +08:00
|
|
|
|
|
|
|
|
Examples
|
|
|
|
|
--------
|
|
|
|
|
>>> from sklearn.utils import indices_to_mask
|
|
|
|
|
>>> indices = [1, 2 , 3, 4]
|
|
|
|
|
>>> indices_to_mask(indices, 5)
|
2018-03-27 13:44:40 +08:00
|
|
|
array([False, True, True, True, True])
|
[MRG] Remove heavy memory footprint in BaseBagging due to OOB scoring (#7118)
* Remove heavy memory footprint for OOB scoring from bagging.
- Remove `estimators_samples` attribute from `BaseBagging`
- Add method `_get_estimators_samples` to `BaseBagging` that
returns a generator producing sample indices on demand.
- Slight refactor of `_parallel_build_estimators()` to
isolate and group lines accessing random state.
* Replaced `BaseBagging.estimators_samples_` attribute with property.
- Accessing `BaseBagging.estimators_samples_` now triggers call to
`BaseBagging._get_estimators_samples` as well as deprecation
warning for release 0.20.
- This should make the fix for the OOB memory issue fully backwards
compatible.
* Remove print statement.
* Added test, made new method more general.
- Added test to `test_bagging.py` to ensure that indices generated
on the fly are identical to indices generated at fit time.
- Refactored `_get_estimators_samples()` to `_get_estimators_indices()`,
now both feature and samples indices are returned.
- Refactored `estimators_samples_()` to deal with above.
* Rename index generating functions and arguments.
* `estimators_samples_()` returns list instead of generator
* Removed `estimators_samples_` deprection warning.
* Actually removed `estimators_samples_` deprecation warning.
* New mask generation function, new bagging test, new BaseBagging attributes.
- Added new private function in bagging.py that converts indices to
a boolean mask.
- Added new bagging test to make sure identical OOB scores are generated
when the same estimator if fit with fixed random state and identical
training data.
- Added new private attributes `BaseBagging._max_features` and
`BaseBagging._max_samples` to store validated input values.
* Streamlined code, improved `estimators_samples_()` documentation.
- Removed `max_samples` argument from `_parallel_build_estimators()`,
this value is now accessed via `ensemble._max_samples`.
- Removed validation of `ensemble.max_features` and `max_samples`,
instead use `ensemble._max_features` and `ensemble._max_samples`
which are assumed to be already validated.
- Removed unnecessary `samples` variable from `_parallel_build_estimators()`.
- Changed the way `random_state` is generated in `_parallel_build_estimators()`
and `BaseBagging._get_estimators_data_draws()` to direct numpy method to
reflect that seeds created in `BaseBagging._fit()` are trustworthy.
- Due to above removed generation of new seed for each estimator in
`_parallel_build_estimators()` and `BaseBagging._get_estimators_data_draws()`.
- Added documentation to `BaseBagging.estimators_samples_()` property
indicating the reason it's generated dynamically and the associated performance
penalty.
- Returned `BaggingClassifier._set_oob_score()` and `BaggingRegressor._set_oob_score()`
to directly accessing `self.estimators_samples_`.
* Streamlined code, improved `estimators_samples_()` documentation.
- Removed `max_samples` argument from `_parallel_build_estimators()`,
this value is now accessed via `ensemble._max_samples`.
- Removed validation of `ensemble.max_features` and `max_samples`,
instead use `ensemble._max_features` and `ensemble._max_samples`
which are assumed to be already validated.
- Removed unnecessary `samples` variable from `_parallel_build_estimators()`.
- Changed the way `random_state` is generated in `_parallel_build_estimators()`
and `BaseBagging._get_estimators_data_draws()` to direct numpy method to
reflect that seeds created in `BaseBagging._fit()` are trustworthy.
- Due to above removed generation of new seed for each estimator in
`_parallel_build_estimators()` and `BaseBagging._get_estimators_data_draws()`.
- Added documentation to `BaseBagging.estimators_samples_()` property
indicating the reason it's generated dynamically and the associated performance
penalty.
- Returned `BaggingClassifier._set_oob_score()` and `BaggingRegressor._set_oob_score()`
to directly accessing `self.estimators_samples_`.
* PEP8, remove optional arguments, add public function to utils.
- Update indentation and line length to conform to PEP8.
- Update `estimators_samples_()` docstring to conform to PEP8 and
PEP257.
- Remove optional arguments to `BaseBagging._get_estimators_data_draws()`,
rename to `BaseBagging._get_estimators_indices()`.
- Remove optional arguments from `_generate_mask_from_indices()`,
move to `utils.metaestimators`, rename to `indices_to_mask()`.
* Add indices_to_mask to __all__ in utils.metaestimators
* Move utils function, new test for `estimators_samples` correctness.
- Moved `indices_to_mask` from `utils.metaestimators` to `utils.validation`
- Added new test to `ensemble.test_bagging` to make sure refitting
an individual estimator from the bagging ensemble using the corresponding
samples identified in `BaseBagging.estimators_samples` returns the same model.
* Adjust/remove tests, move `indices_to_mask` to `utils.__init__`.
- Remove test_bagging.test_consistent_index_sampling
- Update formatting checks in test_bagging.test_estimators_samples
to make sure each mask is numpy boolean array
- Move indices_to_mask from utils.validation to utils.__init__
* update class docstring for `estimators_samples_`
- Updated class docstring of `estimators_samples_` attribute for `BaggingClassifier` and `BaggingRegressor` to indicate that samples are identified with boolean masks.
* PEP8, made `max_samples` arg optional in _fit()
- Fixed PEP8 issues.
- Gave `max_samples` argument of `BaseBagging._fit()` a default
value of `None` as indicated in the docstring. Added code to
check for and process `None` value.
- Added a few more comments to `_fit()`.
* 2 new `max_samples` consistency tests, update whats_new.rst
* Minor change
* Update whats_new.rst
2016-08-23 14:59:32 +08:00
|
|
|
"""
|
|
|
|
|
if mask_length <= np.max(indices):
|
|
|
|
|
raise ValueError("mask_length must be greater than max(indices)")
|
|
|
|
|
|
|
|
|
|
mask = np.zeros(mask_length, dtype=np.bool)
|
|
|
|
|
mask[indices] = True
|
|
|
|
|
|
|
|
|
|
return mask
|
2018-05-25 10:04:05 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_chunk_n_rows(row_bytes, max_n_rows=None,
|
|
|
|
|
working_memory=None):
|
|
|
|
|
"""Calculates how many rows can be processed within working_memory
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
row_bytes : int
|
|
|
|
|
The expected number of bytes of memory that will be consumed
|
|
|
|
|
during the processing of each row.
|
|
|
|
|
max_n_rows : int, optional
|
|
|
|
|
The maximum return value.
|
|
|
|
|
working_memory : int or float, optional
|
|
|
|
|
The number of rows to fit inside this number of MiB will be returned.
|
|
|
|
|
When None (default), the value of
|
|
|
|
|
``sklearn.get_config()['working_memory']`` is used.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
int or the value of n_samples
|
|
|
|
|
|
|
|
|
|
Warns
|
|
|
|
|
-----
|
|
|
|
|
Issues a UserWarning if ``row_bytes`` exceeds ``working_memory`` MiB.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
if working_memory is None:
|
|
|
|
|
working_memory = get_config()['working_memory']
|
|
|
|
|
|
|
|
|
|
chunk_n_rows = int(working_memory * (2 ** 20) // row_bytes)
|
|
|
|
|
if max_n_rows is not None:
|
|
|
|
|
chunk_n_rows = min(chunk_n_rows, max_n_rows)
|
|
|
|
|
if chunk_n_rows < 1:
|
|
|
|
|
warnings.warn('Could not adhere to working_memory config. '
|
|
|
|
|
'Currently %.0fMiB, %.0fMiB required.' %
|
|
|
|
|
(working_memory, np.ceil(row_bytes * 2 ** -20)))
|
|
|
|
|
chunk_n_rows = 1
|
|
|
|
|
return chunk_n_rows
|
2018-06-20 23:20:33 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_scalar_nan(x):
|
|
|
|
|
"""Tests if x is NaN
|
|
|
|
|
|
|
|
|
|
This function is meant to overcome the issue that np.isnan does not allow
|
|
|
|
|
non-numerical types as input, and that np.nan is not np.float('nan').
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
x : any type
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
boolean
|
|
|
|
|
|
|
|
|
|
Examples
|
|
|
|
|
--------
|
|
|
|
|
>>> is_scalar_nan(np.nan)
|
|
|
|
|
True
|
|
|
|
|
>>> is_scalar_nan(float("nan"))
|
|
|
|
|
True
|
|
|
|
|
>>> is_scalar_nan(None)
|
|
|
|
|
False
|
|
|
|
|
>>> is_scalar_nan("")
|
|
|
|
|
False
|
|
|
|
|
>>> is_scalar_nan([np.nan])
|
|
|
|
|
False
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# convert from numpy.bool_ to python bool to ensure that testing
|
|
|
|
|
# is_scalar_nan(x) is True does not fail.
|
|
|
|
|
# Redondant np.floating is needed because numbers can't match np.float32
|
|
|
|
|
# in python 2.
|
|
|
|
|
return bool(isinstance(x, (numbers.Real, np.floating)) and np.isnan(x))
|