0% found this document useful (0 votes)
2K views2,387 pages

Scikit Learn Docs PDF

Uploaded by

sailusha
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2K views2,387 pages

Scikit Learn Docs PDF

Uploaded by

sailusha
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 2387

scikit-learn user guide

Release 0.20.3

scikit-learn developers

Mar 01, 2019


CONTENTS

1 Welcome to scikit-learn 1
1.1 Installing scikit-learn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Frequently Asked Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.4 Related Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.5 About us . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.6 Who is using scikit-learn? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.7 Release History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.8 Version 0.20.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.9 Version 0.20.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.10 Version 0.20.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.11 Version 0.20.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.12 Version 0.19.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
1.13 Version 0.19.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
1.14 Version 0.19 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
1.15 Previous Releases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

2 scikit-learn Tutorials 129


2.1 An introduction to machine learning with scikit-learn . . . . . . . . . . . . . . . . . . . . . . . . . . 129
2.2 A tutorial on statistical-learning for scientific data processing . . . . . . . . . . . . . . . . . . . . . 135
2.3 Working With Text Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
2.4 Choosing the right estimator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
2.5 External Resources, Videos and Talks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171

3 User Guide 173


3.1 Supervised learning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
3.2 Unsupervised learning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
3.3 Model selection and evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
3.4 Dataset transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535
3.5 Dataset loading utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583
3.6 Computing with scikit-learn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608

4 Glossary of Common Terms and API Elements 623


4.1 General Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 623
4.2 Class APIs and Estimator Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 631
4.3 Target Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634
4.4 Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636
4.5 Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 638
4.6 Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641
4.7 Data and sample properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642

i
5 Examples 643
5.1 Miscellaneous examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643
5.2 Examples based on real world datasets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678
5.3 Biclustering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 739
5.4 Calibration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751
5.5 Classification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769
5.6 Clustering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 784
5.7 Pipelines and composite estimators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866
5.8 Covariance estimation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 901
5.9 Cross decomposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 916
5.10 Dataset examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 920
5.11 Decomposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 929
5.12 Ensemble methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 975
5.13 Tutorial exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1030
5.14 Feature Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038
5.15 Gaussian Process for Machine Learning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1048
5.16 Generalized Linear Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1077
5.17 Manifold learning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1164
5.18 Gaussian Mixture Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1193
5.19 Model Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1210
5.20 Multioutput methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1258
5.21 Nearest Neighbors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1261
5.22 Neural Networks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1283
5.23 Preprocessing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1296
5.24 Semi Supervised Classification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1322
5.25 Support Vector Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1334
5.26 Working with text documents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1365
5.27 Decision Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1382

6 API Reference 1393


6.1 sklearn.base: Base classes and utility functions . . . . . . . . . . . . . . . . . . . . . . . . . . 1393
6.2 sklearn.calibration: Probability Calibration . . . . . . . . . . . . . . . . . . . . . . . . . . 1400
6.3 sklearn.cluster: Clustering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1404
6.4 sklearn.cluster.bicluster: Biclustering . . . . . . . . . . . . . . . . . . . . . . . . . . . 1443
6.5 sklearn.compose: Composite Estimators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1450
6.6 sklearn.covariance: Covariance Estimators . . . . . . . . . . . . . . . . . . . . . . . . . . . 1457
6.7 sklearn.cross_decomposition: Cross decomposition . . . . . . . . . . . . . . . . . . . . 1488
6.8 sklearn.datasets: Datasets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1501
6.9 sklearn.decomposition: Matrix Decomposition . . . . . . . . . . . . . . . . . . . . . . . . 1546
6.10 sklearn.discriminant_analysis: Discriminant Analysis . . . . . . . . . . . . . . . . . . 1598
6.11 sklearn.dummy: Dummy estimators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1606
6.12 sklearn.ensemble: Ensemble Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1611
6.13 sklearn.exceptions: Exceptions and warnings . . . . . . . . . . . . . . . . . . . . . . . . . 1641
6.14 sklearn.feature_extraction: Feature Extraction . . . . . . . . . . . . . . . . . . . . . . . 1646
6.15 sklearn.feature_selection: Feature Selection . . . . . . . . . . . . . . . . . . . . . . . . 1673
6.16 sklearn.gaussian_process: Gaussian Processes . . . . . . . . . . . . . . . . . . . . . . . . 1708
6.17 sklearn.isotonic: Isotonic regression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1747
6.18 sklearn.impute: Impute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1752
6.19 sklearn.kernel_approximation Kernel Approximation . . . . . . . . . . . . . . . . . . . 1756
6.20 sklearn.kernel_ridge Kernel Ridge Regression . . . . . . . . . . . . . . . . . . . . . . . . 1766
6.21 sklearn.linear_model: Generalized Linear Models . . . . . . . . . . . . . . . . . . . . . . . 1769
6.22 sklearn.manifold: Manifold Learning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1865
6.23 sklearn.metrics: Metrics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1884
6.24 sklearn.mixture: Gaussian Mixture Models . . . . . . . . . . . . . . . . . . . . . . . . . . . 1951

ii
6.25 sklearn.model_selection: Model Selection . . . . . . . . . . . . . . . . . . . . . . . . . . 1962
6.26 sklearn.multiclass: Multiclass and multilabel classification . . . . . . . . . . . . . . . . . . 2016
6.27 sklearn.multioutput: Multioutput regression and classification . . . . . . . . . . . . . . . . 2024
6.28 sklearn.naive_bayes: Naive Bayes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2034
6.29 sklearn.neighbors: Nearest Neighbors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2048
6.30 sklearn.neural_network: Neural network models . . . . . . . . . . . . . . . . . . . . . . . 2095
6.31 sklearn.pipeline: Pipeline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2107
6.32 sklearn.preprocessing: Preprocessing and Normalization . . . . . . . . . . . . . . . . . . . 2116
6.33 sklearn.random_projection: Random projection . . . . . . . . . . . . . . . . . . . . . . . 2171
6.34 sklearn.semi_supervised Semi-Supervised Learning . . . . . . . . . . . . . . . . . . . . . 2177
6.35 sklearn.svm: Support Vector Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2183
6.36 sklearn.tree: Decision Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2214
6.37 sklearn.utils: Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2238
6.38 Recently deprecated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2265

7 Developer’s Guide 2293


7.1 Contributing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2293
7.2 Developers’ Tips and Tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2314
7.3 Utilities for Developers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2318
7.4 How to optimize for speed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2321
7.5 Advanced installation instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2327
7.6 Maintainer / core-developer information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2332

Bibliography 2335

Index 2343

iii
iv
CHAPTER

ONE

WELCOME TO SCIKIT-LEARN

1.1 Installing scikit-learn

Note: If you wish to contribute to the project, it’s recommended you install the latest development version.

1.1.1 Installing the latest release

Scikit-learn requires:
• Python (>= 2.7 or >= 3.4),
• NumPy (>= 1.8.2),
• SciPy (>= 0.13.3).

Warning: Scikit-learn 0.20 is the last version to support Python 2.7 and Python 3.4. Scikit-learn 0.21 will require
Python 3.5 or newer.

If you already have a working installation of numpy and scipy, the easiest way to install scikit-learn is using pip

pip install -U scikit-learn

or conda:

conda install scikit-learn

If you have not installed NumPy or SciPy yet, you can also install these using conda or pip. When using pip, please
ensure that binary wheels are used, and NumPy and SciPy are not recompiled from source, which can happen when
using particular configurations of operating system and hardware (such as Linux on a Raspberry Pi). Building numpy
and scipy from source can be complex (especially on Windows) and requires careful configuration to ensure that they
link against an optimized implementation of linear algebra routines. Instead, use a third-party distribution as described
below.
If you must install scikit-learn and its dependencies with pip, you can install it as scikit-learn[alldeps]. The
most common use case for this is in a requirements.txt file used as part of an automated build process for a
PaaS application or a Docker image. This option is not intended for manual installation from the command line.

1
scikit-learn user guide, Release 0.20.3

Note: For installing on PyPy, PyPy3-v5.10+, Numpy 1.14.0+, and scipy 1.1.0+ are required.

For installation instructions for more distributions see other distributions. For compiling the development version
from source, or building the package if no distribution is available for your architecture, see the Advanced installation
instructions.

1.1.2 Third-party Distributions

If you don’t already have a python installation with numpy and scipy, we recommend to install either via your package
manager or via a python bundle. These come with numpy, scipy, scikit-learn, matplotlib and many other helpful
scientific and data processing libraries.
Available options are:

Canopy and Anaconda for all supported platforms

Canopy and Anaconda both ship a recent version of scikit-learn, in addition to a large set of scientific python library
for Windows, Mac OSX and Linux.
Anaconda offers scikit-learn as part of its free distribution.

Warning: To upgrade or uninstall scikit-learn installed with Anaconda or conda you should not use the pip
command. Instead:
To upgrade scikit-learn:
conda update scikit-learn

To uninstall scikit-learn:
conda remove scikit-learn

Upgrading with pip install -U scikit-learn or uninstalling pip uninstall scikit-learn is


likely fail to properly remove files installed by the conda command.
pip upgrade and uninstall operations only work on packages installed via pip install.

WinPython for Windows

The WinPython project distributes scikit-learn as an additional plugin.

1.2 Frequently Asked Questions

Here we try to give some answers to questions that regularly pop up on the mailing list.

1.2.1 What is the project name (a lot of people get it wrong)?

scikit-learn, but not scikit or SciKit nor sci-kit learn. Also not scikits.learn or scikits-learn, which were previously
used.

2 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

1.2.2 How do you pronounce the project name?

sy-kit learn. sci stands for science!

1.2.3 Why scikit?

There are multiple scikits, which are scientific toolboxes built around SciPy. You can find a list at https://scikits.
appspot.com/scikits. Apart from scikit-learn, another popular one is scikit-image.

1.2.4 How can I contribute to scikit-learn?

See Contributing. Before wanting to add a new algorithm, which is usually a major and lengthy undertaking, it is
recommended to start with known issues. Please do not contact the contributors of scikit-learn directly regarding
contributing to scikit-learn.

1.2.5 What’s the best way to get help on scikit-learn usage?

For general machine learning questions, please use Cross Validated with the [machine-learning] tag.
For scikit-learn usage questions, please use Stack Overflow with the [scikit-learn] and [python] tags. You
can alternatively use the mailing list.
Please make sure to include a minimal reproduction code snippet (ideally shorter than 10 lines) that highlights your
problem on a toy dataset (for instance from sklearn.datasets or randomly generated with functions of numpy.
random with a fixed random seed). Please remove any line of code that is not necessary to reproduce your problem.
The problem should be reproducible by simply copy-pasting your code snippet in a Python shell with scikit-learn
installed. Do not forget to include the import statements.
More guidance to write good reproduction code snippets can be found at:
https://stackoverflow.com/help/mcve
If your problem raises an exception that you do not understand (even after googling it), please make sure to include
the full traceback that you obtain when running the reproduction script.
For bug reports or feature requests, please make use of the issue tracker on GitHub.
There is also a scikit-learn Gitter channel where some users and developers might be found.
Please do not email any authors directly to ask for assistance, report bugs, or for any other issue related to
scikit-learn.

1.2.6 How should I save, export or deploy estimators for production?

See Model persistence.

1.2.7 How can I create a bunch object?

Don’t make a bunch object! They are not part of the scikit-learn API. Bunch objects are just a way to package some
numpy arrays. As a scikit-learn user you only ever need numpy arrays to feed your model with data.
For instance to train a classifier, all you need is a 2D array X for the input variables and a 1D array y for the target
variables. The array X holds the features as columns and samples as rows . The array y contains integer values to
encode the class membership of each sample in X.

1.2. Frequently Asked Questions 3


scikit-learn user guide, Release 0.20.3

1.2.8 How can I load my own datasets into a format usable by scikit-learn?

Generally, scikit-learn works on any numeric data stored as numpy arrays or scipy sparse matrices. Other types that
are convertible to numeric arrays such as pandas DataFrame are also acceptable.
For more information on loading your data files into these usable data structures, please refer to loading external
datasets.

1.2.9 What are the inclusion criteria for new algorithms ?

We only consider well-established algorithms for inclusion. A rule of thumb is at least 3 years since publication, 200+
citations and wide use and usefulness. A technique that provides a clear-cut improvement (e.g. an enhanced data
structure or a more efficient approximation technique) on a widely-used method will also be considered for inclusion.
From the algorithms or techniques that meet the above criteria, only those which fit well within the current API of
scikit-learn, that is a fit, predict/transform interface and ordinarily having input/output that is a numpy array
or sparse matrix, are accepted.
The contributor should support the importance of the proposed addition with research papers and/or implementations
in other similar packages, demonstrate its usefulness via common use-cases/applications and corroborate performance
improvements, if any, with benchmarks and/or plots. It is expected that the proposed algorithm should outperform the
methods that are already implemented in scikit-learn at least in some areas.
Also note that your implementation need not be in scikit-learn to be used together with scikit-learn tools. You can
implement your favorite algorithm in a scikit-learn compatible way, upload it to GitHub and let us know. We will be
happy to list it under Related Projects. If you already have a package on GitHub following the scikit-learn API, you
may also be interested to look at scikit-learn-contrib.

1.2.10 Why are you so selective on what algorithms you include in scikit-learn?

Code is maintenance cost, and we need to balance the amount of code we have with the size of the team (and add to
this the fact that complexity scales non linearly with the number of features). The package relies on core developers
using their free time to fix bugs, maintain code and review contributions. Any algorithm that is added needs future
attention by the developers, at which point the original author might long have lost interest. See also What are the
inclusion criteria for new algorithms ?. For a great read about long-term maintenance issues in open-source software,
look at the Executive Summary of Roads and Bridges

1.2.11 Why did you remove HMMs from scikit-learn?

See Will you add graphical models or sequence prediction to scikit-learn?.

1.2.12 Will you add graphical models or sequence prediction to scikit-learn?

Not in the foreseeable future. scikit-learn tries to provide a unified API for the basic tasks in machine learning, with
pipelines and meta-algorithms like grid search to tie everything together. The required concepts, APIs, algorithms
and expertise required for structured learning are different from what scikit-learn has to offer. If we started doing
arbitrary structured learning, we’d need to redesign the whole package and the project would likely collapse under its
own weight.
There are two project with API similar to scikit-learn that do structured prediction:
• pystruct handles general structured learning (focuses on SSVMs on arbitrary graph structures with approximate
inference; defines the notion of sample as an instance of the graph structure)

4 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• seqlearn handles sequences only (focuses on exact inference; has HMMs, but mostly for the sake of complete-
ness; treats a feature vector as a sample and uses an offset encoding for the dependencies between feature
vectors)

1.2.13 Will you add GPU support?

No, or at least not in the near future. The main reason is that GPU support will introduce many software dependencies
and introduce platform specific issues. scikit-learn is designed to be easy to install on a wide variety of platforms.
Outside of neural networks, GPUs don’t play a large role in machine learning today, and much larger gains in speed
can often be achieved by a careful choice of algorithms.

1.2.14 Do you support PyPy?

In case you didn’t know, PyPy is an alternative Python implementation with a built-in just-in-time compiler. Experi-
mental support for PyPy3-v5.10+ has been added, which requires Numpy 1.14.0+, and scipy 1.1.0+.

1.2.15 How do I deal with string data (or trees, graphs. . . )?

scikit-learn estimators assume you’ll feed them real-valued feature vectors. This assumption is hard-coded in pretty
much all of the library. However, you can feed non-numerical inputs to estimators in several ways.
If you have text documents, you can use a term frequency features; see Text feature extraction for the built-in text
vectorizers. For more general feature extraction from any kind of data, see Loading features from dicts and Feature
hashing.
Another common case is when you have non-numerical data and a custom distance (or similarity) metric on these data.
Examples include strings with edit distance (aka. Levenshtein distance; e.g., DNA or RNA sequences). These can be
encoded as numbers, but doing so is painful and error-prone. Working with distance metrics on arbitrary data can be
done in two ways.
Firstly, many estimators take precomputed distance/similarity matrices, so if the dataset is not too large, you can
compute distances for all pairs of inputs. If the dataset is large, you can use feature vectors with only one “feature”,
which is an index into a separate data structure, and supply a custom metric function that looks up the actual data in
this data structure. E.g., to use DBSCAN with Levenshtein distances:

>>> from leven import levenshtein


>>> import numpy as np
>>> from sklearn.cluster import dbscan
>>> data = ["ACCTCCTAGAAG", "ACCTACTAGAAGTT", "GAATATTAGGCCGA"]
>>> def lev_metric(x, y):
... i, j = int(x[0]), int(y[0]) # extract indices
... return levenshtein(data[i], data[j])
...
>>> X = np.arange(len(data)).reshape(-1, 1)
>>> X
array([[0],
[1],
[2]])
>>> # We need to specify algoritum='brute' as the default assumes
>>> # a continuous feature space.
>>> dbscan(X, metric=lev_metric, eps=5, min_samples=2, algorithm='brute')
...
([0, 1], array([ 0, 0, -1]))

1.2. Frequently Asked Questions 5


scikit-learn user guide, Release 0.20.3

(This uses the third-party edit distance package leven.)


Similar tricks can be used, with some care, for tree kernels, graph kernels, etc.

1.2.16 Why do I sometime get a crash/freeze with n_jobs > 1 under OSX or Linux?

Several scikit-learn tools such as GridSearchCV and cross_val_score rely internally on Python’s multipro-
cessing module to parallelize execution onto several Python processes by passing n_jobs > 1 as argument.
The problem is that Python multiprocessing does a fork system call without following it with an exec system
call for performance reasons. Many libraries like (some versions of) Accelerate / vecLib under OSX, (some versions
of) MKL, the OpenMP runtime of GCC, nvidia’s Cuda (and probably many others), manage their own internal thread
pool. Upon a call to fork, the thread pool state in the child process is corrupted: the thread pool believes it has many
threads while only the main thread state has been forked. It is possible to change the libraries to make them detect
when a fork happens and reinitialize the thread pool in that case: we did that for OpenBLAS (merged upstream in
master since 0.2.10) and we contributed a patch to GCC’s OpenMP runtime (not yet reviewed).
But in the end the real culprit is Python’s multiprocessing that does fork without exec to reduce the overhead
of starting and using new Python processes for parallel computing. Unfortunately this is a violation of the POSIX
standard and therefore some software editors like Apple refuse to consider the lack of fork-safety in Accelerate /
vecLib as a bug.
In Python 3.4+ it is now possible to configure multiprocessing to use the ‘forkserver’ or ‘spawn’ start methods
(instead of the default ‘fork’) to manage the process pools. To work around this issue when using scikit-learn, you
can set the JOBLIB_START_METHOD environment variable to ‘forkserver’. However the user should be aware that
using the ‘forkserver’ method prevents joblib.Parallel to call function interactively defined in a shell session.
If you have custom code that uses multiprocessing directly instead of using it via joblib you can enable the
‘forkserver’ mode globally for your program: Insert the following instructions in your main script:

import multiprocessing

# other imports, custom code, load data, define model...

if __name__ == '__main__':
multiprocessing.set_start_method('forkserver')

# call scikit-learn utils with n_jobs > 1 here

You can find more default on the new start methods in the multiprocessing documentation.

1.2.17 Why does my job use more cores than specified with n_jobs under OSX or
Linux?

This happens when vectorized numpy operations are handled by libraries such as MKL or OpenBLAS.
While scikit-learn adheres to the limit set by n_jobs, numpy operations vectorized using MKL (or OpenBLAS) will
make use of multiple threads within each scikit-learn job (thread or process).
The number of threads used by the BLAS library can be set via an environment variable. For example, to set the
maximum number of threads to some integer value N, the following environment variables should be set:
• For MKL: export MKL_NUM_THREADS=N
• For OpenBLAS: export OPENBLAS_NUM_THREADS=N

6 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

1.2.18 Why is there no support for deep or reinforcement learning / Will there be
support for deep or reinforcement learning in scikit-learn?

Deep learning and reinforcement learning both require a rich vocabulary to define an architecture, with deep learning
additionally requiring GPUs for efficient computing. However, neither of these fit within the design constraints of
scikit-learn; as a result, deep learning and reinforcement learning are currently out of scope for what scikit-learn seeks
to achieve.
You can find more information about addition of gpu support at Will you add GPU support?.

1.2.19 Why is my pull request not getting any attention?

The scikit-learn review process takes a significant amount of time, and contributors should not be discouraged by a
lack of activity or review on their pull request. We care a lot about getting things right the first time, as maintenance
and later change comes at a high cost. We rarely release any “experimental” code, so all of our contributions will be
subject to high use immediately and should be of the highest quality possible initially.
Beyond that, scikit-learn is limited in its reviewing bandwidth; many of the reviewers and core developers are working
on scikit-learn on their own time. If a review of your pull request comes slowly, it is likely because the reviewers are
busy. We ask for your understanding and request that you not close your pull request or discontinue your work solely
because of this reason.

1.2.20 How do I set a random_state for an entire execution?

For testing and replicability, it is often important to have the entire execution controlled by a single seed for the pseudo-
random number generator used in algorithms that have a randomized component. Scikit-learn does not use its own
global random state; whenever a RandomState instance or an integer random seed is not provided as an argument, it
relies on the numpy global random state, which can be set using numpy.random.seed. For example, to set an
execution’s numpy global random state to 42, one could execute the following in his or her script:
import numpy as np
np.random.seed(42)

However, a global random state is prone to modification by other code during execution. Thus, the only way to ensure
replicability is to pass RandomState instances everywhere and ensure that both estimators and cross-validation
splitters have their random_state parameter set.

1.2.21 Why do categorical variables need preprocessing in scikit-learn, compared


to other tools?

Most of scikit-learn assumes data is in NumPy arrays or SciPy sparse matrices of a single numeric dtype. These do
not explicitly represent categorical variables at present. Thus, unlike R’s data.frames or pandas.DataFrame, we require
explicit conversion of categorical features to numeric values, as discussed in Encoding categorical features. See also
Column Transformer with Mixed Types for an example of working with heterogeneous (e.g. categorical and numeric)
data.

1.2.22 Why does Scikit-learn not directly work with, for example, pan-
das.DataFrame?

The homogeneous NumPy and SciPy data objects currently expected are most efficient to process for most operations.
Extensive work would also be needed to support Pandas categorical types. Restricting input to homogeneous types
therefore reduces maintenance cost and encourages usage of efficient data structures.

1.2. Frequently Asked Questions 7


scikit-learn user guide, Release 0.20.3

1.3 Support

There are several ways to get in touch with the developers.

1.3.1 Mailing List

• The main mailing list is scikit-learn.


• There is also a commit list scikit-learn-commits, where updates to the main repository and test failures get
notified.

1.3.2 User questions

• Some scikit-learn developers support users on StackOverflow using the [scikit-learn] tag.
• For general theoretical or methodological Machine Learning questions stack exchange is probably a more suit-
able venue.
In both cases please use a descriptive question in the title field (e.g. no “Please help with scikit-learn!” as this is not a
question) and put details on what you tried to achieve, what were the expected results and what you observed instead
in the details field.
Code and data snippets are welcome. Minimalistic (up to ~20 lines long) reproduction script very helpful.
Please describe the nature of your data and the how you preprocessed it: what is the number of samples, what is the
number and type of features (i.d. categorical or numerical) and for supervised learning tasks, what target are your
trying to predict: binary, multiclass (1 out of n_classes) or multilabel (k out of n_classes) classification or
continuous variable regression.

1.3.3 Bug tracker

If you think you’ve encountered a bug, please report it to the issue tracker:
https://github.com/scikit-learn/scikit-learn/issues
Don’t forget to include:
• steps (or better script) to reproduce,
• expected outcome,
• observed outcome or python (or gdb) tracebacks
To help developers fix your bug faster, please link to a https://gist.github.com holding a standalone minimalistic python
script that reproduces your bug and optionally a minimalistic subsample of your dataset (for instance exported as CSV
files using numpy.savetxt).
Note: gists are git cloneable repositories and thus you can use git to push datafiles to them.

1.3.4 IRC

Some developers like to hang out on channel #scikit-learn on irc.freenode.net.


If you do not have an IRC client or are behind a firewall this web client works fine: https://webchat.freenode.net

8 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

1.3.5 Documentation resources

This documentation is relative to 0.20.3. Documentation for other versions can be found here.
Printable pdf documentation for old versions can be found here.

1.4 Related Projects

Projects implementing the scikit-learn estimator API are encouraged to use the scikit-learn-contrib template which
facilitates best practices for testing and documenting estimators. The scikit-learn-contrib GitHub organisation also
accepts high-quality contributions of repositories conforming to this template.
Below is a list of sister-projects, extensions and domain specific packages.

1.4.1 Interoperability and framework enhancements

These tools adapt scikit-learn for use with other technologies or otherwise enhance the functionality of scikit-learn’s
estimators.
Data formats
• sklearn_pandas bridge for scikit-learn pipelines and pandas data frame with dedicated transformers.
• sklearn_xarray provides compatibility of scikit-learn estimators with xarray data structures.
Auto-ML
• auto_ml Automated machine learning for production and analytics, built on scikit-learn and related projects.
Trains a pipeline wth all the standard machine learning steps. Tuned for prediction speed and ease of transfer to
production environments.
• auto-sklearn An automated machine learning toolkit and a drop-in replacement for a scikit-learn estimator
• TPOT An automated machine learning toolkit that optimizes a series of scikit-learn operators to design a ma-
chine learning pipeline, including data and feature preprocessors as well as the estimators. Works as a drop-in
replacement for a scikit-learn estimator.
• scikit-optimize A library to minimize (very) expensive and noisy black-box functions. It implements sev-
eral methods for sequential model-based optimization, and includes a replacement for GridSearchCV or
RandomizedSearchCV to do cross-validated parameter search using any of these strategies.
Experimentation frameworks
• REP Environment for conducting data-driven research in a consistent and reproducible way
• ML Frontend provides dataset management and SVM fitting/prediction through web-based and programmatic
interfaces.
• Scikit-Learn Laboratory A command-line wrapper around scikit-learn that makes it easy to run machine learning
experiments with multiple learners and large feature sets.
• Xcessiv is a notebook-like application for quick, scalable, and automated hyperparameter tuning and stacked
ensembling. Provides a framework for keeping track of model-hyperparameter combinations.
Model inspection and visualisation
• eli5 A library for debugging/inspecting machine learning models and explaining their predictions.
• mlxtend Includes model visualization utilities.

1.4. Related Projects 9


scikit-learn user guide, Release 0.20.3

• scikit-plot A visualization library for quick and easy generation of common plots in data analysis and machine
learning.
• yellowbrick A suite of custom matplotlib visualizers for scikit-learn estimators to support visual feature analysis,
model selection, evaluation, and diagnostics.
Model export for production
• onnxmltools Serializes many Scikit-learn pipelines to ONNX for interchange and prediction.
• sklearn2pmml Serialization of a wide variety of scikit-learn estimators and transformers into PMML with the
help of JPMML-SkLearn library.
• sklearn-porter Transpile trained scikit-learn models to C, Java, Javascript and others.
• sklearn-compiledtrees Generate a C++ implementation of the predict function for decision trees (and ensembles)
trained by sklearn. Useful for latency-sensitive production environments.

1.4.2 Other estimators and tasks

Not everything belongs or is mature enough for the central scikit-learn project. The following are projects providing
interfaces similar to scikit-learn for additional learning algorithms, infrastructures and tasks.
Structured learning
• Seqlearn Sequence classification using HMMs or structured perceptron.
• HMMLearn Implementation of hidden markov models that was previously part of scikit-learn.
• PyStruct General conditional random fields and structured prediction.
• pomegranate Probabilistic modelling for Python, with an emphasis on hidden Markov models.
• sklearn-crfsuite Linear-chain conditional random fields (CRFsuite wrapper with sklearn-like API).
Deep neural networks etc.
• pylearn2 A deep learning and neural network library build on theano with scikit-learn like interface.
• sklearn_theano scikit-learn compatible estimators, transformers, and datasets which use Theano internally
• nolearn A number of wrappers and abstractions around existing neural network libraries
• keras Deep Learning library capable of running on top of either TensorFlow or Theano.
• lasagne A lightweight library to build and train neural networks in Theano.
• skorch A scikit-learn compatible neural network library that wraps PyTorch.
Broad scope
• mlxtend Includes a number of additional estimators as well as model visualization utilities.
• sparkit-learn Scikit-learn API and functionality for PySpark’s distributed modelling.
Other regression and classification
• xgboost Optimised gradient boosted decision tree library.
• ML-Ensemble Generalized ensemble learning (stacking, blending, subsemble, deep ensembles, etc.).
• lightning Fast state-of-the-art linear model solvers (SDCA, AdaGrad, SVRG, SAG, etc. . . ).
• py-earth Multivariate adaptive regression splines
• Kernel Regression Implementation of Nadaraya-Watson kernel regression with automatic bandwidth selection
• gplearn Genetic Programming for symbolic regression tasks.

10 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• multiisotonic Isotonic regression on multidimensional features.


• scikit-multilearn Multi-label classification with focus on label space manipulation.
• seglearn Time series and sequence learning using sliding window segmentation.
Decomposition and clustering
• lda: Fast implementation of latent Dirichlet allocation in Cython which uses Gibbs sampling
to sample from the true posterior distribution. (scikit-learn’s sklearn.decomposition.
LatentDirichletAllocation implementation uses variational inference to sample from a tractable
approximation of a topic model’s posterior distribution.)
• Sparse Filtering Unsupervised feature learning based on sparse-filtering
• kmodes k-modes clustering algorithm for categorical data, and several of its variations.
• hdbscan HDBSCAN and Robust Single Linkage clustering algorithms for robust variable density clustering.
• spherecluster Spherical K-means and mixture of von Mises Fisher clustering routines for data on the unit hyper-
sphere.
Pre-processing
• categorical-encoding A library of sklearn compatible categorical variable encoders.
• imbalanced-learn Various methods to under- and over-sample datasets.

1.4.3 Statistical learning with Python

Other packages useful for data analysis and machine learning.


• Pandas Tools for working with heterogeneous and columnar data, relational queries, time series and basic statis-
tics.
• theano A CPU/GPU array processing framework geared towards deep learning research.
• statsmodels Estimating and analysing statistical models. More focused on statistical tests and less on prediction
than scikit-learn.
• PyMC Bayesian statistical models and fitting algorithms.
• Sacred Tool to help you configure, organize, log and reproduce experiments
• Seaborn Visualization library based on matplotlib. It provides a high-level interface for drawing attractive
statistical graphics.
• Deep Learning A curated list of deep learning software libraries.

Domain specific packages

• scikit-image Image processing and computer vision in python.


• Natural language toolkit (nltk) Natural language processing and some machine learning.
• gensim A library for topic modelling, document indexing and similarity retrieval
• NiLearn Machine learning for neuro-imaging.
• AstroML Machine learning for astronomy.
• MSMBuilder Machine learning for protein conformational dynamics time series.
• scikit-surprise A scikit for building and evaluating recommender systems.

1.4. Related Projects 11


scikit-learn user guide, Release 0.20.3

1.4.4 Snippets and tidbits

The wiki has more!

1.5 About us

1.5.1 History

This project was started in 2007 as a Google Summer of Code project by David Cournapeau. Later that year, Matthieu
Brucher started work on this project as part of his thesis.
In 2010 Fabian Pedregosa, Gael Varoquaux, Alexandre Gramfort and Vincent Michel of INRIA took leadership of the
project and made the first public release, February the 1st 2010. Since then, several releases have appeared following
a ~3 month cycle, and a thriving international community has been leading the development.

1.5.2 Authors

The following people have been core contributors to scikit-learn’s development and maintenance:
Please do not email the authors directly to ask for assistance or report issues. Instead, please see What’s the best way
to ask questions about scikit-learn in the FAQ.
See also:
How you can contribute to the project

1.5.3 Governance

The decision making process and governance structure of scikit-learn is laid out in the governance document.

1.5.4 Citing scikit-learn

If you use scikit-learn in a scientific publication, we would appreciate citations to the following paper:
Scikit-learn: Machine Learning in Python, Pedregosa et al., JMLR 12, pp. 2825-2830, 2011.
Bibtex entry:

@article{scikit-learn,
title={Scikit-learn: Machine Learning in {P}ython},
author={Pedregosa, F. and Varoquaux, G. and Gramfort, A. and Michel, V.
and Thirion, B. and Grisel, O. and Blondel, M. and Prettenhofer, P.
and Weiss, R. and Dubourg, V. and Vanderplas, J. and Passos, A. and
Cournapeau, D. and Brucher, M. and Perrot, M. and Duchesnay, E.},
journal={Journal of Machine Learning Research},
volume={12},
pages={2825--2830},
year={2011}
}

If you want to cite scikit-learn for its API or design, you may also want to consider the following paper:

12 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

API design for machine learning software: experiences from the scikit-learn project, Buitinck et al., 2013.
Bibtex entry:

@inproceedings{sklearn_api,
author = {Lars Buitinck and Gilles Louppe and Mathieu Blondel and
Fabian Pedregosa and Andreas Mueller and Olivier Grisel and
Vlad Niculae and Peter Prettenhofer and Alexandre Gramfort
and Jaques Grobler and Robert Layton and Jake VanderPlas and
Arnaud Joly and Brian Holt and Ga{\"{e}}l Varoquaux},
title = {{API} design for machine learning software: experiences from
˓→the scikit-learn

project},
booktitle = {ECML PKDD Workshop: Languages for Data Mining and Machine
˓→Learning},

year = {2013},
pages = {108--122},
}

1.5.5 Artwork

High quality PNG and SVG logos are available in the doc/logos/ source directory.

1.5.6 Funding

INRIA actively supports this project. It has provided funding for Fabian Pedregosa (2010-2012), Jaques Grob-
ler (2012-2013) and Olivier Grisel (2013-2017) to work on this project full-time. It also hosts coding sprints and

other events. Paris-Saclay Center for Data Science funded one year
for a developer to work on the project full-time (2014-2015) and 50% of the time of Guillaume Lemaitre (2016-

2017). NYU Moore-Sloan Data Science Environment funded An-


dreas Mueller (2014-2016) to work on this project. The Moore-Sloan Data Science Environment also funds sev-

1.5. About us 13
scikit-learn user guide, Release 0.20.3

eral students to work on the project part-time. Télécom Paris-


tech funded Manoj Kumar (2014), Tom Dupré la Tour (2015), Raghav RV (2015-2017), Thierry Guillemot (2016-

2017) and Albert Thomas (2017) to work on scikit-learn. Columbia University funds An-

dreas Müller since 2016. Andreas Müller also received a grant to improve scikit-learn

from the Alfred P. Sloan Foundation in 2017. The University of

Sydney funds Joel Nothman since July 2017. The Labex Digi-
Cosme funded Nicolas Goix (2015-2016), Tom Dupré la Tour (2015-2016 and 2017-2018), Mathurin Massias (2018-
2019) to work part time on scikit-learn during their PhDs. It also funded a scikit-learn coding sprint in 2015.

The following students were sponsored by Google to work on


scikit-learn through the Google Summer of Code program.
• 2007 - David Cournapeau
• 2011 - ‘Vlad Niculae‘_

14 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• 2012 - ‘Vlad Niculae‘_, Immanuel Bayer.


• 2013 - Kemal Eren, Nicolas Trésegnie
• 2014 - Hamzeh Alsalhi, Issam Laradji, Maheshakya Wijewardena, Manoj Kumar.
• 2015 - Raghav RV, Wei Xue
• 2016 - Nelson Liu, YenChen Lin
It also provided funding for sprints and events around scikit-learn. If you would like to participate in the next Google
Summer of code program, please see this page.
The NeuroDebian project providing Debian packaging and contributions is supported by Dr. James V. Haxby (Dart-
mouth College).
The PSF helped find and manage funding for our 2011 Granada sprint. More information can be found here
tinyclues funded the 2011 international Granada sprint.

Donating to the project

If you are interested in donating to the project or to one of our code-sprints, you can use the Paypal button below or the
NumFOCUS Donations Page (if you use the latter, please indicate that you are donating for the scikit-learn project).
All donations will be handled by NumFOCUS, a non-profit-organization which is managed by a board of Scipy
community members. NumFOCUS’s mission is to foster scientific computing software, in particular in Python. As
a fiscal home of scikit-learn, it ensures that money is available when needed to keep the project funded and available
while in compliance with tax regulations.
The received donations for the scikit-learn project mostly will go towards covering travel-expenses for code sprints, as
well as towards the organization budget of the project1 .

Notes

The 2013 Paris international sprint

1.5. About us 15
scikit-learn user guide, Release 0.20.3

Fig. 1.1: IAP VII/19 - DYSCO

For more information on this sprint, see here

1.5.7 Infrastructure support

• We would like to thank Rackspace for providing us with a free Rackspace Cloud account to automatically build
the documentation and the example gallery from for the development version of scikit-learn using this tool.
• We would also like to thank Shining Panda for free CPU time on their Continuous Integration server.

1.6 Who is using scikit-learn?

1.6.1 J.P.Morgan

Scikit-learn is an indispensable part of the Python machine learning toolkit at JPMorgan. It is very widely used
across all parts of the bank for classification, predictive analytics, and very many other machine learning tasks. Its
straightforward API, its breadth of algorithms, and the quality of its documentation combine to make scikit-learn
simultaneously very approachable and very powerful.
Stephen Simmons, VP, Athena Research, JPMorgan

1.6.2 Spotify

1 Regarding the organization budget in particular, we might use some of the donated funds to pay for other project expenses such as DNS,

hosting or continuous integration services.

16 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

Scikit-learn provides a toolbox with solid implementations of a bunch of state-of-the-art models and makes it easy to
plug them into existing applications. We’ve been using it quite a lot for music recommendations at Spotify and I think
it’s the most well-designed ML package I’ve seen so far.
Erik Bernhardsson, Engineering Manager Music Discovery & Machine Learning, Spotify

1.6.3 Inria

At INRIA, we use scikit-learn to support leading-edge basic research in many teams: Parietal for neuroimaging, Lear
for computer vision, Visages for medical image analysis, Privatics for security. The project is a fantastic tool to
address difficult applications of machine learning in an academic environment as it is performant and versatile, but all
easy-to-use and well documented, which makes it well suited to grad students.
Gaël Varoquaux, research at Parietal

1.6.4 betaworks

Betaworks is a NYC-based startup studio that builds new products, grows companies, and invests in others. Over
the past 8 years we’ve launched a handful of social data analytics-driven services, such as Bitly, Chartbeat, digg and
Scale Model. Consistently the betaworks data science team uses Scikit-learn for a variety of tasks. From exploratory
analysis, to product development, it is an essential part of our toolkit. Recent uses are included in digg’s new video
recommender system, and Poncho’s dynamic heuristic subspace clustering.
Gilad Lotan, Chief Data Scientist

1.6.5 Hugging Face

At Hugging Face we’re using NLP and probabilistic models to generate conversational Artificial intelligences that are
fun to chat with. Despite using deep neural nets for a few of our NLP tasks, scikit-learn is still the bread-and-butter of
our daily machine learning routine. The ease of use and predictability of the interface, as well as the straightforward
mathematical explanations that are here when you need them, is the killer feature. We use a variety of scikit-learn
models in production and they are also operationally very pleasant to work with.
Julien Chaumond, Chief Technology Officer

1.6. Who is using scikit-learn? 17


scikit-learn user guide, Release 0.20.3

1.6.6 Evernote

Building a classifier is typically an iterative process of exploring the data, selecting the features (the attributes of the
data believed to be predictive in some way), training the models, and finally evaluating them. For many of these tasks,
we relied on the excellent scikit-learn package for Python.
Read more
Mark Ayzenshtat, VP, Augmented Intelligence

1.6.7 Télécom ParisTech

At Telecom ParisTech, scikit-learn is used for hands-on sessions and home assignments in introductory and advanced
machine learning courses. The classes are for undergrads and masters students. The great benefit of scikit-learn is its
fast learning curve that allows students to quickly start working on interesting and motivating problems.
Alexandre Gramfort, Assistant Professor

1.6.8 Booking.com

At Booking.com, we use machine learning algorithms for many different applications, such as recommending ho-
tels and destinations to our customers, detecting fraudulent reservations, or scheduling our customer service agents.
Scikit-learn is one of the tools we use when implementing standard algorithms for prediction tasks. Its API and doc-
umentations are excellent and make it easy to use. The scikit-learn developers do a great job of incorporating state of
the art implementations and new algorithms into the package. Thus, scikit-learn provides convenient access to a wide
spectrum of algorithms, and allows us to readily find the right tool for the right job.
Melanie Mueller, Data Scientist

1.6.9 AWeber

18 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

The scikit-learn toolkit is indispensable for the Data Analysis and Management team at AWeber. It allows us to do
AWesome stuff we would not otherwise have the time or resources to accomplish. The documentation is excellent,
allowing new engineers to quickly evaluate and apply many different algorithms to our data. The text feature extraction
utilities are useful when working with the large volume of email content we have at AWeber. The RandomizedPCA
implementation, along with Pipelining and FeatureUnions, allows us to develop complex machine learning algorithms
efficiently and reliably.
Anyone interested in learning more about how AWeber deploys scikit-learn in a production environment should check
out talks from PyData Boston by AWeber’s Michael Becker available at https://github.com/mdbecker/pydata_2013
Michael Becker, Software Engineer, Data Analysis and Management Ninjas

1.6.10 Yhat

The combination of consistent APIs, thorough documentation, and top notch implementation make scikit-learn our
favorite machine learning package in Python. scikit-learn makes doing advanced analysis in Python accessible to
anyone. At Yhat, we make it easy to integrate these models into your production applications. Thus eliminating the
unnecessary dev time encountered productionizing analytical work.
Greg Lamp, Co-founder Yhat

1.6.11 Rangespan

The Python scikit-learn toolkit is a core tool in the data science group at Rangespan. Its large collection of well
documented models and algorithms allow our team of data scientists to prototype fast and quickly iterate to find the
right solution to our learning problems. We find that scikit-learn is not only the right tool for prototyping, but its
careful and well tested implementation give us the confidence to run scikit-learn models in production.
Jurgen Van Gael, Data Science Director at Rangespan Ltd

1.6. Who is using scikit-learn? 19


scikit-learn user guide, Release 0.20.3

1.6.12 Birchbox

At Birchbox, we face a range of machine learning problems typical to E-commerce: product recommendation, user
clustering, inventory prediction, trends detection, etc. Scikit-learn lets us experiment with many models, especially in
the exploration phase of a new project: the data can be passed around in a consistent way; models are easy to save and
reuse; updates keep us informed of new developments from the pattern discovery research community. Scikit-learn is
an important tool for our team, built the right way in the right language.
Thierry Bertin-Mahieux, Birchbox, Data Scientist

1.6.13 Bestofmedia Group

Scikit-learn is our #1 toolkit for all things machine learning at Bestofmedia. We use it for a variety of tasks (e.g. spam
fighting, ad click prediction, various ranking models) thanks to the varied, state-of-the-art algorithm implementations
packaged into it. In the lab it accelerates prototyping of complex pipelines. In production I can say it has proven to be
robust and efficient enough to be deployed for business critical components.
Eustache Diemert, Lead Scientist Bestofmedia Group

1.6.14 Change.org

20 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

At change.org we automate the use of scikit-learn’s RandomForestClassifier in our production systems to drive email
targeting that reaches millions of users across the world each week. In the lab, scikit-learn’s ease-of-use, performance,
and overall variety of algorithms implemented has proved invaluable in giving us a single reliable source to turn to for
our machine-learning needs.
Vijay Ramesh, Software Engineer in Data/science at Change.org

1.6.15 PHIMECA Engineering

At PHIMECA Engineering, we use scikit-learn estimators as surrogates for expensive-to-evaluate numerical models
(mostly but not exclusively finite-element mechanical models) for speeding up the intensive post-processing operations
involved in our simulation-based decision making framework. Scikit-learn’s fit/predict API together with its efficient
cross-validation tools considerably eases the task of selecting the best-fit estimator. We are also using scikit-learn for
illustrating concepts in our training sessions. Trainees are always impressed by the ease-of-use of scikit-learn despite
the apparent theoretical complexity of machine learning.
Vincent Dubourg, PHIMECA Engineering, PhD Engineer

1.6.16 HowAboutWe

At HowAboutWe, scikit-learn lets us implement a wide array of machine learning techniques in analysis and in pro-
duction, despite having a small team. We use scikit-learn’s classification algorithms to predict user behavior, enabling
us to (for example) estimate the value of leads from a given traffic source early in the lead’s tenure on our site. Also, our
users’ profiles consist of primarily unstructured data (answers to open-ended questions), so we use scikit-learn’s fea-
ture extraction and dimensionality reduction tools to translate these unstructured data into inputs for our matchmaking
system.
Daniel Weitzenfeld, Senior Data Scientist at HowAboutWe

1.6.17 PeerIndex

At PeerIndex we use scientific methodology to build the Influence Graph - a unique dataset that allows us to identify
who’s really influential and in which context. To do this, we have to tackle a range of machine learning and predic-
tive modeling problems. Scikit-learn has emerged as our primary tool for developing prototypes and making quick
progress. From predicting missing data and classifying tweets to clustering communities of social media users, scikit-

1.6. Who is using scikit-learn? 21


scikit-learn user guide, Release 0.20.3

learn proved useful in a variety of applications. Its very intuitive interface and excellent compatibility with other
python tools makes it and indispensable tool in our daily research efforts.
Ferenc Huszar - Senior Data Scientist at Peerindex

1.6.18 DataRobot

DataRobot is building next generation predictive analytics software to make data scientists more productive, and
scikit-learn is an integral part of our system. The variety of machine learning techniques in combination with the
solid implementations that scikit-learn offers makes it a one-stop-shopping library for machine learning in Python.
Moreover, its consistent API, well-tested code and permissive licensing allow us to use it in a production environment.
Scikit-learn has literally saved us years of work we would have had to do ourselves to bring our product to market.
Jeremy Achin, CEO & Co-founder DataRobot Inc.

1.6.19 OkCupid

We’re using scikit-learn at OkCupid to evaluate and improve our matchmaking system. The range of features it has,
especially preprocessing utilities, means we can use it for a wide variety of projects, and it’s performant enough to
handle the volume of data that we need to sort through. The documentation is really thorough, as well, which makes
the library quite easy to use.
David Koh - Senior Data Scientist at OkCupid

1.6.20 Lovely

At Lovely, we strive to deliver the best apartment marketplace, with respect to our users and our listings. From
understanding user behavior, improving data quality, and detecting fraud, scikit-learn is a regular tool for gathering
insights, predictive modeling and improving our product. The easy-to-read documentation and intuitive architecture of
the API makes machine learning both explorable and accessible to a wide range of python developers. I’m constantly
recommending that more developers and scientists try scikit-learn.
Simon Frid - Data Scientist, Lead at Lovely

22 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

1.6.21 Data Publica

Data Publica builds a new predictive sales tool for commercial and marketing teams called C-Radar. We extensively
use scikit-learn to build segmentations of customers through clustering, and to predict future customers based on past
partnerships success or failure. We also categorize companies using their website communication thanks to scikit-learn
and its machine learning algorithm implementations. Eventually, machine learning makes it possible to detect weak
signals that traditional tools cannot see. All these complex tasks are performed in an easy and straightforward way
thanks to the great quality of the scikit-learn framework.
Guillaume Lebourgeois & Samuel Charron - Data Scientists at Data Publica

1.6.22 Machinalis

Scikit-learn is the cornerstone of all the machine learning projects carried at Machinalis. It has a consistent API, a
wide selection of algorithms and lots of auxiliary tools to deal with the boilerplate. We have used it in production en-
vironments on a variety of projects including click-through rate prediction, information extraction, and even counting
sheep!
In fact, we use it so much that we’ve started to freeze our common use cases into Python packages, some of them
open-sourced, like FeatureForge . Scikit-learn in one word: Awesome.
Rafael Carrascosa, Lead developer

1.6.23 solido

Scikit-learn is helping to drive Moore’s Law, via Solido. Solido creates computer-aided design tools used by the
majority of top-20 semiconductor companies and fabs, to design the bleeding-edge chips inside smartphones, auto-
mobiles, and more. Scikit-learn helps to power Solido’s algorithms for rare-event estimation, worst-case verification,
optimization, and more. At Solido, we are particularly fond of scikit-learn’s libraries for Gaussian Process models,
large-scale regularized linear regression, and classification. Scikit-learn has increased our productivity, because for
many ML problems we no longer need to “roll our own” code. This PyData 2014 talk has details.
Trent McConaghy, founder, Solido Design Automation Inc.

1.6. Who is using scikit-learn? 23


scikit-learn user guide, Release 0.20.3

1.6.24 INFONEA

We employ scikit-learn for rapid prototyping and custom-made Data Science solutions within our in-memory based
Business Intelligence Software INFONEA®. As a well-documented and comprehensive collection of state-of-the-art
algorithms and pipelining methods, scikit-learn enables us to provide flexible and scalable scientific analysis solutions.
Thus, scikit-learn is immensely valuable in realizing a powerful integration of Data Science technology within self-
service business analytics.
Thorsten Kranz, Data Scientist, Coma Soft AG.

1.6.25 Dataiku

Our software, Data Science Studio (DSS), enables users to create data services that combine ETL with Machine
Learning. Our Machine Learning module integrates many scikit-learn algorithms. The scikit-learn library is a perfect
integration with DSS because it offers algorithms for virtually all business cases. Our goal is to offer a transparent and
flexible tool that makes it easier to optimize time consuming aspects of building a data service, preparing data, and
training machine learning algorithms on all types of data.
Florian Douetteau, CEO, Dataiku

1.6.26 Otto Group

Here at Otto Group, one of global Big Five B2C online retailers, we are using scikit-learn in all aspects of our daily
work from data exploration to development of machine learning application to the productive deployment of those
services. It helps us to tackle machine learning problems ranging from e-commerce to logistics. It consistent APIs
enabled us to build the Palladium REST-API framework around it and continuously deliver scikit-learn based services.
Christian Rammig, Head of Data Science, Otto Group

1.6.27 Zopa

At Zopa, the first ever Peer-to-Peer lending platform, we extensively use scikit-learn to run the business and optimize
our users’ experience. It powers our Machine Learning models involved in credit risk, fraud risk, marketing, and
pricing, and has been used for originating at least 1 billion GBP worth of Zopa loans. It is very well documented,
powerful, and simple to use. We are grateful for the capabilities it has provided, and for allowing us to deliver on our
mission of making money simple and fair.

24 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

Vlasios Vasileiou, Head of Data Science, Zopa

1.6.28 MARS

Scikit-Learn is integral to the Machine Learning Ecosystem at Mars. Whether we’re designing better recipes for
petfood or closely analysing our cocoa supply chain, Scikit-Learn is used as a tool for rapidly prototyping ideas and
taking them to production. This allows us to better understand and meet the needs of our consumers worldwide.
Scikit-Learn’s feature-rich toolset is easy to use and equips our associates with the capabilities they need to solve the
business challenges they face every day.
Michael Fitzke Next Generation Technologies Sr Leader, Mars Inc.

1.7 Release History

Release notes for current and recent releases are detailed on this page, with previous releases linked below.
Tip: Subscribe to scikit-learn releases on libraries.io to be notified when new versions are released.

1.8 Version 0.20.3

March 1, 2019
This is a bug-fix release with some minor documentation improvements and enhancements to features released in
0.20.0.

1.8.1 Changelog

sklearn.cluster

• [F IX ] Fixed a bug in cluster.KMeans where computation was single threaded when n_jobs > 1 or n_jobs =
-1. #12949 by Prabakaran Kumaresshan.

sklearn.compose

• [F IX ] Fixed a bug in compose.ColumnTransformer to handle negative indexes in the columns list of the
transformers. #12946 by Pierre Tallotte.

sklearn.covariance

• [F IX ] Fixed a regression in covariance.graphical_lasso so that the case n_features=2 is handled


correctly. #13276 by Aurélien Bellet.

1.7. Release History 25


scikit-learn user guide, Release 0.20.3

sklearn.decomposition

• [F IX ] Fixed a bug in decomposition.sparse_encode where computation was single threaded when


n_jobs > 1 or n_jobs = -1. #13005 by Prabakaran Kumaresshan.

sklearn.datasets

• [E FFICIENCY ] sklearn.datasets.fetch_openml now loads data by streaming, avoiding high memory


usage. #13312 by Joris Van den Bossche.

sklearn.feature_extraction

• [F IX ] Fixed a bug in feature_extraction.text.CountVectorizer which would result in the sparse


feature matrix having conflicting indptr and indices precisions under very large vocabularies. #11295 by Gabriel
Vacaliuc.

sklearn.impute

• [F IX ] add support for non-numeric data in sklearn.impute.MissingIndicator which was not sup-
ported while sklearn.impute.SimpleImputer was supporting this for some imputation strategies.
#13046 by Guillaume Lemaitre.

sklearn.linear_model

• [F IX ] Fixed a bug in linear_model.MultiTaskElasticNet and linear_model.


MultiTaskLasso which were breaking when warm_start = True. #12360 by Aakanksha Joshi.

sklearn.preprocessing

• [F IX ] Fixed a bug in preprocessing.KBinsDiscretizer where strategy='kmeans' fails with an


error during transformation due to unsorted bin edges. #13134 by Sandro Casagrande.
• [F IX ] Fixed a bug in preprocessing.OneHotEncoder where the deprecation of
categorical_features was handled incorrectly in combination with handle_unknown='ignore'.
#12881 by Joris Van den Bossche.
• [F IX ] Bins whose width are too small (i.e., <= 1e-8) are removed with a warning in preprocessing.
KBinsDiscretizer. #13165 by Hanmin Qin.

sklearn.svm

• [F IX ] Fixed a bug in svm.SVC, svm.NuSVC, svm.SVR, svm.NuSVR and svm.OneClassSVM where the
scale option of parameter gamma is erroneously defined as 1 / (n_features * X.std()). It’s now
defined as 1 / (n_features * X.var()). #13221 by Hanmin Qin.

26 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

1.8.2 Code and Documentation Contributors

With thanks to:


Adrin Jalali, Agamemnon Krasoulis, Albert Thomas, Andreas Mueller, Aurélien Bellet, bertrandhaut, Bharat Raghu-
nathan, Dowon, Emmanuel Arias, Fibinse Xavier, Finn O’Shea, Gabriel Vacaliuc, Gael Varoquaux, Guillaume
Lemaitre, Hanmin Qin, joaak, Joel Nothman, Joris Van den Bossche, Jérémie Méhault, kms15, Kossori Aruku, Lak-
shya KD, maikia, Manuel López-Ibáñez, Marco Gorelli, MarcoGorelli, mferrari3, Mickaël Schoentgen, Nicolas Hug,
pavlos kallis, Pierre Glaser, pierretallotte, Prabakaran Kumaresshan, Reshama Shaikh, Rohit Kapoor, Roman Yurchak,
SandroCasagrande, Tashay Green, Thomas Fan, Vishaal Kapoor, Zhuyi Xue, Zijie (ZJ) Poh

1.9 Version 0.20.2

December 20, 2018


This is a bug-fix release with some minor documentation improvements and enhancements to features released in
0.20.0.

1.9.1 Changed models

The following estimators and functions, when fit with the same data and parameters, may produce different models
from the previous version. This often occurs due to changes in the modelling logic (bug fixes or enhancements), or in
random sampling procedures.
• sklearn.neighbors when metric=='jaccard' (bug fix)
• use of 'seuclidean' or 'mahalanobis' metrics in some cases (bug fix)

1.9.2 Changelog

sklearn.compose

• [F IX ] Fixed an issue in compose.make_column_transformer which raises unexpected error when


columns is pandas Index or pandas Series. #12704 by Hanmin Qin.

sklearn.metrics

• [F IX ] Fixed a bug in metrics.pairwise_distances and metrics.


pairwise_distances_chunked where parameters V of "seuclidean" and VI of "mahalanobis"
metrics were computed after the data was split into chunks instead of being pre-computed on whole data.
#12701 by Jeremie du Boisberranger.

sklearn.neighbors

• [F IX ] Fixed sklearn.neighbors.DistanceMetric jaccard distance function to return 0 when two all-


zero vectors are compared. #12685 by Thomas Fan.

1.9. Version 0.20.2 27


scikit-learn user guide, Release 0.20.3

sklearn.utils

• [F IX ] Calling utils.check_array on pandas.Series with categorical data, which raised an error in 0.20.0,
now returns the expected output again. #12699 by Joris Van den Bossche.

1.9.3 Code and Documentation Contributors

With thanks to:


adanhawth, Adrin Jalali, Albert Thomas, Andreas Mueller, Dan Stine, Feda Curic, Hanmin Qin, Jan S, jeremiedbb,
Joel Nothman, Joris Van den Bossche, josephsalmon, Katrin Leinweber, Loic Esteve, Muhammad Hassaan Rafique,
Nicolas Hug, Olivier Grisel, Paul Paczuski, Reshama Shaikh, Sam Waterbury, Shivam Kotwalia, Thomas Fan

1.10 Version 0.20.1

November 21, 2018


This is a bug-fix release with some minor documentation improvements and enhancements to features released in
0.20.0. Note that we also include some API changes in this release, so you might get some extra warnings after
updating from 0.20.0 to 0.20.1.

1.10.1 Changed models

The following estimators and functions, when fit with the same data and parameters, may produce different models
from the previous version. This often occurs due to changes in the modelling logic (bug fixes or enhancements), or in
random sampling procedures.
• decomposition.IncrementalPCA (bug fix)

1.10.2 Changelog

sklearn.cluster

• [E FFICIENCY ] make cluster.MeanShift no longer try to do nested parallelism as the overhead would hurt
performance significantly when n_jobs > 1. #12159 by Olivier Grisel.
• [F IX ] Fixed a bug in cluster.DBSCAN with precomputed sparse neighbors graph, which would add explicitly
zeros on the diagonal even when already present. #12105 by Tom Dupre la Tour.

sklearn.compose

• [F IX ] Fixed an issue in compose.ColumnTransformer when stacking columns with types not convertible
to a numeric. #11912 by Adrin Jalali.
• [API C HANGE ] compose.ColumnTransformer now applies the sparse_threshold even if all trans-
formation results are sparse. #12304 by Andreas Müller.
• [API C HANGE ] compose.make_column_transformer now expects (transformer, columns) in-
stead of (columns, transformer) to keep consistent with compose.ColumnTransformer. #12339
by Adrin Jalali.

28 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

sklearn.datasets

• [F IX ] datasets.fetch_openml to correctly use the local cache. #12246 by Jan N. van Rijn.
• [F IX ] datasets.fetch_openml to correctly handle ignore attributes and row id attributes. #12330 by Jan
N. van Rijn.
• [F IX ] Fixed integer overflow in datasets.make_classification for values of n_informative pa-
rameter larger than 64. #10811 by Roman Feldbauer.
• [F IX ] Fixed olivetti faces dataset DESCR attribute to point to the right location in datasets.
fetch_olivetti_faces. #12441 by Jérémie du Boisberranger
• [F IX ] datasets.fetch_openml to retry downloading when reading from local cache fails. #12517 by
Thomas Fan.

sklearn.decomposition

• [F IX ] Fixed a regression in decomposition.IncrementalPCA where 0.20.0 raised an error if the number


of samples in the final batch for fitting IncrementalPCA was smaller than n_components. #12234 by Ming Li.

sklearn.ensemble

• [F IX ] Fixed a bug mostly affecting ensemble.RandomForestClassifier where


class_weight='balanced_subsample' failed with more than 32 classes. #12165 by Joel Nothman.
• [F IX ] Fixed a bug affecting ensemble.BaggingClassifier, ensemble.BaggingRegressor and
ensemble.IsolationForest, where max_features was sometimes rounded down to zero. #12388
by Connor Tann.

sklearn.feature_extraction

• [F IX ] Fixed a regression in v0.20.0 where feature_extraction.text.CountVectorizer and other


text vectorizers could error during stop words validation with custom preprocessors or tokenizers. #12393 by
Roman Yurchak.

sklearn.linear_model

• [F IX ] linear_model.SGDClassifier and variants with early_stopping=True would not use a


consistent validation split in the multiclass case and this would cause a crash when using those estimators as
part of parallel parameter search or cross-validation. #12122 by Olivier Grisel.
• [F IX ] Fixed a bug affecting SGDClassifier in the multiclass case. Each one-versus-all step is run in a
joblib.Parallel call and mutating a common parameter, causing a segmentation fault if called within a
backend using processes and not threads. We now use require=sharedmem at the joblib.Parallel
instance creation. #12518 by Pierre Glaser and Olivier Grisel.

sklearn.metrics

• [F IX ] Fixed a bug in metrics.pairwise.pairwise_distances_argmin_min which returned the


square root of the distance when the metric parameter was set to “euclidean”. #12481 by Jérémie du Boisber-
ranger.

1.10. Version 0.20.1 29


scikit-learn user guide, Release 0.20.3

• [F IX ] Fixed a bug in metrics.pairwise.pairwise_distances_chunked which didn’t ensure the


diagonal is zero for euclidean distances. #12612 by Andreas Müller.
• [API C HANGE ] The metrics.calinski_harabaz_score has been renamed to metrics.
calinski_harabasz_score and will be removed in version 0.23. #12211 by Lisa Thomas, Mark Hannel
and Melissa Ferrari.

sklearn.mixture

• [F IX ] Ensure that the fit_predict method of mixture.GaussianMixture and mixture.


BayesianGaussianMixture always yield assignments consistent with fit followed by predict even
if the convergence criterion is too loose or not met. #12451 by Olivier Grisel.

sklearn.neighbors

• [F IX ] force the parallelism backend to threading for neighbors.KDTree and neighbors.BallTree


in Python 2.7 to avoid pickling errors caused by the serialization of their methods. #12171 by Thomas Moreau.

sklearn.preprocessing

• [F IX ] Fixed bug in preprocessing.OrdinalEncoder when passing manually specified categories.


#12365 by Joris Van den Bossche.
• [F IX ] Fixed bug in preprocessing.KBinsDiscretizer where the transform method mutates the
_encoder attribute. The transform method is now thread safe. #12514 by Hanmin Qin.
• [F IX ] Fixed a bug in preprocessing.PowerTransformer where the Yeo-Johnson transform was incor-
rect for lambda parameters outside of [0, 2] #12522 by Nicolas Hug.
• [F IX ] Fixed a bug in preprocessing.OneHotEncoder where transform failed when set to ignore un-
known numpy strings of different lengths #12471 by Gabriel Marzinotto.
• [API C HANGE ] The default value of the method argument in preprocessing.power_transform will
be changed from box-cox to yeo-johnson to match preprocessing.PowerTransformer in ver-
sion 0.23. A FutureWarning is raised when the default value is used. #12317 by Eric Chang.

sklearn.utils

• [F IX ] Use float64 for mean accumulator to avoid floating point precision issues in preprocessing.
StandardScaler and decomposition.IncrementalPCA when using float32 datasets. #12338 by
bauks.
• [F IX ] Calling utils.check_array on pandas.Series, which raised an error in 0.20.0, now returns the ex-
pected output again. #12625 by Andreas Müller

Miscellaneous

• [F IX ] When using site joblib by setting the environment variable SKLEARN_SITE_JOBLIB, added compatibility
with joblib 0.11 in addition to 0.12+. #12350 by Joel Nothman and Roman Yurchak.
• [F IX ] Make sure to avoid raising FutureWarning when calling np.vstack with numpy 1.16 and later (use
list comprehensions instead of generator expressions in many locations of the scikit-learn code base). #12467
by Olivier Grisel.

30 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• [API C HANGE ] Removed all mentions of sklearn.externals.joblib, and deprecated joblib


methods exposed in sklearn.utils, except for utils.parallel_backend and utils.
register_parallel_backend, which allow users to configure parallel computation in scikit-learn. Other
functionalities are part of joblib. package and should be used directly, by installing it. The goal of this change
is to prepare for unvendoring joblib in future version of scikit-learn. #12345 by Thomas Moreau

1.10.3 Code and Documentation Contributors

With thanks to:


^__^, Adrin Jalali, Andrea Navarrete, Andreas Mueller, bauks, BenjaStudio, Cheuk Ting Ho, Connossor, Corey Levin-
son, Dan Stine, daten-kieker, Denis Kataev, Dillon Gardner, Dmitry Vukolov, Dougal J. Sutherland, Edward J Brown,
Eric Chang, Federico Caselli, Gabriel Marzinotto, Gael Varoquaux, GauravAhlawat, Gustavo De Mari Pereira, Han-
min Qin, haroldfox, JackLangerman, Jacopo Notarstefano, janvanrijn, jdethurens, jeremiedbb, Joel Nothman, Joris
Van den Bossche, Koen, Kushal Chauhan, Lee Yi Jie Joel, Lily Xiong, mail-liam, Mark Hannel, melsyt, Ming Li,
Nicholas Smith, Nicolas Hug, Nikolay Shebanov, Oleksandr Pavlyk, Olivier Grisel, Peter Hausamann, Pierre Glaser,
Pulkit Maloo, Quentin Batista, Radostin Stoyanov, Ramil Nugmanov, Rebekah Kim, Reshama Shaikh, Rohan Singh,
Roman Feldbauer, Roman Yurchak, Roopam Sharma, Sam Waterbury, Scott Lowe, Sebastian Raschka, Stephen Tier-
ney, SylvainLan, TakingItCasual, Thomas Fan, Thomas Moreau, Tom Dupré la Tour, Tulio Casagrande, Utkarsh
Upadhyay, Xing Han Lu, Yaroslav Halchenko, Zach Miller

1.11 Version 0.20.0

September 25, 2018


This release packs in a mountain of bug fixes, features and enhancements for the Scikit-learn library, and improvements
to the documentation and examples. Thanks to our contributors!
This release is dedicated to the memory of Raghav Rajagopalan.

Warning: Version 0.20 is the last version of scikit-learn to support Python 2.7 and Python 3.4. Scikit-learn 0.21
will require Python 3.5 or higher.

1.11.1 Highlights

We have tried to improve our support for common data-science use-cases including missing values, categorical vari-
ables, heterogeneous data, and features/targets with unusual distributions. Missing values in features, represented by
NaNs, are now accepted in column-wise preprocessing such as scalers. Each feature is fitted disregarding NaNs, and
data containing NaNs can be transformed. The new impute module provides estimators for learning despite missing
data.
ColumnTransformer handles the case where different features or columns of a pandas.DataFrame need dif-
ferent preprocessing. String or pandas Categorical columns can now be encoded with OneHotEncoder or
OrdinalEncoder.
TransformedTargetRegressor helps when the regression target needs to be transformed to be modeled.
PowerTransformer and KBinsDiscretizer join QuantileTransformer as non-linear transformations.
Beyond this, we have added sample_weight support to several estimators (including KMeans,
BayesianRidge and KernelDensity) and improved stopping criteria in others (including MLPRegressor,
GradientBoostingRegressor and SGDRegressor).

1.11. Version 0.20.0 31


scikit-learn user guide, Release 0.20.3

This release is also the first to be accompanied by a Glossary of Common Terms and API Elements developed by Joel
Nothman. The glossary is a reference resource to help users and contributors become familiar with the terminology
and conventions used in Scikit-learn.
Sorry if your contribution didn’t make it into the highlights. There’s a lot here. . .

1.11.2 Changed models

The following estimators and functions, when fit with the same data and parameters, may produce different models
from the previous version. This often occurs due to changes in the modelling logic (bug fixes or enhancements), or in
random sampling procedures.
• cluster.MeanShift (bug fix)
• decomposition.IncrementalPCA in Python 2 (bug fix)
• decomposition.SparsePCA (bug fix)
• ensemble.GradientBoostingClassifier (bug fix affecting feature importances)
• isotonic.IsotonicRegression (bug fix)
• linear_model.ARDRegression (bug fix)
• linear_model.LogisticRegressionCV (bug fix)
• linear_model.OrthogonalMatchingPursuit (bug fix)
• linear_model.PassiveAggressiveClassifier (bug fix)
• linear_model.PassiveAggressiveRegressor (bug fix)
• linear_model.Perceptron (bug fix)
• linear_model.SGDClassifier (bug fix)
• linear_model.SGDRegressor (bug fix)
• metrics.roc_auc_score (bug fix)
• metrics.roc_curve (bug fix)
• neural_network.BaseMultilayerPerceptron (bug fix)
• neural_network.MLPClassifier (bug fix)
• neural_network.MLPRegressor (bug fix)
• The v0.19.0 release notes failed to mention a backwards incompatibility with model_selection.
StratifiedKFold when shuffle=True due to #7823.
Details are listed in the changelog below.
(While we are trying to better inform users by providing this information, we cannot assure that this list is complete.)

1.11.3 Known Major Bugs

• #11924: linear_model.LogisticRegressionCV with solver=’lbfgs’ and multi_class=’multinomial’


may be non-deterministic or otherwise broken on macOS. This appears to be the case on Travis CI servers, but
has not been confirmed on personal MacBooks! This issue has been present in previous releases.

32 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• #9354: metrics.pairwise.euclidean_distances (which is used several times throughout the li-


brary) gives results with poor precision, which particularly affects its use with 32-bit float inputs. This became
more problematic in versions 0.18 and 0.19 when some algorithms were changed to avoid casting 32-bit data
into 64-bit.

1.11.4 Changelog

Support for Python 3.3 has been officially dropped.

sklearn.cluster

• [M AJOR F EATURE ] cluster.AgglomerativeClustering now supports Single Linkage clustering via


linkage='single'. #9372 by Leland McInnes and Steve Astels.
• [F EATURE ] cluster.KMeans and cluster.MiniBatchKMeans now support sample weights via new
parameter sample_weight in fit function. #10933 by Johannes Hansen.
• [E FFICIENCY ] cluster.KMeans, cluster.MiniBatchKMeans and cluster.k_means passed with
algorithm='full' now enforces row-major ordering, improving runtime. #10471 by Gaurav Dhingra.
• [E FFICIENCY ] cluster.DBSCAN now is parallelized according to n_jobs regardless of algorithm. #8003
by Joël Billaud.
• [E NHANCEMENT ] cluster.KMeans now gives a warning if the number of distinct clusters found is smaller
than n_clusters. This may occur when the number of distinct points in the data set is actually smaller than
the number of cluster one is looking for. #10059 by Christian Braune.
• [F IX ] Fixed a bug where the fit method of cluster.AffinityPropagation stored cluster centers as 3d
array instead of 2d array in case of non-convergence. For the same class, fixed undefined and arbitrary behavior
in case of training data where all samples had equal similarity. #9612. By Jonatan Samoocha.
• [F IX ] Fixed a bug in cluster.spectral_clustering where the normalization of the spectrum was
using a division instead of a multiplication. #8129 by Jan Margeta, Guillaume Lemaitre, and Devansh D..
• [F IX ] Fixed a bug in cluster.k_means_elkan where the returned iteration was 1 less than the correct
value. Also added the missing n_iter_ attribute in the docstring of cluster.KMeans. #11353 by Jeremie
du Boisberranger.
• [F IX ] Fixed a bug in cluster.mean_shift where the assigned labels were not deterministic if there were
multiple clusters with the same intensities. #11901 by Adrin Jalali.
• [API C HANGE ] Deprecate pooling_func unused parameter in cluster.
AgglomerativeClustering. #9875 by Kumar Ashutosh.

sklearn.compose

• New module.
• [M AJOR F EATURE ] Added compose.ColumnTransformer, which allows to apply different transformers
to different columns of arrays or pandas DataFrames. #9012 by Andreas Müller and Joris Van den Bossche, and
#11315 by Thomas Fan.
• [M AJOR F EATURE ] Added the compose.TransformedTargetRegressor which transforms the target y
before fitting a regression model. The predictions are mapped back to the original space via an inverse transform.
#9041 by Andreas Müller and Guillaume Lemaitre.

1.11. Version 0.20.0 33


scikit-learn user guide, Release 0.20.3

sklearn.covariance

• [E FFICIENCY ] Runtime improvements to covariance.GraphicalLasso. #9858 by Steven Brown.


• [API C HANGE ] The covariance.graph_lasso, covariance.GraphLasso and covariance.
GraphLassoCV have been renamed to covariance.graphical_lasso, covariance.
GraphicalLasso and covariance.GraphicalLassoCV respectively and will be removed in
version 0.22. #9993 by Artiem Krinitsyn

sklearn.datasets

• [M AJOR F EATURE ] Added datasets.fetch_openml to fetch datasets from OpenML. OpenML is a free,
open data sharing platform and will be used instead of mldata as it provides better service availability. #9908 by
Andreas Müller and Jan N. van Rijn.
• [F EATURE ] In datasets.make_blobs, one can now pass a list to the n_samples parameter to indicate
the number of samples to generate per cluster. #8617 by Maskani Filali Mohamed and Konstantinos Katrioplas.
• [F EATURE ] Add filename attribute to datasets that have a CSV file. #9101 by alex-33 and Maskani Filali
Mohamed.
• [F EATURE ] return_X_y parameter has been added to several dataset loaders. #10774 by Chris Catalfo.
• [F IX ] Fixed a bug in datasets.load_boston which had a wrong data point. #10795 by Takeshi
Yoshizawa.
• [F IX ] Fixed a bug in datasets.load_iris which had two wrong data points. #11082 by Sadhana Srini-
vasan and Hanmin Qin.
• [F IX ] Fixed a bug in datasets.fetch_kddcup99, where data were not properly shuffled. #9731 by Nico-
las Goix.
• [F IX ] Fixed a bug in datasets.make_circles, where no odd number of data points could be generated.
#10045 by Christian Braune.
• [API C HANGE ] Deprecated sklearn.datasets.fetch_mldata to be removed in version 0.22. ml-
data.org is no longer operational. Until removal it will remain possible to load cached datasets. #11466 by
Joel Nothman.

sklearn.decomposition

• [F EATURE ] decomposition.dict_learning functions and models now support positivity constraints.


This applies to the dictionary and sparse code. #6374 by John Kirkham.
• [F EATURE ] [F IX ] decomposition.SparsePCA now exposes normalize_components. When set to
True, the train and test data are centered with the train mean repsectively during the fit phase and the transform
phase. This fixes the behavior of SparsePCA. When set to False, which is the default, the previous abnormal
behaviour still holds. The False value is for backward compatibility and should not be used. #11585 by Ivan
Panico.
• [E FFICIENCY ] Efficiency improvements in decomposition.dict_learning. #11420 and others by John
Kirkham.
• [F IX ] Fix for uninformative error in decomposition.IncrementalPCA: now an error is raised if the
number of components is larger than the chosen batch size. The n_components=None case was adapted
accordingly. #6452. By Wally Gauze.
• [F IX ] Fixed a bug where the partial_fit method of decomposition.IncrementalPCA used integer
division instead of float division on Python 2. #9492 by James Bourbeau.

34 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• [F IX ] In decomposition.PCA selecting a n_components parameter greater than the number of samples now
raises an error. Similarly, the n_components=None case now selects the minimum of n_samples and
n_features. #8484 by Wally Gauze.
• [F IX ] Fixed a bug in decomposition.PCA where users will get unexpected error with large datasets when
n_components='mle' on Python 3 versions. #9886 by Hanmin Qin.
• [F IX ] Fixed an underflow in calculating KL-divergence for decomposition.NMF #10142 by Tom Dupre la
Tour.
• [F IX ] Fixed a bug in decomposition.SparseCoder when running OMP sparse coding in parallel using
read-only memory mapped datastructures. #5956 by Vighnesh Birodkar and Olivier Grisel.

sklearn.discriminant_analysis

• [E FFICIENCY ] Memory usage improvement for _class_means and _class_cov in


discriminant_analysis. #10898 by Nanxin Chen.

sklearn.dummy

• [F EATURE ] dummy.DummyRegressor now has a return_std option in its predict method. The re-
turned standard deviations will be zeros.
• [F EATURE ] dummy.DummyClassifier and dummy.DummyRegressor now only require X to be an ob-
ject with finite length or shape. #9832 by Vrishank Bhardwaj.
• [F EATURE ] dummy.DummyClassifier and dummy.DummyRegressor can now be scored without sup-
plying test samples. #11951 by Rüdiger Busche.

sklearn.ensemble

• [F EATURE ] ensemble.BaggingRegressor and ensemble.BaggingClassifier can now be fit


with missing/non-finite values in X and/or multi-output Y to support wrapping pipelines that perform their
own imputation. #9707 by Jimmy Wan.
• [F EATURE ] ensemble.GradientBoostingClassifier and ensemble.
GradientBoostingRegressor now support early stopping via n_iter_no_change,
validation_fraction and tol. #7071 by Raghav RV
• [F EATURE ] Added named_estimators_ parameter in ensemble.VotingClassifier to access fitted
estimators. #9157 by Herilalaina Rakotoarison.
• [F IX ] Fixed a bug when fitting ensemble.GradientBoostingClassifier or ensemble.
GradientBoostingRegressor with warm_start=True which previously raised a segmentation fault
due to a non-conversion of CSC matrix into CSR format expected by decision_function. Similarly,
Fortran-ordered arrays are converted to C-ordered arrays in the dense case. #9991 by Guillaume Lemaitre.
• [F IX ] Fixed a bug in ensemble.GradientBoostingRegressor and ensemble.
GradientBoostingClassifier to have feature importances summed and then normalized, rather
than normalizing on a per-tree basis. The previous behavior over-weighted the Gini importance of features that
appear in later stages. This issue only affected feature importances. #11176 by Gil Forsyth.
• [API C HANGE ] The default value of the n_estimators parameter of ensemble.
RandomForestClassifier, ensemble.RandomForestRegressor, ensemble.
ExtraTreesClassifier, ensemble.ExtraTreesRegressor, and ensemble.
RandomTreesEmbedding will change from 10 in version 0.20 to 100 in 0.22. A FutureWarning is
raised when the default value is used. #11542 by Anna Ayzenshtat.

1.11. Version 0.20.0 35


scikit-learn user guide, Release 0.20.3

• [API C HANGE ] Classes derived from ensemble.BaseBagging. The attribute estimators_samples_


will return a list of arrays containing the indices selected for each bootstrap instead of a list of arrays containing
the mask of the samples selected for each bootstrap. Indices allows to repeat samples while mask does not allow
this functionality. #9524 by Guillaume Lemaitre.
• [F IX ] ensemble.BaseBagging where one could not deterministically reproduce fit result using the object
attributes when random_state is set. #9723 by Guillaume Lemaitre.

sklearn.feature_extraction

• [F EATURE ] Enable the call to get_feature_names in unfitted feature_extraction.text.


CountVectorizer initialized with a vocabulary. #10908 by Mohamed Maskani.
• [E NHANCEMENT ] idf_ can now be set on a feature_extraction.text.TfidfTransformer.
#10899 by Sergey Melderis.
• [F IX ] Fixed a bug in feature_extraction.image.extract_patches_2d which would throw an
exception if max_patches was greater than or equal to the number of all possible patches rather than simply
returning the number of possible patches. #10101 by Varun Agrawal
• [F IX ] Fixed a bug in feature_extraction.text.CountVectorizer, feature_extraction.
text.TfidfVectorizer, feature_extraction.text.HashingVectorizer to support 64 bit
sparse array indexing necessary to process large datasets with more than 2·109 tokens (words or n-grams).
#9147 by Claes-Fredrik Mannby and Roman Yurchak.
• [F IX ] Fixed bug in feature_extraction.text.TfidfVectorizer which was ignoring the parame-
ter dtype. In addition, feature_extraction.text.TfidfTransformer will preserve dtype for
floating and raise a warning if dtype requested is integer. #10441 by Mayur Kulkarni and Guillaume Lemaitre.

sklearn.feature_selection

• [F EATURE ] Added select K best features functionality to feature_selection.SelectFromModel.


#6689 by Nihar Sheth and Quazi Rahman.
• [F EATURE ] Added min_features_to_select parameter to feature_selection.RFECV to bound
evaluated features counts. #11293 by Brent Yi.
• [F EATURE ] feature_selection.RFECV ’s fit method now supports groups. #9656 by Adam Greenhall.
• [F IX ] Fixed computation of n_features_to_compute for edge case with tied CV scores in
feature_selection.RFECV . #9222 by Nick Hoh.

sklearn.gaussian_process

• [E FFICIENCY ] In gaussian_process.GaussianProcessRegressor, method predict is faster


when using return_std=True in particular more when called several times in a row. #9234 by andrewww
and Minghui Liu.

sklearn.impute

• New module, adopting preprocessing.Imputer as impute.SimpleImputer with minor changes


(see under preprocessing below).
• [M AJOR F EATURE ] Added impute.MissingIndicator which generates a binary indicator for missing
values. #8075 by Maniteja Nandana and Guillaume Lemaitre.

36 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• [F EATURE ] The impute.SimpleImputer has a new strategy, 'constant', to complete missing values
with a fixed one, given by the fill_value parameter. This strategy supports numeric and non-numeric data,
and so does the 'most_frequent' strategy now. #11211 by Jeremie du Boisberranger.

sklearn.isotonic

• [F IX ] Fixed a bug in isotonic.IsotonicRegression which incorrectly combined weights when fitting


a model to data involving points with identical X values. #9484 by Dallas Card

sklearn.linear_model

• [F EATURE ] linear_model.SGDClassifier, linear_model.SGDRegressor, linear_model.


PassiveAggressiveClassifier, linear_model.PassiveAggressiveRegressor and
linear_model.Perceptron now expose early_stopping, validation_fraction and
n_iter_no_change parameters, to stop optimization monitoring the score on a validation set. A new learn-
ing rate "adaptive" strategy divides the learning rate by 5 each time n_iter_no_change consecutive
epochs fail to improve the model. #9043 by Tom Dupre la Tour.
• [F EATURE ] Add sample_weight parameter to the fit method of linear_model.BayesianRidge for
weighted linear regression. #10112 by Peter St. John.
• [F IX ] Fixed a bug in logistic.logistic_regression_path to ensure that the returned coefficients
are correct when multiclass='multinomial'. Previously, some of the coefficients would override each
other, leading to incorrect results in linear_model.LogisticRegressionCV . #11724 by Nicolas Hug.
• [F IX ] Fixed a bug in linear_model.LogisticRegression where when using the parameter
multi_class='multinomial', the predict_proba method was returning incorrect probabilities in
the case of binary outcomes. #9939 by Roger Westover.
• [F IX ] Fixed a bug in linear_model.LogisticRegressionCV where the score method always com-
putes accuracy, not the metric given by the scoring parameter. #10998 by Thomas Fan.
• [F IX ] Fixed a bug in linear_model.LogisticRegressionCV where the ‘ovr’ strategy was always used
to compute cross-validation scores in the multiclass setting, even if 'multinomial' was set. #8720 by
William de Vazelhes.
• [F IX ] Fixed a bug in linear_model.OrthogonalMatchingPursuit that was broken when setting
normalize=False. #10071 by Alexandre Gramfort.
• [F IX ] Fixed a bug in linear_model.ARDRegression which caused incorrectly updated estimates for the
standard deviation and the coefficients. #10153 by Jörg Döpfert.
• [F IX ] Fixed a bug in linear_model.ARDRegression and linear_model.BayesianRidge which
caused NaN predictions when fitted with a constant target. #10095 by Jörg Döpfert.
• [F IX ] Fixed a bug in linear_model.RidgeClassifierCV where the parameter store_cv_values
was not implemented though it was documented in cv_values as a way to set up the storage of cross-
validation values for different alphas. #10297 by Mabel Villalba-Jiménez.
• [F IX ] Fixed a bug in linear_model.ElasticNet which caused the input to be overridden when using
parameter copy_X=True and check_input=False. #10581 by Yacine Mazari.
• [F IX ] Fixed a bug in sklearn.linear_model.Lasso where the coefficient had wrong shape when
fit_intercept=False. #10687 by Martin Hahn.
• [F IX ] Fixed a bug in sklearn.linear_model.LogisticRegression where the
multi_class='multinomial' with binary output with warm_start=True #10836 by Aish-
warya Srinivasan.

1.11. Version 0.20.0 37


scikit-learn user guide, Release 0.20.3

• [F IX ] Fixed a bug in linear_model.RidgeCV where using integer alphas raised an error. #10397 by
Mabel Villalba-Jiménez.
• [F IX ] Fixed condition triggering gap computation in linear_model.Lasso and linear_model.
ElasticNet when working with sparse matrices. #10992 by Alexandre Gramfort.
• [F IX ] Fixed a bug in linear_model.SGDClassifier, linear_model.
SGDRegressor, linear_model.PassiveAggressiveClassifier, linear_model.
PassiveAggressiveRegressor and linear_model.Perceptron, where the stopping criterion
was stopping the algorithm before convergence. A parameter n_iter_no_change was added and set by
default to 5. Previous behavior is equivalent to setting the parameter to 1. #9043 by Tom Dupre la Tour.
• [F IX ] Fixed a bug where liblinear and libsvm-based estimators would segfault if passed a scipy.sparse matrix
with 64-bit indices. They now raise a ValueError. #11327 by Karan Dhingra and Joel Nothman.
• [API C HANGE ] The default values of the solver and multi_class parameters of linear_model.
LogisticRegression will change respectively from 'liblinear' and 'ovr' in version 0.20 to
'lbfgs' and 'auto' in version 0.22. A FutureWarning is raised when the default values are used. #11905
by Tom Dupre la Tour and Joel Nothman.
• [API C HANGE ] Deprecate positive=True option in linear_model.Lars as the underlying implemen-
tation is broken. Use linear_model.Lasso instead. #9837 by Alexandre Gramfort.
• [API C HANGE ] n_iter_ may vary from previous releases in linear_model.LogisticRegression
with solver='lbfgs' and linear_model.HuberRegressor. For Scipy <= 1.0.0, the optimizer could
perform more than the requested maximum number of iterations. Now both estimators will report at most
max_iter iterations even if more were performed. #10723 by Joel Nothman.

sklearn.manifold

• [E FFICIENCY ] Speed improvements for both ‘exact’ and ‘barnes_hut’ methods in manifold.TSNE. #10593
and #10610 by Tom Dupre la Tour.
• [F EATURE ] Support sparse input in manifold.Isomap.fit. #8554 by Leland McInnes.
• [F EATURE ] manifold.t_sne.trustworthiness accepts metrics other than Euclidean. #9775 by
William de Vazelhes.
• [F IX ] Fixed a bug in manifold.spectral_embedding where the normalization of the spectrum was
using a division instead of a multiplication. #8129 by Jan Margeta, Guillaume Lemaitre, and Devansh D..
• [API C HANGE ] [F EATURE ] Deprecate precomputed parameter in function manifold.t_sne.
trustworthiness. Instead, the new parameter metric should be used with any compatible metric in-
cluding ‘precomputed’, in which case the input matrix X should be a matrix of pairwise distances or squared
distances. #9775 by William de Vazelhes.
• [API C HANGE ] Deprecate precomputed parameter in function manifold.t_sne.trustworthiness.
Instead, the new parameter metric should be used with any compatible metric including ‘precomputed’, in
which case the input matrix X should be a matrix of pairwise distances or squared distances. #9775 by William
de Vazelhes.

sklearn.metrics

• [M AJOR F EATURE ] Added the metrics.davies_bouldin_score metric for evaluation of clustering mod-
els without a ground truth. #10827 by Luis Osa.
• [M AJOR F EATURE ] Added the metrics.balanced_accuracy_score metric and a corresponding
'balanced_accuracy' scorer for binary and multiclass classification. #8066 by @xyguo and Aman
Dalmia, and #10587 by Joel Nothman.

38 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• [F EATURE ] Partial AUC is available via max_fpr parameter in metrics.roc_auc_score. #3840 by


Alexander Niederbühl.
• [F EATURE ] A scorer based on metrics.brier_score_loss is also available. #9521 by Hanmin Qin.
• [F EATURE ] Added control over the normalization in metrics.normalized_mutual_info_score and
metrics.adjusted_mutual_info_score via the average_method parameter. In version 0.22, the
default normalizer for each will become the arithmetic mean of the entropies of each clustering. #11124 by
Arya McCarthy.
• [F EATURE ] Added output_dict parameter in metrics.classification_report to return classifi-
cation statistics as dictionary. #11160 by Dan Barkhorn.
• [F EATURE ] metrics.classification_report now reports all applicable averages on the given data, in-
cluding micro, macro and weighted average as well as samples average for multilabel data. #11679 by Alexander
Pacha.
• [F EATURE ] metrics.average_precision_score now supports binary y_true other than {0, 1} or
{-1, 1} through pos_label parameter. #9980 by Hanmin Qin.
• [F EATURE ] metrics.label_ranking_average_precision_score now supports
sample_weight. #10845 by Jose Perez-Parras Toledano.
• [F EATURE ] Add dense_output parameter to metrics.pairwise.linear_kernel. When False and
both inputs are sparse, will return a sparse matrix. #10999 by Taylor G Smith.
• [E FFICIENCY ] metrics.silhouette_score and metrics.silhouette_samples are more mem-
ory efficient and run faster. This avoids some reported freezes and MemoryErrors. #11135 by Joel Nothman.
• [F IX ] Fixed a bug in metrics.precision_recall_fscore_support when truncated range(n_labels)
is passed as value for labels. #10377 by Gaurav Dhingra.
• [F IX ] Fixed a bug due to floating point error in metrics.roc_auc_score with non-integer sample weights.
#9786 by Hanmin Qin.
• [F IX ] Fixed a bug where metrics.roc_curve sometimes starts on y-axis instead of (0, 0), which is in-
consistent with the document and other implementations. Note that this will not influence the result from
metrics.roc_auc_score #10093 by alexryndin and Hanmin Qin.
• [F IX ] Fixed a bug to avoid integer overflow. Casted product to 64 bits integer in metrics.
mutual_info_score. #9772 by Kumar Ashutosh.
• [F IX ] Fixed a bug where metrics.average_precision_score will sometimes return nan when
sample_weight contains 0. #9980 by Hanmin Qin.
• [F IX ] Fixed a bug in metrics.fowlkes_mallows_score to avoid integer overflow. Casted return value
of contingency_matrix to int64 and computed product of square roots rather than square root of product. #9515
by Alan Liddell and Manh Dao.
• [API C HANGE ] Deprecate reorder parameter in metrics.auc as it’s no longer required for metrics.
roc_auc_score. Moreover using reorder=True can hide bugs due to floating point error in the input.
#9851 by Hanmin Qin.
• [API C HANGE ] In metrics.normalized_mutual_info_score and metrics.
adjusted_mutual_info_score, warn that average_method will have a new default value.
In version 0.22, the default normalizer for each will become the arithmetic mean of the entropies of
each clustering. Currently, metrics.normalized_mutual_info_score uses the default of
average_method='geometric', and metrics.adjusted_mutual_info_score uses the
default of average_method='max' to match their behaviors in version 0.19. #11124 by Arya McCarthy.
• [API C HANGE ] The batch_size parameter to metrics.pairwise_distances_argmin_min and
metrics.pairwise_distances_argmin is deprecated to be removed in v0.22. It no longer has any ef-

1.11. Version 0.20.0 39


scikit-learn user guide, Release 0.20.3

fect, as batch size is determined by global working_memory config. See Limiting Working Memory. #10280
by Joel Nothman and Aman Dalmia.

sklearn.mixture

• [F EATURE ] Added function fit_predict to mixture.GaussianMixture and mixture.


GaussianMixture, which is essentially equivalent to calling fit and predict. #10336 by Shu Haoran
and Andrew Peng.
• [F IX ] Fixed a bug in mixture.BaseMixture where the reported n_iter_ was missing an iteration. It af-
fected mixture.GaussianMixture and mixture.BayesianGaussianMixture. #10740 by Erich
Schubert and Guillaume Lemaitre.
• [F IX ] Fixed a bug in mixture.BaseMixture and its subclasses mixture.GaussianMixture and
mixture.BayesianGaussianMixture where the lower_bound_ was not the max lower bound across
all initializations (when n_init > 1), but just the lower bound of the last initialization. #10869 by Aurélien
Géron.

sklearn.model_selection

• [F EATURE ] Add return_estimator parameter in model_selection.cross_validate to return estimators


fitted on each split. #9686 by Aurélien Bellet.
• [F EATURE ] New refit_time_ attribute will be stored in model_selection.GridSearchCV and
model_selection.RandomizedSearchCV if refit is set to True. This will allow measuring the
complete time it takes to perform hyperparameter optimization and refitting the best model on the whole dataset.
#11310 by Matthias Feurer.
• [F EATURE ] Expose error_score parameter in model_selection.cross_validate,
model_selection.cross_val_score, model_selection.learning_curve and
model_selection.validation_curve to control the behavior triggered when an error occurs in
model_selection._fit_and_score. #11576 by Samuel O. Ronsin.
• [F EATURE ] BaseSearchCV now has an experimental, private interface to support customized parameter
search strategies, through its _run_search method. See the implementations in model_selection.
GridSearchCV and model_selection.RandomizedSearchCV and please provide feedback if you
use this. Note that we do not assure the stability of this API beyond version 0.20. #9599 by Joel Nothman
• [E NHANCEMENT ] Add improved error message in model_selection.cross_val_score when multiple
metrics are passed in scoring keyword. #11006 by Ming Li.
• [API C HANGE ] The default number of cross-validation folds cv and the default number of splits n_splits in
the model_selection.KFold-like splitters will change from 3 to 5 in 0.22 as 3-fold has a lot of variance.
#11557 by Alexandre Boucaud.
• [API C HANGE ] The default of iid parameter of model_selection.GridSearchCV and
model_selection.RandomizedSearchCV will change from True to False in version 0.22 to
correspond to the standard definition of cross-validation, and the parameter will be removed in version
0.24 altogether. This parameter is of greatest practical significance where the sizes of different test sets in
cross-validation were very unequal, i.e. in group-based CV strategies. #9085 by Laurent Direr and Andreas
Müller.
• [API C HANGE ] The default value of the error_score parameter in model_selection.GridSearchCV
and model_selection.RandomizedSearchCV will change to np.NaN in version 0.22. #10677 by
Kirill Zhdanovich.

40 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• [API C HANGE ] Changed ValueError exception raised in model_selection.ParameterSampler to a


UserWarning for case where the class is instantiated with a greater value of n_iter than the total space of
parameters in the parameter grid. n_iter now acts as an upper bound on iterations. #10982 by Juliet Lawton
• [API C HANGE ] Invalid input for model_selection.ParameterGrid now raises TypeError. #10928 by
Solutus Immensus

sklearn.multioutput

• [M AJOR F EATURE ] Added multioutput.RegressorChain for multi-target regression. #9257 by Kumar


Ashutosh.

sklearn.naive_bayes

• [M AJOR F EATURE ] Added naive_bayes.ComplementNB, which implements the Complement Naive Bayes
classifier described in Rennie et al. (2003). #8190 by Michael A. Alcorn.
• [F EATURE ] Add var_smoothing parameter in naive_bayes.GaussianNB to give a precise control over
variances calculation. #9681 by Dmitry Mottl.
• [F IX ] Fixed a bug in naive_bayes.GaussianNB which incorrectly raised error for prior list which summed
to 1. #10005 by Gaurav Dhingra.
• [F IX ] Fixed a bug in naive_bayes.MultinomialNB which did not accept vector valued pseudocounts
(alpha). #10346 by Tobias Madsen

sklearn.neighbors

• [E FFICIENCY ] neighbors.RadiusNeighborsRegressor and neighbors.


RadiusNeighborsClassifier are now parallelized according to n_jobs regardless of algorithm.
#10887 by Joël Billaud.
• [E FFICIENCY ] Nearest neighbors query methods are now more memory efficient when
algorithm='brute'. #11136 by Joel Nothman and Aman Dalmia.
• [F EATURE ] Add sample_weight parameter to the fit method of neighbors.KernelDensity to enable
weighting in kernel density estimation. #4394 by Samuel O. Ronsin.
• [F EATURE ] Novelty detection with neighbors.LocalOutlierFactor: Add a novelty param-
eter to neighbors.LocalOutlierFactor. When novelty is set to True, neighbors.
LocalOutlierFactor can then be used for novelty detection, i.e. predict on new unseen data. Available
prediction methods are predict, decision_function and score_samples. By default, novelty is
set to False, and only the fit_predict method is avaiable. By Albert Thomas.
• [F IX ] Fixed a bug in neighbors.NearestNeighbors where fitting a NearestNeighbors model fails when
a) the distance metric used is a callable and b) the input to the NearestNeighbors model is sparse. #9579 by
Thomas Kober.
• [F IX ] Fixed a bug so predict in neighbors.RadiusNeighborsRegressor can handle empty neigh-
bor set when using non uniform weights. Also raises a new warning when no neighbors are found for samples.
#9655 by Andreas Bjerre-Nielsen.
• [F IX ] [E FFICIENCY ] Fixed a bug in KDTree construction that results in faster construction and querying times.
#11556 by Jake VanderPlas
• [F IX ] Fixed a bug in neighbors.KDTree and neighbors.BallTree where pickled tree objects would
change their type to the super class BinaryTree. #11774 by Nicolas Hug.

1.11. Version 0.20.0 41


scikit-learn user guide, Release 0.20.3

sklearn.neural_network

• [F EATURE ] Add n_iter_no_change parameter in neural_network.BaseMultilayerPerceptron,


neural_network.MLPRegressor, and neural_network.MLPClassifier to give control over
maximum number of epochs to not meet tol improvement. #9456 by Nicholas Nadeau.
• [F IX ] Fixed a bug in neural_network.BaseMultilayerPerceptron, neural_network.
MLPRegressor, and neural_network.MLPClassifier with new n_iter_no_change parameter
now at 10 from previously hardcoded 2. #9456 by Nicholas Nadeau.
• [F IX ] Fixed a bug in neural_network.MLPRegressor where fitting quit unexpectedly early due to local
minima or fluctuations. #9456 by Nicholas Nadeau

sklearn.pipeline

• [F EATURE ] The predict method of pipeline.Pipeline now passes keyword arguments on to the
pipeline’s last estimator, enabling the use of parameters such as return_std in a pipeline with caution.
#9304 by Breno Freitas.
• [API C HANGE ] pipeline.FeatureUnion now supports 'drop' as a transformer to drop features. #11144
by Thomas Fan.

sklearn.preprocessing

• [M AJOR F EATURE ] Expanded preprocessing.OneHotEncoder to allow to encode categorical string


features as a numeric array using a one-hot (or dummy) encoding scheme, and added preprocessing.
OrdinalEncoder to convert to ordinal integers. Those two classes now handle encoding of all feature types
(also handles string-valued features) and derives the categories based on the unique values in the features instead
of the maximum value in the features. #9151 and #10521 by Vighnesh Birodkar and Joris Van den Bossche.
• [M AJOR F EATURE ] Added preprocessing.KBinsDiscretizer for turning continuous features into cat-
egorical or one-hot encoded features. #7668, #9647, #10195, #10192, #11272, #11467 and #11505. by Henry
Lin, Hanmin Qin, Tom Dupre la Tour and Giovanni Giuseppe Costa.
• [M AJOR F EATURE ] Added preprocessing.PowerTransformer, which implements the Yeo-Johnson
and Box-Cox power transformations. Power transformations try to find a set of feature-wise parametric trans-
formations to approximately map data to a Gaussian distribution centered at zero and with unit variance. This is
useful as a variance-stabilizing transformation in situations where normality and homoscedasticity are desirable.
#10210 by Eric Chang and Maniteja Nandana, and #11520 by Nicolas Hug.
• [M AJOR F EATURE ] NaN values are ignored and handled in the following preprocessing methods:
preprocessing.MaxAbsScaler, preprocessing.MinMaxScaler, preprocessing.
RobustScaler, preprocessing.StandardScaler, preprocessing.PowerTransformer,
preprocessing.QuantileTransformer classes and preprocessing.maxabs_scale,
preprocessing.minmax_scale, preprocessing.robust_scale, preprocessing.scale,
preprocessing.power_transform, preprocessing.quantile_transform functions respec-
tively addressed in issues #11011, #11005, #11308, #11206, #11306, and #10437. By Lucija Gregov and
Guillaume Lemaitre.
• [F EATURE ] preprocessing.PolynomialFeatures now supports sparse input. #10452 by Aman
Dalmia and Joel Nothman.
• [F EATURE ] preprocessing.RobustScaler and preprocessing.robust_scale can be fitted us-
ing sparse matrices. #11308 by Guillaume Lemaitre.
• [F EATURE ] preprocessing.OneHotEncoder now supports the get_feature_names method to obtain the
transformed feature names. #10181 by Nirvan Anjirbag and Joris Van den Bossche.

42 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• [F EATURE ] A parameter check_inverse was added to preprocessing.FunctionTransformer to


ensure that func and inverse_func are the inverse of each other. #9399 by Guillaume Lemaitre.
• [F EATURE ] The transform method of sklearn.preprocessing.MultiLabelBinarizer now ig-
nores any unknown classes. A warning is raised stating the unknown classes classes found which are ignored.
#10913 by Rodrigo Agundez.
• [F IX ] Fixed bugs in preprocessing.LabelEncoder which would sometimes throw errors when
transform or inverse_transform was called with empty arrays. #10458 by Mayur Kulkarni.
• [F IX ] Fix ValueError in preprocessing.LabelEncoder when using inverse_transform on unseen
labels. #9816 by Charlie Newey.
• [F IX ] Fix bug in preprocessing.OneHotEncoder which discarded the dtype when returning a sparse
matrix output. #11042 by Daniel Morales.
• [F IX ] Fix fit and partial_fit in preprocessing.StandardScaler in the rare case when
with_mean=False and with_std=False which was crashing by calling fit more than once and giving in-
consistent results for mean_ whether the input was a sparse or a dense matrix. mean_ will be set to None
with both sparse and dense inputs. n_samples_seen_ will be also reported for both input types. #11235 by
Guillaume Lemaitre.
• [API C HANGE ] Deprecate n_values and categorical_features parameters and
active_features_, feature_indices_ and n_values_ attributes of preprocessing.
OneHotEncoder. The n_values parameter can be replaced with the new categories pa-
rameter, and the attributes with the new categories_ attribute. Selecting the categorical fea-
tures with the categorical_features parameter is now better supported using the compose.
ColumnTransformer. #10521 by Joris Van den Bossche.
• [API C HANGE ] Deprecate preprocessing.Imputer and move the corresponding module to impute.
SimpleImputer. #9726 by Kumar Ashutosh.
• [API C HANGE ] The axis parameter that was in preprocessing.Imputer is no longer present in
impute.SimpleImputer. The behavior is equivalent to axis=0 (impute along columns). Row-
wise imputation can be performed with FunctionTransformer (e.g., FunctionTransformer(lambda X:
SimpleImputer().fit_transform(X.T).T)). #10829 by Guillaume Lemaitre and Gilberto Olimpio.
• [API C HANGE ] The NaN marker for the missing values has been changed between the preprocessing.
Imputer and the impute.SimpleImputer. missing_values='NaN' should now be
missing_values=np.nan. #11211 by Jeremie du Boisberranger.
• [API C HANGE ] In preprocessing.FunctionTransformer, the default of validate will be from
True to False in 0.22. #10655 by Guillaume Lemaitre.

sklearn.svm

• [F IX ] Fixed a bug in svm.SVC where when the argument kernel is unicode in Python2, the
predict_proba method was raising an unexpected TypeError given dense inputs. #10412 by Jiongyan
Zhang.
• [API C HANGE ] Deprecate random_state parameter in svm.OneClassSVM as the underlying implemen-
tation is not random. #9497 by Albert Thomas.
• [API C HANGE ] The default value of gamma parameter of svm.SVC, NuSVC, SVR, NuSVR, OneClassSVM
will change from 'auto' to 'scale' in version 0.22 to account better for unscaled features. #8361 by
Gaurav Dhingra and Ting Neo.

1.11. Version 0.20.0 43


scikit-learn user guide, Release 0.20.3

sklearn.tree

• [E NHANCEMENT ] Although private (and hence not assured API stability), tree._criterion.
ClassificationCriterion and tree._criterion.RegressionCriterion may now be cim-
ported and extended. #10325 by Camil Staps.
• [F IX ] Fixed a bug in tree.BaseDecisionTree with splitter=”best” where split threshold could become
infinite when values in X were near infinite. #10536 by Jonathan Ohayon.
• [F IX ] Fixed a bug in tree.MAE to ensure sample weights are being used during the calculation of tree MAE im-
purity. Previous behaviour could cause suboptimal splits to be chosen since the impurity calculation considered
all samples to be of equal weight importance. #11464 by John Stott.

sklearn.utils

• [F EATURE ] utils.check_array and utils.check_X_y now have accept_large_sparse to con-


trol whether scipy.sparse matrices with 64-bit indices should be rejected. #11327 by Karan Dhingra and Joel
Nothman.
• [E FFICIENCY ] [F IX ] Avoid copying the data in utils.check_array when the input data is a memmap (and
copy=False). #10663 by Arthur Mensch and Loïc Estève.
• [API C HANGE ] utils.check_array yield a FutureWarning indicating that arrays of bytes/strings will
be interpreted as decimal numbers beginning in version 0.22. #10229 by Ryan Lee

Multiple modules

• [F EATURE ] [API C HANGE ] More consistent outlier detection API: Add a score_samples method
in svm.OneClassSVM , ensemble.IsolationForest, neighbors.LocalOutlierFactor,
covariance.EllipticEnvelope. It allows to access raw score functions from original pa-
pers. A new offset_ parameter allows to link score_samples and decision_function
methods. The contamination parameter of ensemble.IsolationForest and neighbors.
LocalOutlierFactor decision_function methods is used to define this offset_ such that outliers
(resp. inliers) have negative (resp. positive) decision_function values. By default, contamination
is kept unchanged to 0.1 for a deprecation period. In 0.22, it will be set to “auto”, thus using method-specific
score offsets. In covariance.EllipticEnvelope decision_function method, the raw_values
parameter is deprecated as the shifted Mahalanobis distance will be always returned in 0.22. #9015 by Nicolas
Goix.
• [F EATURE ] [API C HANGE ] A behaviour parameter has been introduced in ensemble.
IsolationForest to ensure backward compatibility. In the old behaviour, the decision_function is
independent of the contamination parameter. A threshold attribute depending on the contamination
parameter is thus used. In the new behaviour the decision_function is dependent on the
contamination parameter, in such a way that 0 becomes its natural threshold to detect outliers. Set-
ting behaviour to “old” is deprecated and will not be possible in version 0.22. Beside, the behaviour parameter
will be removed in 0.24. #11553 by Nicolas Goix.
• [API C HANGE ] Added convergence warning to svm.LinearSVC and linear_model.
LogisticRegression when verbose is set to 0. #10881 by Alexandre Sevin.
• [API C HANGE ] Changed warning type from UserWarning to exceptions.ConvergenceWarning
for failing convergence in linear_model.logistic_regression_path, linear_model.
RANSACRegressor, linear_model.ridge_regression, gaussian_process.
GaussianProcessRegressor, gaussian_process.GaussianProcessClassifier,
decomposition.fastica, cross_decomposition.PLSCanonical, cluster.
AffinityPropagation, and cluster.Birch. #10306 by Jonathan Siebert.

44 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

Miscellaneous

• [M AJOR F EATURE ] A new configuration parameter, working_memory was added to control memory con-
sumption limits in chunked operations, such as the new metrics.pairwise_distances_chunked. See
Limiting Working Memory. #10280 by Joel Nothman and Aman Dalmia.
• [F EATURE ] The version of joblib bundled with Scikit-learn is now 0.12. This uses a new default multiprocess-
ing implementation, named loky. While this may incur some memory and communication overhead, it should
provide greater cross-platform stability than relying on Python standard library multiprocessing. #11741 by the
Joblib developers, especially Thomas Moreau and Olivier Grisel.
• [F EATURE ] An environment variable to use the site joblib instead of the vendored one was added (Environment
variables). The main API of joblib is now exposed in sklearn.utils. #11166 by Gael Varoquaux.
• [F EATURE ] Add almost complete PyPy 3 support. Known unsupported functionalities are datasets.
load_svmlight_file, feature_extraction.FeatureHasher and feature_extraction.
text.HashingVectorizer. For running on PyPy, PyPy3-v5.10+, Numpy 1.14.0+, and scipy 1.1.0+ are
required. #11010 by Ronan Lamy and Roman Yurchak.
• [F EATURE ] A utility method sklearn.show_versions was added to print out information relevant for
debugging. It includes the user system, the Python executable, the version of the main libraries and BLAS
binding information. #11596 by Alexandre Boucaud
• [F IX ] Fixed a bug when setting parameters on meta-estimator, involving both a wrapped estimator and its pa-
rameter. #9999 by Marcus Voss and Joel Nothman.
• [F IX ] Fixed a bug where calling sklearn.base.clone was not thread safe and could result in a “pop from
empty list” error. #9569 by Andreas Müller.
• [API C HANGE ] The default value of n_jobs is changed from 1 to None in all related functions and classes.
n_jobs=None means unset. It will generally be interpreted as n_jobs=1, unless the current joblib.
Parallel backend context specifies otherwise (See Glossary for additional information). Note that this
change happens immediately (i.e., without a deprecation cycle). #11741 by Olivier Grisel.
• [F IX ] Fixed a bug in validation helpers where passing a Dask DataFrame results in an error. #12462 by Zachariah
Miller

1.11.5 Changes to estimator checks

These changes mostly affect library developers.


• Checks for transformers now apply if the estimator implements transform, regardless of whether it inherits from
sklearn.base.TransformerMixin. #10474 by Joel Nothman.
• Classifiers are now checked for consistency between decision_function and categorical predictions. #10500 by
Narine Kokhlikyan.
• Allow tests in utils.estimator_checks.check_estimator to test functions that accept pairwise
data. #9701 by Kyle Johnson
• Allow utils.estimator_checks.check_estimator to check that there is no private settings apart
from parameters during estimator initialization. #9378 by Herilalaina Rakotoarison
• The set of checks in utils.estimator_checks.check_estimator now includes a
check_set_params test which checks that set_params is equivalent to passing parameters in
__init__ and warns if it encounters parameter validation. #7738 by Alvin Chiang
• Add invariance tests for clustering metrics. #8102 by Ankita Sinha and Guillaume Lemaitre.
• Add check_methods_subset_invariance to check_estimator, which checks that estimator
methods are invariant if applied to a data subset. #10428 by Jonathan Ohayon

1.11. Version 0.20.0 45


scikit-learn user guide, Release 0.20.3

• Add tests in utils.estimator_checks.check_estimator to check that an estimator can handle


read-only memmap input data. #10663 by Arthur Mensch and Loïc Estève.
• check_sample_weights_pandas_series now uses 8 rather than 6 samples to accommodate for the
default number of clusters in cluster.KMeans. #10933 by Johannes Hansen.
• Estimators are now checked for whether sample_weight=None equates to sample_weight=np.
ones(...). #11558 by Sergul Aydore.

1.11.6 Code and Documentation Contributors

Thanks to everyone who has contributed to the maintenance and improvement of the project since version 0.19, in-
cluding:
211217613, Aarshay Jain, absolutelyNoWarranty, Adam Greenhall, Adam Kleczewski, Adam Richie-Halford, adelr,
AdityaDaflapurkar, Adrin Jalali, Aidan Fitzgerald, aishgrt1, Akash Shivram, Alan Liddell, Alan Yee, Albert Thomas,
Alexander Lenail, Alexander-N, Alexandre Boucaud, Alexandre Gramfort, Alexandre Sevin, Alex Egg, Alvaro Perez-
Diaz, Amanda, Aman Dalmia, Andreas Bjerre-Nielsen, Andreas Mueller, Andrew Peng, Angus Williams, Aniruddha
Dave, annaayzenshtat, Anthony Gitter, Antonio Quinonez, Anubhav Marwaha, Arik Pamnani, Arthur Ozga, Artiem
K, Arunava, Arya McCarthy, Attractadore, Aurélien Bellet, Aurélien Geron, Ayush Gupta, Balakumaran Manoha-
ran, Bangda Sun, Barry Hart, Bastian Venthur, Ben Lawson, Benn Roth, Breno Freitas, Brent Yi, brett koonce,
Caio Oliveira, Camil Staps, cclauss, Chady Kamar, Charlie Brummitt, Charlie Newey, chris, Chris, Chris Catalfo,
Chris Foster, Chris Holdgraf, Christian Braune, Christian Hirsch, Christian Hogan, Christopher Jenness, Clement
Joudet, cnx, cwitte, Dallas Card, Dan Barkhorn, Daniel, Daniel Ferreira, Daniel Gomez, Daniel Klevebring, Danielle
Shwed, Daniel Mohns, Danil Baibak, Darius Morawiec, David Beach, David Burns, David Kirkby, David Nichol-
son, David Pickup, Derek, Didi Bar-Zev, diegodlh, Dillon Gardner, Dillon Niederhut, dilutedsauce, dlovell, Dmitry
Mottl, Dmitry Petrov, Dor Cohen, Douglas Duhaime, Ekaterina Tuzova, Eric Chang, Eric Dean Sanchez, Erich Schu-
bert, Eunji, Fang-Chieh Chou, FarahSaeed, felix, Félix Raimundo, fenx, filipj8, FrankHui, Franz Wompner, Freija
Descamps, frsi, Gabriele Calvo, Gael Varoquaux, Gaurav Dhingra, Georgi Peev, Gil Forsyth, Giovanni Giuseppe
Costa, gkevinyen5418, goncalo-rodrigues, Gryllos Prokopis, Guillaume Lemaitre, Guillaume “Vermeille” Sanchez,
Gustavo De Mari Pereira, hakaa1, Hanmin Qin, Henry Lin, Hong, Honghe, Hossein Pourbozorg, Hristo, Hunan Ros-
tomyan, iampat, Ivan PANICO, Jaewon Chung, Jake VanderPlas, jakirkham, James Bourbeau, James Malcolm, Jamie
Cox, Jan Koch, Jan Margeta, Jan Schlüter, janvanrijn, Jason Wolosonovich, JC Liu, Jeb Bearer, jeremiedbb, Jimmy
Wan, Jinkun Wang, Jiongyan Zhang, jjabl, jkleint, Joan Massich, Joël Billaud, Joel Nothman, Johannes Hansen,
JohnStott, Jonatan Samoocha, Jonathan Ohayon, Jörg Döpfert, Joris Van den Bossche, Jose Perez-Parras Toledano,
josephsalmon, jotasi, jschendel, Julian Kuhlmann, Julien Chaumond, julietcl, Justin Shenk, Karl F, Kasper Primdal
Lauritzen, Katrin Leinweber, Kirill, ksemb, Kuai Yu, Kumar Ashutosh, Kyeongpil Kang, Kye Taylor, kyledrogo,
Leland McInnes, Léo DS, Liam Geron, Liutong Zhou, Lizao Li, lkjcalc, Loic Esteve, louib, Luciano Viola, Lucija
Gregov, Luis Osa, Luis Pedro Coelho, Luke M Craig, Luke Persola, Mabel, Mabel Villalba, Maniteja Nandana, MarkI-
wanchyshyn, Mark Roth, Markus Müller, MarsGuy, Martin Gubri, martin-hahn, martin-kokos, mathurinm, Matthias
Feurer, Max Copeland, Mayur Kulkarni, Meghann Agarwal, Melanie Goetz, Michael A. Alcorn, Minghui Liu, Ming
Li, Minh Le, Mohamed Ali Jamaoui, Mohamed Maskani, Mohammad Shahebaz, Muayyad Alsadi, Nabarun Pal, Na-
garjuna Kumar, Naoya Kanai, Narendran Santhanam, NarineK, Nathaniel Saul, Nathan Suh, Nicholas Nadeau, P.Eng.,
AVS, Nick Hoh, Nicolas Goix, Nicolas Hug, Nicolau Werneck, nielsenmarkus11, Nihar Sheth, Nikita Titov, Nilesh
Kevlani, Nirvan Anjirbag, notmatthancock, nzw, Oleksandr Pavlyk, oliblum90, Oliver Rausch, Olivier Grisel, Oren
Milman, Osaid Rehman Nasir, pasbi, Patrick Fernandes, Patrick Olden, Paul Paczuski, Pedro Morales, Peter, Peter St.
John, pierreablin, pietruh, Pinaki Nath Chowdhury, Piotr Szymański, Pradeep Reddy Raamana, Pravar D Mahajan,
pravarmahajan, QingYing Chen, Raghav RV, Rajendra arora, RAKOTOARISON Herilalaina, Rameshwar Bhaskaran,
RankyLau, Rasul Kerimov, Reiichiro Nakano, Rob, Roman Kosobrodov, Roman Yurchak, Ronan Lamy, rragundez,
Rüdiger Busche, Ryan, Sachin Kelkar, Sagnik Bhattacharya, Sailesh Choyal, Sam Radhakrishnan, Sam Steingold,
Samuel Bell, Samuel O. Ronsin, Saqib Nizam Shamsi, SATISH J, Saurabh Gupta, Scott Gigante, Sebastian Flen-
nerhag, Sebastian Raschka, Sebastien Dubois, Sébastien Lerique, Sebastin Santy, Sergey Feldman, Sergey Melderis,
Sergul Aydore, Shahebaz, Shalil Awaley, Shangwu Yao, Sharad Vijalapuram, Sharan Yalburgi, shenhanc78, Shivam
Rastogi, Shu Haoran, siftikha, Sinclert Pérez, SolutusImmensus, Somya Anand, srajan paliwal, Sriharsha Hatwar, Sri
Krishna, Stefan van der Walt, Stephen McDowell, Steven Brown, syonekura, Taehoon Lee, Takanori Hayashi, tarcusx,

46 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

Taylor G Smith, theriley106, Thomas, Thomas Fan, Thomas Heavey, Tobias Madsen, tobycheese, Tom Augspurger,
Tom Dupré la Tour, Tommy, Trevor Stephens, Trishnendu Ghorai, Tulio Casagrande, twosigmajab, Umar Farouk
Umar, Urvang Patel, Utkarsh Upadhyay, Vadim Markovtsev, Varun Agrawal, Vathsala Achar, Vilhelm von Ehren-
heim, Vinayak Mehta, Vinit, Vinod Kumar L, Viraj Mavani, Viraj Navkal, Vivek Kumar, Vlad Niculae, vqean3, Vris-
hank Bhardwaj, vufg, wallygauze, Warut Vijitbenjaronk, wdevazelhes, Wenhao Zhang, Wes Barnett, Will, William de
Vazelhes, Will Rosenfeld, Xin Xiong, Yiming (Paul) Li, ymazari, Yufeng, Zach Griffith, Zé Vinícius, Zhenqing Hu,
Zhiqing Xiao, Zijie (ZJ) Poh

1.12 Version 0.19.2

July, 2018
This release is exclusively in order to support Python 3.7.

1.12.1 Related changes

• n_iter_ may vary from previous releases in linear_model.LogisticRegression with


solver='lbfgs' and linear_model.HuberRegressor. For Scipy <= 1.0.0, the optimizer could
perform more than the requested maximum number of iterations. Now both estimators will report at most
max_iter iterations even if more were performed. #10723 by Joel Nothman.

1.13 Version 0.19.1

October 23, 2017


This is a bug-fix release with some minor documentation improvements and enhancements to features released in
0.19.0.
Note there may be minor differences in TSNE output in this release (due to #9623), in the case where multiple samples
have equal distance to some sample.

1.13.1 Changelog

API changes

• Reverted the addition of metrics.ndcg_score and metrics.dcg_score which had been merged into
version 0.19.0 by error. The implementations were broken and undocumented.
• return_train_score which was added to model_selection.GridSearchCV ,
model_selection.RandomizedSearchCV and model_selection.cross_validate in
version 0.19.0 will be changing its default value from True to False in version 0.21. We found that calculating
training score could have a great effect on cross validation runtime in some cases. Users should explicitly
set return_train_score to False if prediction or scoring functions are slow, resulting in a deleterious
effect on CV runtime, or to True if they wish to use the calculated scores. #9677 by Kumar Ashutosh and Joel
Nothman.
• correlation_models and regression_models from the legacy gaussian processes implementation
have been belatedly deprecated. #9717 by Kumar Ashutosh.

1.12. Version 0.19.2 47


scikit-learn user guide, Release 0.20.3

Bug fixes

• Avoid integer overflows in metrics.matthews_corrcoef. #9693 by Sam Steingold.


• Fixed a bug in the objective function for manifold.TSNE (both exact and with the Barnes-Hut approximation)
when n_components >= 3. #9711 by @goncalo-rodrigues.
• Fix regression in model_selection.cross_val_predict where it raised an error with
method='predict_proba' for some probabilistic classifiers. #9641 by James Bourbeau.
• Fixed a bug where datasets.make_classification modified its input weights. #9865 by Sachin
Kelkar.
• model_selection.StratifiedShuffleSplit now works with multioutput multiclass or multilabel
data with more than 1000 columns. #9922 by Charlie Brummitt.
• Fixed a bug with nested and conditional parameter setting, e.g. setting a pipeline step and its parameter at the
same time. #9945 by Andreas Müller and Joel Nothman.
Regressions in 0.19.0 fixed in 0.19.1:
• Fixed a bug where parallelised prediction in random forests was not thread-safe and could (rarely) result in
arbitrary errors. #9830 by Joel Nothman.
• Fix regression in model_selection.cross_val_predict where it no longer accepted X as a list.
#9600 by Rasul Kerimov.
• Fixed handling of cross_val_predict for binary classification with
method='decision_function'. #9593 by Reiichiro Nakano and core devs.
• Fix regression in pipeline.Pipeline where it no longer accepted steps as a tuple. #9604 by Joris Van
den Bossche.
• Fix bug where n_iter was not properly deprecated, leaving n_iter unavailable for interim use
in linear_model.SGDClassifier, linear_model.SGDRegressor, linear_model.
PassiveAggressiveClassifier, linear_model.PassiveAggressiveRegressor and
linear_model.Perceptron. #9558 by Andreas Müller.
• Dataset fetchers make sure temporary files are closed before removing them, which caused errors on Windows.
#9847 by Joan Massich.
• Fixed a regression in manifold.TSNE where it no longer supported metrics other than ‘euclidean’ and ‘pre-
computed’. #9623 by Oli Blum.

Enhancements

• Our test suite and utils.estimator_checks.check_estimators can now be run without Nose in-
stalled. #9697 by Joan Massich.
• To improve usability of version 0.19’s pipeline.Pipeline caching, memory now allows joblib.
Memory instances. This make use of the new utils.validation.check_memory helper. issue:9584
by Kumar Ashutosh
• Some fixes to examples: #9750, #9788, #9815
• Made a FutureWarning in SGD-based estimators less verbose. #9802 by Vrishank Bhardwaj.

1.13.2 Code and Documentation Contributors

With thanks to:

48 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

Joel Nothman, Loic Esteve, Andreas Mueller, Kumar Ashutosh, Vrishank Bhardwaj, Hanmin Qin, Rasul Kerimov,
James Bourbeau, Nagarjuna Kumar, Nathaniel Saul, Olivier Grisel, Roman Yurchak, Reiichiro Nakano, Sachin Kelkar,
Sam Steingold, Yaroslav Halchenko, diegodlh, felix, goncalo-rodrigues, jkleint, oliblum90, pasbi, Anthony Gitter, Ben
Lawson, Charlie Brummitt, Didi Bar-Zev, Gael Varoquaux, Joan Massich, Joris Van den Bossche, nielsenmarkus11

1.14 Version 0.19

August 12, 2017

1.14.1 Highlights

We are excited to release a number of great new features including neighbors.LocalOutlierFactor


for anomaly detection, preprocessing.QuantileTransformer for robust feature transformation, and
the multioutput.ClassifierChain meta-estimator to simply account for dependencies between classes
in multilabel problems. We have some new algorithms in existing estimators, such as multiplicative up-
date in decomposition.NMF and multinomial linear_model.LogisticRegression with L1 loss (use
solver='saga').
Cross validation is now able to return the results from multiple metric evaluations. The new model_selection.
cross_validate can return many scores on the test data as well as training set performance and timings, and we
have extended the scoring and refit parameters for grid/randomized search to handle multiple metrics.
You can also learn faster. For instance, the new option to cache transformations in pipeline.Pipeline makes
grid search over pipelines including slow transformations much more efficient. And you can predict faster: if you’re
sure you know what you’re doing, you can turn off validating that the input is finite using config_context.
We’ve made some important fixes too. We’ve fixed a longstanding implementation error in metrics.
average_precision_score, so please be cautious with prior results reported from that function. A number
of errors in the manifold.TSNE implementation have been fixed, particularly in the default Barnes-Hut approx-
imation. semi_supervised.LabelSpreading and semi_supervised.LabelPropagation have had
substantial fixes. LabelPropagation was previously broken. LabelSpreading should now correctly respect its alpha
parameter.

1.14.2 Changed models

The following estimators and functions, when fit with the same data and parameters, may produce different models
from the previous version. This often occurs due to changes in the modelling logic (bug fixes or enhancements), or in
random sampling procedures.
• cluster.KMeans with sparse X and initial centroids given (bug fix)
• cross_decomposition.PLSRegression with scale=True (bug fix)
• ensemble.GradientBoostingClassifier and ensemble.GradientBoostingRegressor
where min_impurity_split is used (bug fix)
• gradient boosting loss='quantile' (bug fix)
• ensemble.IsolationForest (bug fix)
• feature_selection.SelectFdr (bug fix)
• linear_model.RANSACRegressor (bug fix)
• linear_model.LassoLars (bug fix)
• linear_model.LassoLarsIC (bug fix)

1.14. Version 0.19 49


scikit-learn user guide, Release 0.20.3

• manifold.TSNE (bug fix)


• neighbors.NearestCentroid (bug fix)
• semi_supervised.LabelSpreading (bug fix)
• semi_supervised.LabelPropagation (bug fix)
• tree based models where min_weight_fraction_leaf is used (enhancement)
• model_selection.StratifiedKFold with shuffle=True (this change, due to #7823 was not men-
tioned in the release notes at the time)
Details are listed in the changelog below.
(While we are trying to better inform users by providing this information, we cannot assure that this list is complete.)

1.14.3 Changelog

New features

Classifiers and regressors


• Added multioutput.ClassifierChain for multi-label classification. By Adam Kleczewski.
• Added solver 'saga' that implements the improved version of Stochastic Average Gradient, in
linear_model.LogisticRegression and linear_model.Ridge. It allows the use of L1 penalty
with multinomial logistic loss, and behaves marginally better than ‘sag’ during the first epochs of ridge and
logistic regression. #8446 by Arthur Mensch.
Other estimators
• Added the neighbors.LocalOutlierFactor class for anomaly detection based on nearest neighbors.
#5279 by Nicolas Goix and Alexandre Gramfort.
• Added preprocessing.QuantileTransformer class and preprocessing.
quantile_transform function for features normalization based on quantiles. #8363 by Denis Engemann,
Guillaume Lemaitre, Olivier Grisel, Raghav RV, Thierry Guillemot, and Gael Varoquaux.
• The new solver 'mu' implements a Multiplicate Update in decomposition.NMF, allowing the optimization
of all beta-divergences, including the Frobenius norm, the generalized Kullback-Leibler divergence and the
Itakura-Saito divergence. #5295 by Tom Dupre la Tour.
Model selection and evaluation
• model_selection.GridSearchCV and model_selection.RandomizedSearchCV now support
simultaneous evaluation of multiple metrics. Refer to the Specifying multiple metrics for evaluation section of
the user guide for more information. #7388 by Raghav RV
• Added the model_selection.cross_validate which allows evaluation of multiple metrics. This func-
tion returns a dict with more useful information from cross-validation such as the train scores, fit times and score
times. Refer to The cross_validate function and multiple metric evaluation section of the userguide for more
information. #7388 by Raghav RV
• Added metrics.mean_squared_log_error, which computes the mean square error of the logarithmic
transformation of targets, particularly useful for targets with an exponential trend. #7655 by Karan Desai.
• Added metrics.dcg_score and metrics.ndcg_score, which compute Discounted cumulative gain
(DCG) and Normalized discounted cumulative gain (NDCG). #7739 by David Gasquez.
• Added the model_selection.RepeatedKFold and model_selection.
RepeatedStratifiedKFold. #8120 by Neeraj Gangwar.

50 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

Miscellaneous
• Validation that input data contains no NaN or inf can now be suppressed using config_context, at your
own risk. This will save on runtime, and may be particularly useful for prediction time. #7548 by Joel Nothman.
• Added a test to ensure parameter listing in docstrings match the function/class signature. #9206 by Alexandre
Gramfort and Raghav RV.

Enhancements

Trees and ensembles


• The min_weight_fraction_leaf constraint in tree construction is now more efficient, taking a fast path
to declare a node a leaf if its weight is less than 2 * the minimum. Note that the constructed tree will be different
from previous versions where min_weight_fraction_leaf is used. #7441 by Nelson Liu.
• ensemble.GradientBoostingClassifier and ensemble.GradientBoostingRegressor
now support sparse input for prediction. #6101 by Ibraim Ganiev.
• ensemble.VotingClassifier now allows changing estimators by using ensemble.
VotingClassifier.set_params. An estimator can also be removed by setting it to None. #7674 by
Yichuan Liu.
• tree.export_graphviz now shows configurable number of decimal places. #8698 by Guillaume
Lemaitre.
• Added flatten_transform parameter to ensemble.VotingClassifier to change output shape of
transform method to 2 dimensional. #7794 by Ibraim Ganiev and Herilalaina Rakotoarison.
Linear, kernelized and related models
• linear_model.SGDClassifier, linear_model.SGDRegressor, linear_model.
PassiveAggressiveClassifier, linear_model.PassiveAggressiveRegressor and
linear_model.Perceptron now expose max_iter and tol parameters, to handle convergence more
precisely. n_iter parameter is deprecated, and the fitted estimator exposes a n_iter_ attribute, with actual
number of iterations before convergence. #5036 by Tom Dupre la Tour.
• Added average parameter to perform weight averaging in linear_model.
PassiveAggressiveClassifier. #4939 by Andrea Esuli.
• linear_model.RANSACRegressor no longer throws an error when calling fit if no inliers are found in
its first iteration. Furthermore, causes of skipped iterations are tracked in newly added attributes, n_skips_*.
#7914 by Michael Horrell.
• In gaussian_process.GaussianProcessRegressor, method predict is a lot faster with
return_std=True. #8591 by Hadrien Bertrand.
• Added return_std to predict method of linear_model.ARDRegression and linear_model.
BayesianRidge. #7838 by Sergey Feldman.
• Memory usage enhancements: Prevent cast from float32 to float64 in: linear_model.
MultiTaskElasticNet; linear_model.LogisticRegression when using newton-cg solver; and
linear_model.Ridge when using svd, sparse_cg, cholesky or lsqr solvers. #8835, #8061 by Joan Massich
and Nicolas Cordier and Thierry Guillemot.
Other predictors
• Custom metrics for the neighbors binary trees now have fewer constraints: they must take two 1d-arrays and
return a float. #6288 by Jake Vanderplas.
• algorithm='auto in neighbors estimators now chooses the most appropriate algorithm for all input
types and metrics. #9145 by Herilalaina Rakotoarison and Reddy Chinthala.

1.14. Version 0.19 51


scikit-learn user guide, Release 0.20.3

Decomposition, manifold learning and clustering


• cluster.MiniBatchKMeans and cluster.KMeans now use significantly less memory when assigning
data points to their nearest cluster center. #7721 by Jon Crall.
• decomposition.PCA, decomposition.IncrementalPCA and decomposition.
TruncatedSVD now expose the singular values from the underlying SVD. They are stored in the
attribute singular_values_, like in decomposition.IncrementalPCA. #7685 by Tommy Löfstedt
• decomposition.NMF now faster when beta_loss=0. #9277 by @hongkahjun.
• Memory improvements for method barnes_hut in manifold.TSNE #7089 by Thomas Moreau and Olivier
Grisel.
• Optimization schedule improvements for Barnes-Hut manifold.TSNE so the results are closer to the one
from the reference implementation lvdmaaten/bhtsne by Thomas Moreau and Olivier Grisel.
• Memory usage enhancements: Prevent cast from float32 to float64 in decomposition.PCA and
decomposition.randomized_svd_low_rank. #9067 by Raghav RV.
Preprocessing and feature selection
• Added norm_order parameter to feature_selection.SelectFromModel to enable selection of the
norm order when coef_ is more than 1D. #6181 by Antoine Wendlinger.
• Added ability to use sparse matrices in feature_selection.f_regression with center=True.
#8065 by Daniel LeJeune.
• Small performance improvement to n-gram creation in feature_extraction.text by binding methods
for loops and special-casing unigrams. #7567 by Jaye Doepke
• Relax assumption on the data for the kernel_approximation.SkewedChi2Sampler. Since the
Skewed-Chi2 kernel is defined on the open interval (−𝑠𝑘𝑒𝑤𝑒𝑑𝑛𝑒𝑠𝑠; +∞)𝑑 , the transform function should not
check whether X < 0 but whether X < -self.skewedness. #7573 by Romain Brault.
• Made default kernel parameters kernel-dependent in kernel_approximation.Nystroem. #5229 by
Saurabh Bansod and Andreas Müller.
Model evaluation and meta-estimators
• pipeline.Pipeline is now able to cache transformers within a pipeline by using the memory constructor
parameter. #7990 by Guillaume Lemaitre.
• pipeline.Pipeline steps can now be accessed as attributes of its named_steps attribute. #8586 by
Herilalaina Rakotoarison.
• Added sample_weight parameter to pipeline.Pipeline.score. #7723 by Mikhail Korobov.
• Added ability to set n_jobs parameter to pipeline.make_union. A TypeError will be raised for any
other kwargs. #8028 by Alexander Booth.
• model_selection.GridSearchCV , model_selection.RandomizedSearchCV and
model_selection.cross_val_score now allow estimators with callable kernels which were
previously prohibited. #8005 by Andreas Müller .
• model_selection.cross_val_predict now returns output of the correct shape for all values of the
argument method. #7863 by Aman Dalmia.
• Added shuffle and random_state parameters to shuffle training data before taking prefixes of it based on
training sizes in model_selection.learning_curve. #7506 by Narine Kokhlikyan.
• model_selection.StratifiedShuffleSplit now works with multioutput multiclass (or multilabel)
data. #9044 by Vlad Niculae.

52 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Speed improvements to model_selection.StratifiedShuffleSplit. #5991 by Arthur Mensch and


Joel Nothman.
• Add shuffle parameter to model_selection.train_test_split. #8845 by themrmax
• multioutput.MultiOutputRegressor and multioutput.MultiOutputClassifier now
support online learning using partial_fit. :issue: 8053 by Peng Yu.
• Add max_train_size parameter to model_selection.TimeSeriesSplit #8282 by Aman Dalmia.
• More clustering metrics are now available through metrics.get_scorer and scoring parameters. #8117
by Raghav RV.
• A scorer based on metrics.explained_variance_score is also available. #9259 by Hanmin Qin.
Metrics
• metrics.matthews_corrcoef now support multiclass classification. #8094 by Jon Crall.
• Add sample_weight parameter to metrics.cohen_kappa_score. #8335 by Victor Poughon.
Miscellaneous
• utils.check_estimator now attempts to ensure that methods transform, predict, etc. do not set attributes
on the estimator. #7533 by Ekaterina Krivich.
• Added type checking to the accept_sparse parameter in utils.validation methods. This parameter
now accepts only boolean, string, or list/tuple of strings. accept_sparse=None is deprecated and should
be replaced by accept_sparse=False. #7880 by Josh Karnofsky.
• Make it possible to load a chunk of an svmlight formatted file by passing a range of bytes to datasets.
load_svmlight_file. #935 by Olivier Grisel.
• dummy.DummyClassifier and dummy.DummyRegressor now accept non-finite features. #8931 by
@Attractadore.

Bug fixes

Trees and ensembles


• Fixed a memory leak in trees when using trees with criterion='mae'. #8002 by Raghav RV.
• Fixed a bug where ensemble.IsolationForest uses an an incorrect formula for the average path length
#8549 by Peter Wang.
• Fixed a bug where ensemble.AdaBoostClassifier throws ZeroDivisionError while fitting data
with single class labels. #7501 by Dominik Krzeminski.
• Fixed a bug in ensemble.GradientBoostingClassifier and ensemble.
GradientBoostingRegressor where a float being compared to 0.0 using == caused a divide by
zero error. #7970 by He Chen.
• Fix a bug where ensemble.GradientBoostingClassifier and ensemble.
GradientBoostingRegressor ignored the min_impurity_split parameter. #8006 by Sebastian
Pölsterl.
• Fixed oob_score in ensemble.BaggingClassifier. #8936 by Michael Lewis
• Fixed excessive memory usage in prediction for random forests estimators. #8672 by Mike Benfield.
• Fixed a bug where sample_weight as a list broke random forests in Python 2 #8068 by @xor.
• Fixed a bug where ensemble.IsolationForest fails when max_features is less than 1. #5732 by
Ishank Gulati.

1.14. Version 0.19 53


scikit-learn user guide, Release 0.20.3

• Fix a bug where gradient boosting with loss='quantile' computed negative errors for negative values of
ytrue - ypred leading to wrong values when calling __call__. #8087 by Alexis Mignon
• Fix a bug where ensemble.VotingClassifier raises an error when a numpy array is passed in for
weights. #7983 by Vincent Pham.
• Fixed a bug where tree.export_graphviz raised an error when the length of features_names does not
match n_features in the decision tree. #8512 by Li Li.
Linear, kernelized and related models
• Fixed a bug where linear_model.RANSACRegressor.fit may run until max_iter if it finds a large
inlier group early. #8251 by @aivision2020.
• Fixed a bug where naive_bayes.MultinomialNB and naive_bayes.BernoulliNB failed when
alpha=0. #5814 by Yichuan Liu and Herilalaina Rakotoarison.
• Fixed a bug where linear_model.LassoLars does not give the same result as the LassoLars implemen-
tation available in R (lars library). #7849 by Jair Montoya Martinez.
• Fixed a bug in linear_model.RandomizedLasso, linear_model.Lars, linear_model.
LassoLars, linear_model.LarsCV and linear_model.LassoLarsCV , where the parameter
precompute was not used consistently across classes, and some values proposed in the docstring could raise
errors. #5359 by Tom Dupre la Tour.
• Fix inconsistent results between linear_model.RidgeCV and linear_model.Ridge when using
normalize=True. #9302 by Alexandre Gramfort.
• Fix a bug where linear_model.LassoLars.fit sometimes left coef_ as a list, rather than an ndarray.
#8160 by CJ Carey.
• Fix linear_model.BayesianRidge.fit to return ridge parameter alpha_ and lambda_ consistent
with calculated coefficients coef_ and intercept_. #8224 by Peter Gedeck.
• Fixed a bug in svm.OneClassSVM where it returned floats instead of integer classes. #8676 by Vathsala
Achar.
• Fix AIC/BIC criterion computation in linear_model.LassoLarsIC. #9022 by Alexandre Gramfort and
Mehmet Basbug.
• Fixed a memory leak in our LibLinear implementation. #9024 by Sergei Lebedev
• Fix bug where stratified CV splitters did not work with linear_model.LassoCV . #8973 by Paulo Haddad.
• Fixed a bug in gaussian_process.GaussianProcessRegressor when the standard deviation and
covariance predicted without fit would fail with a unmeaningful error by default. #6573 by Quazi Marufur
Rahman and Manoj Kumar.
Other predictors
• Fix semi_supervised.BaseLabelPropagation to correctly implement LabelPropagation and
LabelSpreading as done in the referenced papers. #9239 by Andre Ambrosio Boechat, Utkarsh Upadhyay,
and Joel Nothman.
Decomposition, manifold learning and clustering
• Fixed the implementation of manifold.TSNE:
• early_exageration parameter had no effect and is now used for the first 250 optimization iterations.
• Fixed the AssertionError: Tree consistency failed exception reported in #8992.
• Improve the learning schedule to match the one from the reference implementation lvdmaaten/bhtsne. by
Thomas Moreau and Olivier Grisel.

54 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Fix a bug in decomposition.LatentDirichletAllocation where the perplexity method was


returning incorrect results because the transform method returns normalized document topic distributions as
of version 0.18. #7954 by Gary Foreman.
• Fix output shape and bugs with n_jobs > 1 in decomposition.SparseCoder transform and
decomposition.sparse_encode for one-dimensional data and one component. This also impacts the
output shape of decomposition.DictionaryLearning. #8086 by Andreas Müller.
• Fixed the implementation of explained_variance_ in decomposition.PCA, decomposition.
RandomizedPCA and decomposition.IncrementalPCA. #9105 by Hanmin Qin.
• Fixed the implementation of noise_variance_ in decomposition.PCA. #9108 by Hanmin Qin.
• Fixed a bug where cluster.DBSCAN gives incorrect result when input is a precomputed sparse matrix with
initial rows all zero. #8306 by Akshay Gupta
• Fix a bug regarding fitting cluster.KMeans with a sparse array X and initial centroids, where X’s means
were unnecessarily being subtracted from the centroids. #7872 by Josh Karnofsky.
• Fixes to the input validation in covariance.EllipticEnvelope. #8086 by Andreas Müller.
• Fixed a bug in covariance.MinCovDet where inputting data that produced a singular covariance matrix
would cause the helper method _c_step to throw an exception. #3367 by Jeremy Steward
• Fixed a bug in manifold.TSNE affecting convergence of the gradient descent. #8768 by David DeTomaso.
• Fixed a bug in manifold.TSNE where it stored the incorrect kl_divergence_. #6507 by Sebastian
Saeger.
• Fixed improper scaling in cross_decomposition.PLSRegression with scale=True. #7819 by
jayzed82.
• cluster.bicluster.SpectralCoclustering and cluster.bicluster.
SpectralBiclustering fit method conforms with API by accepting y and returning the object.
#6126, #7814 by Laurent Direr and Maniteja Nandana.
• Fix bug where mixture sample methods did not return as many samples as requested. #7702 by Levi John
Wolf.
• Fixed the shrinkage implementation in neighbors.NearestCentroid. #9219 by Hanmin Qin.
Preprocessing and feature selection
• For sparse matrices, preprocessing.normalize with return_norm=True will now raise a
NotImplementedError with ‘l1’ or ‘l2’ norm and with norm ‘max’ the norms returned will be the same as
for dense matrices. #7771 by Ang Lu.
• Fix a bug where feature_selection.SelectFdr did not exactly implement Benjamini-Hochberg pro-
cedure. It formerly may have selected fewer features than it should. #7490 by Peng Meng.
• Fixed a bug where linear_model.RandomizedLasso and linear_model.
RandomizedLogisticRegression breaks for sparse input. #8259 by Aman Dalmia.
• Fix a bug where feature_extraction.FeatureHasher mandatorily applied a sparse random projec-
tion to the hashed features, preventing the use of feature_extraction.text.HashingVectorizer
in a pipeline with feature_extraction.text.TfidfTransformer. #7565 by Roman Yurchak.
• Fix a bug where feature_selection.mutual_info_regression did not correctly use
n_neighbors. #8181 by Guillaume Lemaitre.
Model evaluation and meta-estimators

1.14. Version 0.19 55


scikit-learn user guide, Release 0.20.3

• Fixed a bug where model_selection.BaseSearchCV.inverse_transform re-


turns self.best_estimator_.transform() instead of self.best_estimator_.
inverse_transform(). #8344 by Akshay Gupta and Rasmus Eriksson.
• Added classes_ attribute to model_selection.GridSearchCV , model_selection.
RandomizedSearchCV , grid_search.GridSearchCV, and grid_search.
RandomizedSearchCV that matches the classes_ attribute of best_estimator_. #7661 and
#8295 by Alyssa Batula, Dylan Werner-Meier, and Stephen Hoover.
• Fixed a bug where model_selection.validation_curve reused the same estimator for each parame-
ter value. #7365 by Aleksandr Sandrovskii.
• model_selection.permutation_test_score now works with Pandas types. #5697 by Stijn Tonk.
• Several fixes to input validation in multiclass.OutputCodeClassifier #8086 by Andreas Müller.
• multiclass.OneVsOneClassifier’s partial_fit now ensures all classes are provided up-front.
#6250 by Asish Panda.
• Fix multioutput.MultiOutputClassifier.predict_proba to return a list of 2d arrays, rather
than a 3d array. In the case where different target columns had different numbers of classes, a ValueError
would be raised on trying to stack matrices with different dimensions. #8093 by Peter Bull.
• Cross validation now works with Pandas datatypes that that have a read-only index. #9507 by Loic Esteve.
Metrics
• metrics.average_precision_score no longer linearly interpolates between operating points, and in-
stead weighs precisions by the change in recall since the last operating point, as per the Wikipedia entry. (#7356).
By Nick Dingwall and Gael Varoquaux.
• Fix a bug in metrics.classification._check_targets which would return 'binary' if y_true
and y_pred were both 'binary' but the union of y_true and y_pred was 'multiclass'. #8377 by
Loic Esteve.
• Fixed an integer overflow bug in metrics.confusion_matrix and hence metrics.
cohen_kappa_score. #8354, #7929 by Joel Nothman and Jon Crall.
• Fixed passing of gamma parameter to the chi2 kernel in metrics.pairwise.pairwise_kernels
#5211 by Nick Rhinehart, Saurabh Bansod and Andreas Müller.
Miscellaneous
• Fixed a bug when datasets.make_classification fails when generating more than 30 features. #8159
by Herilalaina Rakotoarison.
• Fixed a bug where datasets.make_moons gives an incorrect result when n_samples is odd. #8198 by
Josh Levy.
• Some fetch_ functions in datasets were ignoring the download_if_missing keyword. #7944 by
Ralf Gommers.
• Fix estimators to accept a sample_weight parameter of type pandas.Series in their fit function.
#7825 by Kathleen Chen.
• Fix a bug in cases where numpy.cumsum may be numerically unstable, raising an exception if instability is
identified. #7376 and #7331 by Joel Nothman and @yangarbiter.
• Fix a bug where base.BaseEstimator.__getstate__ obstructed pickling customizations of child-
classes, when used in a multiple inheritance context. #8316 by Holger Peters.
• Update Sphinx-Gallery from 0.1.4 to 0.1.7 for resolving links in documentation build with Sphinx>1.5 #8010,
#7986 by Oscar Najera

56 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Add data_home parameter to sklearn.datasets.fetch_kddcup99. #9289 by Loic Esteve.


• Fix dataset loaders using Python 3 version of makedirs to also work in Python 2. #9284 by Sebastin Santy.
• Several minor issues were fixed with thanks to the alerts of [lgtm.com](http://lgtm.com). #9278 by Jean Helie,
among others.

1.14.4 API changes summary

Trees and ensembles


• Gradient boosting base models are no longer estimators. By Andreas Müller.
• All tree based estimators now accept a min_impurity_decrease parameter in lieu of the
min_impurity_split, which is now deprecated. The min_impurity_decrease helps stop
splitting the nodes in which the weighted impurity decrease from splitting is no longer at least
min_impurity_decrease. #8449 by Raghav RV.
Linear, kernelized and related models
• n_iter parameter is deprecated in linear_model.SGDClassifier, linear_model.
SGDRegressor, linear_model.PassiveAggressiveClassifier, linear_model.
PassiveAggressiveRegressor and linear_model.Perceptron. By Tom Dupre la Tour.
Other predictors
• neighbors.LSHForest has been deprecated and will be removed in 0.21 due to poor performance. #9078
by Laurent Direr.
• neighbors.NearestCentroid no longer purports to support metric='precomputed' which now
raises an error. #8515 by Sergul Aydore.
• The alpha parameter of semi_supervised.LabelPropagation now has no effect and is deprecated
to be removed in 0.21. #9239 by Andre Ambrosio Boechat, Utkarsh Upadhyay, and Joel Nothman.
Decomposition, manifold learning and clustering
• Deprecate the doc_topic_distr argument of the perplexity method in decomposition.
LatentDirichletAllocation because the user no longer has access to the unnormalized document topic
distribution needed for the perplexity calculation. #7954 by Gary Foreman.
• The n_topics parameter of decomposition.LatentDirichletAllocation has been renamed to
n_components and will be removed in version 0.21. #8922 by @Attractadore.
• decomposition.SparsePCA.transform’s ridge_alpha parameter is deprecated in preference for
class parameter. #8137 by Naoya Kanai.
• cluster.DBSCAN now has a metric_params parameter. #8139 by Naoya Kanai.
Preprocessing and feature selection
• feature_selection.SelectFromModel now has a partial_fit method only if the underlying es-
timator does. By Andreas Müller.
• feature_selection.SelectFromModel now validates the threshold parameter and sets the
threshold_ attribute during the call to fit, and no longer during the call to transform`. By Andreas
Müller.
• The non_negative parameter in feature_extraction.FeatureHasher has been deprecated, and
replaced with a more principled alternative, alternate_sign. #7565 by Roman Yurchak.
• linear_model.RandomizedLogisticRegression, and linear_model.RandomizedLasso
have been deprecated and will be removed in version 0.21. #8995 by Ramana.S.

1.14. Version 0.19 57


scikit-learn user guide, Release 0.20.3

Model evaluation and meta-estimators


• Deprecate the fit_params constructor input to the model_selection.GridSearchCV and
model_selection.RandomizedSearchCV in favor of passing keyword parameters to the fit methods
of those classes. Data-dependent parameters needed for model training should be passed as keyword arguments
to fit, and conforming to this convention will allow the hyperparameter selection classes to be used with tools
such as model_selection.cross_val_predict. #2879 by Stephen Hoover.
• In version 0.21, the default behavior of splitters that use the test_size and train_size parameter will
change, such that specifying train_size alone will cause test_size to be the remainder. #7459 by Nelson
Liu.
• multiclass.OneVsRestClassifier now has partial_fit, decision_function and
predict_proba methods only when the underlying estimator does. #7812 by Andreas Müller and Mikhail
Korobov.
• multiclass.OneVsRestClassifier now has a partial_fit method only if the underlying estima-
tor does. By Andreas Müller.
• The decision_function output shape for binary classification in multiclass.
OneVsRestClassifier and multiclass.OneVsOneClassifier is now (n_samples,) to
conform to scikit-learn conventions. #9100 by Andreas Müller.
• The multioutput.MultiOutputClassifier.predict_proba function used to return a 3d array
(n_samples, n_classes, n_outputs). In the case where different target columns had different numbers
of classes, a ValueError would be raised on trying to stack matrices with different dimensions. This func-
tion now returns a list of arrays where the length of the list is n_outputs, and each array is (n_samples,
n_classes) for that particular output. #8093 by Peter Bull.
• Replace attribute named_steps dict to utils.Bunch in pipeline.Pipeline to enable tab com-
pletion in interactive environment. In the case conflict value on named_steps and dict attribute, dict
behavior will be prioritized. #8481 by Herilalaina Rakotoarison.
Miscellaneous
• Deprecate the y parameter in transform and inverse_transform. The method should not accept y
parameter, as it’s used at the prediction time. #8174 by Tahar Zanouda, Alexandre Gramfort and Raghav RV.
• SciPy >= 0.13.3 and NumPy >= 1.8.2 are now the minimum supported versions for scikit-learn. The following
backported functions in utils have been removed or deprecated accordingly. #8854 and #8874 by Naoya
Kanai
• The store_covariances and covariances_ parameters of discriminant_analysis.
QuadraticDiscriminantAnalysis has been renamed to store_covariance and covariance_
to be consistent with the corresponding parameter names of the discriminant_analysis.
LinearDiscriminantAnalysis. They will be removed in version 0.21. #7998 by Jiacheng
Removed in 0.19:
– utils.fixes.argpartition
– utils.fixes.array_equal
– utils.fixes.astype
– utils.fixes.bincount
– utils.fixes.expit
– utils.fixes.frombuffer_empty
– utils.fixes.in1d
– utils.fixes.norm

58 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

– utils.fixes.rankdata
– utils.fixes.safe_copy
Deprecated in 0.19, to be removed in 0.21:
– utils.arpack.eigs
– utils.arpack.eigsh
– utils.arpack.svds
– utils.extmath.fast_dot
– utils.extmath.logsumexp
– utils.extmath.norm
– utils.extmath.pinvh
– utils.graph.graph_laplacian
– utils.random.choice
– utils.sparsetools.connected_components
– utils.stats.rankdata
• Estimators with both methods decision_function and predict_proba are now required to have a
monotonic relation between them. The method check_decision_proba_consistency has been added
in utils.estimator_checks to check their consistency. #7578 by Shubham Bhardwaj
• All checks in utils.estimator_checks, in particular utils.estimator_checks.
check_estimator now accept estimator instances. Most other checks do not accept estimator classes any
more. #9019 by Andreas Müller.
• Ensure that estimators’ attributes ending with _ are not set in the constructor but only in the fit method.
Most notably, ensemble estimators (deriving from ensemble.BaseEnsemble) now only have self.
estimators_ available after fit. #7464 by Lars Buitinck and Loic Esteve.

1.14.5 Code and Documentation Contributors

Thanks to everyone who has contributed to the maintenance and improvement of the project since version 0.18, in-
cluding:
Joel Nothman, Loic Esteve, Andreas Mueller, Guillaume Lemaitre, Olivier Grisel, Hanmin Qin, Raghav RV, Alexandre
Gramfort, themrmax, Aman Dalmia, Gael Varoquaux, Naoya Kanai, Tom Dupré la Tour, Rishikesh, Nelson Liu, Tae-
hoon Lee, Nelle Varoquaux, Aashil, Mikhail Korobov, Sebastin Santy, Joan Massich, Roman Yurchak, RAKOTOARI-
SON Herilalaina, Thierry Guillemot, Alexandre Abadie, Carol Willing, Balakumaran Manoharan, Josh Karnofsky,
Vlad Niculae, Utkarsh Upadhyay, Dmitry Petrov, Minghui Liu, Srivatsan, Vincent Pham, Albert Thomas, Jake Van-
derPlas, Attractadore, JC Liu, alexandercbooth, chkoar, Óscar Nájera, Aarshay Jain, Kyle Gilliam, Ramana Subra-
manyam, CJ Carey, Clement Joudet, David Robles, He Chen, Joris Van den Bossche, Karan Desai, Katie Luangkote,
Leland McInnes, Maniteja Nandana, Michele Lacchia, Sergei Lebedev, Shubham Bhardwaj, akshay0724, omtcyfz,
rickiepark, waterponey, Vathsala Achar, jbDelafosse, Ralf Gommers, Ekaterina Krivich, Vivek Kumar, Ishank Gulati,
Dave Elliott, ldirer, Reiichiro Nakano, Levi John Wolf, Mathieu Blondel, Sid Kapur, Dougal J. Sutherland, midinas,
mikebenfield, Sourav Singh, Aseem Bansal, Ibraim Ganiev, Stephen Hoover, AishwaryaRK, Steven C. Howell, Gary
Foreman, Neeraj Gangwar, Tahar, Jon Crall, dokato, Kathy Chen, ferria, Thomas Moreau, Charlie Brummitt, Nicolas
Goix, Adam Kleczewski, Sam Shleifer, Nikita Singh, Basil Beirouti, Giorgio Patrini, Manoj Kumar, Rafael Possas,
James Bourbeau, James A. Bednar, Janine Harper, Jaye, Jean Helie, Jeremy Steward, Artsiom, John Wei, Jonathan
LIgo, Jonathan Rahn, seanpwilliams, Arthur Mensch, Josh Levy, Julian Kuhlmann, Julien Aubert, Jörn Hees, Kai,
shivamgargsya, Kat Hempstalk, Kaushik Lakshmikanth, Kennedy, Kenneth Lyons, Kenneth Myers, Kevin Yap, Kir-
ill Bobyrev, Konstantin Podshumok, Arthur Imbert, Lee Murray, toastedcornflakes, Lera, Li Li, Arthur Douillard,

1.14. Version 0.19 59


scikit-learn user guide, Release 0.20.3

Mainak Jas, tobycheese, Manraj Singh, Manvendra Singh, Marc Meketon, MarcoFalke, Matthew Brett, Matthias
Gilch, Mehul Ahuja, Melanie Goetz, Meng, Peng, Michael Dezube, Michal Baumgartner, vibrantabhi19, Artem Golu-
bin, Milen Paskov, Antonin Carette, Morikko, MrMjauh, NALEPA Emmanuel, Namiya, Antoine Wendlinger, Narine
Kokhlikyan, NarineK, Nate Guerin, Angus Williams, Ang Lu, Nicole Vavrova, Nitish Pandey, Okhlopkov Daniil
Olegovich, Andy Craze, Om Prakash, Parminder Singh, Patrick Carlson, Patrick Pei, Paul Ganssle, Paulo Haddad,
Paweł Lorek, Peng Yu, Pete Bachant, Peter Bull, Peter Csizsek, Peter Wang, Pieter Arthur de Jong, Ping-Yao, Chang,
Preston Parry, Puneet Mathur, Quentin Hibon, Andrew Smith, Andrew Jackson, 1kastner, Rameshwar Bhaskaran, Re-
becca Bilbro, Remi Rampin, Andrea Esuli, Rob Hall, Robert Bradshaw, Romain Brault, Aman Pratik, Ruifeng Zheng,
Russell Smith, Sachin Agarwal, Sailesh Choyal, Samson Tan, Samuël Weber, Sarah Brown, Sebastian Pölsterl, Se-
bastian Raschka, Sebastian Saeger, Alyssa Batula, Abhyuday Pratap Singh, Sergey Feldman, Sergul Aydore, Sharan
Yalburgi, willduan, Siddharth Gupta, Sri Krishna, Almer, Stijn Tonk, Allen Riddell, Theofilos Papapanagiotou, Alison,
Alexis Mignon, Tommy Boucher, Tommy Löfstedt, Toshihiro Kamishima, Tyler Folkman, Tyler Lanigan, Alexander
Junge, Varun Shenoy, Victor Poughon, Vilhelm von Ehrenheim, Aleksandr Sandrovskii, Alan Yee, Vlasios Vasileiou,
Warut Vijitbenjaronk, Yang Zhang, Yaroslav Halchenko, Yichuan Liu, Yuichi Fujikawa, affanv14, aivision2020, xor,
andreh7, brady salz, campustrampus, Agamemnon Krasoulis, ditenberg, elena-sharova, filipj8, fukatani, gedeck, guin-
iol, guoci, hakaa1, hongkahjun, i-am-xhy, jakirkham, jaroslaw-weber, jayzed82, jeroko, jmontoyam, jonathan.striebel,
josephsalmon, jschendel, leereeves, martin-hahn, mathurinm, mehak-sachdeva, mlewis1729, mlliou112, mthorrell,
ndingwall, nuffe, yangarbiter, plagree, pldtc325, Breno Freitas, Brett Olsen, Brian A. Alfano, Brian Burns, polmauri,
Brandon Carter, Charlton Austin, Chayant T15h, Chinmaya Pancholi, Christian Danielsen, Chung Yen, Chyi-Kwei
Yau, pravarmahajan, DOHMATOB Elvis, Daniel LeJeune, Daniel Hnyk, Darius Morawiec, David DeTomaso, David
Gasquez, David Haberthür, David Heryanto, David Kirkby, David Nicholson, rashchedrin, Deborah Gertrude Digges,
Denis Engemann, Devansh D, Dickson, Bob Baxley, Don86, E. Lynch-Klarup, Ed Rogers, Elizabeth Ferriss, Ellen-
Co2, Fabian Egli, Fang-Chieh Chou, Bing Tian Dai, Greg Stupp, Grzegorz Szpak, Bertrand Thirion, Hadrien Bertrand,
Harizo Rajaona, zxcvbnius, Henry Lin, Holger Peters, Icyblade Dai, Igor Andriushchenko, Ilya, Isaac Laughlin, Iván
Vallés, Aurélien Bellet, JPFrancoia, Jacob Schreiber, Asish Mahapatra

1.15 Previous Releases

1.15.1 Version 0.18.2

June 20, 2017

Last release with Python 2.6 support

Scikit-learn 0.18 is the last major release of scikit-learn to support Python 2.6. Later versions of scikit-learn will
require Python 2.7 or above.

Changelog

• Fixes for compatibility with NumPy 1.13.0: #7946 #8355 by Loic Esteve.
• Minor compatibility changes in the examples #9010 #8040 #9149.

Code Contributors

Aman Dalmia, Loic Esteve, Nate Guerin, Sergei Lebedev

60 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

1.15.2 Version 0.18.1

November 11, 2016

Changelog

Enhancements

• Improved sample_without_replacement speed by utilizing numpy.random.permutation for most cases.


As a result, samples may differ in this release for a fixed random state. Affected estimators:
– ensemble.BaggingClassifier
– ensemble.BaggingRegressor
– linear_model.RANSACRegressor
– model_selection.RandomizedSearchCV
– random_projection.SparseRandomProjection
This also affects the datasets.make_classification method.

Bug fixes

• Fix issue where min_grad_norm and n_iter_without_progress parameters were not being utilised
by manifold.TSNE. #6497 by Sebastian Säger
• Fix bug for svm’s decision values when decision_function_shape is ovr in svm.SVC. svm.SVC’s
decision_function was incorrect from versions 0.17.0 through 0.18.0. #7724 by Bing Tian Dai
• Attribute explained_variance_ratio of discriminant_analysis.
LinearDiscriminantAnalysis calculated with SVD and Eigen solver are now of the same length.
#7632 by JPFrancoia
• Fixes issue in Univariate feature selection where score functions were not accepting multi-label targets. #7676
by Mohammed Affan
• Fixed setting parameters when calling fit multiple times on feature_selection.SelectFromModel.
#7756 by Andreas Müller
• Fixes issue in partial_fit method of multiclass.OneVsRestClassifier when number of classes
used in partial_fit was less than the total number of classes in the data. #7786 by Srivatsan Ramesh
• Fixes issue in calibration.CalibratedClassifierCV where the sum of probabilities of each class
for a data was not 1, and CalibratedClassifierCV now handles the case where the training set has less
number of classes than the total data. #7799 by Srivatsan Ramesh
• Fix a bug where sklearn.feature_selection.SelectFdr did not exactly implement Benjamini-
Hochberg procedure. It formerly may have selected fewer features than it should. #7490 by Peng Meng.
• sklearn.manifold.LocallyLinearEmbedding now correctly handles integer inputs. #6282 by Jake
Vanderplas.
• The min_weight_fraction_leaf parameter of tree-based classifiers and regressors now assumes uniform
sample weights by default if the sample_weight argument is not passed to the fit function. Previously, the
parameter was silently ignored. #7301 by Nelson Liu.
• Numerical issue with linear_model.RidgeCV on centered data when n_features > n_samples. #6178 by
Bertrand Thirion

1.15. Previous Releases 61


scikit-learn user guide, Release 0.20.3

• Tree splitting criterion classes’ cloning/pickling is now memory safe #7680 by Ibraim Ganiev.
• Fixed a bug where decomposition.NMF sets its n_iters_ attribute in transform(). #7553 by Ekaterina
Krivich.
• sklearn.linear_model.LogisticRegressionCV now correctly handles string labels. #5874 by
Raghav RV.
• Fixed a bug where sklearn.model_selection.train_test_split raised an error when
stratify is a list of string labels. #7593 by Raghav RV.
• Fixed a bug where sklearn.model_selection.GridSearchCV and sklearn.
model_selection.RandomizedSearchCV were not pickleable because of a pickling bug in np.
ma.MaskedArray. #7594 by Raghav RV.
• All cross-validation utilities in sklearn.model_selection now permit one time cross-validation splitters
for the cv parameter. Also non-deterministic cross-validation splitters (where multiple calls to split produce
dissimilar splits) can be used as cv parameter. The sklearn.model_selection.GridSearchCV will
cross-validate each parameter setting on the split produced by the first split call to the cross-validation splitter.
#7660 by Raghav RV.
• Fix bug where preprocessing.MultiLabelBinarizer.fit_transform returned an invalid CSR
matrix. #7750 by CJ Carey.
• Fixed a bug where metrics.pairwise.cosine_distances could return a small negative distance.
#7732 by Artsion.

API changes summary

Trees and forests


• The min_weight_fraction_leaf parameter of tree-based classifiers and regressors now assumes uniform
sample weights by default if the sample_weight argument is not passed to the fit function. Previously, the
parameter was silently ignored. #7301 by Nelson Liu.
• Tree splitting criterion classes’ cloning/pickling is now memory safe. #7680 by Ibraim Ganiev.
Linear, kernelized and related models
• Length of explained_variance_ratio of discriminant_analysis.
LinearDiscriminantAnalysis changed for both Eigen and SVD solvers. The attribute has now
a length of min(n_components, n_classes - 1). #7632 by JPFrancoia
• Numerical issue with linear_model.RidgeCV on centered data when n_features > n_samples.
#6178 by Bertrand Thirion

1.15.3 Version 0.18

September 28, 2016

Last release with Python 2.6 support

Scikit-learn 0.18 will be the last version of scikit-learn to support Python 2.6. Later versions of scikit-learn will
require Python 2.7 or above.

62 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

Model Selection Enhancements and API Changes

• The model_selection module


The new module sklearn.model_selection, which groups together the functionalities of formerly
sklearn.cross_validation, sklearn.grid_search and sklearn.learning_curve, intro-
duces new possibilities such as nested cross-validation and better manipulation of parameter searches with Pan-
das.
Many things will stay the same but there are some key differences. Read below to know more about the changes.
• Data-independent CV splitters enabling nested cross-validation
The new cross-validation splitters, defined in the sklearn.model_selection, are no longer initialized
with any data-dependent parameters such as y. Instead they expose a split method that takes in the data and
yields a generator for the different splits.
This change makes it possible to use the cross-validation splitters to perform nested cross-validation, facilitated
by model_selection.GridSearchCV and model_selection.RandomizedSearchCV utilities.
• The enhanced cv_results_ attribute
The new cv_results_ attribute (of model_selection.GridSearchCV and model_selection.
RandomizedSearchCV ) introduced in lieu of the grid_scores_ attribute is a dict of 1D arrays with
elements in each array corresponding to the parameter settings (i.e. search candidates).
The cv_results_ dict can be easily imported into pandas as a DataFrame for exploring the search results.
The cv_results_ arrays include scores for each cross-validation split (with keys such as
'split0_test_score'), as well as their mean ('mean_test_score') and standard deviation
('std_test_score').
The ranks for the search candidates (based on their mean cross-validation score) is available at
cv_results_['rank_test_score'].
The parameter values for each parameter is stored separately as numpy masked object arrays. The value, for
that search candidate, is masked if the corresponding parameter is not applicable. Additionally a list of all the
parameter dicts are stored at cv_results_['params'].
• Parameters n_folds and n_iter renamed to n_splits
Some parameter names have changed: The n_folds parameter in new model_selection.KFold,
model_selection.GroupKFold (see below for the name change), and model_selection.
StratifiedKFold is now renamed to n_splits. The n_iter parameter in model_selection.
ShuffleSplit, the new class model_selection.GroupShuffleSplit and model_selection.
StratifiedShuffleSplit is now renamed to n_splits.
• Rename of splitter classes which accepts group labels along with data
The cross-validation splitters LabelKFold, LabelShuffleSplit, LeaveOneLabelOut and
LeavePLabelOut have been renamed to model_selection.GroupKFold, model_selection.
GroupShuffleSplit, model_selection.LeaveOneGroupOut and model_selection.
LeavePGroupsOut respectively.
Note the change from singular to plural form in model_selection.LeavePGroupsOut.
• Fit parameter labels renamed to groups
The labels parameter in the split method of the newly renamed splitters model_selection.
GroupKFold, model_selection.LeaveOneGroupOut, model_selection.
LeavePGroupsOut, model_selection.GroupShuffleSplit is renamed to groups following the
new nomenclature of their class names.

1.15. Previous Releases 63


scikit-learn user guide, Release 0.20.3

• Parameter n_labels renamed to n_groups


The parameter n_labels in the newly renamed model_selection.LeavePGroupsOut is changed to
n_groups.
• Training scores and Timing information
cv_results_ also includes the training scores for each cross-validation split (with keys such
as 'split0_train_score'), as well as their mean ('mean_train_score') and stan-
dard deviation ('std_train_score'). To avoid the cost of evaluating training score, set
return_train_score=False.
Additionally the mean and standard deviation of the times taken to split, train and score the model across all the
cross-validation splits is available at the key 'mean_time' and 'std_time' respectively.

Changelog

New features

Classifiers and Regressors


• The Gaussian Process module has been reimplemented and now offers classification and regression esti-
mators through gaussian_process.GaussianProcessClassifier and gaussian_process.
GaussianProcessRegressor. Among other things, the new implementation supports kernel engineering,
gradient-based hyperparameter optimization or sampling of functions from GP prior and GP posterior. Extensive
documentation and examples are provided. By Jan Hendrik Metzen.
• Added new supervised learning algorithm: Multi-layer Perceptron #3204 by Issam H. Laradji
• Added linear_model.HuberRegressor, a linear model robust to outliers. #5291 by Manoj Kumar.
• Added the multioutput.MultiOutputRegressor meta-estimator. It converts single output regressors
to multi-output regressors by fitting one regressor per output. By Tim Head.
Other estimators
• New mixture.GaussianMixture and mixture.BayesianGaussianMixture replace former mix-
ture models, employing faster inference for sounder results. #7295 by Wei Xue and Thierry Guillemot.
• Class decomposition.RandomizedPCA is now factored into decomposition.PCA and it is avail-
able calling with parameter svd_solver='randomized'. The default number of n_iter for
'randomized' has changed to 4. The old behavior of PCA is recovered by svd_solver='full'. An
additional solver calls arpack and performs truncated (non-randomized) SVD. By default, the best solver is
selected depending on the size of the input and the number of components requested. #5299 by Giorgio Patrini.
• Added two functions for mutual information estimation: feature_selection.
mutual_info_classif and feature_selection.mutual_info_regression. These
functions can be used in feature_selection.SelectKBest and feature_selection.
SelectPercentile as score functions. By Andrea Bravi and Nikolay Mayorov.
• Added the ensemble.IsolationForest class for anomaly detection based on random forests. By Nicolas
Goix.
• Added algorithm="elkan" to cluster.KMeans implementing Elkan’s fast K-Means algorithm. By
Andreas Müller.
Model selection and evaluation
• Added metrics.cluster.fowlkes_mallows_score, the Fowlkes Mallows Index which measures the
similarity of two clusterings of a set of points By Arnaud Fouchet and Thierry Guillemot.

64 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Added metrics.calinski_harabaz_score, which computes the Calinski and Harabaz score to evalu-
ate the resulting clustering of a set of points. By Arnaud Fouchet and Thierry Guillemot.
• Added new cross-validation splitter model_selection.TimeSeriesSplit to handle time series data.
#6586 by YenChen Lin
• The cross-validation iterators are replaced by cross-validation splitters available from sklearn.
model_selection, allowing for nested cross-validation. See Model Selection Enhancements and API
Changes for more information. #4294 by Raghav RV.

Enhancements

Trees and ensembles


• Added a new splitting criterion for tree.DecisionTreeRegressor, the mean absolute er-
ror. This criterion can also be used in ensemble.ExtraTreesRegressor, ensemble.
RandomForestRegressor, and the gradient boosting estimators. #6667 by Nelson Liu.
• Added weighted impurity-based early stopping criterion for decision tree growth. #6954 by Nelson Liu
• The random forest, extra tree and decision tree estimators now has a method decision_path which returns
the decision path of samples in the tree. By Arnaud Joly.
• A new example has been added unveiling the decision tree structure. By Arnaud Joly.
• Random forest, extra trees, decision trees and gradient boosting estimator accept the parameter
min_samples_split and min_samples_leaf provided as a percentage of the training samples. By
yelite and Arnaud Joly.
• Gradient boosting estimators accept the parameter criterion to specify to splitting criterion used in built
decision trees. #6667 by Nelson Liu.
• The memory footprint is reduced (sometimes greatly) for ensemble.bagging.BaseBagging and classes
that inherit from it, i.e, ensemble.BaggingClassifier, ensemble.BaggingRegressor, and
ensemble.IsolationForest, by dynamically generating attribute estimators_samples_ only
when it is needed. By David Staub.
• Added n_jobs and sample_weight parameters for ensemble.VotingClassifier to fit underlying
estimators in parallel. #5805 by Ibraim Ganiev.
Linear, kernelized and related models
• In linear_model.LogisticRegression, the SAG solver is now available in the multinomial case.
#5251 by Tom Dupre la Tour.
• linear_model.RANSACRegressor, svm.LinearSVC and svm.LinearSVR now support
sample_weight. By Imaculate.
• Add parameter loss to linear_model.RANSACRegressor to measure the error on the samples for every
trial. By Manoj Kumar.
• Prediction of out-of-sample events with Isotonic Regression (isotonic.IsotonicRegression) is now
much faster (over 1000x in tests with synthetic data). By Jonathan Arfa.
• Isotonic regression (isotonic.IsotonicRegression) now uses a better algorithm to avoid O(n^2) be-
havior in pathological cases, and is also generally faster (##6691). By Antony Lee.
• naive_bayes.GaussianNB now accepts data-independent class-priors through the parameter priors.
By Guillaume Lemaitre.

1.15. Previous Releases 65


scikit-learn user guide, Release 0.20.3

• linear_model.ElasticNet and linear_model.Lasso now works with np.float32 input data


without converting it into np.float64. This allows to reduce the memory consumption. #6913 by YenChen
Lin.
• semi_supervised.LabelPropagation and semi_supervised.LabelSpreading now accept
arbitrary kernel functions in addition to strings knn and rbf. #5762 by Utkarsh Upadhyay.
Decomposition, manifold learning and clustering
• Added inverse_transform function to decomposition.NMF to compute data matrix of original shape.
By Anish Shah.
• cluster.KMeans and cluster.MiniBatchKMeans now works with np.float32 and np.
float64 input data without converting it. This allows to reduce the memory consumption by using np.
float32. #6846 by Sebastian Säger and YenChen Lin.
Preprocessing and feature selection
• preprocessing.RobustScaler now accepts quantile_range parameter. #5929 by Konstantin Pod-
shumok.
• feature_extraction.FeatureHasher now accepts string values. #6173 by Ryad Zenine and
Devashish Deshpande.
• Keyword arguments can now be supplied to func in preprocessing.FunctionTransformer by
means of the kw_args parameter. By Brian McFee.
• feature_selection.SelectKBest and feature_selection.SelectPercentile now accept
score functions that take X, y as input and return only the scores. By Nikolay Mayorov.
Model evaluation and meta-estimators
• multiclass.OneVsOneClassifier and multiclass.OneVsRestClassifier now support
partial_fit. By Asish Panda and Philipp Dowling.
• Added support for substituting or disabling pipeline.Pipeline and pipeline.FeatureUnion com-
ponents using the set_params interface that powers sklearn.grid_search. See Selecting dimension-
ality reduction with Pipeline and GridSearchCV By Joel Nothman and Robert McGibbon.
• The new cv_results_ attribute of model_selection.GridSearchCV (and model_selection.
RandomizedSearchCV ) can be easily imported into pandas as a DataFrame. Ref Model Selection En-
hancements and API Changes for more information. #6697 by Raghav RV.
• Generalization of model_selection.cross_val_predict. One can pass method names such as pre-
dict_proba to be used in the cross validation framework instead of the default predict. By Ori Ziv and Sears
Merritt.
• The training scores and time taken for training followed by scoring for each search candidate are now available
at the cv_results_ dict. See Model Selection Enhancements and API Changes for more information. #7325
by Eugene Chen and Raghav RV.
Metrics
• Added labels flag to metrics.log_loss to explicitly provide the labels when the number of classes in
y_true and y_pred differ. #7239 by Hong Guangguo with help from Mads Jensen and Nelson Liu.
• Support sparse contingency matrices in cluster evaluation (metrics.cluster.supervised) to scale to a
large number of clusters. #7419 by Gregory Stupp and Joel Nothman.
• Add sample_weight parameter to metrics.matthews_corrcoef. By Jatin Shah and Raghav RV.
• Speed up metrics.silhouette_score by using vectorized operations. By Manoj Kumar.
• Add sample_weight parameter to metrics.confusion_matrix. By Bernardo Stein.

66 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

Miscellaneous
• Added n_jobs parameter to feature_selection.RFECV to compute the score on the test folds in par-
allel. By Manoj Kumar
• Codebase does not contain C/C++ cython generated files: they are generated during build. Distribution packages
will still contain generated C/C++ files. By Arthur Mensch.
• Reduce the memory usage for 32-bit float input arrays of utils.sparse_func.mean_variance_axis
and utils.sparse_func.incr_mean_variance_axis by supporting cython fused types. By
YenChen Lin.
• The ignore_warnings now accept a category argument to ignore only the warnings of a specified type. By
Thierry Guillemot.
• Added parameter return_X_y and return type (data, target) : tuple option to load_iris
dataset #7049, load_breast_cancer dataset #7152, load_digits dataset, load_diabetes dataset,
load_linnerud dataset, load_boston dataset #7154 by Manvendra Singh.
• Simplification of the clone function, deprecate support for estimators that modify parameters in __init__.
#5540 by Andreas Müller.
• When unpickling a scikit-learn estimator in a different version than the one the estimator was trained with, a
UserWarning is raised, see the documentation on model persistence for more details. (#7248) By Andreas
Müller.

Bug fixes

Trees and ensembles


• Random forest, extra trees, decision trees and gradient boosting won’t accept anymore
min_samples_split=1 as at least 2 samples are required to split a decision tree node. By Arnaud
Joly
• ensemble.VotingClassifier now raises NotFittedError if predict, transform or
predict_proba are called on the non-fitted estimator. by Sebastian Raschka.
• Fix bug where ensemble.AdaBoostClassifier and ensemble.AdaBoostRegressor would per-
form poorly if the random_state was fixed (#7411). By Joel Nothman.
• Fix bug in ensembles with randomization where the ensemble would not set random_state
on base estimators in a pipeline or similar nesting. (#7411). Note, results for ensemble.
BaggingClassifier ensemble.BaggingRegressor, ensemble.AdaBoostClassifier and
ensemble.AdaBoostRegressor will now differ from previous versions. By Joel Nothman.
Linear, kernelized and related models
• Fixed incorrect gradient computation for loss='squared_epsilon_insensitive' in
linear_model.SGDClassifier and linear_model.SGDRegressor (#6764). By Wenhua
Yang.
• Fix bug in linear_model.LogisticRegressionCV where solver='liblinear' did not accept
class_weights='balanced. (#6817). By Tom Dupre la Tour.
• Fix bug in neighbors.RadiusNeighborsClassifier where an error occurred when there were out-
liers being labelled and a weight function specified (#6902). By LeonieBorne.
• Fix linear_model.ElasticNet sparse decision function to match output with dense in the multioutput
case.
Decomposition, manifold learning and clustering

1.15. Previous Releases 67


scikit-learn user guide, Release 0.20.3

• decomposition.RandomizedPCA default number of iterated_power is 4 instead of 3. #5141 by Giorgio


Patrini.
• utils.extmath.randomized_svd performs 4 power iterations by default, instead or 0. In practice this
is enough for obtaining a good approximation of the true eigenvalues/vectors in the presence of noise. When
n_components is small (< .1 * min(X.shape)) n_iter is set to 7, unless the user specifies a higher number.
This improves precision with few components. #5299 by Giorgio Patrini.
• Whiten/non-whiten inconsistency between components of decomposition.PCA and decomposition.
RandomizedPCA (now factored into PCA, see the New features) is fixed. components_ are stored with no
whitening. #5299 by Giorgio Patrini.
• Fixed bug in manifold.spectral_embedding where diagonal of unnormalized Laplacian matrix was
incorrectly set to 1. #4995 by Peter Fischer.
• Fixed incorrect initialization of utils.arpack.eigsh on all occurrences. Affects cluster.
bicluster.SpectralBiclustering, decomposition.KernelPCA, manifold.
LocallyLinearEmbedding, and manifold.SpectralEmbedding (#5012). By Peter Fischer.
• Attribute explained_variance_ratio_ calculated with the SVD solver of
discriminant_analysis.LinearDiscriminantAnalysis now returns correct results. By
JPFrancoia
Preprocessing and feature selection
• preprocessing.data._transform_selected now always passes a copy of X to transform function
when copy=True (#7194). By Caio Oliveira.
Model evaluation and meta-estimators
• model_selection.StratifiedKFold now raises error if all n_labels for individual classes is less than
n_folds. #6182 by Devashish Deshpande.
• Fixed bug in model_selection.StratifiedShuffleSplit where train and test sample could overlap
in some edge cases, see #6121 for more details. By Loic Esteve.
• Fix in sklearn.model_selection.StratifiedShuffleSplit to return splits of size
train_size and test_size in all cases (#6472). By Andreas Müller.
• Cross-validation of OneVsOneClassifier and OneVsRestClassifier now works with precomputed
kernels. #7350 by Russell Smith.
• Fix incomplete predict_proba method delegation from model_selection.GridSearchCV to
linear_model.SGDClassifier (#7159) by Yichuan Liu.
Metrics
• Fix bug in metrics.silhouette_score in which clusters of size 1 were incorrectly scored. They should
get a score of 0. By Joel Nothman.
• Fix bug in metrics.silhouette_samples so that it now works with arbitrary labels, not just those
ranging from 0 to n_clusters - 1.
• Fix bug where expected and adjusted mutual information were incorrect if cluster contingency cells exceeded
2**16. By Joel Nothman.
• metrics.pairwise.pairwise_distances now converts arrays to boolean arrays when required in
scipy.spatial.distance. #5460 by Tom Dupre la Tour.
• Fix sparse input support in metrics.silhouette_score as well as example exam-
ples/text/document_clustering.py. By YenChen Lin.
• metrics.roc_curve and metrics.precision_recall_curve no longer round y_score values
when creating ROC curves; this was causing problems for users with very small differences in scores (#7353).

68 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

Miscellaneous
• model_selection.tests._search._check_param_grid now works correctly with all types that
extends/implements Sequence (except string), including range (Python 3.x) and xrange (Python 2.x). #7323 by
Viacheslav Kovalevskyi.
• utils.extmath.randomized_range_finder is more numerically stable when many power iterations
are requested, since it applies LU normalization by default. If n_iter<2 numerical issues are unlikely, thus
no normalization is applied. Other normalization options are available: 'none', 'LU' and 'QR'. #5141 by
Giorgio Patrini.
• Fix a bug where some formats of scipy.sparse matrix, and estimators with them as parameters, could not
be passed to base.clone. By Loic Esteve.
• datasets.load_svmlight_file now is able to read long int QID values. #7101 by Ibraim Ganiev.

API changes summary

Linear, kernelized and related models


• residual_metric has been deprecated in linear_model.RANSACRegressor. Use loss instead.
By Manoj Kumar.
• Access to public attributes .X_ and .y_ has been deprecated in isotonic.IsotonicRegression. By
Jonathan Arfa.
Decomposition, manifold learning and clustering
• The old mixture.DPGMM is deprecated in favor of the new mixture.BayesianGaussianMixture
(with the parameter weight_concentration_prior_type='dirichlet_process'). The new
class solves the computational problems of the old class and computes the Gaussian mixture with a Dirich-
let process prior faster than before. #7295 by Wei Xue and Thierry Guillemot.
• The old mixture.VBGMM is deprecated in favor of the new mixture.BayesianGaussianMixture
(with the parameter weight_concentration_prior_type='dirichlet_distribution'). The
new class solves the computational problems of the old class and computes the Variational Bayesian Gaussian
mixture faster than before. #6651 by Wei Xue and Thierry Guillemot.
• The old mixture.GMM is deprecated in favor of the new mixture.GaussianMixture. The new class
computes the Gaussian mixture faster than before and some of computational problems have been solved. #6666
by Wei Xue and Thierry Guillemot.
Model evaluation and meta-estimators
• The sklearn.cross_validation, sklearn.grid_search and sklearn.learning_curve
have been deprecated and the classes and functions have been reorganized into the sklearn.
model_selection module. Ref Model Selection Enhancements and API Changes for more information.
#4294 by Raghav RV.
• The grid_scores_ attribute of model_selection.GridSearchCV and model_selection.
RandomizedSearchCV is deprecated in favor of the attribute cv_results_. Ref Model Selection En-
hancements and API Changes for more information. #6697 by Raghav RV.
• The parameters n_iter or n_folds in old CV splitters are replaced by the new parameter n_splits since
it can provide a consistent and unambiguous interface to represent the number of train-test splits. #7187 by
YenChen Lin.
• classes parameter was renamed to labels in metrics.hamming_loss. #7260 by Sebastián Vanrell.

1.15. Previous Releases 69


scikit-learn user guide, Release 0.20.3

• The splitter classes LabelKFold, LabelShuffleSplit, LeaveOneLabelOut and


LeavePLabelsOut are renamed to model_selection.GroupKFold, model_selection.
GroupShuffleSplit, model_selection.LeaveOneGroupOut and model_selection.
LeavePGroupsOut respectively. Also the parameter labels in the split method of the newly renamed
splitters model_selection.LeaveOneGroupOut and model_selection.LeavePGroupsOut
is renamed to groups. Additionally in model_selection.LeavePGroupsOut, the parameter
n_labels is renamed to n_groups. #6660 by Raghav RV.
• Error and loss names for scoring parameters are now prefixed by 'neg_', such as
neg_mean_squared_error. The unprefixed versions are deprecated and will be removed in version 0.20.
#7261 by Tim Head.

Code Contributors

Aditya Joshi, Alejandro, Alexander Fabisch, Alexander Loginov, Alexander Minyushkin, Alexander Rudy, Alexan-
dre Abadie, Alexandre Abraham, Alexandre Gramfort, Alexandre Saint, alexfields, Alvaro Ulloa, alyssaq, Amlan
Kar, Andreas Mueller, andrew giessel, Andrew Jackson, Andrew McCulloh, Andrew Murray, Anish Shah, Arafat,
Archit Sharma, Ariel Rokem, Arnaud Joly, Arnaud Rachez, Arthur Mensch, Ash Hoover, asnt, b0noI, Behzad Tabib-
ian, Bernardo, Bernhard Kratzwald, Bhargav Mangipudi, blakeflei, Boyuan Deng, Brandon Carter, Brett Naul, Brian
McFee, Caio Oliveira, Camilo Lamus, Carol Willing, Cass, CeShine Lee, Charles Truong, Chyi-Kwei Yau, CJ Carey,
codevig, Colin Ni, Dan Shiebler, Daniel, Daniel Hnyk, David Ellis, David Nicholson, David Staub, David Thaler,
David Warshaw, Davide Lasagna, Deborah, definitelyuncertain, Didi Bar-Zev, djipey, dsquareindia, edwinENSAE,
Elias Kuthe, Elvis DOHMATOB, Ethan White, Fabian Pedregosa, Fabio Ticconi, fisache, Florian Wilhelm, Francis,
Francis O’Donovan, Gael Varoquaux, Ganiev Ibraim, ghg, Gilles Louppe, Giorgio Patrini, Giovanni Cherubin, Gio-
vanni Lanzani, Glenn Qian, Gordon Mohr, govin-vatsan, Graham Clenaghan, Greg Reda, Greg Stupp, Guillaume
Lemaitre, Gustav Mörtberg, halwai, Harizo Rajaona, Harry Mavroforakis, hashcode55, hdmetor, Henry Lin, Hob-
son Lane, Hugo Bowne-Anderson, Igor Andriushchenko, Imaculate, Inki Hwang, Isaac Sijaranamual, Ishank Gulati,
Issam Laradji, Iver Jordal, jackmartin, Jacob Schreiber, Jake Vanderplas, James Fiedler, James Routley, Jan Zikes,
Janna Brettingen, jarfa, Jason Laska, jblackburne, jeff levesque, Jeffrey Blackburne, Jeffrey04, Jeremy Hintz, jere-
mynixon, Jeroen, Jessica Yung, Jill-Jênn Vie, Jimmy Jia, Jiyuan Qian, Joel Nothman, johannah, John, John Boersma,
John Kirkham, John Moeller, jonathan.striebel, joncrall, Jordi, Joseph Munoz, Joshua Cook, JPFrancoia, jrfiedler,
JulianKahnert, juliathebrave, kaichogami, KamalakerDadi, Kenneth Lyons, Kevin Wang, kingjr, kjell, Konstantin
Podshumok, Kornel Kielczewski, Krishna Kalyan, krishnakalyan3, Kvle Putnam, Kyle Jackson, Lars Buitinck, ldavid,
LeiG, LeightonZhang, Leland McInnes, Liang-Chi Hsieh, Lilian Besson, lizsz, Loic Esteve, Louis Tiao, Léonie Borne,
Mads Jensen, Maniteja Nandana, Manoj Kumar, Manvendra Singh, Marco, Mario Krell, Mark Bao, Mark Szepieniec,
Martin Madsen, MartinBpr, MaryanMorel, Massil, Matheus, Mathieu Blondel, Mathieu Dubois, Matteo, Matthias Ek-
man, Max Moroz, Michael Scherer, michiaki ariga, Mikhail Korobov, Moussa Taifi, mrandrewandrade, Mridul Seth,
nadya-p, Naoya Kanai, Nate George, Nelle Varoquaux, Nelson Liu, Nick James, NickleDave, Nico, Nicolas Goix,
Nikolay Mayorov, ningchi, nlathia, okbalefthanded, Okhlopkov, Olivier Grisel, Panos Louridas, Paul Strickland, Per-
rine Letellier, pestrickland, Peter Fischer, Pieter, Ping-Yao, Chang, practicalswift, Preston Parry, Qimu Zheng, Rachit
Kansal, Raghav RV, Ralf Gommers, Ramana.S, Rammig, Randy Olson, Rob Alexander, Robert Lutz, Robin Schucker,
Rohan Jain, Ruifeng Zheng, Ryan Yu, Rémy Léone, saihttam, Saiwing Yeung, Sam Shleifer, Samuel St-Jean, Sar-
taj Singh, Sasank Chilamkurthy, saurabh.bansod, Scott Andrews, Scott Lowe, seales, Sebastian Raschka, Sebastian
Saeger, Sebastián Vanrell, Sergei Lebedev, shagun Sodhani, shanmuga cv, Shashank Shekhar, shawpan, shengxid-
uan, Shota, shuckle16, Skipper Seabold, sklearn-ci, SmedbergM, srvanrell, Sébastien Lerique, Taranjeet, themrmax,
Thierry, Thierry Guillemot, Thomas, Thomas Hallock, Thomas Moreau, Tim Head, tKammy, toastedcornflakes, Tom,
TomDLT, Toshihiro Kamishima, tracer0tong, Trent Hauck, trevorstephens, Tue Vo, Varun, Varun Jewalikar, Viach-
eslav, Vighnesh Birodkar, Vikram, Villu Ruusmann, Vinayak Mehta, walter, waterponey, Wenhua Yang, Wenjian
Huang, Will Welch, wyseguy7, xyguo, yanlend, Yaroslav Halchenko, yelite, Yen, YenChenLin, Yichuan Liu, Yoav
Ram, Yoshiki, Zheng RuiFeng, zivori, Óscar Nájera

70 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

1.15.4 Version 0.17.1

February 18, 2016

Changelog

Bug fixes

• Upgrade vendored joblib to version 0.9.4 that fixes an important bug in joblib.Parallel that can silently
yield to wrong results when working on datasets larger than 1MB: https://github.com/joblib/joblib/blob/0.9.4/
CHANGES.rst
• Fixed reading of Bunch pickles generated with scikit-learn version <= 0.16. This can affect users who have
already downloaded a dataset with scikit-learn 0.16 and are loading it with scikit-learn 0.17. See #6196 for how
this affected datasets.fetch_20newsgroups. By Loic Esteve.
• Fixed a bug that prevented using ROC AUC score to perform grid search on several CPU / cores on large arrays.
See #6147 By Olivier Grisel.
• Fixed a bug that prevented to properly set the presort parameter in ensemble.
GradientBoostingRegressor. See #5857 By Andrew McCulloh.
• Fixed a joblib error when evaluating the perplexity of a decomposition.
LatentDirichletAllocation model. See #6258 By Chyi-Kwei Yau.

1.15.5 Version 0.17

November 5, 2015

Changelog

New features

• All the Scaler classes but preprocessing.RobustScaler can be fitted online by calling partial_fit. By
Giorgio Patrini.
• The new class ensemble.VotingClassifier implements a “majority rule” / “soft voting” ensemble
classifier to combine estimators for classification. By Sebastian Raschka.
• The new class preprocessing.RobustScaler provides an alternative to preprocessing.
StandardScaler for feature-wise centering and range normalization that is robust to outliers. By Thomas
Unterthiner.
• The new class preprocessing.MaxAbsScaler provides an alternative to preprocessing.
MinMaxScaler for feature-wise range normalization when the data is already centered or sparse. By Thomas
Unterthiner.
• The new class preprocessing.FunctionTransformer turns a Python function into a Pipeline-
compatible transformer object. By Joe Jevnik.
• The new classes cross_validation.LabelKFold and cross_validation.
LabelShuffleSplit generate train-test folds, respectively similar to cross_validation.KFold and
cross_validation.ShuffleSplit, except that the folds are conditioned on a label array. By Brian
McFee, Jean Kossaifi and Gilles Louppe.

1.15. Previous Releases 71


scikit-learn user guide, Release 0.20.3

• decomposition.LatentDirichletAllocation implements the Latent Dirichlet Allocation topic


model with online variational inference. By Chyi-Kwei Yau, with code based on an implementation by Matt
Hoffman. (#3659)
• The new solver sag implements a Stochastic Average Gradient descent and is available in both
linear_model.LogisticRegression and linear_model.Ridge. This solver is very efficient for
large datasets. By Danny Sullivan and Tom Dupre la Tour. (#4738)
• The new solver cd implements a Coordinate Descent in decomposition.NMF. Previous solver based on
Projected Gradient is still available setting new parameter solver to pg, but is deprecated and will be removed
in 0.19, along with decomposition.ProjectedGradientNMF and parameters sparseness, eta,
beta and nls_max_iter. New parameters alpha and l1_ratio control L1 and L2 regularization, and
shuffle adds a shuffling step in the cd solver. By Tom Dupre la Tour and Mathieu Blondel.

Enhancements

• manifold.TSNE now supports approximate optimization via the Barnes-Hut method, leading to much faster
fitting. By Christopher Erick Moody. (#4025)
• cluster.mean_shift_.MeanShift now supports parallel execution, as implemented in the
mean_shift function. By Martino Sorbaro.
• naive_bayes.GaussianNB now supports fitting with sample_weight. By Jan Hendrik Metzen.
• dummy.DummyClassifier now supports a prior fitting strategy. By Arnaud Joly.
• Added a fit_predict method for mixture.GMM and subclasses. By Cory Lorenz.
• Added the metrics.label_ranking_loss metric. By Arnaud Joly.
• Added the metrics.cohen_kappa_score metric.
• Added a warm_start constructor parameter to the bagging ensemble models to increase the size of the en-
semble. By Tim Head.
• Added option to use multi-output regression metrics without averaging. By Konstantin Shmelkov and Michael
Eickenberg.
• Added stratify option to cross_validation.train_test_split for stratified splitting. By
Miroslav Batchkarov.
• The tree.export_graphviz function now supports aesthetic improvements for tree.
DecisionTreeClassifier and tree.DecisionTreeRegressor, including options for coloring
nodes by their majority class or impurity, showing variable names, and using node proportions instead of raw
sample counts. By Trevor Stephens.
• Improved speed of newton-cg solver in linear_model.LogisticRegression, by avoiding loss com-
putation. By Mathieu Blondel and Tom Dupre la Tour.
• The class_weight="auto" heuristic in classifiers supporting class_weight was deprecated and re-
placed by the class_weight="balanced" option, which has a simpler formula and interpretation. By
Hanna Wallach and Andreas Müller.
• Add class_weight parameter to automatically weight samples by class frequency for linear_model.
PassiveAggressiveClassifier. By Trevor Stephens.
• Added backlinks from the API reference pages to the user guide. By Andreas Müller.
• The labels parameter to sklearn.metrics.f1_score, sklearn.metrics.fbeta_score,
sklearn.metrics.recall_score and sklearn.metrics.precision_score has been ex-

72 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

tended. It is now possible to ignore one or more labels, such as where a multiclass problem has a majority
class to ignore. By Joel Nothman.
• Add sample_weight support to linear_model.RidgeClassifier. By Trevor Stephens.
• Provide an option for sparse output from sklearn.metrics.pairwise.cosine_similarity. By
Jaidev Deshpande.
• Add minmax_scale to provide a function interface for MinMaxScaler. By Thomas Unterthiner.
• dump_svmlight_file now handles multi-label datasets. By Chih-Wei Chang.
• RCV1 dataset loader (sklearn.datasets.fetch_rcv1). By Tom Dupre la Tour.
• The “Wisconsin Breast Cancer” classical two-class classification dataset is now included in scikit-learn, avail-
able with sklearn.dataset.load_breast_cancer.
• Upgraded to joblib 0.9.3 to benefit from the new automatic batching of short tasks. This makes it possible for
scikit-learn to benefit from parallelism when many very short tasks are executed in parallel, for instance by the
grid_search.GridSearchCV meta-estimator with n_jobs > 1 used with a large grid of parameters on
a small dataset. By Vlad Niculae, Olivier Grisel and Loic Esteve.
• For more details about changes in joblib 0.9.3 see the release notes: https://github.com/joblib/joblib/blob/master/
CHANGES.rst#release-093
• Improved speed (3 times per iteration) of decomposition.DictLearning with coordinate descent
method from linear_model.Lasso. By Arthur Mensch.
• Parallel processing (threaded) for queries of nearest neighbors (using the ball-tree) by Nikolay Mayorov.
• Allow datasets.make_multilabel_classification to output a sparse y. By Kashif Rasul.
• cluster.DBSCAN now accepts a sparse matrix of precomputed distances, allowing memory-efficient distance
precomputation. By Joel Nothman.
• tree.DecisionTreeClassifier now exposes an apply method for retrieving the leaf indices samples
are predicted as. By Daniel Galvez and Gilles Louppe.
• Speed up decision tree regressors, random forest regressors, extra trees regressors and gradient boosting estima-
tors by computing a proxy of the impurity improvement during the tree growth. The proxy quantity is such that
the split that maximizes this value also maximizes the impurity improvement. By Arnaud Joly, Jacob Schreiber
and Gilles Louppe.
• Speed up tree based methods by reducing the number of computations needed when computing the impurity
measure taking into account linear relationship of the computed statistics. The effect is particularly visible with
extra trees and on datasets with categorical or sparse features. By Arnaud Joly.
• ensemble.GradientBoostingRegressor and ensemble.GradientBoostingClassifier
now expose an apply method for retrieving the leaf indices each sample ends up in under each try. By Ja-
cob Schreiber.
• Add sample_weight support to linear_model.LinearRegression. By Sonny Hu. (##4881)
• Add n_iter_without_progress to manifold.TSNE to control the stopping criterion. By Santi Vil-
lalba. (#5186)
• Added optional parameter random_state in linear_model.Ridge , to set the seed of the pseudo random
generator used in sag solver. By Tom Dupre la Tour.
• Added optional parameter warm_start in linear_model.LogisticRegression. If set to True, the
solvers lbfgs, newton-cg and sag will be initialized with the coefficients computed in the previous fit. By
Tom Dupre la Tour.

1.15. Previous Releases 73


scikit-learn user guide, Release 0.20.3

• Added sample_weight support to linear_model.LogisticRegression for the lbfgs,


newton-cg, and sag solvers. By Valentin Stolbunov. Support added to the liblinear solver. By Manoj
Kumar.
• Added optional parameter presort to ensemble.GradientBoostingRegressor and ensemble.
GradientBoostingClassifier, keeping default behavior the same. This allows gradient boosters to
turn off presorting when building deep trees or using sparse data. By Jacob Schreiber.
• Altered metrics.roc_curve to drop unnecessary thresholds by default. By Graham Clenaghan.
• Added feature_selection.SelectFromModel meta-transformer which can be used along with es-
timators that have coef_ or feature_importances_ attribute to select important features of the input data. By
Maheshakya Wijewardena, Joel Nothman and Manoj Kumar.
• Added metrics.pairwise.laplacian_kernel. By Clyde Fare.
• covariance.GraphLasso allows separate control of the convergence criterion for the Elastic-Net subprob-
lem via the enet_tol parameter.
• Improved verbosity in decomposition.DictionaryLearning.
• ensemble.RandomForestClassifier and ensemble.RandomForestRegressor no longer ex-
plicitly store the samples used in bagging, resulting in a much reduced memory footprint for storing random
forest models.
• Added positive option to linear_model.Lars and linear_model.lars_path to force coeffi-
cients to be positive. (#5131)
• Added the X_norm_squared parameter to metrics.pairwise.euclidean_distances to provide
precomputed squared norms for X.
• Added the fit_predict method to pipeline.Pipeline.
• Added the preprocessing.min_max_scale function.

Bug fixes

• Fixed non-determinism in dummy.DummyClassifier with sparse multi-label output. By Andreas Müller.


• Fixed the output shape of linear_model.RANSACRegressor to (n_samples, ). By Andreas Müller.
• Fixed bug in decomposition.DictLearning when n_jobs < 0. By Andreas Müller.
• Fixed bug where grid_search.RandomizedSearchCV could consume a lot of memory for large discrete
grids. By Joel Nothman.
• Fixed bug in linear_model.LogisticRegressionCV where penalty was ignored in the final fit. By
Manoj Kumar.
• Fixed bug in ensemble.forest.ForestClassifier while computing oob_score and X is a
sparse.csc_matrix. By Ankur Ankan.
• All regressors now consistently handle and warn when given y that is of shape (n_samples, 1). By Andreas
Müller and Henry Lin. (#5431)
• Fix in cluster.KMeans cluster reassignment for sparse input by Lars Buitinck.
• Fixed a bug in lda.LDA that could cause asymmetric covariance matrices when using shrinkage. By Martin
Billinger.
• Fixed cross_validation.cross_val_predict for estimators with sparse predictions. By Buddha
Prakash.

74 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Fixed the predict_proba method of linear_model.LogisticRegression to use soft-max instead


of one-vs-rest normalization. By Manoj Kumar. (#5182)
• Fixed the partial_fit method of linear_model.SGDClassifier when called with
average=True. By Andrew Lamb. (#5282)
• Dataset fetchers use different filenames under Python 2 and Python 3 to avoid pickling compatibility issues. By
Olivier Grisel. (#5355)
• Fixed a bug in naive_bayes.GaussianNB which caused classification results to depend on scale. By Jake
Vanderplas.
• Fixed temporarily linear_model.Ridge, which was incorrect when fitting the intercept in the case of
sparse data. The fix automatically changes the solver to ‘sag’ in this case. #5360 by Tom Dupre la Tour.
• Fixed a performance bug in decomposition.RandomizedPCA on data with a large number of features
and fewer samples. (#4478) By Andreas Müller, Loic Esteve and Giorgio Patrini.
• Fixed bug in cross_decomposition.PLS that yielded unstable and platform dependent output, and failed
on fit_transform. By Arthur Mensch.
• Fixes to the Bunch class used to store datasets.
• Fixed ensemble.plot_partial_dependence ignoring the percentiles parameter.
• Providing a set as vocabulary in CountVectorizer no longer leads to inconsistent results when pickling.
• Fixed the conditions on when a precomputed Gram matrix needs to be recomputed in linear_model.
LinearRegression, linear_model.OrthogonalMatchingPursuit, linear_model.Lasso
and linear_model.ElasticNet.
• Fixed inconsistent memory layout in the coordinate descent solver that affected linear_model.
DictionaryLearning and covariance.GraphLasso. (#5337) By Olivier Grisel.
• manifold.LocallyLinearEmbedding no longer ignores the reg parameter.
• Nearest Neighbor estimators with custom distance metrics can now be pickled. (#4362)
• Fixed a bug in pipeline.FeatureUnion where transformer_weights were not properly handled
when performing grid-searches.
• Fixed a bug in linear_model.LogisticRegression and linear_model.
LogisticRegressionCV when using class_weight='balanced'```or
``class_weight='auto'. By Tom Dupre la Tour.
• Fixed bug #5495 when doing OVR(SVC(decision_function_shape=”ovr”)). Fixed by Elvis Dohmatob.

API changes summary

• Attribute data_min, data_max and data_range in preprocessing.MinMaxScaler are deprecated and


won’t be available from 0.19. Instead, the class now exposes data_min_, data_max_ and data_range_. By
Giorgio Patrini.
• All Scaler classes now have an scale_ attribute, the feature-wise rescaling applied by their transform methods.
The old attribute std_ in preprocessing.StandardScaler is deprecated and superseded by scale_; it
won’t be available in 0.19. By Giorgio Patrini.
• svm.SVC` and svm.NuSVC now have an decision_function_shape parameter to make their decision
function of shape (n_samples, n_classes) by setting decision_function_shape='ovr'. This
will be the default behavior starting in 0.19. By Andreas Müller.

1.15. Previous Releases 75


scikit-learn user guide, Release 0.20.3

• Passing 1D data arrays as input to estimators is now deprecated as it caused confusion in how the array ele-
ments should be interpreted as features or as samples. All data arrays are now expected to be explicitly shaped
(n_samples, n_features). By Vighnesh Birodkar.
• lda.LDA and qda.QDA have been moved to discriminant_analysis.
LinearDiscriminantAnalysis and discriminant_analysis.
QuadraticDiscriminantAnalysis.
• The store_covariance and tol parameters have been moved from the fit method to the constructor in
discriminant_analysis.LinearDiscriminantAnalysis and the store_covariances and
tol parameters have been moved from the fit method to the constructor in discriminant_analysis.
QuadraticDiscriminantAnalysis.
• Models inheriting from _LearntSelectorMixin will no longer support the transform methods. (i.e, Ran-
domForests, GradientBoosting, LogisticRegression, DecisionTrees, SVMs and SGD related models). Wrap
these models around the metatransfomer feature_selection.SelectFromModel to remove features
(according to coefs_ or feature_importances_) which are below a certain threshold value instead.
• cluster.KMeans re-runs cluster-assignments in case of non-convergence, to ensure consistency of
predict(X) and labels_. By Vighnesh Birodkar.
• Classifier and Regressor models are now tagged as such using the _estimator_type attribute.
• Cross-validation iterators always provide indices into training and test set, not boolean masks.
• The decision_function on all regressors was deprecated and will be removed in 0.19. Use predict
instead.
• datasets.load_lfw_pairs is deprecated and will be removed in 0.19. Use datasets.
fetch_lfw_pairs instead.
• The deprecated hmm module was removed.
• The deprecated Bootstrap cross-validation iterator was removed.
• The deprecated Ward and WardAgglomerative classes have been removed. Use clustering.
AgglomerativeClustering instead.
• cross_validation.check_cv is now a public function.
• The property residues_ of linear_model.LinearRegression is deprecated and will be removed in
0.19.
• The deprecated n_jobs parameter of linear_model.LinearRegression has been moved to the con-
structor.
• Removed deprecated class_weight parameter from linear_model.SGDClassifier’s fit method.
Use the construction parameter instead.
• The deprecated support for the sequence of sequences (or list of lists) multilabel format was removed. To convert
to and from the supported binary indicator matrix format, use MultiLabelBinarizer.
• The behavior of calling the inverse_transform method of Pipeline.pipeline will change in 0.19.
It will no longer reshape one-dimensional input to two-dimensional input.
• The deprecated attributes indicator_matrix_, multilabel_ and classes_ of preprocessing.
LabelBinarizer were removed.
• Using gamma=0 in svm.SVC and svm.SVR to automatically set the gamma to 1. / n_features is dep-
recated and will be removed in 0.19. Use gamma="auto" instead.

76 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

Code Contributors

Aaron Schumacher, Adithya Ganesh, akitty, Alexandre Gramfort, Alexey Grigorev, Ali Baharev, Allen Riddell, Ando
Saabas, Andreas Mueller, Andrew Lamb, Anish Shah, Ankur Ankan, Anthony Erlinger, Ari Rouvinen, Arnaud Joly,
Arnaud Rachez, Arthur Mensch, banilo, Barmaley.exe, benjaminirving, Boyuan Deng, Brett Naul, Brian McFee,
Buddha Prakash, Chi Zhang, Chih-Wei Chang, Christof Angermueller, Christoph Gohlke, Christophe Bourguignat,
Christopher Erick Moody, Chyi-Kwei Yau, Cindy Sridharan, CJ Carey, Clyde-fare, Cory Lorenz, Dan Blanchard,
Daniel Galvez, Daniel Kronovet, Danny Sullivan, Data1010, David, David D Lowe, David Dotson, djipey, Dmitry
Spikhalskiy, Donne Martin, Dougal J. Sutherland, Dougal Sutherland, edson duarte, Eduardo Caro, Eric Larson, Eric
Martin, Erich Schubert, Fernando Carrillo, Frank C. Eckert, Frank Zalkow, Gael Varoquaux, Ganiev Ibraim, Gilles
Louppe, Giorgio Patrini, giorgiop, Graham Clenaghan, Gryllos Prokopis, gwulfs, Henry Lin, Hsuan-Tien Lin, Im-
manuel Bayer, Ishank Gulati, Jack Martin, Jacob Schreiber, Jaidev Deshpande, Jake Vanderplas, Jan Hendrik Metzen,
Jean Kossaifi, Jeffrey04, Jeremy, jfraj, Jiali Mei, Joe Jevnik, Joel Nothman, John Kirkham, John Wittenauer, Joseph,
Joshua Loyal, Jungkook Park, KamalakerDadi, Kashif Rasul, Keith Goodman, Kian Ho, Konstantin Shmelkov, Kyler
Brown, Lars Buitinck, Lilian Besson, Loic Esteve, Louis Tiao, maheshakya, Maheshakya Wijewardena, Manoj Ku-
mar, MarkTab marktab.net, Martin Ku, Martin Spacek, MartinBpr, martinosorb, MaryanMorel, Masafumi Oyamada,
Mathieu Blondel, Matt Krump, Matti Lyra, Maxim Kolganov, mbillinger, mhg, Michael Heilman, Michael Patterson,
Miroslav Batchkarov, Nelle Varoquaux, Nicolas, Nikolay Mayorov, Olivier Grisel, Omer Katz, Óscar Nájera, Pauli
Virtanen, Peter Fischer, Peter Prettenhofer, Phil Roth, pianomania, Preston Parry, Raghav RV, Rob Zinkov, Robert
Layton, Rohan Ramanath, Saket Choudhary, Sam Zhang, santi, saurabh.bansod, scls19fr, Sebastian Raschka, Sebas-
tian Saeger, Shivan Sornarajah, SimonPL, sinhrks, Skipper Seabold, Sonny Hu, sseg, Stephen Hoover, Steven De
Gryze, Steven Seguin, Theodore Vasiloudis, Thomas Unterthiner, Tiago Freitas Pereira, Tian Wang, Tim Head, Timo-
thy Hopper, tokoroten, Tom Dupré la Tour, Trevor Stephens, Valentin Stolbunov, Vighnesh Birodkar, Vinayak Mehta,
Vincent, Vincent Michel, vstolbunov, wangz10, Wei Xue, Yucheng Low, Yury Zhauniarovich, Zac Stewart, zhai_pro,
Zichen Wang

1.15.6 Version 0.16.1

April 14, 2015

Changelog

Bug fixes

• Allow input data larger than block_size in covariance.LedoitWolf by Andreas Müller.


• Fix a bug in isotonic.IsotonicRegression deduplication that caused unstable result in
calibration.CalibratedClassifierCV by Jan Hendrik Metzen.
• Fix sorting of labels in func:preprocessing.label_binarize by Michael Heilman.
• Fix several stability and convergence issues in cross_decomposition.CCA and
cross_decomposition.PLSCanonical by Andreas Müller
• Fix a bug in cluster.KMeans when precompute_distances=False on fortran-ordered data.
• Fix a speed regression in ensemble.RandomForestClassifier’s predict and predict_proba
by Andreas Müller.
• Fix a regression where utils.shuffle converted lists and dataframes to arrays, by Olivier Grisel

1.15.7 Version 0.16

March 26, 2015

1.15. Previous Releases 77


scikit-learn user guide, Release 0.20.3

Highlights

• Speed improvements (notably in cluster.DBSCAN ), reduced memory requirements, bug-fixes and better
default settings.
• Multinomial Logistic regression and a path algorithm in linear_model.LogisticRegressionCV .
• Out-of core learning of PCA via decomposition.IncrementalPCA.
• Probability callibration of classifiers using calibration.CalibratedClassifierCV .
• cluster.Birch clustering method for large-scale datasets.
• Scalable approximate nearest neighbors search with Locality-sensitive hashing forests in neighbors.
LSHForest.
• Improved error messages and better validation when using malformed input data.
• More robust integration with pandas dataframes.

Changelog

New features

• The new neighbors.LSHForest implements locality-sensitive hashing for approximate nearest neighbors
search. By Maheshakya Wijewardena.
• Added svm.LinearSVR. This class uses the liblinear implementation of Support Vector Regression which is
much faster for large sample sizes than svm.SVR with linear kernel. By Fabian Pedregosa and Qiang Luo.
• Incremental fit for GaussianNB.
• Added sample_weight support to dummy.DummyClassifier and dummy.DummyRegressor. By
Arnaud Joly.
• Added the metrics.label_ranking_average_precision_score metrics. By Arnaud Joly.
• Add the metrics.coverage_error metrics. By Arnaud Joly.
• Added linear_model.LogisticRegressionCV . By Manoj Kumar, Fabian Pedregosa, Gael Varoquaux
and Alexandre Gramfort.
• Added warm_start constructor parameter to make it possible for any trained forest model to grow additional
trees incrementally. By Laurent Direr.
• Added sample_weight support to ensemble.GradientBoostingClassifier and ensemble.
GradientBoostingRegressor. By Peter Prettenhofer.
• Added decomposition.IncrementalPCA, an implementation of the PCA algorithm that supports out-
of-core learning with a partial_fit method. By Kyle Kastner.
• Averaged SGD for SGDClassifier and SGDRegressor By Danny Sullivan.
• Added cross_val_predict function which computes cross-validated estimates. By Luis Pedro Coelho
• Added linear_model.TheilSenRegressor, a robust generalized-median-based estimator. By Florian
Wilhelm.
• Added metrics.median_absolute_error, a robust metric. By Gael Varoquaux and Florian Wilhelm.
• Add cluster.Birch, an online clustering algorithm. By Manoj Kumar, Alexandre Gramfort and Joel Noth-
man.

78 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Added shrinkage support to discriminant_analysis.LinearDiscriminantAnalysis using two


new solvers. By Clemens Brunner and Martin Billinger.
• Added kernel_ridge.KernelRidge, an implementation of kernelized ridge regression. By Mathieu
Blondel and Jan Hendrik Metzen.
• All solvers in linear_model.Ridge now support sample_weight. By Mathieu Blondel.
• Added cross_validation.PredefinedSplit cross-validation for fixed user-provided cross-validation
folds. By Thomas Unterthiner.
• Added calibration.CalibratedClassifierCV , an approach for calibrating the predicted probabili-
ties of a classifier. By Alexandre Gramfort, Jan Hendrik Metzen, Mathieu Blondel and Balazs Kegl.

Enhancements

• Add option return_distance in hierarchical.ward_tree to return distances between nodes for


both structured and unstructured versions of the algorithm. By Matteo Visconti di Oleggio Castello. The same
option was added in hierarchical.linkage_tree. By Manoj Kumar
• Add support for sample weights in scorer objects. Metrics with sample weight support will automatically benefit
from it. By Noel Dawe and Vlad Niculae.
• Added newton-cg and lbfgs solver support in linear_model.LogisticRegression. By Manoj Ku-
mar.
• Add selection="random" parameter to implement stochastic coordinate descent for linear_model.
Lasso, linear_model.ElasticNet and related. By Manoj Kumar.
• Add sample_weight parameter to metrics.jaccard_similarity_score and metrics.
log_loss. By Jatin Shah.
• Support sparse multilabel indicator representation in preprocessing.LabelBinarizer and
multiclass.OneVsRestClassifier (by Hamzeh Alsalhi with thanks to Rohit Sivaprasad), as
well as evaluation metrics (by Joel Nothman).
• Add sample_weight parameter to metrics.jaccard_similarity_score. By Jatin Shah.
• Add support for multiclass in metrics.hinge_loss. Added labels=None as optional parameter. By Saurabh
Jha.
• Add sample_weight parameter to metrics.hinge_loss. By Saurabh Jha.
• Add multi_class="multinomial" option in linear_model.LogisticRegression to imple-
ment a Logistic Regression solver that minimizes the cross-entropy or multinomial loss instead of the default
One-vs-Rest setting. Supports lbfgs and newton-cg solvers. By Lars Buitinck and Manoj Kumar. Solver option
newton-cg by Simon Wu.
• DictVectorizer can now perform fit_transform on an iterable in a single pass, when giving the option
sort=False. By Dan Blanchard.
• GridSearchCV and RandomizedSearchCV can now be configured to work with estimators that may fail
and raise errors on individual folds. This option is controlled by the error_score parameter. This does not affect
errors raised on re-fit. By Michal Romaniuk.
• Add digits parameter to metrics.classification_report to allow report to show different precision of floating
point numbers. By Ian Gilmore.
• Add a quantile prediction strategy to the dummy.DummyRegressor. By Aaron Staple.
• Add handle_unknown option to preprocessing.OneHotEncoder to handle unknown categorical fea-
tures more gracefully during transform. By Manoj Kumar.

1.15. Previous Releases 79


scikit-learn user guide, Release 0.20.3

• Added support for sparse input data to decision trees and their ensembles. By Fares Hedyati and Arnaud Joly.
• Optimized cluster.AffinityPropagation by reducing the number of memory allocations of large
temporary data-structures. By Antony Lee.
• Parellization of the computation of feature importances in random forest. By Olivier Grisel and Arnaud Joly.
• Add n_iter_ attribute to estimators that accept a max_iter attribute in their constructor. By Manoj Kumar.
• Added decision function for multiclass.OneVsOneClassifier By Raghav RV and Kyle Beauchamp.
• neighbors.kneighbors_graph and radius_neighbors_graph support non-Euclidean metrics.
By Manoj Kumar
• Parameter connectivity in cluster.AgglomerativeClustering and family now accept callables
that return a connectivity matrix. By Manoj Kumar.
• Sparse support for paired_distances. By Joel Nothman.
• cluster.DBSCAN now supports sparse input and sample weights and has been optimized: the inner loop has
been rewritten in Cython and radius neighbors queries are now computed in batch. By Joel Nothman and Lars
Buitinck.
• Add class_weight parameter to automatically weight samples by class frequency for
ensemble.RandomForestClassifier, tree.DecisionTreeClassifier, ensemble.
ExtraTreesClassifier and tree.ExtraTreeClassifier. By Trevor Stephens.
• grid_search.RandomizedSearchCV now does sampling without replacement if all parameters are given
as lists. By Andreas Müller.
• Parallelized calculation of pairwise_distances is now supported for scipy metrics and custom callables.
By Joel Nothman.
• Allow the fitting and scoring of all clustering algorithms in pipeline.Pipeline. By Andreas Müller.
• More robust seeding and improved error messages in cluster.MeanShift by Andreas Müller.
• Make the stopping criterion for mixture.GMM, mixture.DPGMM and mixture.VBGMM less dependent on
the number of samples by thresholding the average log-likelihood change instead of its sum over all samples.
By Hervé Bredin.
• The outcome of manifold.spectral_embedding was made deterministic by flipping the sign of eigen-
vectors. By Hasil Sharma.
• Significant performance and memory usage improvements in preprocessing.PolynomialFeatures.
By Eric Martin.
• Numerical stability improvements for preprocessing.StandardScaler and preprocessing.
scale. By Nicolas Goix
• svm.SVC fitted on sparse input now implements decision_function. By Rob Zinkov and Andreas
Müller.
• cross_validation.train_test_split now preserves the input type, instead of converting to numpy
arrays.

Documentation improvements

• Added example of using FeatureUnion for heterogeneous input. By Matt Terry


• Documentation on scorers was improved, to highlight the handling of loss functions. By Matt Pico.
• A discrepancy between liblinear output and scikit-learn’s wrappers is now noted. By Manoj Kumar.

80 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Improved documentation generation: examples referring to a class or function are now shown in a gallery on
the class/function’s API reference page. By Joel Nothman.
• More explicit documentation of sample generators and of data transformation. By Joel Nothman.
• sklearn.neighbors.BallTree and sklearn.neighbors.KDTree used to point to empty pages
stating that they are aliases of BinaryTree. This has been fixed to show the correct class docs. By Manoj Kumar.
• Added silhouette plots for analysis of KMeans clustering using metrics.silhouette_samples and
metrics.silhouette_score. See Selecting the number of clusters with silhouette analysis on KMeans
clustering

Bug fixes

• Metaestimators now support ducktyping for the presence of decision_function,


predict_proba and other methods. This fixes behavior of grid_search.GridSearchCV,
grid_search.RandomizedSearchCV, pipeline.Pipeline, feature_selection.RFE,
feature_selection.RFECV when nested. By Joel Nothman
• The scoring attribute of grid-search and cross-validation methods is no longer ignored when a
grid_search.GridSearchCV is given as a base estimator or the base estimator doesn’t have predict.
• The function hierarchical.ward_tree now returns the children in the same order for both the structured
and unstructured versions. By Matteo Visconti di Oleggio Castello.
• feature_selection.RFECV now correctly handles cases when step is not equal to 1. By Nikolay
Mayorov
• The decomposition.PCA now undoes whitening in its inverse_transform. Also, its components_
now always have unit length. By Michael Eickenberg.
• Fix incomplete download of the dataset when datasets.download_20newsgroups is called. By Manoj
Kumar.
• Various fixes to the Gaussian processes subpackage by Vincent Dubourg and Jan Hendrik Metzen.
• Calling partial_fit with class_weight=='auto' throws an appropriate error message and suggests
a work around. By Danny Sullivan.
• RBFSampler with gamma=g formerly approximated rbf_kernel with gamma=g/2.; the definition of
gamma is now consistent, which may substantially change your results if you use a fixed value. (If you cross-
validated over gamma, it probably doesn’t matter too much.) By Dougal Sutherland.
• Pipeline object delegate the classes_ attribute to the underlying estimator. It allows, for instance, to make
bagging of a pipeline object. By Arnaud Joly
• neighbors.NearestCentroid now uses the median as the centroid when metric is set to manhattan.
It was using the mean before. By Manoj Kumar
• Fix numerical stability issues in linear_model.SGDClassifier and linear_model.
SGDRegressor by clipping large gradients and ensuring that weight decay rescaling is always positive (for
large l2 regularization and large learning rate values). By Olivier Grisel
• When compute_full_tree is set to “auto”, the full tree is built when n_clusters is high and is early stopped when
n_clusters is low, while the behavior should be vice-versa in cluster.AgglomerativeClustering (and
friends). This has been fixed By Manoj Kumar
• Fix lazy centering of data in linear_model.enet_path and linear_model.lasso_path. It was
centered around one. It has been changed to be centered around the origin. By Manoj Kumar

1.15. Previous Releases 81


scikit-learn user guide, Release 0.20.3

• Fix handling of precomputed affinity matrices in cluster.AgglomerativeClustering when using


connectivity constraints. By Cathy Deng
• Correct partial_fit handling of class_prior for sklearn.naive_bayes.MultinomialNB and
sklearn.naive_bayes.BernoulliNB. By Trevor Stephens.
• Fixed a crash in metrics.precision_recall_fscore_support when using unsorted labels in the
multi-label setting. By Andreas Müller.
• Avoid skipping the first nearest neighbor in the methods radius_neighbors, kneighbors,
kneighbors_graph and radius_neighbors_graph in sklearn.neighbors.
NearestNeighbors and family, when the query data is not the same as fit data. By Manoj Kumar.
• Fix log-density calculation in the mixture.GMM with tied covariance. By Will Dawson
• Fixed a scaling error in feature_selection.SelectFdr where a factor n_features was missing. By
Andrew Tulloch
• Fix zero division in neighbors.KNeighborsRegressor and related classes when using distance weight-
ing and having identical data points. By Garret-R.
• Fixed round off errors with non positive-definite covariance matrices in GMM. By Alexis Mignon.
• Fixed a error in the computation of conditional probabilities in naive_bayes.BernoulliNB. By Hanna
Wallach.
• Make the method radius_neighbors of neighbors.NearestNeighbors return the samples lying
on the boundary for algorithm='brute'. By Yan Yi.
• Flip sign of dual_coef_ of svm.SVC to make it consistent with the documentation and
decision_function. By Artem Sobolev.
• Fixed handling of ties in isotonic.IsotonicRegression. We now use the weighted average of targets
(secondary method). By Andreas Müller and Michael Bommarito.

API changes summary

• GridSearchCV and cross_val_score and other meta-estimators don’t convert pandas DataFrames into
arrays any more, allowing DataFrame specific operations in custom estimators.
• multiclass.fit_ovr, multiclass.predict_ovr, predict_proba_ovr, multiclass.
fit_ovo, multiclass.predict_ovo, multiclass.fit_ecoc and multiclass.
predict_ecoc are deprecated. Use the underlying estimators instead.
• Nearest neighbors estimators used to take arbitrary keyword arguments and pass these to their distance metric.
This will no longer be supported in scikit-learn 0.18; use the metric_params argument instead.
• n_jobs parameter of the fit method shifted to the constructor of the LinearRegression class.
• The predict_proba method of multiclass.OneVsRestClassifier now returns two probabilities
per sample in the multiclass case; this is consistent with other estimators and with the method’s documenta-
tion, but previous versions accidentally returned only the positive probability. Fixed by Will Lamond and Lars
Buitinck.
• Change default value of precompute in ElasticNet and Lasso to False. Setting precompute to “auto” was
found to be slower when n_samples > n_features since the computation of the Gram matrix is computationally
expensive and outweighs the benefit of fitting the Gram for just one alpha. precompute="auto" is now
deprecated and will be removed in 0.18 By Manoj Kumar.
• Expose positive option in linear_model.enet_path and linear_model.enet_path which
constrains coefficients to be positive. By Manoj Kumar.

82 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Users should now supply an explicit average parameter to sklearn.metrics.f1_score, sklearn.


metrics.fbeta_score, sklearn.metrics.recall_score and sklearn.metrics.
precision_score when performing multiclass or multilabel (i.e. not binary) classification. By Joel
Nothman.
• scoring parameter for cross validation now accepts ‘f1_micro’, ‘f1_macro’ or ‘f1_weighted’. ‘f1’ is now for
binary classification only. Similar changes apply to ‘precision’ and ‘recall’. By Joel Nothman.
• The fit_intercept, normalize and return_models parameters in linear_model.enet_path
and linear_model.lasso_path have been removed. They were deprecated since 0.14
• From now onwards, all estimators will uniformly raise NotFittedError (utils.validation.
NotFittedError), when any of the predict like methods are called before the model is fit. By Raghav
RV.
• Input data validation was refactored for more consistent input validation. The check_arrays function was
replaced by check_array and check_X_y. By Andreas Müller.
• Allow X=None in the methods radius_neighbors, kneighbors, kneighbors_graph and
radius_neighbors_graph in sklearn.neighbors.NearestNeighbors and family. If set to
None, then for every sample this avoids setting the sample itself as the first nearest neighbor. By Manoj Kumar.
• Add parameter include_self in neighbors.kneighbors_graph and neighbors.
radius_neighbors_graph which has to be explicitly set by the user. If set to True, then the
sample itself is considered as the first nearest neighbor.
• thresh parameter is deprecated in favor of new tol parameter in GMM, DPGMM and VBGMM. See Enhancements
section for details. By Hervé Bredin.
• Estimators will treat input with dtype object as numeric when possible. By Andreas Müller
• Estimators now raise ValueError consistently when fitted on empty data (less than 1 sample or less than 1 feature
for 2D input). By Olivier Grisel.
• The shuffle option of linear_model.SGDClassifier, linear_model.SGDRegressor,
linear_model.Perceptron, linear_model.PassiveAggressiveClassifier and
linear_model.PassiveAggressiveRegressor now defaults to True.
• cluster.DBSCAN now uses a deterministic initialization. The random_state parameter is deprecated. By
Erich Schubert.

Code Contributors

A. Flaxman, Aaron Schumacher, Aaron Staple, abhishek thakur, Akshay, akshayah3, Aldrian Obaja, Alexander
Fabisch, Alexandre Gramfort, Alexis Mignon, Anders Aagaard, Andreas Mueller, Andreas van Cranenburgh, An-
drew Tulloch, Andrew Walker, Antony Lee, Arnaud Joly, banilo, Barmaley.exe, Ben Davies, Benedikt Koehler, bhsu,
Boris Feld, Borja Ayerdi, Boyuan Deng, Brent Pedersen, Brian Wignall, Brooke Osborn, Calvin Giles, Cathy Deng,
Celeo, cgohlke, chebee7i, Christian Stade-Schuldt, Christof Angermueller, Chyi-Kwei Yau, CJ Carey, Clemens Brun-
ner, Daiki Aminaka, Dan Blanchard, danfrankj, Danny Sullivan, David Fletcher, Dmitrijs Milajevs, Dougal J. Suther-
land, Erich Schubert, Fabian Pedregosa, Florian Wilhelm, floydsoft, Félix-Antoine Fortin, Gael Varoquaux, Garrett-R,
Gilles Louppe, gpassino, gwulfs, Hampus Bengtsson, Hamzeh Alsalhi, Hanna Wallach, Harry Mavroforakis, Hasil
Sharma, Helder, Herve Bredin, Hsiang-Fu Yu, Hugues SALAMIN, Ian Gilmore, Ilambharathi Kanniah, Imran Haque,
isms, Jake VanderPlas, Jan Dlabal, Jan Hendrik Metzen, Jatin Shah, Javier López Peña, jdcaballero, Jean Kossaifi, Jeff
Hammerbacher, Joel Nothman, Jonathan Helmus, Joseph, Kaicheng Zhang, Kevin Markham, Kyle Beauchamp, Kyle
Kastner, Lagacherie Matthieu, Lars Buitinck, Laurent Direr, leepei, Loic Esteve, Luis Pedro Coelho, Lukas Michel-
bacher, maheshakya, Manoj Kumar, Manuel, Mario Michael Krell, Martin, Martin Billinger, Martin Ku, Mateusz
Susik, Mathieu Blondel, Matt Pico, Matt Terry, Matteo Visconti dOC, Matti Lyra, Max Linke, Mehdi Cherti, Michael
Bommarito, Michael Eickenberg, Michal Romaniuk, MLG, mr.Shu, Nelle Varoquaux, Nicola Montecchio, Nicolas,
Nikolay Mayorov, Noel Dawe, Okal Billy, Olivier Grisel, Óscar Nájera, Paolo Puggioni, Peter Prettenhofer, Pratap

1.15. Previous Releases 83


scikit-learn user guide, Release 0.20.3

Vardhan, pvnguyen, queqichao, Rafael Carrascosa, Raghav R V, Rahiel Kasim, Randall Mason, Rob Zinkov, Robert
Bradshaw, Saket Choudhary, Sam Nicholls, Samuel Charron, Saurabh Jha, sethdandridge, sinhrks, snuderl, Stefan
Otte, Stefan van der Walt, Steve Tjoa, swu, Sylvain Zimmer, tejesh95, terrycojones, Thomas Delteil, Thomas Un-
terthiner, Tomas Kazmar, trevorstephens, tttthomasssss, Tzu-Ming Kuo, ugurcaliskan, ugurthemaster, Vinayak Mehta,
Vincent Dubourg, Vjacheslav Murashkin, Vlad Niculae, wadawson, Wei Xue, Will Lamond, Wu Jiang, x0l, Xinfan
Meng, Yan Yi, Yu-Chin

1.15.8 Version 0.15.2

September 4, 2014

Bug fixes

• Fixed handling of the p parameter of the Minkowski distance that was previously ignored in nearest neighbors
models. By Nikolay Mayorov.
• Fixed duplicated alphas in linear_model.LassoLars with early stopping on 32 bit Python. By Olivier
Grisel and Fabian Pedregosa.
• Fixed the build under Windows when scikit-learn is built with MSVC while NumPy is built with MinGW. By
Olivier Grisel and Federico Vaggi.
• Fixed an array index overflow bug in the coordinate descent solver. By Gael Varoquaux.
• Better handling of numpy 1.9 deprecation warnings. By Gael Varoquaux.
• Removed unnecessary data copy in cluster.KMeans. By Gael Varoquaux.
• Explicitly close open files to avoid ResourceWarnings under Python 3. By Calvin Giles.
• The transform of discriminant_analysis.LinearDiscriminantAnalysis now projects the
input on the most discriminant directions. By Martin Billinger.
• Fixed potential overflow in _tree.safe_realloc by Lars Buitinck.
• Performance optimization in isotonic.IsotonicRegression. By Robert Bradshaw.
• nose is non-longer a runtime dependency to import sklearn, only for running the tests. By Joel Nothman.
• Many documentation and website fixes by Joel Nothman, Lars Buitinck Matt Pico, and others.

1.15.9 Version 0.15.1

August 1, 2014

Bug fixes

• Made cross_validation.cross_val_score use cross_validation.KFold instead of


cross_validation.StratifiedKFold on multi-output classification problems. By Nikolay Mayorov.
• Support unseen labels preprocessing.LabelBinarizer to restore the default behavior of 0.14.1 for
backward compatibility. By Hamzeh Alsalhi.
• Fixed the cluster.KMeans stopping criterion that prevented early convergence detection. By Edward Raff
and Gael Varoquaux.
• Fixed the behavior of multiclass.OneVsOneClassifier. in case of ties at the per-class vote level by
computing the correct per-class sum of prediction scores. By Andreas Müller.

84 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Made cross_validation.cross_val_score and grid_search.GridSearchCV accept Python


lists as input data. This is especially useful for cross-validation and model selection of text processing pipelines.
By Andreas Müller.
• Fixed data input checks of most estimators to accept input data that implements the NumPy __array__
protocol. This is the case for for pandas.Series and pandas.DataFrame in recent versions of pandas.
By Gael Varoquaux.
• Fixed a regression for linear_model.SGDClassifier with class_weight="auto" on data with
non-contiguous labels. By Olivier Grisel.

1.15.10 Version 0.15

July 15, 2014

Highlights

• Many speed and memory improvements all across the code


• Huge speed and memory improvements to random forests (and extra trees) that also benefit better from parallel
computing.
• Incremental fit to BernoulliRBM
• Added cluster.AgglomerativeClustering for hierarchical agglomerative clustering with average
linkage, complete linkage and ward strategies.
• Added linear_model.RANSACRegressor for robust regression models.
• Added dimensionality reduction with manifold.TSNE which can be used to visualize high-dimensional data.

Changelog

New features

• Added ensemble.BaggingClassifier and ensemble.BaggingRegressor meta-estimators for


ensembling any kind of base estimator. See the Bagging section of the user guide for details and examples.
By Gilles Louppe.
• New unsupervised feature selection algorithm feature_selection.VarianceThreshold, by Lars
Buitinck.
• Added linear_model.RANSACRegressor meta-estimator for the robust fitting of regression models. By
Johannes Schönberger.
• Added cluster.AgglomerativeClustering for hierarchical agglomerative clustering with average
linkage, complete linkage and ward strategies, by Nelle Varoquaux and Gael Varoquaux.
• Shorthand constructors pipeline.make_pipeline and pipeline.make_union were added by Lars
Buitinck.
• Shuffle option for cross_validation.StratifiedKFold. By Jeffrey Blackburne.
• Incremental learning (partial_fit) for Gaussian Naive Bayes by Imran Haque.
• Added partial_fit to BernoulliRBM By Danny Sullivan.
• Added learning_curve utility to chart performance with respect to training size. See Plotting Learning
Curves. By Alexander Fabisch.

1.15. Previous Releases 85


scikit-learn user guide, Release 0.20.3

• Add positive option in LassoCV and ElasticNetCV . By Brian Wignall and Alexandre Gramfort.
• Added linear_model.MultiTaskElasticNetCV and linear_model.MultiTaskLassoCV . By
Manoj Kumar.
• Added manifold.TSNE. By Alexander Fabisch.

Enhancements

• Add sparse input support to ensemble.AdaBoostClassifier and ensemble.


AdaBoostRegressor meta-estimators. By Hamzeh Alsalhi.
• Memory improvements of decision trees, by Arnaud Joly.
• Decision trees can now be built in best-first manner by using max_leaf_nodes as the stopping criteria.
Refactored the tree code to use either a stack or a priority queue for tree building. By Peter Prettenhofer and
Gilles Louppe.
• Decision trees can now be fitted on fortran- and c-style arrays, and non-continuous arrays without the need to
make a copy. If the input array has a different dtype than np.float32, a fortran- style copy will be made
since fortran-style memory layout has speed advantages. By Peter Prettenhofer and Gilles Louppe.
• Speed improvement of regression trees by optimizing the the computation of the mean square error criterion.
This lead to speed improvement of the tree, forest and gradient boosting tree modules. By Arnaud Joly
• The img_to_graph and grid_tograph functions in sklearn.feature_extraction.image now
return np.ndarray instead of np.matrix when return_as=np.ndarray. See the Notes section for
more information on compatibility.
• Changed the internal storage of decision trees to use a struct array. This fixed some small bugs, while improving
code and providing a small speed gain. By Joel Nothman.
• Reduce memory usage and overhead when fitting and predicting with forests of randomized trees in parallel
with n_jobs != 1 by leveraging new threading backend of joblib 0.8 and releasing the GIL in the tree fitting
Cython code. By Olivier Grisel and Gilles Louppe.
• Speed improvement of the sklearn.ensemble.gradient_boosting module. By Gilles Louppe and
Peter Prettenhofer.
• Various enhancements to the sklearn.ensemble.gradient_boosting module: a warm_start ar-
gument to fit additional trees, a max_leaf_nodes argument to fit GBM style trees, a monitor fit argument
to inspect the estimator during training, and refactoring of the verbose code. By Peter Prettenhofer.
• Faster sklearn.ensemble.ExtraTrees by caching feature values. By Arnaud Joly.
• Faster depth-based tree building algorithm such as decision tree, random forest, extra trees or gradient tree
boosting (with depth based growing strategy) by avoiding trying to split on found constant features in the sample
subset. By Arnaud Joly.
• Add min_weight_fraction_leaf pre-pruning parameter to tree-based methods: the minimum weighted
fraction of the input samples required to be at a leaf node. By Noel Dawe.
• Added metrics.pairwise_distances_argmin_min, by Philippe Gervais.
• Added predict method to cluster.AffinityPropagation and cluster.MeanShift, by Mathieu
Blondel.
• Vector and matrix multiplications have been optimised throughout the library by Denis Engemann, and Alexan-
dre Gramfort. In particular, they should take less memory with older NumPy versions (prior to 1.7.2).
• Precision-recall and ROC examples now use train_test_split, and have more explanation of why these metrics
are useful. By Kyle Kastner

86 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• The training algorithm for decomposition.NMF is faster for sparse matrices and has much lower memory
complexity, meaning it will scale up gracefully to large datasets. By Lars Buitinck.
• Added svd_method option with default value to “randomized” to decomposition.FactorAnalysis to
save memory and significantly speedup computation by Denis Engemann, and Alexandre Gramfort.
• Changed cross_validation.StratifiedKFold to try and preserve as much of the original ordering of
samples as possible so as not to hide overfitting on datasets with a non-negligible level of samples dependency.
By Daniel Nouri and Olivier Grisel.
• Add multi-output support to gaussian_process.GaussianProcess by John Novak.
• Support for precomputed distance matrices in nearest neighbor estimators by Robert Layton and Joel Nothman.
• Norm computations optimized for NumPy 1.6 and later versions by Lars Buitinck. In particular, the k-means
algorithm no longer needs a temporary data structure the size of its input.
• dummy.DummyClassifier can now be used to predict a constant output value. By Manoj Kumar.
• dummy.DummyRegressor has now a strategy parameter which allows to predict the mean, the median of the
training set or a constant output value. By Maheshakya Wijewardena.
• Multi-label classification output in multilabel indicator format is now supported by metrics.
roc_auc_score and metrics.average_precision_score by Arnaud Joly.
• Significant performance improvements (more than 100x speedup for large problems) in isotonic.
IsotonicRegression by Andrew Tulloch.
• Speed and memory usage improvements to the SGD algorithm for linear models: it now uses threads, not
separate processes, when n_jobs>1. By Lars Buitinck.
• Grid search and cross validation allow NaNs in the input arrays so that preprocessors such as
preprocessing.Imputer can be trained within the cross validation loop, avoiding potentially skewed
results.
• Ridge regression can now deal with sample weights in feature space (only sample space until then). By Michael
Eickenberg. Both solutions are provided by the Cholesky solver.
• Several classification and regression metrics now support weighted samples with the new
sample_weight argument: metrics.accuracy_score, metrics.zero_one_loss,
metrics.precision_score, metrics.average_precision_score, metrics.
f1_score, metrics.fbeta_score, metrics.recall_score, metrics.roc_auc_score,
metrics.explained_variance_score, metrics.mean_squared_error, metrics.
mean_absolute_error, metrics.r2_score. By Noel Dawe.
• Speed up of the sample generator datasets.make_multilabel_classification. By Joel Nothman.

Documentation improvements

• The Working With Text Data tutorial has now been worked in to the main documentation’s tutorial section.
Includes exercises and skeletons for tutorial presentation. Original tutorial created by several authors including
Olivier Grisel, Lars Buitinck and many others. Tutorial integration into the scikit-learn documentation by Jaques
Grobler
• Added Computational Performance documentation. Discussion and examples of prediction latency / throughput
and different factors that have influence over speed. Additional tips for building faster models and choosing a
relevant compromise between speed and predictive power. By Eustache Diemert.

1.15. Previous Releases 87


scikit-learn user guide, Release 0.20.3

Bug fixes

• Fixed bug in decomposition.MiniBatchDictionaryLearning : partial_fit was not working


properly.
• Fixed bug in linear_model.stochastic_gradient : l1_ratio was used as (1.0 - l1_ratio)
.
• Fixed bug in multiclass.OneVsOneClassifier with string labels
• Fixed a bug in LassoCV and ElasticNetCV : they would not pre-compute the Gram matrix with
precompute=True or precompute="auto" and n_samples > n_features. By Manoj Kumar.
• Fixed incorrect estimation of the degrees of freedom in feature_selection.f_regression when vari-
ates are not centered. By Virgile Fritsch.
• Fixed a race condition in parallel processing with pre_dispatch != "all" (for instance, in
cross_val_score). By Olivier Grisel.
• Raise error in cluster.FeatureAgglomeration and cluster.WardAgglomeration when no
samples are given, rather than returning meaningless clustering.
• Fixed bug in gradient_boosting.GradientBoostingRegressor with loss='huber': gamma
might have not been initialized.
• Fixed feature importances as computed with a forest of randomized trees when fit with sample_weight !=
None and/or with bootstrap=True. By Gilles Louppe.

API changes summary

• sklearn.hmm is deprecated. Its removal is planned for the 0.17 release.


• Use of covariance.EllipticEnvelop has now been removed after deprecation. Please use
covariance.EllipticEnvelope instead.
• cluster.Ward is deprecated. Use cluster.AgglomerativeClustering instead.
• cluster.WardClustering is deprecated. Use
• cluster.AgglomerativeClustering instead.
• cross_validation.Bootstrap is deprecated. cross_validation.KFold or
cross_validation.ShuffleSplit are recommended instead.
• Direct support for the sequence of sequences (or list of lists) multilabel format is deprecated. To convert to and
from the supported binary indicator matrix format, use MultiLabelBinarizer. By Joel Nothman.
• Add score method to PCA following the model of probabilistic PCA and deprecate ProbabilisticPCA
model whose score implementation is not correct. The computation now also exploits the matrix inversion
lemma for faster computation. By Alexandre Gramfort.
• The score method of FactorAnalysis now returns the average log-likelihood of the samples. Use
score_samples to get log-likelihood of each sample. By Alexandre Gramfort.
• Generating boolean masks (the setting indices=False) from cross-validation generators is deprecated. Sup-
port for masks will be removed in 0.17. The generators have produced arrays of indices by default since 0.10.
By Joel Nothman.
• 1-d arrays containing strings with dtype=object (as used in Pandas) are now considered valid classification
targets. This fixes a regression from version 0.13 in some classifiers. By Joel Nothman.
• Fix wrong explained_variance_ratio_ attribute in RandomizedPCA. By Alexandre Gramfort.

88 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Fit alphas for each l1_ratio instead of mean_l1_ratio in linear_model.ElasticNetCV and


linear_model.LassoCV . This changes the shape of alphas_ from (n_alphas,) to (n_l1_ratio,
n_alphas) if the l1_ratio provided is a 1-D array like object of length greater than one. By Manoj Kumar.
• Fix linear_model.ElasticNetCV and linear_model.LassoCV when fitting intercept and input
data is sparse. The automatic grid of alphas was not computed correctly and the scaling with normalize was
wrong. By Manoj Kumar.
• Fix wrong maximal number of features drawn (max_features) at each split for decision trees, random forests
and gradient tree boosting. Previously, the count for the number of drawn features started only after one non
constant features in the split. This bug fix will affect computational and generalization performance of those
algorithms in the presence of constant features. To get back previous generalization performance, you should
modify the value of max_features. By Arnaud Joly.
• Fix wrong maximal number of features drawn (max_features) at each split for ensemble.
ExtraTreesClassifier and ensemble.ExtraTreesRegressor. Previously, only non constant
features in the split was counted as drawn. Now constant features are counted as drawn. Furthermore at least
one feature must be non constant in order to make a valid split. This bug fix will affect computational and gen-
eralization performance of extra trees in the presence of constant features. To get back previous generalization
performance, you should modify the value of max_features. By Arnaud Joly.
• Fix utils.compute_class_weight when class_weight=="auto". Previously it was broken for
input of non-integer dtype and the weighted array that was returned was wrong. By Manoj Kumar.
• Fix cross_validation.Bootstrap to return ValueError when n_train + n_test > n. By
Ronald Phlypo.

People

List of contributors for release 0.15 by number of commits.


• 312 Olivier Grisel
• 275 Lars Buitinck
• 221 Gael Varoquaux
• 148 Arnaud Joly
• 134 Johannes Schönberger
• 119 Gilles Louppe
• 113 Joel Nothman
• 111 Alexandre Gramfort
• 95 Jaques Grobler
• 89 Denis Engemann
• 83 Peter Prettenhofer
• 83 Alexander Fabisch
• 62 Mathieu Blondel
• 60 Eustache Diemert
• 60 Nelle Varoquaux
• 49 Michael Bommarito
• 45 Manoj-Kumar-S

1.15. Previous Releases 89


scikit-learn user guide, Release 0.20.3

• 28 Kyle Kastner
• 26 Andreas Mueller
• 22 Noel Dawe
• 21 Maheshakya Wijewardena
• 21 Brooke Osborn
• 21 Hamzeh Alsalhi
• 21 Jake VanderPlas
• 21 Philippe Gervais
• 19 Bala Subrahmanyam Varanasi
• 12 Ronald Phlypo
• 10 Mikhail Korobov
• 8 Thomas Unterthiner
• 8 Jeffrey Blackburne
• 8 eltermann
• 8 bwignall
• 7 Ankit Agrawal
• 7 CJ Carey
• 6 Daniel Nouri
• 6 Chen Liu
• 6 Michael Eickenberg
• 6 ugurthemaster
• 5 Aaron Schumacher
• 5 Baptiste Lagarde
• 5 Rajat Khanduja
• 5 Robert McGibbon
• 5 Sergio Pascual
• 4 Alexis Metaireau
• 4 Ignacio Rossi
• 4 Virgile Fritsch
• 4 Sebastian Säger
• 4 Ilambharathi Kanniah
• 4 sdenton4
• 4 Robert Layton
• 4 Alyssa
• 4 Amos Waterland
• 3 Andrew Tulloch

90 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• 3 murad
• 3 Steven Maude
• 3 Karol Pysniak
• 3 Jacques Kvam
• 3 cgohlke
• 3 cjlin
• 3 Michael Becker
• 3 hamzeh
• 3 Eric Jacobsen
• 3 john collins
• 3 kaushik94
• 3 Erwin Marsi
• 2 csytracy
• 2 LK
• 2 Vlad Niculae
• 2 Laurent Direr
• 2 Erik Shilts
• 2 Raul Garreta
• 2 Yoshiki Vázquez Baeza
• 2 Yung Siang Liau
• 2 abhishek thakur
• 2 James Yu
• 2 Rohit Sivaprasad
• 2 Roland Szabo
• 2 amormachine
• 2 Alexis Mignon
• 2 Oscar Carlsson
• 2 Nantas Nardelli
• 2 jess010
• 2 kowalski87
• 2 Andrew Clegg
• 2 Federico Vaggi
• 2 Simon Frid
• 2 Félix-Antoine Fortin
• 1 Ralf Gommers
• 1 t-aft

1.15. Previous Releases 91


scikit-learn user guide, Release 0.20.3

• 1 Ronan Amicel
• 1 Rupesh Kumar Srivastava
• 1 Ryan Wang
• 1 Samuel Charron
• 1 Samuel St-Jean
• 1 Fabian Pedregosa
• 1 Skipper Seabold
• 1 Stefan Walk
• 1 Stefan van der Walt
• 1 Stephan Hoyer
• 1 Allen Riddell
• 1 Valentin Haenel
• 1 Vijay Ramesh
• 1 Will Myers
• 1 Yaroslav Halchenko
• 1 Yoni Ben-Meshulam
• 1 Yury V. Zaytsev
• 1 adrinjalali
• 1 ai8rahim
• 1 alemagnani
• 1 alex
• 1 benjamin wilson
• 1 chalmerlowe
• 1 dzikie drożdże
• 1 jamestwebber
• 1 matrixorz
• 1 popo
• 1 samuela
• 1 François Boulogne
• 1 Alexander Measure
• 1 Ethan White
• 1 Guilherme Trein
• 1 Hendrik Heuer
• 1 IvicaJovic
• 1 Jan Hendrik Metzen
• 1 Jean Michel Rouly

92 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• 1 Eduardo Ariño de la Rubia


• 1 Jelle Zijlstra
• 1 Eddy L O Jansson
• 1 Denis
• 1 John
• 1 John Schmidt
• 1 Jorge Cañardo Alastuey
• 1 Joseph Perla
• 1 Joshua Vredevoogd
• 1 José Ricardo
• 1 Julien Miotte
• 1 Kemal Eren
• 1 Kenta Sato
• 1 David Cournapeau
• 1 Kyle Kelley
• 1 Daniele Medri
• 1 Laurent Luce
• 1 Laurent Pierron
• 1 Luis Pedro Coelho
• 1 DanielWeitzenfeld
• 1 Craig Thompson
• 1 Chyi-Kwei Yau
• 1 Matthew Brett
• 1 Matthias Feurer
• 1 Max Linke
• 1 Chris Filo Gorgolewski
• 1 Charles Earl
• 1 Michael Hanke
• 1 Michele Orrù
• 1 Bryan Lunt
• 1 Brian Kearns
• 1 Paul Butler
• 1 Paweł Mandera
• 1 Peter
• 1 Andrew Ash
• 1 Pietro Zambelli

1.15. Previous Releases 93


scikit-learn user guide, Release 0.20.3

• 1 staubda

1.15.11 Version 0.14

August 7, 2013

Changelog

• Missing values with sparse and dense matrices can be imputed with the transformer preprocessing.
Imputer by Nicolas Trésegnie.
• The core implementation of decisions trees has been rewritten from scratch, allowing for faster tree induction
and lower memory consumption in all tree-based estimators. By Gilles Louppe.
• Added ensemble.AdaBoostClassifier and ensemble.AdaBoostRegressor, by Noel Dawe and
Gilles Louppe. See the AdaBoost section of the user guide for details and examples.
• Added grid_search.RandomizedSearchCV and grid_search.ParameterSampler for random-
ized hyperparameter optimization. By Andreas Müller.
• Added biclustering algorithms (sklearn.cluster.bicluster.SpectralCoclustering and
sklearn.cluster.bicluster.SpectralBiclustering), data generation methods (sklearn.
datasets.make_biclusters and sklearn.datasets.make_checkerboard), and scoring met-
rics (sklearn.metrics.consensus_score). By Kemal Eren.
• Added Restricted Boltzmann Machines (neural_network.BernoulliRBM ). By Yann Dauphin.
• Python 3 support by Justin Vincent, Lars Buitinck, Subhodeep Moitra and Olivier Grisel. All tests now pass
under Python 3.3.
• Ability to pass one penalty (alpha value) per target in linear_model.Ridge, by @eickenberg and Mathieu
Blondel.
• Fixed sklearn.linear_model.stochastic_gradient.py L2 regularization issue (minor practical
significance). By Norbert Crombach and Mathieu Blondel .
• Added an interactive version of Andreas Müller’s Machine Learning Cheat Sheet (for scikit-learn) to the docu-
mentation. See Choosing the right estimator. By Jaques Grobler.
• grid_search.GridSearchCV and cross_validation.cross_val_score now support the use
of advanced scoring function such as area under the ROC curve and f-beta scores. See The scoring parameter:
defining model evaluation rules for details. By Andreas Müller and Lars Buitinck. Passing a function from
sklearn.metrics as score_func is deprecated.
• Multi-label classification output is now supported by metrics.accuracy_score,
metrics.zero_one_loss, metrics.f1_score, metrics.fbeta_score, metrics.
classification_report, metrics.precision_score and metrics.recall_score by
Arnaud Joly.
• Two new metrics metrics.hamming_loss and metrics.jaccard_similarity_score are added
with multi-label support by Arnaud Joly.
• Speed and memory usage improvements in feature_extraction.text.CountVectorizer and
feature_extraction.text.TfidfVectorizer, by Jochen Wersdörfer and Roman Sinayev.
• The min_df parameter in feature_extraction.text.CountVectorizer and
feature_extraction.text.TfidfVectorizer, which used to be 2, has been reset to 1 to
avoid unpleasant surprises (empty vocabularies) for novice users who try it out on tiny document collections. A
value of at least 2 is still recommended for practical use.

94 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• svm.LinearSVC, linear_model.SGDClassifier and linear_model.SGDRegressor now


have a sparsify method that converts their coef_ into a sparse matrix, meaning stored models trained
using these estimators can be made much more compact.
• linear_model.SGDClassifier now produces multiclass probability estimates when trained under log
loss or modified Huber loss.
• Hyperlinks to documentation in example code on the website by Martin Luessi.
• Fixed bug in preprocessing.MinMaxScaler causing incorrect scaling of the features for non-default
feature_range settings. By Andreas Müller.
• max_features in tree.DecisionTreeClassifier, tree.DecisionTreeRegressor and all
derived ensemble estimators now supports percentage values. By Gilles Louppe.
• Performance improvements in isotonic.IsotonicRegression by Nelle Varoquaux.
• metrics.accuracy_score has an option normalize to return the fraction or the number of correctly clas-
sified sample by Arnaud Joly.
• Added metrics.log_loss that computes log loss, aka cross-entropy loss. By Jochen Wersdörfer and Lars
Buitinck.
• A bug that caused ensemble.AdaBoostClassifier’s to output incorrect probabilities has been fixed.
• Feature selectors now share a mixin providing consistent transform, inverse_transform and
get_support methods. By Joel Nothman.
• A fitted grid_search.GridSearchCV or grid_search.RandomizedSearchCV can now generally
be pickled. By Joel Nothman.
• Refactored and vectorized implementation of metrics.roc_curve and metrics.
precision_recall_curve. By Joel Nothman.
• The new estimator sklearn.decomposition.TruncatedSVD performs dimensionality reduction using
SVD on sparse matrices, and can be used for latent semantic analysis (LSA). By Lars Buitinck.
• Added self-contained example of out-of-core learning on text data Out-of-core classification of text documents.
By Eustache Diemert.
• The default number of components for sklearn.decomposition.RandomizedPCA is now correctly
documented to be n_features. This was the default behavior, so programs using it will continue to work as
they did.
• sklearn.cluster.KMeans now fits several orders of magnitude faster on sparse data (the speedup depends
on the sparsity). By Lars Buitinck.
• Reduce memory footprint of FastICA by Denis Engemann and Alexandre Gramfort.
• Verbose output in sklearn.ensemble.gradient_boosting now uses a column format and prints
progress in decreasing frequency. It also shows the remaining time. By Peter Prettenhofer.
• sklearn.ensemble.gradient_boosting provides out-of-bag improvement oob_improvement_
rather than the OOB score for model selection. An example that shows how to use OOB estimates to select the
number of trees was added. By Peter Prettenhofer.
• Most metrics now support string labels for multiclass classification by Arnaud Joly and Lars Buitinck.
• New OrthogonalMatchingPursuitCV class by Alexandre Gramfort and Vlad Niculae.
• Fixed a bug in sklearn.covariance.GraphLassoCV : the ‘alphas’ parameter now works as expected
when given a list of values. By Philippe Gervais.

1.15. Previous Releases 95


scikit-learn user guide, Release 0.20.3

• Fixed an important bug in sklearn.covariance.GraphLassoCV that prevented all folds provided by


a CV object to be used (only the first 3 were used). When providing a CV object, execution time may thus
increase significantly compared to the previous version (bug results are correct now). By Philippe Gervais.
• cross_validation.cross_val_score and the grid_search module is now tested with multi-
output data by Arnaud Joly.
• datasets.make_multilabel_classification can now return the output in label indicator multil-
abel format by Arnaud Joly.
• K-nearest neighbors, neighbors.KNeighborsRegressor and neighbors.
RadiusNeighborsRegressor, and radius neighbors, neighbors.RadiusNeighborsRegressor
and neighbors.RadiusNeighborsClassifier support multioutput data by Arnaud Joly.
• Random state in LibSVM-based estimators (svm.SVC, NuSVC, OneClassSVM, svm.SVR, svm.NuSVR)
can now be controlled. This is useful to ensure consistency in the probability estimates for the classifiers trained
with probability=True. By Vlad Niculae.
• Out-of-core learning support for discrete naive Bayes classifiers sklearn.naive_bayes.
MultinomialNB and sklearn.naive_bayes.BernoulliNB by adding the partial_fit
method by Olivier Grisel.
• New website design and navigation by Gilles Louppe, Nelle Varoquaux, Vincent Michel and Andreas Müller.
• Improved documentation on multi-class, multi-label and multi-output classification by Yannick Schwartz and
Arnaud Joly.
• Better input and error handling in the metrics module by Arnaud Joly and Joel Nothman.
• Speed optimization of the hmm module by Mikhail Korobov
• Significant speed improvements for sklearn.cluster.DBSCAN by cleverless

API changes summary

• The auc_score was renamed roc_auc_score.


• Testing scikit-learn with sklearn.test() is deprecated. Use nosetests sklearn from the command
line.
• Feature importances in tree.DecisionTreeClassifier, tree.DecisionTreeRegressor and all
derived ensemble estimators are now computed on the fly when accessing the feature_importances_
attribute. Setting compute_importances=True is no longer required. By Gilles Louppe.
• linear_model.lasso_path and linear_model.enet_path can return its results in the same format
as that of linear_model.lars_path. This is done by setting the return_models parameter to False.
By Jaques Grobler and Alexandre Gramfort
• grid_search.IterGrid was renamed to grid_search.ParameterGrid.
• Fixed bug in KFold causing imperfect class balance in some cases. By Alexandre Gramfort and Tadej Janež.
• sklearn.neighbors.BallTree has been refactored, and a sklearn.neighbors.KDTree has been
added which shares the same interface. The Ball Tree now works with a wide variety of distance metrics.
Both classes have many new methods, including single-tree and dual-tree queries, breadth-first and depth-first
searching, and more advanced queries such as kernel density estimation and 2-point correlation functions. By
Jake Vanderplas
• Support for scipy.spatial.cKDTree within neighbors queries has been removed, and the functionality replaced
with the new KDTree class.

96 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• sklearn.neighbors.KernelDensity has been added, which performs efficient kernel density estima-
tion with a variety of kernels.
• sklearn.decomposition.KernelPCA now always returns output with n_components components,
unless the new parameter remove_zero_eig is set to True. This new behavior is consistent with the way
kernel PCA was always documented; previously, the removal of components with zero eigenvalues was tacitly
performed on all data.
• gcv_mode="auto" no longer tries to perform SVD on a densified sparse matrix in sklearn.
linear_model.RidgeCV .
• Sparse matrix support in sklearn.decomposition.RandomizedPCA is now deprecated in favor of the
new TruncatedSVD.
• cross_validation.KFold and cross_validation.StratifiedKFold now enforce n_folds >=
2 otherwise a ValueError is raised. By Olivier Grisel.
• datasets.load_files’s charset and charset_errors parameters were renamed encoding and
decode_errors.
• Attribute oob_score_ in sklearn.ensemble.GradientBoostingRegressor and
sklearn.ensemble.GradientBoostingClassifier is deprecated and has been replaced by
oob_improvement_ .
• Attributes in OrthogonalMatchingPursuit have been deprecated (copy_X, Gram, . . . ) and precompute_gram
renamed precompute for consistency. See #2224.
• sklearn.preprocessing.StandardScaler now converts integer input to float, and raises a warning.
Previously it rounded for dense integer input.
• sklearn.multiclass.OneVsRestClassifier now has a decision_function method. This
will return the distance of each sample from the decision boundary for each class, as long as the underlying
estimators implement the decision_function method. By Kyle Kastner.
• Better input validation, warning on unexpected shapes for y.

People

List of contributors for release 0.14 by number of commits.


• 277 Gilles Louppe
• 245 Lars Buitinck
• 187 Andreas Mueller
• 124 Arnaud Joly
• 112 Jaques Grobler
• 109 Gael Varoquaux
• 107 Olivier Grisel
• 102 Noel Dawe
• 99 Kemal Eren
• 79 Joel Nothman
• 75 Jake VanderPlas
• 73 Nelle Varoquaux
• 71 Vlad Niculae

1.15. Previous Releases 97


scikit-learn user guide, Release 0.20.3

• 65 Peter Prettenhofer
• 64 Alexandre Gramfort
• 54 Mathieu Blondel
• 38 Nicolas Trésegnie
• 35 eustache
• 27 Denis Engemann
• 25 Yann N. Dauphin
• 19 Justin Vincent
• 17 Robert Layton
• 15 Doug Coleman
• 14 Michael Eickenberg
• 13 Robert Marchman
• 11 Fabian Pedregosa
• 11 Philippe Gervais
• 10 Jim Holmström
• 10 Tadej Janež
• 10 syhw
• 9 Mikhail Korobov
• 9 Steven De Gryze
• 8 sergeyf
• 7 Ben Root
• 7 Hrishikesh Huilgolkar
• 6 Kyle Kastner
• 6 Martin Luessi
• 6 Rob Speer
• 5 Federico Vaggi
• 5 Raul Garreta
• 5 Rob Zinkov
• 4 Ken Geis
• 3 A. Flaxman
• 3 Denton Cockburn
• 3 Dougal Sutherland
• 3 Ian Ozsvald
• 3 Johannes Schönberger
• 3 Robert McGibbon
• 3 Roman Sinayev

98 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• 3 Szabo Roland
• 2 Diego Molla
• 2 Imran Haque
• 2 Jochen Wersdörfer
• 2 Sergey Karayev
• 2 Yannick Schwartz
• 2 jamestwebber
• 1 Abhijeet Kolhe
• 1 Alexander Fabisch
• 1 Bastiaan van den Berg
• 1 Benjamin Peterson
• 1 Daniel Velkov
• 1 Fazlul Shahriar
• 1 Felix Brockherde
• 1 Félix-Antoine Fortin
• 1 Harikrishnan S
• 1 Jack Hale
• 1 JakeMick
• 1 James McDermott
• 1 John Benediktsson
• 1 John Zwinck
• 1 Joshua Vredevoogd
• 1 Justin Pati
• 1 Kevin Hughes
• 1 Kyle Kelley
• 1 Matthias Ekman
• 1 Miroslav Shubernetskiy
• 1 Naoki Orii
• 1 Norbert Crombach
• 1 Rafael Cunha de Almeida
• 1 Rolando Espinoza La fuente
• 1 Seamus Abshere
• 1 Sergey Feldman
• 1 Sergio Medina
• 1 Stefano Lattarini
• 1 Steve Koch

1.15. Previous Releases 99


scikit-learn user guide, Release 0.20.3

• 1 Sturla Molden
• 1 Thomas Jarosch
• 1 Yaroslav Halchenko

1.15.12 Version 0.13.1

February 23, 2013


The 0.13.1 release only fixes some bugs and does not add any new functionality.

Changelog

• Fixed a testing error caused by the function cross_validation.train_test_split being interpreted


as a test by Yaroslav Halchenko.
• Fixed a bug in the reassignment of small clusters in the cluster.MiniBatchKMeans by Gael Varoquaux.
• Fixed default value of gamma in decomposition.KernelPCA by Lars Buitinck.
• Updated joblib to 0.7.0d by Gael Varoquaux.
• Fixed scaling of the deviance in ensemble.GradientBoostingClassifier by Peter Prettenhofer.
• Better tie-breaking in multiclass.OneVsOneClassifier by Andreas Müller.
• Other small improvements to tests and documentation.

People

List of contributors for release 0.13.1 by number of commits.


• 16 Lars Buitinck
• 12 Andreas Müller
• 8 Gael Varoquaux
• 5 Robert Marchman
• 3 Peter Prettenhofer
• 2 Hrishikesh Huilgolkar
• 1 Bastiaan van den Berg
• 1 Diego Molla
• 1 Gilles Louppe
• 1 Mathieu Blondel
• 1 Nelle Varoquaux
• 1 Rafael Cunha de Almeida
• 1 Rolando Espinoza La fuente
• 1 Vlad Niculae
• 1 Yaroslav Halchenko

100 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

1.15.13 Version 0.13

January 21, 2013

New Estimator Classes

• dummy.DummyClassifier and dummy.DummyRegressor, two data-independent predictors by Mathieu


Blondel. Useful to sanity-check your estimators. See Dummy estimators in the user guide. Multioutput support
added by Arnaud Joly.
• decomposition.FactorAnalysis, a transformer implementing the classical factor analysis, by Chris-
tian Osendorfer and Alexandre Gramfort. See Factor Analysis in the user guide.
• feature_extraction.FeatureHasher, a transformer implementing the “hashing trick” for fast,
low-memory feature extraction from string fields by Lars Buitinck and feature_extraction.text.
HashingVectorizer for text documents by Olivier Grisel See Feature hashing and Vectorizing a large
text corpus with the hashing trick for the documentation and sample usage.
• pipeline.FeatureUnion, a transformer that concatenates results of several other transformers by Andreas
Müller. See FeatureUnion: composite feature spaces in the user guide.
• random_projection.GaussianRandomProjection, random_projection.
SparseRandomProjection and the function random_projection.
johnson_lindenstrauss_min_dim. The first two are transformers implementing Gaussian and
sparse random projection matrix by Olivier Grisel and Arnaud Joly. See Random Projection in the user guide.
• kernel_approximation.Nystroem, a transformer for approximating arbitrary kernels by Andreas
Müller. See Nystroem Method for Kernel Approximation in the user guide.
• preprocessing.OneHotEncoder, a transformer that computes binary encodings of categorical features
by Andreas Müller. See Encoding categorical features in the user guide.
• linear_model.PassiveAggressiveClassifier and linear_model.
PassiveAggressiveRegressor, predictors implementing an efficient stochastic optimization for
linear models by Rob Zinkov and Mathieu Blondel. See Passive Aggressive Algorithms in the user guide.
• ensemble.RandomTreesEmbedding, a transformer for creating high-dimensional sparse representations
using ensembles of totally random trees by Andreas Müller. See Totally Random Trees Embedding in the user
guide.
• manifold.SpectralEmbedding and function manifold.spectral_embedding, implementing
the “laplacian eigenmaps” transformation for non-linear dimensionality reduction by Wei Li. See Spectral
Embedding in the user guide.
• isotonic.IsotonicRegression by Fabian Pedregosa, Alexandre Gramfort and Nelle Varoquaux,

Changelog

• metrics.zero_one_loss (formerly metrics.zero_one) now has option for normalized output that
reports the fraction of misclassifications, rather than the raw number of misclassifications. By Kyle Beauchamp.
• tree.DecisionTreeClassifier and all derived ensemble models now support sample weighting, by
Noel Dawe and Gilles Louppe.
• Speedup improvement when using bootstrap samples in forests of randomized trees, by Peter Prettenhofer and
Gilles Louppe.
• Partial dependence plots for Gradient Tree Boosting in ensemble.partial_dependence.
partial_dependence by Peter Prettenhofer. See Partial Dependence Plots for an example.

1.15. Previous Releases 101


scikit-learn user guide, Release 0.20.3

• The table of contents on the website has now been made expandable by Jaques Grobler.
• feature_selection.SelectPercentile now breaks ties deterministically instead of returning all
equally ranked features.
• feature_selection.SelectKBest and feature_selection.SelectPercentile are more
numerically stable since they use scores, rather than p-values, to rank results. This means that they might
sometimes select different features than they did previously.
• Ridge regression and ridge classification fitting with sparse_cg solver no longer has quadratic memory com-
plexity, by Lars Buitinck and Fabian Pedregosa.
• Ridge regression and ridge classification now support a new fast solver called lsqr, by Mathieu Blondel.
• Speed up of metrics.precision_recall_curve by Conrad Lee.
• Added support for reading/writing svmlight files with pairwise preference attribute (qid in svmlight file format)
in datasets.dump_svmlight_file and datasets.load_svmlight_file by Fabian Pedregosa.
• Faster and more robust metrics.confusion_matrix and Clustering performance evaluation by Wei Li.
• cross_validation.cross_val_score now works with precomputed kernels and affinity matrices, by
Andreas Müller.
• LARS algorithm made more numerically stable with heuristics to drop regressors too correlated as well as to
stop the path when numerical noise becomes predominant, by Gael Varoquaux.
• Faster implementation of metrics.precision_recall_curve by Conrad Lee.
• New kernel metrics.chi2_kernel by Andreas Müller, often used in computer vision applications.
• Fix of longstanding bug in naive_bayes.BernoulliNB fixed by Shaun Jackman.
• Implemented predict_proba in multiclass.OneVsRestClassifier, by Andrew Winterman.
• Improve consistency in gradient boosting: estimators ensemble.GradientBoostingRegressor and
ensemble.GradientBoostingClassifier use the estimator tree.DecisionTreeRegressor
instead of the tree._tree.Tree data structure by Arnaud Joly.
• Fixed a floating point exception in the decision trees module, by Seberg.
• Fix metrics.roc_curve fails when y_true has only one class by Wei Li.
• Add the metrics.mean_absolute_error function which computes the mean absolute error. The
metrics.mean_squared_error, metrics.mean_absolute_error and metrics.r2_score
metrics support multioutput by Arnaud Joly.
• Fixed class_weight support in svm.LinearSVC and linear_model.LogisticRegression by
Andreas Müller. The meaning of class_weight was reversed as erroneously higher weight meant less
positives of a given class in earlier releases.
• Improve narrative documentation and consistency in sklearn.metrics for regression and classification
metrics by Arnaud Joly.
• Fixed a bug in sklearn.svm.SVC when using csr-matrices with unsorted indices by Xinfan Meng and An-
dreas Müller.
• MiniBatchKMeans: Add random reassignment of cluster centers with little observations attached to them,
by Gael Varoquaux.

API changes summary

• Renamed all occurrences of n_atoms to n_components for consistency.


This applies to decomposition.DictionaryLearning, decomposition.

102 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

MiniBatchDictionaryLearning, decomposition.dict_learning, decomposition.


dict_learning_online.
• Renamed all occurrences of max_iters to max_iter for consistency. This applies to
semi_supervised.LabelPropagation and semi_supervised.label_propagation.
LabelSpreading.
• Renamed all occurrences of learn_rate to learning_rate for consistency in ensemble.
BaseGradientBoosting and ensemble.GradientBoostingRegressor.
• The module sklearn.linear_model.sparse is gone. Sparse matrix support was already integrated into
the “regular” linear models.
• sklearn.metrics.mean_square_error, which incorrectly returned the accumulated error, was re-
moved. Use mean_squared_error instead.
• Passing class_weight parameters to fit methods is no longer supported. Pass them to estimator construc-
tors instead.
• GMMs no longer have decode and rvs methods. Use the score, predict or sample methods instead.
• The solver fit option in Ridge regression and classification is now deprecated and will be removed in v0.14.
Use the constructor option instead.
• feature_extraction.text.DictVectorizer now returns sparse matrices in the CSR format, in-
stead of COO.
• Renamed k in cross_validation.KFold and cross_validation.StratifiedKFold to
n_folds, renamed n_bootstraps to n_iter in cross_validation.Bootstrap.
• Renamed all occurrences of n_iterations to n_iter for consistency. This applies to
cross_validation.ShuffleSplit, cross_validation.StratifiedShuffleSplit,
utils.randomized_range_finder and utils.randomized_svd.
• Replaced rho in linear_model.ElasticNet and linear_model.SGDClassifier by
l1_ratio. The rho parameter had different meanings; l1_ratio was introduced to avoid confu-
sion. It has the same meaning as previously rho in linear_model.ElasticNet and (1-rho) in
linear_model.SGDClassifier.
• linear_model.LassoLars and linear_model.Lars now store a list of paths in the case of multiple
targets, rather than an array of paths.
• The attribute gmm of hmm.GMMHMM was renamed to gmm_ to adhere more strictly with the API.
• cluster.spectral_embedding was moved to manifold.spectral_embedding.
• Renamed eig_tol in manifold.spectral_embedding, cluster.SpectralClustering to
eigen_tol, renamed mode to eigen_solver.
• Renamed mode in manifold.spectral_embedding and cluster.SpectralClustering to
eigen_solver.
• classes_ and n_classes_ attributes of tree.DecisionTreeClassifier and all derived ensemble
models are now flat in case of single output problems and nested in case of multi-output problems.
• The estimators_ attribute of ensemble.gradient_boosting.GradientBoostingRegressor
and ensemble.gradient_boosting.GradientBoostingClassifier is now an array of
:class:’tree.DecisionTreeRegressor’.
• Renamed chunk_size to batch_size in decomposition.MiniBatchDictionaryLearning
and decomposition.MiniBatchSparsePCA for consistency.
• svm.SVC and svm.NuSVC now provide a classes_ attribute and support arbitrary dtypes for labels y.
Also, the dtype returned by predict now reflects the dtype of y during fit (used to be np.float).

1.15. Previous Releases 103


scikit-learn user guide, Release 0.20.3

• Changed default test_size in cross_validation.train_test_split to None, added pos-


sibility to infer test_size from train_size in cross_validation.ShuffleSplit and
cross_validation.StratifiedShuffleSplit.
• Renamed function sklearn.metrics.zero_one to sklearn.metrics.zero_one_loss. Be
aware that the default behavior in sklearn.metrics.zero_one_loss is different from sklearn.
metrics.zero_one: normalize=False is changed to normalize=True.
• Renamed function metrics.zero_one_score to metrics.accuracy_score.
• datasets.make_circles now has the same number of inner and outer points.
• In the Naive Bayes classifiers, the class_prior parameter was moved from fit to __init__.

People

List of contributors for release 0.13 by number of commits.


• 364 Andreas Müller
• 143 Arnaud Joly
• 137 Peter Prettenhofer
• 131 Gael Varoquaux
• 117 Mathieu Blondel
• 108 Lars Buitinck
• 106 Wei Li
• 101 Olivier Grisel
• 65 Vlad Niculae
• 54 Gilles Louppe
• 40 Jaques Grobler
• 38 Alexandre Gramfort
• 30 Rob Zinkov
• 19 Aymeric Masurelle
• 18 Andrew Winterman
• 17 Fabian Pedregosa
• 17 Nelle Varoquaux
• 16 Christian Osendorfer
• 14 Daniel Nouri
• 13 Virgile Fritsch
• 13 syhw
• 12 Satrajit Ghosh
• 10 Corey Lynch
• 10 Kyle Beauchamp
• 9 Brian Cheung

104 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• 9 Immanuel Bayer
• 9 mr.Shu
• 8 Conrad Lee
• 8 James Bergstra
• 7 Tadej Janež
• 6 Brian Cajes
• 6 Jake Vanderplas
• 6 Michael
• 6 Noel Dawe
• 6 Tiago Nunes
• 6 cow
• 5 Anze
• 5 Shiqiao Du
• 4 Christian Jauvin
• 4 Jacques Kvam
• 4 Richard T. Guy
• 4 Robert Layton
• 3 Alexandre Abraham
• 3 Doug Coleman
• 3 Scott Dickerson
• 2 ApproximateIdentity
• 2 John Benediktsson
• 2 Mark Veronda
• 2 Matti Lyra
• 2 Mikhail Korobov
• 2 Xinfan Meng
• 1 Alejandro Weinstein
• 1 Alexandre Passos
• 1 Christoph Deil
• 1 Eugene Nizhibitsky
• 1 Kenneth C. Arnold
• 1 Luis Pedro Coelho
• 1 Miroslav Batchkarov
• 1 Pavel
• 1 Sebastian Berg
• 1 Shaun Jackman

1.15. Previous Releases 105


scikit-learn user guide, Release 0.20.3

• 1 Subhodeep Moitra
• 1 bob
• 1 dengemann
• 1 emanuele
• 1 x006

1.15.14 Version 0.12.1

October 8, 2012
The 0.12.1 release is a bug-fix release with no additional features, but is instead a set of bug fixes

Changelog

• Improved numerical stability in spectral embedding by Gael Varoquaux


• Doctest under windows 64bit by Gael Varoquaux
• Documentation fixes for elastic net by Andreas Müller and Alexandre Gramfort
• Proper behavior with fortran-ordered NumPy arrays by Gael Varoquaux
• Make GridSearchCV work with non-CSR sparse matrix by Lars Buitinck
• Fix parallel computing in MDS by Gael Varoquaux
• Fix Unicode support in count vectorizer by Andreas Müller
• Fix MinCovDet breaking with X.shape = (3, 1) by Virgile Fritsch
• Fix clone of SGD objects by Peter Prettenhofer
• Stabilize GMM by Virgile Fritsch

People

• 14 Peter Prettenhofer
• 12 Gael Varoquaux
• 10 Andreas Müller
• 5 Lars Buitinck
• 3 Virgile Fritsch
• 1 Alexandre Gramfort
• 1 Gilles Louppe
• 1 Mathieu Blondel

1.15.15 Version 0.12

September 4, 2012

106 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

Changelog

• Various speed improvements of the decision trees module, by Gilles Louppe.


• ensemble.GradientBoostingRegressor and ensemble.GradientBoostingClassifier
now support feature subsampling via the max_features argument, by Peter Prettenhofer.
• Added Huber and Quantile loss functions to ensemble.GradientBoostingRegressor, by Peter Pret-
tenhofer.
• Decision trees and forests of randomized trees now support multi-output classification and regression problems,
by Gilles Louppe.
• Added preprocessing.LabelEncoder, a simple utility class to normalize labels or transform non-
numerical labels, by Mathieu Blondel.
• Added the epsilon-insensitive loss and the ability to make probabilistic predictions with the modified huber loss
in Stochastic Gradient Descent, by Mathieu Blondel.
• Added Multi-dimensional Scaling (MDS), by Nelle Varoquaux.
• SVMlight file format loader now detects compressed (gzip/bzip2) files and decompresses them on the fly, by
Lars Buitinck.
• SVMlight file format serializer now preserves double precision floating point values, by Olivier Grisel.
• A common testing framework for all estimators was added, by Andreas Müller.
• Understandable error messages for estimators that do not accept sparse input by Gael Varoquaux
• Speedups in hierarchical clustering by Gael Varoquaux. In particular building the tree now supports early
stopping. This is useful when the number of clusters is not small compared to the number of samples.
• Add MultiTaskLasso and MultiTaskElasticNet for joint feature selection, by Alexandre Gramfort.
• Added metrics.auc_score and metrics.average_precision_score convenience functions by
Andreas Müller.
• Improved sparse matrix support in the Feature selection module by Andreas Müller.
• New word boundaries-aware character n-gram analyzer for the Text feature extraction module by @kernc.
• Fixed bug in spectral clustering that led to single point clusters by Andreas Müller.
• In feature_extraction.text.CountVectorizer, added an option to ignore infrequent words,
min_df by Andreas Müller.
• Add support for multiple targets in some linear models (ElasticNet, Lasso and OrthogonalMatchingPursuit) by
Vlad Niculae and Alexandre Gramfort.
• Fixes in decomposition.ProbabilisticPCA score function by Wei Li.
• Fixed feature importance computation in Gradient Tree Boosting.

API changes summary

• The old scikits.learn package has disappeared; all code should import from sklearn instead, which
was introduced in 0.9.
• In metrics.roc_curve, the thresholds array is now returned with it’s order reversed, in order to keep
it consistent with the order of the returned fpr and tpr.
• In hmm objects, like hmm.GaussianHMM, hmm.MultinomialHMM, etc., all parameters must be passed to
the object when initialising it and not through fit. Now fit will only accept the data as an input parameter.

1.15. Previous Releases 107


scikit-learn user guide, Release 0.20.3

• For all SVM classes, a faulty behavior of gamma was fixed. Previously, the default gamma value was only
computed the first time fit was called and then stored. It is now recalculated on every call to fit.
• All Base classes are now abstract meta classes so that they can not be instantiated.
• cluster.ward_tree now also returns the parent array. This is necessary for early-stopping in which case
the tree is not completely built.
• In feature_extraction.text.CountVectorizer the parameters min_n and max_n were joined to
the parameter n_gram_range to enable grid-searching both at once.
• In feature_extraction.text.CountVectorizer, words that appear only in one document are now
ignored by default. To reproduce the previous behavior, set min_df=1.
• Fixed API inconsistency: linear_model.SGDClassifier.predict_proba now returns 2d array
when fit on two classes.
• Fixed API inconsistency: discriminant_analysis.QuadraticDiscriminantAnalysis.
decision_function and discriminant_analysis.LinearDiscriminantAnalysis.
decision_function now return 1d arrays when fit on two classes.
• Grid of alphas used for fitting linear_model.LassoCV and linear_model.ElasticNetCV is now
stored in the attribute alphas_ rather than overriding the init parameter alphas.
• Linear models when alpha is estimated by cross-validation store the estimated value in the alpha_ attribute
rather than just alpha or best_alpha.
• ensemble.GradientBoostingClassifier now supports ensemble.
GradientBoostingClassifier.staged_predict_proba, and ensemble.
GradientBoostingClassifier.staged_predict.
• svm.sparse.SVC and other sparse SVM classes are now deprecated. The all classes in the Support Vector
Machines module now automatically select the sparse or dense representation base on the input.
• All clustering algorithms now interpret the array X given to fit as input data, in particular cluster.
SpectralClustering and cluster.AffinityPropagation which previously expected affinity ma-
trices.
• For clustering algorithms that take the desired number of clusters as a parameter, this parameter is now called
n_clusters.

People

• 267 Andreas Müller


• 94 Gilles Louppe
• 89 Gael Varoquaux
• 79 Peter Prettenhofer
• 60 Mathieu Blondel
• 57 Alexandre Gramfort
• 52 Vlad Niculae
• 45 Lars Buitinck
• 44 Nelle Varoquaux
• 37 Jaques Grobler
• 30 Alexis Mignon

108 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• 30 Immanuel Bayer
• 27 Olivier Grisel
• 16 Subhodeep Moitra
• 13 Yannick Schwartz
• 12 @kernc
• 11 Virgile Fritsch
• 9 Daniel Duckworth
• 9 Fabian Pedregosa
• 9 Robert Layton
• 8 John Benediktsson
• 7 Marko Burjek
• 5 Nicolas Pinto
• 4 Alexandre Abraham
• 4 Jake Vanderplas
• 3 Brian Holt
• 3 Edouard Duchesnay
• 3 Florian Hoenig
• 3 flyingimmidev
• 2 Francois Savard
• 2 Hannes Schulz
• 2 Peter Welinder
• 2 Yaroslav Halchenko
• 2 Wei Li
• 1 Alex Companioni
• 1 Brandyn A. White
• 1 Bussonnier Matthias
• 1 Charles-Pierre Astolfi
• 1 Dan O’Huiginn
• 1 David Cournapeau
• 1 Keith Goodman
• 1 Ludwig Schwardt
• 1 Olivier Hervieu
• 1 Sergio Medina
• 1 Shiqiao Du
• 1 Tim Sheerman-Chase
• 1 buguen

1.15. Previous Releases 109


scikit-learn user guide, Release 0.20.3

1.15.16 Version 0.11

May 7, 2012

Changelog

Highlights

• Gradient boosted regression trees (Gradient Tree Boosting) for classification and regression by Peter Pretten-
hofer and Scott White .
• Simple dict-based feature loader with support for categorical variables (feature_extraction.
DictVectorizer) by Lars Buitinck.
• Added Matthews correlation coefficient (metrics.matthews_corrcoef) and added macro and micro av-
erage options to metrics.precision_score, metrics.recall_score and metrics.f1_score
by Satrajit Ghosh.
• Out of Bag Estimates of generalization error for Ensemble methods by Andreas Müller.
• Randomized sparse linear models for feature selection, by Alexandre Gramfort and Gael Varoquaux
• Label Propagation for semi-supervised learning, by Clay Woolam. Note the semi-supervised API is still work
in progress, and may change.
• Added BIC/AIC model selection to classical Gaussian mixture models and unified the API with the remainder
of scikit-learn, by Bertrand Thirion
• Added sklearn.cross_validation.StratifiedShuffleSplit, which is a sklearn.
cross_validation.ShuffleSplit with balanced splits, by Yannick Schwartz.
• sklearn.neighbors.NearestCentroid classifier added, along with a shrink_threshold param-
eter, which implements shrunken centroid classification, by Robert Layton.

Other changes

• Merged dense and sparse implementations of Stochastic Gradient Descent module and exposed utility extension
types for sequential datasets seq_dataset and weight vectors weight_vector by Peter Prettenhofer.
• Added partial_fit (support for online/minibatch learning) and warm_start to the Stochastic Gradient De-
scent module by Mathieu Blondel.
• Dense and sparse implementations of Support Vector Machines classes and linear_model.
LogisticRegression merged by Lars Buitinck.
• Regressors can now be used as base estimator in the Multiclass and multilabel algorithms module by Mathieu
Blondel.
• Added n_jobs option to metrics.pairwise.pairwise_distances and metrics.pairwise.
pairwise_kernels for parallel computation, by Mathieu Blondel.
• K-means can now be run in parallel, using the n_jobs argument to either K-means or KMeans, by Robert
Layton.
• Improved Cross-validation: evaluating estimator performance and Tuning the hyper-parameters of an estima-
tor documentation and introduced the new cross_validation.train_test_split helper function by
Olivier Grisel

110 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• svm.SVC members coef_ and intercept_ changed sign for consistency with decision_function;
for kernel==linear, coef_ was fixed in the one-vs-one case, by Andreas Müller.
• Performance improvements to efficient leave-one-out cross-validated Ridge regression, esp. for the
n_samples > n_features case, in linear_model.RidgeCV , by Reuben Fletcher-Costin.
• Refactoring and simplification of the Text feature extraction API and fixed a bug that caused possible negative
IDF, by Olivier Grisel.
• Beam pruning option in _BaseHMM module has been removed since it is difficult to Cythonize. If you are
interested in contributing a Cython version, you can use the python version in the git history as a reference.
• Classes in Nearest Neighbors now support arbitrary Minkowski metric for nearest neighbors searches. The
metric can be specified by argument p.

API changes summary

• covariance.EllipticEnvelop is now deprecated - Please use covariance.EllipticEnvelope


instead.
• NeighborsClassifier and NeighborsRegressor are gone in the module Nearest Neighbors. Use
the classes KNeighborsClassifier, RadiusNeighborsClassifier, KNeighborsRegressor
and/or RadiusNeighborsRegressor instead.
• Sparse classes in the Stochastic Gradient Descent module are now deprecated.
• In mixture.GMM, mixture.DPGMM and mixture.VBGMM, parameters must be passed to an object when
initialising it and not through fit. Now fit will only accept the data as an input parameter.
• methods rvs and decode in GMM module are now deprecated. sample and score or predict should be
used instead.
• attribute _scores and _pvalues in univariate feature selection objects are now deprecated. scores_ or
pvalues_ should be used instead.
• In LogisticRegression, LinearSVC, SVC and NuSVC, the class_weight parameter is now an ini-
tialization parameter, not a parameter to fit. This makes grid searches over this parameter possible.
• LFW data is now always shape (n_samples, n_features) to be consistent with the Olivetti faces
dataset. Use images and pairs attribute to access the natural images shapes instead.
• In svm.LinearSVC, the meaning of the multi_class parameter changed. Options now are 'ovr' and
'crammer_singer', with 'ovr' being the default. This does not change the default behavior but hopefully
is less confusing.
• Class feature_selection.text.Vectorizer is deprecated and replaced by
feature_selection.text.TfidfVectorizer.
• The preprocessor / analyzer nested structure for text feature extraction has been removed. All those features are
now directly passed as flat constructor arguments to feature_selection.text.TfidfVectorizer
and feature_selection.text.CountVectorizer, in particular the following parameters are now
used:
• analyzer can be 'word' or 'char' to switch the default analysis scheme, or use a specific python callable
(as previously).
• tokenizer and preprocessor have been introduced to make it still possible to customize those steps with
the new API.
• input explicitly control how to interpret the sequence passed to fit and predict: filenames, file objects or
direct (byte or Unicode) strings.

1.15. Previous Releases 111


scikit-learn user guide, Release 0.20.3

• charset decoding is explicit and strict by default.


• the vocabulary, fitted or not is now stored in the vocabulary_ attribute to be consistent with the project
conventions.
• Class feature_selection.text.TfidfVectorizer now derives directly from
feature_selection.text.CountVectorizer to make grid search trivial.
• methods rvs in _BaseHMM module are now deprecated. sample should be used instead.
• Beam pruning option in _BaseHMM module is removed since it is difficult to be Cythonized. If you are inter-
ested, you can look in the history codes by git.
• The SVMlight format loader now supports files with both zero-based and one-based column indices, since both
occur “in the wild”.
• Arguments in class ShuffleSplit are now consistent with StratifiedShuffleSplit. Arguments
test_fraction and train_fraction are deprecated and renamed to test_size and train_size
and can accept both float and int.
• Arguments in class Bootstrap are now consistent with StratifiedShuffleSplit. Arguments
n_test and n_train are deprecated and renamed to test_size and train_size and can accept both
float and int.
• Argument p added to classes in Nearest Neighbors to specify an arbitrary Minkowski metric for nearest neigh-
bors searches.

People

• 282 Andreas Müller


• 239 Peter Prettenhofer
• 198 Gael Varoquaux
• 129 Olivier Grisel
• 114 Mathieu Blondel
• 103 Clay Woolam
• 96 Lars Buitinck
• 88 Jaques Grobler
• 82 Alexandre Gramfort
• 50 Bertrand Thirion
• 42 Robert Layton
• 28 flyingimmidev
• 26 Jake Vanderplas
• 26 Shiqiao Du
• 21 Satrajit Ghosh
• 17 David Marek
• 17 Gilles Louppe
• 14 Vlad Niculae
• 11 Yannick Schwartz

112 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• 10 Fabian Pedregosa
• 9 fcostin
• 7 Nick Wilson
• 5 Adrien Gaidon
• 5 Nicolas Pinto
• 4 David Warde-Farley
• 5 Nelle Varoquaux
• 5 Emmanuelle Gouillart
• 3 Joonas Sillanpää
• 3 Paolo Losi
• 2 Charles McCarthy
• 2 Roy Hyunjin Han
• 2 Scott White
• 2 ibayer
• 1 Brandyn White
• 1 Carlos Scheidegger
• 1 Claire Revillet
• 1 Conrad Lee
• 1 Edouard Duchesnay
• 1 Jan Hendrik Metzen
• 1 Meng Xinfan
• 1 Rob Zinkov
• 1 Shiqiao
• 1 Udi Weinsberg
• 1 Virgile Fritsch
• 1 Xinfan Meng
• 1 Yaroslav Halchenko
• 1 jansoe
• 1 Leon Palafox

1.15.17 Version 0.10

January 11, 2012

1.15. Previous Releases 113


scikit-learn user guide, Release 0.20.3

Changelog

• Python 2.5 compatibility was dropped; the minimum Python version needed to use scikit-learn is now 2.6.
• Sparse inverse covariance estimation using the graph Lasso, with associated cross-validated estimator, by Gael
Varoquaux
• New Tree module by Brian Holt, Peter Prettenhofer, Satrajit Ghosh and Gilles Louppe. The module comes with
complete documentation and examples.
• Fixed a bug in the RFE module by Gilles Louppe (issue #378).
• Fixed a memory leak in Support Vector Machines module by Brian Holt (issue #367).
• Faster tests by Fabian Pedregosa and others.
• Silhouette Coefficient cluster analysis evaluation metric added as sklearn.metrics.
silhouette_score by Robert Layton.
• Fixed a bug in K-means in the handling of the n_init parameter: the clustering algorithm used to be run
n_init times but the last solution was retained instead of the best solution by Olivier Grisel.
• Minor refactoring in Stochastic Gradient Descent module; consolidated dense and sparse predict methods; En-
hanced test time performance by converting model parameters to fortran-style arrays after fitting (only multi-
class).
• Adjusted Mutual Information metric added as sklearn.metrics.adjusted_mutual_info_score
by Robert Layton.
• Models like SVC/SVR/LinearSVC/LogisticRegression from libsvm/liblinear now support scaling of C regular-
ization parameter by the number of samples by Alexandre Gramfort.
• New Ensemble Methods module by Gilles Louppe and Brian Holt. The module comes with the random forest
algorithm and the extra-trees method, along with documentation and examples.
• Novelty and Outlier Detection: outlier and novelty detection, by Virgile Fritsch.
• Kernel Approximation: a transform implementing kernel approximation for fast SGD on non-linear kernels by
Andreas Müller.
• Fixed a bug due to atom swapping in Orthogonal Matching Pursuit (OMP) by Vlad Niculae.
• Sparse coding with a precomputed dictionary by Vlad Niculae.
• Mini Batch K-Means performance improvements by Olivier Grisel.
• K-means support for sparse matrices by Mathieu Blondel.
• Improved documentation for developers and for the sklearn.utils module, by Jake Vanderplas.
• Vectorized 20newsgroups dataset loader (sklearn.datasets.fetch_20newsgroups_vectorized)
by Mathieu Blondel.
• Multiclass and multilabel algorithms by Lars Buitinck.
• Utilities for fast computation of mean and variance for sparse matrices by Mathieu Blondel.
• Make sklearn.preprocessing.scale and sklearn.preprocessing.Scaler work on sparse
matrices by Olivier Grisel
• Feature importances using decision trees and/or forest of trees, by Gilles Louppe.
• Parallel implementation of forests of randomized trees by Gilles Louppe.
• sklearn.cross_validation.ShuffleSplit can subsample the train sets as well as the test sets by
Olivier Grisel.

114 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Errors in the build of the documentation fixed by Andreas Müller.

API changes summary

Here are the code migration instructions when upgrading from scikit-learn version 0.9:
• Some estimators that may overwrite their inputs to save memory previously had overwrite_ parameters;
these have been replaced with copy_ parameters with exactly the opposite meaning.
This particularly affects some of the estimators in linear_model. The default behavior is still to copy
everything passed in.
• The SVMlight dataset loader sklearn.datasets.load_svmlight_file no longer supports loading
two files at once; use load_svmlight_files instead. Also, the (unused) buffer_mb parameter is gone.
• Sparse estimators in the Stochastic Gradient Descent module use dense parameter vector coef_ instead of
sparse_coef_. This significantly improves test time performance.
• The Covariance estimation module now has a robust estimator of covariance, the Minimum Covariance Deter-
minant estimator.
• Cluster evaluation metrics in metrics.cluster have been refactored but the changes are backwards compat-
ible. They have been moved to the metrics.cluster.supervised, along with metrics.cluster.
unsupervised which contains the Silhouette Coefficient.
• The permutation_test_score function now behaves the same way as cross_val_score (i.e. uses
the mean score across the folds.)
• Cross Validation generators now use integer indices (indices=True) by default instead of boolean masks.
This make it more intuitive to use with sparse matrix data.
• The functions used for sparse coding, sparse_encode and sparse_encode_parallel have been com-
bined into sklearn.decomposition.sparse_encode, and the shapes of the arrays have been trans-
posed for consistency with the matrix factorization setting, as opposed to the regression setting.
• Fixed an off-by-one error in the SVMlight/LibSVM file format handling; files generated using sklearn.
datasets.dump_svmlight_file should be re-generated. (They should continue to work, but acciden-
tally had one extra column of zeros prepended.)
• BaseDictionaryLearning class replaced by SparseCodingMixin.
• sklearn.utils.extmath.fast_svd has been renamed sklearn.utils.extmath.
randomized_svd and the default oversampling is now fixed to 10 additional random vectors instead
of doubling the number of components to extract. The new behavior follows the reference paper.

People

The following people contributed to scikit-learn since last release:


• 246 Andreas Müller
• 242 Olivier Grisel
• 220 Gilles Louppe
• 183 Brian Holt
• 166 Gael Varoquaux
• 144 Lars Buitinck
• 73 Vlad Niculae

1.15. Previous Releases 115


scikit-learn user guide, Release 0.20.3

• 65 Peter Prettenhofer
• 64 Fabian Pedregosa
• 60 Robert Layton
• 55 Mathieu Blondel
• 52 Jake Vanderplas
• 44 Noel Dawe
• 38 Alexandre Gramfort
• 24 Virgile Fritsch
• 23 Satrajit Ghosh
• 3 Jan Hendrik Metzen
• 3 Kenneth C. Arnold
• 3 Shiqiao Du
• 3 Tim Sheerman-Chase
• 3 Yaroslav Halchenko
• 2 Bala Subrahmanyam Varanasi
• 2 DraXus
• 2 Michael Eickenberg
• 1 Bogdan Trach
• 1 Félix-Antoine Fortin
• 1 Juan Manuel Caicedo Carvajal
• 1 Nelle Varoquaux
• 1 Nicolas Pinto
• 1 Tiziano Zito
• 1 Xinfan Meng

1.15.18 Version 0.9

September 21, 2011


scikit-learn 0.9 was released on September 2011, three months after the 0.8 release and includes the new modules
Manifold learning, The Dirichlet Process as well as several new algorithms and documentation improvements.
This release also includes the dictionary-learning work developed by Vlad Niculae as part of the Google Summer of
Code program.

116 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

1.15. Previous Releases 117


scikit-learn user guide, Release 0.20.3

Changelog

• New Manifold learning module by Jake Vanderplas and Fabian Pedregosa.


• New Dirichlet Process Gaussian Mixture Model by Alexandre Passos
• Nearest Neighbors module refactoring by Jake Vanderplas : general refactoring, support for sparse matrices in
input, speed and documentation improvements. See the next section for a full list of API changes.
• Improvements on the Feature selection module by Gilles Louppe : refactoring of the RFE classes, documenta-
tion rewrite, increased efficiency and minor API changes.
• Sparse principal components analysis (SparsePCA and MiniBatchSparsePCA) by Vlad Niculae, Gael Varo-
quaux and Alexandre Gramfort
• Printing an estimator now behaves independently of architectures and Python version thanks to Jean Kossaifi.
• Loader for libsvm/svmlight format by Mathieu Blondel and Lars Buitinck
• Documentation improvements: thumbnails in example gallery by Fabian Pedregosa.
• Important bugfixes in Support Vector Machines module (segfaults, bad performance) by Fabian Pedregosa.
• Added Multinomial Naive Bayes and Bernoulli Naive Bayes by Lars Buitinck
• Text feature extraction optimizations by Lars Buitinck
• Chi-Square feature selection (feature_selection.univariate_selection.chi2) by Lars Buit-
inck.
• Generated datasets module refactoring by Gilles Louppe
• Multiclass and multilabel algorithms by Mathieu Blondel
• Ball tree rewrite by Jake Vanderplas

118 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Implementation of DBSCAN algorithm by Robert Layton


• Kmeans predict and transform by Robert Layton
• Preprocessing module refactoring by Olivier Grisel
• Faster mean shift by Conrad Lee
• New Bootstrap, Random permutations cross-validation a.k.a. Shuffle & Split and various other improve-
ments in cross validation schemes by Olivier Grisel and Gael Varoquaux
• Adjusted Rand index and V-Measure clustering evaluation metrics by Olivier Grisel
• Added Orthogonal Matching Pursuit by Vlad Niculae
• Added 2D-patch extractor utilities in the Feature extraction module by Vlad Niculae
• Implementation of linear_model.LassoLarsCV (cross-validated Lasso solver using the Lars algorithm)
and linear_model.LassoLarsIC (BIC/AIC model selection in Lars) by Gael Varoquaux and Alexandre
Gramfort
• Scalability improvements to metrics.roc_curve by Olivier Hervieu
• Distance helper functions metrics.pairwise.pairwise_distances and metrics.pairwise.
pairwise_kernels by Robert Layton
• Mini-Batch K-Means by Nelle Varoquaux and Peter Prettenhofer.
• mldata utilities by Pietro Berkes.
• olivetti_faces by David Warde-Farley.

API changes summary

Here are the code migration instructions when upgrading from scikit-learn version 0.8:
• The scikits.learn package was renamed sklearn. There is still a scikits.learn package alias for
backward compatibility.
Third-party projects with a dependency on scikit-learn 0.9+ should upgrade their codebase. For instance, under
Linux / MacOSX just run (make a backup first!):

find -name "*.py" | xargs sed -i 's/\bscikits.learn\b/sklearn/g'

• Estimators no longer accept model parameters as fit arguments: instead all parameters must be only
be passed as constructor arguments or using the now public set_params method inherited from base.
BaseEstimator.
Some estimators can still accept keyword arguments on the fit but this is restricted to data-dependent values
(e.g. a Gram matrix or an affinity matrix that are precomputed from the X data matrix.
• The cross_val package has been renamed to cross_validation although there is also a cross_val
package alias in place for backward compatibility.
Third-party projects with a dependency on scikit-learn 0.9+ should upgrade their codebase. For instance, under
Linux / MacOSX just run (make a backup first!):

find -name "*.py" | xargs sed -i 's/\bcross_val\b/cross_validation/g'

• The score_func argument of the sklearn.cross_validation.cross_val_score function is


now expected to accept y_test and y_predicted as only arguments for classification and regression tasks
or X_test for unsupervised estimators.

1.15. Previous Releases 119


scikit-learn user guide, Release 0.20.3

• gamma parameter for support vector machine algorithms is set to 1 / n_features by default, instead of 1
/ n_samples.
• The sklearn.hmm has been marked as orphaned: it will be removed from scikit-learn in version 0.11 unless
someone steps up to contribute documentation, examples and fix lurking numerical stability issues.
• sklearn.neighbors has been made into a submodule. The two previously available estimators,
NeighborsClassifier and NeighborsRegressor have been marked as deprecated. Their function-
ality has been divided among five new classes: NearestNeighbors for unsupervised neighbors searches,
KNeighborsClassifier & RadiusNeighborsClassifier for supervised classification problems,
and KNeighborsRegressor & RadiusNeighborsRegressor for supervised regression problems.
• sklearn.ball_tree.BallTree has been moved to sklearn.neighbors.BallTree. Using the
former will generate a warning.
• sklearn.linear_model.LARS() and related classes (LassoLARS, LassoLARSCV, etc.) have been re-
named to sklearn.linear_model.Lars().
• All distance metrics and kernels in sklearn.metrics.pairwise now have a Y parameter, which by
default is None. If not given, the result is the distance (or kernel similarity) between each sample in Y. If given,
the result is the pairwise distance (or kernel similarity) between samples in X to Y.
• sklearn.metrics.pairwise.l1_distance is now called manhattan_distance, and by default
returns the pairwise distance. For the component wise distance, set the parameter sum_over_features to
False.
Backward compatibility package aliases and other deprecated classes and functions will be removed in version 0.11.

People

38 people contributed to this release.


• 387 Vlad Niculae
• 320 Olivier Grisel
• 192 Lars Buitinck
• 179 Gael Varoquaux
• 168 Fabian Pedregosa (INRIA, Parietal Team)
• 127 Jake Vanderplas
• 120 Mathieu Blondel
• 85 Alexandre Passos
• 67 Alexandre Gramfort
• 57 Peter Prettenhofer
• 56 Gilles Louppe
• 42 Robert Layton
• 38 Nelle Varoquaux
• 32 Jean Kossaifi
• 30 Conrad Lee
• 22 Pietro Berkes
• 18 andy

120 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• 17 David Warde-Farley
• 12 Brian Holt
• 11 Robert
• 8 Amit Aides
• 8 Virgile Fritsch
• 7 Yaroslav Halchenko
• 6 Salvatore Masecchia
• 5 Paolo Losi
• 4 Vincent Schut
• 3 Alexis Metaireau
• 3 Bryan Silverthorn
• 3 Andreas Müller
• 2 Minwoo Jake Lee
• 1 Emmanuelle Gouillart
• 1 Keith Goodman
• 1 Lucas Wiman
• 1 Nicolas Pinto
• 1 Thouis (Ray) Jones
• 1 Tim Sheerman-Chase

1.15.19 Version 0.8

May 11, 2011


scikit-learn 0.8 was released on May 2011, one month after the first “international” scikit-learn coding sprint and is
marked by the inclusion of important modules: Hierarchical clustering, Cross decomposition, Non-negative matrix
factorization (NMF or NNMF), initial support for Python 3 and by important enhancements and bug fixes.

Changelog

Several new modules where introduced during this release:


• New Hierarchical clustering module by Vincent Michel, Bertrand Thirion, Alexandre Gramfort and Gael Varo-
quaux.
• Kernel PCA implementation by Mathieu Blondel
• labeled_faces_in_the_wild by Olivier Grisel.
• New Cross decomposition module by Edouard Duchesnay.
• Non-negative matrix factorization (NMF or NNMF) module Vlad Niculae
• Implementation of the Oracle Approximating Shrinkage algorithm by Virgile Fritsch in the Covariance estima-
tion module.
Some other modules benefited from significant improvements or cleanups.

1.15. Previous Releases 121


scikit-learn user guide, Release 0.20.3

• Initial support for Python 3: builds and imports cleanly, some modules are usable while others have failing tests
by Fabian Pedregosa.
• decomposition.PCA is now usable from the Pipeline object by Olivier Grisel.
• Guide How to optimize for speed by Olivier Grisel.
• Fixes for memory leaks in libsvm bindings, 64-bit safer BallTree by Lars Buitinck.
• bug and style fixing in K-means algorithm by Jan Schlüter.
• Add attribute converged to Gaussian Mixture Models by Vincent Schut.
• Implemented transform, predict_log_proba in discriminant_analysis.
LinearDiscriminantAnalysis By Mathieu Blondel.
• Refactoring in the Support Vector Machines module and bug fixes by Fabian Pedregosa, Gael Varoquaux and
Amit Aides.
• Refactored SGD module (removed code duplication, better variable naming), added interface for sample weight
by Peter Prettenhofer.
• Wrapped BallTree with Cython by Thouis (Ray) Jones.
• Added function svm.l1_min_c by Paolo Losi.
• Typos, doc style, etc. by Yaroslav Halchenko, Gael Varoquaux, Olivier Grisel, Yann Malet, Nicolas Pinto, Lars
Buitinck and Fabian Pedregosa.

People

People that made this release possible preceded by number of commits:


• 159 Olivier Grisel
• 96 Gael Varoquaux
• 96 Vlad Niculae
• 94 Fabian Pedregosa
• 36 Alexandre Gramfort
• 32 Paolo Losi
• 31 Edouard Duchesnay
• 30 Mathieu Blondel
• 25 Peter Prettenhofer
• 22 Nicolas Pinto
• 11 Virgile Fritsch
– 7 Lars Buitinck
– 6 Vincent Michel
– 5 Bertrand Thirion
– 4 Thouis (Ray) Jones
– 4 Vincent Schut
– 3 Jan Schlüter
– 2 Julien Miotte

122 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

– 2 Matthieu Perrot
– 2 Yann Malet
– 2 Yaroslav Halchenko
– 1 Amit Aides
– 1 Andreas Müller
– 1 Feth Arezki
– 1 Meng Xinfan

1.15.20 Version 0.7

March 2, 2011
scikit-learn 0.7 was released in March 2011, roughly three months after the 0.6 release. This release is marked by the
speed improvements in existing algorithms like k-Nearest Neighbors and K-Means algorithm and by the inclusion of
an efficient algorithm for computing the Ridge Generalized Cross Validation solution. Unlike the preceding release,
no new modules where added to this release.

Changelog

• Performance improvements for Gaussian Mixture Model sampling [Jan Schlüter].


• Implementation of efficient leave-one-out cross-validated Ridge in linear_model.RidgeCV [Mathieu
Blondel]
• Better handling of collinearity and early stopping in linear_model.lars_path [Alexandre Gramfort and
Fabian Pedregosa].
• Fixes for liblinear ordering of labels and sign of coefficients [Dan Yamins, Paolo Losi, Mathieu Blondel and
Fabian Pedregosa].
• Performance improvements for Nearest Neighbors algorithm in high-dimensional spaces [Fabian Pedregosa].
• Performance improvements for cluster.KMeans [Gael Varoquaux and James Bergstra].
• Sanity checks for SVM-based classes [Mathieu Blondel].
• Refactoring of neighbors.NeighborsClassifier and neighbors.kneighbors_graph: added
different algorithms for the k-Nearest Neighbor Search and implemented a more stable algorithm for finding
barycenter weights. Also added some developer documentation for this module, see notes_neighbors for more
information [Fabian Pedregosa].
• Documentation improvements: Added pca.RandomizedPCA and linear_model.
LogisticRegression to the class reference. Also added references of matrices used for clustering
and other fixes [Gael Varoquaux, Fabian Pedregosa, Mathieu Blondel, Olivier Grisel, Virgile Fritsch ,
Emmanuelle Gouillart]
• Binded decision_function in classes that make use of liblinear, dense and sparse variants, like svm.
LinearSVC or linear_model.LogisticRegression [Fabian Pedregosa].
• Performance and API improvements to metrics.euclidean_distances and to pca.
RandomizedPCA [James Bergstra].
• Fix compilation issues under NetBSD [Kamel Ibn Hassen Derouiche]
• Allow input sequences of different lengths in hmm.GaussianHMM [Ron Weiss].

1.15. Previous Releases 123


scikit-learn user guide, Release 0.20.3

• Fix bug in affinity propagation caused by incorrect indexing [Xinfan Meng]

People

People that made this release possible preceded by number of commits:


• 85 Fabian Pedregosa
• 67 Mathieu Blondel
• 20 Alexandre Gramfort
• 19 James Bergstra
• 14 Dan Yamins
• 13 Olivier Grisel
• 12 Gael Varoquaux
• 4 Edouard Duchesnay
• 4 Ron Weiss
• 2 Satrajit Ghosh
• 2 Vincent Dubourg
• 1 Emmanuelle Gouillart
• 1 Kamel Ibn Hassen Derouiche
• 1 Paolo Losi
• 1 VirgileFritsch
• 1 Yaroslav Halchenko
• 1 Xinfan Meng

1.15.21 Version 0.6

December 21, 2010


scikit-learn 0.6 was released on December 2010. It is marked by the inclusion of several new modules and a general
renaming of old ones. It is also marked by the inclusion of new example, including applications to real-world datasets.

Changelog

• New stochastic gradient descent module by Peter Prettenhofer. The module comes with complete documentation
and examples.
• Improved svm module: memory consumption has been reduced by 50%, heuristic to automatically set class
weights, possibility to assign weights to samples (see SVM: Weighted samples for an example).
• New Gaussian Processes module by Vincent Dubourg. This module also has great documenta-
tion and some very neat examples. See example_gaussian_process_plot_gp_regression.py or exam-
ple_gaussian_process_plot_gp_probabilistic_classification_after_regression.py for a taste of what can be done.
• It is now possible to use liblinear’s Multi-class SVC (option multi_class in svm.LinearSVC)
• New features and performance improvements of text feature extraction.

124 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

• Improved sparse matrix support, both in main classes (grid_search.GridSearchCV) as in modules


sklearn.svm.sparse and sklearn.linear_model.sparse.
• Lots of cool new examples and a new section that uses real-world datasets was created. These include: Faces
recognition example using eigenfaces and SVMs, Species distribution modeling, Libsvm GUI, Wikipedia princi-
pal eigenvector and others.
• Faster Least Angle Regression algorithm. It is now 2x faster than the R version on worst case and up to 10x
times faster on some cases.
• Faster coordinate descent algorithm. In particular, the full path version of lasso (linear_model.
lasso_path) is more than 200x times faster than before.
• It is now possible to get probability estimates from a linear_model.LogisticRegression model.
• module renaming: the glm module has been renamed to linear_model, the gmm module has been included into
the more general mixture model and the sgd module has been included in linear_model.
• Lots of bug fixes and documentation improvements.

People

People that made this release possible preceded by number of commits:


• 207 Olivier Grisel
• 167 Fabian Pedregosa
• 97 Peter Prettenhofer
• 68 Alexandre Gramfort
• 59 Mathieu Blondel
• 55 Gael Varoquaux
• 33 Vincent Dubourg
• 21 Ron Weiss
• 9 Bertrand Thirion
• 3 Alexandre Passos
• 3 Anne-Laure Fouque
• 2 Ronan Amicel
• 1 Christian Osendorfer

1.15.22 Version 0.5

October 11, 2010

Changelog

New classes

• Support for sparse matrices in some classifiers of modules svm and linear_model (see svm.
sparse.SVC, svm.sparse.SVR, svm.sparse.LinearSVC, linear_model.sparse.Lasso,
linear_model.sparse.ElasticNet)

1.15. Previous Releases 125


scikit-learn user guide, Release 0.20.3

• New pipeline.Pipeline object to compose different estimators.


• Recursive Feature Elimination routines in module Feature selection.
• Addition of various classes capable of cross validation in the linear_model module (linear_model.
LassoCV , linear_model.ElasticNetCV , etc.).
• New, more efficient LARS algorithm implementation. The Lasso variant of the algorithm is also implemented.
See linear_model.lars_path, linear_model.Lars and linear_model.LassoLars.
• New Hidden Markov Models module (see classes hmm.GaussianHMM, hmm.MultinomialHMM, hmm.
GMMHMM)
• New module feature_extraction (see class reference)
• New FastICA algorithm in module sklearn.fastica

Documentation

• Improved documentation for many modules, now separating narrative documentation from the class reference.
As an example, see documentation for the SVM module and the complete class reference.

Fixes

• API changes: adhere variable names to PEP-8, give more meaningful names.
• Fixes for svm module to run on a shared memory context (multiprocessing).
• It is again possible to generate latex (and thus PDF) from the sphinx docs.

Examples

• new examples using some of the mlcomp datasets: sphx_glr_auto_examples_mlcomp_sparse_document_classif


py (since removed) and Classification of text documents using sparse features
• Many more examples. See here the full list of examples.

External dependencies

• Joblib is now a dependency of this package, although it is shipped with (sklearn.externals.joblib).

Removed modules

• Module ann (Artificial Neural Networks) has been removed from the distribution. Users wanting this sort of
algorithms should take a look into pybrain.

Misc

• New sphinx theme for the web page.

126 Chapter 1. Welcome to scikit-learn


scikit-learn user guide, Release 0.20.3

Authors

The following is a list of authors for this release, preceded by number of commits:
• 262 Fabian Pedregosa
• 240 Gael Varoquaux
• 149 Alexandre Gramfort
• 116 Olivier Grisel
• 40 Vincent Michel
• 38 Ron Weiss
• 23 Matthieu Perrot
• 10 Bertrand Thirion
• 7 Yaroslav Halchenko
• 9 VirgileFritsch
• 6 Edouard Duchesnay
• 4 Mathieu Blondel
• 1 Ariel Rokem
• 1 Matthieu Brucher

1.15.23 Version 0.4

August 26, 2010

Changelog

Major changes in this release include:


• Coordinate Descent algorithm (Lasso, ElasticNet) refactoring & speed improvements (roughly 100x times
faster).
• Coordinate Descent Refactoring (and bug fixing) for consistency with R’s package GLMNET.
• New metrics module.
• New GMM module contributed by Ron Weiss.
• Implementation of the LARS algorithm (without Lasso variant for now).
• feature_selection module redesign.
• Migration to GIT as version control system.
• Removal of obsolete attrselect module.
• Rename of private compiled extensions (added underscore).
• Removal of legacy unmaintained code.
• Documentation improvements (both docstring and rst).
• Improvement of the build system to (optionally) link with MKL. Also, provide a lite BLAS implementation in
case no system-wide BLAS is found.

1.15. Previous Releases 127


scikit-learn user guide, Release 0.20.3

• Lots of new examples.


• Many, many bug fixes . . .

Authors

The committer list for this release is the following (preceded by number of commits):
• 143 Fabian Pedregosa
• 35 Alexandre Gramfort
• 34 Olivier Grisel
• 11 Gael Varoquaux
• 5 Yaroslav Halchenko
• 2 Vincent Michel
• 1 Chris Filo Gorgolewski

1.15.24 Earlier versions

Earlier versions included contributions by Fred Mailhot, David Cooke, David Huard, Dave Morrill, Ed Schofield,
Travis Oliphant, Pearu Peterson.

128 Chapter 1. Welcome to scikit-learn


CHAPTER

TWO

SCIKIT-LEARN TUTORIALS

2.1 An introduction to machine learning with scikit-learn

Section contents

In this section, we introduce the machine learning vocabulary that we use throughout scikit-learn and give a simple
learning example.

2.1.1 Machine learning: the problem setting

In general, a learning problem considers a set of n samples of data and then tries to predict properties of unknown data.
If each sample is more than a single number and, for instance, a multi-dimensional entry (aka multivariate data), it is
said to have several attributes or features.
Learning problems fall into a few categories:
• supervised learning, in which the data comes with additional attributes that we want to predict (Click here to go
to the scikit-learn supervised learning page).This problem can be either:
– classification: samples belong to two or more classes and we want to learn from already labeled data how
to predict the class of unlabeled data. An example of a classification problem would be handwritten digit
recognition, in which the aim is to assign each input vector to one of a finite number of discrete categories.
Another way to think of classification is as a discrete (as opposed to continuous) form of supervised
learning where one has a limited number of categories and for each of the n samples provided, one is to
try to label them with the correct category or class.
– regression: if the desired output consists of one or more continuous variables, then the task is called
regression. An example of a regression problem would be the prediction of the length of a salmon as a
function of its age and weight.
• unsupervised learning, in which the training data consists of a set of input vectors x without any corresponding
target values. The goal in such problems may be to discover groups of similar examples within the data, where
it is called clustering, or to determine the distribution of data within the input space, known as density estima-
tion, or to project the data from a high-dimensional space down to two or three dimensions for the purpose of
visualization (Click here to go to the Scikit-Learn unsupervised learning page).

129
scikit-learn user guide, Release 0.20.3

Training set and testing set

Machine learning is about learning some properties of a data set and then testing those properties against another
data set. A common practice in machine learning is to evaluate an algorithm by splitting a data set into two. We
call one of those sets the training set, on which we learn some properties; we call the other set the testing set, on
which we test the learned properties.

2.1.2 Loading an example dataset

scikit-learn comes with a few standard datasets, for instance the iris and digits datasets for classification and the boston
house prices dataset for regression.
In the following, we start a Python interpreter from our shell and then load the iris and digits datasets. Our
notational convention is that $ denotes the shell prompt while >>> denotes the Python interpreter prompt:
$ python
>>> from sklearn import datasets
>>> iris = datasets.load_iris()
>>> digits = datasets.load_digits()

A dataset is a dictionary-like object that holds all the data and some metadata about the data. This data is stored in
the .data member, which is a n_samples, n_features array. In the case of supervised problem, one or more
response variables are stored in the .target member. More details on the different datasets can be found in the
dedicated section.
For instance, in the case of the digits dataset, digits.data gives access to the features that can be used to classify
the digits samples:
>>> print(digits.data)
[[ 0. 0. 5. ... 0. 0. 0.]
[ 0. 0. 0. ... 10. 0. 0.]
[ 0. 0. 0. ... 16. 9. 0.]
...
[ 0. 0. 1. ... 6. 0. 0.]
[ 0. 0. 2. ... 12. 0. 0.]
[ 0. 0. 10. ... 12. 1. 0.]]

and digits.target gives the ground truth for the digit dataset, that is the number corresponding to each digit
image that we are trying to learn:
>>> digits.target
array([0, 1, 2, ..., 8, 9, 8])

Shape of the data arrays

The data is always a 2D array, shape (n_samples, n_features), although the original data may have had a
different shape. In the case of the digits, each original sample is an image of shape (8, 8) and can be accessed
using:
>>> digits.images[0]
array([[ 0., 0., 5., 13., 9., 1., 0., 0.],
[ 0., 0., 13., 15., 10., 15., 5., 0.],
[ 0., 3., 15., 2., 0., 11., 8., 0.],
[ 0., 4., 12., 0., 0., 8., 8., 0.],
[ 0., 5., 8., 0., 0., 9., 8., 0.],
[ 0., 4., 11., 0., 1., 12., 7., 0.],
[ 0., 2., 14., 5., 10., 12., 0., 0.],
130 [ 0., 0., 6., 13., 10., 0., 0., 0.]]) Chapter 2. scikit-learn Tutorials
scikit-learn user guide, Release 0.20.3

The simple example on this dataset illustrates how starting from the original problem one can shape the data for
consumption in scikit-learn.

Loading from external datasets

To load from an external dataset, please refer to loading external datasets.

2.1.3 Learning and predicting

In the case of the digits dataset, the task is to predict, given an image, which digit it represents. We are given samples
of each of the 10 possible classes (the digits zero through nine) on which we fit an estimator to be able to predict the
classes to which unseen samples belong.
In scikit-learn, an estimator for classification is a Python object that implements the methods fit(X, y) and
predict(T).
An example of an estimator is the class sklearn.svm.SVC, which implements support vector classification. The
estimator’s constructor takes as arguments the model’s parameters.
For now, we will consider the estimator as a black box:

>>> from sklearn import svm


>>> clf = svm.SVC(gamma=0.001, C=100.)

Choosing the parameters of the model

In this example, we set the value of gamma manually. To find good values for these parameters, we can use tools
such as grid search and cross validation.

The clf (for classifier) estimator instance is first fitted to the model; that is, it must learn from the model. This is
done by passing our training set to the fit method. For the training set, we’ll use all the images from our dataset,
except for the last image, which we’ll reserve for our predicting. We select the training set with the [:-1] Python
syntax, which produces a new array that contains all but the last item from digits.data:

>>> clf.fit(digits.data[:-1], digits.target[:-1])


SVC(C=100.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma=0.001, kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)

Now you can predict new values. In this case, you’ll predict using the last image from digits.data. By predicting,
you’ll determine the image from the training set that best matches the last image.

>>> clf.predict(digits.data[-1:])
array([8])

2.1. An introduction to machine learning with scikit-learn 131


scikit-learn user guide, Release 0.20.3

The corresponding image is: As you can see, it is a challenging task: after all, the images
are of poor resolution. Do you agree with the classifier?
A complete example of this classification problem is available as an example that you can run and study: Recognizing
hand-written digits.

2.1.4 Model persistence

It is possible to save a model in scikit-learn by using Python’s built-in persistence model, pickle:

>>> from sklearn import svm


>>> from sklearn import datasets
>>> clf = svm.SVC(gamma='scale')
>>> iris = datasets.load_iris()
>>> X, y = iris.data, iris.target
>>> clf.fit(X, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='scale', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)

>>> import pickle


>>> s = pickle.dumps(clf)
>>> clf2 = pickle.loads(s)
>>> clf2.predict(X[0:1])
array([0])
>>> y[0]
0

In the specific case of scikit-learn, it may be more interesting to use joblib’s replacement for pickle (joblib.dump
& joblib.load), which is more efficient on big data but it can only pickle to the disk and not to a string:

>>> from joblib import dump, load


>>> dump(clf, 'filename.joblib')

Later, you can reload the pickled model (possibly in another Python process) with:

>>> clf = load('filename.joblib')

Note: joblib.dump and joblib.load functions also accept file-like object instead of filenames. More infor-
mation on data persistence with Joblib is available here.

Note that pickle has some security and maintainability issues. Please refer to section Model persistence for more
detailed information about model persistence with scikit-learn.

132 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

2.1.5 Conventions

scikit-learn estimators follow certain rules to make their behavior more predictive. These are described in more detail
in the Glossary of Common Terms and API Elements.

Type casting

Unless otherwise specified, input will be cast to float64:

>>> import numpy as np


>>> from sklearn import random_projection

>>> rng = np.random.RandomState(0)


>>> X = rng.rand(10, 2000)
>>> X = np.array(X, dtype='float32')
>>> X.dtype
dtype('float32')

>>> transformer = random_projection.GaussianRandomProjection()


>>> X_new = transformer.fit_transform(X)
>>> X_new.dtype
dtype('float64')

In this example, X is float32, which is cast to float64 by fit_transform(X).


Regression targets are cast to float64 and classification targets are maintained:

>>> from sklearn import datasets


>>> from sklearn.svm import SVC
>>> iris = datasets.load_iris()
>>> clf = SVC(gamma='scale')
>>> clf.fit(iris.data, iris.target)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='scale', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)

>>> list(clf.predict(iris.data[:3]))
[0, 0, 0]

>>> clf.fit(iris.data, iris.target_names[iris.target])


SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='scale', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)

>>> list(clf.predict(iris.data[:3]))
['setosa', 'setosa', 'setosa']

Here, the first predict() returns an integer array, since iris.target (an integer array) was used in fit. The
second predict() returns a string array, since iris.target_names was for fitting.

Refitting and updating parameters

Hyper-parameters of an estimator can be updated after it has been constructed via the set_params() method. Calling
fit() more than once will overwrite what was learned by any previous fit():

2.1. An introduction to machine learning with scikit-learn 133


scikit-learn user guide, Release 0.20.3

>>> import numpy as np


>>> from sklearn.svm import SVC

>>> rng = np.random.RandomState(0)


>>> X = rng.rand(100, 10)
>>> y = rng.binomial(1, 0.5, 100)
>>> X_test = rng.rand(5, 10)

>>> clf = SVC()


>>> clf.set_params(kernel='linear').fit(X, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
kernel='linear', max_iter=-1, probability=False, random_state=None,
shrinking=True, tol=0.001, verbose=False)
>>> clf.predict(X_test)
array([1, 0, 1, 1, 0])

>>> clf.set_params(kernel='rbf', gamma='scale').fit(X, y)


SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='scale', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> clf.predict(X_test)
array([0, 0, 0, 1, 0])

Here, the default kernel rbf is first changed to linear via SVC.set_params() after the estimator has been
constructed, and changed back to rbf to refit the estimator and to make a second prediction.

Multiclass vs. multilabel fitting

When using multiclass classifiers, the learning and prediction task that is performed is dependent on the
format of the target data fit upon:

>>> from sklearn.svm import SVC


>>> from sklearn.multiclass import OneVsRestClassifier
>>> from sklearn.preprocessing import LabelBinarizer

>>> X = [[1, 2], [2, 4], [4, 5], [3, 2], [3, 1]]
>>> y = [0, 0, 1, 1, 2]

>>> classif = OneVsRestClassifier(estimator=SVC(gamma='scale',


... random_state=0))
>>> classif.fit(X, y).predict(X)
array([0, 0, 1, 1, 2])

In the above case, the classifier is fit on a 1d array of multiclass labels and the predict() method therefore provides
corresponding multiclass predictions. It is also possible to fit upon a 2d array of binary label indicators:

>>> y = LabelBinarizer().fit_transform(y)
>>> classif.fit(X, y).predict(X)
array([[1, 0, 0],
[1, 0, 0],
[0, 1, 0],
[0, 0, 0],
[0, 0, 0]])

134 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

Here, the classifier is fit() on a 2d binary label representation of y, using the LabelBinarizer. In this case
predict() returns a 2d array representing the corresponding multilabel predictions.
Note that the fourth and fifth instances returned all zeroes, indicating that they matched none of the three labels fit
upon. With multilabel outputs, it is similarly possible for an instance to be assigned multiple labels:
>>> from sklearn.preprocessing import MultiLabelBinarizer
>>> y = [[0, 1], [0, 2], [1, 3], [0, 2, 3], [2, 4]]
>>> y = MultiLabelBinarizer().fit_transform(y)
>>> classif.fit(X, y).predict(X)
array([[1, 1, 0, 0, 0],
[1, 0, 1, 0, 0],
[0, 1, 0, 1, 0],
[1, 0, 1, 0, 0],
[1, 0, 1, 0, 0]])

In this case, the classifier is fit upon instances each assigned multiple labels. The MultiLabelBinarizer is
used to binarize the 2d array of multilabels to fit upon. As a result, predict() returns a 2d array with multiple
predicted labels for each instance.

2.2 A tutorial on statistical-learning for scientific data processing

Statistical learning

Machine learning is a technique with a growing importance, as the size of the datasets experimental sciences are fac-
ing is rapidly growing. Problems it tackles range from building a prediction function linking different observations,
to classifying observations, or learning the structure in an unlabeled dataset.
This tutorial will explore statistical learning, the use of machine learning techniques with the goal of statistical
inference: drawing conclusions on the data at hand.
Scikit-learn is a Python module integrating classic machine learning algorithms in the tightly-knit world of scientific
Python packages (NumPy, SciPy, matplotlib).

2.2.1 Statistical learning: the setting and the estimator object in scikit-learn

Datasets

Scikit-learn deals with learning information from one or more datasets that are represented as 2D arrays. They can be
understood as a list of multi-dimensional observations. We say that the first axis of these arrays is the samples axis,
while the second is the features axis.

A simple example shipped with scikit-learn: iris dataset

>>> from sklearn import datasets


>>> iris = datasets.load_iris()
>>> data = iris.data
>>> data.shape
(150, 4)

It is made of 150 observations of irises, each described by 4 features: their sepal and petal length and width, as
detailed in iris.DESCR.

2.2. A tutorial on statistical-learning for scientific data processing 135


scikit-learn user guide, Release 0.20.3

When the data is not initially in the (n_samples, n_features) shape, it needs to be preprocessed in order to
be used by scikit-learn.

An example of reshaping data would be the digits dataset

The digits dataset is made of 1797 8x8 images of hand-written digits


>>> digits = datasets.load_digits()
>>> digits.images.shape
(1797, 8, 8)
>>> import matplotlib.pyplot as plt
>>> plt.imshow(digits.images[-1], cmap=plt.cm.gray_r)
<matplotlib.image.AxesImage object at ...>

To use this dataset with scikit-learn, we transform each 8x8 image into a feature vector of length 64
>>> data = digits.images.reshape((digits.images.shape[0], -1))

Estimators objects

Fitting data: the main API implemented by scikit-learn is that of the estimator. An estimator is any object that learns
from data; it may be a classification, regression or clustering algorithm or a transformer that extracts/filters useful
features from raw data.
All estimator objects expose a fit method that takes a dataset (usually a 2-d array):

>>> estimator.fit(data)

Estimator parameters: All the parameters of an estimator can be set when it is instantiated or by modifying the
corresponding attribute:

>>> estimator = Estimator(param1=1, param2=2)


>>> estimator.param1
1

Estimated parameters: When data is fitted with an estimator, parameters are estimated from the data at hand. All the
estimated parameters are attributes of the estimator object ending by an underscore:

>>> estimator.estimated_param_

136 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

2.2.2 Supervised learning: predicting an output variable from high-dimensional ob-


servations

The problem solved in supervised learning

Supervised learning consists in learning the link between two datasets: the observed data X and an external variable
y that we are trying to predict, usually called “target” or “labels”. Most often, y is a 1D array of length n_samples.
All supervised estimators in scikit-learn implement a fit(X, y) method to fit the model and a predict(X)
method that, given unlabeled observations X, returns the predicted labels y.

Vocabulary: classification and regression

If the prediction task is to classify the observations in a set of finite labels, in other words to “name” the objects
observed, the task is said to be a classification task. On the other hand, if the goal is to predict a continuous target
variable, it is said to be a regression task.
When doing classification in scikit-learn, y is a vector of integers or strings.
Note: See the Introduction to machine learning with scikit-learn Tutorial for a quick run-through on the basic
machine learning vocabulary used within scikit-learn.

Nearest neighbor and the curse of dimensionality

Classifying irises:

2.2. A tutorial on statistical-learning for scientific data processing 137


scikit-learn user guide, Release 0.20.3

The iris dataset is a


classification task consisting in identifying 3 different types of irises (Setosa, Versicolour, and Virginica) from their
petal and sepal length and width:
>>> import numpy as np
>>> from sklearn import datasets
>>> iris = datasets.load_iris()
>>> iris_X = iris.data
>>> iris_y = iris.target
>>> np.unique(iris_y)
array([0, 1, 2])

k-Nearest neighbors classifier

The simplest possible classifier is the nearest neighbor: given a new observation X_test, find in the training set (i.e.
the data used to train the estimator) the observation with the closest feature vector. (Please see the Nearest Neighbors
section of the online Scikit-learn documentation for more information about this type of classifier.)

Training set and testing set

While experimenting with any learning algorithm, it is important not to test the prediction of an estimator on the
data used to fit the estimator as this would not be evaluating the performance of the estimator on new data. This is
why datasets are often split into train and test data.

138 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

KNN (k nearest neighbors) classification example:

>>> # Split iris data in train and test data


>>> # A random permutation, to split the data randomly
>>> np.random.seed(0)
>>> indices = np.random.permutation(len(iris_X))
>>> iris_X_train = iris_X[indices[:-10]]
>>> iris_y_train = iris_y[indices[:-10]]
>>> iris_X_test = iris_X[indices[-10:]]
>>> iris_y_test = iris_y[indices[-10:]]
>>> # Create and fit a nearest-neighbor classifier
>>> from sklearn.neighbors import KNeighborsClassifier
>>> knn = KNeighborsClassifier()
>>> knn.fit(iris_X_train, iris_y_train)
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
metric_params=None, n_jobs=None, n_neighbors=5, p=2,
weights='uniform')
>>> knn.predict(iris_X_test)
array([1, 2, 1, 0, 0, 0, 2, 1, 2, 0])
>>> iris_y_test
array([1, 1, 1, 0, 0, 0, 2, 1, 2, 0])

The curse of dimensionality

For an estimator to be effective, you need the distance between neighboring points to be less than some value 𝑑, which
depends on the problem. In one dimension, this requires on average 𝑛 ∼ 1/𝑑 points. In the context of the above 𝑘-NN
example, if the data is described by just one feature with values ranging from 0 to 1 and with 𝑛 training observations,
then new data will be no further away than 1/𝑛. Therefore, the nearest neighbor decision rule will be efficient as soon
as 1/𝑛 is small compared to the scale of between-class feature variations.
If the number of features is 𝑝, you now require 𝑛 ∼ 1/𝑑𝑝 points. Let’s say that we require 10 points in one dimension:
now 10𝑝 points are required in 𝑝 dimensions to pave the [0, 1] space. As 𝑝 becomes large, the number of training points
required for a good estimator grows exponentially.
For example, if each point is just a single number (8 bytes), then an effective 𝑘-NN estimator in a paltry 𝑝 ∼ 20
dimensions would require more training data than the current estimated size of the entire internet (±1000 Exabytes or

2.2. A tutorial on statistical-learning for scientific data processing 139


scikit-learn user guide, Release 0.20.3

so).
This is called the curse of dimensionality and is a core problem that machine learning addresses.

Linear model: from regression to sparsity

Diabetes dataset

The diabetes dataset consists of 10 physiological variables (age, sex, weight, blood pressure) measure on 442
patients, and an indication of disease progression after one year:
>>> diabetes = datasets.load_diabetes()
>>> diabetes_X_train = diabetes.data[:-20]
>>> diabetes_X_test = diabetes.data[-20:]
>>> diabetes_y_train = diabetes.target[:-20]
>>> diabetes_y_test = diabetes.target[-20:]

The task at hand is to predict disease progression from physiological variables.

Linear regression

LinearRegression, in its simplest form, fits a linear model to the data set by adjusting a set
of parameters in order to make the sum of the squared residuals of the model as small as possible.

Linear models: 𝑦 = 𝑋𝛽 + 𝜖
• 𝑋: data
• 𝑦: target variable
• 𝛽: Coefficients
• 𝜖: Observation noise

>>> from sklearn import linear_model


>>> regr = linear_model.LinearRegression()
>>> regr.fit(diabetes_X_train, diabetes_y_train)
...
LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None,
normalize=False)
>>> print(regr.coef_)
[ 0.30349955 -237.63931533 510.53060544 327.73698041 -814.13170937
492.81458798 102.84845219 184.60648906 743.51961675 76.09517222]

>>> # The mean square error

140 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

>>> np.mean((regr.predict(diabetes_X_test) - diabetes_y_test)**2)


...
2004.56760268...

>>> # Explained variance score: 1 is perfect prediction


>>> # and 0 means that there is no linear relationship
>>> # between X and y.
>>> regr.score(diabetes_X_test, diabetes_y_test)
0.5850753022690...

Shrinkage

If there are few data points per dimension, noise in the observations induces high variance:

>>> X = np.c_[ .5, 1].T


>>> y = [.5, 1]
>>> test = np.c_[ 0, 2].T
>>> regr = linear_model.LinearRegression()

>>> import matplotlib.pyplot as plt


>>> plt.figure()

>>> np.random.seed(0)
>>> for _ in range(6):
... this_X = .1 * np.random.normal(size=(2, 1)) + X
... regr.fit(this_X, y)
... plt.plot(test, regr.predict(test))
... plt.scatter(this_X, y, s=3)

A solution in high-dimensional statistical learning is to shrink the regression coefficients to zero: any
two randomly chosen set of observations are likely to be uncorrelated. This is called Ridge regression:

2.2. A tutorial on statistical-learning for scientific data processing 141


scikit-learn user guide, Release 0.20.3

>>> regr = linear_model.Ridge(alpha=.1)

>>> plt.figure()

>>> np.random.seed(0)
>>> for _ in range(6):
... this_X = .1 * np.random.normal(size=(2, 1)) + X
... regr.fit(this_X, y)
... plt.plot(test, regr.predict(test))
... plt.scatter(this_X, y, s=3)

This is an example of bias/variance tradeoff: the larger the ridge alpha parameter, the higher the bias and the lower
the variance.
We can choose alpha to minimize left out error, this time using the diabetes dataset rather than our synthetic data:

>>> from __future__ import print_function


>>> alphas = np.logspace(-4, -1, 6)
>>> print([regr.set_params(alpha=alpha)
... .fit(diabetes_X_train, diabetes_y_train)
... .score(diabetes_X_test, diabetes_y_test)
... for alpha in alphas])
...
[0.5851110683883..., 0.5852073015444..., 0.5854677540698...,
0.5855512036503..., 0.5830717085554..., 0.57058999437...]

Note: Capturing in the fitted parameters noise that prevents the model to generalize to new data is called overfitting.
The bias introduced by the ridge regression is called a regularization.

Sparsity

Fitting only features 1 and 2

142 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

Note: A representation of the full diabetes dataset would involve 11 dimensions (10 feature dimensions and one of
the target variable). It is hard to develop an intuition on such representation, but it may be useful to keep in mind that
it would be a fairly empty space.

We can see that, although feature 2 has a strong coefficient on the full model, it conveys little information on y when
considered with feature 1.
To improve the conditioning of the problem (i.e. mitigating the The curse of dimensionality), it would be interesting
to select only the informative features and set non-informative ones, like feature 2 to 0. Ridge regression will decrease
their contribution, but not set them to zero. Another penalization approach, called Lasso (least absolute shrinkage and
selection operator), can set some coefficients to zero. Such methods are called sparse method and sparsity can be
seen as an application of Occam’s razor: prefer simpler models.

>>> regr = linear_model.Lasso()


>>> scores = [regr.set_params(alpha=alpha)
... .fit(diabetes_X_train, diabetes_y_train)
... .score(diabetes_X_test, diabetes_y_test)
... for alpha in alphas]
>>> best_alpha = alphas[scores.index(max(scores))]
>>> regr.alpha = best_alpha
>>> regr.fit(diabetes_X_train, diabetes_y_train)
Lasso(alpha=0.025118864315095794, copy_X=True, fit_intercept=True,
max_iter=1000, normalize=False, positive=False, precompute=False,
random_state=None, selection='cyclic', tol=0.0001, warm_start=False)
>>> print(regr.coef_)
[ 0. -212.43764548 517.19478111 313.77959962 -160.8303982 -0.
-187.19554705 69.38229038 508.66011217 71.84239008]

2.2. A tutorial on statistical-learning for scientific data processing 143


scikit-learn user guide, Release 0.20.3

Different algorithms for the same problem

Different algorithms can be used to solve the same mathematical problem. For instance the Lasso object in scikit-
learn solves the lasso regression problem using a coordinate descent method, that is efficient on large datasets.
However, scikit-learn also provides the LassoLars object using the LARS algorithm, which is very efficient for
problems in which the weight vector estimated is very sparse (i.e. problems with very few observations).

Classification

For classification, as in the labeling iris task, linear regression is not


the right approach as it will give too much weight to data far from the decision frontier. A linear approach is to fit a
sigmoid function or logistic function:
1
𝑦 = sigmoid(𝑋𝛽 − offset) + 𝜖 = +𝜖
1 + exp(−𝑋𝛽 + offset)

>>> log = linear_model.LogisticRegression(solver='lbfgs', C=1e5,


... multi_class='multinomial')
>>> log.fit(iris_X_train, iris_y_train)
LogisticRegression(C=100000.0, class_weight=None, dual=False,
fit_intercept=True, intercept_scaling=1, max_iter=100,
multi_class='multinomial', n_jobs=None, penalty='l2', random_state=None,
solver='lbfgs', tol=0.0001, verbose=0, warm_start=False)

This is known as LogisticRegression.

144 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

Multiclass classification

If you have several classes to predict, an option often used is to fit one-versus-all classifiers and then use a voting
heuristic for the final decision.

Shrinkage and sparsity with logistic regression

The C parameter controls the amount of regularization in the LogisticRegression object: a large value
for C results in less regularization. penalty="l2" gives Shrinkage (i.e. non-sparse coefficients), while
penalty="l1" gives Sparsity.

Exercise

Try classifying the digits dataset with nearest neighbors and a linear model. Leave out the last 10% and test
prediction performance on these observations.
from sklearn import datasets, neighbors, linear_model

digits = datasets.load_digits()
X_digits = digits.data / digits.data.max()
y_digits = digits.target

Solution: ../../auto_examples/exercises/plot_digits_classification_exercise.py

Support vector machines (SVMs)

Linear SVMs

Support Vector Machines belong to the discriminant model family: they try to find a combination of samples to build
a plane maximizing the margin between the two classes. Regularization is set by the C parameter: a small value for C
means the margin is calculated using many or all of the observations around the separating line (more regularization);
a large value for C means the margin is calculated on observations close to the separating line (less regularization).

Unregularized SVM Regularized SVM (default)

2.2. A tutorial on statistical-learning for scientific data processing 145


scikit-learn user guide, Release 0.20.3

Example:

• Plot different SVM classifiers in the iris dataset

SVMs can be used in regression –SVR (Support Vector Regression)–, or in classification –SVC (Support Vector Clas-
sification).

>>> from sklearn import svm


>>> svc = svm.SVC(kernel='linear')
>>> svc.fit(iris_X_train, iris_y_train)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
kernel='linear', max_iter=-1, probability=False, random_state=None,
shrinking=True, tol=0.001, verbose=False)

Warning: Normalizing data


For many estimators, including the SVMs, having datasets with unit standard deviation for each feature is important
to get good prediction.

Using kernels

Classes are not always linearly separable in feature space. The solution is to build a decision function that is not linear
but may be polynomial instead. This is done using the kernel trick that can be seen as creating a decision energy by
positioning kernels on observations:

Linear kernel Polynomial kernel

>>> svc = svm.SVC(kernel='linear') >>> svc = svm.SVC(kernel='poly',


... degree=3)
>>> # degree: polynomial degree

146 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

RBF kernel (Radial Basis Function)

>>> svc = svm.SVC(kernel='rbf')


>>> # gamma: inverse of size of
>>> # radial kernel

Interactive example

See the SVM GUI to download svm_gui.py; add data points of both classes with right and left button, fit the
model and change parameters and data.

2.2. A tutorial on statistical-learning for scientific data processing 147


scikit-learn user guide, Release 0.20.3

Exercise

Try classifying classes 1 and 2 from the iris dataset with SVMs, with the 2 first features. Leave out 10% of each
class and test prediction performance on these observations.
Warning: the classes are ordered, do not leave out the last 10%, you would be testing on only one class.
Hint: You can use the decision_function method on a grid to get intuitions.
iris = datasets.load_iris()
X = iris.data
y = iris.target

X = X[y != 0, :2]
y = y[y != 0]

Solution: ../../auto_examples/exercises/plot_iris_exercise.py

2.2.3 Model selection: choosing estimators and their parameters

Score, and cross-validated scores

As we have seen, every estimator exposes a score method that can judge the quality of the fit (or the prediction) on
new data. Bigger is better.

>>> from sklearn import datasets, svm


>>> digits = datasets.load_digits()
>>> X_digits = digits.data
>>> y_digits = digits.target
>>> svc = svm.SVC(C=1, kernel='linear')
>>> svc.fit(X_digits[:-100], y_digits[:-100]).score(X_digits[-100:], y_digits[-100:])
0.98

To get a better measure of prediction accuracy (which we can use as a proxy for goodness of fit of the model), we can
successively split the data in folds that we use for training and testing:

>>> import numpy as np


>>> X_folds = np.array_split(X_digits, 3)
>>> y_folds = np.array_split(y_digits, 3)
>>> scores = list()
>>> for k in range(3):
... # We use 'list' to copy, in order to 'pop' later on
... X_train = list(X_folds)
... X_test = X_train.pop(k)
... X_train = np.concatenate(X_train)
... y_train = list(y_folds)
... y_test = y_train.pop(k)
... y_train = np.concatenate(y_train)
... scores.append(svc.fit(X_train, y_train).score(X_test, y_test))
>>> print(scores)
[0.934..., 0.956..., 0.939...]

This is called a KFold cross-validation.

148 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

Cross-validation generators

Scikit-learn has a collection of classes which can be used to generate lists of train/test indices for popular cross-
validation strategies.
They expose a split method which accepts the input dataset to be split and yields the train/test set indices for each
iteration of the chosen cross-validation strategy.
This example shows an example usage of the split method.

>>> from sklearn.model_selection import KFold, cross_val_score


>>> X = ["a", "a", "a", "b", "b", "c", "c", "c", "c", "c"]
>>> k_fold = KFold(n_splits=5)
>>> for train_indices, test_indices in k_fold.split(X):
... print('Train: %s | test: %s' % (train_indices, test_indices))
Train: [2 3 4 5 6 7 8 9] | test: [0 1]
Train: [0 1 4 5 6 7 8 9] | test: [2 3]
Train: [0 1 2 3 6 7 8 9] | test: [4 5]
Train: [0 1 2 3 4 5 8 9] | test: [6 7]
Train: [0 1 2 3 4 5 6 7] | test: [8 9]

The cross-validation can then be performed easily:

>>> [svc.fit(X_digits[train], y_digits[train]).score(X_digits[test], y_digits[test])


... for train, test in k_fold.split(X_digits)]
[0.963..., 0.922..., 0.963..., 0.963..., 0.930...]

The cross-validation score can be directly calculated using the cross_val_score helper. Given an estimator, the
cross-validation object and the input dataset, the cross_val_score splits the data repeatedly into a training and a
testing set, trains the estimator using the training set and computes the scores based on the testing set for each iteration
of cross-validation.
By default the estimator’s score method is used to compute the individual scores.
Refer the metrics module to learn more on the available scoring methods.

>>> cross_val_score(svc, X_digits, y_digits, cv=k_fold, n_jobs=-1)


array([0.96388889, 0.92222222, 0.9637883 , 0.9637883 , 0.93036212])

n_jobs=-1 means that the computation will be dispatched on all the CPUs of the computer.
Alternatively, the scoring argument can be provided to specify an alternative scoring method.

>>> cross_val_score(svc, X_digits, y_digits, cv=k_fold,


... scoring='precision_macro')
array([0.96578289, 0.92708922, 0.96681476, 0.96362897, 0.93192644])

Cross-validation generators

KFold (n_splits, shuffle, ran- StratifiedKFold (n_splits, GroupKFold (n_splits)


dom_state) shuffle, random_state)
Splits it into K folds, trains on K-1 Same as K-Fold but preserves the Ensures that the same group is not in
and then tests on the left-out. class distribution within each fold. both testing and training sets.

2.2. A tutorial on statistical-learning for scientific data processing 149


scikit-learn user guide, Release 0.20.3

ShuffleSplit (n_splits, StratifiedShuffleSplit GroupShuffleSplit


test_size, train_size, ran-
dom_state)
Generates train/test indices based Same as shuffle split but preserves the Ensures that the same group is not
on random permutation. class distribution within each iteration. in both testing and training sets.

LeaveOneGroupOut () LeavePGroupsOut (n_groups) LeaveOneOut ()


Takes a group array to group observations. Leave P groups out. Leave one observation out.

LeavePOut (p) PredefinedSplit


Leave P observations out. Generates train/test indices based on predefined splits.

Exercise

On the digits dataset, plot the cross-validation


score of a SVC estimator with an linear kernel as a function of parameter C (use a logarithmic grid of points,
from 1 to 10).

import numpy as np
from sklearn.model_selection import cross_val_score
from sklearn import datasets, svm

digits = datasets.load_digits()
X = digits.data
y = digits.target

svc = svm.SVC(kernel='linear')
C_s = np.logspace(-10, 0, 10)

Solution: Cross-validation on Digits Dataset Exercise

150 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

Grid-search and cross-validated estimators

Grid-search

scikit-learn provides an object that, given data, computes the score during the fit of an estimator on a parameter grid and
chooses the parameters to maximize the cross-validation score. This object takes an estimator during the construction
and exposes an estimator API:

>>> from sklearn.model_selection import GridSearchCV, cross_val_score


>>> Cs = np.logspace(-6, -1, 10)
>>> clf = GridSearchCV(estimator=svc, param_grid=dict(C=Cs),
... n_jobs=-1)
>>> clf.fit(X_digits[:1000], y_digits[:1000])
GridSearchCV(cv=None,...
>>> clf.best_score_
0.925...
>>> clf.best_estimator_.C
0.0077...

>>> # Prediction performance on test set is not as good as on train set


>>> clf.score(X_digits[1000:], y_digits[1000:])
0.943...

By default, the GridSearchCV uses a 3-fold cross-validation. However, if it detects that a classifier is passed, rather
than a regressor, it uses a stratified 3-fold. The default will change to a 5-fold cross-validation in version 0.22.

Nested cross-validation

>>> cross_val_score(clf, X_digits, y_digits)


array([0.938..., 0.963..., 0.944...])

Two cross-validation loops are performed in parallel: one by the GridSearchCV estimator to set gamma and the
other one by cross_val_score to measure the prediction performance of the estimator. The resulting scores
are unbiased estimates of the prediction score on new data.

Warning: You cannot nest objects with parallel computing (n_jobs different than 1).

Cross-validated estimators

Cross-validation to set a parameter can be done more efficiently on an algorithm-by-algorithm basis. This is why, for
certain estimators, scikit-learn exposes Cross-validation: evaluating estimator performance estimators that set their
parameter automatically by cross-validation:

>>> from sklearn import linear_model, datasets


>>> lasso = linear_model.LassoCV(cv=3)
>>> diabetes = datasets.load_diabetes()
>>> X_diabetes = diabetes.data
>>> y_diabetes = diabetes.target
>>> lasso.fit(X_diabetes, y_diabetes)
LassoCV(alphas=None, copy_X=True, cv=3, eps=0.001, fit_intercept=True,
max_iter=1000, n_alphas=100, n_jobs=None, normalize=False,
positive=False, precompute='auto', random_state=None,

2.2. A tutorial on statistical-learning for scientific data processing 151


scikit-learn user guide, Release 0.20.3

selection='cyclic', tol=0.0001, verbose=False)


>>> # The estimator chose automatically its lambda:
>>> lasso.alpha_
0.01229...

These estimators are called similarly to their counterparts, with ‘CV’ appended to their name.

Exercise

On the diabetes dataset, find the optimal regularization parameter alpha.


Bonus: How much can you trust the selection of alpha?

from sklearn import datasets


from sklearn.linear_model import LassoCV
from sklearn.linear_model import Lasso
from sklearn.model_selection import KFold
from sklearn.model_selection import GridSearchCV

diabetes = datasets.load_diabetes()

Solution: Cross-validation on diabetes Dataset Exercise

2.2.4 Unsupervised learning: seeking representations of the data

Clustering: grouping observations together

The problem solved in clustering

Given the iris dataset, if we knew that there were 3 types of iris, but did not have access to a taxonomist to label
them: we could try a clustering task: split the observations into well-separated group called clusters.

K-means clustering

Note that there exist a lot of different clustering criteria and associated algorithms. The simplest clustering algorithm

is K-means.

152 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

>>> from sklearn import cluster, datasets


>>> iris = datasets.load_iris()
>>> X_iris = iris.data
>>> y_iris = iris.target

>>> k_means = cluster.KMeans(n_clusters=3)


>>> k_means.fit(X_iris)
KMeans(algorithm='auto', copy_x=True, init='k-means++', ...
>>> print(k_means.labels_[::10])
[1 1 1 1 1 0 0 0 0 0 2 2 2 2 2]
>>> print(y_iris[::10])
[0 0 0 0 0 1 1 1 1 1 2 2 2 2 2]

Warning: There is absolutely no guarantee of recovering a ground truth. First, choosing the right number of
clusters is hard. Second, the algorithm is sensitive to initialization, and can fall into local minima, although scikit-
learn employs several tricks to mitigate this issue.

Bad initialization 8 clusters Ground truth

Don’t over-interpret clustering results

Application example: vector quantization

Clustering in general and KMeans, in particular, can be seen as a way of choosing a small number of exemplars to
compress the information. The problem is sometimes known as vector quantization. For instance, this can be used
to posterize an image:
>>> import scipy as sp
>>> try:
... face = sp.face(gray=True)
... except AttributeError:
... from scipy import misc
... face = misc.face(gray=True)
>>> X = face.reshape((-1, 1)) # We need an (n_sample, n_feature) array
>>> k_means = cluster.KMeans(n_clusters=5, n_init=1)
>>> k_means.fit(X)
KMeans(algorithm='auto', copy_x=True, init='k-means++', ...
>>> values = k_means.cluster_centers_.squeeze()
>>> labels = k_means.labels_
>>> face_compressed = np.choose(labels, values)
>>> face_compressed.shape = face.shape

2.2. A tutorial on statistical-learning for scientific data processing 153


scikit-learn user guide, Release 0.20.3

Raw image K-means quantization Equal bins Image histogram

Hierarchical agglomerative clustering: Ward

A Hierarchical clustering method is a type of cluster analysis that aims to build a hierarchy of clusters. In general, the
various approaches of this technique are either:
• Agglomerative - bottom-up approaches: each observation starts in its own cluster, and clusters are iteratively
merged in such a way to minimize a linkage criterion. This approach is particularly interesting when the clus-
ters of interest are made of only a few observations. When the number of clusters is large, it is much more
computationally efficient than k-means.
• Divisive - top-down approaches: all observations start in one cluster, which is iteratively split as one moves
down the hierarchy. For estimating large numbers of clusters, this approach is both slow (due to all observations
starting as one cluster, which it splits recursively) and statistically ill-posed.

Connectivity-constrained clustering

With agglomerative clustering, it is possible to specify which samples can be clustered together by giving a connec-
tivity graph. Graphs in scikit-learn are represented by their adjacency matrix. Often, a sparse matrix is used. This
can be useful, for instance, to retrieve connected regions (sometimes also referred to as connected components) when

clustering an image:

import matplotlib.pyplot as plt

from skimage.data import coins


from skimage.transform import rescale

from sklearn.feature_extraction.image import grid_to_graph


from sklearn.cluster import AgglomerativeClustering

# #############################################################################
# Generate data

154 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

orig_coins = coins()

# Resize it to 20% of the original size to speed up the processing


# Applying a Gaussian filter for smoothing prior to down-scaling
# reduces aliasing artifacts.
smoothened_coins = gaussian_filter(orig_coins, sigma=2)
rescaled_coins = rescale(smoothened_coins, 0.2, mode="reflect")

X = np.reshape(rescaled_coins, (-1, 1))

# #############################################################################
# Define the structure A of the data. Pixels connected to their neighbors.
connectivity = grid_to_graph(*rescaled_coins.shape)

Feature agglomeration

We have seen that sparsity could be used to mitigate the curse of dimensionality, i.e an insufficient amount of ob-
servations compared to the number of features. Another approach is to merge together similar features: feature
agglomeration. This approach can be implemented by clustering in the feature direction, in other words clustering

the transposed data.

>>> digits = datasets.load_digits()


>>> images = digits.images
>>> X = np.reshape(images, (len(images), -1))
>>> connectivity = grid_to_graph(*images[0].shape)

>>> agglo = cluster.FeatureAgglomeration(connectivity=connectivity,


... n_clusters=32)
>>> agglo.fit(X)
FeatureAgglomeration(affinity='euclidean', compute_full_tree='auto',...
>>> X_reduced = agglo.transform(X)

>>> X_approx = agglo.inverse_transform(X_reduced)


>>> images_approx = np.reshape(X_approx, images.shape)

transform and inverse_transform methods

Some estimators expose a transform method, for instance to reduce the dimensionality of the dataset.

2.2. A tutorial on statistical-learning for scientific data processing 155


scikit-learn user guide, Release 0.20.3

Decompositions: from a signal to components and loadings

Components and loadings

If X is our multivariate data, then the problem that we are trying to solve is to rewrite it on a different observational
basis: we want to learn loadings L and a set of components C such that X = L C. Different criteria exist to choose
the components

Principal component analysis: PCA

Principal component analysis (PCA) selects the successive components that explain the maximum variance in the
signal.

The point cloud spanned by the observations above is very flat in one direction: one of the three univariate features
can almost be exactly computed using the other two. PCA finds the directions in which the data is not flat
When used to transform data, PCA can reduce the dimensionality of the data by projecting on a principal subspace.

>>> # Create a signal with only 2 useful dimensions


>>> x1 = np.random.normal(size=100)
>>> x2 = np.random.normal(size=100)
>>> x3 = x1 + x2
>>> X = np.c_[x1, x2, x3]

>>> from sklearn import decomposition


>>> pca = decomposition.PCA()
>>> pca.fit(X)
PCA(copy=True, iterated_power='auto', n_components=None, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)
>>> print(pca.explained_variance_)
[ 2.18565811e+00 1.19346747e+00 8.43026679e-32]

>>> # As we can see, only the 2 first components are useful


>>> pca.n_components = 2
>>> X_reduced = pca.fit_transform(X)
>>> X_reduced.shape
(100, 2)

156 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

Independent Component Analysis: ICA

Independent component analysis (ICA) selects components so that the distribution of their loadings carries
a maximum amount of independent information. It is able to recover non-Gaussian independent signals:

>>> # Generate sample data


>>> import numpy as np
>>> from scipy import signal
>>> time = np.linspace(0, 10, 2000)
>>> s1 = np.sin(2 * time) # Signal 1 : sinusoidal signal
>>> s2 = np.sign(np.sin(3 * time)) # Signal 2 : square signal
>>> s3 = signal.sawtooth(2 * np.pi * time) # Signal 3: saw tooth signal
>>> S = np.c_[s1, s2, s3]
>>> S += 0.2 * np.random.normal(size=S.shape) # Add noise
>>> S /= S.std(axis=0) # Standardize data
>>> # Mix data
>>> A = np.array([[1, 1, 1], [0.5, 2, 1], [1.5, 1, 2]]) # Mixing matrix
>>> X = np.dot(S, A.T) # Generate observations

>>> # Compute ICA


>>> ica = decomposition.FastICA()
>>> S_ = ica.fit_transform(X) # Get the estimated sources
>>> A_ = ica.mixing_.T
>>> np.allclose(X, np.dot(S_, A_) + ica.mean_)
True

2.2. A tutorial on statistical-learning for scientific data processing 157


scikit-learn user guide, Release 0.20.3

2.2.5 Putting it all together

Pipelining

We have seen that some estimators can transform data and that some estimators can predict variables. We can also

create combined estimators:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

from sklearn import datasets


from sklearn.decomposition import PCA
from sklearn.linear_model import SGDClassifier
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV

# Define a pipeline to search for the best combination of PCA truncation


# and classifier regularization.
logistic = SGDClassifier(loss='log', penalty='l2', early_stopping=True,
max_iter=10000, tol=1e-5, random_state=0)
pca = PCA()
pipe = Pipeline(steps=[('pca', pca), ('logistic', logistic)])

digits = datasets.load_digits()
X_digits = digits.data
y_digits = digits.target

# Parameters of pipelines can be set using ‘__’ separated parameter names:


param_grid = {
'pca__n_components': [5, 20, 30, 40, 50, 64],
'logistic__alpha': np.logspace(-4, 4, 5),

158 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

}
search = GridSearchCV(pipe, param_grid, iid=False, cv=5,
return_train_score=False)
search.fit(X_digits, y_digits)
print("Best parameter (CV score=%0.3f):" % search.best_score_)
print(search.best_params_)

# Plot the PCA spectrum


pca.fit(X_digits)

fig, (ax0, ax1) = plt.subplots(nrows=2, sharex=True, figsize=(6, 6))


ax0.plot(pca.explained_variance_ratio_, linewidth=2)
ax0.set_ylabel('PCA explained variance')

ax0.axvline(search.best_estimator_.named_steps['pca'].n_components,

Face recognition with eigenfaces

The dataset used in this example is a preprocessed excerpt of the “Labeled Faces in the Wild”, also known as LFW:
http://vis-www.cs.umass.edu/lfw/lfw-funneled.tgz (233MB)
"""
===================================================
Faces recognition example using eigenfaces and SVMs
===================================================

The dataset used in this example is a preprocessed excerpt of the


"Labeled Faces in the Wild", aka LFW_:

http://vis-www.cs.umass.edu/lfw/lfw-funneled.tgz (233MB)

.. _LFW: http://vis-www.cs.umass.edu/lfw/

Expected results for the top 5 most represented people in the dataset:

================== ============ ======= ========== =======


precision recall f1-score support
================== ============ ======= ========== =======
Ariel Sharon 0.67 0.92 0.77 13
Colin Powell 0.75 0.78 0.76 60
Donald Rumsfeld 0.78 0.67 0.72 27
George W Bush 0.86 0.86 0.86 146
Gerhard Schroeder 0.76 0.76 0.76 25
Hugo Chavez 0.67 0.67 0.67 15
Tony Blair 0.81 0.69 0.75 36

avg / total 0.80 0.80 0.80 322


================== ============ ======= ========== =======

"""
from __future__ import print_function

from time import time


import logging
import matplotlib.pyplot as plt

2.2. A tutorial on statistical-learning for scientific data processing 159


scikit-learn user guide, Release 0.20.3

from sklearn.model_selection import train_test_split


from sklearn.model_selection import GridSearchCV
from sklearn.datasets import fetch_lfw_people
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import PCA
from sklearn.svm import SVC

print(__doc__)

# Display progress logs on stdout


logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')

# #############################################################################
# Download the data, if not already on disk and load it as numpy arrays

lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4)

# introspect the images arrays to find the shapes (for plotting)


n_samples, h, w = lfw_people.images.shape

# for machine learning we use the 2 data directly (as relative pixel
# positions info is ignored by this model)
X = lfw_people.data
n_features = X.shape[1]

# the label to predict is the id of the person


y = lfw_people.target
target_names = lfw_people.target_names
n_classes = target_names.shape[0]

print("Total dataset size:")


print("n_samples: %d" % n_samples)
print("n_features: %d" % n_features)
print("n_classes: %d" % n_classes)

# #############################################################################
# Split into a training set and a test set using a stratified k fold

# split into a training and testing set


X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42)

# #############################################################################
# Compute a PCA (eigenfaces) on the face dataset (treated as unlabeled
# dataset): unsupervised feature extraction / dimensionality reduction
n_components = 150

print("Extracting the top %d eigenfaces from %d faces"


% (n_components, X_train.shape[0]))
t0 = time()
pca = PCA(n_components=n_components, svd_solver='randomized',
whiten=True).fit(X_train)
print("done in %0.3fs" % (time() - t0))

160 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

eigenfaces = pca.components_.reshape((n_components, h, w))

print("Projecting the input data on the eigenfaces orthonormal basis")


t0 = time()
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
print("done in %0.3fs" % (time() - t0))

# #############################################################################
# Train a SVM classification model

print("Fitting the classifier to the training set")


t0 = time()
param_grid = {'C': [1e3, 5e3, 1e4, 5e4, 1e5],
'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1], }
clf = GridSearchCV(SVC(kernel='rbf', class_weight='balanced'),
param_grid, cv=5)
clf = clf.fit(X_train_pca, y_train)
print("done in %0.3fs" % (time() - t0))
print("Best estimator found by grid search:")
print(clf.best_estimator_)

# #############################################################################
# Quantitative evaluation of the model quality on the test set

print("Predicting people's names on the test set")


t0 = time()
y_pred = clf.predict(X_test_pca)
print("done in %0.3fs" % (time() - t0))

print(classification_report(y_test, y_pred, target_names=target_names))


print(confusion_matrix(y_test, y_pred, labels=range(n_classes)))

# #############################################################################
# Qualitative evaluation of the predictions using matplotlib

def plot_gallery(images, titles, h, w, n_row=3, n_col=4):


"""Helper function to plot a gallery of portraits"""
plt.figure(figsize=(1.8 * n_col, 2.4 * n_row))
plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
for i in range(n_row * n_col):
plt.subplot(n_row, n_col, i + 1)
plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)
plt.title(titles[i], size=12)
plt.xticks(())
plt.yticks(())

# plot the result of the prediction on a portion of the test set

def title(y_pred, y_test, target_names, i):


pred_name = target_names[y_pred[i]].rsplit(' ', 1)[-1]
true_name = target_names[y_test[i]].rsplit(' ', 1)[-1]
return 'predicted: %s\ntrue: %s' % (pred_name, true_name)

2.2. A tutorial on statistical-learning for scientific data processing 161


scikit-learn user guide, Release 0.20.3

prediction_titles = [title(y_pred, y_test, target_names, i)


for i in range(y_pred.shape[0])]

plot_gallery(X_test, prediction_titles, h, w)

# plot the gallery of the most significative eigenfaces

eigenface_titles = ["eigenface %d" % i for i in range(eigenfaces.shape[0])]


plot_gallery(eigenfaces, eigenface_titles, h, w)

plt.show()

Prediction Eigenfaces

Expected results for the top 5 most represented people in the dataset:

precision recall f1-score support

Gerhard_Schroeder 0.91 0.75 0.82 28


Donald_Rumsfeld 0.84 0.82 0.83 33
Tony_Blair 0.65 0.82 0.73 34
Colin_Powell 0.78 0.88 0.83 58
George_W_Bush 0.93 0.86 0.90 129

avg / total 0.86 0.84 0.85 282

Open problem: Stock Market Structure

Can we predict the variation in stock prices for Google over a given time frame?
Learning a graph structure

162 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

2.2.6 Finding help

The project mailing list

If you encounter a bug with scikit-learn or something that needs clarification in the docstring or the online
documentation, please feel free to ask on the Mailing List

Q&A communities with Machine Learning practitioners

Quora.com Quora has a topic for Machine Learning related questions that also features some
interesting discussions: https://www.quora.com/topic/Machine-Learning
Stack Exchange The Stack Exchange family of sites hosts multiple subdomains for Machine
Learning questions.
– _’An excellent free online course for Machine Learning taught by Professor Andrew Ng of Stanford’: https://www.
coursera.org/learn/machine-learning
– _’Another excellent free online course that takes a more general approach to Artificial Intelligence’:
https://www.udacity.com/course/intro-to-artificial-intelligence–cs271

2.3 Working With Text Data

The goal of this guide is to explore some of the main scikit-learn tools on a single practical task: analyzing a
collection of text documents (newsgroups posts) on twenty different topics.
In this section we will see how to:
• load the file contents and the categories
• extract feature vectors suitable for machine learning
• train a linear model to perform categorization
• use a grid search strategy to find a good configuration of both the feature extraction components and the classifier

2.3.1 Tutorial setup

To get started with this tutorial, you must first install scikit-learn and all of its required dependencies.
Please refer to the installation instructions page for more information and for system-specific instructions.
The source of this tutorial can be found within your scikit-learn folder:

scikit-learn/doc/tutorial/text_analytics/

The source can also be found on Github.


The tutorial folder should contain the following sub-folders:
• *.rst files - the source of the tutorial document written with sphinx
• data - folder to put the datasets used during the tutorial
• skeletons - sample incomplete scripts for the exercises
• solutions - solutions of the exercises

2.3. Working With Text Data 163


scikit-learn user guide, Release 0.20.3

You can already copy the skeletons into a new folder somewhere on your hard-drive named
sklearn_tut_workspace where you will edit your own files for the exercises while keeping the original
skeletons intact:

% cp -r skeletons work_directory/sklearn_tut_workspace

Machine learning algorithms need data. Go to each $TUTORIAL_HOME/data sub-folder and run the
fetch_data.py script from there (after having read them first).
For instance:

% cd $TUTORIAL_HOME/data/languages
% less fetch_data.py
% python fetch_data.py

2.3.2 Loading the 20 newsgroups dataset

The dataset is called “Twenty Newsgroups”. Here is the official description, quoted from the website:
The 20 Newsgroups data set is a collection of approximately 20,000 newsgroup documents, partitioned
(nearly) evenly across 20 different newsgroups. To the best of our knowledge, it was originally collected
by Ken Lang, probably for his paper “Newsweeder: Learning to filter netnews,” though he does not explic-
itly mention this collection. The 20 newsgroups collection has become a popular data set for experiments
in text applications of machine learning techniques, such as text classification and text clustering.
In the following we will use the built-in dataset loader for 20 newsgroups from scikit-learn. Alternatively, it is possible
to download the dataset manually from the website and use the sklearn.datasets.load_files function by
pointing it to the 20news-bydate-train sub-folder of the uncompressed archive folder.
In order to get faster execution times for this first example we will work on a partial dataset with only 4 categories out
of the 20 available in the dataset:

>>> categories = ['alt.atheism', 'soc.religion.christian',


... 'comp.graphics', 'sci.med']

We can now load the list of files matching those categories as follows:

>>> from sklearn.datasets import fetch_20newsgroups


>>> twenty_train = fetch_20newsgroups(subset='train',
... categories=categories, shuffle=True, random_state=42)

The returned dataset is a scikit-learn “bunch”: a simple holder object with fields that can be both accessed
as python dict keys or object attributes for convenience, for instance the target_names holds the list of the
requested category names:

>>> twenty_train.target_names
['alt.atheism', 'comp.graphics', 'sci.med', 'soc.religion.christian']

The files themselves are loaded in memory in the data attribute. For reference the filenames are also available:

>>> len(twenty_train.data)
2257
>>> len(twenty_train.filenames)
2257

Let’s print the first lines of the first loaded file:

164 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

>>> print("\n".join(twenty_train.data[0].split("\n")[:3]))
From: [email protected] (Michael Collier)
Subject: Converting images to HP LaserJet III?
Nntp-Posting-Host: hampton

>>> print(twenty_train.target_names[twenty_train.target[0]])
comp.graphics

Supervised learning algorithms will require a category label for each document in the training set. In this case the cat-
egory is the name of the newsgroup which also happens to be the name of the folder holding the individual documents.
For speed and space efficiency reasons scikit-learn loads the target attribute as an array of integers that corre-
sponds to the index of the category name in the target_names list. The category integer id of each sample is stored
in the target attribute:

>>> twenty_train.target[:10]
array([1, 1, 3, 3, 3, 3, 3, 2, 2, 2])

It is possible to get back the category names as follows:

>>> for t in twenty_train.target[:10]:


... print(twenty_train.target_names[t])
...
comp.graphics
comp.graphics
soc.religion.christian
soc.religion.christian
soc.religion.christian
soc.religion.christian
soc.religion.christian
sci.med
sci.med
sci.med

You might have noticed that the samples were shuffled randomly when we called fetch_20newsgroups(...,
shuffle=True, random_state=42): this is useful if you wish to select only a subset of samples to quickly
train a model and get a first idea of the results before re-training on the complete dataset later.

2.3.3 Extracting features from text files

In order to perform machine learning on text documents, we first need to turn the text content into numerical feature
vectors.

Bags of words

The most intuitive way to do so is to use a bags of words representation:


1. Assign a fixed integer id to each word occurring in any document of the training set (for instance by building a
dictionary from words to integer indices).
2. For each document #i, count the number of occurrences of each word w and store it in X[i, j] as the value
of feature #j where j is the index of word w in the dictionary.
The bags of words representation implies that n_features is the number of distinct words in the corpus: this
number is typically larger than 100,000.

2.3. Working With Text Data 165


scikit-learn user guide, Release 0.20.3

If n_samples == 10000, storing X as a NumPy array of type float32 would require 10000 x 100000 x 4 bytes =
4GB in RAM which is barely manageable on today’s computers.
Fortunately, most values in X will be zeros since for a given document less than a few thousand distinct words will
be used. For this reason we say that bags of words are typically high-dimensional sparse datasets. We can save a lot
of memory by only storing the non-zero parts of the feature vectors in memory.
scipy.sparse matrices are data structures that do exactly this, and scikit-learn has built-in support for these
structures.

Tokenizing text with scikit-learn

Text preprocessing, tokenizing and filtering of stopwords are all included in CountVectorizer, which builds a
dictionary of features and transforms documents to feature vectors:

>>> from sklearn.feature_extraction.text import CountVectorizer


>>> count_vect = CountVectorizer()
>>> X_train_counts = count_vect.fit_transform(twenty_train.data)
>>> X_train_counts.shape
(2257, 35788)

CountVectorizer supports counts of N-grams of words or consecutive characters. Once fitted, the vectorizer has
built a dictionary of feature indices:

>>> count_vect.vocabulary_.get(u'algorithm')
4690

The index value of a word in the vocabulary is linked to its frequency in the whole training corpus.

From occurrences to frequencies

Occurrence count is a good start but there is an issue: longer documents will have higher average count values than
shorter documents, even though they might talk about the same topics.
To avoid these potential discrepancies it suffices to divide the number of occurrences of each word in a document by
the total number of words in the document: these new features are called tf for Term Frequencies.
Another refinement on top of tf is to downscale weights for words that occur in many documents in the corpus and are
therefore less informative than those that occur only in a smaller portion of the corpus.
This downscaling is called tf–idf for “Term Frequency times Inverse Document Frequency”.
Both tf and tf–idf can be computed as follows using TfidfTransformer:

>>> from sklearn.feature_extraction.text import TfidfTransformer


>>> tf_transformer = TfidfTransformer(use_idf=False).fit(X_train_counts)
>>> X_train_tf = tf_transformer.transform(X_train_counts)
>>> X_train_tf.shape
(2257, 35788)

In the above example-code, we firstly use the fit(..) method to fit our estimator to the data and secondly the
transform(..) method to transform our count-matrix to a tf-idf representation. These two steps can be com-
bined to achieve the same end result faster by skipping redundant processing. This is done through using the
fit_transform(..) method as shown below, and as mentioned in the note in the previous section:

166 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

>>> tfidf_transformer = TfidfTransformer()


>>> X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)
>>> X_train_tfidf.shape
(2257, 35788)

2.3.4 Training a classifier

Now that we have our features, we can train a classifier to try to predict the category of a post. Let’s start with a
naïve Bayes classifier, which provides a nice baseline for this task. scikit-learn includes several variants of this
classifier; the one most suitable for word counts is the multinomial variant:

>>> from sklearn.naive_bayes import MultinomialNB


>>> clf = MultinomialNB().fit(X_train_tfidf, twenty_train.target)

To try to predict the outcome on a new document we need to extract the features using almost the same feature extract-
ing chain as before. The difference is that we call transform instead of fit_transform on the transformers,
since they have already been fit to the training set:

>>> docs_new = ['God is love', 'OpenGL on the GPU is fast']


>>> X_new_counts = count_vect.transform(docs_new)
>>> X_new_tfidf = tfidf_transformer.transform(X_new_counts)

>>> predicted = clf.predict(X_new_tfidf)

>>> for doc, category in zip(docs_new, predicted):


... print('%r => %s' % (doc, twenty_train.target_names[category]))
...
'God is love' => soc.religion.christian
'OpenGL on the GPU is fast' => comp.graphics

2.3.5 Building a pipeline

In order to make the vectorizer => transformer => classifier easier to work with, scikit-learn provides a
Pipeline class that behaves like a compound classifier:

>>> from sklearn.pipeline import Pipeline


>>> text_clf = Pipeline([
... ('vect', CountVectorizer()),
... ('tfidf', TfidfTransformer()),
... ('clf', MultinomialNB()),
... ])

The names vect, tfidf and clf (classifier) are arbitrary. We will use them to perform grid search for suitable
hyperparameters below. We can now train the model with a single command:

>>> text_clf.fit(twenty_train.data, twenty_train.target)


Pipeline(...)

2.3.6 Evaluation of the performance on the test set

Evaluating the predictive accuracy of the model is equally easy:

2.3. Working With Text Data 167


scikit-learn user guide, Release 0.20.3

>>> import numpy as np


>>> twenty_test = fetch_20newsgroups(subset='test',
... categories=categories, shuffle=True, random_state=42)
>>> docs_test = twenty_test.data
>>> predicted = text_clf.predict(docs_test)
>>> np.mean(predicted == twenty_test.target)
0.8348...

We achieved 83.5% accuracy. Let’s see if we can do better with a linear support vector machine (SVM), which is
widely regarded as one of the best text classification algorithms (although it’s also a bit slower than naïve Bayes). We
can change the learner by simply plugging a different classifier object into our pipeline:

>>> from sklearn.linear_model import SGDClassifier


>>> text_clf = Pipeline([
... ('vect', CountVectorizer()),
... ('tfidf', TfidfTransformer()),
... ('clf', SGDClassifier(loss='hinge', penalty='l2',
... alpha=1e-3, random_state=42,
... max_iter=5, tol=None)),
... ])

>>> text_clf.fit(twenty_train.data, twenty_train.target)


Pipeline(...)
>>> predicted = text_clf.predict(docs_test)
>>> np.mean(predicted == twenty_test.target)
0.9127...

We achieved 91.3% accuracy using the SVM. scikit-learn provides further utilities for more detailed perfor-
mance analysis of the results:

>>> from sklearn import metrics


>>> print(metrics.classification_report(twenty_test.target, predicted,
... target_names=twenty_test.target_names))
...
precision recall f1-score support

alt.atheism 0.95 0.81 0.87 319


comp.graphics 0.88 0.97 0.92 389
sci.med 0.94 0.90 0.92 396
soc.religion.christian 0.90 0.95 0.93 398

micro avg 0.91 0.91 0.91 1502


macro avg 0.92 0.91 0.91 1502
weighted avg 0.92 0.91 0.91 1502

>>> metrics.confusion_matrix(twenty_test.target, predicted)


array([[258, 11, 15, 35],
[ 4, 379, 3, 3],
[ 5, 33, 355, 3],
[ 5, 10, 4, 379]])

As expected the confusion matrix shows that posts from the newsgroups on atheism and Christianity are more often
confused for one another than with computer graphics.

168 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

2.3.7 Parameter tuning using grid search

We’ve already encountered some parameters such as use_idf in the TfidfTransformer. Classifiers tend to have
many parameters as well; e.g., MultinomialNB includes a smoothing parameter alpha and SGDClassifier
has a penalty parameter alpha and configurable loss and penalty terms in the objective function (see the module
documentation, or use the Python help function to get a description of these).
Instead of tweaking the parameters of the various components of the chain, it is possible to run an exhaustive search of
the best parameters on a grid of possible values. We try out all classifiers on either words or bigrams, with or without
idf, and with a penalty parameter of either 0.01 or 0.001 for the linear SVM:

>>> from sklearn.model_selection import GridSearchCV


>>> parameters = {
... 'vect__ngram_range': [(1, 1), (1, 2)],
... 'tfidf__use_idf': (True, False),
... 'clf__alpha': (1e-2, 1e-3),
... }

Obviously, such an exhaustive search can be expensive. If we have multiple CPU cores at our disposal, we can tell
the grid searcher to try these eight parameter combinations in parallel with the n_jobs parameter. If we give this
parameter a value of -1, grid search will detect how many cores are installed and use them all:

>>> gs_clf = GridSearchCV(text_clf, parameters, cv=5, iid=False, n_jobs=-1)

The grid search instance behaves like a normal scikit-learn model. Let’s perform the search on a smaller subset
of the training data to speed up the computation:

>>> gs_clf = gs_clf.fit(twenty_train.data[:400], twenty_train.target[:400])

The result of calling fit on a GridSearchCV object is a classifier that we can use to predict:

>>> twenty_train.target_names[gs_clf.predict(['God is love'])[0]]


'soc.religion.christian'

The object’s best_score_ and best_params_ attributes store the best mean score and the parameters setting
corresponding to that score:

>>> gs_clf.best_score_
0.9...
>>> for param_name in sorted(parameters.keys()):
... print("%s: %r" % (param_name, gs_clf.best_params_[param_name]))
...
clf__alpha: 0.001
tfidf__use_idf: True
vect__ngram_range: (1, 2)

A more detailed summary of the search is available at gs_clf.cv_results_.


The cv_results_ parameter can be easily imported into pandas as a DataFrame for further inspection.

Exercises

To do the exercises, copy the content of the ‘skeletons’ folder as a new folder named ‘workspace’:

% cp -r skeletons workspace

2.3. Working With Text Data 169


scikit-learn user guide, Release 0.20.3

You can then edit the content of the workspace without fear of losing the original exercise instructions.
Then fire an ipython shell and run the work-in-progress script with:

[1] %run workspace/exercise_XX_script.py arg1 arg2 arg3

If an exception is triggered, use %debug to fire-up a post mortem ipdb session.


Refine the implementation and iterate until the exercise is solved.
For each exercise, the skeleton file provides all the necessary import statements, boilerplate code to load the
data and sample code to evaluate the predictive accuracy of the model.

2.3.8 Exercise 1: Language identification

• Write a text classification pipeline using a custom preprocessor and CharNGramAnalyzer using data from
Wikipedia articles as training set.
• Evaluate the performance on some held out test set.
ipython command line:

%run workspace/exercise_01_language_train_model.py data/languages/paragraphs/

2.3.9 Exercise 2: Sentiment Analysis on movie reviews

• Write a text classification pipeline to classify movie reviews as either positive or negative.
• Find a good set of parameters using grid search.
• Evaluate the performance on a held out test set.
ipython command line:

%run workspace/exercise_02_sentiment.py data/movie_reviews/txt_sentoken/

2.3.10 Exercise 3: CLI text classification utility

Using the results of the previous exercises and the cPickle module of the standard library, write a command line
utility that detects the language of some text provided on stdin and estimate the polarity (positive or negative) if the
text is written in English.
Bonus point if the utility is able to give a confidence level for its predictions.

2.3.11 Where to from here

Here are a few suggestions to help further your scikit-learn intuition upon the completion of this tutorial:
• Try playing around with the analyzer and token normalisation under CountVectorizer.
• If you don’t have labels, try using Clustering on your problem.
• If you have multiple labels per document, e.g categories, have a look at the Multiclass and multilabel section.
• Try using Truncated SVD for latent semantic analysis.

170 Chapter 2. scikit-learn Tutorials


scikit-learn user guide, Release 0.20.3

• Have a look at using Out-of-core Classification to learn from data that would not fit into the computer main
memory.
• Have a look at the Hashing Vectorizer as a memory efficient alternative to CountVectorizer.

2.4 Choosing the right estimator

Often the hardest part of solving a machine learning problem can be finding the right estimator for the job.
Different estimators are better suited for different types of data and different problems.
The flowchart below is designed to give users a bit of a rough guide on how to approach problems with regard to which
estimators to try on your data.
Click on any estimator in the chart below to see its documentation.

2.5 External Resources, Videos and Talks

For written tutorials, see the Tutorial section of the documentation.

2.5.1 New to Scientific Python?

For those that are still new to the scientific Python ecosystem, we highly recommend the Python Scientific Lecture
Notes. This will help you find your footing a bit and will definitely improve your scikit-learn experience. A basic
understanding of NumPy arrays is recommended to make the most of scikit-learn.

2.5.2 External Tutorials

There are several online tutorials available which are geared toward specific subject areas:
• Machine Learning for NeuroImaging in Python
• Machine Learning for Astronomical Data Analysis

2.5.3 Videos

• An introduction to scikit-learn Part I and Part II at Scipy 2013 by Gael Varoquaux, Jake Vanderplas and Olivier
Grisel. Notebooks on github.
• Introduction to scikit-learn by Gael Varoquaux at ICML 2010
A three minute video from a very early stage of scikit-learn, explaining the basic idea and approach
we are following.
• Introduction to statistical learning with scikit-learn by Gael Varoquaux at SciPy 2011
An extensive tutorial, consisting of four sessions of one hour. The tutorial covers the basics of ma-
chine learning, many algorithms and how to apply them using scikit-learn. The material correspond-
ing is now in the scikit-learn documentation section A tutorial on statistical-learning for scientific
data processing.
• Statistical Learning for Text Classification with scikit-learn and NLTK (and slides) by Olivier Grisel at PyCon
2011

2.4. Choosing the right estimator 171


scikit-learn user guide, Release 0.20.3

Thirty minute introduction to text classification. Explains how to use NLTK and scikit-learn to solve
real-world text classification tasks and compares against cloud-based solutions.
• Introduction to Interactive Predictive Analytics in Python with scikit-learn by Olivier Grisel at PyCon 2012
3-hours long introduction to prediction tasks using scikit-learn.
• scikit-learn - Machine Learning in Python by Jake Vanderplas at the 2012 PyData workshop at Google
Interactive demonstration of some scikit-learn features. 75 minutes.
• scikit-learn tutorial by Jake Vanderplas at PyData NYC 2012
Presentation using the online tutorial, 45 minutes.

Note: Doctest Mode


The code-examples in the above tutorials are written in a python-console format. If you wish to easily execute these
examples in IPython, use:

%doctest_mode

in the IPython-console. You can then simply copy and paste the examples directly into IPython without having to
worry about removing the >>> manually.

172 Chapter 2. scikit-learn Tutorials


CHAPTER

THREE

USER GUIDE

3.1 Supervised learning

3.1.1 Generalized Linear Models

The following are a set of methods intended for regression in which the target value is expected to be a linear combi-
nation of the input variables. In mathematical notion, if 𝑦ˆ is the predicted value.

𝑦ˆ(𝑤, 𝑥) = 𝑤0 + 𝑤1 𝑥1 + ... + 𝑤𝑝 𝑥𝑝

Across the module, we designate the vector 𝑤 = (𝑤1 , ..., 𝑤𝑝 ) as coef_ and 𝑤0 as intercept_.
To perform classification with generalized linear models, see Logistic regression.

Ordinary Least Squares

LinearRegression fits a linear model with coefficients 𝑤 = (𝑤1 , ..., 𝑤𝑝 ) to minimize the residual sum of squares
between the observed responses in the dataset, and the responses predicted by the linear approximation. Mathemati-
cally it solves a problem of the form:
2
min ||𝑋𝑤 − 𝑦||2
𝑤

LinearRegression will take in its fit method arrays X, y and will store the coefficients 𝑤 of the linear model
in its coef_ member:

173
scikit-learn user guide, Release 0.20.3

>>> from sklearn import linear_model


>>> reg = linear_model.LinearRegression()
>>> reg.fit([[0, 0], [1, 1], [2, 2]], [0, 1, 2])
...
LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None,
normalize=False)
>>> reg.coef_
array([0.5, 0.5])

However, coefficient estimates for Ordinary Least Squares rely on the independence of the model terms. When terms
are correlated and the columns of the design matrix 𝑋 have an approximate linear dependence, the design matrix
becomes close to singular and as a result, the least-squares estimate becomes highly sensitive to random errors in the
observed response, producing a large variance. This situation of multicollinearity can arise, for example, when data
are collected without an experimental design.

Examples:

• Linear Regression Example

Ordinary Least Squares Complexity

This method computes the least squares solution using a singular value decomposition of X. If X is a matrix of size (n,
p) this method has a cost of 𝑂(𝑛𝑝2 ), assuming that 𝑛 ≥ 𝑝.

Ridge Regression

Ridge regression addresses some of the problems of Ordinary Least Squares by imposing a penalty on the size of
coefficients. The ridge coefficients minimize a penalized residual sum of squares,
2 2
min ||𝑋𝑤 − 𝑦||2 + 𝛼||𝑤||2
𝑤

Here, 𝛼 ≥ 0 is a complexity parameter that controls the amount of shrinkage: the larger the value of 𝛼, the greater the
amount of shrinkage and thus the coefficients become more robust to collinearity.

As with other linear models, Ridge will take in its fit method arrays X, y and will store the coefficients 𝑤 of the
linear model in its coef_ member:

174 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

>>> from sklearn import linear_model


>>> reg = linear_model.Ridge(alpha=.5)
>>> reg.fit([[0, 0], [0, 0], [1, 1]], [0, .1, 1])
Ridge(alpha=0.5, copy_X=True, fit_intercept=True, max_iter=None,
normalize=False, random_state=None, solver='auto', tol=0.001)
>>> reg.coef_
array([0.34545455, 0.34545455])
>>> reg.intercept_
0.13636...

Examples:

• Plot Ridge coefficients as a function of the regularization


• Classification of text documents using sparse features

Ridge Complexity

This method has the same order of complexity than an Ordinary Least Squares.

Setting the regularization parameter: generalized Cross-Validation

RidgeCV implements ridge regression with built-in cross-validation of the alpha parameter. The object works in
the same way as GridSearchCV except that it defaults to Generalized Cross-Validation (GCV), an efficient form of
leave-one-out cross-validation:

>>> from sklearn import linear_model


>>> reg = linear_model.RidgeCV(alphas=[0.1, 1.0, 10.0], cv=3)
>>> reg.fit([[0, 0], [0, 0], [1, 1]], [0, .1, 1])
RidgeCV(alphas=[0.1, 1.0, 10.0], cv=3, fit_intercept=True, scoring=None,
normalize=False)
>>> reg.alpha_
0.1

References

• “Notes on Regularized Least Squares”, Rifkin & Lippert (technical report, course slides).

Lasso

The Lasso is a linear model that estimates sparse coefficients. It is useful in some contexts due to its tendency
to prefer solutions with fewer parameter values, effectively reducing the number of variables upon which the given
solution is dependent. For this reason, the Lasso and its variants are fundamental to the field of compressed sensing.
Under certain conditions, it can recover the exact set of non-zero weights (see Compressive sensing: tomography
reconstruction with L1 prior (Lasso)).
Mathematically, it consists of a linear model trained with ℓ1 prior as regularizer. The objective function to minimize

3.1. Supervised learning 175


scikit-learn user guide, Release 0.20.3

is:
1
min ||𝑋𝑤 − 𝑦||22 + 𝛼||𝑤||1
𝑤 2𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠

The lasso estimate thus solves the minimization of the least-squares penalty with 𝛼||𝑤||1 added, where 𝛼 is a constant
and ||𝑤||1 is the ℓ1 -norm of the parameter vector.
The implementation in the class Lasso uses coordinate descent as the algorithm to fit the coefficients. See Least
Angle Regression for another implementation:

>>> from sklearn import linear_model


>>> reg = linear_model.Lasso(alpha=0.1)
>>> reg.fit([[0, 0], [1, 1]], [0, 1])
Lasso(alpha=0.1, copy_X=True, fit_intercept=True, max_iter=1000,
normalize=False, positive=False, precompute=False, random_state=None,
selection='cyclic', tol=0.0001, warm_start=False)
>>> reg.predict([[1, 1]])
array([0.8])

Also useful for lower-level tasks is the function lasso_path that computes the coefficients along the full path of
possible values.

Examples:

• Lasso and Elastic Net for Sparse Signals


• Compressive sensing: tomography reconstruction with L1 prior (Lasso)

Note: Feature selection with Lasso


As the Lasso regression yields sparse models, it can thus be used to perform feature selection, as detailed in L1-based
feature selection.

The following two references explain the iterations used in the coordinate descent solver of scikit-learn, as well as the
duality gap computation used for convergence control.

References

• “Regularization Path For Generalized linear Models by Coordinate Descent”, Friedman, Hastie & Tibshirani,
J Stat Softw, 2010 (Paper).
• “An Interior-Point Method for Large-Scale L1-Regularized Least Squares,” S. J. Kim, K. Koh, M. Lustig, S.
Boyd and D. Gorinevsky, in IEEE Journal of Selected Topics in Signal Processing, 2007 (Paper)

Setting regularization parameter

The alpha parameter controls the degree of sparsity of the coefficients estimated.

176 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Using cross-validation

scikit-learn exposes objects that set the Lasso alpha parameter by cross-validation: LassoCV and LassoLarsCV .
LassoLarsCV is based on the Least Angle Regression algorithm explained below.
For high-dimensional datasets with many collinear regressors, LassoCV is most often preferable. However,
LassoLarsCV has the advantage of exploring more relevant values of alpha parameter, and if the number of samples
is very small compared to the number of features, it is often faster than LassoCV .

Information-criteria based model selection

Alternatively, the estimator LassoLarsIC proposes to use the Akaike information criterion (AIC) and the Bayes
Information criterion (BIC). It is a computationally cheaper alternative to find the optimal value of alpha as the regu-
larization path is computed only once instead of k+1 times when using k-fold cross-validation. However, such criteria
needs a proper estimation of the degrees of freedom of the solution, are derived for large samples (asymptotic results)
and assume the model is correct, i.e. that the data are actually generated by this model. They also tend to break when
the problem is badly conditioned (more features than samples).

Examples:

• Lasso model selection: Cross-Validation / AIC / BIC

3.1. Supervised learning 177


scikit-learn user guide, Release 0.20.3

Comparison with the regularization parameter of SVM

The equivalence between alpha and the regularization parameter of SVM, C is given by alpha = 1 / C or
alpha = 1 / (n_samples * C), depending on the estimator and the exact objective function optimized by
the model.

Multi-task Lasso

The MultiTaskLasso is a linear model that estimates sparse coefficients for multiple regression problems jointly:
y is a 2D array, of shape (n_samples, n_tasks). The constraint is that the selected features are the same for all
the regression problems, also called tasks.
The following figure compares the location of the non-zeros in W obtained with a simple Lasso or a MultiTaskLasso.
The Lasso estimates yields scattered non-zeros while the non-zeros of the MultiTaskLasso are full columns.

Fitting a time-series model, imposing that any active feature be active at all times.

Examples:

• Joint feature selection with multi-task Lasso

Mathematically, it consists of a linear model trained with a mixed ℓ1 ℓ2 prior as regularizer. The objective function to

178 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

minimize is:
1
min ||𝑋𝑊 − 𝑌 ||2𝐹 𝑟𝑜 + 𝛼||𝑊 ||21
𝑤 2𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠

where 𝐹 𝑟𝑜 indicates the Frobenius norm:


√︃∑︁
||𝐴||𝐹 𝑟𝑜 = 𝑎2𝑖𝑗
𝑖𝑗

and ℓ1 ℓ2 reads:
∑︁ √︃∑︁
||𝐴||21 = 𝑎2𝑖𝑗
𝑖 𝑗

The implementation in the class MultiTaskLasso uses coordinate descent as the algorithm to fit the coefficients.

Elastic Net

ElasticNet is a linear regression model trained with L1 and L2 prior as regularizer. This combination allows for
learning a sparse model where few of the weights are non-zero like Lasso, while still maintaining the regularization
properties of Ridge. We control the convex combination of L1 and L2 using the l1_ratio parameter.
Elastic-net is useful when there are multiple features which are correlated with one another. Lasso is likely to pick one
of these at random, while elastic-net is likely to pick both.
A practical advantage of trading-off between Lasso and Ridge is it allows Elastic-Net to inherit some of Ridge’s
stability under rotation.
The objective function to minimize is in this case

1 𝛼(1 − 𝜌)
min ||𝑋𝑤 − 𝑦||22 + 𝛼𝜌||𝑤||1 + ||𝑤||22
𝑤 2𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠 2

The class ElasticNetCV can be used to set the parameters alpha (𝛼) and l1_ratio (𝜌) by cross-validation.

Examples:

3.1. Supervised learning 179


scikit-learn user guide, Release 0.20.3

• Lasso and Elastic Net for Sparse Signals


• Lasso and Elastic Net

The following two references explain the iterations used in the coordinate descent solver of scikit-learn, as well as the
duality gap computation used for convergence control.

References

• “Regularization Path For Generalized linear Models by Coordinate Descent”, Friedman, Hastie & Tibshirani,
J Stat Softw, 2010 (Paper).
• “An Interior-Point Method for Large-Scale L1-Regularized Least Squares,” S. J. Kim, K. Koh, M. Lustig, S.
Boyd and D. Gorinevsky, in IEEE Journal of Selected Topics in Signal Processing, 2007 (Paper)

Multi-task Elastic Net

The MultiTaskElasticNet is an elastic-net model that estimates sparse coefficients for multiple regression prob-
lems jointly: Y is a 2D array, of shape (n_samples, n_tasks). The constraint is that the selected features are
the same for all the regression problems, also called tasks.
Mathematically, it consists of a linear model trained with a mixed ℓ1 ℓ2 prior and ℓ2 prior as regularizer. The objective
function to minimize is:
1 𝛼(1 − 𝜌)
min ||𝑋𝑊 − 𝑌 ||2𝐹 𝑟𝑜 + 𝛼𝜌||𝑊 ||21 + ||𝑊 ||2𝐹 𝑟𝑜
𝑊 2𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠 2

The implementation in the class MultiTaskElasticNet uses coordinate descent as the algorithm to fit the coef-
ficients.
The class MultiTaskElasticNetCV can be used to set the parameters alpha (𝛼) and l1_ratio (𝜌) by cross-
validation.

Least Angle Regression

Least-angle regression (LARS) is a regression algorithm for high-dimensional data, developed by Bradley Efron,
Trevor Hastie, Iain Johnstone and Robert Tibshirani. LARS is similar to forward stepwise regression. At each step,
it finds the predictor most correlated with the response. When there are multiple predictors having equal correlation,
instead of continuing along the same predictor, it proceeds in a direction equiangular between the predictors.
The advantages of LARS are:
• It is numerically efficient in contexts where p >> n (i.e., when the number of dimensions is significantly greater
than the number of points)
• It is computationally just as fast as forward selection and has the same order of complexity as an ordinary least
squares.
• It produces a full piecewise linear solution path, which is useful in cross-validation or similar attempts to tune
the model.
• If two variables are almost equally correlated with the response, then their coefficients should increase at ap-
proximately the same rate. The algorithm thus behaves as intuition would expect, and also is more stable.
• It is easily modified to produce solutions for other estimators, like the Lasso.
The disadvantages of the LARS method include:

180 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

• Because LARS is based upon an iterative refitting of the residuals, it would appear to be especially sensitive to
the effects of noise. This problem is discussed in detail by Weisberg in the discussion section of the Efron et al.
(2004) Annals of Statistics article.
The LARS model can be used using estimator Lars, or its low-level implementation lars_path.

LARS Lasso

LassoLars is a lasso model implemented using the LARS algorithm, and unlike the implementation based on
coordinate_descent, this yields the exact solution, which is piecewise linear as a function of the norm of its coefficients.

>>> from sklearn import linear_model


>>> reg = linear_model.LassoLars(alpha=.1)
>>> reg.fit([[0, 0], [1, 1]], [0, 1])
LassoLars(alpha=0.1, copy_X=True, eps=..., fit_intercept=True,
fit_path=True, max_iter=500, normalize=True, positive=False,
precompute='auto', verbose=False)
>>> reg.coef_
array([0.717157..., 0. ])

Examples:

• Lasso path using LARS

The Lars algorithm provides the full path of the coefficients along the regularization parameter almost for free, thus a
common operation consist of retrieving the path with function lars_path

Mathematical formulation

The algorithm is similar to forward stepwise regression, but instead of including variables at each step, the estimated
parameters are increased in a direction equiangular to each one’s correlations with the residual.
Instead of giving a vector result, the LARS solution consists of a curve denoting the solution for each value of the
L1 norm of the parameter vector. The full coefficients path is stored in the array coef_path_, which has size
(n_features, max_features+1). The first column is always zero.

3.1. Supervised learning 181


scikit-learn user guide, Release 0.20.3

References:

• Original Algorithm is detailed in the paper Least Angle Regression by Hastie et al.

Orthogonal Matching Pursuit (OMP)

OrthogonalMatchingPursuit and orthogonal_mp implements the OMP algorithm for approximating the
fit of a linear model with constraints imposed on the number of non-zero coefficients (ie. the L 0 pseudo-norm).
Being a forward feature selection method like Least Angle Regression, orthogonal matching pursuit can approximate
the optimum solution vector with a fixed number of non-zero elements:

arg min ||𝑦 − 𝑋𝛾||22 subject to ||𝛾||0 ≤ 𝑛𝑛𝑜𝑛𝑧𝑒𝑟𝑜_𝑐𝑜𝑒𝑓 𝑠


𝛾

Alternatively, orthogonal matching pursuit can target a specific error instead of a specific number of non-zero coeffi-
cients. This can be expressed as:

arg min ||𝛾||0 subject to ||𝑦 − 𝑋𝛾||22 ≤ tol


𝛾

OMP is based on a greedy algorithm that includes at each step the atom most highly correlated with the current
residual. It is similar to the simpler matching pursuit (MP) method, but better in that at each iteration, the residual is
recomputed using an orthogonal projection on the space of the previously chosen dictionary elements.

Examples:

• Orthogonal Matching Pursuit

References:

• http://www.cs.technion.ac.il/~ronrubin/Publications/KSVD-OMP-v2.pdf
• Matching pursuits with time-frequency dictionaries, S. G. Mallat, Z. Zhang,

Bayesian Regression

Bayesian regression techniques can be used to include regularization parameters in the estimation procedure: the
regularization parameter is not set in a hard sense but tuned to the data at hand.
This can be done by introducing uninformative priors over the hyper parameters of the model. The ℓ2 regularization
used in Ridge Regression is equivalent to finding a maximum a posteriori estimation under a Gaussian prior over the
parameters 𝑤 with precision 𝜆−1 . Instead of setting lambda manually, it is possible to treat it as a random variable to
be estimated from the data.
To obtain a fully probabilistic model, the output 𝑦 is assumed to be Gaussian distributed around 𝑋𝑤:

𝑝(𝑦|𝑋, 𝑤, 𝛼) = 𝒩 (𝑦|𝑋𝑤, 𝛼)

Alpha is again treated as a random variable that is to be estimated from the data.
The advantages of Bayesian Regression are:

182 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

• It adapts to the data at hand.


• It can be used to include regularization parameters in the estimation procedure.
The disadvantages of Bayesian regression include:
• Inference of the model can be time consuming.

References

• A good introduction to Bayesian methods is given in C. Bishop: Pattern Recognition and Machine learning
• Original Algorithm is detailed in the book Bayesian learning for neural networks by Radford M. Neal

Bayesian Ridge Regression

BayesianRidge estimates a probabilistic model of the regression problem as described above. The prior for the
parameter 𝑤 is given by a spherical Gaussian:

𝑝(𝑤|𝜆) = 𝒩 (𝑤|0, 𝜆−1 I𝑝 )

The priors over 𝛼 and 𝜆 are chosen to be gamma distributions, the conjugate prior for the precision of the Gaussian.
The resulting model is called Bayesian Ridge Regression, and is similar to the classical Ridge. The parameters
𝑤, 𝛼 and 𝜆 are estimated jointly during the fit of the model. The remaining hyperparameters are the parameters of
the gamma priors over 𝛼 and 𝜆. These are usually chosen to be non-informative. The parameters are estimated by
maximizing the marginal log likelihood.
By default 𝛼1 = 𝛼2 = 𝜆1 = 𝜆2 = 10−6 .

Bayesian Ridge Regression is used for regression:

>>> from sklearn import linear_model


>>> X = [[0., 0.], [1., 1.], [2., 2.], [3., 3.]]
>>> Y = [0., 1., 2., 3.]
>>> reg = linear_model.BayesianRidge()
>>> reg.fit(X, Y)
BayesianRidge(alpha_1=1e-06, alpha_2=1e-06, compute_score=False, copy_X=True,

3.1. Supervised learning 183


scikit-learn user guide, Release 0.20.3

fit_intercept=True, lambda_1=1e-06, lambda_2=1e-06, n_iter=300,


normalize=False, tol=0.001, verbose=False)

After being fitted, the model can then be used to predict new values:

>>> reg.predict([[1, 0.]])


array([0.50000013])

The weights 𝑤 of the model can be access:

>>> reg.coef_
array([0.49999993, 0.49999993])

Due to the Bayesian framework, the weights found are slightly different to the ones found by Ordinary Least Squares.
However, Bayesian Ridge Regression is more robust to ill-posed problem.

Examples:

• Bayesian Ridge Regression

References

• More details can be found in the article Bayesian Interpolation by MacKay, David J. C.

Automatic Relevance Determination - ARD

ARDRegression is very similar to Bayesian Ridge Regression, but can lead to sparser weights 𝑤12 .
ARDRegression poses a different prior over 𝑤, by dropping the assumption of the Gaussian being spherical.
Instead, the distribution over 𝑤 is assumed to be an axis-parallel, elliptical Gaussian distribution.
This means each weight 𝑤𝑖 is drawn from a Gaussian distribution, centered on zero and with a precision 𝜆𝑖 :

𝑝(𝑤|𝜆) = 𝒩 (𝑤|0, 𝐴−1 )

with 𝑑𝑖𝑎𝑔 (𝐴) = 𝜆 = {𝜆1 , ..., 𝜆𝑝 }.


In contrast to Bayesian Ridge Regression, each coordinate of 𝑤𝑖 has its own standard deviation 𝜆𝑖 . The prior over all
𝜆𝑖 is chosen to be the same gamma distribution given by hyperparameters 𝜆1 and 𝜆2 .
ARD is also known in the literature as Sparse Bayesian Learning and Relevance Vector Machine34 .

Examples:

• Automatic Relevance Determination Regression (ARD)

1 Christopher M. Bishop: Pattern Recognition and Machine Learning, Chapter 7.2.1


2 David Wipf and Srikantan Nagarajan: A new view of automatic relevance determination
3 Michael E. Tipping: Sparse Bayesian Learning and the Relevance Vector Machine
4 Tristan Fletcher: Relevance Vector Machines explained

184 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

References:

Logistic regression

Logistic regression, despite its name, is a linear model for classification rather than regression. Logistic regression is
also known in the literature as logit regression, maximum-entropy classification (MaxEnt) or the log-linear classifier.
In this model, the probabilities describing the possible outcomes of a single trial are modeled using a logistic function.
The implementation of logistic regression in scikit-learn can be accessed from class LogisticRegression. This
implementation can fit binary, One-vs- Rest, or multinomial logistic regression with optional L2 or L1 regularization.
As an optimization problem, binary class L2 penalized logistic regression minimizes the following cost function:
𝑛
1 ∑︁
min 𝑤𝑇 𝑤 + 𝐶 log(exp(−𝑦𝑖 (𝑋𝑖𝑇 𝑤 + 𝑐)) + 1).
𝑤,𝑐 2
𝑖=1

Similarly, L1 regularized logistic regression solves the following optimization problem


𝑛
∑︁
min ‖𝑤‖1 + 𝐶 log(exp(−𝑦𝑖 (𝑋𝑖𝑇 𝑤 + 𝑐)) + 1).
𝑤,𝑐
𝑖=1

Note that, in this notation, it’s assumed that the observation 𝑦𝑖 takes values in the set −1, 1 at trial 𝑖.
The solvers implemented in the class LogisticRegression are “liblinear”, “newton-cg”, “lbfgs”, “sag” and
“saga”:
The solver “liblinear” uses a coordinate descent (CD) algorithm, and relies on the excellent C++ LIBLINEAR library,
which is shipped with scikit-learn. However, the CD algorithm implemented in liblinear cannot learn a true multino-
mial (multiclass) model; instead, the optimization problem is decomposed in a “one-vs-rest” fashion so separate binary
classifiers are trained for all classes. This happens under the hood, so LogisticRegression instances using this
solver behave as multiclass classifiers. For L1 penalization sklearn.svm.l1_min_c allows to calculate the lower
bound for C in order to get a non “null” (all feature weights to zero) model.
The “lbfgs”, “sag” and “newton-cg” solvers only support L2 penalization and are found to converge faster for some
high dimensional data. Setting multi_class to “multinomial” with these solvers learns a true multinomial logistic
regression model5 , which means that its probability estimates should be better calibrated than the default “one-vs-
rest” setting.
5 Christopher M. Bishop: Pattern Recognition and Machine Learning, Chapter 4.3.4

3.1. Supervised learning 185


scikit-learn user guide, Release 0.20.3

The “sag” solver uses a Stochastic Average Gradient descent6 . It is faster than other solvers for large datasets, when
both the number of samples and the number of features are large.
The “saga” solver7 is a variant of “sag” that also supports the non-smooth penalty=”l1” option. This is therefore the
solver of choice for sparse multinomial logistic regression.
The “lbfgs” is an optimization algorithm that approximates the Broyden–Fletcher–Goldfarb–Shanno algorithm8 ,
which belongs to quasi-Newton methods. The “lbfgs” solver is recommended for use for small data-sets but for
larger datasets its performance suffers.9
The following table summarizes the penalties supported by each solver:

Solvers
Penalties ‘liblinear’ ‘lbfgs’ ‘newton-cg’ ‘sag’ ‘saga’
Multinomial + L2 penalty no yes yes yes yes
OVR + L2 penalty yes yes yes yes yes
Multinomial + L1 penalty no no no no yes
OVR + L1 penalty yes no no no yes
Behaviors

Penalize the intercept (bad) yes no no no no


Faster for large datasets no no no yes yes
Robust to unscaled datasets yes yes yes no no

The “lbfgs” solver is used by default for its robustness. For large datasets the “saga” solver is usually faster. For large
dataset, you may also consider using SGDClassifier with ‘log’ loss, which might be even faster but require more
tuning.

Examples:

• L1 Penalty and Sparsity in Logistic Regression


• Regularization path of L1- Logistic Regression
• Plot multinomial and One-vs-Rest Logistic Regression
• Multiclass sparse logisitic regression on newgroups20
• MNIST classfification using multinomial logistic + L1

Differences from liblinear:

There might be a difference in the scores obtained between LogisticRegression with solver=liblinear
or LinearSVC and the external liblinear library directly, when fit_intercept=False and the fit coef_
(or) the data to be predicted are zeroes. This is because for the sample(s) with decision_function zero,
LogisticRegression and LinearSVC predict the negative class, while liblinear predicts the positive class.
Note that a model with fit_intercept=False and having many samples with decision_function zero,
is likely to be a underfit, bad model and you are advised to set fit_intercept=True and increase the inter-
cept_scaling.

6Mark Schmidt, Nicolas Le Roux, and Francis Bach: Minimizing Finite Sums with the Stochastic Average Gradient.
7Aaron Defazio, Francis Bach, Simon Lacoste-Julien: SAGA: A Fast Incremental Gradient Method With Support for Non-Strongly Convex
Composite Objectives.
8 https://en.wikipedia.org/wiki/Broyden%E2%80%93Fletcher%E2%80%93Goldfarb%E2%80%93Shanno_algorithm
9 “Performance Evaluation of Lbfgs vs other solvers”

186 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Note: Feature selection with sparse logistic regression


A logistic regression with L1 penalty yields sparse models, and can thus be used to perform feature selection, as
detailed in L1-based feature selection.

LogisticRegressionCV implements Logistic Regression with builtin cross-validation to find out the optimal C
parameter. “newton-cg”, “sag”, “saga” and “lbfgs” solvers are found to be faster for high-dimensional dense data, due
to warm-starting. For the multiclass case, if multi_class option is set to “ovr”, an optimal C is obtained for each class
and if the multi_class option is set to “multinomial”, an optimal C is obtained by minimizing the cross-entropy loss.

References:

Stochastic Gradient Descent - SGD

Stochastic gradient descent is a simple yet very efficient approach to fit linear models. It is particularly useful when the
number of samples (and the number of features) is very large. The partial_fit method allows online/out-of-core
learning.
The classes SGDClassifier and SGDRegressor provide functionality to fit linear models for classifica-
tion and regression using different (convex) loss functions and different penalties. E.g., with loss="log",
SGDClassifier fits a logistic regression model, while with loss="hinge" it fits a linear support vector ma-
chine (SVM).

References

• Stochastic Gradient Descent

Perceptron

The Perceptron is another simple classification algorithm suitable for large scale learning. By default:
• It does not require a learning rate.
• It is not regularized (penalized).
• It updates its model only on mistakes.
The last characteristic implies that the Perceptron is slightly faster to train than SGD with the hinge loss and that the
resulting models are sparser.

Passive Aggressive Algorithms

The passive-aggressive algorithms are a family of algorithms for large-scale learning. They are similar to the Per-
ceptron in that they do not require a learning rate. However, contrary to the Perceptron, they include a regularization
parameter C.
For classification, PassiveAggressiveClassifier can be used with loss='hinge' (PA-I) or
loss='squared_hinge' (PA-II). For regression, PassiveAggressiveRegressor can be used with
loss='epsilon_insensitive' (PA-I) or loss='squared_epsilon_insensitive' (PA-II).

3.1. Supervised learning 187


scikit-learn user guide, Release 0.20.3

References:

• “Online Passive-Aggressive Algorithms” K. Crammer, O. Dekel, J. Keshat, S. Shalev-Shwartz, Y. Singer -


JMLR 7 (2006)

Robustness regression: outliers and modeling errors

Robust regression is interested in fitting a regression model in the presence of corrupt data: either outliers, or error in
the model.

Different scenario and useful concepts

There are different things to keep in mind when dealing with data corrupted by outliers:
• Outliers in X or in y?

Outliers in the y direction Outliers in the X direction

• Fraction of outliers versus amplitude of error

188 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

The number of outlying points matters, but also how much they are outliers.

Small outliers Large outliers

An important notion of robust fitting is that of breakdown point: the fraction of data that can be outlying for the fit to
start missing the inlying data.
Note that in general, robust fitting in high-dimensional setting (large n_features) is very hard. The robust models here
will probably not work in these settings.

Trade-offs: which estimator?

Scikit-learn provides 3 robust regression estimators: RANSAC, Theil Sen and HuberRegressor
• HuberRegressor should be faster than RANSAC and Theil Sen unless the number of samples are
very large, i.e n_samples >> n_features. This is because RANSAC and Theil Sen fit on
smaller subsets of the data. However, both Theil Sen and RANSAC are unlikely to be as robust as
HuberRegressor for the default parameters.
• RANSAC is faster than Theil Sen and scales much better with the number of samples
• RANSAC will deal better with large outliers in the y direction (most common situation)
• Theil Sen will cope better with medium-size outliers in the X direction, but this property will
disappear in large dimensional settings.
When in doubt, use RANSAC

RANSAC: RANdom SAmple Consensus

RANSAC (RANdom SAmple Consensus) fits a model from random subsets of inliers from the complete data set.
RANSAC is a non-deterministic algorithm producing only a reasonable result with a certain probability, which is de-
pendent on the number of iterations (see max_trials parameter). It is typically used for linear and non-linear regression
problems and is especially popular in the fields of photogrammetric computer vision.
The algorithm splits the complete input sample data into a set of inliers, which may be subject to noise, and outliers,
which are e.g. caused by erroneous measurements or invalid hypotheses about the data. The resulting model is then
estimated only from the determined inliers.

3.1. Supervised learning 189


scikit-learn user guide, Release 0.20.3

Details of the algorithm

Each iteration performs the following steps:


1. Select min_samples random samples from the original data and check whether the set of data is valid (see
is_data_valid).
2. Fit a model to the random subset (base_estimator.fit) and check whether the estimated model is valid
(see is_model_valid).
3. Classify all data as inliers or outliers by calculating the residuals to the estimated model (base_estimator.
predict(X) - y) - all data samples with absolute residuals smaller than the residual_threshold are
considered as inliers.
4. Save fitted model as best model if number of inlier samples is maximal. In case the current estimated model has
the same number of inliers, it is only considered as the best model if it has better score.
These steps are performed either a maximum number of times (max_trials) or until one of the special stop criteria
are met (see stop_n_inliers and stop_score). The final model is estimated using all inlier samples (consensus
set) of the previously determined best model.
The is_data_valid and is_model_valid functions allow to identify and reject degenerate combinations of
random sub-samples. If the estimated model is not needed for identifying degenerate cases, is_data_valid should
be used as it is called prior to fitting the model and thus leading to better computational performance.

Examples:

• Robust linear model estimation using RANSAC


• Robust linear estimator fitting

References:

• https://en.wikipedia.org/wiki/RANSAC
• “Random Sample Consensus: A Paradigm for Model Fitting with Applications to Image Analysis and Auto-
mated Cartography” Martin A. Fischler and Robert C. Bolles - SRI International (1981)
• “Performance Evaluation of RANSAC Family” Sunglok Choi, Taemin Kim and Wonpil Yu - BMVC (2009)

190 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Theil-Sen estimator: generalized-median-based estimator

The TheilSenRegressor estimator uses a generalization of the median in multiple dimensions. It is thus robust
to multivariate outliers. Note however that the robustness of the estimator decreases quickly with the dimensionality of
the problem. It looses its robustness properties and becomes no better than an ordinary least squares in high dimension.

Examples:

• Theil-Sen Regression
• Robust linear estimator fitting

References:

• https://en.wikipedia.org/wiki/Theil%E2%80%93Sen_estimator

Theoretical considerations

TheilSenRegressor is comparable to the Ordinary Least Squares (OLS) in terms of asymptotic efficiency and as
an unbiased estimator. In contrast to OLS, Theil-Sen is a non-parametric method which means it makes no assumption
about the underlying distribution of the data. Since Theil-Sen is a median-based estimator, it is more robust against
corrupted data aka outliers. In univariate setting, Theil-Sen has a breakdown point of about 29.3% in case of a simple
linear regression which means that it can tolerate arbitrary corrupted data of up to 29.3%.

The implementation of TheilSenRegressor in scikit-learn follows a generalization to a multivariate linear re-


gression model10 using the spatial median which is a generalization of the median to multiple dimensions11 .
In terms of time and space complexity, Theil-Sen scales according to
(︂ )︂
𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠
𝑛𝑠𝑢𝑏𝑠𝑎𝑚𝑝𝑙𝑒𝑠
10 Xin Dang, Hanxiang Peng, Xueqin Wang and Heping Zhang: Theil-Sen Estimators in a Multiple Linear Regression Model.
11

20. Kärkkäinen and S. Äyrämö: On Computation of Spatial Median for Robust Data Mining.

3.1. Supervised learning 191


scikit-learn user guide, Release 0.20.3

which makes it infeasible to be applied exhaustively to problems with a large number of samples and features. There-
fore, the magnitude of a subpopulation can be chosen to limit the time and space complexity by considering only a
random subset of all possible combinations.

Examples:

• Theil-Sen Regression

References:

Huber Regression

The HuberRegressor is different to Ridge because it applies a linear loss to samples that are classified as outliers.
A sample is classified as an inlier if the absolute error of that sample is lesser than a certain threshold. It differs from
TheilSenRegressor and RANSACRegressor because it does not ignore the effect of the outliers but gives a
lesser weight to them.

The loss function that HuberRegressor minimizes is given by


𝑛 (︂ (︂ )︂ )︂
∑︁ 𝑋𝑖 𝑤 − 𝑦𝑖 2
min 𝜎 + 𝐻𝜖 𝜎 + 𝛼||𝑤||2
𝑤,𝜎
𝑖=1
𝜎

where
{︃
𝑧2, if |𝑧| < 𝜖,
𝐻𝜖 (𝑧) =
2𝜖|𝑧| − 𝜖2 , otherwise

It is advised to set the parameter epsilon to 1.35 to achieve 95% statistical efficiency.

Notes

The HuberRegressor differs from using SGDRegressor with loss set to huber in the following ways.

192 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

• HuberRegressor is scaling invariant. Once epsilon is set, scaling X and y down or up by different values
would produce the same robustness to outliers as before. as compared to SGDRegressor where epsilon
has to be set again when X and y are scaled.
• HuberRegressor should be more efficient to use on data with small number of samples while
SGDRegressor needs a number of passes on the training data to produce the same robustness.

Examples:

• HuberRegressor vs Ridge on dataset with strong outliers

References:

• Peter J. Huber, Elvezio M. Ronchetti: Robust Statistics, Concomitant scale estimates, pg 172

Also, this estimator is different from the R implementation of Robust Regression (http://www.ats.ucla.edu/stat/r/dae/
rreg.htm) because the R implementation does a weighted least squares implementation with weights given to each
sample on the basis of how much the residual is greater than a certain threshold.

Polynomial regression: extending linear models with basis functions

One common pattern within machine learning is to use linear models trained on nonlinear functions of the data. This
approach maintains the generally fast performance of linear methods, while allowing them to fit a much wider range
of data.
For example, a simple linear regression can be extended by constructing polynomial features from the coefficients.
In the standard linear regression case, you might have a model that looks like this for two-dimensional data:

𝑦ˆ(𝑤, 𝑥) = 𝑤0 + 𝑤1 𝑥1 + 𝑤2 𝑥2

If we want to fit a paraboloid to the data instead of a plane, we can combine the features in second-order polynomials,
so that the model looks like this:

𝑦ˆ(𝑤, 𝑥) = 𝑤0 + 𝑤1 𝑥1 + 𝑤2 𝑥2 + 𝑤3 𝑥1 𝑥2 + 𝑤4 𝑥21 + 𝑤5 𝑥22

The (sometimes surprising) observation is that this is still a linear model: to see this, imagine creating a new variable

𝑧 = [𝑥1 , 𝑥2 , 𝑥1 𝑥2 , 𝑥21 , 𝑥22 ]

With this re-labeling of the data, our problem can be written

𝑦ˆ(𝑤, 𝑥) = 𝑤0 + 𝑤1 𝑧1 + 𝑤2 𝑧2 + 𝑤3 𝑧3 + 𝑤4 𝑧4 + 𝑤5 𝑧5

We see that the resulting polynomial regression is in the same class of linear models we’d considered above (i.e. the
model is linear in 𝑤) and can be solved by the same techniques. By considering linear fits within a higher-dimensional
space built with these basis functions, the model has the flexibility to fit a much broader range of data.
Here is an example of applying this idea to one-dimensional data, using polynomial features of varying degrees:
This figure is created using the PolynomialFeatures preprocessor. This preprocessor transforms an input data
matrix into a new data matrix of a given degree. It can be used as follows:

3.1. Supervised learning 193


scikit-learn user guide, Release 0.20.3

>>> from sklearn.preprocessing import PolynomialFeatures


>>> import numpy as np
>>> X = np.arange(6).reshape(3, 2)
>>> X
array([[0, 1],
[2, 3],
[4, 5]])
>>> poly = PolynomialFeatures(degree=2)
>>> poly.fit_transform(X)
array([[ 1., 0., 1., 0., 0., 1.],
[ 1., 2., 3., 4., 6., 9.],
[ 1., 4., 5., 16., 20., 25.]])

The features of X have been transformed from [𝑥1 , 𝑥2 ] to [1, 𝑥1 , 𝑥2 , 𝑥21 , 𝑥1 𝑥2 , 𝑥22 ], and can now be used within any
linear model.
This sort of preprocessing can be streamlined with the Pipeline tools. A single object representing a simple polynomial
regression can be created and used as follows:

>>> from sklearn.preprocessing import PolynomialFeatures


>>> from sklearn.linear_model import LinearRegression
>>> from sklearn.pipeline import Pipeline
>>> import numpy as np
>>> model = Pipeline([('poly', PolynomialFeatures(degree=3)),
... ('linear', LinearRegression(fit_intercept=False))])
>>> # fit to an order-3 polynomial data
>>> x = np.arange(5)
>>> y = 3 - 2 * x + x ** 2 - x ** 3
>>> model = model.fit(x[:, np.newaxis], y)
>>> model.named_steps['linear'].coef_
array([ 3., -2., 1., -1.])

The linear model trained on polynomial features is able to exactly recover the input polynomial coefficients.
In some cases it’s not necessary to include higher powers of any single feature, but only the so-called interaction
features that multiply together at most 𝑑 distinct features. These can be gotten from PolynomialFeatures with
the setting interaction_only=True.
For example, when dealing with boolean features, 𝑥𝑛𝑖 = 𝑥𝑖 for all 𝑛 and is therefore useless; but 𝑥𝑖 𝑥𝑗 represents the
conjunction of two booleans. This way, we can solve the XOR problem with a linear classifier:

194 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

>>> from sklearn.linear_model import Perceptron


>>> from sklearn.preprocessing import PolynomialFeatures
>>> import numpy as np
>>> X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
>>> y = X[:, 0] ^ X[:, 1]
>>> y
array([0, 1, 1, 0])
>>> X = PolynomialFeatures(interaction_only=True).fit_transform(X).astype(int)
>>> X
array([[1, 0, 0, 0],
[1, 0, 1, 0],
[1, 1, 0, 0],
[1, 1, 1, 1]])
>>> clf = Perceptron(fit_intercept=False, max_iter=10, tol=None,
... shuffle=False).fit(X, y)

And the classifier “predictions” are perfect:

>>> clf.predict(X)
array([0, 1, 1, 0])
>>> clf.score(X, y)
1.0

3.1.2 Linear and Quadratic Discriminant Analysis

Linear Discriminant Analysis (discriminant_analysis.LinearDiscriminantAnalysis) and


Quadratic Discriminant Analysis (discriminant_analysis.QuadraticDiscriminantAnalysis)
are two classic classifiers, with, as their names suggest, a linear and a quadratic decision surface, respectively.
These classifiers are attractive because they have closed-form solutions that can be easily computed, are inherently
multiclass, have proven to work well in practice, and have no hyperparameters to tune.

3.1. Supervised learning 195


scikit-learn user guide, Release 0.20.3

The plot shows decision boundaries for Linear Discriminant Analysis and Quadratic Discriminant Analysis. The
bottom row demonstrates that Linear Discriminant Analysis can only learn linear boundaries, while Quadratic Dis-
criminant Analysis can learn quadratic boundaries and is therefore more flexible.

Examples:

Linear and Quadratic Discriminant Analysis with covariance ellipsoid: Comparison of LDA and QDA on synthetic
data.

Dimensionality reduction using Linear Discriminant Analysis

discriminant_analysis.LinearDiscriminantAnalysis can be used to perform supervised dimen-


sionality reduction, by projecting the input data to a linear subspace consisting of the directions which maximize
the separation between classes (in a precise sense discussed in the mathematics section below). The dimension of the
output is necessarily less than the number of classes, so this is, in general, a rather strong dimensionality reduction,
and only makes sense in a multiclass setting.
This is implemented in discriminant_analysis.LinearDiscriminantAnalysis.transform. The
desired dimensionality can be set using the n_components constructor parameter. This parameter has no influence
on discriminant_analysis.LinearDiscriminantAnalysis.fit or discriminant_analysis.

196 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

LinearDiscriminantAnalysis.predict.

Examples:

Comparison of LDA and PCA 2D projection of Iris dataset: Comparison of LDA and PCA for dimensionality
reduction of the Iris dataset

Mathematical formulation of the LDA and QDA classifiers

Both LDA and QDA can be derived from simple probabilistic models which model the class conditional distribution
of the data 𝑃 (𝑋|𝑦 = 𝑘) for each class 𝑘. Predictions can then be obtained by using Bayes’ rule:

𝑃 (𝑋|𝑦 = 𝑘)𝑃 (𝑦 = 𝑘) 𝑃 (𝑋|𝑦 = 𝑘)𝑃 (𝑦 = 𝑘)


𝑃 (𝑦 = 𝑘|𝑋) = = ∑︀
𝑃 (𝑋) 𝑙 𝑃 (𝑋|𝑦 = 𝑙) · 𝑃 (𝑦 = 𝑙)

and we select the class 𝑘 which maximizes this conditional probability.


More specifically, for linear and quadratic discriminant analysis, 𝑃 (𝑋|𝑦) is modeled as a multivariate Gaussian distri-
bution with density:
(︂ )︂
1 1 𝑡 −1
𝑃 (𝑋|𝑦 = 𝑘) = exp − (𝑋 − 𝜇𝑘 ) Σ 𝑘 (𝑋 − 𝜇𝑘 )
(2𝜋)𝑑/2 |Σ𝑘 |1/2 2
where 𝑑 is the number of features.
To use this model as a classifier, we just need to estimate from the training data the class priors 𝑃 (𝑦 = 𝑘) (by the
proportion of instances of class 𝑘), the class means 𝜇𝑘 (by the empirical sample class means) and the covariance
matrices (either by the empirical sample class covariance matrices, or by a regularized estimator: see the section on
shrinkage below).
In the case of LDA, the Gaussians for each class are assumed to share the same covariance matrix: Σ𝑘 = Σ for
all 𝑘. This leads to linear decision surfaces, which can be seen by comparing the log-probability ratios log[𝑃 (𝑦 =
𝑘|𝑋)/𝑃 (𝑦 = 𝑙|𝑋)]:
(︂ )︂ (︂ )︂
𝑃 (𝑦 = 𝑘|𝑋) 𝑃 (𝑋|𝑦 = 𝑘)𝑃 (𝑦 = 𝑘)
log = log =0⇔
𝑃 (𝑦 = 𝑙|𝑋) 𝑃 (𝑋|𝑦 = 𝑙)𝑃 (𝑦 = 𝑙)
1 𝑃 (𝑦 = 𝑘)
(𝜇𝑘 − 𝜇𝑙 )𝑡 Σ−1 𝑋 = (𝜇𝑡𝑘 Σ−1 𝜇𝑘 − 𝜇𝑡𝑙 Σ−1 𝜇𝑙 ) − log
2 𝑃 (𝑦 = 𝑙)
In the case of QDA, there are no assumptions on the covariance matrices Σ𝑘 of the Gaussians, leading to quadratic
decision surfaces. See3 for more details.

Note: Relation with Gaussian Naive Bayes


If in the QDA model one assumes that the covariance matrices are diagonal, then the inputs are assumed to be con-
ditionally independent in each class, and the resulting classifier is equivalent to the Gaussian Naive Bayes classifier
naive_bayes.GaussianNB.

Mathematical formulation of LDA dimensionality reduction

To understand the use of LDA in dimensionality reduction, it is useful to start with a geometric reformulation of the
LDA classification rule explained above. We write 𝐾 for the total number of target classes. Since in LDA we assume
3 “The Elements of Statistical Learning”, Hastie T., Tibshirani R., Friedman J., Section 4.3, p.106-119, 2008.

3.1. Supervised learning 197


scikit-learn user guide, Release 0.20.3

that all classes have the same estimated covariance Σ, we can rescale the data so that this covariance is the identity:

𝑋 * = 𝐷−1/2 𝑈 𝑡 𝑋 with Σ = 𝑈 𝐷𝑈 𝑡

Then one can show that to classify a data point after scaling is equivalent to finding the estimated class mean 𝜇*𝑘 which
is closest to the data point in the Euclidean distance. But this can be done just as well after projecting on the 𝐾 − 1
affine subspace 𝐻𝐾 generated by all the 𝜇*𝑘 for all classes. This shows that, implicit in the LDA classifier, there is a
dimensionality reduction by linear projection onto a 𝐾 − 1 dimensional space.
We can reduce the dimension even more, to a chosen 𝐿, by projecting onto the linear subspace 𝐻𝐿 which max-
imizes the variance of the 𝜇*𝑘 after projection (in effect, we are doing a form of PCA for the transformed class
means 𝜇*𝑘 ). This 𝐿 corresponds to the n_components parameter used in the discriminant_analysis.
LinearDiscriminantAnalysis.transform method. See3 for more details.

Shrinkage

Shrinkage is a tool to improve estimation of covariance matrices in situations where the number of training sam-
ples is small compared to the number of features. In this scenario, the empirical sample covariance is a poor es-
timator. Shrinkage LDA can be used by setting the shrinkage parameter of the discriminant_analysis.
LinearDiscriminantAnalysis class to ‘auto’. This automatically determines the optimal shrinkage parameter
in an analytic way following the lemma introduced by Ledoit and Wolf4 . Note that currently shrinkage only works
when setting the solver parameter to ‘lsqr’ or ‘eigen’.
The shrinkage parameter can also be manually set between 0 and 1. In particular, a value of 0 corresponds to
no shrinkage (which means the empirical covariance matrix will be used) and a value of 1 corresponds to complete
shrinkage (which means that the diagonal matrix of variances will be used as an estimate for the covariance matrix).
Setting this parameter to a value between these two extrema will estimate a shrunk version of the covariance matrix.

4 Ledoit O, Wolf M. Honey, I Shrunk the Sample Covariance Matrix. The Journal of Portfolio Management 30(4), 110-119, 2004.

198 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Estimation algorithms

The default solver is ‘svd’. It can perform both classification and transform, and it does not rely on the calculation
of the covariance matrix. This can be an advantage in situations where the number of features is large. However, the
‘svd’ solver cannot be used with shrinkage.
The ‘lsqr’ solver is an efficient algorithm that only works for classification. It supports shrinkage.
The ‘eigen’ solver is based on the optimization of the between class scatter to within class scatter ratio. It can be used
for both classification and transform, and it supports shrinkage. However, the ‘eigen’ solver needs to compute the
covariance matrix, so it might not be suitable for situations with a high number of features.

Examples:

Normal and Shrinkage Linear Discriminant Analysis for classification: Comparison of LDA classifiers with and
without shrinkage.

References:

3.1.3 Kernel ridge regression

Kernel ridge regression (KRR) [M2012] combines Ridge Regression (linear least squares with l2-norm regularization)
with the kernel trick. It thus learns a linear function in the space induced by the respective kernel and the data. For
non-linear kernels, this corresponds to a non-linear function in the original space.
The form of the model learned by KernelRidge is identical to support vector regression (SVR). However, different
loss functions are used: KRR uses squared error loss while support vector regression uses 𝜖-insensitive loss, both
combined with l2 regularization. In contrast to SVR, fitting KernelRidge can be done in closed-form and is typically
faster for medium-sized datasets. On the other hand, the learned model is non-sparse and thus slower than SVR, which
learns a sparse model for 𝜖 > 0, at prediction-time.
The following figure compares KernelRidge and SVR on an artificial dataset, which consists of a sinusoidal target
function and strong noise added to every fifth datapoint. The learned model of KernelRidge and SVR is plotted,
where both complexity/regularization and bandwidth of the RBF kernel have been optimized using grid-search. The
learned functions are very similar; however, fitting KernelRidge is approx. seven times faster than fitting SVR
(both with grid-search). However, prediction of 100000 target values is more than three times faster with SVR since it
has learned a sparse model using only approx. 1/3 of the 100 training datapoints as support vectors.
The next figure compares the time for fitting and prediction of KernelRidge and SVR for different sizes of the
training set. Fitting KernelRidge is faster than SVR for medium-sized training sets (less than 1000 samples);
however, for larger training sets SVR scales better. With regard to prediction time, SVR is faster than KernelRidge
for all sizes of the training set because of the learned sparse solution. Note that the degree of sparsity and thus the
prediction time depends on the parameters 𝜖 and 𝐶 of the SVR; 𝜖 = 0 would correspond to a dense model.

References:

3.1.4 Support Vector Machines

Support vector machines (SVMs) are a set of supervised learning methods used for classification, regression and
outliers detection.

3.1. Supervised learning 199


scikit-learn user guide, Release 0.20.3

200 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

3.1. Supervised learning 201


scikit-learn user guide, Release 0.20.3

The advantages of support vector machines are:


• Effective in high dimensional spaces.
• Still effective in cases where number of dimensions is greater than the number of samples.
• Uses a subset of training points in the decision function (called support vectors), so it is also memory efficient.
• Versatile: different Kernel functions can be specified for the decision function. Common kernels are provided,
but it is also possible to specify custom kernels.
The disadvantages of support vector machines include:
• If the number of features is much greater than the number of samples, avoid over-fitting in choosing Kernel
functions and regularization term is crucial.
• SVMs do not directly provide probability estimates, these are calculated using an expensive five-fold cross-
validation (see Scores and probabilities, below).
The support vector machines in scikit-learn support both dense (numpy.ndarray and convertible to that by numpy.
asarray) and sparse (any scipy.sparse) sample vectors as input. However, to use an SVM to make predictions
for sparse data, it must have been fit on such data. For optimal performance, use C-ordered numpy.ndarray (dense)
or scipy.sparse.csr_matrix (sparse) with dtype=float64.

Classification

SVC, NuSVC and LinearSVC are classes capable of performing multi-class classification on a dataset.

202 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

SVC and NuSVC are similar methods, but accept slightly different sets of parameters and have different mathematical
formulations (see section Mathematical formulation). On the other hand, LinearSVC is another implementation
of Support Vector Classification for the case of a linear kernel. Note that LinearSVC does not accept keyword
kernel, as this is assumed to be linear. It also lacks some of the members of SVC and NuSVC, like support_.
As other classifiers, SVC, NuSVC and LinearSVC take as input two arrays: an array X of size [n_samples,
n_features] holding the training samples, and an array y of class labels (strings or integers), size [n_samples]:

>>> from sklearn import svm


>>> X = [[0, 0], [1, 1]]
>>> y = [0, 1]
>>> clf = svm.SVC(gamma='scale')
>>> clf.fit(X, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='scale', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)

After being fitted, the model can then be used to predict new values:

>>> clf.predict([[2., 2.]])


array([1])

SVMs decision function depends on some subset of the training data, called the support vectors. Some properties of
these support vectors can be found in members support_vectors_, support_ and n_support:

>>> # get support vectors


>>> clf.support_vectors_
array([[0., 0.],
[1., 1.]])
>>> # get indices of support vectors
>>> clf.support_
array([0, 1]...)
>>> # get number of support vectors for each class
>>> clf.n_support_
array([1, 1]...)

Multi-class classification

SVC and NuSVC implement the “one-against-one” approach (Knerr et al., 1990) for multi- class classifica-
tion. If n_class is the number of classes, then n_class * (n_class - 1) / 2 classifiers are con-
structed and each one trains data from two classes. To provide a consistent interface with other classifiers, the
decision_function_shape option allows to aggregate the results of the “one-against-one” classifiers to a deci-
sion function of shape (n_samples, n_classes):

>>> X = [[0], [1], [2], [3]]


>>> Y = [0, 1, 2, 3]
>>> clf = svm.SVC(gamma='scale', decision_function_shape='ovo')
>>> clf.fit(X, Y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovo', degree=3, gamma='scale', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> dec = clf.decision_function([[1]])
>>> dec.shape[1] # 4 classes: 4*3/2 = 6
6

3.1. Supervised learning 203


scikit-learn user guide, Release 0.20.3

>>> clf.decision_function_shape = "ovr"


>>> dec = clf.decision_function([[1]])
>>> dec.shape[1] # 4 classes
4

On the other hand, LinearSVC implements “one-vs-the-rest” multi-class strategy, thus training n_class models. If
there are only two classes, only one model is trained:

>>> lin_clf = svm.LinearSVC()


>>> lin_clf.fit(X, Y)
LinearSVC(C=1.0, class_weight=None, dual=True, fit_intercept=True,
intercept_scaling=1, loss='squared_hinge', max_iter=1000,
multi_class='ovr', penalty='l2', random_state=None, tol=0.0001,
verbose=0)
>>> dec = lin_clf.decision_function([[1]])
>>> dec.shape[1]
4

See Mathematical formulation for a complete description of the decision function.


Note that the LinearSVC also implements an alternative multi-class strategy, the so-called multi-class SVM formu-
lated by Crammer and Singer, by using the option multi_class='crammer_singer'. This method is consis-
tent, which is not true for one-vs-rest classification. In practice, one-vs-rest classification is usually preferred, since
the results are mostly similar, but the runtime is significantly less.
For “one-vs-rest” LinearSVC the attributes coef_ and intercept_ have the shape [n_class,
n_features] and [n_class] respectively. Each row of the coefficients corresponds to one of the n_class
many “one-vs-rest” classifiers and similar for the intercepts, in the order of the “one” class.
In the case of “one-vs-one” SVC, the layout of the attributes is a little more involved. In the case of having
a linear kernel, the attributes coef_ and intercept_ have the shape [n_class * (n_class - 1) /
2, n_features] and [n_class * (n_class - 1) / 2] respectively. This is similar to the layout for
LinearSVC described above, with each row now corresponding to a binary classifier. The order for classes 0 to n is
“0 vs 1”, “0 vs 2” , . . . “0 vs n”, “1 vs 2”, “1 vs 3”, “1 vs n”, . . . “n-1 vs n”.
The shape of dual_coef_ is [n_class-1, n_SV] with a somewhat hard to grasp layout. The columns corre-
spond to the support vectors involved in any of the n_class * (n_class - 1) / 2 “one-vs-one” classifiers.
Each of the support vectors is used in n_class - 1 classifiers. The n_class - 1 entries in each row correspond
to the dual coefficients for these classifiers.
This might be made more clear by an example:
Consider a three class problem with class 0 having three support vectors 𝑣00 , 𝑣01 , 𝑣02 and class 1 and 2 having two
support vectors 𝑣10 , 𝑣11 and 𝑣20 , 𝑣21 respectively. For each support vector 𝑣𝑖𝑗 , there are two dual coefficients. Let’s call
the coefficient of support vector 𝑣𝑖𝑗 in the classifier between classes 𝑖 and 𝑘 𝛼𝑖,𝑘 𝑗
. Then dual_coef_ looks like this:

0 0
𝛼0,1 𝛼0,2 Coefficients for SVs of class 0
1 1
𝛼0,1 𝛼0,2
2 2
𝛼0,1 𝛼0,2
0 0
𝛼1,0 𝛼1,2 Coefficients for SVs of class 1
1 1
𝛼1,0 𝛼1,2
0 0
𝛼2,0 𝛼2,1 Coefficients for SVs of class 2
1 1
𝛼2,0 𝛼2,1

204 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Scores and probabilities

The decision_function method of SVC and NuSVC gives per-class scores for each sample (or a single score
per sample in the binary case). When the constructor option probability is set to True, class membership
probability estimates (from the methods predict_proba and predict_log_proba) are enabled. In the binary
case, the probabilities are calibrated using Platt scaling: logistic regression on the SVM’s scores, fit by an additional
cross-validation on the training data. In the multiclass case, this is extended as per Wu et al. (2004).
Needless to say, the cross-validation involved in Platt scaling is an expensive operation for large datasets. In addition,
the probability estimates may be inconsistent with the scores, in the sense that the “argmax” of the scores may not be
the argmax of the probabilities. (E.g., in binary classification, a sample may be labeled by predict as belonging
to a class that has probability <½ according to predict_proba.) Platt’s method is also known to have theoret-
ical issues. If confidence scores are required, but these do not have to be probabilities, then it is advisable to set
probability=False and use decision_function instead of predict_proba.

References:

• Wu, Lin and Weng, “Probability estimates for multi-class classification by pairwise coupling”, JMLR 5:975-
1005, 2004.
• Platt “Probabilistic outputs for SVMs and comparisons to regularized likelihood methods”.

Unbalanced problems

In problems where it is desired to give more importance to certain classes or certain individual samples keywords
class_weight and sample_weight can be used.
SVC (but not NuSVC) implement a keyword class_weight in the fit method. It’s a dictionary of the form
{class_label : value}, where value is a floating point number > 0 that sets the parameter C of class
class_label to C * value.

3.1. Supervised learning 205


scikit-learn user guide, Release 0.20.3

SVC, NuSVC, SVR, NuSVR and OneClassSVM implement also weights for individual samples in method fit
through keyword sample_weight. Similar to class_weight, these set the parameter C for the i-th example to
C * sample_weight[i].

Examples:

• Plot different SVM classifiers in the iris dataset,


• SVM: Maximum margin separating hyperplane,
• SVM: Separating hyperplane for unbalanced classes
• SVM-Anova: SVM with univariate feature selection,
• Non-linear SVM
• SVM: Weighted samples,

Regression

The method of Support Vector Classification can be extended to solve regression problems. This method is called
Support Vector Regression.
The model produced by support vector classification (as described above) depends only on a subset of the training
data, because the cost function for building the model does not care about training points that lie beyond the margin.
Analogously, the model produced by Support Vector Regression depends only on a subset of the training data, because
the cost function for building the model ignores any training data close to the model prediction.
There are three different implementations of Support Vector Regression: SVR, NuSVR and LinearSVR.
LinearSVR provides a faster implementation than SVR but only considers linear kernels, while NuSVR implements
a slightly different formulation than SVR and LinearSVR. See Implementation details for further details.
As with classification classes, the fit method will take as argument vectors X, y, only that in this case y is expected to
have floating point values instead of integer values:

>>> from sklearn import svm


>>> X = [[0, 0], [2, 2]]

206 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

>>> y = [0.5, 2.5]


>>> clf = svm.SVR()
>>> clf.fit(X, y)
SVR(C=1.0, cache_size=200, coef0=0.0, degree=3, epsilon=0.1,
gamma='auto_deprecated', kernel='rbf', max_iter=-1, shrinking=True,
tol=0.001, verbose=False)
>>> clf.predict([[1, 1]])
array([1.5])

Examples:

• Support Vector Regression (SVR) using linear and non-linear kernels

Density estimation, novelty detection

The class OneClassSVM implements a One-Class SVM which is used in outlier detection.
See Novelty and Outlier Detection for the description and usage of OneClassSVM.

Complexity

Support Vector Machines are powerful tools, but their compute and storage requirements increase rapidly with the
number of training vectors. The core of an SVM is a quadratic programming problem (QP), separating support
vectors from the rest of the training data. The QP solver used by this libsvm-based implementation scales between
𝑂(𝑛𝑓 𝑒𝑎𝑡𝑢𝑟𝑒𝑠 × 𝑛2𝑠𝑎𝑚𝑝𝑙𝑒𝑠 ) and 𝑂(𝑛𝑓 𝑒𝑎𝑡𝑢𝑟𝑒𝑠 × 𝑛3𝑠𝑎𝑚𝑝𝑙𝑒𝑠 ) depending on how efficiently the libsvm cache is used in
practice (dataset dependent). If the data is very sparse 𝑛𝑓 𝑒𝑎𝑡𝑢𝑟𝑒𝑠 should be replaced by the average number of non-
zero features in a sample vector.
Also note that for the linear case, the algorithm used in LinearSVC by the liblinear implementation is much more
efficient than its libsvm-based SVC counterpart and can scale almost linearly to millions of samples and/or features.

Tips on Practical Use

• Avoiding data copy: For SVC, SVR, NuSVC and NuSVR, if the data passed to certain methods is not C-ordered
contiguous, and double precision, it will be copied before calling the underlying C implementation. You can
check whether a given numpy array is C-contiguous by inspecting its flags attribute.
For LinearSVC (and LogisticRegression) any input passed as a numpy array will be copied and con-
verted to the liblinear internal sparse data representation (double precision floats and int32 indices of non-zero
components). If you want to fit a large-scale linear classifier without copying a dense numpy C-contiguous
double precision array as input we suggest to use the SGDClassifier class instead. The objective function
can be configured to be almost the same as the LinearSVC model.
• Kernel cache size: For SVC, SVR, NuSVC and NuSVR, the size of the kernel cache has a strong impact on run
times for larger problems. If you have enough RAM available, it is recommended to set cache_size to a
higher value than the default of 200(MB), such as 500(MB) or 1000(MB).
• Setting C: C is 1 by default and it’s a reasonable default choice. If you have a lot of noisy observations you
should decrease it. It corresponds to regularize more the estimation.
LinearSVC and :class‘LinearSVR‘ are less sensitive to C when it becomes large, and prediction results stop
improving after a certain threshold. Meanwhile, larger C values will take more time to train, sometimes up to
10 times longer, as shown by Fan et al. (2008)

3.1. Supervised learning 207


scikit-learn user guide, Release 0.20.3

• Support Vector Machine algorithms are not scale invariant, so it is highly recommended to scale your data.
For example, scale each attribute on the input vector X to [0,1] or [-1,+1], or standardize it to have mean 0
and variance 1. Note that the same scaling must be applied to the test vector to obtain meaningful results. See
section Preprocessing data for more details on scaling and normalization.
• Parameter nu in NuSVC/OneClassSVM /NuSVR approximates the fraction of training errors and support vec-
tors.
• In SVC, if data for classification are unbalanced (e.g. many positive and few negative), set
class_weight='balanced' and/or try different penalty parameters C.
• Randomness of the underlying implementations: The underlying implementations of SVC and NuSVC use
a random number generator only to shuffle the data for probability estimation (when probability is set to
True). This randomness can be controlled with the random_state parameter. If probability is set
to False these estimators are not random and random_state has no effect on the results. The underlying
OneClassSVM implementation is similar to the ones of SVC and NuSVC. As no probability estimation is
provided for OneClassSVM , it is not random.
The underlying LinearSVC implementation uses a random number generator to select features when fitting the
model with a dual coordinate descent (i.e when dual is set to True). It is thus not uncommon, to have slightly
different results for the same input data. If that happens, try with a smaller tol parameter. This randomness
can also be controlled with the random_state parameter. When dual is set to False the underlying
implementation of LinearSVC is not random and random_state has no effect on the results.
• Using L1 penalization as provided by LinearSVC(loss='l2', penalty='l1', dual=False)
yields a sparse solution, i.e. only a subset of feature weights is different from zero and contribute to the de-
cision function. Increasing C yields a more complex model (more feature are selected). The C value that yields
a “null” model (all weights equal to zero) can be calculated using l1_min_c.

References:

• Fan, Rong-En, et al., “LIBLINEAR: A library for large linear classification.”, Journal of machine learning
research 9.Aug (2008): 1871-1874.

Kernel functions

The kernel function can be any of the following:


• linear: ⟨𝑥, 𝑥′ ⟩.
• polynomial: (𝛾⟨𝑥, 𝑥′ ⟩ + 𝑟)𝑑 . 𝑑 is specified by keyword degree, 𝑟 by coef0.
• rbf: exp(−𝛾‖𝑥 − 𝑥′ ‖2 ). 𝛾 is specified by keyword gamma, must be greater than 0.
• sigmoid (tanh(𝛾⟨𝑥, 𝑥′ ⟩ + 𝑟)), where 𝑟 is specified by coef0.
Different kernels are specified by keyword kernel at initialization:

>>> linear_svc = svm.SVC(kernel='linear')


>>> linear_svc.kernel
'linear'
>>> rbf_svc = svm.SVC(kernel='rbf')
>>> rbf_svc.kernel
'rbf'

208 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Custom Kernels

You can define your own kernels by either giving the kernel as a python function or by precomputing the Gram matrix.
Classifiers with custom kernels behave the same way as any other classifiers, except that:
• Field support_vectors_ is now empty, only indices of support vectors are stored in support_
• A reference (and not a copy) of the first argument in the fit() method is stored for future reference. If that
array changes between the use of fit() and predict() you will have unexpected results.

Using Python functions as kernels

You can also use your own defined kernels by passing a function to the keyword kernel in the constructor.
Your kernel must take as arguments two matrices of shape (n_samples_1, n_features), (n_samples_2,
n_features) and return a kernel matrix of shape (n_samples_1, n_samples_2).
The following code defines a linear kernel and creates a classifier instance that will use that kernel:

>>> import numpy as np


>>> from sklearn import svm
>>> def my_kernel(X, Y):
... return np.dot(X, Y.T)
...
>>> clf = svm.SVC(kernel=my_kernel)

Examples:

• SVM with custom kernel.

Using the Gram matrix

Set kernel='precomputed' and pass the Gram matrix instead of X in the fit method. At the moment, the kernel
values between all training vectors and the test vectors must be provided.

>>> import numpy as np


>>> from sklearn import svm
>>> X = np.array([[0, 0], [1, 1]])
>>> y = [0, 1]
>>> clf = svm.SVC(kernel='precomputed')
>>> # linear kernel computation
>>> gram = np.dot(X, X.T)
>>> clf.fit(gram, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
kernel='precomputed', max_iter=-1, probability=False,
random_state=None, shrinking=True, tol=0.001, verbose=False)
>>> # predict on training examples
>>> clf.predict(gram)
array([0, 1])

3.1. Supervised learning 209


scikit-learn user guide, Release 0.20.3

Parameters of the RBF Kernel

When training an SVM with the Radial Basis Function (RBF) kernel, two parameters must be considered: C and
gamma. The parameter C, common to all SVM kernels, trades off misclassification of training examples against
simplicity of the decision surface. A low C makes the decision surface smooth, while a high C aims at classifying all
training examples correctly. gamma defines how much influence a single training example has. The larger gamma is,
the closer other examples must be to be affected.
Proper choice of C and gamma is critical to the SVM’s performance. One is advised to use sklearn.
model_selection.GridSearchCV with C and gamma spaced exponentially far apart to choose good values.

Examples:

• RBF SVM parameters

Mathematical formulation

A support vector machine constructs a hyper-plane or set of hyper-planes in a high or infinite dimensional space, which
can be used for classification, regression or other tasks. Intuitively, a good separation is achieved by the hyper-plane
that has the largest distance to the nearest training data points of any class (so-called functional margin), since in
general the larger the margin the lower the generalization error of the classifier.

210 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

SVC

Given training vectors 𝑥𝑖 ∈ R𝑝 , i=1,. . . , n, in two classes, and a vector 𝑦 ∈ {1, −1}𝑛 , SVC solves the following primal
problem:
𝑛
1 ∑︁
min 𝑤𝑇 𝑤 + 𝐶 𝜁𝑖
𝑤,𝑏,𝜁 2
𝑖=1
subject to 𝑦𝑖 (𝑤𝑇 𝜑(𝑥𝑖 ) + 𝑏) ≥ 1 − 𝜁𝑖 ,
𝜁𝑖 ≥ 0, 𝑖 = 1, ..., 𝑛

Its dual is
1
min 𝛼𝑇 𝑄𝛼 − 𝑒𝑇 𝛼
𝛼 2
subject to 𝑦 𝑇 𝛼 = 0
0 ≤ 𝛼𝑖 ≤ 𝐶, 𝑖 = 1, ..., 𝑛

where 𝑒 is the vector of all ones, 𝐶 > 0 is the upper bound, 𝑄 is an 𝑛 by 𝑛 positive semidefinite matrix, 𝑄𝑖𝑗 ≡
𝑦𝑖 𝑦𝑗 𝐾(𝑥𝑖 , 𝑥𝑗 ), where 𝐾(𝑥𝑖 , 𝑥𝑗 ) = 𝜑(𝑥𝑖 )𝑇 𝜑(𝑥𝑗 ) is the kernel. Here training vectors are implicitly mapped into a
higher (maybe infinite) dimensional space by the function 𝜑.
The decision function is:
𝑛
∑︁
sgn( 𝑦𝑖 𝛼𝑖 𝐾(𝑥𝑖 , 𝑥) + 𝜌)
𝑖=1

Note: While SVM models derived from libsvm and liblinear use C as regularization parameter, most other estimators
use alpha. The exact equivalence between the amount of regularization of two models depends on the exact objective
function optimized by the model. For example, when the estimator used is sklearn.linear_model.Ridge
1
regression, the relation between them is given as 𝐶 = 𝑎𝑙𝑝ℎ𝑎 .

This parameters can be accessed through the members dual_coef_ which holds the product 𝑦𝑖 𝛼𝑖 ,
support_vectors_ which holds the support vectors, and intercept_ which holds the independent term 𝜌
:

References:

• “Automatic Capacity Tuning of Very Large VC-dimension Classifiers”, I. Guyon, B. Boser, V. Vapnik -
Advances in neural information processing 1993.
• “Support-vector networks”, C. Cortes, V. Vapnik - Machine Learning, 20, 273-297 (1995).

NuSVC

We introduce a new parameter 𝜈 which controls the number of support vectors and training errors. The parameter
𝜈 ∈ (0, 1] is an upper bound on the fraction of training errors and a lower bound of the fraction of support vectors.
It can be shown that the 𝜈-SVC formulation is a reparameterization of the 𝐶-SVC and therefore mathematically
equivalent.

3.1. Supervised learning 211


scikit-learn user guide, Release 0.20.3

SVR

Given training vectors 𝑥𝑖 ∈ R𝑝 , i=1,. . . , n, and a vector 𝑦 ∈ R𝑛 𝜀-SVR solves the following primal problem:
𝑛
1 ∑︁
min * 𝑤𝑇 𝑤 + 𝐶 (𝜁𝑖 + 𝜁𝑖* )
𝑤,𝑏,𝜁,𝜁 2
𝑖=1
subject to 𝑦𝑖 − 𝑤𝑇 𝜑(𝑥𝑖 ) − 𝑏 ≤ 𝜀 + 𝜁𝑖 ,
𝑤𝑇 𝜑(𝑥𝑖 ) + 𝑏 − 𝑦𝑖 ≤ 𝜀 + 𝜁𝑖* ,
𝜁𝑖 , 𝜁𝑖* ≥ 0, 𝑖 = 1, ..., 𝑛

Its dual is
1
min (𝛼 − 𝛼* )𝑇 𝑄(𝛼 − 𝛼* ) + 𝜀𝑒𝑇 (𝛼 + 𝛼* ) − 𝑦 𝑇 (𝛼 − 𝛼* )
2
𝛼,𝛼*

subject to 𝑒𝑇 (𝛼 − 𝛼* ) = 0
0 ≤ 𝛼𝑖 , 𝛼𝑖* ≤ 𝐶, 𝑖 = 1, ..., 𝑛

where 𝑒 is the vector of all ones, 𝐶 > 0 is the upper bound, 𝑄 is an 𝑛 by 𝑛 positive semidefinite matrix, 𝑄𝑖𝑗 ≡
𝐾(𝑥𝑖 , 𝑥𝑗 ) = 𝜑(𝑥𝑖 )𝑇 𝜑(𝑥𝑗 ) is the kernel. Here training vectors are implicitly mapped into a higher (maybe infinite)
dimensional space by the function 𝜑.
The decision function is:
𝑛
∑︁
(𝛼𝑖 − 𝛼𝑖* )𝐾(𝑥𝑖 , 𝑥) + 𝜌
𝑖=1

These parameters can be accessed through the members dual_coef_ which holds the difference 𝛼𝑖 − 𝛼𝑖* ,
support_vectors_ which holds the support vectors, and intercept_ which holds the independent term 𝜌

References:

• “A Tutorial on Support Vector Regression”, Alex J. Smola, Bernhard Schölkopf - Statistics and Computing
archive Volume 14 Issue 3, August 2004, p. 199-222.

Implementation details

Internally, we use libsvm and liblinear to handle all computations. These libraries are wrapped using C and Cython.

References:

For a description of the implementation and details of the algorithms used, please refer to
• LIBSVM: A Library for Support Vector Machines.
• LIBLINEAR – A Library for Large Linear Classification.

3.1.5 Stochastic Gradient Descent

Stochastic Gradient Descent (SGD) is a simple yet very efficient approach to discriminative learning of linear clas-
sifiers under convex loss functions such as (linear) Support Vector Machines and Logistic Regression. Even though

212 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

SGD has been around in the machine learning community for a long time, it has received a considerable amount of
attention just recently in the context of large-scale learning.
SGD has been successfully applied to large-scale and sparse machine learning problems often encountered in text
classification and natural language processing. Given that the data is sparse, the classifiers in this module easily scale
to problems with more than 10^5 training examples and more than 10^5 features.
The advantages of Stochastic Gradient Descent are:
• Efficiency.
• Ease of implementation (lots of opportunities for code tuning).
The disadvantages of Stochastic Gradient Descent include:
• SGD requires a number of hyperparameters such as the regularization parameter and the number of iterations.
• SGD is sensitive to feature scaling.

Classification

Warning: Make sure you permute (shuffle) your training data before fitting the model or use shuffle=True
to shuffle after each iteration.

The class SGDClassifier implements a plain stochastic gradient descent learning routine which supports different
loss functions and penalties for classification.

As other classifiers, SGD has to be fitted with two arrays: an array X of size [n_samples, n_features] holding the
training samples, and an array Y of size [n_samples] holding the target values (class labels) for the training samples:

>>> from sklearn.linear_model import SGDClassifier


>>> X = [[0., 0.], [1., 1.]]

3.1. Supervised learning 213


scikit-learn user guide, Release 0.20.3

>>> y = [0, 1]
>>> clf = SGDClassifier(loss="hinge", penalty="l2", max_iter=5)
>>> clf.fit(X, y)
SGDClassifier(alpha=0.0001, average=False, class_weight=None,
early_stopping=False, epsilon=0.1, eta0=0.0, fit_intercept=True,
l1_ratio=0.15, learning_rate='optimal', loss='hinge', max_iter=5,
n_iter=None, n_iter_no_change=5, n_jobs=None, penalty='l2',
power_t=0.5, random_state=None, shuffle=True, tol=None,
validation_fraction=0.1, verbose=0, warm_start=False)

After being fitted, the model can then be used to predict new values:

>>> clf.predict([[2., 2.]])


array([1])

SGD fits a linear model to the training data. The member coef_ holds the model parameters:

>>> clf.coef_
array([[9.9..., 9.9...]])

Member intercept_ holds the intercept (aka offset or bias):

>>> clf.intercept_
array([-9.9...])

Whether or not the model should use an intercept, i.e. a biased hyperplane, is controlled by the parameter
fit_intercept.
To get the signed distance to the hyperplane use SGDClassifier.decision_function:

>>> clf.decision_function([[2., 2.]])


array([29.6...])

The concrete loss function can be set via the loss parameter. SGDClassifier supports the following loss func-
tions:
• loss="hinge": (soft-margin) linear Support Vector Machine,
• loss="modified_huber": smoothed hinge loss,
• loss="log": logistic regression,
• and all regression losses below.
The first two loss functions are lazy, they only update the model parameters if an example violates the margin con-
straint, which makes training very efficient and may result in sparser models, even when L2 penalty is used.
Using loss="log" or loss="modified_huber" enables the predict_proba method, which gives a vector
of probability estimates 𝑃 (𝑦|𝑥) per sample 𝑥:

>>> clf = SGDClassifier(loss="log", max_iter=5).fit(X, y)


>>> clf.predict_proba([[1., 1.]])
array([[0.00..., 0.99...]])

The concrete penalty can be set via the penalty parameter. SGD supports the following penalties:
• penalty="l2": L2 norm penalty on coef_.
• penalty="l1": L1 norm penalty on coef_.

214 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

• penalty="elasticnet": Convex combination of L2 and L1; (1 - l1_ratio) * L2 +


l1_ratio * L1.
The default setting is penalty="l2". The L1 penalty leads to sparse solutions, driving most coefficients to zero.
The Elastic Net solves some deficiencies of the L1 penalty in the presence of highly correlated attributes. The param-
eter l1_ratio controls the convex combination of L1 and L2 penalty.
SGDClassifier supports multi-class classification by combining multiple binary classifiers in a “one versus all”
(OVA) scheme. For each of the 𝐾 classes, a binary classifier is learned that discriminates between that and all other
𝐾 − 1 classes. At testing time, we compute the confidence score (i.e. the signed distances to the hyperplane) for each
classifier and choose the class with the highest confidence. The Figure below illustrates the OVA approach on the iris
dataset. The dashed lines represent the three OVA classifiers; the background colors show the decision surface induced
by the three classifiers.

In the case of multi-class classification coef_ is a two-dimensional array of shape=[n_classes,


n_features] and intercept_ is a one-dimensional array of shape=[n_classes]. The i-th row of coef_
holds the weight vector of the OVA classifier for the i-th class; classes are indexed in ascending order (see at-
tribute classes_). Note that, in principle, since they allow to create a probability model, loss="log" and
loss="modified_huber" are more suitable for one-vs-all classification.
SGDClassifier supports both weighted classes and weighted instances via the fit parameters class_weight
and sample_weight. See the examples below and the doc string of SGDClassifier.fit for further informa-
tion.

Examples:

• SGD: Maximum margin separating hyperplane,


• Plot multi-class SGD on the iris dataset
• SGD: Weighted samples
• Comparing various online solvers

3.1. Supervised learning 215


scikit-learn user guide, Release 0.20.3

• SVM: Separating hyperplane for unbalanced classes (See the Note)

SGDClassifier supports averaged SGD (ASGD). Averaging can be enabled by setting `average=True`.
ASGD works by averaging the coefficients of the plain SGD over each iteration over a sample. When using ASGD
the learning rate can be larger and even constant leading on some datasets to a speed up in training time.
For classification with a logistic loss, another variant of SGD with an averaging strategy is available with Stochastic
Average Gradient (SAG) algorithm, available as a solver in LogisticRegression.

Regression

The class SGDRegressor implements a plain stochastic gradient descent learning routine which supports different
loss functions and penalties to fit linear regression models. SGDRegressor is well suited for regression prob-
lems with a large number of training samples (> 10.000), for other problems we recommend Ridge, Lasso, or
ElasticNet.
The concrete loss function can be set via the loss parameter. SGDRegressor supports the following loss functions:
• loss="squared_loss": Ordinary least squares,
• loss="huber": Huber loss for robust regression,
• loss="epsilon_insensitive": linear Support Vector Regression.
The Huber and epsilon-insensitive loss functions can be used for robust regression. The width of the insensitive region
has to be specified via the parameter epsilon. This parameter depends on the scale of the target variables.
SGDRegressor supports averaged SGD as SGDClassifier. Averaging can be enabled by setting
`average=True`.
For regression with a squared loss and a l2 penalty, another variant of SGD with an averaging strategy is available with
Stochastic Average Gradient (SAG) algorithm, available as a solver in Ridge.

Stochastic Gradient Descent for sparse data

Note: The sparse implementation produces slightly different results than the dense implementation due to a shrunk
learning rate for the intercept.

There is built-in support for sparse data given in any matrix in a format supported by scipy.sparse. For maximum
efficiency, however, use the CSR matrix format as defined in scipy.sparse.csr_matrix.

Examples:

• Classification of text documents using sparse features

Complexity

The major advantage of SGD is its efficiency, which is basically linear in the number of training examples. If X is a
matrix of size (n, p) training has a cost of 𝑂(𝑘𝑛¯
𝑝), where k is the number of iterations (epochs) and 𝑝¯ is the average
number of non-zero attributes per sample.
Recent theoretical results, however, show that the runtime to get some desired optimization accuracy does not increase
as the training set size increases.

216 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Stopping criterion

The classes SGDClassifier and SGDRegressor provide two criteria to stop the algorithm when a given level of
convergence is reached:
• With early_stopping=True, the input data is split into a training set and a validation set. The model
is then fitted on the training set, and the stopping criterion is based on the prediction score computed on the
validation set. The size of the validation set can be changed with the parameter validation_fraction.
• With early_stopping=False, the model is fitted on the entire input data and the stopping criterion is
based on the objective function computed on the input data.
In both cases, the criterion is evaluated once by epoch, and the algorithm stops when the criterion does not improve
n_iter_no_change times in a row. The improvement is evaluated with a tolerance tol, and the algorithm stops
in any case after a maximum number of iteration max_iter.

Tips on Practical Use

• Stochastic Gradient Descent is sensitive to feature scaling, so it is highly recommended to scale your data. For
example, scale each attribute on the input vector X to [0,1] or [-1,+1], or standardize it to have mean 0 and
variance 1. Note that the same scaling must be applied to the test vector to obtain meaningful results. This can
be easily done using StandardScaler:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(X_train) # Don't cheat - fit only on training data
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test) # apply same transformation to test data

If your attributes have an intrinsic scale (e.g. word frequencies or indicator features) scaling is not needed.
• Finding a reasonable regularization term 𝛼 is best done using GridSearchCV, usually in the range 10.
0**-np.arange(1,7).
• Empirically, we found that SGD converges after observing approx. 10^6 training samples. Thus, a reasonable
first guess for the number of iterations is max_iter = np.ceil(10**6 / n), where n is the size of the
training set.
• If you apply SGD to features extracted using PCA we found that it is often wise to scale the feature values by
some constant c such that the average L2 norm of the training data equals one.
• We found that Averaged SGD works best with a larger number of features and a higher eta0

References:

• “Efficient BackProp” Y. LeCun, L. Bottou, G. Orr, K. Müller - In Neural Networks: Tricks of the Trade 1998.

Mathematical formulation

Given a set of training examples (𝑥1 , 𝑦1 ), . . . , (𝑥𝑛 , 𝑦𝑛 ) where 𝑥𝑖 ∈ R𝑚 and 𝑦𝑖 ∈ {−1, 1}, our goal is to learn a linear
scoring function 𝑓 (𝑥) = 𝑤𝑇 𝑥 + 𝑏 with model parameters 𝑤 ∈ R𝑚 and intercept 𝑏 ∈ R. In order to make predictions,
we simply look at the sign of 𝑓 (𝑥). A common choice to find the model parameters is by minimizing the regularized
training error given by
𝑛
1 ∑︁
𝐸(𝑤, 𝑏) = 𝐿(𝑦𝑖 , 𝑓 (𝑥𝑖 )) + 𝛼𝑅(𝑤)
𝑛 𝑖=1

3.1. Supervised learning 217


scikit-learn user guide, Release 0.20.3

where 𝐿 is a loss function that measures model (mis)fit and 𝑅 is a regularization term (aka penalty) that penalizes
model complexity; 𝛼 > 0 is a non-negative hyperparameter.
Different choices for 𝐿 entail different classifiers such as
• Hinge: (soft-margin) Support Vector Machines.
• Log: Logistic Regression.
• Least-Squares: Ridge Regression.
• Epsilon-Insensitive: (soft-margin) Support Vector Regression.
All of the above loss functions can be regarded as an upper bound on the misclassification error (Zero-one loss) as
shown in the Figure below.

Popular choices for the regularization term 𝑅 include:


∑︀𝑛
• L2 norm: 𝑅(𝑤) := 12 𝑖=1 𝑤𝑖2 ,
∑︀𝑛
• L1 norm: 𝑅(𝑤) := 𝑖=1 |𝑤𝑖 |, which leads to sparse solutions.
∑︀𝑛 ∑︀𝑛
• Elastic Net: 𝑅(𝑤) := 𝜌2 𝑖=1 𝑤𝑖2 + (1 − 𝜌) 𝑖=1 |𝑤𝑖 |, a convex combination of L2 and L1, where 𝜌 is given
by 1 - l1_ratio.
The Figure below shows the contours of the different regularization terms in the parameter space when 𝑅(𝑤) = 1.

SGD

Stochastic gradient descent is an optimization method for unconstrained optimization problems. In contrast to (batch)
gradient descent, SGD approximates the true gradient of 𝐸(𝑤, 𝑏) by considering a single training example at a time.
The class SGDClassifier implements a first-order SGD learning routine. The algorithm iterates over the training

218 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

3.1. Supervised learning 219


scikit-learn user guide, Release 0.20.3

examples and for each example updates the model parameters according to the update rule given by

𝜕𝑅(𝑤) 𝜕𝐿(𝑤𝑇 𝑥𝑖 + 𝑏, 𝑦𝑖 )
𝑤 ← 𝑤 − 𝜂(𝛼 + )
𝜕𝑤 𝜕𝑤
where 𝜂 is the learning rate which controls the step-size in the parameter space. The intercept 𝑏 is updated similarly
but without regularization.
The learning rate 𝜂 can be either constant or gradually decaying. For classification, the default learning rate schedule
(learning_rate='optimal') is given by
1
𝜂 (𝑡) =
𝛼(𝑡0 + 𝑡)

where 𝑡 is the time step (there are a total of n_samples * n_iter time steps), 𝑡0 is determined based on a heuristic
proposed by Léon Bottou such that the expected initial updates are comparable with the expected size of the weights
(this assuming that the norm of the training samples is approx. 1). The exact definition can be found in _init_t in
BaseSGD.
For regression the default learning rate schedule is inverse scaling (learning_rate='invscaling'), given by
𝑒𝑡𝑎0
𝜂 (𝑡) = 𝑝𝑜𝑤𝑒𝑟_𝑡
𝑡
where 𝑒𝑡𝑎0 and 𝑝𝑜𝑤𝑒𝑟_𝑡 are hyperparameters chosen by the user via eta0 and power_t, resp.
For a constant learning rate use learning_rate='constant' and use eta0 to specify the learning rate.
For an adaptively decreasing learning rate, use learning_rate='adaptive' and use eta0 to specify the start-
ing learning rate. When the stopping criterion is reached, the learning rate is divided by 5, and the algorithm does not
stop. The algorithm stops when the learning rate goes below 1e-6.
The model parameters can be accessed through the members coef_ and intercept_:
• Member coef_ holds the weights 𝑤
• Member intercept_ holds 𝑏

References:

• “Solving large scale linear prediction problems using stochastic gradient descent algorithms” T. Zhang - In
Proceedings of ICML ‘04.
• “Regularization and variable selection via the elastic net” H. Zou, T. Hastie - Journal of the Royal Statistical
Society Series B, 67 (2), 301-320.
• “Towards Optimal One Pass Large Scale Learning with Averaged Stochastic Gradient Descent” Xu, Wei

Implementation details

The implementation of SGD is influenced by the Stochastic Gradient SVM of Léon Bottou. Similar to SvmSGD,
the weight vector is represented as the product of a scalar and a vector which allows an efficient weight update in
the case of L2 regularization. In the case of sparse feature vectors, the intercept is updated with a smaller learning
rate (multiplied by 0.01) to account for the fact that it is updated more frequently. Training examples are picked up
sequentially and the learning rate is lowered after each observed example. We adopted the learning rate schedule from
Shalev-Shwartz et al. 2007. For multi-class classification, a “one versus all” approach is used. We use the truncated
gradient algorithm proposed by Tsuruoka et al. 2009 for L1 regularization (and the Elastic Net). The code is written
in Cython.

220 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

References:

• “Stochastic Gradient Descent” L. Bottou - Website, 2010.


• “The Tradeoffs of Large Scale Machine Learning” L. Bottou - Website, 2011.
• “Pegasos: Primal estimated sub-gradient solver for svm” S. Shalev-Shwartz, Y. Singer, N. Srebro - In Pro-
ceedings of ICML ‘07.
• “Stochastic gradient descent training for l1-regularized log-linear models with cumulative penalty” Y. Tsu-
ruoka, J. Tsujii, S. Ananiadou - In Proceedings of the AFNLP/ACL ‘09.

3.1.6 Nearest Neighbors

sklearn.neighbors provides functionality for unsupervised and supervised neighbors-based learning methods.
Unsupervised nearest neighbors is the foundation of many other learning methods, notably manifold learning and
spectral clustering. Supervised neighbors-based learning comes in two flavors: classification for data with discrete
labels, and regression for data with continuous labels.
The principle behind nearest neighbor methods is to find a predefined number of training samples closest in distance
to the new point, and predict the label from these. The number of samples can be a user-defined constant (k-nearest
neighbor learning), or vary based on the local density of points (radius-based neighbor learning). The distance can,
in general, be any metric measure: standard Euclidean distance is the most common choice. Neighbors-based meth-
ods are known as non-generalizing machine learning methods, since they simply “remember” all of its training data
(possibly transformed into a fast indexing structure such as a Ball Tree or KD Tree).
Despite its simplicity, nearest neighbors has been successful in a large number of classification and regression prob-
lems, including handwritten digits and satellite image scenes. Being a non-parametric method, it is often successful in
classification situations where the decision boundary is very irregular.
The classes in sklearn.neighbors can handle either NumPy arrays or scipy.sparse matrices as input. For dense
matrices, a large number of possible distance metrics are supported. For sparse matrices, arbitrary Minkowski metrics
are supported for searches.
There are many learning routines which rely on nearest neighbors at their core. One example is kernel density estima-
tion, discussed in the density estimation section.

Unsupervised Nearest Neighbors

NearestNeighbors implements unsupervised nearest neighbors learning. It acts as a uniform interface to three
different nearest neighbors algorithms: BallTree, KDTree, and a brute-force algorithm based on routines in
sklearn.metrics.pairwise. The choice of neighbors search algorithm is controlled through the keyword
'algorithm', which must be one of ['auto', 'ball_tree', 'kd_tree', 'brute']. When the de-
fault value 'auto' is passed, the algorithm attempts to determine the best approach from the training data. For a
discussion of the strengths and weaknesses of each option, see Nearest Neighbor Algorithms.

Warning: Regarding the Nearest Neighbors algorithms, if two neighbors 𝑘 + 1 and 𝑘 have identical
distances but different labels, the result will depend on the ordering of the training data.

3.1. Supervised learning 221


scikit-learn user guide, Release 0.20.3

Finding the Nearest Neighbors

For the simple task of finding the nearest neighbors between two sets of data, the unsupervised algorithms within
sklearn.neighbors can be used:

>>> from sklearn.neighbors import NearestNeighbors


>>> import numpy as np
>>> X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
>>> nbrs = NearestNeighbors(n_neighbors=2, algorithm='ball_tree').fit(X)
>>> distances, indices = nbrs.kneighbors(X)
>>> indices
array([[0, 1],
[1, 0],
[2, 1],
[3, 4],
[4, 3],
[5, 4]]...)
>>> distances
array([[0. , 1. ],
[0. , 1. ],
[0. , 1.41421356],
[0. , 1. ],
[0. , 1. ],
[0. , 1.41421356]])

Because the query set matches the training set, the nearest neighbor of each point is the point itself, at a distance of
zero.
It is also possible to efficiently produce a sparse graph showing the connections between neighboring points:

>>> nbrs.kneighbors_graph(X).toarray()
array([[1., 1., 0., 0., 0., 0.],
[1., 1., 0., 0., 0., 0.],
[0., 1., 1., 0., 0., 0.],
[0., 0., 0., 1., 1., 0.],
[0., 0., 0., 1., 1., 0.],
[0., 0., 0., 0., 1., 1.]])

The dataset is structured such that points nearby in index order are nearby in parameter space, leading to an ap-
proximately block-diagonal matrix of K-nearest neighbors. Such a sparse graph is useful in a variety of cir-
cumstances which make use of spatial relationships between points for unsupervised learning: in particular,
see sklearn.manifold.Isomap, sklearn.manifold.LocallyLinearEmbedding, and sklearn.
cluster.SpectralClustering.

KDTree and BallTree Classes

Alternatively, one can use the KDTree or BallTree classes directly to find nearest neighbors. This is the function-
ality wrapped by the NearestNeighbors class used above. The Ball Tree and KD Tree have the same interface;
we’ll show an example of using the KD Tree here:

>>> from sklearn.neighbors import KDTree


>>> import numpy as np
>>> X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
>>> kdt = KDTree(X, leaf_size=30, metric='euclidean')
>>> kdt.query(X, k=2, return_distance=False)
array([[0, 1],

222 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

[1, 0],
[2, 1],
[3, 4],
[4, 3],
[5, 4]]...)

Refer to the KDTree and BallTree class documentation for more information on the options available for nearest
neighbors searches, including specification of query strategies, distance metrics, etc. For a list of available metrics,
see the documentation of the DistanceMetric class.

Nearest Neighbors Classification

Neighbors-based classification is a type of instance-based learning or non-generalizing learning: it does not attempt
to construct a general internal model, but simply stores instances of the training data. Classification is computed from
a simple majority vote of the nearest neighbors of each point: a query point is assigned the data class which has the
most representatives within the nearest neighbors of the point.
scikit-learn implements two different nearest neighbors classifiers: KNeighborsClassifier implements learn-
ing based on the 𝑘 nearest neighbors of each query point, where 𝑘 is an integer value specified by the user.
RadiusNeighborsClassifier implements learning based on the number of neighbors within a fixed radius
𝑟 of each training point, where 𝑟 is a floating-point value specified by the user.
The 𝑘-neighbors classification in KNeighborsClassifier is the most commonly used technique. The optimal
choice of the value 𝑘 is highly data-dependent: in general a larger 𝑘 suppresses the effects of noise, but makes the
classification boundaries less distinct.
In cases where the data is not uniformly sampled, radius-based neighbors classification in
RadiusNeighborsClassifier can be a better choice. The user specifies a fixed radius 𝑟, such that
points in sparser neighborhoods use fewer nearest neighbors for the classification. For high-dimensional parameter
spaces, this method becomes less effective due to the so-called “curse of dimensionality”.
The basic nearest neighbors classification uses uniform weights: that is, the value assigned to a query point is computed
from a simple majority vote of the nearest neighbors. Under some circumstances, it is better to weight the neighbors
such that nearer neighbors contribute more to the fit. This can be accomplished through the weights keyword. The
default value, weights = 'uniform', assigns uniform weights to each neighbor. weights = 'distance'
assigns weights proportional to the inverse of the distance from the query point. Alternatively, a user-defined function
of the distance can be supplied to compute the weights.

3.1. Supervised learning 223


scikit-learn user guide, Release 0.20.3

Examples:

• Nearest Neighbors Classification: an example of classification using nearest neighbors.

Nearest Neighbors Regression

Neighbors-based regression can be used in cases where the data labels are continuous rather than discrete variables.
The label assigned to a query point is computed based on the mean of the labels of its nearest neighbors.
scikit-learn implements two different neighbors regressors: KNeighborsRegressor implements learning
based on the 𝑘 nearest neighbors of each query point, where 𝑘 is an integer value specified by the user.
RadiusNeighborsRegressor implements learning based on the neighbors within a fixed radius 𝑟 of the query
point, where 𝑟 is a floating-point value specified by the user.
The basic nearest neighbors regression uses uniform weights: that is, each point in the local neighborhood contributes
uniformly to the classification of a query point. Under some circumstances, it can be advantageous to weight points
such that nearby points contribute more to the regression than faraway points. This can be accomplished through the
weights keyword. The default value, weights = 'uniform', assigns equal weights to all points. weights
= 'distance' assigns weights proportional to the inverse of the distance from the query point. Alternatively, a
user-defined function of the distance can be supplied, which will be used to compute the weights.

The use of multi-output nearest neighbors for regression is demonstrated in Face completion with a multi-output
estimators. In this example, the inputs X are the pixels of the upper half of faces and the outputs Y are the pixels of
the lower half of those faces.

Examples:

• Nearest Neighbors regression: an example of regression using nearest neighbors.

224 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

3.1. Supervised learning 225


scikit-learn user guide, Release 0.20.3

• Face completion with a multi-output estimators: an example of multi-output regression using nearest neigh-
bors.

Nearest Neighbor Algorithms

Brute Force

Fast computation of nearest neighbors is an active area of research in machine learning. The most naive neighbor
search implementation involves the brute-force computation of distances between all pairs of points in the dataset: for
𝑁 samples in 𝐷 dimensions, this approach scales as 𝑂[𝐷𝑁 2 ]. Efficient brute-force neighbors searches can be very
competitive for small data samples. However, as the number of samples 𝑁 grows, the brute-force approach quickly
becomes infeasible. In the classes within sklearn.neighbors, brute-force neighbors searches are specified using
the keyword algorithm = 'brute', and are computed using the routines available in sklearn.metrics.
pairwise.

K-D Tree

To address the computational inefficiencies of the brute-force approach, a variety of tree-based data structures have
been invented. In general, these structures attempt to reduce the required number of distance calculations by efficiently
encoding aggregate distance information for the sample. The basic idea is that if point 𝐴 is very distant from point
𝐵, and point 𝐵 is very close to point 𝐶, then we know that points 𝐴 and 𝐶 are very distant, without having to
explicitly calculate their distance. In this way, the computational cost of a nearest neighbors search can be reduced to
𝑂[𝐷𝑁 log(𝑁 )] or better. This is a significant improvement over brute-force for large 𝑁 .
An early approach to taking advantage of this aggregate information was the KD tree data structure (short for K-
dimensional tree), which generalizes two-dimensional Quad-trees and 3-dimensional Oct-trees to an arbitrary number
of dimensions. The KD tree is a binary tree structure which recursively partitions the parameter space along the data
axes, dividing it into nested orthotropic regions into which data points are filed. The construction of a KD tree is very
fast: because partitioning is performed only along the data axes, no 𝐷-dimensional distances need to be computed.
Once constructed, the nearest neighbor of a query point can be determined with only 𝑂[log(𝑁 )] distance computations.
Though the KD tree approach is very fast for low-dimensional (𝐷 < 20) neighbors searches, it becomes inefficient
as 𝐷 grows very large: this is one manifestation of the so-called “curse of dimensionality”. In scikit-learn, KD tree
neighbors searches are specified using the keyword algorithm = 'kd_tree', and are computed using the class
KDTree.

References:

• “Multidimensional binary search trees used for associative searching”, Bentley, J.L., Communications of the
ACM (1975)

Ball Tree

To address the inefficiencies of KD Trees in higher dimensions, the ball tree data structure was developed. Where KD
trees partition data along Cartesian axes, ball trees partition data in a series of nesting hyper-spheres. This makes tree
construction more costly than that of the KD tree, but results in a data structure which can be very efficient on highly
structured data, even in very high dimensions.
A ball tree recursively divides the data into nodes defined by a centroid 𝐶 and radius 𝑟, such that each point in the
node lies within the hyper-sphere defined by 𝑟 and 𝐶. The number of candidate points for a neighbor search is reduced

226 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

through use of the triangle inequality:

|𝑥 + 𝑦| ≤ |𝑥| + |𝑦|

With this setup, a single distance calculation between a test point and the centroid is sufficient to determine a lower
and upper bound on the distance to all points within the node. Because of the spherical geometry of the ball tree nodes,
it can out-perform a KD-tree in high dimensions, though the actual performance is highly dependent on the structure
of the training data. In scikit-learn, ball-tree-based neighbors searches are specified using the keyword algorithm
= 'ball_tree', and are computed using the class sklearn.neighbors.BallTree. Alternatively, the user
can work with the BallTree class directly.

References:

• “Five balltree construction algorithms”, Omohundro, S.M., International Computer Science Institute Techni-
cal Report (1989)

Choice of Nearest Neighbors Algorithm

The optimal algorithm for a given dataset is a complicated choice, and depends on a number of factors:
• number of samples 𝑁 (i.e. n_samples) and dimensionality 𝐷 (i.e. n_features).
– Brute force query time grows as 𝑂[𝐷𝑁 ]
– Ball tree query time grows as approximately 𝑂[𝐷 log(𝑁 )]
– KD tree query time changes with 𝐷 in a way that is difficult to precisely characterise. For small 𝐷 (less
than 20 or so) the cost is approximately 𝑂[𝐷 log(𝑁 )], and the KD tree query can be very efficient. For
larger 𝐷, the cost increases to nearly 𝑂[𝐷𝑁 ], and the overhead due to the tree structure can lead to queries
which are slower than brute force.
For small data sets (𝑁 less than 30 or so), log(𝑁 ) is comparable to 𝑁 , and brute force algorithms can be more
efficient than a tree-based approach. Both KDTree and BallTree address this through providing a leaf size
parameter: this controls the number of samples at which a query switches to brute-force. This allows both
algorithms to approach the efficiency of a brute-force computation for small 𝑁 .
• data structure: intrinsic dimensionality of the data and/or sparsity of the data. Intrinsic dimensionality refers
to the dimension 𝑑 ≤ 𝐷 of a manifold on which the data lies, which can be linearly or non-linearly embedded
in the parameter space. Sparsity refers to the degree to which the data fills the parameter space (this is to be
distinguished from the concept as used in “sparse” matrices. The data matrix may have no zero entries, but the
structure can still be “sparse” in this sense).
– Brute force query time is unchanged by data structure.
– Ball tree and KD tree query times can be greatly influenced by data structure. In general, sparser data with a
smaller intrinsic dimensionality leads to faster query times. Because the KD tree internal representation is
aligned with the parameter axes, it will not generally show as much improvement as ball tree for arbitrarily
structured data.
Datasets used in machine learning tend to be very structured, and are very well-suited for tree-based queries.
• number of neighbors 𝑘 requested for a query point.
– Brute force query time is largely unaffected by the value of 𝑘
– Ball tree and KD tree query time will become slower as 𝑘 increases. This is due to two effects: first, a
larger 𝑘 leads to the necessity to search a larger portion of the parameter space. Second, using 𝑘 > 1
requires internal queueing of results as the tree is traversed.

3.1. Supervised learning 227


scikit-learn user guide, Release 0.20.3

As 𝑘 becomes large compared to 𝑁 , the ability to prune branches in a tree-based query is reduced. In this
situation, Brute force queries can be more efficient.
• number of query points. Both the ball tree and the KD Tree require a construction phase. The cost of this
construction becomes negligible when amortized over many queries. If only a small number of queries will
be performed, however, the construction can make up a significant fraction of the total cost. If very few query
points will be required, brute force is better than a tree-based method.
Currently, algorithm = 'auto' selects 'kd_tree' if 𝑘 < 𝑁/2 and the 'effective_metric_'
is in the 'VALID_METRICS' list of 'kd_tree'. It selects 'ball_tree' if 𝑘 < 𝑁/2 and the
'effective_metric_' is in the 'VALID_METRICS' list of 'ball_tree'. It selects 'brute' if 𝑘 < 𝑁/2
and the 'effective_metric_' is not in the 'VALID_METRICS' list of 'kd_tree' or 'ball_tree'. It
selects 'brute' if 𝑘 >= 𝑁/2. This choice is based on the assumption that the number of query points is at least the
same order as the number of training points, and that leaf_size is close to its default value of 30.

Effect of leaf_size

As noted above, for small sample sizes a brute force search can be more efficient than a tree-based query. This fact is
accounted for in the ball tree and KD tree by internally switching to brute force searches within leaf nodes. The level
of this switch can be specified with the parameter leaf_size. This parameter choice has many effects:
construction time A larger leaf_size leads to a faster tree construction time, because fewer nodes need to be
created
query time Both a large or small leaf_size can lead to suboptimal query cost. For leaf_size approaching
1, the overhead involved in traversing nodes can significantly slow query times. For leaf_size approach-
ing the size of the training set, queries become essentially brute force. A good compromise between these is
leaf_size = 30, the default value of the parameter.
memory As leaf_size increases, the memory required to store a tree structure decreases. This is especially
important in the case of ball tree, which stores a 𝐷-dimensional centroid for each node. The required storage
space for BallTree is approximately 1 / leaf_size times the size of the training set.
leaf_size is not referenced for brute force queries.

Nearest Centroid Classifier

The NearestCentroid classifier is a simple algorithm that represents each class by the centroid of its members.
In effect, this makes it similar to the label updating phase of the sklearn.KMeans algorithm. It also has no param-
eters to choose, making it a good baseline classifier. It does, however, suffer on non-convex classes, as well as when
classes have drastically different variances, as equal variance in all dimensions is assumed. See Linear Discrim-
inant Analysis (sklearn.discriminant_analysis.LinearDiscriminantAnalysis) and Quadratic
Discriminant Analysis (sklearn.discriminant_analysis.QuadraticDiscriminantAnalysis) for
more complex methods that do not make this assumption. Usage of the default NearestCentroid is simple:

>>> from sklearn.neighbors.nearest_centroid import NearestCentroid


>>> import numpy as np
>>> X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
>>> y = np.array([1, 1, 1, 2, 2, 2])
>>> clf = NearestCentroid()
>>> clf.fit(X, y)
NearestCentroid(metric='euclidean', shrink_threshold=None)
>>> print(clf.predict([[-0.8, -1]]))
[1]

228 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Nearest Shrunken Centroid

The NearestCentroid classifier has a shrink_threshold parameter, which implements the nearest shrunken
centroid classifier. In effect, the value of each feature for each centroid is divided by the within-class variance of that
feature. The feature values are then reduced by shrink_threshold. Most notably, if a particular feature value
crosses zero, it is set to zero. In effect, this removes the feature from affecting the classification. This is useful, for
example, for removing noisy features.
In the example below, using a small shrink threshold increases the accuracy of the model from 0.81 to 0.82.

Examples:

• Nearest Centroid Classification: an example of classification using nearest centroid with different shrink
thresholds.

3.1.7 Gaussian Processes

Gaussian Processes (GP) are a generic supervised learning method designed to solve regression and probabilistic
classification problems.
The advantages of Gaussian processes are:
• The prediction interpolates the observations (at least for regular kernels).
• The prediction is probabilistic (Gaussian) so that one can compute empirical confidence intervals and decide
based on those if one should refit (online fitting, adaptive fitting) the prediction in some region of interest.
• Versatile: different kernels can be specified. Common kernels are provided, but it is also possible to specify
custom kernels.
The disadvantages of Gaussian processes include:
• They are not sparse, i.e., they use the whole samples/features information to perform the prediction.
• They lose efficiency in high dimensional spaces – namely when the number of features exceeds a few dozens.

Gaussian Process Regression (GPR)

The GaussianProcessRegressor implements Gaussian processes (GP) for regression purposes. For this, the
prior of the GP needs to be specified. The prior mean is assumed to be constant and zero (for normalize_y=False)

3.1. Supervised learning 229


scikit-learn user guide, Release 0.20.3

or the training data’s mean (for normalize_y=True). The prior’s covariance is specified by passing a kernel object.
The hyperparameters of the kernel are optimized during fitting of GaussianProcessRegressor by maximizing the log-
marginal-likelihood (LML) based on the passed optimizer. As the LML may have multiple local optima, the
optimizer can be started repeatedly by specifying n_restarts_optimizer. The first run is always conducted
starting from the initial hyperparameter values of the kernel; subsequent runs are conducted from hyperparameter
values that have been chosen randomly from the range of allowed values. If the initial hyperparameters should be kept
fixed, None can be passed as optimizer.
The noise level in the targets can be specified by passing it via the parameter alpha, either globally as a scalar or
per datapoint. Note that a moderate noise level can also be helpful for dealing with numeric issues during fitting as
it is effectively implemented as Tikhonov regularization, i.e., by adding it to the diagonal of the kernel matrix. An
alternative to specifying the noise level explicitly is to include a WhiteKernel component into the kernel, which can
estimate the global noise level from the data (see example below).
The implementation is based on Algorithm 2.1 of [RW2006]. In addition to the API of standard scikit-learn estimators,
GaussianProcessRegressor:
• allows prediction without prior fitting (based on the GP prior)
• provides an additional method sample_y(X), which evaluates samples drawn from the GPR (prior or poste-
rior) at given inputs
• exposes a method log_marginal_likelihood(theta), which can be used externally for other ways of
selecting hyperparameters, e.g., via Markov chain Monte Carlo.

GPR examples

GPR with noise-level estimation

This example illustrates that GPR with a sum-kernel including a WhiteKernel can estimate the noise level of data. An
illustration of the log-marginal-likelihood (LML) landscape shows that there exist two local maxima of LML.
The first corresponds to a model with a high noise level and a large length scale, which explains all variations in the
data by noise.
The second one has a smaller noise level and shorter length scale, which explains most of the variation by the noise-
free functional relationship. The second model has a higher likelihood; however, depending on the initial value for the
hyperparameters, the gradient-based optimization might also converge to the high-noise solution. It is thus important
to repeat the optimization several times for different initializations.

Comparison of GPR and Kernel Ridge Regression

Both kernel ridge regression (KRR) and GPR learn a target function by employing internally the “kernel trick”. KRR
learns a linear function in the space induced by the respective kernel which corresponds to a non-linear function in
the original space. The linear function in the kernel space is chosen based on the mean-squared error loss with ridge
regularization. GPR uses the kernel to define the covariance of a prior distribution over the target functions and uses
the observed training data to define a likelihood function. Based on Bayes theorem, a (Gaussian) posterior distribution
over target functions is defined, whose mean is used for prediction.
A major difference is that GPR can choose the kernel’s hyperparameters based on gradient-ascent on the marginal
likelihood function while KRR needs to perform a grid search on a cross-validated loss function (mean-squared error
loss). A further difference is that GPR learns a generative, probabilistic model of the target function and can thus
provide meaningful confidence intervals and posterior samples along with the predictions while KRR only provides
predictions.

230 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

3.1. Supervised learning 231


scikit-learn user guide, Release 0.20.3

232 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

3.1. Supervised learning 233


scikit-learn user guide, Release 0.20.3

The following figure illustrates both methods on an artificial dataset, which consists of a sinusoidal target function
and strong noise. The figure compares the learned model of KRR and GPR based on a ExpSineSquared kernel,
which is suited for learning periodic functions. The kernel’s hyperparameters control the smoothness (length_scale)
and periodicity of the kernel (periodicity). Moreover, the noise level of the data is learned explicitly by GPR by an
additional WhiteKernel component in the kernel and by the regularization parameter alpha of KRR.

The figure shows that both methods learn reasonable models of the target function. GPR correctly identifies the peri-
odicity of the function to be roughly 2 * 𝜋 (6.28), while KRR chooses the doubled periodicity 4 * 𝜋 . Besides that, GPR
provides reasonable confidence bounds on the prediction which are not available for KRR. A major difference between
the two methods is the time required for fitting and predicting: while fitting KRR is fast in principle, the grid-search
for hyperparameter optimization scales exponentially with the number of hyperparameters (“curse of dimensional-
ity”). The gradient-based optimization of the parameters in GPR does not suffer from this exponential scaling and is
thus considerable faster on this example with 3-dimensional hyperparameter space. The time for predicting is similar;
however, generating the variance of the predictive distribution of GPR takes considerable longer than just predicting
the mean.

GPR on Mauna Loa CO2 data

This example is based on Section 5.4.3 of [RW2006]. It illustrates an example of complex kernel engineering and
hyperparameter optimization using gradient ascent on the log-marginal-likelihood. The data consists of the monthly
average atmospheric CO2 concentrations (in parts per million by volume (ppmv)) collected at the Mauna Loa Obser-
vatory in Hawaii, between 1958 and 1997. The objective is to model the CO2 concentration as a function of the time
t.
The kernel is composed of several terms that are responsible for explaining different properties of the signal:
• a long term, smooth rising trend is to be explained by an RBF kernel. The RBF kernel with a large length-scale
enforces this component to be smooth; it is not enforced that the trend is rising which leaves this choice to the
GP. The specific length-scale and the amplitude are free hyperparameters.
• a seasonal component, which is to be explained by the periodic ExpSineSquared kernel with a fixed periodicity
of 1 year. The length-scale of this periodic component, controlling its smoothness, is a free parameter. In order
to allow decaying away from exact periodicity, the product with an RBF kernel is taken. The length-scale of this
RBF component controls the decay time and is a further free parameter.

234 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

• smaller, medium term irregularities are to be explained by a RationalQuadratic kernel component, whose length-
scale and alpha parameter, which determines the diffuseness of the length-scales, are to be determined. Ac-
cording to [RW2006], these irregularities can better be explained by a RationalQuadratic than an RBF kernel
component, probably because it can accommodate several length-scales.
• a “noise” term, consisting of an RBF kernel contribution, which shall explain the correlated noise components
such as local weather phenomena, and a WhiteKernel contribution for the white noise. The relative amplitudes
and the RBF’s length scale are further free parameters.
Maximizing the log-marginal-likelihood after subtracting the target’s mean yields the following kernel with an LML
of -83.214:

34.4**2 * RBF(length_scale=41.8)
+ 3.27**2 * RBF(length_scale=180) * ExpSineSquared(length_scale=1.44,
periodicity=1)
+ 0.446**2 * RationalQuadratic(alpha=17.7, length_scale=0.957)
+ 0.197**2 * RBF(length_scale=0.138) + WhiteKernel(noise_level=0.0336)

Thus, most of the target signal (34.4ppm) is explained by a long-term rising trend (length-scale 41.8 years). The
periodic component has an amplitude of 3.27ppm, a decay time of 180 years and a length-scale of 1.44. The long
decay time indicates that we have a locally very close to periodic seasonal component. The correlated noise has an
amplitude of 0.197ppm with a length scale of 0.138 years and a white-noise contribution of 0.197ppm. Thus, the
overall noise level is very small, indicating that the data can be very well explained by the model. The figure shows
also that the model makes very confident predictions until around 2015

3.1. Supervised learning 235


scikit-learn user guide, Release 0.20.3

Gaussian Process Classification (GPC)

The GaussianProcessClassifier implements Gaussian processes (GP) for classification purposes, more
specifically for probabilistic classification, where test predictions take the form of class probabilities. GaussianPro-
cessClassifier places a GP prior on a latent function 𝑓 , which is then squashed through a link function to obtain the
probabilistic classification. The latent function 𝑓 is a so-called nuisance function, whose values are not observed and
are not relevant by themselves. Its purpose is to allow a convenient formulation of the model, and 𝑓 is removed (inte-
grated out) during prediction. GaussianProcessClassifier implements the logistic link function, for which the integral
cannot be computed analytically but is easily approximated in the binary case.
In contrast to the regression setting, the posterior of the latent function 𝑓 is not Gaussian even for a GP prior since
a Gaussian likelihood is inappropriate for discrete class labels. Rather, a non-Gaussian likelihood corresponding to
the logistic link function (logit) is used. GaussianProcessClassifier approximates the non-Gaussian posterior with a
Gaussian based on the Laplace approximation. More details can be found in Chapter 3 of [RW2006].
The GP prior mean is assumed to be zero. The prior’s covariance is specified by passing a kernel object. The hyper-
parameters of the kernel are optimized during fitting of GaussianProcessRegressor by maximizing the log-marginal-
likelihood (LML) based on the passed optimizer. As the LML may have multiple local optima, the optimizer can
be started repeatedly by specifying n_restarts_optimizer. The first run is always conducted starting from the
initial hyperparameter values of the kernel; subsequent runs are conducted from hyperparameter values that have been
chosen randomly from the range of allowed values. If the initial hyperparameters should be kept fixed, None can be
passed as optimizer.
GaussianProcessClassifier supports multi-class classification by performing either one-versus-rest or one-
versus-one based training and prediction. In one-versus-rest, one binary Gaussian process classifier is fitted for each
class, which is trained to separate this class from the rest. In “one_vs_one”, one binary Gaussian process classifier is
fitted for each pair of classes, which is trained to separate these two classes. The predictions of these binary predictors
are combined into multi-class predictions. See the section on multi-class classification for more details.
In the case of Gaussian process classification, “one_vs_one” might be computationally cheaper since it has to solve
many problems involving only a subset of the whole training set rather than fewer problems on the whole dataset. Since
Gaussian process classification scales cubically with the size of the dataset, this might be considerably faster. How-
ever, note that “one_vs_one” does not support predicting probability estimates but only plain predictions. Moreover,
note that GaussianProcessClassifier does not (yet) implement a true multi-class Laplace approximation in-
ternally, but as discussed above is based on solving several binary classification tasks internally, which are combined
using one-versus-rest or one-versus-one.

GPC examples

Probabilistic predictions with GPC

This example illustrates the predicted probability of GPC for an RBF kernel with different choices of the hyperparam-
eters. The first figure shows the predicted probability of GPC with arbitrarily chosen hyperparameters and with the
hyperparameters corresponding to the maximum log-marginal-likelihood (LML).
While the hyperparameters chosen by optimizing LML have a considerable larger LML, they perform slightly worse
according to the log-loss on test data. The figure shows that this is because they exhibit a steep change of the class
probabilities at the class boundaries (which is good) but have predicted probabilities close to 0.5 far away from the
class boundaries (which is bad) This undesirable effect is caused by the Laplace approximation used internally by
GPC.
The second figure shows the log-marginal-likelihood for different choices of the kernel’s hyperparameters, highlighting
the two choices of the hyperparameters used in the first figure by black dots.

236 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

3.1. Supervised learning 237


scikit-learn user guide, Release 0.20.3

238 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Illustration of GPC on the XOR dataset

This example illustrates GPC on XOR data. Compared are a stationary, isotropic kernel (RBF) and a non-stationary
kernel (DotProduct). On this particular dataset, the DotProduct kernel obtains considerably better results because
the class-boundaries are linear and coincide with the coordinate axes. In practice, however, stationary kernels such as
RBF often obtain better results.

Gaussian process classification (GPC) on iris dataset

This example illustrates the predicted probability of GPC for an isotropic and anisotropic RBF kernel on a two-
dimensional version for the iris-dataset. This illustrates the applicability of GPC to non-binary classification. The
anisotropic RBF kernel obtains slightly higher log-marginal-likelihood by assigning different length-scales to the two
feature dimensions.

Kernels for Gaussian Processes

Kernels (also called “covariance functions” in the context of GPs) are a crucial ingredient of GPs which determine
the shape of prior and posterior of the GP. They encode the assumptions on the function being learned by defining the
“similarity” of two datapoints combined with the assumption that similar datapoints should have similar target values.
Two categories of kernels can be distinguished: stationary kernels depend only on the distance of two datapoints
and not on their absolute values 𝑘(𝑥𝑖 , 𝑥𝑗 ) = 𝑘(𝑑(𝑥𝑖 , 𝑥𝑗 )) and are thus invariant to translations in the input space,
while non-stationary kernels depend also on the specific values of the datapoints. Stationary kernels can further be
subdivided into isotropic and anisotropic kernels, where isotropic kernels are also invariant to rotations in the input
space. For more details, we refer to Chapter 4 of [RW2006].

Gaussian Process Kernel API

The main usage of a Kernel is to compute the GP’s covariance between datapoints. For this, the method __call__
of the kernel can be called. This method can either be used to compute the “auto-covariance” of all pairs of datapoints

3.1. Supervised learning 239


scikit-learn user guide, Release 0.20.3

in a 2d array X, or the “cross-covariance” of all combinations of datapoints of a 2d array X with datapoints in a 2d


array Y. The following identity holds true for all kernels k (except for the WhiteKernel): k(X) == K(X, Y=X)
If only the diagonal of the auto-covariance is being used, the method diag() of a kernel can be called, which is more
computationally efficient than the equivalent call to __call__: np.diag(k(X, X)) == k.diag(X)
Kernels are parameterized by a vector 𝜃 of hyperparameters. These hyperparameters can for instance control length-
scales or periodicity of a kernel (see below). All kernels support computing analytic gradients of the kernel’s auto-
covariance with respect to 𝜃 via setting eval_gradient=True in the __call__ method. This gradient is used by
the Gaussian process (both regressor and classifier) in computing the gradient of the log-marginal-likelihood, which
in turn is used to determine the value of 𝜃, which maximizes the log-marginal-likelihood, via gradient ascent. For
each hyperparameter, the initial value and the bounds need to be specified when creating an instance of the kernel.
The current value of 𝜃 can be get and set via the property theta of the kernel object. Moreover, the bounds of the
hyperparameters can be accessed by the property bounds of the kernel. Note that both properties (theta and bounds)
return log-transformed values of the internally used values since those are typically more amenable to gradient-based
optimization. The specification of each hyperparameter is stored in the form of an instance of Hyperparameter
in the respective kernel. Note that a kernel using a hyperparameter with name “x” must have the attributes self.x and
self.x_bounds.
The abstract base class for all kernels is Kernel. Kernel implements a similar interface as Estimator, providing
the methods get_params(), set_params(), and clone(). This allows setting kernel values also via meta-
estimators such as Pipeline or GridSearch. Note that due to the nested structure of kernels (by applying kernel
operators, see below), the names of kernel parameters might become relatively complicated. In general, for a binary
kernel operator, parameters of the left operand are prefixed with k1__ and parameters of the right operand with k2__.
An additional convenience method is clone_with_theta(theta), which returns a cloned version of the kernel
but with the hyperparameters set to theta. An illustrative example:
>>> from sklearn.gaussian_process.kernels import ConstantKernel, RBF
>>> kernel = ConstantKernel(constant_value=1.0, constant_value_bounds=(0.0, 10.0)) *
˓→RBF(length_scale=0.5, length_scale_bounds=(0.0, 10.0)) + RBF(length_scale=2.0,

˓→length_scale_bounds=(0.0, 10.0))

>>> for hyperparameter in kernel.hyperparameters: print(hyperparameter)


Hyperparameter(name='k1__k1__constant_value', value_type='numeric', bounds=array([[ 0.
˓→, 10.]]), n_elements=1, fixed=False)

Hyperparameter(name='k1__k2__length_scale', value_type='numeric', bounds=array([[ 0.,


˓→10.]]), n_elements=1, fixed=False)

240 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Hyperparameter(name='k2__length_scale', value_type='numeric', bounds=array([[ 0., 10.


˓→]]), n_elements=1, fixed=False)

>>> params = kernel.get_params()


>>> for key in sorted(params): print("%s : %s" % (key, params[key]))
k1 : 1**2 * RBF(length_scale=0.5)
k1__k1 : 1**2
k1__k1__constant_value : 1.0
k1__k1__constant_value_bounds : (0.0, 10.0)
k1__k2 : RBF(length_scale=0.5)
k1__k2__length_scale : 0.5
k1__k2__length_scale_bounds : (0.0, 10.0)
k2 : RBF(length_scale=2)
k2__length_scale : 2.0
k2__length_scale_bounds : (0.0, 10.0)
>>> print(kernel.theta) # Note: log-transformed
[ 0. -0.69314718 0.69314718]
>>> print(kernel.bounds) # Note: log-transformed
[[ -inf 2.30258509]
[ -inf 2.30258509]
[ -inf 2.30258509]]

All Gaussian process kernels are interoperable with sklearn.metrics.pairwise and vice versa: instances
of subclasses of Kernel can be passed as metric to pairwise_kernels from sklearn.metrics.
pairwise. Moreover, kernel functions from pairwise can be used as GP kernels by using the wrapper class
PairwiseKernel. The only caveat is that the gradient of the hyperparameters is not analytic but numeric and
all those kernels support only isotropic distances. The parameter gamma is considered to be a hyperparameter and
may be optimized. The other kernel parameters are set directly at initialization and are kept fixed.

Basic kernels

The ConstantKernel kernel can be used as part of a Product kernel where it scales the magnitude of the other
factor (kernel) or as part of a Sum kernel, where it modifies the mean of the Gaussian process. It depends on a
parameter 𝑐𝑜𝑛𝑠𝑡𝑎𝑛𝑡_𝑣𝑎𝑙𝑢𝑒. It is defined as:

𝑘(𝑥𝑖 , 𝑥𝑗 ) = 𝑐𝑜𝑛𝑠𝑡𝑎𝑛𝑡_𝑣𝑎𝑙𝑢𝑒 ∀ 𝑥1 , 𝑥2

The main use-case of the WhiteKernel kernel is as part of a sum-kernel where it explains the noise-component of
the signal. Tuning its parameter 𝑛𝑜𝑖𝑠𝑒_𝑙𝑒𝑣𝑒𝑙 corresponds to estimating the noise-level. It is defined as:

𝑘(𝑥𝑖 , 𝑥𝑗 ) = 𝑛𝑜𝑖𝑠𝑒_𝑙𝑒𝑣𝑒𝑙 if 𝑥𝑖 == 𝑥𝑗 else 0

Kernel operators

Kernel operators take one or two base kernels and combine them into a new kernel. The Sum kernel takes two kernels
𝑘1 and 𝑘2 and combines them via 𝑘𝑠𝑢𝑚 (𝑋, 𝑌 ) = 𝑘1(𝑋, 𝑌 ) + 𝑘2(𝑋, 𝑌 ). The Product kernel takes two kernels 𝑘1
and 𝑘2 and combines them via 𝑘𝑝𝑟𝑜𝑑𝑢𝑐𝑡 (𝑋, 𝑌 ) = 𝑘1(𝑋, 𝑌 ) * 𝑘2(𝑋, 𝑌 ). The Exponentiation kernel takes one
base kernel and a scalar parameter 𝑒𝑥𝑝𝑜𝑛𝑒𝑛𝑡 and combines them via 𝑘𝑒𝑥𝑝 (𝑋, 𝑌 ) = 𝑘(𝑋, 𝑌 )exponent .

Radial-basis function (RBF) kernel

The RBF kernel is a stationary kernel. It is also known as the “squared exponential” kernel. It is parameterized by a
length-scale parameter 𝑙 > 0, which can either be a scalar (isotropic variant of the kernel) or a vector with the same

3.1. Supervised learning 241


scikit-learn user guide, Release 0.20.3

number of dimensions as the inputs 𝑥 (anisotropic variant of the kernel). The kernel is given by:
(︂ )︂
1 2
𝑘(𝑥𝑖 , 𝑥𝑗 ) = exp − 𝑑(𝑥𝑖 /𝑙, 𝑥𝑗 /𝑙)
2
This kernel is infinitely differentiable, which implies that GPs with this kernel as covariance function have mean square
derivatives of all orders, and are thus very smooth. The prior and posterior of a GP resulting from an RBF kernel are
shown in the following figure:

Matérn kernel

The Matern kernel is a stationary kernel and a generalization of the RBF kernel. It has an additional parameter 𝜈
which controls the smoothness of the resulting function. It is parameterized by a length-scale parameter 𝑙 > 0, which

242 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

can either be a scalar (isotropic variant of the kernel) or a vector with the same number of dimensions as the inputs 𝑥
(anisotropic variant of the kernel). The kernel is given by:
(︃ )︃𝜈 (︃ )︃
1 √ √
𝑘(𝑥𝑖 , 𝑥𝑗 ) = 𝜎 2 𝛾 2𝜈𝑑(𝑥𝑖 /𝑙, 𝑥𝑗 /𝑙) 𝐾𝜈 𝛾 2𝜈𝑑(𝑥𝑖 /𝑙, 𝑥𝑗 /𝑙) ,
Γ(𝜈)2𝜈−1

As 𝜈 → ∞, the Matérn kernel converges to the RBF kernel. When 𝜈 = 1/2, the Matérn kernel becomes identical to
the absolute exponential kernel, i.e.,
(︃ )︃
𝑘(𝑥𝑖 , 𝑥𝑗 ) = 𝜎 2 exp − 𝛾𝑑(𝑥𝑖 /𝑙, 𝑥𝑗 /𝑙) 𝜈= 1
2

In particular, 𝜈 = 3/2:
(︃ )︃ (︃ )︃
√ √
𝑘(𝑥𝑖 , 𝑥𝑗 ) = 𝜎 2 1 + 𝛾 3𝑑(𝑥𝑖 /𝑙, 𝑥𝑗 /𝑙) exp − 𝛾 3𝑑(𝑥𝑖 /𝑙, 𝑥𝑗 /𝑙) 𝜈= 3
2

and 𝜈 = 5/2:
(︃ )︃ (︃ )︃
2
√ 5 √
𝑘(𝑥𝑖 , 𝑥𝑗 ) = 𝜎 1 + 𝛾 5𝑑(𝑥𝑖 /𝑙, 𝑥𝑗 /𝑙) + 𝛾 2 𝑑(𝑥𝑖 /𝑙, 𝑥𝑗 /𝑙)2 exp − 𝛾 5𝑑(𝑥𝑖 /𝑙, 𝑥𝑗 /𝑙) 𝜈= 5
2
3

are popular choices for learning functions that are not infinitely differentiable (as assumed by the RBF kernel) but at
least once (𝜈 = 3/2) or twice differentiable (𝜈 = 5/2).
The flexibility of controlling the smoothness of the learned function via 𝜈 allows adapting to the properties of the
true underlying functional relation. The prior and posterior of a GP resulting from a Matérn kernel are shown in the
following figure:
See [RW2006], pp84 for further details regarding the different variants of the Matérn kernel.

Rational quadratic kernel

The RationalQuadratic kernel can be seen as a scale mixture (an infinite sum) of RBF kernels with different
characteristic length-scales. It is parameterized by a length-scale parameter 𝑙 > 0 and a scale mixture parameter 𝛼 > 0
Only the isotropic variant where 𝑙 is a scalar is supported at the moment. The kernel is given by:
)︂−𝛼
𝑑(𝑥𝑖 , 𝑥𝑗 )2
(︂
𝑘(𝑥𝑖 , 𝑥𝑗 ) = 1+
2𝛼𝑙2

The prior and posterior of a GP resulting from a RationalQuadratic kernel are shown in the following figure:

Exp-Sine-Squared kernel

The ExpSineSquared kernel allows modeling periodic functions. It is parameterized by a length-scale parameter
𝑙 > 0 and a periodicity parameter 𝑝 > 0. Only the isotropic variant where 𝑙 is a scalar is supported at the moment.
The kernel is given by:
(︁ )︁
2
𝑘(𝑥𝑖 , 𝑥𝑗 ) = exp −2 (sin(𝜋/𝑝 * 𝑑(𝑥𝑖 , 𝑥𝑗 ))/𝑙)

The prior and posterior of a GP resulting from an ExpSineSquared kernel are shown in the following figure:

3.1. Supervised learning 243


scikit-learn user guide, Release 0.20.3

244 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

3.1. Supervised learning 245


scikit-learn user guide, Release 0.20.3

246 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Dot-Product kernel

The DotProduct kernel is non-stationary and can be obtained from linear regression by putting 𝑁 (0, 1) priors on
the coefficients of 𝑥𝑑 (𝑑 = 1, ..., 𝐷) and a prior of 𝑁 (0, 𝜎02 ) on the bias. The DotProduct kernel is invariant to a
rotation of the coordinates about the origin, but not translations. It is parameterized by a parameter 𝜎02 . For 𝜎02 = 0,
the kernel is called the homogeneous linear kernel, otherwise it is inhomogeneous. The kernel is given by

𝑘(𝑥𝑖 , 𝑥𝑗 ) = 𝜎02 + 𝑥𝑖 · 𝑥𝑗

The DotProduct kernel is commonly combined with exponentiation. An example with exponent 2 is shown in the
following figure:

3.1. Supervised learning 247


scikit-learn user guide, Release 0.20.3

References

3.1.8 Cross decomposition

The cross decomposition module contains two main families of algorithms: the partial least squares (PLS) and the
canonical correlation analysis (CCA).
These families of algorithms are useful to find linear relations between two multivariate datasets: the X and Y argu-
ments of the fit method are 2D arrays.

Cross decomposition algorithms find the fundamental relations between two matrices (X and Y). They are latent
variable approaches to modeling the covariance structures in these two spaces. They will try to find the multidi-
mensional direction in the X space that explains the maximum multidimensional variance direction in the Y space.
PLS-regression is particularly suited when the matrix of predictors has more variables than observations, and when
there is multicollinearity among X values. By contrast, standard regression will fail in these cases.
Classes included in this module are PLSRegression PLSCanonical, CCA and PLSSVD

Reference:

• JA Wegelin A survey of Partial Least Squares (PLS) methods, with emphasis on the two-block case

Examples:

248 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

• Compare cross decomposition methods

3.1.9 Naive Bayes

Naive Bayes methods are a set of supervised learning algorithms based on applying Bayes’ theorem with the “naive”
assumption of conditional independence between every pair of features given the value of the class variable. Bayes’
theorem states the following relationship, given class variable 𝑦 and dependent feature vector 𝑥1 through 𝑥𝑛 , :

𝑃 (𝑦)𝑃 (𝑥1 , . . . 𝑥𝑛 | 𝑦)
𝑃 (𝑦 | 𝑥1 , . . . , 𝑥𝑛 ) =
𝑃 (𝑥1 , . . . , 𝑥𝑛 )

Using the naive conditional independence assumption that

𝑃 (𝑥𝑖 |𝑦, 𝑥1 , . . . , 𝑥𝑖−1 , 𝑥𝑖+1 , . . . , 𝑥𝑛 ) = 𝑃 (𝑥𝑖 |𝑦),

for all 𝑖, this relationship is simplified to


∏︀𝑛
𝑃 (𝑦) 𝑖=1 𝑃 (𝑥𝑖 | 𝑦)
𝑃 (𝑦 | 𝑥1 , . . . , 𝑥𝑛 ) =
𝑃 (𝑥1 , . . . , 𝑥𝑛 )

Since 𝑃 (𝑥1 , . . . , 𝑥𝑛 ) is constant given the input, we can use the following classification rule:
𝑛
∏︁
𝑃 (𝑦 | 𝑥1 , . . . , 𝑥𝑛 ) ∝ 𝑃 (𝑦) 𝑃 (𝑥𝑖 | 𝑦)
𝑖=1

𝑛
∏︁
𝑦ˆ = arg max 𝑃 (𝑦) 𝑃 (𝑥𝑖 | 𝑦),
𝑦
𝑖=1

and we can use Maximum A Posteriori (MAP) estimation to estimate 𝑃 (𝑦) and 𝑃 (𝑥𝑖 | 𝑦); the former is then the
relative frequency of class 𝑦 in the training set.
The different naive Bayes classifiers differ mainly by the assumptions they make regarding the distribution of 𝑃 (𝑥𝑖 |
𝑦).
In spite of their apparently over-simplified assumptions, naive Bayes classifiers have worked quite well in many real-
world situations, famously document classification and spam filtering. They require a small amount of training data to
estimate the necessary parameters. (For theoretical reasons why naive Bayes works well, and on which types of data
it does, see the references below.)
Naive Bayes learners and classifiers can be extremely fast compared to more sophisticated methods. The decoupling
of the class conditional feature distributions means that each distribution can be independently estimated as a one
dimensional distribution. This in turn helps to alleviate problems stemming from the curse of dimensionality.
On the flip side, although naive Bayes is known as a decent classifier, it is known to be a bad estimator, so the
probability outputs from predict_proba are not to be taken too seriously.

References:

• H. Zhang (2004). The optimality of Naive Bayes. Proc. FLAIRS.

3.1. Supervised learning 249


scikit-learn user guide, Release 0.20.3

Gaussian Naive Bayes

GaussianNB implements the Gaussian Naive Bayes algorithm for classification. The likelihood of the features is
assumed to be Gaussian:
(𝑥𝑖 − 𝜇𝑦 )2
(︂ )︂
1
𝑃 (𝑥𝑖 | 𝑦) = exp −
2𝜎𝑦2
√︁
2𝜋𝜎𝑦2

The parameters 𝜎𝑦 and 𝜇𝑦 are estimated using maximum likelihood.

>>> from sklearn import datasets


>>> iris = datasets.load_iris()
>>> from sklearn.naive_bayes import GaussianNB
>>> gnb = GaussianNB()
>>> y_pred = gnb.fit(iris.data, iris.target).predict(iris.data)
>>> print("Number of mislabeled points out of a total %d points : %d"
... % (iris.data.shape[0],(iris.target != y_pred).sum()))
Number of mislabeled points out of a total 150 points : 6

Multinomial Naive Bayes

MultinomialNB implements the naive Bayes algorithm for multinomially distributed data, and is one of the two
classic naive Bayes variants used in text classification (where the data are typically represented as word vector counts,
although tf-idf vectors are also known to work well in practice). The distribution is parametrized by vectors 𝜃𝑦 =
(𝜃𝑦1 , . . . , 𝜃𝑦𝑛 ) for each class 𝑦, where 𝑛 is the number of features (in text classification, the size of the vocabulary)
and 𝜃𝑦𝑖 is the probability 𝑃 (𝑥𝑖 | 𝑦) of feature 𝑖 appearing in a sample belonging to class 𝑦.
The parameters 𝜃𝑦 is estimated by a smoothed version of maximum likelihood, i.e. relative frequency counting:

𝑁𝑦𝑖 + 𝛼
𝜃ˆ𝑦𝑖 =
𝑁𝑦 + 𝛼𝑛
∑︀
𝑁𝑦𝑖 =
where ∑︀ 𝑥∈𝑇 𝑥𝑖 is the number of times feature 𝑖 appears in a sample of class 𝑦 in the training set 𝑇 , and
𝑛
𝑁𝑦 = 𝑖=1 𝑁𝑦𝑖 is the total count of all features for class 𝑦.
The smoothing priors 𝛼 ≥ 0 accounts for features not present in the learning samples and prevents zero probabilities
in further computations. Setting 𝛼 = 1 is called Laplace smoothing, while 𝛼 < 1 is called Lidstone smoothing.

Complement Naive Bayes

ComplementNB implements the complement naive Bayes (CNB) algorithm. CNB is an adaptation of the standard
multinomial naive Bayes (MNB) algorithm that is particularly suited for imbalanced data sets. Specifically, CNB uses
statistics from the complement of each class to compute the model’s weights. The inventors of CNB show empirically
that the parameter estimates for CNB are more stable than those for MNB. Further, CNB regularly outperforms MNB
(often by a considerable margin) on text classification tasks. The procedure for calculating the weights is as follows:
∑︀
𝛼𝑖 + 𝑗:𝑦𝑗 ̸=𝑐 𝑑𝑖𝑗
𝜃ˆ𝑐𝑖 = ∑︀ ∑︀
𝛼 + 𝑗:𝑦𝑗 ̸=𝑐 𝑘 𝑑𝑘𝑗
𝑤𝑐𝑖 = log 𝜃ˆ𝑐𝑖
𝑤𝑐𝑖
𝑤𝑐𝑖 = ∑︀
𝑗 |𝑤𝑐𝑗 |

where the summations are over all documents 𝑗 not in class 𝑐, 𝑑𝑖𝑗 is either the ∑︀
count or tf-idf value of term 𝑖 in
document 𝑗, 𝛼𝑖 is a smoothing hyperparameter like that found in MNB, and 𝛼 = 𝑖 𝛼𝑖 . The second normalization

250 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

addresses the tendency for longer documents to dominate parameter estimates in MNB. The classification rule is:
∑︁
𝑐ˆ = arg min 𝑡𝑖 𝑤𝑐𝑖
𝑐
𝑖

i.e., a document is assigned to the class that is the poorest complement match.

References:

• Rennie, J. D., Shih, L., Teevan, J., & Karger, D. R. (2003). Tackling the poor assumptions of naive bayes text
classifiers. In ICML (Vol. 3, pp. 616-623).

Bernoulli Naive Bayes

BernoulliNB implements the naive Bayes training and classification algorithms for data that is distributed ac-
cording to multivariate Bernoulli distributions; i.e., there may be multiple features but each one is assumed to be a
binary-valued (Bernoulli, boolean) variable. Therefore, this class requires samples to be represented as binary-valued
feature vectors; if handed any other kind of data, a BernoulliNB instance may binarize its input (depending on the
binarize parameter).
The decision rule for Bernoulli naive Bayes is based on

𝑃 (𝑥𝑖 | 𝑦) = 𝑃 (𝑖 | 𝑦)𝑥𝑖 + (1 − 𝑃 (𝑖 | 𝑦))(1 − 𝑥𝑖 )

which differs from multinomial NB’s rule in that it explicitly penalizes the non-occurrence of a feature 𝑖 that is an
indicator for class 𝑦, where the multinomial variant would simply ignore a non-occurring feature.
In the case of text classification, word occurrence vectors (rather than word count vectors) may be used to train and
use this classifier. BernoulliNB might perform better on some datasets, especially those with shorter documents.
It is advisable to evaluate both models, if time permits.

References:

• C.D. Manning, P. Raghavan and H. Schütze (2008). Introduction to Information Retrieval. Cambridge Uni-
versity Press, pp. 234-265.
• A. McCallum and K. Nigam (1998). A comparison of event models for Naive Bayes text classification. Proc.
AAAI/ICML-98 Workshop on Learning for Text Categorization, pp. 41-48.
• V. Metsis, I. Androutsopoulos and G. Paliouras (2006). Spam filtering with Naive Bayes – Which Naive
Bayes? 3rd Conf. on Email and Anti-Spam (CEAS).

Out-of-core naive Bayes model fitting

Naive Bayes models can be used to tackle large scale classification problems for which the full training set might not fit
in memory. To handle this case, MultinomialNB, BernoulliNB, and GaussianNB expose a partial_fit
method that can be used incrementally as done with other classifiers as demonstrated in Out-of-core classification of
text documents. All naive Bayes classifiers support sample weighting.
Contrary to the fit method, the first call to partial_fit needs to be passed the list of all the expected class labels.
For an overview of available strategies in scikit-learn, see also the out-of-core learning documentation.

3.1. Supervised learning 251


scikit-learn user guide, Release 0.20.3

Note: The partial_fit method call of naive Bayes models introduces some computational overhead. It is
recommended to use data chunk sizes that are as large as possible, that is as the available RAM allows.

3.1.10 Decision Trees

Decision Trees (DTs) are a non-parametric supervised learning method used for classification and regression. The
goal is to create a model that predicts the value of a target variable by learning simple decision rules inferred from the
data features.
For instance, in the example below, decision trees learn from data to approximate a sine curve with a set of if-then-else
decision rules. The deeper the tree, the more complex the decision rules and the fitter the model.

Some advantages of decision trees are:


• Simple to understand and to interpret. Trees can be visualised.
• Requires little data preparation. Other techniques often require data normalisation, dummy variables need to be
created and blank values to be removed. Note however that this module does not support missing values.
• The cost of using the tree (i.e., predicting data) is logarithmic in the number of data points used to train the tree.
• Able to handle both numerical and categorical data. Other techniques are usually specialised in analysing
datasets that have only one type of variable. See algorithms for more information.
• Able to handle multi-output problems.
• Uses a white box model. If a given situation is observable in a model, the explanation for the condition is easily
explained by boolean logic. By contrast, in a black box model (e.g., in an artificial neural network), results may
be more difficult to interpret.
• Possible to validate a model using statistical tests. That makes it possible to account for the reliability of the
model.

252 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

• Performs well even if its assumptions are somewhat violated by the true model from which the data were
generated.
The disadvantages of decision trees include:
• Decision-tree learners can create over-complex trees that do not generalise the data well. This is called overfit-
ting. Mechanisms such as pruning (not currently supported), setting the minimum number of samples required
at a leaf node or setting the maximum depth of the tree are necessary to avoid this problem.
• Decision trees can be unstable because small variations in the data might result in a completely different tree
being generated. This problem is mitigated by using decision trees within an ensemble.
• The problem of learning an optimal decision tree is known to be NP-complete under several aspects of optimality
and even for simple concepts. Consequently, practical decision-tree learning algorithms are based on heuristic
algorithms such as the greedy algorithm where locally optimal decisions are made at each node. Such algorithms
cannot guarantee to return the globally optimal decision tree. This can be mitigated by training multiple trees in
an ensemble learner, where the features and samples are randomly sampled with replacement.
• There are concepts that are hard to learn because decision trees do not express them easily, such as XOR, parity
or multiplexer problems.
• Decision tree learners create biased trees if some classes dominate. It is therefore recommended to balance the
dataset prior to fitting with the decision tree.

Classification

DecisionTreeClassifier is a class capable of performing multi-class classification on a dataset.


As with other classifiers, DecisionTreeClassifier takes as input two arrays: an array X, sparse or dense,
of size [n_samples, n_features] holding the training samples, and an array Y of integer values, size
[n_samples], holding the class labels for the training samples:

>>> from sklearn import tree


>>> X = [[0, 0], [1, 1]]
>>> Y = [0, 1]
>>> clf = tree.DecisionTreeClassifier()
>>> clf = clf.fit(X, Y)

After being fitted, the model can then be used to predict the class of samples:

>>> clf.predict([[2., 2.]])


array([1])

Alternatively, the probability of each class can be predicted, which is the fraction of training samples of the same class
in a leaf:

>>> clf.predict_proba([[2., 2.]])


array([[0., 1.]])

DecisionTreeClassifier is capable of both binary (where the labels are [-1, 1]) classification and multiclass
(where the labels are [0, . . . , K-1]) classification.
Using the Iris dataset, we can construct a tree as follows:

>>> from sklearn.datasets import load_iris


>>> from sklearn import tree
>>> iris = load_iris()
>>> clf = tree.DecisionTreeClassifier()
>>> clf = clf.fit(iris.data, iris.target)

3.1. Supervised learning 253


scikit-learn user guide, Release 0.20.3

Once trained, we can export the tree in Graphviz format using the export_graphviz exporter. If you use the
conda package manager, the graphviz binaries and the python package can be installed with
conda install python-graphviz
Alternatively binaries for graphviz can be downloaded from the graphviz project homepage, and the Python wrapper
installed from pypi with pip install graphviz.
Below is an example graphviz export of the above tree trained on the entire iris dataset; the results are saved in an
output file iris.pdf :

>>> import graphviz


>>> dot_data = tree.export_graphviz(clf, out_file=None)
>>> graph = graphviz.Source(dot_data)
>>> graph.render("iris")

The export_graphviz exporter also supports a variety of aesthetic options, including coloring nodes by their class
(or value for regression) and using explicit variable and class names if desired. Jupyter notebooks also render these
plots inline automatically:

>>> dot_data = tree.export_graphviz(clf, out_file=None,


... feature_names=iris.feature_names,
... class_names=iris.target_names,
... filled=True, rounded=True,
... special_characters=True)
>>> graph = graphviz.Source(dot_data)
>>> graph

Examples:

• Plot the decision surface of a decision tree on the iris dataset

Regression

Decision trees can also be applied to regression problems, using the DecisionTreeRegressor class.
As in the classification setting, the fit method will take as argument arrays X and y, only that in this case y is expected
to have floating point values instead of integer values:

>>> from sklearn import tree


>>> X = [[0, 0], [2, 2]]
>>> y = [0.5, 2.5]
>>> clf = tree.DecisionTreeRegressor()
>>> clf = clf.fit(X, y)
>>> clf.predict([[1, 1]])
array([0.5])

Examples:

• Decision Tree Regression

254 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

3.1. Supervised learning 255


scikit-learn user guide, Release 0.20.3

Multi-output problems

A multi-output problem is a supervised learning problem with several outputs to predict, that is when Y is a 2d array
of size [n_samples, n_outputs].
When there is no correlation between the outputs, a very simple way to solve this kind of problem is to build n
independent models, i.e. one for each output, and then to use those models to independently predict each one of the
n outputs. However, because it is likely that the output values related to the same input are themselves correlated, an
often better way is to build a single model capable of predicting simultaneously all n outputs. First, it requires lower
training time since only a single estimator is built. Second, the generalization accuracy of the resulting estimator may
often be increased.
With regard to decision trees, this strategy can readily be used to support multi-output problems. This requires the
following changes:
• Store n output values in leaves, instead of 1;
• Use splitting criteria that compute the average reduction across all n outputs.
This module offers support for multi-output problems by implementing this strategy in both
DecisionTreeClassifier and DecisionTreeRegressor. If a decision tree is fit on an output
array Y of size [n_samples, n_outputs] then the resulting estimator will:
• Output n_output values upon predict;
• Output a list of n_output arrays of class probabilities upon predict_proba.
The use of multi-output trees for regression is demonstrated in Multi-output Decision Tree Regression. In this example,
the input X is a single real value and the outputs Y are the sine and cosine of X.
The use of multi-output trees for classification is demonstrated in Face completion with a multi-output estimators. In
this example, the inputs X are the pixels of the upper half of faces and the outputs Y are the pixels of the lower half of
those faces.

256 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Examples:

• Multi-output Decision Tree Regression


• Face completion with a multi-output estimators

References:

• M. Dumont et al, Fast multi-class image annotation with random subwindows and multiple output randomized
trees, International Conference on Computer Vision Theory and Applications 2009

Complexity

In general, the run time cost to construct a balanced binary tree is 𝑂(𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠 𝑛𝑓 𝑒𝑎𝑡𝑢𝑟𝑒𝑠 log(𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠 )) and query
time 𝑂(log(𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠 )). Although the tree construction algorithm attempts to generate balanced trees, they will not
always be balanced. Assuming that the subtrees remain approximately balanced, the cost at each node consists of
searching through 𝑂(𝑛𝑓 𝑒𝑎𝑡𝑢𝑟𝑒𝑠 ) to find the feature that offers the largest reduction in entropy. This has a cost of
𝑂(𝑛𝑓 𝑒𝑎𝑡𝑢𝑟𝑒𝑠 𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠 log(𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠 )) at each node, leading to a total cost over the entire trees (by summing the cost at
each node) of 𝑂(𝑛𝑓 𝑒𝑎𝑡𝑢𝑟𝑒𝑠 𝑛2𝑠𝑎𝑚𝑝𝑙𝑒𝑠 log(𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠 )).
Scikit-learn offers a more efficient implementation for the construction of decision trees. A naive implementation
(as above) would recompute the class label histograms (for classification) or the means (for regression) at for each
new split point along a given feature. Presorting the feature over all relevant samples, and retaining a running la-
bel count, will reduce the complexity at each node to 𝑂(𝑛𝑓 𝑒𝑎𝑡𝑢𝑟𝑒𝑠 log(𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠 )), which results in a total cost of
𝑂(𝑛𝑓 𝑒𝑎𝑡𝑢𝑟𝑒𝑠 𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠 log(𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠 )). This is an option for all tree based algorithms. By default it is turned on for
gradient boosting, where in general it makes training faster, but turned off for all other algorithms as it tends to slow
down training when training deep trees.

3.1. Supervised learning 257


scikit-learn user guide, Release 0.20.3

258 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Tips on practical use

• Decision trees tend to overfit on data with a large number of features. Getting the right ratio of samples to
number of features is important, since a tree with few samples in high dimensional space is very likely to
overfit.
• Consider performing dimensionality reduction (PCA, ICA, or Feature selection) beforehand to give your tree a
better chance of finding features that are discriminative.
• Visualise your tree as you are training by using the export function. Use max_depth=3 as an initial tree
depth to get a feel for how the tree is fitting to your data, and then increase the depth.
• Remember that the number of samples required to populate the tree doubles for each additional level the tree
grows to. Use max_depth to control the size of the tree to prevent overfitting.
• Use min_samples_split or min_samples_leaf to ensure that multiple samples inform every decision
in the tree, by controlling which splits will be considered. A very small number will usually mean the tree will
overfit, whereas a large number will prevent the tree from learning the data. Try min_samples_leaf=5 as an
initial value. If the sample size varies greatly, a float number can be used as percentage in these two parameters.
While min_samples_split can create arbitrarily small leaves, min_samples_leaf guarantees that each
leaf has a minimum size, avoiding low-variance, over-fit leaf nodes in regression problems. For classification
with few classes, min_samples_leaf=1 is often the best choice.
• Balance your dataset before training to prevent the tree from being biased toward the classes that are dominant.
Class balancing can be done by sampling an equal number of samples from each class, or preferably by nor-
malizing the sum of the sample weights (sample_weight) for each class to the same value. Also note that
weight-based pre-pruning criteria, such as min_weight_fraction_leaf, will then be less biased toward
dominant classes than criteria that are not aware of the sample weights, like min_samples_leaf.
• If the samples are weighted, it will be easier to optimize the tree structure using weight-based pre-pruning
criterion such as min_weight_fraction_leaf, which ensure that leaf nodes contain at least a fraction of
the overall sum of the sample weights.
• All decision trees use np.float32 arrays internally. If training data is not in this format, a copy of the dataset
will be made.
• If the input matrix X is very sparse, it is recommended to convert to sparse csc_matrix before calling fit and
sparse csr_matrix before calling predict. Training time can be orders of magnitude faster for a sparse matrix
input compared to a dense matrix when features have zero values in most of the samples.

Tree algorithms: ID3, C4.5, C5.0 and CART

What are all the various decision tree algorithms and how do they differ from each other? Which one is implemented
in scikit-learn?
ID3 (Iterative Dichotomiser 3) was developed in 1986 by Ross Quinlan. The algorithm creates a multiway tree, finding
for each node (i.e. in a greedy manner) the categorical feature that will yield the largest information gain for categorical
targets. Trees are grown to their maximum size and then a pruning step is usually applied to improve the ability of the
tree to generalise to unseen data.
C4.5 is the successor to ID3 and removed the restriction that features must be categorical by dynamically defining
a discrete attribute (based on numerical variables) that partitions the continuous attribute value into a discrete set of
intervals. C4.5 converts the trained trees (i.e. the output of the ID3 algorithm) into sets of if-then rules. These accuracy
of each rule is then evaluated to determine the order in which they should be applied. Pruning is done by removing a
rule’s precondition if the accuracy of the rule improves without it.
C5.0 is Quinlan’s latest version release under a proprietary license. It uses less memory and builds smaller rulesets
than C4.5 while being more accurate.

3.1. Supervised learning 259


scikit-learn user guide, Release 0.20.3

CART (Classification and Regression Trees) is very similar to C4.5, but it differs in that it supports numerical target
variables (regression) and does not compute rule sets. CART constructs binary trees using the feature and threshold
that yield the largest information gain at each node.
scikit-learn uses an optimised version of the CART algorithm; however, scikit-learn implementation does not support
categorical variables for now.

Mathematical formulation

Given training vectors 𝑥𝑖 ∈ 𝑅𝑛 , i=1,. . . , l and a label vector 𝑦 ∈ 𝑅𝑙 , a decision tree recursively partitions the space
such that the samples with the same labels are grouped together.
Let the data at node 𝑚 be represented by 𝑄. For each candidate split 𝜃 = (𝑗, 𝑡𝑚 ) consisting of a feature 𝑗 and threshold
𝑡𝑚 , partition the data into 𝑄𝑙𝑒𝑓 𝑡 (𝜃) and 𝑄𝑟𝑖𝑔ℎ𝑡 (𝜃) subsets

𝑄𝑙𝑒𝑓 𝑡 (𝜃) = (𝑥, 𝑦)|𝑥𝑗 <= 𝑡𝑚


𝑄𝑟𝑖𝑔ℎ𝑡 (𝜃) = 𝑄 ∖ 𝑄𝑙𝑒𝑓 𝑡 (𝜃)

The impurity at 𝑚 is computed using an impurity function 𝐻(), the choice of which depends on the task being solved
(classification or regression)
𝑛𝑙𝑒𝑓 𝑡 𝑛𝑟𝑖𝑔ℎ𝑡
𝐺(𝑄, 𝜃) = 𝐻(𝑄𝑙𝑒𝑓 𝑡 (𝜃)) + 𝐻(𝑄𝑟𝑖𝑔ℎ𝑡 (𝜃))
𝑁𝑚 𝑁𝑚
Select the parameters that minimises the impurity

𝜃* = argmin𝜃 𝐺(𝑄, 𝜃)

Recurse for subsets 𝑄𝑙𝑒𝑓 𝑡 (𝜃* ) and 𝑄𝑟𝑖𝑔ℎ𝑡 (𝜃* ) until the maximum allowable depth is reached, 𝑁𝑚 < min𝑠𝑎𝑚𝑝𝑙𝑒𝑠 or
𝑁𝑚 = 1.

Classification criteria

If a target is a classification outcome taking on values 0,1,. . . ,K-1, for node 𝑚, representing a region 𝑅𝑚 with 𝑁𝑚
observations, let
∑︁
𝑝𝑚𝑘 = 1/𝑁𝑚 𝐼(𝑦𝑖 = 𝑘)
𝑥𝑖 ∈𝑅𝑚

be the proportion of class k observations in node 𝑚


Common measures of impurity are Gini
∑︁
𝐻(𝑋𝑚 ) = 𝑝𝑚𝑘 (1 − 𝑝𝑚𝑘 )
𝑘

Entropy
∑︁
𝐻(𝑋𝑚 ) = − 𝑝𝑚𝑘 log(𝑝𝑚𝑘 )
𝑘

and Misclassification

𝐻(𝑋𝑚 ) = 1 − max(𝑝𝑚𝑘 )

where 𝑋𝑚 is the training data in node 𝑚

260 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Regression criteria

If the target is a continuous value, then for node 𝑚, representing a region 𝑅𝑚 with 𝑁𝑚 observations, common criteria
to minimise as for determining locations for future splits are Mean Squared Error, which minimizes the L2 error
using mean values at terminal nodes, and Mean Absolute Error, which minimizes the L1 error using median values at
terminal nodes.
Mean Squared Error:
1 ∑︁
𝑦¯𝑚 = 𝑦𝑖
𝑁𝑚
𝑖∈𝑁𝑚
1 ∑︁
𝐻(𝑋𝑚 ) = (𝑦𝑖 − 𝑦¯𝑚 )2
𝑁𝑚
𝑖∈𝑁𝑚

Mean Absolute Error:


1 ∑︁
𝑦¯𝑚 = 𝑦𝑖
𝑁𝑚
𝑖∈𝑁𝑚
1 ∑︁
𝐻(𝑋𝑚 ) = |𝑦𝑖 − 𝑦¯𝑚 |
𝑁𝑚
𝑖∈𝑁𝑚

where 𝑋𝑚 is the training data in node 𝑚

References:

• https://en.wikipedia.org/wiki/Decision_tree_learning
• https://en.wikipedia.org/wiki/Predictive_analytics
• L. Breiman, J. Friedman, R. Olshen, and C. Stone. Classification and Regression Trees. Wadsworth, Belmont,
CA, 1984.
• J.R. Quinlan. C4. 5: programs for machine learning. Morgan Kaufmann, 1993.
• T. Hastie, R. Tibshirani and J. Friedman. Elements of Statistical Learning, Springer, 2009.

3.1.11 Ensemble methods

The goal of ensemble methods is to combine the predictions of several base estimators built with a given learning
algorithm in order to improve generalizability / robustness over a single estimator.
Two families of ensemble methods are usually distinguished:
• In averaging methods, the driving principle is to build several estimators independently and then to average
their predictions. On average, the combined estimator is usually better than any of the single base estimator
because its variance is reduced.
Examples: Bagging methods, Forests of randomized trees, . . .
• By contrast, in boosting methods, base estimators are built sequentially and one tries to reduce the bias of the
combined estimator. The motivation is to combine several weak models to produce a powerful ensemble.
Examples: AdaBoost, Gradient Tree Boosting, . . .

3.1. Supervised learning 261


scikit-learn user guide, Release 0.20.3

Bagging meta-estimator

In ensemble algorithms, bagging methods form a class of algorithms which build several instances of a black-box
estimator on random subsets of the original training set and then aggregate their individual predictions to form a final
prediction. These methods are used as a way to reduce the variance of a base estimator (e.g., a decision tree), by
introducing randomization into its construction procedure and then making an ensemble out of it. In many cases,
bagging methods constitute a very simple way to improve with respect to a single model, without making it necessary
to adapt the underlying base algorithm. As they provide a way to reduce overfitting, bagging methods work best with
strong and complex models (e.g., fully developed decision trees), in contrast with boosting methods which usually
work best with weak models (e.g., shallow decision trees).
Bagging methods come in many flavours but mostly differ from each other by the way they draw random subsets of
the training set:
• When random subsets of the dataset are drawn as random subsets of the samples, then this algorithm is known
as Pasting [B1999].
• When samples are drawn with replacement, then the method is known as Bagging [B1996].
• When random subsets of the dataset are drawn as random subsets of the features, then the method is known as
Random Subspaces [H1998].
• Finally, when base estimators are built on subsets of both samples and features, then the method is known as
Random Patches [LG2012].
In scikit-learn, bagging methods are offered as a unified BaggingClassifier meta-estimator (resp.
BaggingRegressor), taking as input a user-specified base estimator along with parameters specifying the strategy
to draw random subsets. In particular, max_samples and max_features control the size of the subsets (in terms
of samples and features), while bootstrap and bootstrap_features control whether samples and features
are drawn with or without replacement. When using a subset of the available samples the generalization accuracy can
be estimated with the out-of-bag samples by setting oob_score=True. As an example, the snippet below illustrates
how to instantiate a bagging ensemble of KNeighborsClassifier base estimators, each built on random subsets
of 50% of the samples and 50% of the features.

>>> from sklearn.ensemble import BaggingClassifier


>>> from sklearn.neighbors import KNeighborsClassifier
>>> bagging = BaggingClassifier(KNeighborsClassifier(),
... max_samples=0.5, max_features=0.5)

Examples:

• Single estimator versus bagging: bias-variance decomposition

References

Forests of randomized trees

The sklearn.ensemble module includes two averaging algorithms based on randomized decision trees: the Ran-
domForest algorithm and the Extra-Trees method. Both algorithms are perturb-and-combine techniques [B1998]
specifically designed for trees. This means a diverse set of classifiers is created by introducing randomness in the
classifier construction. The prediction of the ensemble is given as the averaged prediction of the individual classifiers.

262 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

As other classifiers, forest classifiers have to be fitted with two arrays: a sparse or dense array X of size [n_samples,
n_features] holding the training samples, and an array Y of size [n_samples] holding the target values (class
labels) for the training samples:
>>> from sklearn.ensemble import RandomForestClassifier
>>> X = [[0, 0], [1, 1]]
>>> Y = [0, 1]
>>> clf = RandomForestClassifier(n_estimators=10)
>>> clf = clf.fit(X, Y)

Like decision trees, forests of trees also extend to multi-output problems (if Y is an array of size [n_samples,
n_outputs]).

Random Forests

In random forests (see RandomForestClassifier and RandomForestRegressor classes), each tree in the
ensemble is built from a sample drawn with replacement (i.e., a bootstrap sample) from the training set. In addition,
when splitting a node during the construction of the tree, the split that is chosen is no longer the best split among all
features. Instead, the split that is picked is the best split among a random subset of the features. As a result of this
randomness, the bias of the forest usually slightly increases (with respect to the bias of a single non-random tree) but,
due to averaging, its variance also decreases, usually more than compensating for the increase in bias, hence yielding
an overall better model.
In contrast to the original publication [B2001], the scikit-learn implementation combines classifiers by averaging their
probabilistic prediction, instead of letting each classifier vote for a single class.

Extremely Randomized Trees

In extremely randomized trees (see ExtraTreesClassifier and ExtraTreesRegressor classes), random-


ness goes one step further in the way splits are computed. As in random forests, a random subset of candidate features
is used, but instead of looking for the most discriminative thresholds, thresholds are drawn at random for each candi-
date feature and the best of these randomly-generated thresholds is picked as the splitting rule. This usually allows to
reduce the variance of the model a bit more, at the expense of a slightly greater increase in bias:
>>> from sklearn.model_selection import cross_val_score
>>> from sklearn.datasets import make_blobs
>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.ensemble import ExtraTreesClassifier
>>> from sklearn.tree import DecisionTreeClassifier

>>> X, y = make_blobs(n_samples=10000, n_features=10, centers=100,


... random_state=0)

>>> clf = DecisionTreeClassifier(max_depth=None, min_samples_split=2,


... random_state=0)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean()
0.98...

>>> clf = RandomForestClassifier(n_estimators=10, max_depth=None,


... min_samples_split=2, random_state=0)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean()
0.999...

3.1. Supervised learning 263


scikit-learn user guide, Release 0.20.3

>>> clf = ExtraTreesClassifier(n_estimators=10, max_depth=None,


... min_samples_split=2, random_state=0)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean() > 0.999
True

Parameters

The main parameters to adjust when using these methods is n_estimators and max_features. The former
is the number of trees in the forest. The larger the better, but also the longer it will take to compute. In addition,
note that results will stop getting significantly better beyond a critical number of trees. The latter is the size of
the random subsets of features to consider when splitting a node. The lower the greater the reduction of variance,
but also the greater the increase in bias. Empirical good default values are max_features=n_features for
regression problems, and max_features=sqrt(n_features) for classification tasks (where n_features is
the number of features in the data). Good results are often achieved when setting max_depth=None in combination
with min_samples_split=2 (i.e., when fully developing the trees). Bear in mind though that these values are
usually not optimal, and might result in models that consume a lot of RAM. The best parameter values should always be
cross-validated. In addition, note that in random forests, bootstrap samples are used by default (bootstrap=True)
while the default strategy for extra-trees is to use the whole dataset (bootstrap=False). When using bootstrap
sampling the generalization accuracy can be estimated on the left out or out-of-bag samples. This can be enabled by
setting oob_score=True.

Note: The size of the model with the default parameters is 𝑂(𝑀 * 𝑁 * 𝑙𝑜𝑔(𝑁 )), where 𝑀 is the number of
trees and 𝑁 is the number of samples. In order to reduce the size of the model, you can change these parameters:
min_samples_split, max_leaf_nodes, max_depth and min_samples_leaf.

264 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Parallelization

Finally, this module also features the parallel construction of the trees and the parallel computation of the predictions
through the n_jobs parameter. If n_jobs=k then computations are partitioned into k jobs, and run on k cores of
the machine. If n_jobs=-1 then all cores available on the machine are used. Note that because of inter-process
communication overhead, the speedup might not be linear (i.e., using k jobs will unfortunately not be k times as fast).
Significant speedup can still be achieved though when building a large number of trees, or when building a single tree
requires a fair amount of time (e.g., on large datasets).

Examples:

• Plot the decision surfaces of ensembles of trees on the iris dataset


• Pixel importances with a parallel forest of trees
• Face completion with a multi-output estimators

References

• P. Geurts, D. Ernst., and L. Wehenkel, “Extremely randomized trees”, Machine Learning, 63(1), 3-42, 2006.

Feature importance evaluation

The relative rank (i.e. depth) of a feature used as a decision node in a tree can be used to assess the relative importance
of that feature with respect to the predictability of the target variable. Features used at the top of the tree contribute
to the final prediction decision of a larger fraction of the input samples. The expected fraction of the samples they
contribute to can thus be used as an estimate of the relative importance of the features. In scikit-learn, the fraction of
samples a feature contributes to is combined with the decrease in impurity from splitting them to create a normalized
estimate of the predictive power of that feature.
By averaging the estimates of predictive ability over several randomized trees one can reduce the variance of such
an estimate and use it for feature selection. This is known as the mean decrease in impurity, or MDI. Refer to [L2014]
for more information on MDI and feature importance evaluation with Random Forests.
The following example shows a color-coded representation of the relative importances of each individual pixel for a
face recognition task using a ExtraTreesClassifier model.
In practice those estimates are stored as an attribute named feature_importances_ on the fitted model. This
is an array with shape (n_features,) whose values are positive and sum to 1.0. The higher the value, the more
important is the contribution of the matching feature to the prediction function.

Examples:

• Pixel importances with a parallel forest of trees


• Feature importances with forests of trees

References

3.1. Supervised learning 265


scikit-learn user guide, Release 0.20.3

Totally Random Trees Embedding

RandomTreesEmbedding implements an unsupervised transformation of the data. Using a forest of completely


random trees, RandomTreesEmbedding encodes the data by the indices of the leaves a data point ends up in. This
index is then encoded in a one-of-K manner, leading to a high dimensional, sparse binary coding. This coding can be
computed very efficiently and can then be used as a basis for other learning tasks. The size and sparsity of the code
can be influenced by choosing the number of trees and the maximum depth per tree. For each tree in the ensemble, the
coding contains one entry of one. The size of the coding is at most n_estimators * 2 ** max_depth, the
maximum number of leaves in the forest.
As neighboring data points are more likely to lie within the same leaf of a tree, the transformation performs an implicit,
non-parametric density estimation.

Examples:

• Hashing feature transformation using Totally Random Trees


• Manifold learning on handwritten digits: Locally Linear Embedding, Isomap. . . compares non-linear dimen-
sionality reduction techniques on handwritten digits.
• Feature transformations with ensembles of trees compares supervised and unsupervised tree based feature
transformations.

See also:
Manifold learning techniques can also be useful to derive non-linear representations of feature space, also these ap-
proaches focus also on dimensionality reduction.

266 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

AdaBoost

The module sklearn.ensemble includes the popular boosting algorithm AdaBoost, introduced in 1995 by Freund
and Schapire [FS1995].
The core principle of AdaBoost is to fit a sequence of weak learners (i.e., models that are only slightly better than
random guessing, such as small decision trees) on repeatedly modified versions of the data. The predictions from
all of them are then combined through a weighted majority vote (or sum) to produce the final prediction. The data
modifications at each so-called boosting iteration consist of applying weights 𝑤1 , 𝑤2 , . . . , 𝑤𝑁 to each of the training
samples. Initially, those weights are all set to 𝑤𝑖 = 1/𝑁 , so that the first step simply trains a weak learner on the
original data. For each successive iteration, the sample weights are individually modified and the learning algorithm is
reapplied to the reweighted data. At a given step, those training examples that were incorrectly predicted by the boosted
model induced at the previous step have their weights increased, whereas the weights are decreased for those that were
predicted correctly. As iterations proceed, examples that are difficult to predict receive ever-increasing influence. Each
subsequent weak learner is thereby forced to concentrate on the examples that are missed by the previous ones in the
sequence [HTF].

AdaBoost can be used both for classification and regression problems:


• For multi-class classification, AdaBoostClassifier implements AdaBoost-SAMME and AdaBoost-
SAMME.R [ZZRH2009].
• For regression, AdaBoostRegressor implements AdaBoost.R2 [D1997].

Usage

The following example shows how to fit an AdaBoost classifier with 100 weak learners:
>>> from sklearn.model_selection import cross_val_score
>>> from sklearn.datasets import load_iris
>>> from sklearn.ensemble import AdaBoostClassifier

3.1. Supervised learning 267


scikit-learn user guide, Release 0.20.3

>>> iris = load_iris()


>>> clf = AdaBoostClassifier(n_estimators=100)
>>> scores = cross_val_score(clf, iris.data, iris.target, cv=5)
>>> scores.mean()
0.9...

The number of weak learners is controlled by the parameter n_estimators. The learning_rate parameter
controls the contribution of the weak learners in the final combination. By default, weak learners are decision stumps.
Different weak learners can be specified through the base_estimator parameter. The main parameters to tune to
obtain good results are n_estimators and the complexity of the base estimators (e.g., its depth max_depth or
minimum required number of samples to consider a split min_samples_split).

Examples:

• Discrete versus Real AdaBoost compares the classification error of a decision stump, decision tree, and a
boosted decision stump using AdaBoost-SAMME and AdaBoost-SAMME.R.
• Multi-class AdaBoosted Decision Trees shows the performance of AdaBoost-SAMME and AdaBoost-
SAMME.R on a multi-class problem.
• Two-class AdaBoost shows the decision boundary and decision function values for a non-linearly separable
two-class problem using AdaBoost-SAMME.
• Decision Tree Regression with AdaBoost demonstrates regression with the AdaBoost.R2 algorithm.

References

Gradient Tree Boosting

Gradient Tree Boosting or Gradient Boosted Regression Trees (GBRT) is a generalization of boosting to arbitrary
differentiable loss functions. GBRT is an accurate and effective off-the-shelf procedure that can be used for both
regression and classification problems. Gradient Tree Boosting models are used in a variety of areas including Web
search ranking and ecology.
The advantages of GBRT are:
• Natural handling of data of mixed type (= heterogeneous features)
• Predictive power
• Robustness to outliers in output space (via robust loss functions)
The disadvantages of GBRT are:
• Scalability, due to the sequential nature of boosting it can hardly be parallelized.
The module sklearn.ensemble provides methods for both classification and regression via gradient boosted
regression trees.

Classification

GradientBoostingClassifier supports both binary and multi-class classification. The following example
shows how to fit a gradient boosting classifier with 100 decision stumps as weak learners:

268 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

>>> from sklearn.datasets import make_hastie_10_2


>>> from sklearn.ensemble import GradientBoostingClassifier

>>> X, y = make_hastie_10_2(random_state=0)
>>> X_train, X_test = X[:2000], X[2000:]
>>> y_train, y_test = y[:2000], y[2000:]

>>> clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,


... max_depth=1, random_state=0).fit(X_train, y_train)
>>> clf.score(X_test, y_test)
0.913...

The number of weak learners (i.e. regression trees) is controlled by the parameter n_estimators; The size of each
tree can be controlled either by setting the tree depth via max_depth or by setting the number of leaf nodes via
max_leaf_nodes. The learning_rate is a hyper-parameter in the range (0.0, 1.0] that controls overfitting via
shrinkage .

Note: Classification with more than 2 classes requires the induction of n_classes regression trees at each
iteration, thus, the total number of induced trees equals n_classes * n_estimators. For datasets with
a large number of classes we strongly recommend to use RandomForestClassifier as an alternative to
GradientBoostingClassifier .

Regression

GradientBoostingRegressor supports a number of different loss functions for regression which can be speci-
fied via the argument loss; the default loss function for regression is least squares ('ls').

>>> import numpy as np


>>> from sklearn.metrics import mean_squared_error
>>> from sklearn.datasets import make_friedman1
>>> from sklearn.ensemble import GradientBoostingRegressor

>>> X, y = make_friedman1(n_samples=1200, random_state=0, noise=1.0)


>>> X_train, X_test = X[:200], X[200:]
>>> y_train, y_test = y[:200], y[200:]
>>> est = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1,
... max_depth=1, random_state=0, loss='ls').fit(X_train, y_train)
>>> mean_squared_error(y_test, est.predict(X_test))
5.00...

The figure below shows the results of applying GradientBoostingRegressor with least squares loss and 500
base learners to the Boston house price dataset (sklearn.datasets.load_boston). The plot on the left shows
the train and test error at each iteration. The train error at each iteration is stored in the train_score_ attribute
of the gradient boosting model. The test error at each iterations can be obtained via the staged_predict method
which returns a generator that yields the predictions at each stage. Plots like these can be used to determine the optimal
number of trees (i.e. n_estimators) by early stopping. The plot on the right shows the feature importances which
can be obtained via the feature_importances_ property.

Examples:

• Gradient Boosting regression

3.1. Supervised learning 269


scikit-learn user guide, Release 0.20.3

• Gradient Boosting Out-of-Bag estimates

Fitting additional weak-learners

Both GradientBoostingRegressor and GradientBoostingClassifier support


warm_start=True which allows you to add more estimators to an already fitted model.

>>> _ = est.set_params(n_estimators=200, warm_start=True) # set warm_start and new


˓→nr of trees

>>> _ = est.fit(X_train, y_train) # fit additional 100 trees to est


>>> mean_squared_error(y_test, est.predict(X_test))
3.84...

Controlling the tree size

The size of the regression tree base learners defines the level of variable interactions that can be captured by the
gradient boosting model. In general, a tree of depth h can capture interactions of order h . There are two ways in
which the size of the individual regression trees can be controlled.
If you specify max_depth=h then complete binary trees of depth h will be grown. Such trees will have (at most)
2**h leaf nodes and 2**h - 1 split nodes.
Alternatively, you can control the tree size by specifying the number of leaf nodes via the parameter
max_leaf_nodes. In this case, trees will be grown using best-first search where nodes with the highest improve-
ment in impurity will be expanded first. A tree with max_leaf_nodes=k has k - 1 split nodes and thus can
model interactions of up to order max_leaf_nodes - 1 .
We found that max_leaf_nodes=k gives comparable results to max_depth=k-1 but is significantly faster to
train at the expense of a slightly higher training error. The parameter max_leaf_nodes corresponds to the variable
J in the chapter on gradient boosting in [F2001] and is related to the parameter interaction.depth in R’s gbm
package where max_leaf_nodes == interaction.depth + 1 .

270 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Mathematical formulation

GBRT considers additive models of the following form:

𝑀
∑︁
𝐹 (𝑥) = 𝛾𝑚 ℎ𝑚 (𝑥)
𝑚=1

where ℎ𝑚 (𝑥) are the basis functions which are usually called weak learners in the context of boosting. Gradient Tree
Boosting uses decision trees of fixed size as weak learners. Decision trees have a number of abilities that make them
valuable for boosting, namely the ability to handle data of mixed type and the ability to model complex functions.
Similar to other boosting algorithms, GBRT builds the additive model in a greedy fashion:

𝐹𝑚 (𝑥) = 𝐹𝑚−1 (𝑥) + 𝛾𝑚 ℎ𝑚 (𝑥),

where the newly added tree ℎ𝑚 tries to minimize the loss 𝐿, given the previous ensemble 𝐹𝑚−1 :

𝑛
∑︁
ℎ𝑚 = arg min 𝐿(𝑦𝑖 , 𝐹𝑚−1 (𝑥𝑖 ) + ℎ(𝑥𝑖 )).

𝑖=1

The initial model 𝐹0 is problem specific, for least-squares regression one usually chooses the mean of the target values.

Note: The initial model can also be specified via the init argument. The passed object has to implement fit and
predict.

Gradient Boosting attempts to solve this minimization problem numerically via steepest descent: The steepest descent
direction is the negative gradient of the loss function evaluated at the current model 𝐹𝑚−1 which can be calculated for
any differentiable loss function:

𝑛
∑︁
𝐹𝑚 (𝑥) = 𝐹𝑚−1 (𝑥) − 𝛾𝑚 ∇𝐹 𝐿(𝑦𝑖 , 𝐹𝑚−1 (𝑥𝑖 ))
𝑖=1

Where the step length 𝛾𝑚 is chosen using line search:

𝑛
∑︁ 𝜕𝐿(𝑦𝑖 , 𝐹𝑚−1 (𝑥𝑖 ))
𝛾𝑚 = arg min 𝐿(𝑦𝑖 , 𝐹𝑚−1 (𝑥𝑖 ) − 𝛾 )
𝛾
𝑖=1
𝜕𝐹𝑚−1 (𝑥𝑖 )

The algorithms for regression and classification only differ in the concrete loss function used.

Loss Functions

The following loss functions are supported and can be specified using the parameter loss:
• Regression

3.1. Supervised learning 271


scikit-learn user guide, Release 0.20.3

– Least squares ('ls'): The natural choice for regression due to its superior computational properties. The
initial model is given by the mean of the target values.
– Least absolute deviation ('lad'): A robust loss function for regression. The initial model is given by the
median of the target values.
– Huber ('huber'): Another robust loss function that combines least squares and least absolute deviation;
use alpha to control the sensitivity with regards to outliers (see [F2001] for more details).
– Quantile ('quantile'): A loss function for quantile regression. Use 0 < alpha < 1 to specify the
quantile. This loss function can be used to create prediction intervals (see Prediction Intervals for Gradient
Boosting Regression).
• Classification
– Binomial deviance ('deviance'): The negative binomial log-likelihood loss function for binary classi-
fication (provides probability estimates). The initial model is given by the log odds-ratio.
– Multinomial deviance ('deviance'): The negative multinomial log-likelihood loss function for multi-
class classification with n_classes mutually exclusive classes. It provides probability estimates. The
initial model is given by the prior probability of each class. At each iteration n_classes regression trees
have to be constructed which makes GBRT rather inefficient for data sets with a large number of classes.
– Exponential loss ('exponential'): The same loss function as AdaBoostClassifier. Less robust
to mislabeled examples than 'deviance'; can only be used for binary classification.

Regularization

Shrinkage

[F2001] proposed a simple regularization strategy that scales the contribution of each weak learner by a factor 𝜈:

𝐹𝑚 (𝑥) = 𝐹𝑚−1 (𝑥) + 𝜈𝛾𝑚 ℎ𝑚 (𝑥)

The parameter 𝜈 is also called the learning rate because it scales the step length the gradient descent procedure; it can
be set via the learning_rate parameter.
The parameter learning_rate strongly interacts with the parameter n_estimators, the number of weak learn-
ers to fit. Smaller values of learning_rate require larger numbers of weak learners to maintain a constant training
error. Empirical evidence suggests that small values of learning_rate favor better test error. [HTF2009] recom-
mend to set the learning rate to a small constant (e.g. learning_rate <= 0.1) and choose n_estimators by
early stopping. For a more detailed discussion of the interaction between learning_rate and n_estimators
see [R2007].

Subsampling

[F1999] proposed stochastic gradient boosting, which combines gradient boosting with bootstrap averaging (bagging).
At each iteration the base classifier is trained on a fraction subsample of the available training data. The subsample
is drawn without replacement. A typical value of subsample is 0.5.
The figure below illustrates the effect of shrinkage and subsampling on the goodness-of-fit of the model. We can
clearly see that shrinkage outperforms no-shrinkage. Subsampling with shrinkage can further increase the accuracy of
the model. Subsampling without shrinkage, on the other hand, does poorly.
Another strategy to reduce the variance is by subsampling the features analogous to the random splits in
RandomForestClassifier . The number of subsampled features can be controlled via the max_features
parameter.

272 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Note: Using a small max_features value can significantly decrease the runtime.

Stochastic gradient boosting allows to compute out-of-bag estimates of the test deviance by computing the improve-
ment in deviance on the examples that are not included in the bootstrap sample (i.e. the out-of-bag examples). The
improvements are stored in the attribute oob_improvement_. oob_improvement_[i] holds the improvement
in terms of the loss on the OOB samples if you add the i-th stage to the current predictions. Out-of-bag estimates can
be used for model selection, for example to determine the optimal number of iterations. OOB estimates are usually
very pessimistic thus we recommend to use cross-validation instead and only use OOB if cross-validation is too time
consuming.

Examples:

• Gradient Boosting regularization


• Gradient Boosting Out-of-Bag estimates
• OOB Errors for Random Forests

Interpretation

Individual decision trees can be interpreted easily by simply visualizing the tree structure. Gradient boosting models,
however, comprise hundreds of regression trees thus they cannot be easily interpreted by visual inspection of the
individual trees. Fortunately, a number of techniques have been proposed to summarize and interpret gradient boosting
models.

3.1. Supervised learning 273


scikit-learn user guide, Release 0.20.3

Feature importance

Often features do not contribute equally to predict the target response; in many situations the majority of the features
are in fact irrelevant. When interpreting a model, the first question usually is: what are those important features and
how do they contributing in predicting the target response?
Individual decision trees intrinsically perform feature selection by selecting appropriate split points. This information
can be used to measure the importance of each feature; the basic idea is: the more often a feature is used in the split
points of a tree the more important that feature is. This notion of importance can be extended to decision tree ensembles
by simply averaging the feature importance of each tree (see Feature importance evaluation for more details).
The feature importance scores of a fit gradient boosting model can be accessed via the feature_importances_
property:

>>> from sklearn.datasets import make_hastie_10_2


>>> from sklearn.ensemble import GradientBoostingClassifier

>>> X, y = make_hastie_10_2(random_state=0)
>>> clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,
... max_depth=1, random_state=0).fit(X, y)
>>> clf.feature_importances_
array([0.10..., 0.10..., 0.11..., ...

Examples:

• Gradient Boosting regression

Partial dependence

Partial dependence plots (PDP) show the dependence between the target response and a set of ‘target’ features,
marginalizing over the values of all other features (the ‘complement’ features). Intuitively, we can interpret the partial
dependence as the expected target response1 as a function of the ‘target’ features2 .
Due to the limits of human perception the size of the target feature set must be small (usually, one or two) thus the
target features are usually chosen among the most important features.
The Figure below shows four one-way and one two-way partial dependence plots for the California housing dataset:
One-way PDPs tell us about the interaction between the target response and the target feature (e.g. linear, non-linear).
The upper left plot in the above Figure shows the effect of the median income in a district on the median house price;
we can clearly see a linear relationship among them.
PDPs with two target features show the interactions among the two features. For example, the two-variable PDP in
the above Figure shows the dependence of median house price on joint values of house age and avg. occupants per
household. We can clearly see an interaction between the two features: For an avg. occupancy greater than two, the
house price is nearly independent of the house age, whereas for values less than two there is a strong dependence on
age.
The module partial_dependence provides a convenience function plot_partial_dependence to cre-
ate one-way and two-way partial dependence plots. In the below example we show how to create a grid of partial
dependence plots: two one-way PDPs for the features 0 and 1 and a two-way PDP between the two features:
1
For classification with loss='deviance' the target response is logit(p).
2
More precisely its the expectation of the target response after accounting for the initial model; partial dependence plots do not include the
init model.

274 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

>>> from sklearn.datasets import make_hastie_10_2


>>> from sklearn.ensemble import GradientBoostingClassifier
>>> from sklearn.ensemble.partial_dependence import plot_partial_dependence

>>> X, y = make_hastie_10_2(random_state=0)
>>> clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,
... max_depth=1, random_state=0).fit(X, y)
>>> features = [0, 1, (0, 1)]
>>> fig, axs = plot_partial_dependence(clf, X, features)

For multi-class models, you need to set the class label for which the PDPs should be created via the label argument:

>>> from sklearn.datasets import load_iris


>>> iris = load_iris()
>>> mc_clf = GradientBoostingClassifier(n_estimators=10,
... max_depth=1).fit(iris.data, iris.target)
>>> features = [3, 2, (3, 2)]
>>> fig, axs = plot_partial_dependence(mc_clf, X, features, label=0)

If you need the raw values of the partial dependence function rather than the plots you can use the
partial_dependence function:

>>> from sklearn.ensemble.partial_dependence import partial_dependence

>>> pdp, axes = partial_dependence(clf, [0], X=X)


>>> pdp
array([[ 2.46643157, 2.46643157, ...
>>> axes
[array([-1.62497054, -1.59201391, ...

The function requires either the argument grid which specifies the values of the target features on which the partial
dependence function should be evaluated or the argument X which is a convenience mode for automatically creating
grid from the training data. If X is given, the axes value returned by the function gives the axis for each target
feature.

3.1. Supervised learning 275


scikit-learn user guide, Release 0.20.3

For each value of the ‘target’ features in the grid the partial dependence function need to marginalize the predictions
of a tree over all possible values of the ‘complement’ features. In decision trees this function can be evaluated effi-
ciently without reference to the training data. For each grid point a weighted tree traversal is performed: if a split node
involves a ‘target’ feature, the corresponding left or right branch is followed, otherwise both branches are followed,
each branch is weighted by the fraction of training samples that entered that branch. Finally, the partial dependence
is given by a weighted average of all visited leaves. For tree ensembles the results of each individual tree are again
averaged.

Examples:

• Partial Dependence Plots

References

Voting Classifier

The idea behind the VotingClassifier is to combine conceptually different machine learning classifiers and use
a majority vote or the average predicted probabilities (soft vote) to predict the class labels. Such a classifier can be
useful for a set of equally well performing model in order to balance out their individual weaknesses.

Majority Class Labels (Majority/Hard Voting)

In majority voting, the predicted class label for a particular sample is the class label that represents the majority (mode)
of the class labels predicted by each individual classifier.
E.g., if the prediction for a given sample is
• classifier 1 -> class 1
• classifier 2 -> class 1
• classifier 3 -> class 2
the VotingClassifier (with voting='hard') would classify the sample as “class 1” based on the majority class label.
In the cases of a tie, the VotingClassifier will select the class based on the ascending sort order. E.g., in the following
scenario
• classifier 1 -> class 2
• classifier 2 -> class 1
the class label 1 will be assigned to the sample.

Usage

The following example shows how to fit the majority rule classifier:

>>> from sklearn import datasets


>>> from sklearn.model_selection import cross_val_score
>>> from sklearn.linear_model import LogisticRegression
>>> from sklearn.naive_bayes import GaussianNB
>>> from sklearn.ensemble import RandomForestClassifier

276 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

>>> from sklearn.ensemble import VotingClassifier

>>> iris = datasets.load_iris()


>>> X, y = iris.data[:, 1:3], iris.target

>>> clf1 = LogisticRegression(solver='lbfgs', multi_class='multinomial',


... random_state=1)
>>> clf2 = RandomForestClassifier(n_estimators=50, random_state=1)
>>> clf3 = GaussianNB()

>>> eclf = VotingClassifier(estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],


˓→voting='hard')

>>> for clf, label in zip([clf1, clf2, clf3, eclf], ['Logistic Regression', 'Random
˓→Forest', 'naive Bayes', 'Ensemble']):

... scores = cross_val_score(clf, X, y, cv=5, scoring='accuracy')


... print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(),
˓→label))

Accuracy: 0.95 (+/- 0.04) [Logistic Regression]


Accuracy: 0.94 (+/- 0.04) [Random Forest]
Accuracy: 0.91 (+/- 0.04) [naive Bayes]
Accuracy: 0.95 (+/- 0.04) [Ensemble]

Weighted Average Probabilities (Soft Voting)

In contrast to majority voting (hard voting), soft voting returns the class label as argmax of the sum of predicted
probabilities.
Specific weights can be assigned to each classifier via the weights parameter. When weights are provided, the
predicted class probabilities for each classifier are collected, multiplied by the classifier weight, and averaged. The
final class label is then derived from the class label with the highest average probability.
To illustrate this with a simple example, let’s assume we have 3 classifiers and a 3-class classification problems where
we assign equal weights to all classifiers: w1=1, w2=1, w3=1.
The weighted average probabilities for a sample would then be calculated as follows:

classifier class 1 class 2 class 3


classifier 1 w1 * 0.2 w1 * 0.5 w1 * 0.3
classifier 2 w2 * 0.6 w2 * 0.3 w2 * 0.1
classifier 3 w3 * 0.3 w3 * 0.4 w3 * 0.3
weighted average 0.37 0.4 0.23

Here, the predicted class label is 2, since it has the highest average probability.
The following example illustrates how the decision regions may change when a soft VotingClassifier is used based on
an linear Support Vector Machine, a Decision Tree, and a K-nearest neighbor classifier:
>>> from sklearn import datasets
>>> from sklearn.tree import DecisionTreeClassifier
>>> from sklearn.neighbors import KNeighborsClassifier
>>> from sklearn.svm import SVC
>>> from itertools import product
>>> from sklearn.ensemble import VotingClassifier

>>> # Loading some example data

3.1. Supervised learning 277


scikit-learn user guide, Release 0.20.3

>>> iris = datasets.load_iris()


>>> X = iris.data[:, [0, 2]]
>>> y = iris.target

>>> # Training classifiers


>>> clf1 = DecisionTreeClassifier(max_depth=4)
>>> clf2 = KNeighborsClassifier(n_neighbors=7)
>>> clf3 = SVC(gamma='scale', kernel='rbf', probability=True)
>>> eclf = VotingClassifier(estimators=[('dt', clf1), ('knn', clf2), ('svc', clf3)],
... voting='soft', weights=[2, 1, 2])

>>> clf1 = clf1.fit(X, y)


>>> clf2 = clf2.fit(X, y)
>>> clf3 = clf3.fit(X, y)
>>> eclf = eclf.fit(X, y)

Using the VotingClassifier with GridSearch

The VotingClassifier can also be used together with GridSearch in order to tune the hyperparameters of the individual
estimators:

278 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

>>> from sklearn.model_selection import GridSearchCV


>>> clf1 = LogisticRegression(solver='lbfgs', multi_class='multinomial',
... random_state=1)
>>> clf2 = RandomForestClassifier(random_state=1)
>>> clf3 = GaussianNB()
>>> eclf = VotingClassifier(estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],
˓→voting='soft')

>>> params = {'lr__C': [1.0, 100.0], 'rf__n_estimators': [20, 200]}

>>> grid = GridSearchCV(estimator=eclf, param_grid=params, cv=5)


>>> grid = grid.fit(iris.data, iris.target)

Usage

In order to predict the class labels based on the predicted class-probabilities (scikit-learn estimators in the VotingClas-
sifier must support predict_proba method):

>>> eclf = VotingClassifier(estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],


˓→voting='soft')

Optionally, weights can be provided for the individual classifiers:

>>> eclf = VotingClassifier(estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],


... voting='soft', weights=[2, 5, 1])

3.1.12 Multiclass and multilabel algorithms

Warning: All classifiers in scikit-learn do multiclass classification out-of-the-box. You don’t need to use the
sklearn.multiclass module unless you want to experiment with different multiclass strategies.

The sklearn.multiclass module implements meta-estimators to solve multiclass and multilabel clas-
sification problems by decomposing such problems into binary classification problems. Multitarget regression is also
supported.
• Multiclass classification means a classification task with more than two classes; e.g., classify a set of images of
fruits which may be oranges, apples, or pears. Multiclass classification makes the assumption that each sample
is assigned to one and only one label: a fruit can be either an apple or a pear but not both at the same time.
• Multilabel classification assigns to each sample a set of target labels. This can be thought as predicting proper-
ties of a data-point that are not mutually exclusive, such as topics that are relevant for a document. A text might
be about any of religion, politics, finance or education at the same time or none of these.
• Multioutput regression assigns each sample a set of target values. This can be thought of as predicting several
properties for each data-point, such as wind direction and magnitude at a certain location.
• Multioutput-multiclass classification and multi-task classification means that a single estimator has to handle
several joint classification tasks. This is both a generalization of the multi-label classification task, which only
considers binary classification, as well as a generalization of the multi-class classification task. The output
format is a 2d numpy array or sparse matrix.
The set of labels can be different for each output variable. For instance, a sample could be assigned “pear” for
an output variable that takes possible values in a finite set of species such as “pear”, “apple”; and “blue” or

3.1. Supervised learning 279


scikit-learn user guide, Release 0.20.3

“green” for a second output variable that takes possible values in a finite set of colors such as “green”, “red”,
“blue”, “yellow”. . .
This means that any classifiers handling multi-output multiclass or multi-task classification tasks, support the
multi-label classification task as a special case. Multi-task classification is similar to the multi-output classifica-
tion task with different model formulations. For more information, see the relevant estimator documentation.
All scikit-learn classifiers are capable of multiclass classification, but the meta-estimators offered by sklearn.
multiclass permit changing the way they handle more than two classes because this may have an effect on classifier
performance (either in terms of generalization error or required computational resources).
Below is a summary of the classifiers supported by scikit-learn grouped by strategy; you don’t need the meta-estimators
in this class if you’re using one of these, unless you want custom multiclass behavior:
• Inherently multiclass:
– sklearn.naive_bayes.BernoulliNB
– sklearn.tree.DecisionTreeClassifier
– sklearn.tree.ExtraTreeClassifier
– sklearn.ensemble.ExtraTreesClassifier
– sklearn.naive_bayes.GaussianNB
– sklearn.neighbors.KNeighborsClassifier
– sklearn.semi_supervised.LabelPropagation
– sklearn.semi_supervised.LabelSpreading
– sklearn.discriminant_analysis.LinearDiscriminantAnalysis
– sklearn.svm.LinearSVC (setting multi_class=”crammer_singer”)
– sklearn.linear_model.LogisticRegression (setting multi_class=”multinomial”)
– sklearn.linear_model.LogisticRegressionCV (setting multi_class=”multinomial”)
– sklearn.neural_network.MLPClassifier
– sklearn.neighbors.NearestCentroid
– sklearn.discriminant_analysis.QuadraticDiscriminantAnalysis
– sklearn.neighbors.RadiusNeighborsClassifier
– sklearn.ensemble.RandomForestClassifier
– sklearn.linear_model.RidgeClassifier
– sklearn.linear_model.RidgeClassifierCV
• Multiclass as One-Vs-One:
– sklearn.svm.NuSVC
– sklearn.svm.SVC.
– sklearn.gaussian_process.GaussianProcessClassifier (setting multi_class =
“one_vs_one”)
• Multiclass as One-Vs-All:
– sklearn.ensemble.GradientBoostingClassifier
– sklearn.gaussian_process.GaussianProcessClassifier (setting multi_class =
“one_vs_rest”)

280 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

– sklearn.svm.LinearSVC (setting multi_class=”ovr”)


– sklearn.linear_model.LogisticRegression (setting multi_class=”ovr”)
– sklearn.linear_model.LogisticRegressionCV (setting multi_class=”ovr”)
– sklearn.linear_model.SGDClassifier
– sklearn.linear_model.Perceptron
– sklearn.linear_model.PassiveAggressiveClassifier
• Support multilabel:
– sklearn.tree.DecisionTreeClassifier
– sklearn.tree.ExtraTreeClassifier
– sklearn.ensemble.ExtraTreesClassifier
– sklearn.neighbors.KNeighborsClassifier
– sklearn.neural_network.MLPClassifier
– sklearn.neighbors.RadiusNeighborsClassifier
– sklearn.ensemble.RandomForestClassifier
– sklearn.linear_model.RidgeClassifierCV
• Support multiclass-multioutput:
– sklearn.tree.DecisionTreeClassifier
– sklearn.tree.ExtraTreeClassifier
– sklearn.ensemble.ExtraTreesClassifier
– sklearn.neighbors.KNeighborsClassifier
– sklearn.neighbors.RadiusNeighborsClassifier
– sklearn.ensemble.RandomForestClassifier

Warning: At present, no metric in sklearn.metrics supports the multioutput-multiclass classification task.

Multilabel classification format

In multilabel learning, the joint set of binary classification tasks is expressed with label binary indicator array: each
sample is one row of a 2d array of shape (n_samples, n_classes) with binary values: the one, i.e. the non zero elements,
corresponds to the subset of labels. An array such as np.array([[1, 0, 0], [0, 1, 1], [0, 0, 0]])
represents label 0 in the first sample, labels 1 and 2 in the second sample, and no labels in the third sample.
Producing multilabel data as a list of sets of labels may be more intuitive. The MultiLabelBinarizer transformer
can be used to convert between a collection of collections of labels and the indicator format.

>>> from sklearn.preprocessing import MultiLabelBinarizer


>>> y = [[2, 3, 4], [2], [0, 1, 3], [0, 1, 2, 3, 4], [0, 1, 2]]
>>> MultiLabelBinarizer().fit_transform(y)
array([[0, 0, 1, 1, 1],
[0, 0, 1, 0, 0],
[1, 1, 0, 1, 0],

3.1. Supervised learning 281


scikit-learn user guide, Release 0.20.3

[1, 1, 1, 1, 1],
[1, 1, 1, 0, 0]])

One-Vs-The-Rest

This strategy, also known as one-vs-all, is implemented in OneVsRestClassifier. The strategy consists in
fitting one classifier per class. For each classifier, the class is fitted against all the other classes. In addition to its
computational efficiency (only n_classes classifiers are needed), one advantage of this approach is its interpretability.
Since each class is represented by one and only one classifier, it is possible to gain knowledge about the class by
inspecting its corresponding classifier. This is the most commonly used strategy and is a fair default choice.

Multiclass learning

Below is an example of multiclass learning using OvR:

>>> from sklearn import datasets


>>> from sklearn.multiclass import OneVsRestClassifier
>>> from sklearn.svm import LinearSVC
>>> iris = datasets.load_iris()
>>> X, y = iris.data, iris.target
>>> OneVsRestClassifier(LinearSVC(random_state=0)).fit(X, y).predict(X)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

Multilabel learning

OneVsRestClassifier also supports multilabel classification. To use this feature, feed the classifier an indicator
matrix, in which cell [i, j] indicates the presence of label j in sample i.

Examples:

• Multilabel classification

One-Vs-One

OneVsOneClassifier constructs one classifier per pair of classes. At prediction time, the class which received
the most votes is selected. In the event of a tie (among two classes with an equal number of votes), it selects the class
with the highest aggregate classification confidence by summing over the pair-wise classification confidence levels
computed by the underlying binary classifiers.
Since it requires to fit n_classes * (n_classes - 1) / 2 classifiers, this method is usually slower than
one-vs-the-rest, due to its O(n_classes^2) complexity. However, this method may be advantageous for algorithms
such as kernel algorithms which don’t scale well with n_samples. This is because each individual learning problem
only involves a small subset of the data whereas, with one-vs-the-rest, the complete dataset is used n_classes times.

282 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Multiclass learning

Below is an example of multiclass learning using OvO:

>>> from sklearn import datasets


>>> from sklearn.multiclass import OneVsOneClassifier
>>> from sklearn.svm import LinearSVC
>>> iris = datasets.load_iris()
>>> X, y = iris.data, iris.target
>>> OneVsOneClassifier(LinearSVC(random_state=0)).fit(X, y).predict(X)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

References:

• “Pattern Recognition and Machine Learning. Springer”, Christopher M. Bishop, page 183, (First Edition)

3.1. Supervised learning 283


scikit-learn user guide, Release 0.20.3

Error-Correcting Output-Codes

Output-code based strategies are fairly different from one-vs-the-rest and one-vs-one. With these strategies, each class
is represented in a Euclidean space, where each dimension can only be 0 or 1. Another way to put it is that each class
is represented by a binary code (an array of 0 and 1). The matrix which keeps track of the location/code of each class
is called the code book. The code size is the dimensionality of the aforementioned space. Intuitively, each class should
be represented by a code as unique as possible and a good code book should be designed to optimize classification
accuracy. In this implementation, we simply use a randomly-generated code book as advocated in3 although more
elaborate methods may be added in the future.
At fitting time, one binary classifier per bit in the code book is fitted. At prediction time, the classifiers are used to
project new points in the class space and the class closest to the points is chosen.
In OutputCodeClassifier, the code_size attribute allows the user to control the number of classifiers which
will be used. It is a percentage of the total number of classes.
A number between 0 and 1 will require fewer classifiers than one-vs-the-rest. In theory, log2(n_classes) /
n_classes is sufficient to represent each class unambiguously. However, in practice, it may not lead to good
accuracy since log2(n_classes) is much smaller than n_classes.
A number greater than 1 will require more classifiers than one-vs-the-rest. In this case, some classifiers will in theory
correct for the mistakes made by other classifiers, hence the name “error-correcting”. In practice, however, this may
not happen as classifier mistakes will typically be correlated. The error-correcting output codes have a similar effect
to bagging.

Multiclass learning

Below is an example of multiclass learning using Output-Codes:

>>> from sklearn import datasets


>>> from sklearn.multiclass import OutputCodeClassifier
>>> from sklearn.svm import LinearSVC
>>> iris = datasets.load_iris()
>>> X, y = iris.data, iris.target
>>> clf = OutputCodeClassifier(LinearSVC(random_state=0),
... code_size=2, random_state=0)
>>> clf.fit(X, y).predict(X)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1,
1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

References:

• “Solving multiclass learning problems via error-correcting output codes”, Dietterich T., Bakiri G., Journal of
Artificial Intelligence Research 2, 1995.
• “The Elements of Statistical Learning”, Hastie T., Tibshirani R., Friedman J., page 606 (second-edition) 2008.

3 “The error coding method and PICTs”, James G., Hastie T., Journal of Computational and Graphical statistics 7, 1998.

284 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Multioutput regression

Multioutput regression support can be added to any regressor with MultiOutputRegressor. This strategy con-
sists of fitting one regressor per target. Since each target is represented by exactly one regressor it is possible to
gain knowledge about the target by inspecting its corresponding regressor. As MultiOutputRegressor fits one
regressor per target it can not take advantage of correlations between targets.
Below is an example of multioutput regression:

>>> from sklearn.datasets import make_regression


>>> from sklearn.multioutput import MultiOutputRegressor
>>> from sklearn.ensemble import GradientBoostingRegressor
>>> X, y = make_regression(n_samples=10, n_targets=3, random_state=1)
>>> MultiOutputRegressor(GradientBoostingRegressor(random_state=0)).fit(X, y).
˓→predict(X)

array([[-154.75474165, -147.03498585, -50.03812219],


[ 7.12165031, 5.12914884, -81.46081961],
[-187.8948621 , -100.44373091, 13.88978285],
[-141.62745778, 95.02891072, -191.48204257],
[ 97.03260883, 165.34867495, 139.52003279],
[ 123.92529176, 21.25719016, -7.84253 ],
[-122.25193977, -85.16443186, -107.12274212],
[ -30.170388 , -94.80956739, 12.16979946],
[ 140.72667194, 176.50941682, -17.50447799],
[ 149.37967282, -81.15699552, -5.72850319]])

Multioutput classification

Multioutput classification support can be added to any classifier with MultiOutputClassifier. This strategy
consists of fitting one classifier per target. This allows multiple target variable classifications. The purpose of this class
is to extend estimators to be able to estimate a series of target functions (f1,f2,f3. . . ,fn) that are trained on a single X
predictor matrix to predict a series of responses (y1,y2,y3. . . ,yn).
Below is an example of multioutput classification:

>>> from sklearn.datasets import make_classification


>>> from sklearn.multioutput import MultiOutputClassifier
>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.utils import shuffle
>>> import numpy as np
>>> X, y1 = make_classification(n_samples=10, n_features=100, n_informative=30, n_
˓→classes=3, random_state=1)

>>> y2 = shuffle(y1, random_state=1)


>>> y3 = shuffle(y1, random_state=2)
>>> Y = np.vstack((y1, y2, y3)).T
>>> n_samples, n_features = X.shape # 10,100
>>> n_outputs = Y.shape[1] # 3
>>> n_classes = 3
>>> forest = RandomForestClassifier(n_estimators=100, random_state=1)
>>> multi_target_forest = MultiOutputClassifier(forest, n_jobs=-1)
>>> multi_target_forest.fit(X, Y).predict(X)
array([[2, 2, 0],
[1, 2, 1],
[2, 1, 0],
[0, 0, 2],
[0, 2, 1],
[0, 0, 2],

3.1. Supervised learning 285


scikit-learn user guide, Release 0.20.3

[1, 1, 0],
[1, 1, 1],
[0, 0, 2],
[2, 0, 0]])

Classifier Chain

Classifier chains (see ClassifierChain) are a way of combining a number of binary classifiers into a single
multi-label model that is capable of exploiting correlations among targets.
For a multi-label classification problem with N classes, N binary classifiers are assigned an integer between 0 and N-1.
These integers define the order of models in the chain. Each classifier is then fit on the available training data plus the
true labels of the classes whose models were assigned a lower number.
When predicting, the true labels will not be available. Instead the predictions of each model are passed on to the
subsequent models in the chain to be used as features.
Clearly the order of the chain is important. The first model in the chain has no information about the other labels while
the last model in the chain has features indicating the presence of all of the other labels. In general one does not know
the optimal ordering of the models in the chain so typically many randomly ordered chains are fit and their predictions
are averaged together.

References:

Jesse Read, Bernhard Pfahringer, Geoff Holmes, Eibe Frank, “Classifier Chains for Multi-label Classifica-
tion”, 2009.

Regressor Chain

Regressor chains (see RegressorChain) is analogous to ClassifierChain as a way of combining a number of re-
gressions into a single multi-target model that is capable of exploiting correlations among targets.

3.1.13 Feature selection

The classes in the sklearn.feature_selection module can be used for feature selection/dimensionality re-
duction on sample sets, either to improve estimators’ accuracy scores or to boost their performance on very high-
dimensional datasets.

Removing features with low variance

VarianceThreshold is a simple baseline approach to feature selection. It removes all features whose variance
doesn’t meet some threshold. By default, it removes all zero-variance features, i.e. features that have the same value
in all samples.
As an example, suppose that we have a dataset with boolean features, and we want to remove all features that are
either one or zero (on or off) in more than 80% of the samples. Boolean features are Bernoulli random variables, and
the variance of such variables is given by

Var[𝑋] = 𝑝(1 − 𝑝)

so we can select using the threshold .8 * (1 - .8):

286 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

>>> from sklearn.feature_selection import VarianceThreshold


>>> X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
>>> sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
>>> sel.fit_transform(X)
array([[0, 1],
[1, 0],
[0, 0],
[1, 1],
[1, 0],
[1, 1]])

As expected, VarianceThreshold has removed the first column, which has a probability 𝑝 = 5/6 > .8 of
containing a zero.

Univariate feature selection

Univariate feature selection works by selecting the best features based on univariate statistical tests. It can be seen
as a preprocessing step to an estimator. Scikit-learn exposes feature selection routines as objects that implement the
transform method:
• SelectKBest removes all but the 𝑘 highest scoring features
• SelectPercentile removes all but a user-specified highest scoring percentage of features
• using common univariate statistical tests for each feature: false positive rate SelectFpr, false discovery rate
SelectFdr, or family wise error SelectFwe.
• GenericUnivariateSelect allows to perform univariate feature selection with a configurable strategy.
This allows to select the best univariate selection strategy with hyper-parameter search estimator.
For instance, we can perform a 𝜒2 test to the samples to retrieve only the two best features as follows:

>>> from sklearn.datasets import load_iris


>>> from sklearn.feature_selection import SelectKBest
>>> from sklearn.feature_selection import chi2
>>> iris = load_iris()
>>> X, y = iris.data, iris.target
>>> X.shape
(150, 4)
>>> X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
>>> X_new.shape
(150, 2)

These objects take as input a scoring function that returns univariate scores and p-values (or only scores for
SelectKBest and SelectPercentile):
• For regression: f_regression, mutual_info_regression
• For classification: chi2, f_classif, mutual_info_classif
The methods based on F-test estimate the degree of linear dependency between two random variables. On the other
hand, mutual information methods can capture any kind of statistical dependency, but being nonparametric, they
require more samples for accurate estimation.

Feature selection with sparse data

3.1. Supervised learning 287


scikit-learn user guide, Release 0.20.3

If you use sparse data (i.e. data represented as sparse matrices), chi2, mutual_info_regression,
mutual_info_classif will deal with the data without making it dense.

Warning: Beware not to use a regression scoring function with a classification problem, you will get useless
results.

Examples:

• Univariate Feature Selection


• Comparison of F-test and mutual information

Recursive feature elimination

Given an external estimator that assigns weights to features (e.g., the coefficients of a linear model), recursive feature
elimination (RFE) is to select features by recursively considering smaller and smaller sets of features. First, the
estimator is trained on the initial set of features and the importance of each feature is obtained either through a coef_
attribute or through a feature_importances_ attribute. Then, the least important features are pruned from
current set of features.That procedure is recursively repeated on the pruned set until the desired number of features to
select is eventually reached.
RFECV performs RFE in a cross-validation loop to find the optimal number of features.

Examples:

• Recursive feature elimination: A recursive feature elimination example showing the relevance of pixels in a
digit classification task.
• Recursive feature elimination with cross-validation: A recursive feature elimination example with automatic
tuning of the number of features selected with cross-validation.

Feature selection using SelectFromModel

SelectFromModel is a meta-transformer that can be used along with any estimator that has a coef_ or
feature_importances_ attribute after fitting. The features are considered unimportant and removed, if the
corresponding coef_ or feature_importances_ values are below the provided threshold parameter. Apart
from specifying the threshold numerically, there are built-in heuristics for finding a threshold using a string argument.
Available heuristics are “mean”, “median” and float multiples of these like “0.1*mean”.
For examples on how it is to be used refer to the sections below.

Examples

• Feature selection using SelectFromModel and LassoCV: Selecting the two most important features from the
Boston dataset without knowing the threshold beforehand.

288 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

L1-based feature selection

Linear models penalized with the L1 norm have sparse solutions: many of their estimated coefficients are zero.
When the goal is to reduce the dimensionality of the data to use with another classifier, they can be used along
with feature_selection.SelectFromModel to select the non-zero coefficients. In particular, sparse
estimators useful for this purpose are the linear_model.Lasso for regression, and of linear_model.
LogisticRegression and svm.LinearSVC for classification:

>>> from sklearn.svm import LinearSVC


>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectFromModel
>>> iris = load_iris()
>>> X, y = iris.data, iris.target
>>> X.shape
(150, 4)
>>> lsvc = LinearSVC(C=0.01, penalty="l1", dual=False).fit(X, y)
>>> model = SelectFromModel(lsvc, prefit=True)
>>> X_new = model.transform(X)
>>> X_new.shape
(150, 3)

With SVMs and logistic-regression, the parameter C controls the sparsity: the smaller C the fewer features selected.
With Lasso, the higher the alpha parameter, the fewer features selected.

Examples:

• Classification of text documents using sparse features: Comparison of different algorithms for document
classification including L1-based feature selection.

L1-recovery and compressive sensing

For a good choice of alpha, the Lasso can fully recover the exact set of non-zero variables using only few obser-
vations, provided certain specific conditions are met. In particular, the number of samples should be “sufficiently
large”, or L1 models will perform at random, where “sufficiently large” depends on the number of non-zero co-
efficients, the logarithm of the number of features, the amount of noise, the smallest absolute value of non-zero
coefficients, and the structure of the design matrix X. In addition, the design matrix must display certain specific
properties, such as not being too correlated.
There is no general rule to select an alpha parameter for recovery of non-zero coefficients. It can by set by cross-
validation (LassoCV or LassoLarsCV), though this may lead to under-penalized models: including a small
number of non-relevant variables is not detrimental to prediction score. BIC (LassoLarsIC) tends, on the oppo-
site, to set high values of alpha.
Reference Richard G. Baraniuk “Compressive Sensing”, IEEE Signal Processing Magazine [120] July 2007 http:
//users.isr.ist.utl.pt/~aguiar/CS_notes.pdf

Tree-based feature selection

Tree-based estimators (see the sklearn.tree module and forest of trees in the sklearn.ensemble module)
can be used to compute feature importances, which in turn can be used to discard irrelevant features (when coupled
with the sklearn.feature_selection.SelectFromModel meta-transformer):

3.1. Supervised learning 289


scikit-learn user guide, Release 0.20.3

>>> from sklearn.ensemble import ExtraTreesClassifier


>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectFromModel
>>> iris = load_iris()
>>> X, y = iris.data, iris.target
>>> X.shape
(150, 4)
>>> clf = ExtraTreesClassifier(n_estimators=50)
>>> clf = clf.fit(X, y)
>>> clf.feature_importances_
array([ 0.04..., 0.05..., 0.4..., 0.4...])
>>> model = SelectFromModel(clf, prefit=True)
>>> X_new = model.transform(X)
>>> X_new.shape
(150, 2)

Examples:

• Feature importances with forests of trees: example on synthetic data showing the recovery of the actually
meaningful features.
• Pixel importances with a parallel forest of trees: example on face recognition data.

Feature selection as part of a pipeline

Feature selection is usually used as a pre-processing step before doing the actual learning. The recommended way to
do this in scikit-learn is to use a sklearn.pipeline.Pipeline:

clf = Pipeline([
('feature_selection', SelectFromModel(LinearSVC(penalty="l1"))),
('classification', RandomForestClassifier())
])
clf.fit(X, y)

In this snippet we make use of a sklearn.svm.LinearSVC coupled with sklearn.feature_selection.


SelectFromModel to evaluate feature importances and select the most relevant features. Then, a sklearn.
ensemble.RandomForestClassifier is trained on the transformed output, i.e. using only relevant features.
You can perform similar operations with the other feature selection methods and also classifiers that provide a way to
evaluate feature importances of course. See the sklearn.pipeline.Pipeline examples for more details.

3.1.14 Semi-Supervised

Semi-supervised learning is a situation in which in your training data some of the samples are not labeled. The semi-
supervised estimators in sklearn.semi_supervised are able to make use of this additional unlabeled data to
better capture the shape of the underlying data distribution and generalize better to new samples. These algorithms
can perform well when we have a very small amount of labeled points and a large amount of unlabeled points.

Unlabeled entries in y

It is important to assign an identifier to unlabeled points along with the labeled data when training the model with
the fit method. The identifier that this implementation uses is the integer value −1.

290 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Label Propagation

Label propagation denotes a few variations of semi-supervised graph inference algorithms.


A few features available in this model:
• Can be used for classification and regression tasks
• Kernel methods to project data into alternate dimensional spaces
scikit-learn provides two label propagation models: LabelPropagation and LabelSpreading. Both work by
constructing a similarity graph over all items in the input dataset.

Fig. 3.1: An illustration of label-propagation: the structure of unlabeled observations is consistent with the class
structure, and thus the class label can be propagated to the unlabeled observations of the training set.

LabelPropagation and LabelSpreading differ in modifications to the similarity matrix that graph and the
clamping effect on the label distributions. Clamping allows the algorithm to change the weight of the true ground
labeled data to some degree. The LabelPropagation algorithm performs hard clamping of input labels, which
means 𝛼 = 0. This clamping factor can be relaxed, to say 𝛼 = 0.2, which means that we will always retain 80 percent
of our original label distribution, but the algorithm gets to change its confidence of the distribution within 20 percent.
LabelPropagation uses the raw similarity matrix constructed from the data with no modifications. In contrast,
LabelSpreading minimizes a loss function that has regularization properties, as such it is often more robust to
noise. The algorithm iterates on a modified version of the original graph and normalizes the edge weights by computing
the normalized graph Laplacian matrix. This procedure is also used in Spectral clustering.
Label propagation models have two built-in kernel methods. Choice of kernel effects both scalability and performance
of the algorithms. The following are available:
• rbf (exp(−𝛾|𝑥 − 𝑦|2 ), 𝛾 > 0). 𝛾 is specified by keyword gamma.
• knn (1[𝑥′ ∈ 𝑘𝑁 𝑁 (𝑥)]). 𝑘 is specified by keyword n_neighbors.
The RBF kernel will produce a fully connected graph which is represented in memory by a dense matrix. This matrix
may be very large and combined with the cost of performing a full matrix multiplication calculation for each iteration
of the algorithm can lead to prohibitively long running times. On the other hand, the KNN kernel will produce a much
more memory-friendly sparse matrix which can drastically reduce running times.

Examples

3.1. Supervised learning 291


scikit-learn user guide, Release 0.20.3

• Decision boundary of label propagation versus SVM on the Iris dataset


• Label Propagation learning a complex structure
• Label Propagation digits: Demonstrating performance
• Label Propagation digits active learning

References

[1] Yoshua Bengio, Olivier Delalleau, Nicolas Le Roux. In Semi-Supervised Learning (2006), pp. 193-216
[2] Olivier Delalleau, Yoshua Bengio, Nicolas Le Roux. Efficient Non-Parametric Function Induction in Semi-
Supervised Learning. AISTAT 2005 https://research.microsoft.com/en-us/people/nicolasl/efficient_ssl.pdf

3.1.15 Isotonic regression

The class IsotonicRegression fits a non-decreasing function to data. It solves the following problem:
minimize 𝑖 𝑤𝑖 (𝑦𝑖 − 𝑦ˆ𝑖 )2
∑︀

subject to 𝑦ˆ𝑚𝑖𝑛 = 𝑦ˆ1 ≤ 𝑦ˆ2 ... ≤ 𝑦ˆ𝑛 = 𝑦ˆ𝑚𝑎𝑥


where each 𝑤𝑖 is strictly positive and each 𝑦𝑖 is an arbitrary real number. It yields the vector which is composed of
non-decreasing elements the closest in terms of mean squared error. In practice this list of elements forms a function
that is piecewise linear.

3.1.16 Probability calibration

When performing classification you often want not only to predict the class label, but also obtain a probability of the
respective label. This probability gives you some kind of confidence on the prediction. Some models can give you
poor estimates of the class probabilities and some even do not support probability prediction. The calibration module
allows you to better calibrate the probabilities of a given model, or to add support for probability prediction.
Well calibrated classifiers are probabilistic classifiers for which the output of the predict_proba method can be directly
interpreted as a confidence level. For instance, a well calibrated (binary) classifier should classify the samples such
that among the samples to which it gave a predict_proba value close to 0.8, approximately 80% actually belong to the
positive class. The following plot compares how well the probabilistic predictions of different classifiers are calibrated:

LogisticRegression returns well calibrated predictions by default as it directly optimizes log-loss. In contrast,
the other methods return biased probabilities; with different biases per method:
• GaussianNB tends to push probabilities to 0 or 1 (note the counts in the histograms). This is mainly because
it makes the assumption that features are conditionally independent given the class, which is not the case in this
dataset which contains 2 redundant features.
• RandomForestClassifier shows the opposite behavior: the histograms show peaks at approximately
0.2 and 0.9 probability, while probabilities close to 0 or 1 are very rare. An explanation for this is given by
Niculescu-Mizil and Caruana4 : “Methods such as bagging and random forests that average predictions from a
base set of models can have difficulty making predictions near 0 and 1 because variance in the underlying base
models will bias predictions that should be near zero or one away from these values. Because predictions are
restricted to the interval [0,1], errors caused by variance tend to be one-sided near zero and one. For example,
if a model should predict p = 0 for a case, the only way bagging can achieve this is if all bagged trees predict
4 Predicting Good Probabilities with Supervised Learning, A. Niculescu-Mizil & R. Caruana, ICML 2005

292 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

3.1. Supervised learning 293


scikit-learn user guide, Release 0.20.3

294 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

zero. If we add noise to the trees that bagging is averaging over, this noise will cause some trees to predict
values larger than 0 for this case, thus moving the average prediction of the bagged ensemble away from 0. We
observe this effect most strongly with random forests because the base-level trees trained with random forests
have relatively high variance due to feature subsetting.” As a result, the calibration curve also referred to as the
reliability diagram (Wilks 19955 ) shows a characteristic sigmoid shape, indicating that the classifier could trust
its “intuition” more and return probabilities closer to 0 or 1 typically.
• Linear Support Vector Classification (LinearSVC) shows an even more sigmoid curve as the RandomForest-
Classifier, which is typical for maximum-margin methods (compare Niculescu-Mizil and Caruana4 ), which
focus on hard samples that are close to the decision boundary (the support vectors).
Two approaches for performing calibration of probabilistic predictions are provided: a parametric approach based on
Platt’s sigmoid model and a non-parametric approach based on isotonic regression (sklearn.isotonic). Proba-
bility calibration should be done on new data not used for model fitting. The class CalibratedClassifierCV
uses a cross-validation generator and estimates for each split the model parameter on the train samples and the cali-
bration of the test samples. The probabilities predicted for the folds are then averaged. Already fitted classifiers can
be calibrated by CalibratedClassifierCV via the parameter cv=”prefit”. In this case, the user has to take care
manually that data for model fitting and calibration are disjoint.
The following images demonstrate the benefit of probability calibration. The first image present a dataset with 2
classes and 3 blobs of data. The blob in the middle contains random samples of each class. The probability for the
samples in this blob should be 0.5.

The following image shows on the data above the estimated probability using a Gaussian naive Bayes classifier without
5 On the combination of forecast probabilities for consecutive precipitation periods. Wea. Forecasting, 5, 640–650., Wilks, D. S., 1990a

3.1. Supervised learning 295


scikit-learn user guide, Release 0.20.3

calibration, with a sigmoid calibration and with a non-parametric isotonic calibration. One can observe that the non-
parametric model provides the most accurate probability estimates for samples in the middle, i.e., 0.5.

The following experiment is performed on an artificial dataset for binary classification with 100,000 samples (1,000
of them are used for model fitting) with 20 features. Of the 20 features, only 2 are informative and 10 are redundant.
The figure shows the estimated probabilities obtained with logistic regression, a linear support-vector classifier (SVC),
and linear SVC with both isotonic calibration and sigmoid calibration. The Brier score is a metric which is a combi-
nation of calibration loss and refinement loss, brier_score_loss, reported in the legend (the smaller the better).
Calibration loss is defined as the mean squared deviation from empirical probabilities derived from the slope of ROC
segments. Refinement loss can be defined as the expected optimal loss as measured by the area under the optimal cost
curve.
One can observe here that logistic regression is well calibrated as its curve is nearly diagonal. Linear SVC’s calibration
curve or reliability diagram has a sigmoid curve, which is typical for an under-confident classifier. In the case of
LinearSVC, this is caused by the margin property of the hinge loss, which lets the model focus on hard samples that
are close to the decision boundary (the support vectors). Both kinds of calibration can fix this issue and yield nearly
identical results. The next figure shows the calibration curve of Gaussian naive Bayes on the same data, with both
kinds of calibration and also without calibration.
One can see that Gaussian naive Bayes performs very badly but does so in an other way than linear SVC: While linear
SVC exhibited a sigmoid calibration curve, Gaussian naive Bayes’ calibration curve has a transposed-sigmoid shape.
This is typical for an over-confident classifier. In this case, the classifier’s overconfidence is caused by the redundant
features which violate the naive Bayes assumption of feature-independence.
Calibration of the probabilities of Gaussian naive Bayes with isotonic regression can fix this issue as can be seen from

296 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

3.1. Supervised learning 297


scikit-learn user guide, Release 0.20.3

298 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

the nearly diagonal calibration curve. Sigmoid calibration also improves the brier score slightly, albeit not as strongly
as the non-parametric isotonic calibration. This is an intrinsic limitation of sigmoid calibration, whose parametric form
assumes a sigmoid rather than a transposed-sigmoid curve. The non-parametric isotonic calibration model, however,
makes no such strong assumptions and can deal with either shape, provided that there is sufficient calibration data. In
general, sigmoid calibration is preferable in cases where the calibration curve is sigmoid and where there is limited
calibration data, while isotonic calibration is preferable for non-sigmoid calibration curves and in situations where
large amounts of data are available for calibration.
CalibratedClassifierCV can also deal with classification tasks that involve more than two classes if the base
estimator can do so. In this case, the classifier is calibrated first for each class separately in an one-vs-rest fashion.
When predicting probabilities for unseen data, the calibrated probabilities for each class are predicted separately. As
those probabilities do not necessarily sum to one, a postprocessing is performed to normalize them.
The next image illustrates how sigmoid calibration changes predicted probabilities for a 3-class classification problem.
Illustrated is the standard 2-simplex, where the three corners correspond to the three classes. Arrows point from the
probability vectors predicted by an uncalibrated classifier to the probability vectors predicted by the same classifier
after sigmoid calibration on a hold-out validation set. Colors indicate the true class of an instance (red: class 1, green:
class 2, blue: class 3).

The base classifier is a random forest classifier with 25 base estimators (trees). If this classifier is trained on all 800
training datapoints, it is overly confident in its predictions and thus incurs a large log-loss. Calibrating an identical
classifier, which was trained on 600 datapoints, with method=’sigmoid’ on the remaining 200 datapoints reduces the
confidence of the predictions, i.e., moves the probability vectors from the edges of the simplex towards the center:
This calibration results in a lower log-loss. Note that an alternative would have been to increase the number of base

3.1. Supervised learning 299


scikit-learn user guide, Release 0.20.3

300 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

estimators which would have resulted in a similar decrease in log-loss.

References:

• Obtaining calibrated probability estimates from decision trees and naive Bayesian classifiers, B. Zadrozny &
C. Elkan, ICML 2001
• Transforming Classifier Scores into Accurate Multiclass Probability Estimates, B. Zadrozny & C. Elkan,
(KDD 2002)
• Probabilistic Outputs for Support Vector Machines and Comparisons to Regularized Likelihood Methods, J.
Platt, (1999)

3.1.17 Neural network models (supervised)

Warning: This implementation is not intended for large-scale applications. In particular, scikit-learn offers no
GPU support. For much faster, GPU-based implementations, as well as frameworks offering much more flexibility
to build deep learning architectures, see Related Projects.

Multi-layer Perceptron

Multi-layer Perceptron (MLP) is a supervised learning algorithm that learns a function 𝑓 (·) : 𝑅𝑚 → 𝑅𝑜 by training
on a dataset, where 𝑚 is the number of dimensions for input and 𝑜 is the number of dimensions for output. Given a set
of features 𝑋 = 𝑥1 , 𝑥2 , ..., 𝑥𝑚 and a target 𝑦, it can learn a non-linear function approximator for either classification
or regression. It is different from logistic regression, in that between the input and the output layer, there can be one
or more non-linear layers, called hidden layers. Figure 1 shows a one hidden layer MLP with scalar output.

Fig. 3.2: Figure 1 : One hidden layer MLP.

The leftmost layer, known as the input layer, consists of a set of neurons {𝑥𝑖 |𝑥1 , 𝑥2 , ..., 𝑥𝑚 } representing the input
features. Each neuron in the hidden layer transforms the values from the previous layer with a weighted linear sum-
mation 𝑤1 𝑥1 + 𝑤2 𝑥2 + ... + 𝑤𝑚 𝑥𝑚 , followed by a non-linear activation function 𝑔(·) : 𝑅 → 𝑅 - like the hyperbolic
tan function. The output layer receives the values from the last hidden layer and transforms them into output values.

3.1. Supervised learning 301


scikit-learn user guide, Release 0.20.3

The module contains the public attributes coefs_ and intercepts_. coefs_ is a list of weight matrices, where
weight matrix at index 𝑖 represents the weights between layer 𝑖 and layer 𝑖+1. intercepts_ is a list of bias vectors,
where the vector at index 𝑖 represents the bias values added to layer 𝑖 + 1.
The advantages of Multi-layer Perceptron are:
• Capability to learn non-linear models.
• Capability to learn models in real-time (on-line learning) using partial_fit.
The disadvantages of Multi-layer Perceptron (MLP) include:
• MLP with hidden layers have a non-convex loss function where there exists more than one local minimum.
Therefore different random weight initializations can lead to different validation accuracy.
• MLP requires tuning a number of hyperparameters such as the number of hidden neurons, layers, and iterations.
• MLP is sensitive to feature scaling.
Please see Tips on Practical Use section that addresses some of these disadvantages.

Classification

Class MLPClassifier implements a multi-layer perceptron (MLP) algorithm that trains using Backpropagation.
MLP trains on two arrays: array X of size (n_samples, n_features), which holds the training samples represented as
floating point feature vectors; and array y of size (n_samples,), which holds the target values (class labels) for the
training samples:

>>> from sklearn.neural_network import MLPClassifier


>>> X = [[0., 0.], [1., 1.]]
>>> y = [0, 1]
>>> clf = MLPClassifier(solver='lbfgs', alpha=1e-5,
... hidden_layer_sizes=(5, 2), random_state=1)
...
>>> clf.fit(X, y)
MLPClassifier(activation='relu', alpha=1e-05, batch_size='auto',
beta_1=0.9, beta_2=0.999, early_stopping=False,
epsilon=1e-08, hidden_layer_sizes=(5, 2),
learning_rate='constant', learning_rate_init=0.001,
max_iter=200, momentum=0.9, n_iter_no_change=10,
nesterovs_momentum=True, power_t=0.5, random_state=1,
shuffle=True, solver='lbfgs', tol=0.0001,
validation_fraction=0.1, verbose=False, warm_start=False)

After fitting (training), the model can predict labels for new samples:

>>> clf.predict([[2., 2.], [-1., -2.]])


array([1, 0])

MLP can fit a non-linear model to the training data. clf.coefs_ contains the weight matrices that constitute the
model parameters:

>>> [coef.shape for coef in clf.coefs_]


[(2, 5), (5, 2), (2, 1)]

Currently, MLPClassifier supports only the Cross-Entropy loss function, which allows probability estimates by
running the predict_proba method.

302 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

MLP trains using Backpropagation. More precisely, it trains using some form of gradient descent and the gradients
are calculated using Backpropagation. For classification, it minimizes the Cross-Entropy loss function, giving a vector
of probability estimates 𝑃 (𝑦|𝑥) per sample 𝑥:

>>> clf.predict_proba([[2., 2.], [1., 2.]])


array([[1.967...e-04, 9.998...-01],
[1.967...e-04, 9.998...-01]])

MLPClassifier supports multi-class classification by applying Softmax as the output function.


Further, the model supports multi-label classification in which a sample can belong to more than one class. For each
class, the raw output passes through the logistic function. Values larger or equal to 0.5 are rounded to 1, otherwise to
0. For a predicted output of a sample, the indices where the value is 1 represents the assigned classes of that sample:

>>> X = [[0., 0.], [1., 1.]]


>>> y = [[0, 1], [1, 1]]
>>> clf = MLPClassifier(solver='lbfgs', alpha=1e-5,
... hidden_layer_sizes=(15,), random_state=1)
...
>>> clf.fit(X, y)
MLPClassifier(activation='relu', alpha=1e-05, batch_size='auto',
beta_1=0.9, beta_2=0.999, early_stopping=False,
epsilon=1e-08, hidden_layer_sizes=(15,),
learning_rate='constant', learning_rate_init=0.001,
max_iter=200, momentum=0.9, n_iter_no_change=10,
nesterovs_momentum=True, power_t=0.5, random_state=1,
shuffle=True, solver='lbfgs', tol=0.0001,
validation_fraction=0.1, verbose=False, warm_start=False)
>>> clf.predict([[1., 2.]])
array([[1, 1]])
>>> clf.predict([[0., 0.]])
array([[0, 1]])

See the examples below and the doc string of MLPClassifier.fit for further information.

Examples:

• Compare Stochastic learning strategies for MLPClassifier


• Visualization of MLP weights on MNIST

Regression

Class MLPRegressor implements a multi-layer perceptron (MLP) that trains using backpropagation with no activa-
tion function in the output layer, which can also be seen as using the identity function as activation function. Therefore,
it uses the square error as the loss function, and the output is a set of continuous values.
MLPRegressor also supports multi-output regression, in which a sample can have more than one target.

Regularization

Both MLPRegressor and MLPClassifier use parameter alpha for regularization (L2 regularization) term
which helps in avoiding overfitting by penalizing weights with large magnitudes. Following plot displays varying
decision function with value of alpha.

3.1. Supervised learning 303


scikit-learn user guide, Release 0.20.3

See the examples below for further information.

Examples:

• Varying regularization in Multi-layer Perceptron

Algorithms

MLP trains using Stochastic Gradient Descent, Adam, or L-BFGS. Stochastic Gradient Descent (SGD) updates pa-
rameters using the gradient of the loss function with respect to a parameter that needs adaptation, i.e.

𝜕𝑅(𝑤) 𝜕𝐿𝑜𝑠𝑠
𝑤 ← 𝑤 − 𝜂(𝛼 + )
𝜕𝑤 𝜕𝑤
where 𝜂 is the learning rate which controls the step-size in the parameter space search. 𝐿𝑜𝑠𝑠 is the loss function used
for the network.
More details can be found in the documentation of SGD
Adam is similar to SGD in a sense that it is a stochastic optimizer, but it can automatically adjust the amount to update
parameters based on adaptive estimates of lower-order moments.
With SGD or Adam, training supports online and mini-batch learning.
L-BFGS is a solver that approximates the Hessian matrix which represents the second-order partial derivative of a
function. Further it approximates the inverse of the Hessian matrix to perform parameter updates. The implementation
uses the Scipy version of L-BFGS.
If the selected solver is ‘L-BFGS’, training does not support online nor mini-batch learning.

304 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Complexity

Suppose there are 𝑛 training samples, 𝑚 features, 𝑘 hidden layers, each containing ℎ neurons - for simplicity, and 𝑜
output neurons. The time complexity of backpropagation is 𝑂(𝑛 · 𝑚 · ℎ𝑘 · 𝑜 · 𝑖), where 𝑖 is the number of iterations.
Since backpropagation has a high time complexity, it is advisable to start with smaller number of hidden neurons and
few hidden layers for training.

Mathematical formulation

Given a set of training examples (𝑥1 , 𝑦1 ), (𝑥2 , 𝑦2 ), . . . , (𝑥𝑛 , 𝑦𝑛 ) where 𝑥𝑖 ∈ R𝑛 and 𝑦𝑖 ∈ {0, 1}, a one hidden layer
one hidden neuron MLP learns the function 𝑓 (𝑥) = 𝑊2 𝑔(𝑊1𝑇 𝑥 + 𝑏1 ) + 𝑏2 where 𝑊1 ∈ R𝑚 and 𝑊2 , 𝑏1 , 𝑏2 ∈ R are
model parameters. 𝑊1 , 𝑊2 represent the weights of the input layer and hidden layer, respectively; and 𝑏1 , 𝑏2 represent
the bias added to the hidden layer and the output layer, respectively. 𝑔(·) : 𝑅 → 𝑅 is the activation function, set by
default as the hyperbolic tan. It is given as,
𝑒𝑧 − 𝑒−𝑧
𝑔(𝑧) =
𝑒𝑧 + 𝑒−𝑧
For binary classification, 𝑓 (𝑥) passes through the logistic function 𝑔(𝑧) = 1/(1+𝑒−𝑧 ) to obtain output values between
zero and one. A threshold, set to 0.5, would assign samples of outputs larger or equal 0.5 to the positive class, and the
rest to the negative class.
If there are more than two classes, 𝑓 (𝑥) itself would be a vector of size (n_classes,). Instead of passing through logistic
function, it passes through the softmax function, which is written as,
exp(𝑧𝑖 )
softmax(𝑧)𝑖 = ∑︀𝑘
𝑙=1 exp(𝑧𝑙 )

where 𝑧𝑖 represents the 𝑖 th element of the input to softmax, which corresponds to class 𝑖, and 𝐾 is the number of
classes. The result is a vector containing the probabilities that sample 𝑥 belong to each class. The output is the class
with the highest probability.
In regression, the output remains as 𝑓 (𝑥); therefore, output activation function is just the identity function.
MLP uses different loss functions depending on the problem type. The loss function for classification is Cross-Entropy,
which in binary case is given as,

𝑦 , 𝑦, 𝑊 ) = −𝑦 ln 𝑦ˆ − (1 − 𝑦) ln (1 − 𝑦ˆ) + 𝛼||𝑊 ||22


𝐿𝑜𝑠𝑠(ˆ

where 𝛼||𝑊 ||22 is an L2-regularization term (aka penalty) that penalizes complex models; and 𝛼 > 0 is a non-negative
hyperparameter that controls the magnitude of the penalty.
For regression, MLP uses the Square Error loss function; written as,
1 𝛼
𝐿𝑜𝑠𝑠(ˆ
𝑦 , 𝑦, 𝑊 ) = 𝑦 − 𝑦||22 + ||𝑊 ||22
||ˆ
2 2
Starting from initial random weights, multi-layer perceptron (MLP) minimizes the loss function by repeatedly updating
these weights. After computing the loss, a backward pass propagates it from the output layer to the previous layers,
providing each weight parameter with an update value meant to decrease the loss.
In gradient descent, the gradient ∇𝐿𝑜𝑠𝑠𝑊 of the loss with respect to the weights is computed and deducted from 𝑊 .
More formally, this is expressed as,

𝑊 𝑖+1 = 𝑊 𝑖 − 𝜖∇𝐿𝑜𝑠𝑠𝑖𝑊

where 𝑖 is the iteration step, and 𝜖 is the learning rate with a value larger than 0.
The algorithm stops when it reaches a preset maximum number of iterations; or when the improvement in loss is below
a certain, small number.

3.1. Supervised learning 305


scikit-learn user guide, Release 0.20.3

Tips on Practical Use

• Multi-layer Perceptron is sensitive to feature scaling, so it is highly recommended to scale your data. For
example, scale each attribute on the input vector X to [0, 1] or [-1, +1], or standardize it to have mean 0 and
variance 1. Note that you must apply the same scaling to the test set for meaningful results. You can use
StandardScaler for standardization.

>>> from sklearn.preprocessing import StandardScaler


>>> scaler = StandardScaler()
>>> # Don't cheat - fit only on training data
>>> scaler.fit(X_train)
>>> X_train = scaler.transform(X_train)
>>> # apply same transformation to test data
>>> X_test = scaler.transform(X_test)

An alternative and recommended approach is to use StandardScaler in a Pipeline


• Finding a reasonable regularization parameter 𝛼 is best done using GridSearchCV, usually in the range 10.0
** -np.arange(1, 7).
• Empirically, we observed that L-BFGS converges faster and with better solutions on small datasets. For relatively
large datasets, however, Adam is very robust. It usually converges quickly and gives pretty good performance.
SGD with momentum or nesterov’s momentum, on the other hand, can perform better than those two algorithms
if learning rate is correctly tuned.

More control with warm_start

If you want more control over stopping criteria or learning rate in SGD, or want to do additional monitoring, using
warm_start=True and max_iter=1 and iterating yourself can be helpful:

>>> X = [[0., 0.], [1., 1.]]


>>> y = [0, 1]
>>> clf = MLPClassifier(hidden_layer_sizes=(15,), random_state=1, max_iter=1, warm_
˓→start=True)

>>> for i in range(10):


... clf.fit(X, y)
... # additional monitoring / inspection
MLPClassifier(...

References:

• “Learning representations by back-propagating errors.” Rumelhart, David E., Geoffrey E. Hinton, and Ronald
J. Williams.
• “Stochastic Gradient Descent” L. Bottou - Website, 2010.
• “Backpropagation” Andrew Ng, Jiquan Ngiam, Chuan Yu Foo, Yifan Mai, Caroline Suen - Website, 2011.
• “Efficient BackProp” Y. LeCun, L. Bottou, G. Orr, K. Müller - In Neural Networks: Tricks of the Trade 1998.
• “Adam: A method for stochastic optimization.” Kingma, Diederik, and Jimmy Ba. arXiv preprint
arXiv:1412.6980 (2014).

306 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

3.2 Unsupervised learning

3.2.1 Gaussian mixture models

sklearn.mixture is a package which enables one to learn Gaussian Mixture Models (diagonal, spherical, tied
and full covariance matrices supported), sample them, and estimate them from data. Facilities to help determine the
appropriate number of components are also provided.

Fig. 3.3: Two-component Gaussian mixture model: data points, and equi-probability surfaces of the model.

A Gaussian mixture model is a probabilistic model that assumes all the data points are generated from a mixture of a
finite number of Gaussian distributions with unknown parameters. One can think of mixture models as generalizing
k-means clustering to incorporate information about the covariance structure of the data as well as the centers of the
latent Gaussians.
Scikit-learn implements different classes to estimate Gaussian mixture models, that correspond to different estimation
strategies, detailed below.

Gaussian Mixture

The GaussianMixture object implements the expectation-maximization (EM) algorithm for fitting mixture-of-
Gaussian models. It can also draw confidence ellipsoids for multivariate models, and compute the Bayesian Infor-
mation Criterion to assess the number of clusters in the data. A GaussianMixture.fit method is provided that
learns a Gaussian Mixture Model from train data. Given test data, it can assign to each sample the Gaussian it mostly
probably belong to using the GaussianMixture.predict method.
The GaussianMixture comes with different options to constrain the covariance of the difference classes estimated:
spherical, diagonal, tied or full covariance.

Examples:

• See GMM covariances for an example of using the Gaussian mixture as clustering on the iris dataset.
• See Density Estimation for a Gaussian mixture for an example on plotting the density estimation.

3.2. Unsupervised learning 307


scikit-learn user guide, Release 0.20.3

Pros and cons of class GaussianMixture

Pros

Speed It is the fastest algorithm for learning mixture models


Agnostic As this algorithm maximizes only the likelihood, it will not bias the means towards zero, or
bias the cluster sizes to have specific structures that might or might not apply.

Cons

Singularities When one has insufficiently many points per mixture, estimating the covariance matrices
becomes difficult, and the algorithm is known to diverge and find solutions with infinite likelihood
unless one regularizes the covariances artificially.
Number of components This algorithm will always use all the components it has access to, needing
held-out data or information theoretical criteria to decide how many components to use in the ab-
sence of external cues.

Selecting the number of components in a classical Gaussian Mixture Model

The BIC criterion can be used to select the number of components in a Gaussian Mixture in an efficient way. In theory,
it recovers the true number of components only in the asymptotic regime (i.e. if much data is available and assuming

308 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

that the data was actually generated i.i.d. from a mixture of Gaussian distribution). Note that using a Variational
Bayesian Gaussian mixture avoids the specification of the number of components for a Gaussian mixture model.

Examples:

• See Gaussian Mixture Model Selection for an example of model selection performed with classical Gaussian
mixture.

Estimation algorithm Expectation-maximization

The main difficulty in learning Gaussian mixture models from unlabeled data is that it is one usually doesn’t know
which points came from which latent component (if one has access to this information it gets very easy to fit a separate
Gaussian distribution to each set of points). Expectation-maximization is a well-founded statistical algorithm to get
around this problem by an iterative process. First one assumes random components (randomly centered on data points,
learned from k-means, or even just normally distributed around the origin) and computes for each point a probability
of being generated by each component of the model. Then, one tweaks the parameters to maximize the likelihood of
the data given those assignments. Repeating this process is guaranteed to always converge to a local optimum.

Variational Bayesian Gaussian Mixture

The BayesianGaussianMixture object implements a variant of the Gaussian mixture model with variational
inference algorithms. The API is similar as the one defined by GaussianMixture.

Estimation algorithm: variational inference

Variational inference is an extension of expectation-maximization that maximizes a lower bound on model evidence
(including priors) instead of data likelihood. The principle behind variational methods is the same as expectation-
maximization (that is both are iterative algorithms that alternate between finding the probabilities for each point to

3.2. Unsupervised learning 309


scikit-learn user guide, Release 0.20.3

be generated by each mixture and fitting the mixture to these assigned points), but variational methods add regular-
ization by integrating information from prior distributions. This avoids the singularities often found in expectation-
maximization solutions but introduces some subtle biases to the model. Inference is often notably slower, but not
usually as much so as to render usage unpractical.
Due to its Bayesian nature, the variational algorithm needs more hyper- parameters than expectation-maximization,
the most important of these being the concentration parameter weight_concentration_prior. Specifying a
low value for the concentration prior will make the model put most of the weight on few components set the remain-
ing components weights very close to zero. High values of the concentration prior will allow a larger number of
components to be active in the mixture.
The parameters implementation of the BayesianGaussianMixture class proposes two types of prior for the
weights distribution: a finite mixture model with Dirichlet distribution and an infinite mixture model with the Dirichlet
Process. In practice Dirichlet Process inference algorithm is approximated and uses a truncated distribution with a fixed
maximum number of components (called the Stick-breaking representation). The number of components actually used
almost always depends on the data.
The next figure compares the results obtained for the different type of the weight concentration prior (parameter
weight_concentration_prior_type) for different values of weight_concentration_prior. Here,
we can see the value of the weight_concentration_prior parameter has a strong impact on the effective
number of active components obtained. We can also notice that large values for the concentration weight prior lead
to more uniform weights when the type of prior is ‘dirichlet_distribution’ while this is not necessarily the case for the
‘dirichlet_process’ type (used by default).

310 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

The examples below compare Gaussian mixture models with a fixed number of components, to the variational Gaus-
sian mixture models with a Dirichlet process prior. Here, a classical Gaussian mixture is fitted with 5 components on
a dataset composed of 2 clusters. We can see that the variational Gaussian mixture with a Dirichlet process prior is
able to limit itself to only 2 components whereas the Gaussian mixture fits the data with a fixed number of components
that has to be set a priori by the user. In this case the user has selected n_components=5 which does not match the
true generative distribution of this toy dataset. Note that with very little observations, the variational Gaussian mixture
models with a Dirichlet process prior can take a conservative stand, and fit only one component.

On the following figure we are fitting a dataset not well-depicted by a Gaussian mixture. Adjusting the
weight_concentration_prior, parameter of the BayesianGaussianMixture controls the number of

3.2. Unsupervised learning 311


scikit-learn user guide, Release 0.20.3

components used to fit this data. We also present on the last two plots a random sampling generated from the two
resulting mixtures.

Examples:

• See Gaussian Mixture Model Ellipsoids for an example on plotting the confidence ellipsoids for both
GaussianMixture and BayesianGaussianMixture.
• Gaussian Mixture Model Sine Curve shows using GaussianMixture and
BayesianGaussianMixture to fit a sine wave.
• See Concentration Prior Type Analysis of Variation Bayesian Gaussian Mixture for an ex-
ample plotting the confidence ellipsoids for the BayesianGaussianMixture with dif-

312 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

ferent weight_concentration_prior_type for different values of the parameter


weight_concentration_prior.

Pros and cons of variational inference with BayesianGaussianMixture

Pros

Automatic selection when weight_concentration_prior is small enough and


n_components is larger than what is found necessary by the model, the Variational Bayesian
mixture model has a natural tendency to set some mixture weights values close to zero. This makes
it possible to let the model choose a suitable number of effective components automatically. Only an
upper bound of this number needs to be provided. Note however that the “ideal” number of active
components is very application specific and is typically ill-defined in a data exploration setting.
Less sensitivity to the number of parameters unlike finite models, which will almost always use
all components as much as they can, and hence will produce wildly different solutions for
different numbers of components, the variational inference with a Dirichlet process prior
(weight_concentration_prior_type='dirichlet_process') won’t change much
with changes to the parameters, leading to more stability and less tuning.
Regularization due to the incorporation of prior information, variational solutions have less pathological
special cases than expectation-maximization solutions.

Cons

Speed the extra parametrization necessary for variational inference make inference slower, although not
by much.
Hyperparameters this algorithm needs an extra hyperparameter that might need experimental tuning via
cross-validation.
Bias there are many implicit biases in the inference algorithms (and also in the Dirichlet process if used),
and whenever there is a mismatch between these biases and the data it might be possible to fit better
models using a finite mixture.

The Dirichlet Process

Here we describe variational inference algorithms on Dirichlet process mixture. The Dirichlet process is a prior
probability distribution on clusterings with an infinite, unbounded, number of partitions. Variational techniques let us
incorporate this prior structure on Gaussian mixture models at almost no penalty in inference time, comparing with a
finite Gaussian mixture model.
An important question is how can the Dirichlet process use an infinite, unbounded number of clusters and still be
consistent. While a full explanation doesn’t fit this manual, one can think of its stick breaking process analogy to help
understanding it. The stick breaking process is a generative story for the Dirichlet process. We start with a unit-length
stick and in each step we break off a portion of the remaining stick. Each time, we associate the length of the piece of
the stick to the proportion of points that falls into a group of the mixture. At the end, to represent the infinite mixture,
we associate the last remaining piece of the stick to the proportion of points that don’t fall into all the other groups. The
length of each piece is a random variable with probability proportional to the concentration parameter. Smaller value
of the concentration will divide the unit-length into larger pieces of the stick (defining more concentrated distribution).
Larger concentration values will create smaller pieces of the stick (increasing the number of components with non
zero weights).

3.2. Unsupervised learning 313


scikit-learn user guide, Release 0.20.3

Variational inference techniques for the Dirichlet process still work with a finite approximation to this infinite mixture
model, but instead of having to specify a priori how many components one wants to use, one just specifies the concen-
tration parameter and an upper bound on the number of mixture components (this upper bound, assuming it is higher
than the “true” number of components, affects only algorithmic complexity, not the actual number of components
used).

3.2.2 Manifold learning

Look for the bare necessities


The simple bare necessities
Forget about your worries and your strife
I mean the bare necessities
Old Mother Nature’s recipes
That bring the bare necessities of life

– Baloo’s song [The Jungle Book]

Manifold learning is an approach to non-linear dimensionality reduction. Algorithms for this task are based on the
idea that the dimensionality of many data sets is only artificially high.

Introduction

High-dimensional datasets can be very difficult to visualize. While data in two or three dimensions can be plotted to
show the inherent structure of the data, equivalent high-dimensional plots are much less intuitive. To aid visualization
of the structure of a dataset, the dimension must be reduced in some way.
The simplest way to accomplish this dimensionality reduction is by taking a random projection of the data. Though
this allows some degree of visualization of the data structure, the randomness of the choice leaves much to be desired.
In a random projection, it is likely that the more interesting structure within the data will be lost.

314 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

To address this concern, a number of supervised and unsupervised linear dimensionality reduction frameworks have
been designed, such as Principal Component Analysis (PCA), Independent Component Analysis, Linear Discriminant
Analysis, and others. These algorithms define specific rubrics to choose an “interesting” linear projection of the data.
These methods can be powerful, but often miss important non-linear structure in the data.

Manifold Learning can be thought of as an attempt to generalize linear frameworks like PCA to be sensitive to non-
linear structure in data. Though supervised variants exist, the typical manifold learning problem is unsupervised: it
learns the high-dimensional structure of the data from the data itself, without the use of predetermined classifications.

Examples:

• See Manifold learning on handwritten digits: Locally Linear Embedding, Isomap. . . for an example of
dimensionality reduction on handwritten digits.
• See Comparison of Manifold Learning methods for an example of dimensionality reduction on a toy “S-
curve” dataset.

The manifold learning implementations available in scikit-learn are summarized below

Isomap

One of the earliest approaches to manifold learning is the Isomap algorithm, short for Isometric Mapping. Isomap can
be viewed as an extension of Multi-dimensional Scaling (MDS) or Kernel PCA. Isomap seeks a lower-dimensional

3.2. Unsupervised learning 315


scikit-learn user guide, Release 0.20.3

embedding which maintains geodesic distances between all points. Isomap can be performed with the object Isomap.

Complexity

The Isomap algorithm comprises three stages:


1. Nearest neighbor search. Isomap uses sklearn.neighbors.BallTree for efficient neighbor search.
The cost is approximately 𝑂[𝐷 log(𝑘)𝑁 log(𝑁 )], for 𝑘 nearest neighbors of 𝑁 points in 𝐷 dimensions.
2. Shortest-path graph search. The most efficient known algorithms for this are Dijkstra’s Algorithm, which is
approximately 𝑂[𝑁 2 (𝑘 + log(𝑁 ))], or the Floyd-Warshall algorithm, which is 𝑂[𝑁 3 ]. The algorithm can be
selected by the user with the path_method keyword of Isomap. If unspecified, the code attempts to choose
the best algorithm for the input data.
3. Partial eigenvalue decomposition. The embedding is encoded in the eigenvectors corresponding to the 𝑑
largest eigenvalues of the 𝑁 × 𝑁 isomap kernel. For a dense solver, the cost is approximately 𝑂[𝑑𝑁 2 ]. This
cost can often be improved using the ARPACK solver. The eigensolver can be specified by the user with the
path_method keyword of Isomap. If unspecified, the code attempts to choose the best algorithm for the
input data.
The overall complexity of Isomap is 𝑂[𝐷 log(𝑘)𝑁 log(𝑁 )] + 𝑂[𝑁 2 (𝑘 + log(𝑁 ))] + 𝑂[𝑑𝑁 2 ].
• 𝑁 : number of training data points
• 𝐷 : input dimension
• 𝑘 : number of nearest neighbors
• 𝑑 : output dimension

References:

• “A global geometric framework for nonlinear dimensionality reduction” Tenenbaum, J.B.; De Silva, V.; &
Langford, J.C. Science 290 (5500)

316 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Locally Linear Embedding

Locally linear embedding (LLE) seeks a lower-dimensional projection of the data which preserves distances within
local neighborhoods. It can be thought of as a series of local Principal Component Analyses which are globally
compared to find the best non-linear embedding.
Locally linear embedding can be performed with function locally_linear_embedding or its object-oriented
counterpart LocallyLinearEmbedding.

Complexity

The standard LLE algorithm comprises three stages:


1. Nearest Neighbors Search. See discussion under Isomap above.
2. Weight Matrix Construction. 𝑂[𝐷𝑁 𝑘 3 ]. The construction of the LLE weight matrix involves the solution of
a 𝑘 × 𝑘 linear equation for each of the 𝑁 local neighborhoods
3. Partial Eigenvalue Decomposition. See discussion under Isomap above.
The overall complexity of standard LLE is 𝑂[𝐷 log(𝑘)𝑁 log(𝑁 )] + 𝑂[𝐷𝑁 𝑘 3 ] + 𝑂[𝑑𝑁 2 ].
• 𝑁 : number of training data points
• 𝐷 : input dimension
• 𝑘 : number of nearest neighbors
• 𝑑 : output dimension

References:

• “Nonlinear dimensionality reduction by locally linear embedding” Roweis, S. & Saul, L. Science 290:2323
(2000)

Modified Locally Linear Embedding

One well-known issue with LLE is the regularization problem. When the number of neighbors is greater than the
number of input dimensions, the matrix defining each local neighborhood is rank-deficient. To address this, standard

3.2. Unsupervised learning 317


scikit-learn user guide, Release 0.20.3

LLE applies an arbitrary regularization parameter 𝑟, which is chosen relative to the trace of the local weight matrix.
Though it can be shown formally that as 𝑟 → 0, the solution converges to the desired embedding, there is no guarantee
that the optimal solution will be found for 𝑟 > 0. This problem manifests itself in embeddings which distort the
underlying geometry of the manifold.
One method to address the regularization problem is to use multiple weight vectors in each neighborhood.
This is the essence of modified locally linear embedding (MLLE). MLLE can be performed with function
locally_linear_embedding or its object-oriented counterpart LocallyLinearEmbedding, with the key-
word method = 'modified'. It requires n_neighbors > n_components.

Complexity

The MLLE algorithm comprises three stages:


1. Nearest Neighbors Search. Same as standard LLE
2. Weight Matrix Construction. Approximately 𝑂[𝐷𝑁 𝑘 3 ]+𝑂[𝑁 (𝑘 −𝐷)𝑘 2 ]. The first term is exactly equivalent
to that of standard LLE. The second term has to do with constructing the weight matrix from multiple weights.
In practice, the added cost of constructing the MLLE weight matrix is relatively small compared to the cost of
steps 1 and 3.
3. Partial Eigenvalue Decomposition. Same as standard LLE
The overall complexity of MLLE is 𝑂[𝐷 log(𝑘)𝑁 log(𝑁 )] + 𝑂[𝐷𝑁 𝑘 3 ] + 𝑂[𝑁 (𝑘 − 𝐷)𝑘 2 ] + 𝑂[𝑑𝑁 2 ].
• 𝑁 : number of training data points
• 𝐷 : input dimension
• 𝑘 : number of nearest neighbors
• 𝑑 : output dimension

References:

• “MLLE: Modified Locally Linear Embedding Using Multiple Weights” Zhang, Z. & Wang, J.

318 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Hessian Eigenmapping

Hessian Eigenmapping (also known as Hessian-based LLE: HLLE) is another method of solving the regularization
problem of LLE. It revolves around a hessian-based quadratic form at each neighborhood which is used to recover
the locally linear structure. Though other implementations note its poor scaling with data size, sklearn imple-
ments some algorithmic improvements which make its cost comparable to that of other LLE variants for small output
dimension. HLLE can be performed with function locally_linear_embedding or its object-oriented counter-
part LocallyLinearEmbedding, with the keyword method = 'hessian'. It requires n_neighbors >
n_components * (n_components + 3) / 2.

Complexity

The HLLE algorithm comprises three stages:


1. Nearest Neighbors Search. Same as standard LLE
2. Weight Matrix Construction. Approximately 𝑂[𝐷𝑁 𝑘 3 ] + 𝑂[𝑁 𝑑6 ]. The first term reflects a similar cost to
that of standard LLE. The second term comes from a QR decomposition of the local hessian estimator.
3. Partial Eigenvalue Decomposition. Same as standard LLE
The overall complexity of standard HLLE is 𝑂[𝐷 log(𝑘)𝑁 log(𝑁 )] + 𝑂[𝐷𝑁 𝑘 3 ] + 𝑂[𝑁 𝑑6 ] + 𝑂[𝑑𝑁 2 ].
• 𝑁 : number of training data points
• 𝐷 : input dimension
• 𝑘 : number of nearest neighbors
• 𝑑 : output dimension

References:

• “Hessian Eigenmaps: Locally linear embedding techniques for high-dimensional data” Donoho, D. &
Grimes, C. Proc Natl Acad Sci USA. 100:5591 (2003)

3.2. Unsupervised learning 319


scikit-learn user guide, Release 0.20.3

Spectral Embedding

Spectral Embedding is an approach to calculating a non-linear embedding. Scikit-learn implements Laplacian Eigen-
maps, which finds a low dimensional representation of the data using a spectral decomposition of the graph Laplacian.
The graph generated can be considered as a discrete approximation of the low dimensional manifold in the high dimen-
sional space. Minimization of a cost function based on the graph ensures that points close to each other on the manifold
are mapped close to each other in the low dimensional space, preserving local distances. Spectral embedding can be
performed with the function spectral_embedding or its object-oriented counterpart SpectralEmbedding.

Complexity

The Spectral Embedding (Laplacian Eigenmaps) algorithm comprises three stages:


1. Weighted Graph Construction. Transform the raw input data into graph representation using affinity (adja-
cency) matrix representation.
2. Graph Laplacian Construction. unnormalized Graph Laplacian is constructed as 𝐿 = 𝐷 − 𝐴 for and normal-
1 1
ized one as 𝐿 = 𝐷− 2 (𝐷 − 𝐴)𝐷− 2 .
3. Partial Eigenvalue Decomposition. Eigenvalue decomposition is done on graph Laplacian
The overall complexity of spectral embedding is 𝑂[𝐷 log(𝑘)𝑁 log(𝑁 )] + 𝑂[𝐷𝑁 𝑘 3 ] + 𝑂[𝑑𝑁 2 ].
• 𝑁 : number of training data points
• 𝐷 : input dimension
• 𝑘 : number of nearest neighbors
• 𝑑 : output dimension

References:

• “Laplacian Eigenmaps for Dimensionality Reduction and Data Representation” M. Belkin, P. Niyogi, Neural
Computation, June 2003; 15 (6):1373-1396

Local Tangent Space Alignment

Though not technically a variant of LLE, Local tangent space alignment (LTSA) is algorithmically similar enough
to LLE that it can be put in this category. Rather than focusing on preserving neighborhood distances as in LLE,
LTSA seeks to characterize the local geometry at each neighborhood via its tangent space, and performs a global
optimization to align these local tangent spaces to learn the embedding. LTSA can be performed with function
locally_linear_embedding or its object-oriented counterpart LocallyLinearEmbedding, with the key-
word method = 'ltsa'.

Complexity

The LTSA algorithm comprises three stages:


1. Nearest Neighbors Search. Same as standard LLE
2. Weight Matrix Construction. Approximately 𝑂[𝐷𝑁 𝑘 3 ] + 𝑂[𝑘 2 𝑑]. The first term reflects a similar cost to that
of standard LLE.
3. Partial Eigenvalue Decomposition. Same as standard LLE

320 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

The overall complexity of standard LTSA is 𝑂[𝐷 log(𝑘)𝑁 log(𝑁 )] + 𝑂[𝐷𝑁 𝑘 3 ] + 𝑂[𝑘 2 𝑑] + 𝑂[𝑑𝑁 2 ].
• 𝑁 : number of training data points
• 𝐷 : input dimension
• 𝑘 : number of nearest neighbors
• 𝑑 : output dimension

References:

• “Principal manifolds and nonlinear dimensionality reduction via tangent space alignment” Zhang, Z. & Zha,
H. Journal of Shanghai Univ. 8:406 (2004)

Multi-dimensional Scaling (MDS)

Multidimensional scaling (MDS) seeks a low-dimensional representation of the data in which the distances respect well
the distances in the original high-dimensional space.
In general, is a technique used for analyzing similarity or dissimilarity data. MDS attempts to model similarity or
dissimilarity data as distances in a geometric spaces. The data can be ratings of similarity between objects, interaction
frequencies of molecules, or trade indices between countries.
There exists two types of MDS algorithm: metric and non metric. In the scikit-learn, the class MDS implements
both. In Metric MDS, the input similarity matrix arises from a metric (and thus respects the triangular inequality), the
distances between output two points are then set to be as close as possible to the similarity or dissimilarity data. In
the non-metric version, the algorithms will try to preserve the order of the distances, and hence seek for a monotonic
relationship between the distances in the embedded space and the similarities/dissimilarities.
Let 𝑆 be the similarity matrix, and 𝑋 the coordinates of the 𝑛 input points. Disparities 𝑑ˆ𝑖𝑗 are transformation of the
similarities chosen in some optimal ways. The objective, called the stress, is then defined by 𝑠𝑢𝑚𝑖<𝑗 𝑑𝑖𝑗 (𝑋) − 𝑑ˆ𝑖𝑗 (𝑋)

Metric MDS

The simplest metric MDS model, called absolute MDS, disparities are defined by 𝑑ˆ𝑖𝑗 = 𝑆𝑖𝑗 . With absolute MDS, the
value 𝑆𝑖𝑗 should then correspond exactly to the distance between point 𝑖 and 𝑗 in the embedding point.

3.2. Unsupervised learning 321


scikit-learn user guide, Release 0.20.3

Most commonly, disparities are set to 𝑑ˆ𝑖𝑗 = 𝑏𝑆𝑖𝑗 .

Nonmetric MDS

Non metric MDS focuses on the ordination of the data. If 𝑆𝑖𝑗 < 𝑆𝑘𝑙 , then the embedding should enforce 𝑑𝑖𝑗 < 𝑑𝑗𝑘 .
A simple algorithm to enforce that is to use a monotonic regression of 𝑑𝑖𝑗 on 𝑆𝑖𝑗 , yielding disparities 𝑑ˆ𝑖𝑗 in the same
order as 𝑆𝑖𝑗 .
A trivial solution to this problem is to set all the points on the origin. In order to avoid that, the disparities 𝑑ˆ𝑖𝑗 are
normalized.

References:

• “Modern Multidimensional Scaling - Theory and Applications” Borg, I.; Groenen P. Springer Series in Statis-
tics (1997)
• “Nonmetric multidimensional scaling: a numerical method” Kruskal, J. Psychometrika, 29 (1964)

322 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

• “Multidimensional scaling by optimizing goodness of fit to a nonmetric hypothesis” Kruskal, J. Psychome-


trika, 29, (1964)

t-distributed Stochastic Neighbor Embedding (t-SNE)

t-SNE (TSNE) converts affinities of data points to probabilities. The affinities in the original space are represented by
Gaussian joint probabilities and the affinities in the embedded space are represented by Student’s t-distributions. This
allows t-SNE to be particularly sensitive to local structure and has a few other advantages over existing techniques:
• Revealing the structure at many scales on a single map
• Revealing data that lie in multiple, different, manifolds or clusters
• Reducing the tendency to crowd points together at the center
While Isomap, LLE and variants are best suited to unfold a single continuous low dimensional manifold, t-SNE will
focus on the local structure of the data and will tend to extract clustered local groups of samples as highlighted on the
S-curve example. This ability to group samples based on the local structure might be beneficial to visually disentangle
a dataset that comprises several manifolds at once as is the case in the digits dataset.
The Kullback-Leibler (KL) divergence of the joint probabilities in the original space and the embedded space will
be minimized by gradient descent. Note that the KL divergence is not convex, i.e. multiple restarts with different
initializations will end up in local minima of the KL divergence. Hence, it is sometimes useful to try different seeds
and select the embedding with the lowest KL divergence.
The disadvantages to using t-SNE are roughly:
• t-SNE is computationally expensive, and can take several hours on million-sample datasets where PCA will
finish in seconds or minutes
• The Barnes-Hut t-SNE method is limited to two or three dimensional embeddings.
• The algorithm is stochastic and multiple restarts with different seeds can yield different embeddings. However,
it is perfectly legitimate to pick the embedding with the least error.
• Global structure is not explicitly preserved. This is problem is mitigated by initializing points with PCA (using
init=’pca’).

3.2. Unsupervised learning 323


scikit-learn user guide, Release 0.20.3

Optimizing t-SNE

The main purpose of t-SNE is visualization of high-dimensional data. Hence, it works best when the data will be
embedded on two or three dimensions.
Optimizing the KL divergence can be a little bit tricky sometimes. There are five parameters that control the optimiza-
tion of t-SNE and therefore possibly the quality of the resulting embedding:
• perplexity
• early exaggeration factor
• learning rate
• maximum number of iterations
• angle (not used in the exact method)
The perplexity is defined as 𝑘 = 2(𝑆) where 𝑆 is the Shannon entropy of the conditional probability distribution.
The perplexity of a 𝑘-sided die is 𝑘, so that 𝑘 is effectively the number of nearest neighbors t-SNE considers when
generating the conditional probabilities. Larger perplexities lead to more nearest neighbors and less sensitive to small
structure. Conversely a lower perplexity considers a smaller number of neighbors, and thus ignores more global
information in favour of the local neighborhood. As dataset sizes get larger more points will be required to get a
reasonable sample of the local neighborhood, and hence larger perplexities may be required. Similarly noisier datasets
will require larger perplexity values to encompass enough local neighbors to see beyond the background noise.
The maximum number of iterations is usually high enough and does not need any tuning. The optimization consists of
two phases: the early exaggeration phase and the final optimization. During early exaggeration the joint probabilities
in the original space will be artificially increased by multiplication with a given factor. Larger factors result in larger
gaps between natural clusters in the data. If the factor is too high, the KL divergence could increase during this phase.
Usually it does not have to be tuned. A critical parameter is the learning rate. If it is too low gradient descent will get
stuck in a bad local minimum. If it is too high the KL divergence will increase during optimization. More tips can be
found in Laurens van der Maaten’s FAQ (see references). The last parameter, angle, is a tradeoff between performance
and accuracy. Larger angles imply that we can approximate larger regions by a single point, leading to better speed
but less accurate results.
“How to Use t-SNE Effectively” provides a good discussion of the effects of the various parameters, as well as
interactive plots to explore the effects of different parameters.

Barnes-Hut t-SNE

The Barnes-Hut t-SNE that has been implemented here is usually much slower than other manifold learning algo-
rithms. The optimization is quite difficult and the computation of the gradient is 𝑂[𝑑𝑁 𝑙𝑜𝑔(𝑁 )], where 𝑑 is the number
of output dimensions and 𝑁 is the number of samples. The Barnes-Hut method improves on the exact method where
t-SNE complexity is 𝑂[𝑑𝑁 2 ], but has several other notable differences:
• The Barnes-Hut implementation only works when the target dimensionality is 3 or less. The 2D case is typical
when building visualizations.
• Barnes-Hut only works with dense input data. Sparse data matrices can only be embedded with the exact method
or can be approximated by a dense low rank projection for instance using sklearn.decomposition.
TruncatedSVD
• Barnes-Hut is an approximation of the exact method. The approximation is parameterized with the angle pa-
rameter, therefore the angle parameter is unused when method=”exact”
• Barnes-Hut is significantly more scalable. Barnes-Hut can be used to embed hundred of thousands of data points
while the exact method can handle thousands of samples before becoming computationally intractable

324 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

For visualization purpose (which is the main use case of t-SNE), using the Barnes-Hut method is strongly recom-
mended. The exact t-SNE method is useful for checking the theoretically properties of the embedding possibly in
higher dimensional space but limit to small datasets due to computational constraints.
Also note that the digits labels roughly match the natural grouping found by t-SNE while the linear 2D projection of
the PCA model yields a representation where label regions largely overlap. This is a strong clue that this data can be
well separated by non linear methods that focus on the local structure (e.g. an SVM with a Gaussian RBF kernel).
However, failing to visualize well separated homogeneously labeled groups with t-SNE in 2D does not necessarily
imply that the data cannot be correctly classified by a supervised model. It might be the case that 2 dimensions are not
low enough to accurately represents the internal structure of the data.

References:

• “Visualizing High-Dimensional Data Using t-SNE” van der Maaten, L.J.P.; Hinton, G. Journal of Machine
Learning Research (2008)
• “t-Distributed Stochastic Neighbor Embedding” van der Maaten, L.J.P.
• “Accelerating t-SNE using Tree-Based Algorithms.” L.J.P. van der Maaten. Journal of Machine Learning
Research 15(Oct):3221-3245, 2014.

Tips on practical use

• Make sure the same scale is used over all features. Because manifold learning methods are based on a nearest-
neighbor search, the algorithm may perform poorly otherwise. See StandardScaler for convenient ways of
scaling heterogeneous data.
• The reconstruction error computed by each routine can be used to choose the optimal output dimension. For a
𝑑-dimensional manifold embedded in a 𝐷-dimensional parameter space, the reconstruction error will decrease
as n_components is increased until n_components == d.
• Note that noisy data can “short-circuit” the manifold, in essence acting as a bridge between parts of the manifold
that would otherwise be well-separated. Manifold learning on noisy and/or incomplete data is an active area of
research.
• Certain input configurations can lead to singular weight matrices, for example when more than two points in the
dataset are identical, or when the data is split into disjointed groups. In this case, solver='arpack' will
fail to find the null space. The easiest way to address this is to use solver='dense' which will work on a
singular matrix, though it may be very slow depending on the number of input points. Alternatively, one can
attempt to understand the source of the singularity: if it is due to disjoint sets, increasing n_neighbors may
help. If it is due to identical points in the dataset, removing these points may help.
See also:
Totally Random Trees Embedding can also be useful to derive non-linear representations of feature space, also it does
not perform dimensionality reduction.

3.2.3 Clustering

Clustering of unlabeled data can be performed with the module sklearn.cluster.


Each clustering algorithm comes in two variants: a class, that implements the fit method to learn the clusters on train
data, and a function, that, given train data, returns an array of integer labels corresponding to the different clusters. For
the class, the labels over the training data can be found in the labels_ attribute.

3.2. Unsupervised learning 325


scikit-learn user guide, Release 0.20.3

Input data

One important thing to note is that the algorithms implemented in this module can take different kinds of matrix as
input. All the methods accept standard data matrices of shape [n_samples, n_features]. These can be ob-
tained from the classes in the sklearn.feature_extraction module. For AffinityPropagation,
SpectralClustering and DBSCAN one can also input similarity matrices of shape [n_samples,
n_samples]. These can be obtained from the functions in the sklearn.metrics.pairwise module.

Overview of clustering methods

Fig. 3.4: A comparison of the clustering algorithms in scikit-learn

326 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Method Parameters Scalability Usecase Geometry (metric


name used)
K-Means number of clus- Very large General-purpose, even clus- Distances between
ters n_samples, ter size, flat geometry, not points
medium too many clusters
n_clusters
with MiniBatch code
Affinity propa- damping, sam- Not scalable with Many clusters, uneven clus- Graph distance (e.g.
gation ple preference n_samples ter size, non-flat geometry nearest-neighbor
graph)
Mean-shift bandwidth Not scalable with Many clusters, uneven clus- Distances between
n_samples ter size, non-flat geometry points
Spectral clus- number of clus- Medium Few clusters, even cluster Graph distance (e.g.
tering ters n_samples, small size, non-flat geometry nearest-neighbor
n_clusters graph)
Ward hi- number of clus- Large n_samples Many clusters, possibly con- Distances between
erarchical ters and n_clusters nectivity constraints points
clustering
Agglomerative number of clus- Large n_samples Many clusters, possibly con- Any pairwise distance
clustering ters, linkage and n_clusters nectivity constraints, non
type, distance Euclidean distances
DBSCAN neighborhood Very large Non-flat geometry, uneven Distances between
size n_samples, cluster sizes nearest points
medium
n_clusters
Gaussian mix- many Not scalable Flat geometry, good for den- Mahalanobis dis-
tures sity estimation tances to centers
Birch branching fac- Large Large dataset, outlier re- Euclidean distance
tor, threshold, n_clusters moval, data reduction. between points
optional global and n_samples
clusterer.

Non-flat geometry clustering is useful when the clusters have a specific shape, i.e. a non-flat manifold, and the standard
euclidean distance is not the right metric. This case arises in the two top rows of the figure above.
Gaussian mixture models, useful for clustering, are described in another chapter of the documentation dedicated
to mixture models. KMeans can be seen as a special case of Gaussian mixture model with equal covariance per
component.

K-means

The KMeans algorithm clusters data by trying to separate samples in n groups of equal variance, minimizing a criterion
known as the inertia or within-cluster sum-of-squares. This algorithm requires the number of clusters to be specified.
It scales well to large number of samples and has been used across a large range of application areas in many different
fields.
The k-means algorithm divides a set of 𝑁 samples 𝑋 into 𝐾 disjoint clusters 𝐶, each described by the mean 𝜇𝑗 of
the samples in the cluster. The means are commonly called the cluster “centroids”; note that they are not, in general,
points from 𝑋, although they live in the same space. The K-means algorithm aims to choose centroids that minimise
the inertia, or within-cluster sum of squared criterion:
𝑛
∑︁
min (||𝑥𝑖 − 𝜇𝑗 ||2 )
𝜇𝑗 ∈𝐶
𝑖=0

3.2. Unsupervised learning 327


scikit-learn user guide, Release 0.20.3

Inertia, or the within-cluster sum of squares criterion, can be recognized as a measure of how internally coherent
clusters are. It suffers from various drawbacks:
• Inertia makes the assumption that clusters are convex and isotropic, which is not always the case. It responds
poorly to elongated clusters, or manifolds with irregular shapes.
• Inertia is not a normalized metric: we just know that lower values are better and zero is optimal. But in very
high-dimensional spaces, Euclidean distances tend to become inflated (this is an instance of the so-called “curse
of dimensionality”). Running a dimensionality reduction algorithm such as PCA prior to k-means clustering
can alleviate this problem and speed up the computations.

K-
means is often referred to as Lloyd’s algorithm. In basic terms, the algorithm has three steps. The first step chooses
the initial centroids, with the most basic method being to choose 𝑘 samples from the dataset 𝑋. After initialization,
K-means consists of looping between the two other steps. The first step assigns each sample to its nearest centroid.
The second step creates new centroids by taking the mean value of all of the samples assigned to each previous
centroid. The difference between the old and the new centroids are computed and the algorithm repeats these last two
steps until this value is less than a threshold. In other words, it repeats until the centroids do not move significantly.

328 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

K-means is equivalent to the expectation-maximization algorithm with a


small, all-equal, diagonal covariance matrix.
The algorithm can also be understood through the concept of Voronoi diagrams. First the Voronoi diagram of the points
is calculated using the current centroids. Each segment in the Voronoi diagram becomes a separate cluster. Secondly,
the centroids are updated to the mean of each segment. The algorithm then repeats this until a stopping criterion is
fulfilled. Usually, the algorithm stops when the relative decrease in the objective function between iterations is less
than the given tolerance value. This is not the case in this implementation: iteration stops when centroids move less
than the tolerance.
Given enough time, K-means will always converge, however this may be to a local minimum. This is highly depen-
dent on the initialization of the centroids. As a result, the computation is often done several times, with different
initializations of the centroids. One method to help address this issue is the k-means++ initialization scheme, which
has been implemented in scikit-learn (use the init='k-means++' parameter). This initializes the centroids to
be (generally) distant from each other, leading to provably better results than random initialization, as shown in the
reference.
The algorithm supports sample weights, which can be given by a parameter sample_weight. This allows to assign
more weight to some samples when computing cluster centers and values of inertia. For example, assigning a weight
of 2 to a sample is equivalent to adding a duplicate of that sample to the dataset 𝑋.
A parameter can be given to allow K-means to be run in parallel, called n_jobs. Giving this parameter a positive
value uses that many processors (default: 1). A value of -1 uses all available processors, with -2 using one less, and so
on. Parallelization generally speeds up computation at the cost of memory (in this case, multiple copies of centroids
need to be stored, one for each job).

Warning: The parallel version of K-Means is broken on OS X when numpy uses the Accelerate Framework. This
is expected behavior: Accelerate can be called after a fork but you need to execv the subprocess with the Python
binary (which multiprocessing does not do under posix).

K-means can be used for vector quantization. This is achieved using the transform method of a trained model of
KMeans.

Examples:

• Demonstration of k-means assumptions: Demonstrating when k-means performs intuitively and when it does
not
• A demo of K-Means clustering on the handwritten digits data: Clustering handwritten digits

References:

• “k-means++: The advantages of careful seeding” Arthur, David, and Sergei Vassilvitskii, Proceedings of

3.2. Unsupervised learning 329


scikit-learn user guide, Release 0.20.3

the eighteenth annual ACM-SIAM symposium on Discrete algorithms, Society for Industrial and Applied
Mathematics (2007)

Mini Batch K-Means

The MiniBatchKMeans is a variant of the KMeans algorithm which uses mini-batches to reduce the computation
time, while still attempting to optimise the same objective function. Mini-batches are subsets of the input data, ran-
domly sampled in each training iteration. These mini-batches drastically reduce the amount of computation required
to converge to a local solution. In contrast to other algorithms that reduce the convergence time of k-means, mini-batch
k-means produces results that are generally only slightly worse than the standard algorithm.
The algorithm iterates between two major steps, similar to vanilla k-means. In the first step, 𝑏 samples are drawn
randomly from the dataset, to form a mini-batch. These are then assigned to the nearest centroid. In the second step,
the centroids are updated. In contrast to k-means, this is done on a per-sample basis. For each sample in the mini-batch,
the assigned centroid is updated by taking the streaming average of the sample and all previous samples assigned to
that centroid. This has the effect of decreasing the rate of change for a centroid over time. These steps are performed
until convergence or a predetermined number of iterations is reached.
MiniBatchKMeans converges faster than KMeans, but the quality of the results is reduced. In practice this differ-
ence in quality can be quite small, as shown in the example and cited reference.

Examples:

• Comparison of the K-Means and MiniBatchKMeans clustering algorithms: Comparison of KMeans and
MiniBatchKMeans
• Clustering text documents using k-means: Document clustering using sparse MiniBatchKMeans
• Online learning of a dictionary of parts of faces

References:

• “Web Scale K-Means clustering” D. Sculley, Proceedings of the 19th international conference on World wide
web (2010)

330 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Affinity Propagation

AffinityPropagation creates clusters by sending messages between pairs of samples until convergence. A
dataset is then described using a small number of exemplars, which are identified as those most representative of other
samples. The messages sent between pairs represent the suitability for one sample to be the exemplar of the other,
which is updated in response to the values from other pairs. This updating happens iteratively until convergence, at
which point the final exemplars are chosen, and hence the final clustering is given.

Affinity Propagation can be interesting as it chooses the number of clusters based on the data provided. For this pur-
pose, the two important parameters are the preference, which controls how many exemplars are used, and the damping
factor which damps the responsibility and availability messages to avoid numerical oscillations when updating these
messages.
The main drawback of Affinity Propagation is its complexity. The algorithm has a time complexity of the order
𝑂(𝑁 2 𝑇 ), where 𝑁 is the number of samples and 𝑇 is the number of iterations until convergence. Further, the memory
complexity is of the order 𝑂(𝑁 2 ) if a dense similarity matrix is used, but reducible if a sparse similarity matrix is
used. This makes Affinity Propagation most appropriate for small to medium sized datasets.

Examples:

• Demo of affinity propagation clustering algorithm: Affinity Propagation on a synthetic 2D datasets with 3
classes.
• Visualizing the stock market structure Affinity Propagation on Financial time series to find groups of compa-
nies

Algorithm description: The messages sent between points belong to one of two categories. The first is the responsi-
bility 𝑟(𝑖, 𝑘), which is the accumulated evidence that sample 𝑘 should be the exemplar for sample 𝑖. The second is the
availability 𝑎(𝑖, 𝑘) which is the accumulated evidence that sample 𝑖 should choose sample 𝑘 to be its exemplar, and
considers the values for all other samples that 𝑘 should be an exemplar. In this way, exemplars are chosen by samples
if they are (1) similar enough to many samples and (2) chosen by many samples to be representative of themselves.
More formally, the responsibility of a sample 𝑘 to be the exemplar of sample 𝑖 is given by:

𝑟(𝑖, 𝑘) ← 𝑠(𝑖, 𝑘) − 𝑚𝑎𝑥[𝑎(𝑖, 𝑘 ′ ) + 𝑠(𝑖, 𝑘 ′ )∀𝑘 ′ ̸= 𝑘]

Where 𝑠(𝑖, 𝑘) is the similarity between samples 𝑖 and 𝑘. The availability of sample 𝑘 to be the exemplar of sample 𝑖 is

3.2. Unsupervised learning 331


scikit-learn user guide, Release 0.20.3

given by:
∑︁
𝑎(𝑖, 𝑘) ← 𝑚𝑖𝑛[0, 𝑟(𝑘, 𝑘) + 𝑟(𝑖′ , 𝑘)]
𝑖′ 𝑠.𝑡. 𝑖′ ∈{𝑖,𝑘}
/

To begin with, all values for 𝑟 and 𝑎 are set to zero, and the calculation of each iterates until convergence. As discussed
above, in order to avoid numerical oscillations when updating the messages, the damping factor 𝜆 is introduced to
iteration process:

𝑟𝑡+1 (𝑖, 𝑘) = 𝜆 · 𝑟𝑡 (𝑖, 𝑘) + (1 − 𝜆) · 𝑟𝑡+1 (𝑖, 𝑘)

𝑎𝑡+1 (𝑖, 𝑘) = 𝜆 · 𝑎𝑡 (𝑖, 𝑘) + (1 − 𝜆) · 𝑎𝑡+1 (𝑖, 𝑘)


where 𝑡 indicates the iteration times.

Mean Shift

MeanShift clustering aims to discover blobs in a smooth density of samples. It is a centroid based algorithm, which
works by updating candidates for centroids to be the mean of the points within a given region. These candidates are
then filtered in a post-processing stage to eliminate near-duplicates to form the final set of centroids.
Given a candidate centroid 𝑥𝑖 for iteration 𝑡, the candidate is updated according to the following equation:

𝑥𝑡+1
𝑖 = 𝑚(𝑥𝑡𝑖 )

Where 𝑁 (𝑥𝑖 ) is the neighborhood of samples within a given distance around 𝑥𝑖 and 𝑚 is the mean shift vector that
is computed for each centroid that points towards a region of the maximum increase in the density of points. This
is computed using the following equation, effectively updating a centroid to be the mean of the samples within its
neighborhood:
∑︀
𝑥 ∈𝑁 (𝑥𝑖 ) 𝐾(𝑥𝑗 − 𝑥𝑖 )𝑥𝑗
𝑚(𝑥𝑖 ) = ∑︀𝑗
𝑥𝑗 ∈𝑁 (𝑥𝑖 ) 𝐾(𝑥𝑗 − 𝑥𝑖 )

The algorithm automatically sets the number of clusters, instead of relying on a parameter bandwidth, which dictates
the size of the region to search through. This parameter can be set manually, but can be estimated using the provided
estimate_bandwidth function, which is called if the bandwidth is not set.
The algorithm is not highly scalable, as it requires multiple nearest neighbor searches during the execution of the
algorithm. The algorithm is guaranteed to converge, however the algorithm will stop iterating when the change in
centroids is small.
Labelling a new sample is performed by finding the nearest centroid for a given sample.

Examples:

• A demo of the mean-shift clustering algorithm: Mean Shift clustering on a synthetic 2D datasets with 3
classes.

References:

• “Mean shift: A robust approach toward feature space analysis.” D. Comaniciu and P. Meer, IEEE Transactions
on Pattern Analysis and Machine Intelligence (2002)

332 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Spectral clustering

SpectralClustering does a low-dimension embedding of the affinity matrix between samples, followed by a
KMeans in the low dimensional space. It is especially efficient if the affinity matrix is sparse and the pyamg module
is installed. SpectralClustering requires the number of clusters to be specified. It works well for a small number of
clusters but is not advised when using many clusters.
For two clusters, it solves a convex relaxation of the normalised cuts problem on the similarity graph: cutting the
graph in two so that the weight of the edges cut is small compared to the weights of the edges inside each cluster. This
criteria is especially interesting when working on images: graph vertices are pixels, and edges of the similarity graph
are a function of the gradient of the image.

Warning: Transforming distance to well-behaved similarities


Note that if the values of your similarity matrix are not well distributed, e.g. with negative values or with a distance
matrix rather than a similarity, the spectral problem will be singular and the problem not solvable. In which case
it is advised to apply a transformation to the entries of the matrix. For instance, in the case of a signed distance
matrix, is common to apply a heat kernel:
similarity = np.exp(-beta * distance / distance.std())

See the examples for such an application.

3.2. Unsupervised learning 333


scikit-learn user guide, Release 0.20.3

Examples:

• Spectral clustering for image segmentation: Segmenting objects from a noisy background using spectral
clustering.
• Segmenting the picture of greek coins in regions: Spectral clustering to split the image of coins in regions.

Different label assignment strategies

Different label assignment strategies can be used, corresponding to the assign_labels parameter of
SpectralClustering. The "kmeans" strategy can match finer details of the data, but it can be more unsta-
ble. In particular, unless you control the random_state, it may not be reproducible from run-to-run, as it depends
on a random initialization. On the other hand, the "discretize" strategy is 100% reproducible, but it tends to
create parcels of fairly even and geometrical shape.

assign_labels="kmeans" assign_labels="discretize"

Spectral Clustering Graphs

Spectral Clustering can also be used to cluster graphs by their spectral embeddings. In this case, the affinity matrix is
the adjacency matrix of the graph, and SpectralClustering is initialized with affinity=’precomputed’:

>>> from sklearn.cluster import SpectralClustering


>>> sc = SpectralClustering(3, affinity='precomputed', n_init=100,
... assign_labels='discretize')
>>> sc.fit_predict(adjacency_matrix)

References:

• “A Tutorial on Spectral Clustering” Ulrike von Luxburg, 2007

334 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

• “Normalized cuts and image segmentation” Jianbo Shi, Jitendra Malik, 2000
• “A Random Walks View of Spectral Segmentation” Marina Meila, Jianbo Shi, 2001
• “On Spectral Clustering: Analysis and an algorithm” Andrew Y. Ng, Michael I. Jordan, Yair Weiss, 2001

Hierarchical clustering

Hierarchical clustering is a general family of clustering algorithms that build nested clusters by merging or splitting
them successively. This hierarchy of clusters is represented as a tree (or dendrogram). The root of the tree is the unique
cluster that gathers all the samples, the leaves being the clusters with only one sample. See the Wikipedia page for
more details.
The AgglomerativeClustering object performs a hierarchical clustering using a bottom up approach: each
observation starts in its own cluster, and clusters are successively merged together. The linkage criteria determines the
metric used for the merge strategy:
• Ward minimizes the sum of squared differences within all clusters. It is a variance-minimizing approach and in
this sense is similar to the k-means objective function but tackled with an agglomerative hierarchical approach.
• Maximum or complete linkage minimizes the maximum distance between observations of pairs of clusters.
• Average linkage minimizes the average of the distances between all observations of pairs of clusters.
• Single linkage minimizes the distance between the closest observations of pairs of clusters.
AgglomerativeClustering can also scale to large number of samples when it is used jointly with a connectivity
matrix, but is computationally expensive when no connectivity constraints are added between samples: it considers at
each step all the possible merges.

FeatureAgglomeration

The FeatureAgglomeration uses agglomerative clustering to group together features that look very similar,
thus decreasing the number of features. It is a dimensionality reduction tool, see Unsupervised dimensionality
reduction.

Different linkage type: Ward, complete, average, and single linkage

AgglomerativeClustering supports Ward, single, average, and complete linkage strategies.

3.2. Unsupervised learning 335


scikit-learn user guide, Release 0.20.3

Ag-
glomerative cluster has a “rich get richer” behavior that leads to uneven cluster sizes. In this regard, single linkage is
the worst strategy, and Ward gives the most regular sizes. However, the affinity (or distance used in clustering) cannot
be varied with Ward, thus for non Euclidean metrics, average linkage is a good alternative. Single linkage, while not
robust to noisy data, can be computed very efficiently and can therefore be useful to provide hierarchical clustering of
larger datasets. Single linkage can also perform well on non-globular data.

Examples:

• Various Agglomerative Clustering on a 2D embedding of digits: exploration of the different linkage strategies
in a real dataset.

336 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Adding connectivity constraints

An interesting aspect of AgglomerativeClustering is that connectivity constraints can be added to this al-
gorithm (only adjacent clusters can be merged together), through a connectivity matrix that defines for each sample
the neighboring samples following a given structure of the data. For instance, in the swiss-roll example below, the
connectivity constraints forbid the merging of points that are not adjacent on the swiss roll, and thus avoid forming
clusters that extend across overlapping folds of the roll.

These constraint are useful to impose a certain local structure, but they also make the algorithm faster, especially when
the number of the samples is high.
The connectivity constraints are imposed via an connectivity matrix: a scipy sparse matrix that has elements only
at the intersection of a row and a column with indices of the dataset that should be connected. This matrix can
be constructed from a-priori information: for instance, you may wish to cluster web pages by only merging pages
with a link pointing from one to another. It can also be learned from the data, for instance using sklearn.
neighbors.kneighbors_graph to restrict merging to nearest neighbors as in this example, or using sklearn.
feature_extraction.image.grid_to_graph to enable only merging of neighboring pixels on an image,
as in the coin example.

Examples:

• A demo of structured Ward hierarchical clustering on an image of coins: Ward clustering to split the image
of coins in regions.
• Hierarchical clustering: structured vs unstructured ward: Example of Ward algorithm on a swiss-roll, com-
parison of structured approaches versus unstructured approaches.
• Feature agglomeration vs. univariate selection: Example of dimensionality reduction with feature agglomer-
ation based on Ward hierarchical clustering.
• Agglomerative clustering with and without structure

Warning: Connectivity constraints with single, average and complete linkage


Connectivity constraints and single, complete or average linkage can enhance the ‘rich getting richer’ aspect of
agglomerative clustering, particularly so if they are built with sklearn.neighbors.kneighbors_graph.
In the limit of a small number of clusters, they tend to give a few macroscopically occupied clusters and almost
empty ones. (see the discussion in Agglomerative clustering with and without structure). Single linkage is the
most brittle linkage option with regard to this issue.

3.2. Unsupervised learning 337


scikit-learn user guide, Release 0.20.3

Varying the metric

Single, average and complete linkage can be used with a variety of distances (or affinities), in particular Euclidean
distance (l2), Manhattan distance (or Cityblock, or l1), cosine distance, or any precomputed affinity matrix.
• l1 distance is often good for sparse features, or sparse noise: i.e. many of the features are zero, as in text mining
using occurrences of rare words.
• cosine distance is interesting because it is invariant to global scalings of the signal.
The guidelines for choosing a metric is to use one that maximizes the dis-
tance between samples in different classes, and minimizes that within each class.

Examples:

• Agglomerative clustering with different metrics

DBSCAN

The DBSCAN algorithm views clusters as areas of high density separated by areas of low density. Due to this rather
generic view, clusters found by DBSCAN can be any shape, as opposed to k-means which assumes that clusters are
convex shaped. The central component to the DBSCAN is the concept of core samples, which are samples that are in
areas of high density. A cluster is therefore a set of core samples, each close to each other (measured by some distance
measure) and a set of non-core samples that are close to a core sample (but are not themselves core samples). There
are two parameters to the algorithm, min_samples and eps, which define formally what we mean when we say
dense. Higher min_samples or lower eps indicate higher density necessary to form a cluster.
More formally, we define a core sample as being a sample in the dataset such that there exist min_samples other
samples within a distance of eps, which are defined as neighbors of the core sample. This tells us that the core sample
is in a dense area of the vector space. A cluster is a set of core samples that can be built by recursively taking a core
sample, finding all of its neighbors that are core samples, finding all of their neighbors that are core samples, and so
on. A cluster also has a set of non-core samples, which are samples that are neighbors of a core sample in the cluster
but are not themselves core samples. Intuitively, these samples are on the fringes of a cluster.

338 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Any core sample is part of a cluster, by definition. Any sample that is not a core sample, and is at least eps in distance
from any core sample, is considered an outlier by the algorithm.
In the figure below, the color indicates cluster membership, with large circles indicating core samples found by the
algorithm. Smaller circles are non-core samples that are still part of a cluster. Moreover, the outliers are indicated by
black points below.

Examples:

• Demo of DBSCAN clustering algorithm

Implementation

The DBSCAN algorithm is deterministic, always generating the same clusters when given the same data in the
same order. However, the results can differ when data is provided in a different order. First, even though the core
samples will always be assigned to the same clusters, the labels of those clusters will depend on the order in which
those samples are encountered in the data. Second and more importantly, the clusters to which non-core samples
are assigned can differ depending on the data order. This would happen when a non-core sample has a distance
lower than eps to two core samples in different clusters. By the triangular inequality, those two core samples must
be more distant than eps from each other, or they would be in the same cluster. The non-core sample is assigned
to whichever cluster is generated first in a pass through the data, and so the results will depend on the data ordering.
The current implementation uses ball trees and kd-trees to determine the neighborhood of points, which avoids
calculating the full distance matrix (as was done in scikit-learn versions before 0.14). The possibility to use custom
metrics is retained; for details, see NearestNeighbors.

Memory consumption for large sample sizes

This implementation is by default not memory efficient because it constructs a full pairwise similarity matrix in the
case where kd-trees or ball-trees cannot be used (e.g. with sparse matrices). This matrix will consume n^2 floats.
A couple of mechanisms for getting around this are:
• A sparse radius neighborhood graph (where missing entries are presumed to be out of eps) can be precom-
puted in a memory-efficient way and dbscan can be run over this with metric='precomputed'. See
sklearn.neighbors.NearestNeighbors.radius_neighbors_graph.

3.2. Unsupervised learning 339


scikit-learn user guide, Release 0.20.3

• The dataset can be compressed, either by removing exact duplicates if these occur in your data, or by using
BIRCH. Then you only have a relatively small number of representatives for a large number of points. You
can then provide a sample_weight when fitting DBSCAN.

References:

• “A Density-Based Algorithm for Discovering Clusters in Large Spatial Databases with Noise” Ester, M., H. P.
Kriegel, J. Sander, and X. Xu, In Proceedings of the 2nd International Conference on Knowledge Discovery
and Data Mining, Portland, OR, AAAI Press, pp. 226–231. 1996

Birch

The Birch builds a tree called the Characteristic Feature Tree (CFT) for the given data. The data is essentially lossy
compressed to a set of Characteristic Feature nodes (CF Nodes). The CF Nodes have a number of subclusters called
Characteristic Feature subclusters (CF Subclusters) and these CF Subclusters located in the non-terminal CF Nodes
can have CF Nodes as children.
The CF Subclusters hold the necessary information for clustering which prevents the need to hold the entire input data
in memory. This information includes:
• Number of samples in a subcluster.
• Linear Sum - A n-dimensional vector holding the sum of all samples
• Squared Sum - Sum of the squared L2 norm of all samples.
• Centroids - To avoid recalculation linear sum / n_samples.
• Squared norm of the centroids.
The Birch algorithm has two parameters, the threshold and the branching factor. The branching factor limits the
number of subclusters in a node and the threshold limits the distance between the entering sample and the existing
subclusters.
This algorithm can be viewed as an instance or data reduction method, since it reduces the input data to a set of
subclusters which are obtained directly from the leaves of the CFT. This reduced data can be further processed by
feeding it into a global clusterer. This global clusterer can be set by n_clusters. If n_clusters is set to None,
the subclusters from the leaves are directly read off, otherwise a global clustering step labels these subclusters into
global clusters (labels) and the samples are mapped to the global label of the nearest subcluster.
Algorithm description:
• A new sample is inserted into the root of the CF Tree which is a CF Node. It is then merged with the subcluster of
the root, that has the smallest radius after merging, constrained by the threshold and branching factor conditions.
If the subcluster has any child node, then this is done repeatedly till it reaches a leaf. After finding the nearest
subcluster in the leaf, the properties of this subcluster and the parent subclusters are recursively updated.
• If the radius of the subcluster obtained by merging the new sample and the nearest subcluster is greater than
the square of the threshold and if the number of subclusters is greater than the branching factor, then a space is
temporarily allocated to this new sample. The two farthest subclusters are taken and the subclusters are divided
into two groups on the basis of the distance between these subclusters.
• If this split node has a parent subcluster and there is room for a new subcluster, then the parent is split into two.
If there is no room, then this node is again split into two and the process is continued recursively, till it reaches
the root.
Birch or MiniBatchKMeans?

340 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

• Birch does not scale very well to high dimensional data. As a rule of thumb if n_features is greater than
twenty, it is generally better to use MiniBatchKMeans.
• If the number of instances of data needs to be reduced, or if one wants a large number of subclusters either as a
preprocessing step or otherwise, Birch is more useful than MiniBatchKMeans.
How to use partial_fit?
To avoid the computation of global clustering, for every call of partial_fit the user is advised
1. To set n_clusters=None initially
2. Train all data by multiple calls to partial_fit.
3. Set n_clusters to a required value using brc.set_params(n_clusters=n_clusters).
4. Call partial_fit finally with no arguments, i.e. brc.partial_fit() which performs the global clus-
tering.

References:

• Tian Zhang, Raghu Ramakrishnan, Maron Livny BIRCH: An efficient data clustering method for large
databases. http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf
• Roberto Perdisci JBirch - Java implementation of BIRCH clustering algorithm https://code.google.com/
archive/p/jbirch

Clustering performance evaluation

Evaluating the performance of a clustering algorithm is not as trivial as counting the number of errors or the precision
and recall of a supervised classification algorithm. In particular any evaluation metric should not take the absolute
values of the cluster labels into account but rather if this clustering define separations of the data similar to some
ground truth set of classes or satisfying some assumption such that members belong to the same class are more similar
that members of different classes according to some similarity metric.

Adjusted Rand index

Given the knowledge of the ground truth class assignments labels_true and our clustering algorithm assignments
of the same samples labels_pred, the adjusted Rand index is a function that measures the similarity of the two
assignments, ignoring permutations and with chance normalization:

3.2. Unsupervised learning 341


scikit-learn user guide, Release 0.20.3

>>> from sklearn import metrics


>>> labels_true = [0, 0, 0, 1, 1, 1]
>>> labels_pred = [0, 0, 1, 1, 2, 2]

>>> metrics.adjusted_rand_score(labels_true, labels_pred)


0.24...

One can permute 0 and 1 in the predicted labels, rename 2 to 3, and get the same score:

>>> labels_pred = [1, 1, 0, 0, 3, 3]


>>> metrics.adjusted_rand_score(labels_true, labels_pred)
0.24...

Furthermore, adjusted_rand_score is symmetric: swapping the argument does not change the score. It can
thus be used as a consensus measure:

>>> metrics.adjusted_rand_score(labels_pred, labels_true)


0.24...

Perfect labeling is scored 1.0:

>>> labels_pred = labels_true[:]


>>> metrics.adjusted_rand_score(labels_true, labels_pred)
1.0

Bad (e.g. independent labelings) have negative or close to 0.0 scores:

>>> labels_true = [0, 1, 2, 0, 3, 4, 5, 1]


>>> labels_pred = [1, 1, 0, 0, 2, 2, 2, 2]
>>> metrics.adjusted_rand_score(labels_true, labels_pred)
-0.12...

Advantages

• Random (uniform) label assignments have a ARI score close to 0.0 for any value of n_clusters and
n_samples (which is not the case for raw Rand index or the V-measure for instance).
• Bounded range [-1, 1]: negative values are bad (independent labelings), similar clusterings have a positive ARI,
1.0 is the perfect match score.
• No assumption is made on the cluster structure: can be used to compare clustering algorithms such as k-
means which assumes isotropic blob shapes with results of spectral clustering algorithms which can find cluster
with “folded” shapes.

Drawbacks

• Contrary to inertia, ARI requires knowledge of the ground truth classes while is almost never available in
practice or requires manual assignment by human annotators (as in the supervised learning setting).
However ARI can also be useful in a purely unsupervised setting as a building block for a Consensus Index that
can be used for clustering model selection (TODO).

342 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Examples:

• Adjustment for chance in clustering performance evaluation: Analysis of the impact of the dataset size on the
value of clustering measures for random assignments.

Mathematical formulation

If C is a ground truth class assignment and K the clustering, let us define 𝑎 and 𝑏 as:
• 𝑎, the number of pairs of elements that are in the same set in C and in the same set in K
• 𝑏, the number of pairs of elements that are in different sets in C and in different sets in K
The raw (unadjusted) Rand index is then given by:
𝑎+𝑏
RI = 𝑛
𝐶2 𝑠𝑎𝑚𝑝𝑙𝑒𝑠
𝑛
Where 𝐶2 𝑠𝑎𝑚𝑝𝑙𝑒𝑠 is the total number of possible pairs in the dataset (without ordering).
However the RI score does not guarantee that random label assignments will get a value close to zero (esp. if the
number of clusters is in the same order of magnitude as the number of samples).
To counter this effect we can discount the expected RI 𝐸[RI] of random labelings by defining the adjusted Rand index
as follows:
RI − 𝐸[RI]
ARI =
max(RI) − 𝐸[RI]

References

• Comparing Partitions L. Hubert and P. Arabie, Journal of Classification 1985


• Wikipedia entry for the adjusted Rand index

Mutual Information based scores

Given the knowledge of the ground truth class assignments labels_true and our clustering algorithm assignments
of the same samples labels_pred, the Mutual Information is a function that measures the agreement of the two
assignments, ignoring permutations. Two different normalized versions of this measure are available, Normalized
Mutual Information (NMI) and Adjusted Mutual Information (AMI). NMI is often used in the literature, while
AMI was proposed more recently and is normalized against chance:
>>> from sklearn import metrics
>>> labels_true = [0, 0, 0, 1, 1, 1]
>>> labels_pred = [0, 0, 1, 1, 2, 2]

>>> metrics.adjusted_mutual_info_score(labels_true, labels_pred)


0.22504...

One can permute 0 and 1 in the predicted labels, rename 2 to 3 and get the same score:
>>> labels_pred = [1, 1, 0, 0, 3, 3]
>>> metrics.adjusted_mutual_info_score(labels_true, labels_pred)
0.22504...

3.2. Unsupervised learning 343


scikit-learn user guide, Release 0.20.3

All, mutual_info_score, adjusted_mutual_info_score and normalized_mutual_info_score


are symmetric: swapping the argument does not change the score. Thus they can be used as a consensus measure:

>>> metrics.adjusted_mutual_info_score(labels_pred, labels_true)


0.22504...

Perfect labeling is scored 1.0:

>>> labels_pred = labels_true[:]


>>> metrics.adjusted_mutual_info_score(labels_true, labels_pred)
1.0

>>> metrics.normalized_mutual_info_score(labels_true, labels_pred)


1.0

This is not true for mutual_info_score, which is therefore harder to judge:

>>> metrics.mutual_info_score(labels_true, labels_pred)


0.69...

Bad (e.g. independent labelings) have non-positive scores:

>>> labels_true = [0, 1, 2, 0, 3, 4, 5, 1]


>>> labels_pred = [1, 1, 0, 0, 2, 2, 2, 2]
>>> metrics.adjusted_mutual_info_score(labels_true, labels_pred)
-0.10526...

Advantages

• Random (uniform) label assignments have a AMI score close to 0.0 for any value of n_clusters and
n_samples (which is not the case for raw Mutual Information or the V-measure for instance).
• Upper bound of 1: Values close to zero indicate two label assignments that are largely independent, while
values close to one indicate significant agreement. Further, an AMI of exactly 1 indicates that the two label
assignments are equal (with or without permutation).

Drawbacks

• Contrary to inertia, MI-based measures require the knowledge of the ground truth classes while almost
never available in practice or requires manual assignment by human annotators (as in the supervised learning
setting).
However MI-based measures can also be useful in purely unsupervised setting as a building block for a Consen-
sus Index that can be used for clustering model selection.
• NMI and MI are not adjusted against chance.

Examples:

• Adjustment for chance in clustering performance evaluation: Analysis of the impact of the dataset size on the
value of clustering measures for random assignments. This example also includes the Adjusted Rand Index.

344 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Mathematical formulation

Assume two label assignments (of the same N objects), 𝑈 and 𝑉 . Their entropy is the amount of uncertainty for a
partition set, defined by:
|𝑈 |
∑︁
𝐻(𝑈 ) = − 𝑃 (𝑖) log(𝑃 (𝑖))
𝑖=1

where 𝑃 (𝑖) = |𝑈𝑖 |/𝑁 is the probability that an object picked at random from 𝑈 falls into class 𝑈𝑖 . Likewise for 𝑉 :
|𝑉 |
∑︁
𝐻(𝑉 ) = − 𝑃 ′ (𝑗) log(𝑃 ′ (𝑗))
𝑗=1

With 𝑃 ′ (𝑗) = |𝑉𝑗 |/𝑁 . The mutual information (MI) between 𝑈 and 𝑉 is calculated by:
|𝑈 | |𝑉 | (︂ )︂
∑︁ ∑︁ 𝑃 (𝑖, 𝑗)
MI(𝑈, 𝑉 ) = 𝑃 (𝑖, 𝑗) log
𝑖=1 𝑗=1
𝑃 (𝑖)𝑃 ′ (𝑗)

where 𝑃 (𝑖, 𝑗) = |𝑈𝑖 ∩ 𝑉𝑗 |/𝑁 is the probability that an object picked at random falls into both classes 𝑈𝑖 and 𝑉𝑗 .
It also can be expressed in set cardinality formulation:
|𝑈 | |𝑉 | (︂ )︂
∑︁ ∑︁ |𝑈𝑖 ∩ 𝑉𝑗 | 𝑁 |𝑈𝑖 ∩ 𝑉𝑗 |
MI(𝑈, 𝑉 ) = log
𝑖=1 𝑗=1
𝑁 |𝑈𝑖 ||𝑉𝑗 |

The normalized mutual information is defined as


MI(𝑈, 𝑉 )
NMI(𝑈, 𝑉 ) =
mean(𝐻(𝑈 ), 𝐻(𝑉 ))
This value of the mutual information and also the normalized variant is not adjusted for chance and will tend to increase
as the number of different labels (clusters) increases, regardless of the actual amount of “mutual information” between
the label assignments.
The expected value for the mutual information can be calculated using the following equation [VEB2009]. In this
equation, 𝑎𝑖 = |𝑈𝑖 | (the number of elements in 𝑈𝑖 ) and 𝑏𝑗 = |𝑉𝑗 | (the number of elements in 𝑉𝑗 ).
|𝑈 | |𝑉 | min(𝑎𝑖 ,𝑏𝑗 ) (︂ )︂
∑︁ ∑︁ ∑︁ 𝑛𝑖𝑗 𝑁.𝑛𝑖𝑗 𝑎𝑖 !𝑏𝑗 !(𝑁 − 𝑎𝑖 )!(𝑁 − 𝑏𝑗 )!
𝐸[MI(𝑈, 𝑉 )] = log
𝑖=1 𝑗=1 𝑛𝑖𝑗 =(𝑎𝑖 +𝑏𝑗 −𝑁 )+
𝑁 𝑎𝑖 𝑏𝑗 𝑁 !𝑛𝑖𝑗 !(𝑎𝑖 − 𝑛𝑖𝑗 )!(𝑏𝑗 − 𝑛𝑖𝑗 )!(𝑁 − 𝑎𝑖 − 𝑏𝑗 + 𝑛𝑖𝑗 )!

Using the expected value, the adjusted mutual information can then be calculated using a similar form to that of the
adjusted Rand index:
MI − 𝐸[MI]
AMI =
mean(𝐻(𝑈 ), 𝐻(𝑉 )) − 𝐸[MI]
For normalized mutual information and adjusted mutual information, the normalizing value is typically some gener-
alized mean of the entropies of each clustering. Various generalized means exist, and no firm rules exist for preferring
one over the others. The decision is largely a field-by-field basis; for instance, in community detection, the arithmetic
mean is most common. Each normalizing method provides “qualitatively similar behaviours” [YAT2016]. In our
implementation, this is controlled by the average_method parameter.
Vinh et al. (2010) named variants of NMI and AMI by their averaging method [VEB2010]. Their ‘sqrt’ and ‘sum’
averages are the geometric and arithmetic means; we use these more broadly common names.

3.2. Unsupervised learning 345


scikit-learn user guide, Release 0.20.3

References

• Strehl, Alexander, and Joydeep Ghosh (2002). “Cluster ensembles – a knowledge reuse frame-
work for combining multiple partitions”. Journal of Machine Learning Research 3: 583–617.
doi:10.1162/153244303321897735.
• [VEB2009] Vinh, Epps, and Bailey, (2009). “Information theoretic measures for clusterings compar-
ison”. Proceedings of the 26th Annual International Conference on Machine Learning - ICML ‘09.
doi:10.1145/1553374.1553511. ISBN 9781605585161.
• [VEB2010] Vinh, Epps, and Bailey, (2010). “Information Theoretic Measures for Clusterings Comparison:
Variants, Properties, Normalization and Correction for Chance”. JMLR <http://jmlr.csail.mit.edu/papers/
volume11/vinh10a/vinh10a.pdf>
• Wikipedia entry for the (normalized) Mutual Information
• Wikipedia entry for the Adjusted Mutual Information
• [YAT2016] Yang, Algesheimer, and Tessone, (2016). “A comparative analysis of community detection algo-
rithms on artificial networks”. Scientific Reports 6: 30750. doi:10.1038/srep30750.

Homogeneity, completeness and V-measure

Given the knowledge of the ground truth class assignments of the samples, it is possible to define some intuitive metric
using conditional entropy analysis.
In particular Rosenberg and Hirschberg (2007) define the following two desirable objectives for any cluster assign-
ment:
• homogeneity: each cluster contains only members of a single class.
• completeness: all members of a given class are assigned to the same cluster.
We can turn those concept as scores homogeneity_score and completeness_score. Both are bounded
below by 0.0 and above by 1.0 (higher is better):

>>> from sklearn import metrics


>>> labels_true = [0, 0, 0, 1, 1, 1]
>>> labels_pred = [0, 0, 1, 1, 2, 2]

>>> metrics.homogeneity_score(labels_true, labels_pred)


0.66...

>>> metrics.completeness_score(labels_true, labels_pred)


0.42...

Their harmonic mean called V-measure is computed by v_measure_score:

>>> metrics.v_measure_score(labels_true, labels_pred)


0.51...

The V-measure is actually equivalent to the mutual information (NMI) discussed above, with the aggregation function
being the arithmetic mean [B2011].
Homogeneity, completeness and V-measure can be computed at once using
homogeneity_completeness_v_measure as follows:

346 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

>>> metrics.homogeneity_completeness_v_measure(labels_true, labels_pred)


...
(0.66..., 0.42..., 0.51...)

The following clustering assignment is slightly better, since it is homogeneous but not complete:

>>> labels_pred = [0, 0, 0, 1, 2, 2]


>>> metrics.homogeneity_completeness_v_measure(labels_true, labels_pred)
...
(1.0, 0.68..., 0.81...)

Note: v_measure_score is symmetric: it can be used to evaluate the agreement of two independent assignments
on the same dataset.
This is not the case for completeness_score and homogeneity_score: both are bound by the relationship:

homogeneity_score(a, b) == completeness_score(b, a)

Advantages

• Bounded scores: 0.0 is as bad as it can be, 1.0 is a perfect score.


• Intuitive interpretation: clustering with bad V-measure can be qualitatively analyzed in terms of homogeneity
and completeness to better feel what ‘kind’ of mistakes is done by the assignment.
• No assumption is made on the cluster structure: can be used to compare clustering algorithms such as k-
means which assumes isotropic blob shapes with results of spectral clustering algorithms which can find cluster
with “folded” shapes.

Drawbacks

• The previously introduced metrics are not normalized with regards to random labeling: this means that
depending on the number of samples, clusters and ground truth classes, a completely random labeling will
not always yield the same values for homogeneity, completeness and hence v-measure. In particular random
labeling won’t yield zero scores especially when the number of clusters is large.
This problem can safely be ignored when the number of samples is more than a thousand and the number of
clusters is less than 10. For smaller sample sizes or larger number of clusters it is safer to use an adjusted
index such as the Adjusted Rand Index (ARI).
• These metrics require the knowledge of the ground truth classes while almost never available in practice or
requires manual assignment by human annotators (as in the supervised learning setting).

Examples:

• Adjustment for chance in clustering performance evaluation: Analysis of the impact of the dataset size on the
value of clustering measures for random assignments.

3.2. Unsupervised learning 347


scikit-learn user guide, Release 0.20.3

348 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Mathematical formulation

Homogeneity and completeness scores are formally given by:


𝐻(𝐶|𝐾)
ℎ=1−
𝐻(𝐶)
𝐻(𝐾|𝐶)
𝑐=1−
𝐻(𝐾)
where 𝐻(𝐶|𝐾) is the conditional entropy of the classes given the cluster assignments and is given by:
|𝐶| |𝐾| (︂ )︂
∑︁ ∑︁ 𝑛𝑐,𝑘 𝑛𝑐,𝑘
𝐻(𝐶|𝐾) = − · log
𝑐=1 𝑘=1
𝑛 𝑛𝑘

and 𝐻(𝐶) is the entropy of the classes and is given by:


|𝐶|
∑︁ 𝑛𝑐 (︁ 𝑛 )︁
𝑐
𝐻(𝐶) = − · log
𝑐=1
𝑛 𝑛

with 𝑛 the total number of samples, 𝑛𝑐 and 𝑛𝑘 the number of samples respectively belonging to class 𝑐 and cluster 𝑘,
and finally 𝑛𝑐,𝑘 the number of samples from class 𝑐 assigned to cluster 𝑘.
The conditional entropy of clusters given class 𝐻(𝐾|𝐶) and the entropy of clusters 𝐻(𝐾) are defined in a sym-
metric manner.
Rosenberg and Hirschberg further define V-measure as the harmonic mean of homogeneity and completeness:
ℎ·𝑐
𝑣 =2·
ℎ+𝑐

References

• V-Measure: A conditional entropy-based external cluster evaluation measure Andrew Rosenberg and Julia
Hirschberg, 2007

Fowlkes-Mallows scores

The Fowlkes-Mallows index (sklearn.metrics.fowlkes_mallows_score) can be used when the ground


truth class assignments of the samples is known. The Fowlkes-Mallows score FMI is defined as the geometric mean
of the pairwise precision and recall:
TP
FMI = √︀
(TP + FP)(TP + FN)
Where TP is the number of True Positive (i.e. the number of pair of points that belong to the same clusters in both the
true labels and the predicted labels), FP is the number of False Positive (i.e. the number of pair of points that belong
to the same clusters in the true labels and not in the predicted labels) and FN is the number of False Negative (i.e the
number of pair of points that belongs in the same clusters in the predicted labels and not in the true labels).
The score ranges from 0 to 1. A high value indicates a good similarity between two clusters.
>>> from sklearn import metrics
>>> labels_true = [0, 0, 0, 1, 1, 1]
>>> labels_pred = [0, 0, 1, 1, 2, 2]

3.2. Unsupervised learning 349


scikit-learn user guide, Release 0.20.3

>>> metrics.fowlkes_mallows_score(labels_true, labels_pred)


0.47140...

One can permute 0 and 1 in the predicted labels, rename 2 to 3 and get the same score:

>>> labels_pred = [1, 1, 0, 0, 3, 3]

>>> metrics.fowlkes_mallows_score(labels_true, labels_pred)


0.47140...

Perfect labeling is scored 1.0:

>>> labels_pred = labels_true[:]


>>> metrics.fowlkes_mallows_score(labels_true, labels_pred)
1.0

Bad (e.g. independent labelings) have zero scores:

>>> labels_true = [0, 1, 2, 0, 3, 4, 5, 1]


>>> labels_pred = [1, 1, 0, 0, 2, 2, 2, 2]
>>> metrics.fowlkes_mallows_score(labels_true, labels_pred)
0.0

Advantages

• Random (uniform) label assignments have a FMI score close to 0.0 for any value of n_clusters and
n_samples (which is not the case for raw Mutual Information or the V-measure for instance).
• Upper-bounded at 1: Values close to zero indicate two label assignments that are largely independent, while
values close to one indicate significant agreement. Further, values of exactly 0 indicate purely independent
label assignments and a FMI of exactly 1 indicates that the two label assignments are equal (with or without
permutation).
• No assumption is made on the cluster structure: can be used to compare clustering algorithms such as k-
means which assumes isotropic blob shapes with results of spectral clustering algorithms which can find cluster
with “folded” shapes.

Drawbacks

• Contrary to inertia, FMI-based measures require the knowledge of the ground truth classes while almost
never available in practice or requires manual assignment by human annotators (as in the supervised learning
setting).

References

• E. B. Fowkles and C. L. Mallows, 1983. “A method for comparing two hierarchical clusterings”. Journal of
the American Statistical Association. http://wildfire.stat.ucla.edu/pdflibrary/fowlkes.pdf
• Wikipedia entry for the Fowlkes-Mallows Index

350 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Silhouette Coefficient

If the ground truth labels are not known, evaluation must be performed using the model itself. The Silhouette Coeffi-
cient (sklearn.metrics.silhouette_score) is an example of such an evaluation, where a higher Silhouette
Coefficient score relates to a model with better defined clusters. The Silhouette Coefficient is defined for each sample
and is composed of two scores:
• a: The mean distance between a sample and all other points in the same class.
• b: The mean distance between a sample and all other points in the next nearest cluster.
The Silhouette Coefficient s for a single sample is then given as:

𝑏−𝑎
𝑠=
𝑚𝑎𝑥(𝑎, 𝑏)

The Silhouette Coefficient for a set of samples is given as the mean of the Silhouette Coefficient for each sample.

>>> from sklearn import metrics


>>> from sklearn.metrics import pairwise_distances
>>> from sklearn import datasets
>>> dataset = datasets.load_iris()
>>> X = dataset.data
>>> y = dataset.target

In normal usage, the Silhouette Coefficient is applied to the results of a cluster analysis.

>>> import numpy as np


>>> from sklearn.cluster import KMeans
>>> kmeans_model = KMeans(n_clusters=3, random_state=1).fit(X)
>>> labels = kmeans_model.labels_
>>> metrics.silhouette_score(X, labels, metric='euclidean')
...
0.55...

References

• Peter J. Rousseeuw (1987). “Silhouettes: a Graphical Aid to the Interpretation and Validation of Cluster
Analysis”. Computational and Applied Mathematics 20: 53–65. doi:10.1016/0377-0427(87)90125-7.

Advantages

• The score is bounded between -1 for incorrect clustering and +1 for highly dense clustering. Scores around zero
indicate overlapping clusters.
• The score is higher when clusters are dense and well separated, which relates to a standard concept of a cluster.

Drawbacks

• The Silhouette Coefficient is generally higher for convex clusters than other concepts of clusters, such as density
based clusters like those obtained through DBSCAN.

3.2. Unsupervised learning 351


scikit-learn user guide, Release 0.20.3

Examples:

• Selecting the number of clusters with silhouette analysis on KMeans clustering : In this example the silhouette
analysis is used to choose an optimal value for n_clusters.

Calinski-Harabaz Index

If the ground truth labels are not known, the Calinski-Harabaz index (sklearn.metrics.
calinski_harabaz_score) - also known as the Variance Ratio Criterion - can be used to evaluate the
model, where a higher Calinski-Harabaz score relates to a model with better defined clusters.
For 𝑘 clusters, the Calinski-Harabaz score 𝑠 is given as the ratio of the between-clusters dispersion mean and the
within-cluster dispersion:

Tr(𝐵𝑘 ) 𝑁 −𝑘
𝑠(𝑘) = ×
Tr(𝑊𝑘 ) 𝑘−1

where 𝐵𝐾 is the between group dispersion matrix and 𝑊𝐾 is the within-cluster dispersion matrix defined by:
𝑘 ∑︁
∑︁
𝑊𝑘 = (𝑥 − 𝑐𝑞 )(𝑥 − 𝑐𝑞 )𝑇
𝑞=1 𝑥∈𝐶𝑞

∑︁
𝐵𝑘 = 𝑛𝑞 (𝑐𝑞 − 𝑐)(𝑐𝑞 − 𝑐)𝑇
𝑞

with 𝑁 be the number of points in our data, 𝐶𝑞 be the set of points in cluster 𝑞, 𝑐𝑞 be the center of cluster 𝑞, 𝑐 be the
center of 𝐸, 𝑛𝑞 be the number of points in cluster 𝑞.

>>> from sklearn import metrics


>>> from sklearn.metrics import pairwise_distances
>>> from sklearn import datasets
>>> dataset = datasets.load_iris()
>>> X = dataset.data
>>> y = dataset.target

In normal usage, the Calinski-Harabaz index is applied to the results of a cluster analysis.

>>> import numpy as np


>>> from sklearn.cluster import KMeans
>>> kmeans_model = KMeans(n_clusters=3, random_state=1).fit(X)
>>> labels = kmeans_model.labels_
>>> metrics.calinski_harabaz_score(X, labels)
561.62...

Advantages

• The score is higher when clusters are dense and well separated, which relates to a standard concept of a cluster.
• The score is fast to compute

352 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Drawbacks

• The Calinski-Harabaz index is generally higher for convex clusters than other concepts of clusters, such as
density based clusters like those obtained through DBSCAN.

References

• Caliński, T., & Harabasz, J. (1974). “A dendrite method for cluster analysis”. Communications in Statistics-
theory and Methods 3: 1-27. doi:10.1080/03610926.2011.560741.

Davies-Bouldin Index

If the ground truth labels are not known, the Davies-Bouldin index (sklearn.metrics.
davies_bouldin_score) can be used to evaluate the model, where a lower Davies-Bouldin index relates
to a model with better separation between the clusters.
The index is defined as the average similarity between each cluster 𝐶𝑖 for 𝑖 = 1, ..., 𝑘 and its most similar one 𝐶𝑗 . In
the context of this index, similarity is defined as a measure 𝑅𝑖𝑗 that trades off:
• 𝑠𝑖 , the average distance between each point of cluster 𝑖 and the centroid of that cluster – also know as cluster
diameter.
• 𝑑𝑖𝑗 , the distance between cluster centroids 𝑖 and 𝑗.
A simple choice to construct 𝑅𝑖 𝑗 so that it is nonnegative and symmetric is:
𝑠𝑖 + 𝑠𝑗
𝑅𝑖𝑗 =
𝑑𝑖𝑗

Then the Davies-Bouldin index is defined as:


𝑘
1 ∑︁
𝐷𝐵 = max 𝑅𝑖𝑗
𝑘 𝑖=1 𝑖̸=𝑗

Zero is the lowest possible score. Values closer to zero indicate a better partition.
In normal usage, the Davies-Bouldin index is applied to the results of a cluster analysis as follows:

>>> from sklearn import datasets


>>> iris = datasets.load_iris()
>>> X = iris.data
>>> from sklearn.cluster import KMeans
>>> from sklearn.metrics import davies_bouldin_score
>>> kmeans = KMeans(n_clusters=3, random_state=1).fit(X)
>>> labels = kmeans.labels_
>>> davies_bouldin_score(X, labels)
0.6619...

Advantages

• The computation of Davies-Bouldin is simpler than that of Silhouette scores.


• The index is computed only quantities and features inherent to the dataset.

3.2. Unsupervised learning 353


scikit-learn user guide, Release 0.20.3

Drawbacks

• The Davies-Boulding index is generally higher for convex clusters than other concepts of clusters, such as
density based clusters like those obtained from DBSCAN.
• The usage of centroid distance limits the distance metric to Euclidean space.
• A good value reported by this method does not imply the best information retrieval.

References

• Davies, David L.; Bouldin, Donald W. (1979). “A Cluster Separation Measure” IEEE Transactions on Pattern
Analysis and Machine Intelligence. PAMI-1 (2): 224-227. doi:10.1109/TPAMI.1979.4766909.
• Halkidi, Maria; Batistakis, Yannis; Vazirgiannis, Michalis (2001). “On Clustering Validation Techniques”
Journal of Intelligent Information Systems, 17(2-3), 107-145. doi:10.1023/A:1012801612483.
• Wikipedia entry for Davies-Bouldin index.

Contingency Matrix

Contingency matrix (sklearn.metrics.cluster.contingency_matrix) reports the intersection cardi-


nality for every true/predicted cluster pair. The contingency matrix provides sufficient statistics for all clustering met-
rics where the samples are independent and identically distributed and one doesn’t need to account for some instances
not being clustered.
Here is an example:

>>> from sklearn.metrics.cluster import contingency_matrix


>>> x = ["a", "a", "a", "b", "b", "b"]
>>> y = [0, 0, 1, 1, 2, 2]
>>> contingency_matrix(x, y)
array([[2, 1, 0],
[0, 1, 2]])

The first row of output array indicates that there are three samples whose true cluster is “a”. Of them, two are in
predicted cluster 0, one is in 1, and none is in 2. And the second row indicates that there are three samples whose true
cluster is “b”. Of them, none is in predicted cluster 0, one is in 1 and two are in 2.
A confusion matrix for classification is a square contingency matrix where the order of rows and columns correspond
to a list of classes.

Advantages

• Allows to examine the spread of each true cluster across predicted clusters and vice versa.
• The contingency table calculated is typically utilized in the calculation of a similarity statistic (like the others
listed in this document) between the two clusterings.

Drawbacks

• Contingency matrix is easy to interpret for a small number of clusters, but becomes very hard to interpret for a
large number of clusters.

354 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

• It doesn’t give a single metric to use as an objective for clustering optimisation.

References

• Wikipedia entry for contingency matrix

3.2.4 Biclustering

Biclustering can be performed with the module sklearn.cluster.bicluster. Biclustering algorithms simul-
taneously cluster rows and columns of a data matrix. These clusters of rows and columns are known as biclusters.
Each determines a submatrix of the original data matrix with some desired properties.
For instance, given a matrix of shape (10, 10), one possible bicluster with three rows and two columns induces a
submatrix of shape (3, 2):
>>> import numpy as np
>>> data = np.arange(100).reshape(10, 10)
>>> rows = np.array([0, 2, 3])[:, np.newaxis]
>>> columns = np.array([1, 2])
>>> data[rows, columns]
array([[ 1, 2],
[21, 22],
[31, 32]])

For visualization purposes, given a bicluster, the rows and columns of the data matrix may be rearranged to make the
bicluster contiguous.
Algorithms differ in how they define biclusters. Some of the common types include:
• constant values, constant rows, or constant columns
• unusually high or low values
• submatrices with low variance
• correlated rows or columns
Algorithms also differ in how rows and columns may be assigned to biclusters, which leads to different bicluster
structures. Block diagonal or checkerboard structures occur when rows and columns are divided into partitions.
If each row and each column belongs to exactly one bicluster, then rearranging the rows and columns of the data matrix
reveals the biclusters on the diagonal. Here is an example of this structure where biclusters have higher average values
than the other rows and columns:
In the checkerboard case, each row belongs to all column clusters, and each column belongs to all row clusters. Here
is an example of this structure where the variance of the values within each bicluster is small:
After fitting a model, row and column cluster membership can be found in the rows_ and columns_ attributes.
rows_[i] is a binary vector with nonzero entries corresponding to rows that belong to bicluster i. Similarly,
columns_[i] indicates which columns belong to bicluster i.
Some models also have row_labels_ and column_labels_ attributes. These models partition the rows and
columns, such as in the block diagonal and checkerboard bicluster structures.

Note: Biclustering has many other names in different fields including co-clustering, two-mode clustering, two-way
clustering, block clustering, coupled two-way clustering, etc. The names of some algorithms, such as the Spectral
Co-Clustering algorithm, reflect these alternate names.

3.2. Unsupervised learning 355


scikit-learn user guide, Release 0.20.3

Fig. 3.5: An example of biclusters formed by partitioning rows and columns.

Fig. 3.6: An example of checkerboard biclusters.

356 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Spectral Co-Clustering

The SpectralCoclustering algorithm finds biclusters with values higher than those in the corresponding other
rows and columns. Each row and each column belongs to exactly one bicluster, so rearranging the rows and columns
to make partitions contiguous reveals these high values along the diagonal:

Note: The algorithm treats the input data matrix as a bipartite graph: the rows and columns of the matrix correspond
to the two sets of vertices, and each entry corresponds to an edge between a row and a column. The algorithm
approximates the normalized cut of this graph to find heavy subgraphs.

Mathematical formulation

An approximate solution to the optimal normalized cut may be found via the generalized eigenvalue decomposition of
the Laplacian of the graph. Usually this would mean working directly with the Laplacian matrix. If the original data
matrix 𝐴 has shape 𝑚 × 𝑛, the Laplacian matrix for the corresponding bipartite graph has shape (𝑚 + 𝑛) × (𝑚 + 𝑛).
However, in this case it is possible to work directly with 𝐴, which is smaller and more efficient.
The input matrix 𝐴 is preprocessed as follows:

𝐴𝑛 = 𝑅−1/2 𝐴𝐶 −1/2
∑︀
Where
∑︀ 𝑅 is the diagonal matrix with entry 𝑖 equal to 𝑗 𝐴𝑖𝑗 and 𝐶 is the diagonal matrix with entry 𝑗 equal to
𝑖 𝐴𝑖𝑗 .

The singular value decomposition, 𝐴𝑛 = 𝑈 Σ𝑉 ⊤ , provides the partitions of the rows and columns of 𝐴. A subset of
the left singular vectors gives the row partitions, and a subset of the right singular vectors gives the column partitions.
The ℓ = ⌈log2 𝑘⌉ singular vectors, starting from the second, provide the desired partitioning information. They are
used to form the matrix 𝑍:
⎡ −1/2 ⎤
𝑅 𝑈
𝑍=⎣ ⎦
−1/2
𝐶 𝑉

where the columns of 𝑈 are 𝑢2 , . . . , 𝑢ℓ+1 , and similarly for 𝑉 .


Then the rows of 𝑍 are clustered using k-means. The first n_rows labels provide the row partitioning, and the
remaining n_columns labels provide the column partitioning.

Examples:

• A demo of the Spectral Co-Clustering algorithm: A simple example showing how to generate a data matrix
with biclusters and apply this method to it.
• Biclustering documents with the Spectral Co-clustering algorithm: An example of finding biclusters in the
twenty newsgroup dataset.

References:

• Dhillon, Inderjit S, 2001. Co-clustering documents and words using bipartite spectral graph partitioning.

3.2. Unsupervised learning 357


scikit-learn user guide, Release 0.20.3

Spectral Biclustering

The SpectralBiclustering algorithm assumes that the input data matrix has a hidden checkerboard structure.
The rows and columns of a matrix with this structure may be partitioned so that the entries of any bicluster in the
Cartesian product of row clusters and column clusters are approximately constant. For instance, if there are two row
partitions and three column partitions, each row will belong to three biclusters, and each column will belong to two
biclusters.
The algorithm partitions the rows and columns of a matrix so that a corresponding blockwise-constant checkerboard
matrix provides a good approximation to the original matrix.

Mathematical formulation

The input matrix 𝐴 is first normalized to make the checkerboard pattern more obvious. There are three possible
methods:
1. Independent row and column normalization, as in Spectral Co-Clustering. This method makes the rows sum to
a constant and the columns sum to a different constant.
2. Bistochastization: repeated row and column normalization until convergence. This method makes both rows
and columns sum to the same constant.
3. Log normalization: the log of the data matrix is computed: 𝐿 = log 𝐴. Then the column mean 𝐿𝑖· , row mean
𝐿·𝑗 , and overall mean 𝐿·· of 𝐿 are computed. The final matrix is computed according to the formula
𝐾𝑖𝑗 = 𝐿𝑖𝑗 − 𝐿𝑖· − 𝐿·𝑗 + 𝐿··
After normalizing, the first few singular vectors are computed, just as in the Spectral Co-Clustering algorithm.
If log normalization was used, all the singular vectors are meaningful. However, if independent normalization or
bistochastization were used, the first singular vectors, 𝑢1 and 𝑣1 . are discarded. From now on, the “first” singular
vectors refers to 𝑢2 . . . 𝑢𝑝+1 and 𝑣2 . . . 𝑣𝑝+1 except in the case of log normalization.
Given these singular vectors, they are ranked according to which can be best approximated by a piecewise-constant
vector. The approximations for each vector are found using one-dimensional k-means and scored using the Euclidean
distance. Some subset of the best left and right singular vector are selected. Next, the data is projected to this best
subset of singular vectors and clustered.
For instance, if 𝑝 singular vectors were calculated, the 𝑞 best are found as described, where 𝑞 < 𝑝. Let 𝑈 be the matrix
with columns the 𝑞 best left singular vectors, and similarly 𝑉 for the right. To partition the rows, the rows of 𝐴 are
projected to a 𝑞 dimensional space: 𝐴 * 𝑉 . Treating the 𝑚 rows of this 𝑚 × 𝑞 matrix as samples and clustering using
k-means yields the row labels. Similarly, projecting the columns to 𝐴⊤ * 𝑈 and clustering this 𝑛 × 𝑞 matrix yields the
column labels.

Examples:

• A demo of the Spectral Biclustering algorithm: a simple example showing how to generate a checkerboard
matrix and bicluster it.

References:

• Kluger, Yuval, et. al., 2003. Spectral biclustering of microarray data: coclustering genes and conditions.

358 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Biclustering evaluation

There are two ways of evaluating a biclustering result: internal and external. Internal measures, such as cluster
stability, rely only on the data and the result themselves. Currently there are no internal bicluster measures in scikit-
learn. External measures refer to an external source of information, such as the true solution. When working with
real data the true solution is usually unknown, but biclustering artificial data may be useful for evaluating algorithms
precisely because the true solution is known.
To compare a set of found biclusters to the set of true biclusters, two similarity measures are needed: a similarity
measure for individual biclusters, and a way to combine these individual similarities into an overall score.
To compare individual biclusters, several measures have been used. For now, only the Jaccard index is implemented:
|𝐴 ∩ 𝐵|
𝐽(𝐴, 𝐵) =
|𝐴| + |𝐵| − |𝐴 ∩ 𝐵|

where 𝐴 and 𝐵 are biclusters, |𝐴 ∩ 𝐵| is the number of elements in their intersection. The Jaccard index achieves its
minimum of 0 when the biclusters to not overlap at all and its maximum of 1 when they are identical.
Several methods have been developed to compare two sets of biclusters. For now, only consensus_score (Hochre-
iter et. al., 2010) is available:
1. Compute bicluster similarities for pairs of biclusters, one in each set, using the Jaccard index or a similar
measure.
2. Assign biclusters from one set to another in a one-to-one fashion to maximize the sum of their similarities. This
step is performed using the Hungarian algorithm.
3. The final sum of similarities is divided by the size of the larger set.
The minimum consensus score, 0, occurs when all pairs of biclusters are totally dissimilar. The maximum score, 1,
occurs when both sets are identical.

References:

• Hochreiter, Bodenhofer, et. al., 2010. FABIA: factor analysis for bicluster acquisition.

3.2.5 Decomposing signals in components (matrix factorization problems)

Principal component analysis (PCA)

Exact PCA and probabilistic interpretation

PCA is used to decompose a multivariate dataset in a set of successive orthogonal components that explain a maximum
amount of the variance. In scikit-learn, PCA is implemented as a transformer object that learns 𝑛 components in its
fit method, and can be used on new data to project it on these components.
The optional parameter whiten=True makes it possible to project the data onto the singular space while scaling
each component to unit variance. This is often useful if the models down-stream make strong assumptions on the
isotropy of the signal: this is for example the case for Support Vector Machines with the RBF kernel and the K-Means
clustering algorithm.
Below is an example of the iris dataset, which is comprised of 4 features, projected on the 2 dimensions that explain
most variance:
The PCA object also provides a probabilistic interpretation of the PCA that can give a likelihood of data based on the
amount of variance it explains. As such it implements a score method that can be used in cross-validation:

3.2. Unsupervised learning 359


scikit-learn user guide, Release 0.20.3

360 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Examples:

• Comparison of LDA and PCA 2D projection of Iris dataset


• Model selection with Probabilistic PCA and Factor Analysis (FA)

Incremental PCA

The PCA object is very useful, but has certain limitations for large datasets. The biggest limitation is that PCA only sup-
ports batch processing, which means all of the data to be processed must fit in main memory. The IncrementalPCA
object uses a different form of processing and allows for partial computations which almost exactly match the results
of PCA while processing the data in a minibatch fashion. IncrementalPCA makes it possible to implement out-of-
core Principal Component Analysis either by:
• Using its partial_fit method on chunks of data fetched sequentially from the local hard drive or a network
database.
• Calling its fit method on a memory mapped file using numpy.memmap.
IncrementalPCA only stores estimates of component and noise variances, in order update
explained_variance_ratio_ incrementally. This is why memory usage depends on the number of
samples per batch, rather than the number of samples to be processed in the dataset.

Examples:

• Incremental PCA

PCA using randomized SVD

It is often interesting to project data to a lower-dimensional space that preserves most of the variance, by dropping the
singular vector of components associated with lower singular values.
For instance, if we work with 64x64 pixel gray-level pictures for face recognition, the dimensionality of the data is
4096 and it is slow to train an RBF support vector machine on such wide data. Furthermore we know that the intrinsic
dimensionality of the data is much lower than 4096 since all pictures of human faces look somewhat alike. The
samples lie on a manifold of much lower dimension (say around 200 for instance). The PCA algorithm can be used to
linearly transform the data while both reducing the dimensionality and preserve most of the explained variance at the
same time.
The class PCA used with the optional parameter svd_solver='randomized' is very useful in that case: since
we are going to drop most of the singular vectors it is much more efficient to limit the computation to an approximated
estimate of the singular vectors we will keep to actually perform the transform.
For instance, the following shows 16 sample portraits (centered around 0.0) from the Olivetti dataset. On the right
hand side are the first 16 singular vectors reshaped as portraits. Since we only require the top 16 singular vectors of a
dataset with size 𝑛𝑠𝑎𝑚𝑝𝑙𝑒𝑠 = 400 and 𝑛𝑓 𝑒𝑎𝑡𝑢𝑟𝑒𝑠 = 64 × 64 = 4096, the computation time is less than 1s:

3.2. Unsupervised learning 361


scikit-learn user guide, Release 0.20.3

362 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

3.2. Unsupervised learning 363


scikit-learn user guide, Release 0.20.3

If we note 𝑛max = max(𝑛samples , 𝑛features ) and 𝑛min = min(𝑛samples , 𝑛features ), the time complexity of the random-
ized PCA is 𝑂(𝑛2max · 𝑛components ) instead of 𝑂(𝑛2max · 𝑛min ) for the exact method implemented in PCA.
The memory footprint of randomized PCA is also proportional to 2 · 𝑛max · 𝑛components instead of 𝑛max · 𝑛min for the
exact method.
Note: the implementation of inverse_transform in PCA with svd_solver='randomized' is not the exact
inverse transform of transform even when whiten=False (default).

Examples:

• Faces recognition example using eigenfaces and SVMs


• Faces dataset decompositions

References:

• “Finding structure with randomness: Stochastic algorithms for constructing approximate matrix decomposi-
tions” Halko, et al., 2009

364 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Kernel PCA

KernelPCA is an extension of PCA which achieves non-linear dimensionality reduction through the use of
kernels (see Pairwise metrics, Affinities and Kernels). It has many applications including denoising, compres-
sion and structured prediction (kernel dependency estimation). KernelPCA supports both transform and
inverse_transform.

Examples:

• Kernel PCA

Sparse principal components analysis (SparsePCA and MiniBatchSparsePCA)

SparsePCA is a variant of PCA, with the goal of extracting the set of sparse components that best reconstruct the
data.
Mini-batch sparse PCA (MiniBatchSparsePCA) is a variant of SparsePCA that is faster but less accurate. The
increased speed is reached by iterating over small chunks of the set of features, for a given number of iterations.
Principal component analysis (PCA) has the disadvantage that the components extracted by this method have exclu-
sively dense expressions, i.e. they have non-zero coefficients when expressed as linear combinations of the original
variables. This can make interpretation difficult. In many cases, the real underlying components can be more naturally
imagined as sparse vectors; for example in face recognition, components might naturally map to parts of faces.
Sparse principal components yields a more parsimonious, interpretable representation, clearly emphasizing which of
the original features contribute to the differences between samples.
The following example illustrates 16 components extracted using sparse PCA from the Olivetti faces dataset. It can
be seen how the regularization term induces many zeros. Furthermore, the natural structure of the data causes the
non-zero coefficients to be vertically adjacent. The model does not enforce this mathematically: each component is

3.2. Unsupervised learning 365


scikit-learn user guide, Release 0.20.3

a vector ℎ ∈ R4096 , and there is no notion of vertical adjacency except during the human-friendly visualization as
64x64 pixel images. The fact that the components shown below appear local is the effect of the inherent structure of
the data, which makes such local patterns minimize reconstruction error. There exist sparsity-inducing norms that take
into account adjacency and different kinds of structure; see [Jen09] for a review of such methods. For more details on
how to use Sparse PCA, see the Examples section, below.

Note that there are many different formulations for the Sparse PCA problem. The one implemented here is based
on [Mrl09] . The optimization problem solved is a PCA problem (dictionary learning) with an ℓ1 penalty on the
components:
1
(𝑈 * , 𝑉 * ) = arg min ||𝑋 − 𝑈 𝑉 ||22 + 𝛼||𝑉 ||1
𝑈,𝑉 2
subject to ||𝑈𝑘 ||2 = 1 for all 0 ≤ 𝑘 < 𝑛𝑐𝑜𝑚𝑝𝑜𝑛𝑒𝑛𝑡𝑠

The sparsity-inducing ℓ1 norm also prevents learning components from noise when few training samples are available.
The degree of penalization (and thus sparsity) can be adjusted through the hyperparameter alpha. Small values lead
to a gently regularized factorization, while larger values shrink many coefficients to zero.

Note: While in the spirit of an online algorithm, the class MiniBatchSparsePCA does not implement
partial_fit because the algorithm is online along the features direction, not the samples direction.

366 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Examples:

• Faces dataset decompositions

References:

Truncated singular value decomposition and latent semantic analysis

TruncatedSVD implements a variant of singular value decomposition (SVD) that only computes the 𝑘 largest
singular values, where 𝑘 is a user-specified parameter.
When truncated SVD is applied to term-document matrices (as returned by CountVectorizer or
TfidfVectorizer), this transformation is known as latent semantic analysis (LSA), because it transforms such
matrices to a “semantic” space of low dimensionality. In particular, LSA is known to combat the effects of synonymy
and polysemy (both of which roughly mean there are multiple meanings per word), which cause term-document ma-
trices to be overly sparse and exhibit poor similarity under measures such as cosine similarity.

Note: LSA is also known as latent semantic indexing, LSI, though strictly that refers to its use in persistent indexes
for information retrieval purposes.

Mathematically, truncated SVD applied to training samples 𝑋 produces a low-rank approximation 𝑋:

𝑋 ≈ 𝑋𝑘 = 𝑈𝑘 Σ𝑘 𝑉𝑘⊤

After this operation, 𝑈𝑘 Σ⊤


𝑘 is the transformed training set with 𝑘 features (called n_components in the API).

To also transform a test set 𝑋, we multiply it with 𝑉𝑘 :

𝑋 ′ = 𝑋𝑉𝑘

Note: Most treatments of LSA in the natural language processing (NLP) and information retrieval (IR) literature
swap the axes of the matrix 𝑋 so that it has shape n_features × n_samples. We present LSA in a different way
that matches the scikit-learn API better, but the singular values found are the same.

TruncatedSVD is very similar to PCA, but differs in that it works on sample matrices 𝑋 directly instead of their
covariance matrices. When the columnwise (per-feature) means of 𝑋 are subtracted from the feature values, truncated
SVD on the resulting matrix is equivalent to PCA. In practical terms, this means that the TruncatedSVD transformer
accepts scipy.sparse matrices without the need to densify them, as densifying may fill up memory even for
medium-sized document collections.
While the TruncatedSVD transformer works with any (sparse) feature matrix, using it on tf–idf matrices is recom-
mended over raw frequency counts in an LSA/document processing setting. In particular, sublinear scaling and inverse
document frequency should be turned on (sublinear_tf=True, use_idf=True) to bring the feature values
closer to a Gaussian distribution, compensating for LSA’s erroneous assumptions about textual data.

Examples:

• Clustering text documents using k-means

3.2. Unsupervised learning 367


scikit-learn user guide, Release 0.20.3

References:

• Christopher D. Manning, Prabhakar Raghavan and Hinrich Schütze (2008), Introduction to Information Re-
trieval, Cambridge University Press, chapter 18: Matrix decompositions & latent semantic indexing

Dictionary Learning

Sparse coding with a precomputed dictionary

The SparseCoder object is an estimator that can be used to transform signals into sparse linear combination of
atoms from a fixed, precomputed dictionary such as a discrete wavelet basis. This object therefore does not implement
a fit method. The transformation amounts to a sparse coding problem: finding a representation of the data as a linear
combination of as few dictionary atoms as possible. All variations of dictionary learning implement the following
transform methods, controllable via the transform_method initialization parameter:
• Orthogonal matching pursuit (Orthogonal Matching Pursuit (OMP))
• Least-angle regression (Least Angle Regression)
• Lasso computed by least-angle regression
• Lasso using coordinate descent (Lasso)
• Thresholding
Thresholding is very fast but it does not yield accurate reconstructions. They have been shown useful in literature for
classification tasks. For image reconstruction tasks, orthogonal matching pursuit yields the most accurate, unbiased
reconstruction.
The dictionary learning objects offer, via the split_code parameter, the possibility to separate the positive and
negative values in the results of sparse coding. This is useful when dictionary learning is used for extracting features
that will be used for supervised learning, because it allows the learning algorithm to assign different weights to negative
loadings of a particular atom, from to the corresponding positive loading.
The split code for a single sample has length 2 * n_components and is constructed using the following rule:
First, the regular code of length n_components is computed. Then, the first n_components entries of the
split_code are filled with the positive part of the regular code vector. The second half of the split code is filled
with the negative part of the code vector, only with a positive sign. Therefore, the split_code is non-negative.

Examples:

• Sparse coding with a precomputed dictionary

Generic dictionary learning

Dictionary learning (DictionaryLearning) is a matrix factorization problem that amounts to finding a (usually
overcomplete) dictionary that will perform well at sparsely encoding the fitted data.
Representing data as sparse combinations of atoms from an overcomplete dictionary is suggested to be the way the
mammalian primary visual cortex works. Consequently, dictionary learning applied on image patches has been shown
to give good results in image processing tasks such as image completion, inpainting and denoising, as well as for
supervised recognition tasks.

368 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Dictionary learning is an optimization problem solved by alternatively updating the sparse code, as a solution to
multiple Lasso problems, considering the dictionary fixed, and then updating the dictionary to best fit the sparse code.
1
(𝑈 * , 𝑉 * ) = arg min ||𝑋 − 𝑈 𝑉 ||22 + 𝛼||𝑈 ||1
𝑈,𝑉 2
subject to ||𝑉𝑘 ||2 = 1 for all 0 ≤ 𝑘 < 𝑛atoms

After using such a procedure to fit the dictionary, the transform is simply a sparse coding step that shares the same
implementation with all dictionary learning objects (see Sparse coding with a precomputed dictionary).
It is also possible to constrain the dictionary and/or code to be positive to match constraints that may be present in the
data. Below are the faces with different positivity constraints applied. Red indicates negative values, blue indicates
positive values, and white represents zeros.

3.2. Unsupervised learning 369


scikit-learn user guide, Release 0.20.3

370 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

The following image shows how a dictionary learned from 4x4 pixel image patches extracted from part of the image
of a raccoon face looks like.

Examples:

• Image denoising using dictionary learning

References:

• “Online dictionary learning for sparse coding” J. Mairal, F. Bach, J. Ponce, G. Sapiro, 2009

Mini-batch dictionary learning

MiniBatchDictionaryLearning implements a faster, but less accurate version of the dictionary learning algo-
rithm that is better suited for large datasets.
By default, MiniBatchDictionaryLearning divides the data into mini-batches and optimizes in an online
manner by cycling over the mini-batches for the specified number of iterations. However, at the moment it does not
implement a stopping condition.

3.2. Unsupervised learning 371


scikit-learn user guide, Release 0.20.3

The estimator also implements partial_fit, which updates the dictionary by iterating only once over a mini-batch.
This can be used for online learning when the data is not readily available from the start, or for when the data does not

fit into the memory.

Clustering for dictionary learning

Note that when using dictionary learning to extract a representation (e.g. for sparse coding) clustering can be a
good proxy to learn the dictionary. For instance the MiniBatchKMeans estimator is computationally efficient
and implements on-line learning with a partial_fit method.
Example: Online learning of a dictionary of parts of faces

Factor Analysis

In unsupervised learning we only have a dataset 𝑋 = {𝑥1 , 𝑥2 , . . . , 𝑥𝑛 }. How can this dataset be described mathemat-
ically? A very simple continuous latent variable model for 𝑋 is

𝑥𝑖 = 𝑊 ℎ𝑖 + 𝜇 + 𝜖

The vector ℎ𝑖 is called “latent” because it is unobserved. 𝜖 is considered a noise term distributed according to a
Gaussian with mean 0 and covariance Ψ (i.e. 𝜖 ∼ 𝒩 (0, Ψ)), 𝜇 is some arbitrary offset vector. Such a model is called
“generative” as it describes how 𝑥𝑖 is generated from ℎ𝑖 . If we use all the 𝑥𝑖 ‘s as columns to form a matrix X and all
the ℎ𝑖 ‘s as columns of a matrix H then we can write (with suitably defined M and E):

X = 𝑊H + M + E

In other words, we decomposed matrix X.


If ℎ𝑖 is given, the above equation automatically implies the following probabilistic interpretation:

𝑝(𝑥𝑖 |ℎ𝑖 ) = 𝒩 (𝑊 ℎ𝑖 + 𝜇, Ψ)

For a complete probabilistic model we also need a prior distribution for the latent variable ℎ. The most straightforward
assumption (based on the nice properties of the Gaussian distribution) is ℎ ∼ 𝒩 (0, I). This yields a Gaussian as the
marginal distribution of 𝑥:

𝑝(𝑥) = 𝒩 (𝜇, 𝑊 𝑊 𝑇 + Ψ)

Now, without any further assumptions the idea of having a latent variable ℎ would be superfluous – 𝑥 can be com-
pletely modelled with a mean and a covariance. We need to impose some more specific structure on one of these two
parameters. A simple additional assumption regards the structure of the error covariance Ψ:
• Ψ = 𝜎 2 I: This assumption leads to the probabilistic model of PCA.

372 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

• Ψ = diag(𝜓1 , 𝜓2 , . . . , 𝜓𝑛 ): This model is called FactorAnalysis, a classical statistical model. The matrix
W is sometimes called the “factor loading matrix”.
Both models essentially estimate a Gaussian with a low-rank covariance matrix. Because both models are probabilistic
they can be integrated in more complex models, e.g. Mixture of Factor Analysers. One gets very different models (e.g.
FastICA) if non-Gaussian priors on the latent variables are assumed.
Factor analysis can produce similar components (the columns of its loading matrix) to PCA. However, one can not
make any general statements about these components (e.g. whether they are orthogonal):

The main advantage for Factor Analysis over PCA is that it can model the variance in every direction of the input space
independently (heteroscedastic noise):
This allows better model selection than probabilistic PCA in the presence of heteroscedastic noise:

Examples:

• Model selection with Probabilistic PCA and Factor Analysis (FA)

3.2. Unsupervised learning 373


scikit-learn user guide, Release 0.20.3

374 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

Independent component analysis (ICA)

Independent component analysis separates a multivariate signal into additive subcomponents that are maximally in-
dependent. It is implemented in scikit-learn using the Fast ICA algorithm. Typically, ICA is not used for reducing
dimensionality but for separating superimposed signals. Since the ICA model does not include a noise term, for the
model to be correct, whitening must be applied. This can be done internally using the whiten argument or manually
using one of the PCA variants.
It is classically used to separate mixed signals (a problem known as blind source separation), as in the example below:

ICA can also be used as yet another non linear decomposition that finds components with some sparsity:

3.2. Unsupervised learning 375


scikit-learn user guide, Release 0.20.3

Examples:

• Blind source separation using FastICA


• FastICA on 2D point clouds
• Faces dataset decompositions

Non-negative matrix factorization (NMF or NNMF)

NMF with the Frobenius norm

NMF 1 is an alternative approach to decomposition that assumes that the data and the components are non-negative.
NMF can be plugged in instead of PCA or its variants, in the cases where the data matrix does not contain negative
values. It finds a decomposition of samples 𝑋 into two matrices 𝑊 and 𝐻 of non-negative elements, by optimizing the
distance 𝑑 between 𝑋 and the matrix product 𝑊 𝐻. The most widely used distance function is the squared Frobenius
norm, which is an obvious extension of the Euclidean norm to matrices:
1 1 ∑︁
𝑑Fro (𝑋, 𝑌 ) = ||𝑋 − 𝑌 ||2Fro = (𝑋𝑖𝑗 − 𝑌𝑖𝑗 )2
2 2 𝑖,𝑗

Unlike PCA, the representation of a vector is obtained in an additive fashion, by superimposing the components,
without subtracting. Such additive models are efficient for representing images and text.
It has been observed in [Hoyer, 2004]2 that, when carefully constrained, NMF can produce a parts-based representation
of the dataset, resulting in interpretable models. The following example displays 16 sparse components found by NMF
from the images in the Olivetti faces dataset, in comparison with the PCA eigenfaces.
1 “Learning the parts of objects by non-negative matrix factorization” D. Lee, S. Seung, 1999
2 “Non-negative Matrix Factorization with Sparseness Constraints” P. Hoyer, 2004

376 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

The init attribute determines the initialization method applied, which has a great impact on the performance of the
method. NMF implements the method Nonnegative Double Singular Value Decomposition. NNDSVD4 is based on
two SVD processes, one approximating the data matrix, the other approximating positive sections of the resulting
partial SVD factors utilizing an algebraic property of unit rank matrices. The basic NNDSVD algorithm is better fit
for sparse factorization. Its variants NNDSVDa (in which all zeros are set equal to the mean of all elements of the
data), and NNDSVDar (in which the zeros are set to random perturbations less than the mean of the data divided by
100) are recommended in the dense case.
Note that the Multiplicative Update (‘mu’) solver cannot update zeros present in the initialization, so it leads to poorer
results when used jointly with the basic NNDSVD algorithm which introduces a lot of zeros; in this case, NNDSVDa
or NNDSVDar should be preferred.
NMF can also be initialized with correctly scaled random non-negative matrices by setting init="random". An
integer seed or a RandomState can also be passed to random_state to control reproducibility.
In NMF, L1 and L2 priors can be added to the loss function in order to regularize the model. The L2 prior uses the
Frobenius norm, while the L1 prior uses an elementwise L1 norm. As in ElasticNet, we control the combination
of L1 and L2 with the l1_ratio (𝜌) parameter, and the intensity of the regularization with the alpha (𝛼) parameter.
Then the priors terms are:
𝛼(1 − 𝜌) 𝛼(1 − 𝜌)
𝛼𝜌||𝑊 ||1 + 𝛼𝜌||𝐻||1 + ||𝑊 ||2Fro + ||𝐻||2Fro
2 2
4 “SVD based initialization: A head start for nonnegative matrix factorization” C. Boutsidis, E. Gallopoulos, 2008

3.2. Unsupervised learning 377


scikit-learn user guide, Release 0.20.3

and the regularized objective function is:

𝛼(1 − 𝜌) 𝛼(1 − 𝜌)
𝑑Fro (𝑋, 𝑊 𝐻) + 𝛼𝜌||𝑊 ||1 + 𝛼𝜌||𝐻||1 + ||𝑊 ||2Fro + ||𝐻||2Fro
2 2
NMF regularizes both W and H. The public function non_negative_factorization allows a finer control
through the regularization attribute, and may regularize only W, only H, or both.

NMF with a beta-divergence

As described previously, the most widely used distance function is the squared Frobenius norm, which is an obvious
extension of the Euclidean norm to matrices:
1 1 ∑︁
𝑑Fro (𝑋, 𝑌 ) = ||𝑋 − 𝑌 ||2𝐹 𝑟𝑜 = (𝑋𝑖𝑗 − 𝑌𝑖𝑗 )2
2 2 𝑖,𝑗

Other distance functions can be used in NMF as, for example, the (generalized) Kullback-Leibler (KL) divergence,
also referred as I-divergence:
∑︁ 𝑋𝑖𝑗
𝑑𝐾𝐿 (𝑋, 𝑌 ) = (𝑋𝑖𝑗 log( ) − 𝑋𝑖𝑗 + 𝑌𝑖𝑗 )
𝑖,𝑗
𝑌𝑖𝑗

Or, the Itakura-Saito (IS) divergence:


∑︁ 𝑋𝑖𝑗 𝑋𝑖𝑗
𝑑𝐼𝑆 (𝑋, 𝑌 ) = ( − log( ) − 1)
𝑖,𝑗
𝑌𝑖𝑗 𝑌𝑖𝑗

These three distances are special cases of the beta-divergence family, with 𝛽 = 2, 1, 0 respectively6 . The beta-
divergence are defined by :
∑︁ 1
𝑑𝛽 (𝑋, 𝑌 ) = (𝑋 𝛽 + (𝛽 − 1)𝑌𝑖𝑗𝛽 − 𝛽𝑋𝑖𝑗 𝑌𝑖𝑗𝛽−1 )
𝑖,𝑗
𝛽(𝛽 − 1) 𝑖𝑗

Note that this definition is not valid if 𝛽 ∈ (0; 1), yet it can be continuously extended to the definitions of 𝑑𝐾𝐿 and
𝑑𝐼𝑆 respectively.
NMF implements two solvers, using Coordinate Descent (‘cd’)5 , and Multiplicative Update (‘mu’)6 . The ‘mu’ solver
can optimize every beta-divergence, including of course the Frobenius norm (𝛽 = 2), the (generalized) Kullback-
Leibler divergence (𝛽 = 1) and the Itakura-Saito divergence (𝛽 = 0). Note that for 𝛽 ∈ (1; 2), the ‘mu’ solver is
significantly faster than for other values of 𝛽. Note also that with a negative (or 0, i.e. ‘itakura-saito’) 𝛽, the input
matrix cannot contain zero values.
The ‘cd’ solver can only optimize the Frobenius norm. Due to the underlying non-convexity of NMF, the different
solvers may converge to different minima, even when optimizing the same distance function.
NMF is best used with the fit_transform method, which returns the matrix W. The matrix H is stored into the
fitted model in the components_ attribute; the method transform will decompose a new matrix X_new based on
these stored components:

>>> import numpy as np


>>> X = np.array([[1, 1], [2, 1], [3, 1.2], [4, 1], [5, 0.8], [6, 1]])
>>> from sklearn.decomposition import NMF
>>> model = NMF(n_components=2, init='random', random_state=0)

6 “Algorithms for nonnegative matrix factorization with the beta-divergence” C. Fevotte, J. Idier, 2011
5 “Fast local algorithms for large scale nonnegative matrix and tensor factorizations.” A. Cichocki, A. Phan, 2009

378 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

>>> W = model.fit_transform(X)
>>> H = model.components_
>>> X_new = np.array([[1, 0], [1, 6.1], [1, 0], [1, 4], [3.2, 1], [0, 4]])
>>> W_new = model.transform(X_new)

Examples:

• Faces dataset decompositions


• Topic extraction with Non-negative Matrix Factorization and Latent Dirichlet Allocation
• Beta-divergence loss functions

References:

Latent Dirichlet Allocation (LDA)

Latent Dirichlet Allocation is a generative probabilistic model for collections of discrete dataset such as text corpora.
It is also a topic model that is used for discovering abstract topics from a collection of documents.
The graphical model of LDA is a three-level generative model:

3.2. Unsupervised learning 379


scikit-learn user guide, Release 0.20.3

Note on notations presented in the graphical model above, which can be found in Hoffman et al. (2013):
• The corpus is a collection of 𝐷 documents.
• A document is a sequence of 𝑁 words.
• There are 𝐾 topics in the corpus.
• The boxes represent repeated sampling.
In the graphical model, each node is a random variable and has a role in the generative process. A shaded node
indicates an observed variable and an unshaded node indicates a hidden (latent) variable. In this case, words in the
corpus are the only data that we observe. The latent variables determine the random mixture of topics in the corpus
and the distribution of words in the documents. The goal of LDA is to use the observed words to infer the hidden topic
structure.
When modeling text corpora, the model assumes the following generative process for a corpus with 𝐷 documents and
𝐾 topics, with 𝐾 corresponding to n_components in the API:
1. For each topic 𝑘 ∈ 𝐾, draw 𝛽𝑘 ∼ Dirichlet(𝜂). This provides a distribution over the words, i.e. the
probability of a word appearing in topic 𝑘. 𝜂 corresponds to topic_word_prior.
2. For each document 𝑑 ∈ 𝐷, draw the topic proportions 𝜃𝑑 ∼ Dirichlet(𝛼). 𝛼 corresponds to
doc_topic_prior.
3. For each word 𝑖 in document 𝑑:
1. Draw the topic assignment 𝑧𝑑𝑖 ∼ Multinomial(𝜃𝑑 )
2. Draw the observed word 𝑤𝑖𝑗 ∼ Multinomial(𝛽𝑧𝑑𝑖 )
For parameter estimation, the posterior distribution is:
𝑝(𝑧, 𝜃, 𝛽|𝛼, 𝜂)
𝑝(𝑧, 𝜃, 𝛽|𝑤, 𝛼, 𝜂) =
𝑝(𝑤|𝛼, 𝜂)

Since the posterior is intractable, variational Bayesian method uses a simpler distribution 𝑞(𝑧, 𝜃, 𝛽|𝜆, 𝜑, 𝛾) to approx-
imate it, and those variational parameters 𝜆, 𝜑, 𝛾 are optimized to maximize the Evidence Lower Bound (ELBO):

log 𝑃 (𝑤|𝛼, 𝜂) ≥ 𝐿(𝑤, 𝜑, 𝛾, 𝜆) = 𝐸𝑞 [log 𝑝(𝑤, 𝑧, 𝜃, 𝛽|𝛼, 𝜂)] − 𝐸𝑞 [log 𝑞(𝑧, 𝜃, 𝛽)]

Maximizing ELBO is equivalent to minimizing the Kullback-Leibler(KL) divergence between 𝑞(𝑧, 𝜃, 𝛽) and the true
posterior 𝑝(𝑧, 𝜃, 𝛽|𝑤, 𝛼, 𝜂).
LatentDirichletAllocation implements the online variational Bayes algorithm and supports both online and
batch update methods. While the batch method updates variational variables after each full pass through the data, the
online method updates variational variables from mini-batch data points.

Note: Although the online method is guaranteed to converge to a local optimum point, the quality of the optimum
point and the speed of convergence may depend on mini-batch size and attributes related to learning rate setting.

380 Chapter 3. User Guide


scikit-learn user guide, Release 0.20.3

When LatentDirichletAllocation is applied on a “document-term” matrix, the matrix will be decomposed


into a “topic-term” matrix and a “document-topic” matrix. While “topic-term” matrix is stored as components_ in
the model, “document-topic” matrix can be calculated from transform method.
LatentDirichletAllocation also implements partial_fit method. This is used when data can be fetched
sequentially.

Examples:

• Topic extraction with Non-negative Matrix Factorization and Latent Dirichlet Allocation

References:

• “Latent Dirichlet Allocation” D. Blei, A. Ng, M. Jordan, 2003


• “Online Learning for Latent Dirichlet Allocation” M. Hoffman, D. Blei, F. Bach, 2010
• “Stochastic Variational Inference” M. Hoffman, D. Blei, C. Wang, J. Paisley, 2013

3.2.6 Covariance estimation

Many statistical problems require the estimation of a population’s covariance matrix, which can be seen as an estima-
tion of data set scatter plot shape. Most of the time, such an estimation has to be done on a sample whose properties
(size, structure, homogeneity) have a large influence on the estimation’s quality. The sklearn.covariance package
provides tools for accurately estimating a population’s covariance matrix under various settings.
We assume that the observations are independent and identically distributed (i.i.d.).

Empirical covariance

The covariance matrix of a data set is known to be well approximated by the classical maximum likelihood estimator
(or “empirical covariance”), provided the number of observations is large enough compared to the number of features
(the variables describing the observations). More precisely, the Maximum Likelihood Estimator of a sample is an
unbiased estimator of the corresponding population’s covariance matrix.
The empirical covariance matrix of a sample can be computed using the empirical_covariance function of the
package, or by fitting an EmpiricalCovariance object to the data sample with the EmpiricalCovariance.
fit method. Be careful that results depend on whether the data are centered, so one may want to use the
assume_centered parameter accurately. More precisely, if assume_centered=False, then the test set
is supposed to have the same mean vector as the training set. If not, both should be centered by the user, and
assume_centered=True should be used.

Examples:

• See Shrinkage covariance estimation: LedoitWolf vs OAS and max-likelihood for an example on how to fit an
EmpiricalCovariance object to data.

3.2. Unsupervised learning 381


scikit-learn user guide, Release 0.20.3

Shrunk Covariance

Basic shrinkage

Despite being an unbiased estimator of the covariance matrix, the Maximum Likelihood Estimator is not a good esti-
mator of the eigenvalues of the covariance matrix, so the precision matrix obtained from its inversion is not accurate.
Sometimes, it even occurs that the empirical covariance matrix cannot be inverted for numerical reasons. To avoid
such an inversion problem, a transformation of the empirical covariance matrix has been introduced: the shrinkage.
In scikit-learn, this transformation (with a user-defined shrinkage coefficient) can be directly applied to a pre-computed
covariance with the shrunk_covariance method. Also, a shrunk estimator of the covariance can be fitted to data
with a ShrunkCovariance object and its ShrunkCovariance.fit method. Again, results depend on whether
the data are centered, so one may want to use the assume_centered parameter accurately.
Mathematically, this shrinkage consists in reducing the ratio between the smallest and the largest eigenvalues of the
empirical covariance matrix. It can be done by simply shifting every eigenvalue according to a given offset, which is
equivalent of finding the l2-penalized Maximum Likelihood Estimator of the covariance matrix. In practice, shrinkage
^
boils down to a simple a convex transformation : Σshrunk = (1 − 𝛼)Σ̂ + 𝛼 Tr𝑝Σ Id.
Choosing the amount of shrinkage, 𝛼 amounts to setting a bias/variance trade-off, and is discussed below.

Examples:

• See Shrinkage covariance estimation: LedoitWolf vs OAS and max-likelihood for an example on how to fit a
ShrunkCovariance object to data.

Ledoit-Wolf shrinkage

In their 2004 paper1 , O. Ledoit and M. Wolf propose a formula to compute the optimal shrinkage coefficient 𝛼 that
minimizes the Mean Squared Error between the estimated and the real covariance matrix.
The Ledoit-Wolf estimator of the covariance matrix can be computed on a sample with the ledoit_wolf function of
the sklearn.covariance package, or it can be otherwise obtained by fitting a LedoitWolf object to the same sample.

Note: Case when population covariance matrix is isotropic


It is important to note that when the number of samples is much larger than the number of features, one would expect
that no shrinkage would be necessary. The intuition behind this is that if the population covariance is full rank, when
the number of sample grows, the sample covariance will also become positive definite. As a result, no shrinkage would
necessary and the method should automatically do this.
This, however, is not the case in the Ledoit-Wolf procedure when the population covariance happens to be a multiple of
the identity matrix. In this case, the Ledoit-Wolf shrinkage estimate approaches 1 as the number of samples increases.
This indicates that the optimal estimate of th