2011-06-04 19:57:03 +08:00
|
|
|
.. _preprocessing:
|
|
|
|
|
|
|
|
|
|
==================
|
|
|
|
|
Preprocessing data
|
|
|
|
|
==================
|
|
|
|
|
|
2011-09-02 17:00:02 +08:00
|
|
|
.. currentmodule:: sklearn.preprocessing
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2011-09-02 17:00:02 +08:00
|
|
|
The ``sklearn.preprocessing`` package provides several common
|
2011-06-04 21:55:16 +08:00
|
|
|
utility functions and transformer classes to change raw feature vectors
|
|
|
|
|
into a representation that is more suitable for the downstream estimators.
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2011-08-11 00:51:40 +08:00
|
|
|
.. _preprocessing_scaler:
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2013-07-25 23:28:13 +08:00
|
|
|
Standardization, or mean removal and variance scaling
|
|
|
|
|
=====================================================
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2011-06-06 19:37:40 +08:00
|
|
|
**Standardization** of datasets is a **common requirement for many
|
2011-06-04 19:57:03 +08:00
|
|
|
machine learning estimators** implemented in the scikit: they might behave
|
|
|
|
|
badly if the individual feature do not more or less look like standard
|
|
|
|
|
normally distributed data: Gaussian with **zero mean and unit variance**.
|
|
|
|
|
|
|
|
|
|
In practice we often ignore the shape of the distribution and just
|
|
|
|
|
transform the data to center it by removing the mean value of each
|
2011-06-06 19:37:40 +08:00
|
|
|
feature, then scale it by dividing non-constant features by their
|
2011-06-04 19:57:03 +08:00
|
|
|
standard deviation.
|
|
|
|
|
|
2011-06-06 19:37:40 +08:00
|
|
|
For instance, many elements used in the objective function of
|
2011-06-04 19:57:03 +08:00
|
|
|
a learning algorithm (such as the RBF kernel of Support Vector
|
|
|
|
|
Machines or the l1 and l2 regularizers of linear models) assume that
|
|
|
|
|
all features are centered around zero and have variance in the same
|
|
|
|
|
order. If a feature has a variance that is orders of magnitude larger
|
|
|
|
|
that others, it might dominate the objective function and make the
|
|
|
|
|
estimator unable to learn from other features correctly as expected.
|
|
|
|
|
|
2011-12-18 18:11:56 +08:00
|
|
|
|
2011-06-04 19:57:03 +08:00
|
|
|
The function :func:`scale` provides a quick and easy way to perform this
|
|
|
|
|
operation on a single array-like dataset::
|
|
|
|
|
|
2011-09-02 17:00:02 +08:00
|
|
|
>>> from sklearn import preprocessing
|
2012-11-03 23:39:07 +08:00
|
|
|
>>> import numpy as np
|
|
|
|
|
>>> X = np.array([[ 1., -1., 2.],
|
|
|
|
|
... [ 2., 0., 0.],
|
|
|
|
|
... [ 0., 1., -1.]])
|
2011-06-04 19:57:03 +08:00
|
|
|
>>> X_scaled = preprocessing.scale(X)
|
|
|
|
|
|
|
|
|
|
>>> X_scaled # doctest: +ELLIPSIS
|
|
|
|
|
array([[ 0. ..., -1.22..., 1.33...],
|
|
|
|
|
[ 1.22..., 0. ..., -0.26...],
|
|
|
|
|
[-1.22..., 1.22..., -1.06...]])
|
|
|
|
|
|
2011-12-27 17:42:22 +08:00
|
|
|
..
|
2011-12-18 18:11:56 +08:00
|
|
|
>>> import numpy as np
|
|
|
|
|
>>> print_options = np.get_printoptions()
|
|
|
|
|
>>> np.set_printoptions(suppress=True)
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2011-12-18 18:40:01 +08:00
|
|
|
Scaled data has zero mean and unit variance::
|
|
|
|
|
|
2011-06-04 19:57:03 +08:00
|
|
|
>>> X_scaled.mean(axis=0)
|
|
|
|
|
array([ 0., 0., 0.])
|
|
|
|
|
|
|
|
|
|
>>> X_scaled.std(axis=0)
|
|
|
|
|
array([ 1., 1., 1.])
|
|
|
|
|
|
2011-12-18 18:40:01 +08:00
|
|
|
.. >>> print_options = np.set_printoptions(print_options)
|
2011-12-18 18:11:56 +08:00
|
|
|
|
2011-06-04 21:02:52 +08:00
|
|
|
The ``preprocessing`` module further provides a utility class
|
2012-09-23 19:58:12 +08:00
|
|
|
:class:`StandardScaler` that implements the ``Transformer`` API to compute
|
2011-06-04 21:02:52 +08:00
|
|
|
the mean and standard deviation on a training set so as to be
|
|
|
|
|
able to later reapply the same transformation on the testing set.
|
|
|
|
|
This class is hence suitable for use in the early steps of a
|
2011-09-02 17:00:02 +08:00
|
|
|
:class:`sklearn.pipeline.Pipeline`::
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2012-09-23 19:58:12 +08:00
|
|
|
>>> scaler = preprocessing.StandardScaler().fit(X)
|
2011-06-04 21:02:52 +08:00
|
|
|
>>> scaler
|
2012-09-23 19:58:12 +08:00
|
|
|
StandardScaler(copy=True, with_mean=True, with_std=True)
|
2011-06-04 21:02:52 +08:00
|
|
|
|
2011-06-04 19:57:03 +08:00
|
|
|
>>> scaler.mean_ # doctest: +ELLIPSIS
|
|
|
|
|
array([ 1. ..., 0. ..., 0.33...])
|
|
|
|
|
|
|
|
|
|
>>> scaler.std_ # doctest: +ELLIPSIS
|
|
|
|
|
array([ 0.81..., 0.81..., 1.24...])
|
|
|
|
|
|
2011-06-04 21:02:52 +08:00
|
|
|
>>> scaler.transform(X) # doctest: +ELLIPSIS
|
|
|
|
|
array([[ 0. ..., -1.22..., 1.33...],
|
|
|
|
|
[ 1.22..., 0. ..., -0.26...],
|
|
|
|
|
[-1.22..., 1.22..., -1.06...]])
|
|
|
|
|
|
|
|
|
|
|
2011-06-04 19:57:03 +08:00
|
|
|
The scaler instance can then be used on new data to transform it the
|
|
|
|
|
same way it did on the training set::
|
|
|
|
|
|
|
|
|
|
>>> scaler.transform([[-1., 1., 0.]]) # doctest: +ELLIPSIS
|
|
|
|
|
array([[-2.44..., 1.22..., -0.26...]])
|
|
|
|
|
|
2011-06-04 21:02:52 +08:00
|
|
|
It is possible to disable either centering or scaling by either
|
|
|
|
|
passing ``with_mean=False`` or ``with_std=False`` to the constructor
|
2012-09-23 19:58:12 +08:00
|
|
|
of :class:`StandardScaler`.
|
2011-06-04 21:02:52 +08:00
|
|
|
|
|
|
|
|
|
2013-07-25 23:28:13 +08:00
|
|
|
Scaling features to a range
|
2012-11-03 23:39:07 +08:00
|
|
|
---------------------------
|
|
|
|
|
An alternative standardization is scaling features to
|
|
|
|
|
lie between a given minimum and maximum value, often between zero and one.
|
|
|
|
|
This can be achieved using :class:`MinMaxScaler`.
|
|
|
|
|
|
|
|
|
|
The motivation to use this scaling include robustness to very small
|
|
|
|
|
standard deviations of features and preserving zero entries in sparse data.
|
|
|
|
|
|
2012-11-17 01:46:44 +08:00
|
|
|
Here is an example to scale a toy data matrix to the ``[0, 1]`` range::
|
2012-11-03 23:39:07 +08:00
|
|
|
|
2012-11-17 20:46:42 +08:00
|
|
|
>>> X_train = np.array([[ 1., -1., 2.],
|
|
|
|
|
... [ 2., 0., 0.],
|
|
|
|
|
... [ 0., 1., -1.]])
|
2012-11-17 01:46:44 +08:00
|
|
|
...
|
2012-11-03 23:39:07 +08:00
|
|
|
>>> min_max_scaler = preprocessing.MinMaxScaler()
|
2012-11-17 20:46:42 +08:00
|
|
|
>>> X_train_minmax = min_max_scaler.fit_transform(X_train)
|
|
|
|
|
>>> X_train_minmax
|
2012-11-14 18:54:24 +08:00
|
|
|
array([[ 0.5 , 0. , 1. ],
|
|
|
|
|
[ 1. , 0.5 , 0.33333333],
|
|
|
|
|
[ 0. , 1. , 0. ]])
|
|
|
|
|
|
2012-11-17 20:46:42 +08:00
|
|
|
The same instance of the transformer can then be applied to some new test data
|
|
|
|
|
unseen during the fit call: the same scaling and shifting operations will be
|
|
|
|
|
applied to be consistent with the transformation performed on the train data::
|
2012-11-17 01:46:44 +08:00
|
|
|
|
2012-11-17 20:46:42 +08:00
|
|
|
>>> X_test = np.array([[ -3., -1., 4.]])
|
|
|
|
|
>>> X_test_minmax = min_max_scaler.transform(X_test)
|
|
|
|
|
>>> X_test_minmax
|
2012-11-14 18:54:24 +08:00
|
|
|
array([[-1.5 , 0. , 1.66666667]])
|
2012-11-03 23:39:07 +08:00
|
|
|
|
2012-11-17 20:46:42 +08:00
|
|
|
It is possible to introspect the scaler attributes to find about the exact
|
|
|
|
|
nature of the transformation learned on the training data::
|
|
|
|
|
|
|
|
|
|
>>> min_max_scaler.scale_ # doctest: +ELLIPSIS
|
|
|
|
|
array([ 0.5 , 0.5 , 0.33...])
|
|
|
|
|
|
|
|
|
|
>>> min_max_scaler.min_ # doctest: +ELLIPSIS
|
|
|
|
|
array([ 0. , 0.5 , 0.33...])
|
|
|
|
|
|
|
|
|
|
If :class:`MinMaxScaler` is given an explicit ``feature_range=(min, max)`` the
|
|
|
|
|
full formula is::
|
2012-11-03 23:39:07 +08:00
|
|
|
|
2012-11-17 20:46:42 +08:00
|
|
|
X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
|
2012-11-03 23:39:07 +08:00
|
|
|
|
2012-11-17 20:46:42 +08:00
|
|
|
X_scaled = X_std / (max - min) + min
|
2012-11-03 23:39:07 +08:00
|
|
|
|
2011-06-04 19:57:03 +08:00
|
|
|
.. topic:: References:
|
|
|
|
|
|
|
|
|
|
Further discussion on the importance of centering and scaling data is
|
2011-06-04 20:12:56 +08:00
|
|
|
available on this FAQ: `Should I normalize/standardize/rescale the data?
|
2011-06-04 19:57:03 +08:00
|
|
|
<http://www.faqs.org/faqs/ai-faq/neural-nets/part2/section-16.html>`_
|
|
|
|
|
|
2011-12-27 17:42:22 +08:00
|
|
|
.. topic:: Scaling vs Whitening
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2011-12-27 17:42:22 +08:00
|
|
|
It is sometimes not enough to center and scale the features
|
2011-12-28 22:26:36 +08:00
|
|
|
independently, since a downstream model can further make some assumption
|
2011-12-28 17:45:02 +08:00
|
|
|
on the linear independence of the features.
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2011-09-02 17:00:02 +08:00
|
|
|
To address this issue you can use :class:`sklearn.decomposition.PCA`
|
|
|
|
|
or :class:`sklearn.decomposition.RandomizedPCA` with ``whiten=True``
|
2011-06-04 19:57:03 +08:00
|
|
|
to further remove the linear correlation across features.
|
|
|
|
|
|
2011-12-27 17:42:22 +08:00
|
|
|
.. topic:: Sparse input
|
|
|
|
|
|
2012-09-23 19:58:12 +08:00
|
|
|
:func:`scale` and :class:`StandardScaler` accept ``scipy.sparse`` matrices
|
2011-12-28 17:45:02 +08:00
|
|
|
as input **only when with_mean=False is explicitly passed to the
|
2011-12-28 22:01:19 +08:00
|
|
|
constructor**. Otherwise a ``ValueError`` will be raised as
|
2011-12-27 17:42:22 +08:00
|
|
|
silently centering would break the sparsity and would often crash the
|
2011-12-28 22:01:19 +08:00
|
|
|
execution by allocating excessive amounts of memory unintentionally.
|
2011-12-27 17:42:22 +08:00
|
|
|
|
|
|
|
|
If the centered data is expected to be small enough, explicitly convert
|
|
|
|
|
the input to an array using the ``toarray`` method of sparse matrices
|
|
|
|
|
instead.
|
|
|
|
|
|
|
|
|
|
For sparse input the data is **converted to the Compressed Sparse Rows
|
|
|
|
|
representation** (see ``scipy.sparse.csr_matrix``).
|
|
|
|
|
To avoid unnecessary memory copies, it is recommended to choose the CSR
|
|
|
|
|
representation upstream.
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2012-02-01 19:54:08 +08:00
|
|
|
.. topic:: Scaling target variables in regression
|
|
|
|
|
|
2012-09-23 19:58:12 +08:00
|
|
|
:func:`scale` and :class:`StandardScaler` work out-of-the-box with 1d arrays.
|
2012-02-01 19:54:08 +08:00
|
|
|
This is very useful for scaling the target / response variables used
|
|
|
|
|
for regression.
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2013-07-25 23:31:14 +08:00
|
|
|
|
|
|
|
|
Centering kernel matrices
|
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
|
|
If you have a kernel matrix of a kernel :math:`K` that computes a dot product
|
|
|
|
|
in a feature space defined by function :math:`phi`,
|
|
|
|
|
a :class:`KernelCenterer` can transform the kernel matrix
|
|
|
|
|
so that it contains inner products in the feature space
|
|
|
|
|
defined by :math:`phi` followed by removal of the mean in that space.
|
|
|
|
|
|
|
|
|
|
|
2011-06-04 19:57:03 +08:00
|
|
|
Normalization
|
|
|
|
|
=============
|
|
|
|
|
|
2011-06-06 19:37:40 +08:00
|
|
|
**Normalization** is the process of **scaling individual samples to have
|
|
|
|
|
unit norm**. This process can be useful if you plan to use a quadratic form
|
|
|
|
|
such as the dot-product or any other kernel to quantify the similarity
|
2011-06-04 21:02:52 +08:00
|
|
|
of any pair of samples.
|
|
|
|
|
|
|
|
|
|
This assumption is the base of the `Vector Space Model
|
|
|
|
|
<http://en.wikipedia.org/wiki/Vector_Space_Model>`_ often used in text
|
|
|
|
|
classification and clustering contexts.
|
|
|
|
|
|
|
|
|
|
The function :func:`normalize` provides a quick and easy way to perform this
|
|
|
|
|
operation on a single array-like dataset, either using the ``l1`` or ``l2``
|
|
|
|
|
norms::
|
|
|
|
|
|
|
|
|
|
>>> X = [[ 1., -1., 2.],
|
|
|
|
|
... [ 2., 0., 0.],
|
|
|
|
|
... [ 0., 1., -1.]]
|
|
|
|
|
>>> X_normalized = preprocessing.normalize(X, norm='l2')
|
|
|
|
|
|
|
|
|
|
>>> X_normalized # doctest: +ELLIPSIS
|
|
|
|
|
array([[ 0.40..., -0.40..., 0.81...],
|
|
|
|
|
[ 1. ..., 0. ..., 0. ...],
|
|
|
|
|
[ 0. ..., 0.70..., -0.70...]])
|
|
|
|
|
|
|
|
|
|
The ``preprocessing`` module further provides a utility class
|
|
|
|
|
:class:`Normalizer` that implements the same operation using the
|
2011-06-06 19:37:40 +08:00
|
|
|
``Transformer`` API (even though the ``fit`` method is useless in this case:
|
|
|
|
|
the class is stateless as this operation treats samples independently).
|
2011-06-04 21:02:52 +08:00
|
|
|
|
|
|
|
|
This class is hence suitable for use in the early steps of a
|
2011-09-02 17:00:02 +08:00
|
|
|
:class:`sklearn.pipeline.Pipeline`::
|
2011-06-04 21:02:52 +08:00
|
|
|
|
|
|
|
|
>>> normalizer = preprocessing.Normalizer().fit(X) # fit does nothing
|
|
|
|
|
>>> normalizer
|
|
|
|
|
Normalizer(copy=True, norm='l2')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The normalizer instance can then be used on sample vectors as any transformer::
|
|
|
|
|
|
|
|
|
|
>>> normalizer.transform(X) # doctest: +ELLIPSIS
|
|
|
|
|
array([[ 0.40..., -0.40..., 0.81...],
|
|
|
|
|
[ 1. ..., 0. ..., 0. ...],
|
|
|
|
|
[ 0. ..., 0.70..., -0.70...]])
|
|
|
|
|
|
|
|
|
|
>>> normalizer.transform([[-1., 1., 0.]]) # doctest: +ELLIPSIS
|
|
|
|
|
array([[-0.70..., 0.70..., 0. ...]])
|
|
|
|
|
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2011-12-27 17:42:22 +08:00
|
|
|
.. topic:: Sparse input
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2011-06-06 19:37:40 +08:00
|
|
|
:func:`normalize` and :class:`Normalizer` accept **both dense array-like
|
|
|
|
|
and sparse matrices from scipy.sparse as input**.
|
2011-06-04 19:57:03 +08:00
|
|
|
|
|
|
|
|
For sparse input the data is **converted to the Compressed Sparse Rows
|
|
|
|
|
representation** (see ``scipy.sparse.csr_matrix``) before being fed to
|
2011-06-06 19:37:40 +08:00
|
|
|
efficient Cython routines. To avoid unnecessary memory copies, it is
|
2011-06-06 20:28:10 +08:00
|
|
|
recommended to choose the CSR representation upstream.
|
2011-06-04 19:57:03 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
Binarization
|
|
|
|
|
============
|
|
|
|
|
|
|
|
|
|
Feature binarization
|
|
|
|
|
--------------------
|
|
|
|
|
|
2011-06-04 21:55:16 +08:00
|
|
|
**Feature binarization** is the process of **thresholding numerical
|
2013-06-27 21:09:16 +08:00
|
|
|
features to get boolean values**. This can be useful for downstream
|
2011-06-04 21:55:16 +08:00
|
|
|
probabilistic estimators that make assumption that the input data
|
|
|
|
|
is distributed according to a multi-variate `Bernoulli distribution
|
2011-06-06 19:37:40 +08:00
|
|
|
<http://en.wikipedia.org/wiki/Bernoulli_distribution>`_. For instance,
|
2013-08-13 23:31:40 +08:00
|
|
|
this is the case for the :class:`sklearn.neural_network.BernoulliRBM`.
|
2011-06-04 21:55:16 +08:00
|
|
|
|
2013-06-27 21:09:16 +08:00
|
|
|
It is also common among the text processing community to use binary
|
2011-06-04 21:55:16 +08:00
|
|
|
feature values (probably to simplify the probabilistic reasoning) even
|
|
|
|
|
if normalized counts (a.k.a. term frequencies) or TF-IDF valued features
|
|
|
|
|
often perform slightly better in practice.
|
|
|
|
|
|
|
|
|
|
As for the :class:`Normalizer`, the utility class
|
|
|
|
|
:class:`Binarizer` is meant to be used in the early stages of
|
2011-09-02 17:00:02 +08:00
|
|
|
:class:`sklearn.pipeline.Pipeline`. The ``fit`` method does nothing
|
2011-06-04 21:55:16 +08:00
|
|
|
as each sample is treated independently of others::
|
|
|
|
|
|
|
|
|
|
>>> X = [[ 1., -1., 2.],
|
|
|
|
|
... [ 2., 0., 0.],
|
|
|
|
|
... [ 0., 1., -1.]]
|
|
|
|
|
|
|
|
|
|
>>> binarizer = preprocessing.Binarizer().fit(X) # fit does nothing
|
|
|
|
|
>>> binarizer
|
2011-08-24 22:05:31 +08:00
|
|
|
Binarizer(copy=True, threshold=0.0)
|
2011-06-04 21:55:16 +08:00
|
|
|
|
|
|
|
|
>>> binarizer.transform(X)
|
|
|
|
|
array([[ 1., 0., 1.],
|
|
|
|
|
[ 1., 0., 0.],
|
|
|
|
|
[ 0., 1., 0.]])
|
|
|
|
|
|
|
|
|
|
It is possible to adjust the threshold of the binarizer::
|
|
|
|
|
|
|
|
|
|
>>> binarizer = preprocessing.Binarizer(threshold=1.1)
|
|
|
|
|
>>> binarizer.transform(X)
|
|
|
|
|
array([[ 0., 0., 1.],
|
|
|
|
|
[ 1., 0., 0.],
|
|
|
|
|
[ 0., 0., 0.]])
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2012-09-23 19:58:12 +08:00
|
|
|
As for the :class:`StandardScaler` and :class:`Normalizer` classes, the
|
2011-06-04 22:14:01 +08:00
|
|
|
preprocessing module provides a companion function :func:`binarize`
|
|
|
|
|
to be used when the transformer API is not necessary.
|
|
|
|
|
|
2011-12-27 17:42:22 +08:00
|
|
|
.. topic:: Sparse input
|
2011-06-04 19:57:03 +08:00
|
|
|
|
2011-06-06 19:37:40 +08:00
|
|
|
:func:`binarize` and :class:`Binarizer` accept **both dense array-like
|
|
|
|
|
and sparse matrices from scipy.sparse as input**.
|
2011-06-04 20:23:24 +08:00
|
|
|
|
|
|
|
|
For sparse input the data is **converted to the Compressed Sparse Rows
|
|
|
|
|
representation** (see ``scipy.sparse.csr_matrix``).
|
2011-06-06 19:37:40 +08:00
|
|
|
To avoid unnecessary memory copies, it is recommended to choose the CSR
|
2011-06-06 20:28:10 +08:00
|
|
|
representation upstream.
|
2011-06-04 20:23:24 +08:00
|
|
|
|
2012-10-26 04:07:02 +08:00
|
|
|
|
2013-01-20 21:23:29 +08:00
|
|
|
.. _preprocessing_categorical_features:
|
|
|
|
|
|
2012-11-07 20:32:16 +08:00
|
|
|
Encoding categorical features
|
|
|
|
|
=============================
|
2012-10-26 04:57:53 +08:00
|
|
|
Often features are not given as continuous values but categorical.
|
2012-11-07 20:32:16 +08:00
|
|
|
For example a person could have features ``["male", "female"]``,
|
|
|
|
|
``["from Europe", "from US", "from Asia"]``,
|
2012-10-26 04:07:02 +08:00
|
|
|
``["uses Firefox", "uses Chrome", "uses Safari", "uses Internet Explorer"]``.
|
2012-10-26 17:14:35 +08:00
|
|
|
Such features can be efficiently coded as integers, for instance
|
2012-11-07 20:32:16 +08:00
|
|
|
``["male", "from US", "uses Internet Explorer"]`` could be expressed as
|
|
|
|
|
``[0, 1, 3]`` while ``["female", "from Asia", "uses Chrome"]`` would be
|
|
|
|
|
``[1, 2, 1]``.
|
2012-10-26 04:07:02 +08:00
|
|
|
|
|
|
|
|
Such integer representation can not be used directly with scikit-learn estimators, as these
|
|
|
|
|
expect continuous input, and would interpret the categories as being ordered, which is often
|
2012-10-26 17:14:35 +08:00
|
|
|
not desired (i.e. the set of browsers was ordered arbitrarily).
|
2012-10-26 04:07:02 +08:00
|
|
|
|
2012-10-26 04:57:53 +08:00
|
|
|
One possibility to convert categorical features to features that can be used
|
2012-10-26 04:07:02 +08:00
|
|
|
with scikit-learn estimators is to use a one-of-K or one-hot encoding, which is
|
|
|
|
|
implemented in :class:`OneHotEncoder`. This estimator transforms each
|
2012-10-26 04:57:53 +08:00
|
|
|
categorical feature with ``m`` possible values into ``m`` binary features, with
|
2012-10-26 04:07:02 +08:00
|
|
|
only one active.
|
|
|
|
|
|
|
|
|
|
Continuing the example above::
|
2012-10-26 04:57:53 +08:00
|
|
|
|
2012-10-26 17:56:45 +08:00
|
|
|
>>> enc = preprocessing.OneHotEncoder()
|
2013-07-11 01:01:41 +08:00
|
|
|
>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]]) # doctest: +ELLIPSIS
|
|
|
|
|
OneHotEncoder(categorical_features='all', dtype=<... 'float'>,
|
2013-06-05 18:56:33 +08:00
|
|
|
n_values='auto')
|
2012-10-26 04:57:53 +08:00
|
|
|
>>> enc.transform([[0, 1, 3]]).toarray()
|
2012-10-26 05:11:53 +08:00
|
|
|
array([[ 1., 0., 0., 1., 0., 0., 0., 0., 1.]])
|
2012-10-26 04:07:02 +08:00
|
|
|
|
2012-10-26 17:56:45 +08:00
|
|
|
By default, how many values each feature can take is inferred automatically from the dataset.
|
2013-06-05 18:56:33 +08:00
|
|
|
It is possible to specify this explicitly using the parameter ``n_values``.
|
2012-10-26 17:14:35 +08:00
|
|
|
There are two genders, three possible continents and four web browsers in our
|
|
|
|
|
dataset.
|
2013-06-05 18:56:33 +08:00
|
|
|
Then we fit the estimator, and transform a data point.
|
2012-10-26 04:07:02 +08:00
|
|
|
In the result, the first two numbers encode the gender, the next set of three
|
|
|
|
|
numbers the continent and the last four the web browser.
|
|
|
|
|
|
2012-10-26 04:57:53 +08:00
|
|
|
See :ref:`dict_feature_extraction` for categorical features that are represented
|
2012-10-26 04:07:02 +08:00
|
|
|
as a dict, not as integers.
|
|
|
|
|
|
|
|
|
|
|
2012-05-07 17:44:29 +08:00
|
|
|
Label preprocessing
|
|
|
|
|
===================
|
|
|
|
|
|
|
|
|
|
Label binarization
|
|
|
|
|
------------------
|
|
|
|
|
|
|
|
|
|
:class:`LabelBinarizer` is a utility class to help create a label indicator
|
|
|
|
|
matrix from a list of multi-class labels::
|
|
|
|
|
|
2012-05-07 18:04:16 +08:00
|
|
|
>>> lb = preprocessing.LabelBinarizer()
|
|
|
|
|
>>> lb.fit([1, 2, 6, 4, 2])
|
2012-05-07 17:44:29 +08:00
|
|
|
LabelBinarizer(neg_label=0, pos_label=1)
|
2012-05-07 18:04:16 +08:00
|
|
|
>>> lb.classes_
|
2012-05-07 17:44:29 +08:00
|
|
|
array([1, 2, 4, 6])
|
2012-05-07 18:04:16 +08:00
|
|
|
>>> lb.transform([1, 6])
|
2012-07-26 05:04:38 +08:00
|
|
|
array([[1, 0, 0, 0],
|
|
|
|
|
[0, 0, 0, 1]])
|
2012-05-07 17:44:29 +08:00
|
|
|
|
|
|
|
|
:class:`LabelBinarizer` also supports multiple labels per instance::
|
|
|
|
|
|
2012-05-07 18:04:16 +08:00
|
|
|
>>> lb.fit_transform([(1, 2), (3,)])
|
2012-07-26 05:04:38 +08:00
|
|
|
array([[1, 1, 0],
|
|
|
|
|
[0, 0, 1]])
|
2012-05-07 18:04:16 +08:00
|
|
|
>>> lb.classes_
|
2012-05-07 17:44:29 +08:00
|
|
|
array([1, 2, 3])
|
2011-06-04 22:14:01 +08:00
|
|
|
|
2012-05-09 20:24:22 +08:00
|
|
|
Label encoding
|
|
|
|
|
--------------
|
2012-05-07 17:44:29 +08:00
|
|
|
|
2012-05-09 21:04:46 +08:00
|
|
|
:class:`LabelEncoder` is a utility class to help normalize labels such that
|
|
|
|
|
they contain only values between 0 and n_classes-1. This is sometimes useful
|
|
|
|
|
for writing efficient Cython routines. :class:`LabelEncoder` can be used as
|
|
|
|
|
follows::
|
2012-05-07 17:44:29 +08:00
|
|
|
|
2012-05-09 20:43:21 +08:00
|
|
|
>>> from sklearn import preprocessing
|
2012-05-09 20:24:22 +08:00
|
|
|
>>> le = preprocessing.LabelEncoder()
|
|
|
|
|
>>> le.fit([1, 2, 2, 6])
|
|
|
|
|
LabelEncoder()
|
|
|
|
|
>>> le.classes_
|
2012-05-07 17:44:29 +08:00
|
|
|
array([1, 2, 6])
|
2012-05-09 20:24:22 +08:00
|
|
|
>>> le.transform([1, 1, 2, 6])
|
2012-05-07 17:44:29 +08:00
|
|
|
array([0, 0, 1, 2])
|
2012-05-09 20:24:22 +08:00
|
|
|
>>> le.inverse_transform([0, 0, 1, 2])
|
2012-05-07 17:44:29 +08:00
|
|
|
array([1, 1, 2, 6])
|
|
|
|
|
|
2012-05-09 20:43:21 +08:00
|
|
|
It can also be used to transform non-numerical labels (as long as they are
|
|
|
|
|
hashable and comparable) to numerical labels::
|
|
|
|
|
|
|
|
|
|
>>> le = preprocessing.LabelEncoder()
|
|
|
|
|
>>> le.fit(["paris", "paris", "tokyo", "amsterdam"])
|
|
|
|
|
LabelEncoder()
|
|
|
|
|
>>> list(le.classes_)
|
|
|
|
|
['amsterdam', 'paris', 'tokyo']
|
|
|
|
|
>>> le.transform(["tokyo", "tokyo", "paris"])
|
|
|
|
|
array([2, 2, 1])
|
|
|
|
|
>>> list(le.inverse_transform([2, 2, 1]))
|
|
|
|
|
['tokyo', 'tokyo', 'paris']
|
|
|
|
|
|
2012-05-07 17:44:29 +08:00
|
|
|
|
2013-07-09 17:12:17 +08:00
|
|
|
Imputation of missing values
|
|
|
|
|
============================
|
|
|
|
|
|
|
|
|
|
For various reasons, many real world datasets contain missing values, often
|
2013-07-25 23:28:13 +08:00
|
|
|
encoded as blanks, NaNs or other placeholders. Such datasets however are
|
2013-07-09 17:12:17 +08:00
|
|
|
incompatible with scikit-learn estimators which assume that all values in an
|
|
|
|
|
array are numerical, and that all have and hold meaning. A basic strategy to use
|
|
|
|
|
incomplete datasets is to discard entire rows and/or columns containing missing
|
2013-07-25 23:28:13 +08:00
|
|
|
values. However, this comes at the price of losing data which may be valuable
|
2013-07-09 17:12:17 +08:00
|
|
|
(even though incomplete). A better strategy is to impute the missing values,
|
|
|
|
|
i.e., to infer them from the known part of the data.
|
|
|
|
|
|
|
|
|
|
The :class:`Imputer` class provides basic strategies for imputing missing
|
|
|
|
|
values, either using the mean, the median or the most frequent value of
|
|
|
|
|
the row or column in which the missing values are located. This class
|
2013-07-25 19:00:46 +08:00
|
|
|
also allows for different missing values encodings.
|
2013-07-09 17:12:17 +08:00
|
|
|
|
2013-07-25 19:00:46 +08:00
|
|
|
The following snippet demonstrates how to replace missing values,
|
2013-07-25 23:28:13 +08:00
|
|
|
encoded as ``np.nan``, using the mean value of the columns (axis 0)
|
|
|
|
|
that contain the missing values::
|
2013-07-09 17:12:17 +08:00
|
|
|
|
|
|
|
|
>>> import numpy as np
|
|
|
|
|
>>> from sklearn.preprocessing import Imputer
|
2013-07-25 18:09:01 +08:00
|
|
|
>>> imp = Imputer(missing_values='NaN', strategy='mean', axis=0)
|
2013-07-09 17:12:17 +08:00
|
|
|
>>> imp.fit([[1, 2], [np.nan, 3], [7, 6]])
|
2013-07-25 18:09:01 +08:00
|
|
|
Imputer(axis=0, copy=True, missing_values='NaN', strategy='mean', verbose=0)
|
2013-07-09 17:12:17 +08:00
|
|
|
>>> X = [[np.nan, 2], [6, np.nan], [7, 6]]
|
|
|
|
|
>>> print(imp.transform(X))
|
|
|
|
|
[[ 4. 2. ]
|
|
|
|
|
[ 6. 3.66666667]
|
|
|
|
|
[ 7. 6. ]]
|
|
|
|
|
|
2013-07-25 23:28:13 +08:00
|
|
|
The :class:`Imputer` class also supports sparse matrices::
|
2013-07-09 17:12:17 +08:00
|
|
|
|
|
|
|
|
>>> import scipy.sparse as sp
|
|
|
|
|
>>> X = sp.csc_matrix([[1, 2], [0, 3], [7, 6]])
|
|
|
|
|
>>> imp = Imputer(missing_values=0, strategy='mean', axis=0)
|
|
|
|
|
>>> imp.fit(X)
|
|
|
|
|
Imputer(axis=0, copy=True, missing_values=0, strategy='mean', verbose=0)
|
2013-07-25 19:00:46 +08:00
|
|
|
>>> X_test = sp.csc_matrix([[0, 2], [6, 0], [7, 6]])
|
|
|
|
|
>>> print(imp.transform(X_test))
|
2013-07-09 17:12:17 +08:00
|
|
|
[[ 4. 2. ]
|
|
|
|
|
[ 6. 3.66666667]
|
|
|
|
|
[ 7. 6. ]]
|
|
|
|
|
|
|
|
|
|
Note that, here, missing values are encoded by 0 and are thus implicitly stored
|
|
|
|
|
in the matrix. This format is thus suitable when there are many more missing
|
|
|
|
|
values than observed values.
|
|
|
|
|
|
2013-07-25 23:28:13 +08:00
|
|
|
:class:`Imputer` can be used in a Pipeline as a way to build a composite
|
2013-07-25 20:31:05 +08:00
|
|
|
estimator that supports imputation. See :ref:`example_imputation.py`
|