diff --git a/Makefile b/Makefile index 20bc4f582e124..8ee4aa14f2b0b 100644 --- a/Makefile +++ b/Makefile @@ -26,9 +26,6 @@ clean: clean-ctags in: inplace # just a shortcut inplace: - # to avoid errors in 0.15 upgrade - rm -f sklearn/utils/sparsefuncs*.so - rm -f sklearn/utils/random*.so $(PYTHON) setup.py build_ext -i test-code: in diff --git a/README.rst b/README.rst index 8d67f2017c1a5..ff9ec69e9baf6 100644 --- a/README.rst +++ b/README.rst @@ -78,7 +78,7 @@ Development We welcome new contributors of all experience levels. The scikit-learn community goals are to be helpful, welcoming, and effective. The -`Contributor's Guide `_ +`Development Guide `_ has detailed information about contributing code, documentation, tests, and more. We've included some basic information in this README. @@ -86,7 +86,7 @@ Important links ~~~~~~~~~~~~~~~ - Official source code repo: https://github.com/scikit-learn/scikit-learn -- Download releases: http://sourceforge.net/projects/scikit-learn/files/ +- Download releases: https://pypi.python.org/pypi/scikit-learn - Issue tracker: https://github.com/scikit-learn/scikit-learn/issues Source code @@ -158,4 +158,4 @@ Communication - Mailing list: https://mail.python.org/mailman/listinfo/scikit-learn - IRC channel: ``#scikit-learn`` at ``irc.freenode.net`` - Stack Overflow: http://stackoverflow.com/questions/tagged/scikit-learn -- Website: http://scikit-learn.org \ No newline at end of file +- Website: http://scikit-learn.org diff --git a/appveyor.yml b/appveyor.yml index 205018f166bf6..8d3b3e7d05b19 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -36,6 +36,16 @@ environment: install: + # If there is a newer build queued for the same PR, cancel this one. + # The AppVeyor 'rollout builds' option is supposed to serve the same + # purpose but is problematic because it tends to cancel builds pushed + # directly to master instead of just PR builds. + # credits: JuliaLang developers. + - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod ` + https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | ` + Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { ` + throw "There are newer queued builds for this pull request, failing early." } + # Install Python (from the official .msi of http://python.org) and pip when # not already installed. - "powershell ./build_tools/appveyor/install.ps1" diff --git a/benchmarks/bench_lof.py b/benchmarks/bench_lof.py new file mode 100644 index 0000000000000..620adc3d43b0c --- /dev/null +++ b/benchmarks/bench_lof.py @@ -0,0 +1,119 @@ +""" +============================ +LocalOutlierFactor benchmark +============================ + +A test of LocalOutlierFactor on classical anomaly detection datasets. + +""" + +from time import time +import numpy as np +import matplotlib.pyplot as plt +from sklearn.neighbors import LocalOutlierFactor +from sklearn.metrics import roc_curve, auc +from sklearn.datasets import fetch_kddcup99, fetch_covtype, fetch_mldata +from sklearn.preprocessing import LabelBinarizer +from sklearn.utils import shuffle as sh + +print(__doc__) + +np.random.seed(2) + +# datasets available: ['http', 'smtp', 'SA', 'SF', 'shuttle', 'forestcover'] +datasets = ['shuttle'] + +novelty_detection = True # if False, training set polluted by outliers + +for dataset_name in datasets: + # loading and vectorization + print('loading data') + if dataset_name in ['http', 'smtp', 'SA', 'SF']: + dataset = fetch_kddcup99(subset=dataset_name, shuffle=True, + percent10=False) + X = dataset.data + y = dataset.target + + if dataset_name == 'shuttle': + dataset = fetch_mldata('shuttle') + X = dataset.data + y = dataset.target + X, y = sh(X, y) + # we remove data with label 4 + # normal data are then those of class 1 + s = (y != 4) + X = X[s, :] + y = y[s] + y = (y != 1).astype(int) + + if dataset_name == 'forestcover': + dataset = fetch_covtype(shuffle=True) + X = dataset.data + y = dataset.target + # normal data are those with attribute 2 + # abnormal those with attribute 4 + s = (y == 2) + (y == 4) + X = X[s, :] + y = y[s] + y = (y != 2).astype(int) + + print('vectorizing data') + + if dataset_name == 'SF': + lb = LabelBinarizer() + lb.fit(X[:, 1]) + x1 = lb.transform(X[:, 1]) + X = np.c_[X[:, :1], x1, X[:, 2:]] + y = (y != 'normal.').astype(int) + + if dataset_name == 'SA': + lb = LabelBinarizer() + lb.fit(X[:, 1]) + x1 = lb.transform(X[:, 1]) + lb.fit(X[:, 2]) + x2 = lb.transform(X[:, 2]) + lb.fit(X[:, 3]) + x3 = lb.transform(X[:, 3]) + X = np.c_[X[:, :1], x1, x2, x3, X[:, 4:]] + y = (y != 'normal.').astype(int) + + if dataset_name == 'http' or dataset_name == 'smtp': + y = (y != 'normal.').astype(int) + + n_samples, n_features = np.shape(X) + n_samples_train = n_samples // 2 + n_samples_test = n_samples - n_samples_train + + X = X.astype(float) + X_train = X[:n_samples_train, :] + X_test = X[n_samples_train:, :] + y_train = y[:n_samples_train] + y_test = y[n_samples_train:] + + if novelty_detection: + X_train = X_train[y_train == 0] + y_train = y_train[y_train == 0] + + print('LocalOutlierFactor processing...') + model = LocalOutlierFactor(n_neighbors=20) + tstart = time() + model.fit(X_train) + fit_time = time() - tstart + tstart = time() + + scoring = -model.decision_function(X_test) # the lower, the more normal + predict_time = time() - tstart + fpr, tpr, thresholds = roc_curve(y_test, scoring) + AUC = auc(fpr, tpr) + plt.plot(fpr, tpr, lw=1, + label=('ROC for %s (area = %0.3f, train-time: %0.2fs,' + 'test-time: %0.2fs)' % (dataset_name, AUC, fit_time, + predict_time))) + +plt.xlim([-0.05, 1.05]) +plt.ylim([-0.05, 1.05]) +plt.xlabel('False Positive Rate') +plt.ylabel('True Positive Rate') +plt.title('Receiver operating characteristic') +plt.legend(loc="lower right") +plt.show() diff --git a/circle.yml b/circle.yml index 2e4fa5c3a9370..74fd2fb53c90b 100644 --- a/circle.yml +++ b/circle.yml @@ -6,7 +6,8 @@ dependencies: # Check whether the doc build is required, install build dependencies and # run sphinx to build the doc. override: - - ./build_tools/circle/build_doc.sh + - ./build_tools/circle/build_doc.sh: + timeout: 3600 # seconds test: # Grep error on the documentation override: diff --git a/doc/conf.py b/doc/conf.py index 9c75922b2a50a..e60fc167f9d49 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -35,6 +35,7 @@ 'numpy_ext.numpydoc', 'sphinx.ext.linkcode', 'sphinx.ext.doctest', 'sphinx_gallery.gen_gallery', + 'sphinx_issues', ] # pngmath / imgmath compatibility layer for different sphinx versions @@ -269,6 +270,13 @@ def make_carousel_thumbs(app, exception): sphinx_gallery.gen_rst.scale_image(image, c_thumb, max_width, 190) +# Config for sphinx_issues + +issues_uri = 'https://github.com/scikit-learn/scikit-learn/issues/{issue}' +issues_github_path = 'scikit-learn/scikit-learn' +issues_user_uri = 'https://github.com/{user}' + + def setup(app): # to hide/show the prompt in code examples: app.add_javascript('js/copybutton.js') diff --git a/doc/documentation.rst b/doc/documentation.rst index 3b5bcd889ccc0..f9e2492fbcdb0 100644 --- a/doc/documentation.rst +++ b/doc/documentation.rst @@ -64,7 +64,7 @@ Documentation of scikit-learn 0.19.dev0
-

Contributing

+

Development

Information on how to contribute. This also contains useful information for advanced users, for example how to build their own estimators. diff --git a/doc/faq.rst b/doc/faq.rst index 7a4a2f2a8fd4a..3937b6a223977 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -248,10 +248,13 @@ 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. This makes it possible to not be subject to this issue -anymore. +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 diff --git a/doc/modules/classes.rst b/doc/modules/classes.rst index 8a077daf018df..a4d893bafb340 100644 --- a/doc/modules/classes.rst +++ b/doc/modules/classes.rst @@ -186,6 +186,7 @@ Splitter Functions :template: function.rst model_selection.train_test_split + model_selection.check_cv Hyper-parameter optimizers -------------------------- @@ -201,6 +202,13 @@ Hyper-parameter optimizers model_selection.ParameterGrid model_selection.ParameterSampler + +.. autosummary:: + :toctree: generated/ + :template: function.rst + + model_selection.fit_grid_point + Model validation ---------------- @@ -315,7 +323,6 @@ Samples generator decomposition.PCA decomposition.IncrementalPCA decomposition.ProjectedGradientNMF - decomposition.RandomizedPCA decomposition.KernelPCA decomposition.FactorAnalysis decomposition.FastICA @@ -560,7 +567,6 @@ From text gaussian_process.GaussianProcessRegressor gaussian_process.GaussianProcessClassifier - gaussian_process.GaussianProcess Kernels: @@ -957,7 +963,6 @@ See the :ref:`metrics` section of the user guide for further details. mixture.GaussianMixture mixture.BayesianGaussianMixture - mixture.DPGMM .. _multiclass_ref: @@ -1051,7 +1056,8 @@ See the :ref:`metrics` section of the user guide for further details. neighbors.LSHForest neighbors.DistanceMetric neighbors.KernelDensity - + neighbors.LocalOutlierFactor + .. autosummary:: :toctree: generated/ :template: function.rst @@ -1349,3 +1355,67 @@ Low-level methods utils.estimator_checks.check_estimator utils.resample utils.shuffle + + +Recently deprecated +=================== + +To be removed in 0.19 +--------------------- + +.. autosummary:: + :toctree: generated/ + :template: deprecated_class.rst + + lda.LDA + qda.QDA + +.. autosummary:: + :toctree: generated/ + :template: deprecated_function.rst + + datasets.load_lfw_pairs + datasets.load_lfw_people + + +To be removed in 0.20 +--------------------- + +.. autosummary:: + :toctree: generated/ + :template: deprecated_class.rst + + grid_search.ParameterGrid + grid_search.ParameterSampler + grid_search.GridSearchCV + grid_search.RandomizedSearchCV + cross_validation.LeaveOneOut + cross_validation.LeavePOut + cross_validation.KFold + cross_validation.LabelKFold + cross_validation.LeaveOneLabelOut + cross_validation.LeavePLabelOut + cross_validation.LabelShuffleSplit + cross_validation.StratifiedKFold + cross_validation.ShuffleSplit + cross_validation.StratifiedShuffleSplit + cross_validation.PredefinedSplit + decomposition.RandomizedPCA + gaussian_process.GaussianProcess + mixture.GMM + mixture.DPGMM + mixture.VBGMM + + +.. autosummary:: + :toctree: generated/ + :template: deprecated_function.rst + + grid_search.fit_grid_point + learning_curve.learning_curve + learning_curve.validation_curve + cross_validation.cross_val_predict + cross_validation.cross_val_score + cross_validation.check_cv + cross_validation.permutation_test_score + cross_validation.train_test_split \ No newline at end of file diff --git a/doc/modules/outlier_detection.rst b/doc/modules/outlier_detection.rst index 6682c97bced55..ee54bef985e71 100644 --- a/doc/modules/outlier_detection.rst +++ b/doc/modules/outlier_detection.rst @@ -165,9 +165,10 @@ This strategy is illustrated below. * See :ref:`sphx_glr_auto_examples_covariance_plot_outlier_detection.py` for a comparison of :class:`ensemble.IsolationForest` with + :class:`neighbors.LocalOutlierFactor`, :class:`svm.OneClassSVM` (tuned to perform like an outlier detection method) and a covariance-based outlier detection with - :class:`covariance.MinCovDet`. + :class:`covariance.EllipticEnvelope`. .. topic:: References: @@ -175,8 +176,65 @@ This strategy is illustrated below. Data Mining, 2008. ICDM'08. Eighth IEEE International Conference on. -One-class SVM versus Elliptic Envelope versus Isolation Forest --------------------------------------------------------------- +Local Outlier Factor +-------------------- +Another efficient way to perform outlier detection on moderately high dimensional +datasets is to use the Local Outlier Factor (LOF) algorithm. + +The :class:`neighbors.LocalOutlierFactor` (LOF) algorithm computes a score +(called local outlier factor) reflecting the degree of abnormality of the +observations. +It measures the local density deviation of a given data point with respect to +its neighbors. The idea is to detect the samples that have a substantially +lower density than their neighbors. + +In practice the local density is obtained from the k-nearest neighbors. +The LOF score of an observation is equal to the ratio of the +average local density of his k-nearest neighbors, and its own local density: +a normal instance is expected to have a local density similar to that of its +neighbors, while abnormal data are expected to have much smaller local density. + +The number k of neighbors considered, (alias parameter n_neighbors) is typically +chosen 1) greater than the minimum number of objects a cluster has to contain, +so that other objects can be local outliers relative to this cluster, and 2) +smaller than the maximum number of close by objects that can potentially be +local outliers. +In practice, such informations are generally not available, and taking +n_neighbors=20 appears to work well in general. +When the proportion of outliers is high (i.e. greater than 10 \%, as in the +example below), n_neighbors should be greater (n_neighbors=35 in the example +below). + +The strength of the LOF algorithm is that it takes both local and global +properties of datasets into consideration: it can perform well even in datasets +where abnormal samples have different underlying densities. +The question is not, how isolated the sample is, but how isolated it is +with respect to the surrounding neighborhood. + +This strategy is illustrated below. + +.. figure:: ../auto_examples/neighbors/images/sphx_glr_plot_lof_001.png + :target: ../auto_examples/neighbors/plot_lof.html + :align: center + :scale: 75% + +.. topic:: Examples: + + * See :ref:`sphx_glr_auto_example_neighbors_plot_lof.py` for + an illustration of the use of :class:`neighbors.LocalOutlierFactor`. + + * See :ref:`sphx_glr_auto_example_covariance_plot_outlier_detection.py` for a + comparison with other anomaly detection methods. + +.. topic:: References: + + .. [BKNS2000] Breunig, Kriegel, Ng, and Sander (2000) + `LOF: identifying density-based local outliers. + `_ + Proc. ACM SIGMOD + +One-class SVM versus Elliptic Envelope versus Isolation Forest versus LOF +------------------------------------------------------------------------- Strictly-speaking, the One-class SVM is not an outlier-detection method, but a novelty-detection method: its training set should not be @@ -188,7 +246,8 @@ results in these situations. The examples below illustrate how the performance of the :class:`covariance.EllipticEnvelope` degrades as the data is less and less unimodal. The :class:`svm.OneClassSVM` works better on data with -multiple modes and :class:`ensemble.IsolationForest` performs well in every cases. +multiple modes and :class:`ensemble.IsolationForest` and +:class:`neighbors.LocalOutlierFactor` perform well in every cases. .. |outlier1| image:: ../auto_examples/covariance/images/sphx_glr_plot_outlier_detection_001.png :target: ../auto_examples/covariance/plot_outlier_detection.html @@ -202,7 +261,7 @@ multiple modes and :class:`ensemble.IsolationForest` performs well in every case :target: ../auto_examples/covariance/plot_outlier_detection.html :scale: 50% -.. list-table:: **Comparing One-class SVM approach, and elliptic envelope** +.. list-table:: **Comparing One-class SVM, Isolation Forest, LOF, and Elliptic Envelope** :widths: 40 60 * @@ -213,16 +272,17 @@ multiple modes and :class:`ensemble.IsolationForest` performs well in every case opposite, the decision rule based on fitting an :class:`covariance.EllipticEnvelope` learns an ellipse, which fits well the inlier distribution. The :class:`ensemble.IsolationForest` - performs as well. - - |outlier1| + and :class:`neighbors.LocalOutlierFactor` perform as well. + - |outlier1| * - As the inlier distribution becomes bimodal, the :class:`covariance.EllipticEnvelope` does not fit well the - inliers. However, we can see that both :class:`ensemble.IsolationForest` - and :class:`svm.OneClassSVM` have difficulties to detect the two modes, + inliers. However, we can see that :class:`ensemble.IsolationForest`, + :class:`svm.OneClassSVM` and :class:`neighbors.LocalOutlierFactor` + have difficulties to detect the two modes, and that the :class:`svm.OneClassSVM` - tends to overfit: because it has not model of inliers, it + tends to overfit: because it has no model of inliers, it interprets a region where, by chance some outliers are clustered, as inliers. - |outlier2| @@ -230,7 +290,8 @@ multiple modes and :class:`ensemble.IsolationForest` performs well in every case * - If the inlier distribution is strongly non Gaussian, the :class:`svm.OneClassSVM` is able to recover a reasonable - approximation as well as :class:`ensemble.IsolationForest`, + approximation as well as :class:`ensemble.IsolationForest` + and :class:`neighbors.LocalOutlierFactor`, whereas the :class:`covariance.EllipticEnvelope` completely fails. - |outlier3| @@ -238,6 +299,6 @@ multiple modes and :class:`ensemble.IsolationForest` performs well in every case * See :ref:`sphx_glr_auto_examples_covariance_plot_outlier_detection.py` for a comparison of the :class:`svm.OneClassSVM` (tuned to perform like - an outlier detection method), the :class:`ensemble.IsolationForest` - and a covariance-based outlier - detection with :class:`covariance.MinCovDet`. + an outlier detection method), the :class:`ensemble.IsolationForest`, + the :class:`neighbors.LocalOutlierFactor` + and a covariance-based outlier detection :class:`covariance.EllipticEnvelope`. diff --git a/doc/sphinxext/sphinx_issues.py b/doc/sphinxext/sphinx_issues.py new file mode 100644 index 0000000000000..27d714bf0b76b --- /dev/null +++ b/doc/sphinxext/sphinx_issues.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +"""A Sphinx extension for linking to your project's issue tracker.""" +""" +Copyright 2014 Steven Loria + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +try: + from docutils import nodes, utils +except ImportError: + # Load lazily so that test-sphinxext does not require docutils dependency + pass + +__version__ = '0.2.0' +__author__ = 'Steven Loria' +__license__ = 'MIT' + + +def user_role(name, rawtext, text, lineno, + inliner, options=None, content=None): + """Sphinx role for linking to a user profile. Defaults to linking to + Github profiles, but the profile URIS can be configured via the + ``issues_user_uri`` config value. + + Example: :: + + :user:`sloria` + """ + options = options or {} + content = content or [] + username = utils.unescape(text).strip() + config = inliner.document.settings.env.app.config + if config.issues_user_uri: + ref = config.issues_user_uri.format(user=username) + else: + ref = 'https://github.com/{0}'.format(username) + text = '@{0}'.format(username) + link = nodes.reference(text=text, refuri=ref, **options) + return [link], [] + + +def _make_issue_node(issue_no, config, options=None): + options = options or {} + if issue_no not in ('-', '0'): + if config.issues_uri: + ref = config.issues_uri.format(issue=issue_no) + elif config.issues_github_path: + ref = 'https://github.com/{0}/issues/{1}'.format( + config.issues_github_path, issue_no + ) + issue_text = '#{0}'.format(issue_no) + link = nodes.reference(text=issue_text, refuri=ref, **options) + else: + link = None + return link + + +def issue_role(name, rawtext, text, lineno, + inliner, options=None, content=None): + """Sphinx role for linking to an issue. Must have + `issues_uri` or `issues_github_path` configured in ``conf.py``. + + Examples: :: + + :issue:`123` + :issue:`42,45` + """ + options = options or {} + content = content or [] + issue_nos = [each.strip() for each in utils.unescape(text).split(',')] + config = inliner.document.settings.env.app.config + ret = [] + for i, issue_no in enumerate(issue_nos): + node = _make_issue_node(issue_no, config, options=options) + ret.append(node) + if i != len(issue_nos) - 1: + sep = nodes.raw(text=', ', format='html') + ret.append(sep) + return ret, [] + + +def setup(app): + # Format template for issues URI + # e.g. 'https://github.com/sloria/marshmallow/issues/{issue} + app.add_config_value('issues_uri', default=None, rebuild='html') + # Shortcut for Github, e.g. 'sloria/marshmallow' + app.add_config_value('issues_github_path', default=None, rebuild='html') + # Format template for user profile URI + # e.g. 'https://github.com/{user}' + app.add_config_value('issues_user_uri', default=None, rebuild='html') + app.add_role('issue', issue_role) + app.add_role('user', user_role) diff --git a/doc/templates/deprecated_class.rst b/doc/templates/deprecated_class.rst new file mode 100644 index 0000000000000..857e2c28ce1da --- /dev/null +++ b/doc/templates/deprecated_class.rst @@ -0,0 +1,23 @@ +:mod:`{{module}}`.{{objname}} +{{ underline }}============== + +.. meta:: + :robots: noindex + +.. warning:: + **DEPRECATED** + + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + + {% block methods %} + .. automethod:: __init__ + {% endblock %} + +.. include:: {{module}}.{{objname}}.examples + +.. raw:: html + +
diff --git a/doc/templates/deprecated_class_with_call.rst b/doc/templates/deprecated_class_with_call.rst new file mode 100644 index 0000000000000..a04efcb80be07 --- /dev/null +++ b/doc/templates/deprecated_class_with_call.rst @@ -0,0 +1,24 @@ +:mod:`{{module}}`.{{objname}} +{{ underline }}=============== + +.. meta:: + :robots: noindex + +.. warning:: + **DEPRECATED** + + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + + {% block methods %} + .. automethod:: __init__ + .. automethod:: __call__ + {% endblock %} + +.. include:: {{module}}.{{objname}}.examples + +.. raw:: html + +
diff --git a/doc/templates/deprecated_class_without_init.rst b/doc/templates/deprecated_class_without_init.rst new file mode 100644 index 0000000000000..c019992493610 --- /dev/null +++ b/doc/templates/deprecated_class_without_init.rst @@ -0,0 +1,19 @@ +:mod:`{{module}}`.{{objname}} +{{ underline }}============== + +.. meta:: + :robots: noindex + +.. warning:: + **DEPRECATED** + + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + +.. include:: {{module}}.{{objname}}.examples + +.. raw:: html + +
diff --git a/doc/templates/deprecated_function.rst b/doc/templates/deprecated_function.rst new file mode 100644 index 0000000000000..6d13ac6aca2de --- /dev/null +++ b/doc/templates/deprecated_function.rst @@ -0,0 +1,19 @@ +:mod:`{{module}}`.{{objname}} +{{ underline }}==================== + +.. meta:: + :robots: noindex + +.. warning:: + **DEPRECATED** + + +.. currentmodule:: {{ module }} + +.. autofunction:: {{ objname }} + +.. include:: {{module}}.{{objname}}.examples + +.. raw:: html + +
diff --git a/doc/templates/generate_deprecated.sh b/doc/templates/generate_deprecated.sh new file mode 100755 index 0000000000000..a7301fb5dc419 --- /dev/null +++ b/doc/templates/generate_deprecated.sh @@ -0,0 +1,8 @@ +#!/bin/bash +for f in [^d]*; do (head -n2 < $f; echo ' +.. meta:: + :robots: noindex + +.. warning:: + **DEPRECATED** +'; tail -n+3 $f) > deprecated_$f; done diff --git a/doc/themes/scikit-learn/layout.html b/doc/themes/scikit-learn/layout.html index 32d40e2291a01..b2c053f6eaf45 100644 --- a/doc/themes/scikit-learn/layout.html +++ b/doc/themes/scikit-learn/layout.html @@ -217,7 +217,7 @@

Machine Learning in Python

- {%- if rellinks[1:] %} + {%- if rellinks %} {%- if parents %}
@@ -225,10 +225,7 @@

Machine Learning in Python

{% endif %} - - - {%- for rellink in rellinks[1:]|reverse %} + {%- for rellink in rellinks|reverse %}