diff --git a/.gitignore b/.gitignore deleted file mode 100644 index a2049825..00000000 --- a/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*.pyc -build/ -dist/ -*.egg-info diff --git a/doc/_static/.gitignore b/.nojekyll similarity index 100% rename from doc/_static/.gitignore rename to .nojekyll diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c90a56ed..00000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: python -sudo: false -python: - - "2.7" -install: - - if [[ "$TRAVIS_PYTHON_VERSION" == 2.* ]]; then - wget http://repo.continuum.io/miniconda/Miniconda-3.4.2-Linux-x86_64.sh -O miniconda.sh; - else - wget http://repo.continuum.io/miniconda/Miniconda3-3.4.2-Linux-x86_64.sh -O miniconda.sh; - fi - - bash miniconda.sh -b -p $HOME/miniconda - - export PATH="$HOME/miniconda/bin:$PATH" - - hash -r - - conda config --set always_yes yes --set changeps1 no - - conda update -q conda - # Useful for debugging any issues with conda - - conda info -a - - - conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION scikit-learn - - source activate test-environment - - python setup.py install -script: python setup.py test diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 0d864db6..00000000 --- a/LICENSE.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2015 CJ Carey and Yuan Tang - -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. \ No newline at end of file diff --git a/README.rst b/README.rst deleted file mode 100644 index f71cc873..00000000 --- a/README.rst +++ /dev/null @@ -1,72 +0,0 @@ -|Travis-CI Build Status| |License| |PyPI version| - -metric-learn -============= - -Metric Learning algorithms in Python. - -**Algorithms** - -- Large Margin Nearest Neighbor (LMNN) -- Information Theoretic Metric Learning (ITML) -- Sparse Determinant Metric Learning (SDML) -- Least Squares Metric Learning (LSML) -- Neighborhood Components Analysis (NCA) -- Local Fisher Discriminant Analysis (LFDA) -- Relative Components Analysis (RCA) - -**Dependencies** - -- Python 2.6+ -- numpy, scipy, scikit-learn -- (for running the examples only: matplotlib) - -**Installation/Setup** - -Run ``pip install metric-learn`` to download and install from PyPI. - -Run ``python setup.py install`` for default installation. - -Run ``python setup.py test`` to run all tests. - -**Usage** - -For full usage examples, see the ``test`` and ``examples`` directories. - -Each metric is a subclass of ``BaseMetricLearner``, which provides -default implementations for the methods ``metric``, ``transformer``, and -``transform``. Subclasses must provide an implementation for either -``metric`` or ``transformer``. - -For an instance of a metric learner named ``foo`` learning from a set of -``d``-dimensional points, ``foo.metric()`` returns a ``d`` by ``d`` -matrix ``M`` such that a distance between vectors ``x`` and ``y`` is -expressed ``(x-y).dot(M).dot(x-y)``. - -In the same scenario, ``foo.transformer()`` returns a ``d`` by ``d`` -matrix ``L`` such that a vector ``x`` can be represented in the learned -space as the vector ``L.dot(x)``. - -For convenience, the function ``foo.transform(X)`` is provided for -converting a matrix of points (``X``) into the learned space, in which -standard Euclidean distance can be used. - -**Notes** - -If a recent version of the Shogun Python modular (``modshogun``) library -is available, the LMNN implementation will use the fast C++ version from -there. The two implementations differ slightly, and the C++ version is -more complete. - -**TODO** - -- implement the rest of the methods on `this site`_ - -.. _this site: http://www.cs.cmu.edu/~liuy/distlearn.htm - -.. |Travis-CI Build Status| image:: https://api.travis-ci.org/all-umass/metric-learn.svg?branch=master - :target: https://travis-ci.org/all-umass/metric-learn -.. |License| image:: http://img.shields.io/:license-mit-blue.svg?style=flat - :target: http://badges.mit-license.org -.. |PyPI version| image:: https://badge.fury.io/py/metric-learn.svg - :target: http://badge.fury.io/py/metric-learn \ No newline at end of file diff --git a/_downloads/07fcc19ba03226cd3d83d4e40ec44385/auto_examples_python.zip b/_downloads/07fcc19ba03226cd3d83d4e40ec44385/auto_examples_python.zip new file mode 100644 index 00000000..f5712a9c Binary files /dev/null and b/_downloads/07fcc19ba03226cd3d83d4e40ec44385/auto_examples_python.zip differ diff --git a/_downloads/4f011433714ef22e0c66be75bbfd08e3/plot_sandwich.ipynb b/_downloads/4f011433714ef22e0c66be75bbfd08e3/plot_sandwich.ipynb new file mode 100644 index 00000000..e317ca93 --- /dev/null +++ b/_downloads/4f011433714ef22e0c66be75bbfd08e3/plot_sandwich.ipynb @@ -0,0 +1,50 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Sandwich demo\n\nSandwich demo based on code from http://nbviewer.ipython.org/6576096\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Note

In order to show the charts of the examples you need a graphical\n ``matplotlib`` backend installed. For intance, use ``pip install pyqt5``\n to get Qt graphical interface or use your favorite one.

\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\nfrom matplotlib import pyplot as plt\nfrom sklearn.metrics import pairwise_distances\nfrom sklearn.neighbors import NearestNeighbors\n\nfrom metric_learn import (LMNN, ITML_Supervised, LSML_Supervised,\n SDML_Supervised)\n\n\ndef sandwich_demo():\n x, y = sandwich_data()\n knn = nearest_neighbors(x, k=2)\n ax = plt.subplot(3, 1, 1) # take the whole top row\n plot_sandwich_data(x, y, ax)\n plot_neighborhood_graph(x, knn, y, ax)\n ax.set_title('input space')\n ax.set_aspect('equal')\n ax.set_xticks([])\n ax.set_yticks([])\n\n mls = [\n LMNN(),\n ITML_Supervised(n_constraints=200),\n SDML_Supervised(n_constraints=200, balance_param=0.001),\n LSML_Supervised(n_constraints=200),\n ]\n\n for ax_num, ml in enumerate(mls, start=3):\n ml.fit(x, y)\n tx = ml.transform(x)\n ml_knn = nearest_neighbors(tx, k=2)\n ax = plt.subplot(3, 2, ax_num)\n plot_sandwich_data(tx, y, axis=ax)\n plot_neighborhood_graph(tx, ml_knn, y, axis=ax)\n ax.set_title(ml.__class__.__name__)\n ax.set_xticks([])\n ax.set_yticks([])\n plt.show()\n\n\n# TODO: use this somewhere\ndef visualize_class_separation(X, labels):\n _, (ax1, ax2) = plt.subplots(ncols=2)\n label_order = np.argsort(labels)\n ax1.imshow(pairwise_distances(X[label_order]), interpolation='nearest')\n ax2.imshow(pairwise_distances(labels[label_order, None]),\n interpolation='nearest')\n\n\ndef nearest_neighbors(X, k=5):\n knn = NearestNeighbors(n_neighbors=k)\n knn.fit(X)\n return knn.kneighbors(X, return_distance=False)\n\n\ndef sandwich_data():\n # number of distinct classes\n num_classes = 6\n # number of points per class\n num_points = 9\n # distance between layers, the points of each class are in a layer\n dist = 0.7\n\n data = np.zeros((num_classes, num_points, 2), dtype=float)\n labels = np.zeros((num_classes, num_points), dtype=int)\n\n x_centers = np.arange(num_points, dtype=float) - num_points / 2\n y_centers = dist * (np.arange(num_classes, dtype=float) - num_classes / 2)\n for i, yc in enumerate(y_centers):\n for k, xc in enumerate(x_centers):\n data[i, k, 0] = np.random.normal(xc, 0.1)\n data[i, k, 1] = np.random.normal(yc, 0.1)\n labels[i, :] = i\n return data.reshape((-1, 2)), labels.ravel()\n\n\ndef plot_sandwich_data(x, y, axis=plt, colors='rbgmky'):\n for idx, val in enumerate(np.unique(y)):\n xi = x[y == val]\n axis.scatter(*xi.T, s=50, facecolors='none', edgecolors=colors[idx])\n\n\ndef plot_neighborhood_graph(x, nn, y, axis=plt, colors='rbgmky'):\n for i, a in enumerate(x):\n b = x[nn[i, 1]]\n axis.plot((a[0], b[0]), (a[1], b[1]), colors[y[i]])\n\n\nif __name__ == '__main__':\n sandwich_demo()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/_downloads/6f1e7a639e0699d6164445b55e6c116d/auto_examples_jupyter.zip b/_downloads/6f1e7a639e0699d6164445b55e6c116d/auto_examples_jupyter.zip new file mode 100644 index 00000000..43f923f4 Binary files /dev/null and b/_downloads/6f1e7a639e0699d6164445b55e6c116d/auto_examples_jupyter.zip differ diff --git a/_downloads/a6bf7d7136399675f28d77d001faa48f/plot_sandwich.py b/_downloads/a6bf7d7136399675f28d77d001faa48f/plot_sandwich.py new file mode 100644 index 00000000..740852be --- /dev/null +++ b/_downloads/a6bf7d7136399675f28d77d001faa48f/plot_sandwich.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +""" +Sandwich demo +============= + +Sandwich demo based on code from http://nbviewer.ipython.org/6576096 +""" + +###################################################################### +# .. note:: +# +# In order to show the charts of the examples you need a graphical +# ``matplotlib`` backend installed. For intance, use ``pip install pyqt5`` +# to get Qt graphical interface or use your favorite one. + +import numpy as np +from matplotlib import pyplot as plt +from sklearn.metrics import pairwise_distances +from sklearn.neighbors import NearestNeighbors + +from metric_learn import (LMNN, ITML_Supervised, LSML_Supervised, + SDML_Supervised) + + +def sandwich_demo(): + x, y = sandwich_data() + knn = nearest_neighbors(x, k=2) + ax = plt.subplot(3, 1, 1) # take the whole top row + plot_sandwich_data(x, y, ax) + plot_neighborhood_graph(x, knn, y, ax) + ax.set_title('input space') + ax.set_aspect('equal') + ax.set_xticks([]) + ax.set_yticks([]) + + mls = [ + LMNN(), + ITML_Supervised(n_constraints=200), + SDML_Supervised(n_constraints=200, balance_param=0.001), + LSML_Supervised(n_constraints=200), + ] + + for ax_num, ml in enumerate(mls, start=3): + ml.fit(x, y) + tx = ml.transform(x) + ml_knn = nearest_neighbors(tx, k=2) + ax = plt.subplot(3, 2, ax_num) + plot_sandwich_data(tx, y, axis=ax) + plot_neighborhood_graph(tx, ml_knn, y, axis=ax) + ax.set_title(ml.__class__.__name__) + ax.set_xticks([]) + ax.set_yticks([]) + plt.show() + + +# TODO: use this somewhere +def visualize_class_separation(X, labels): + _, (ax1, ax2) = plt.subplots(ncols=2) + label_order = np.argsort(labels) + ax1.imshow(pairwise_distances(X[label_order]), interpolation='nearest') + ax2.imshow(pairwise_distances(labels[label_order, None]), + interpolation='nearest') + + +def nearest_neighbors(X, k=5): + knn = NearestNeighbors(n_neighbors=k) + knn.fit(X) + return knn.kneighbors(X, return_distance=False) + + +def sandwich_data(): + # number of distinct classes + num_classes = 6 + # number of points per class + num_points = 9 + # distance between layers, the points of each class are in a layer + dist = 0.7 + + data = np.zeros((num_classes, num_points, 2), dtype=float) + labels = np.zeros((num_classes, num_points), dtype=int) + + x_centers = np.arange(num_points, dtype=float) - num_points / 2 + y_centers = dist * (np.arange(num_classes, dtype=float) - num_classes / 2) + for i, yc in enumerate(y_centers): + for k, xc in enumerate(x_centers): + data[i, k, 0] = np.random.normal(xc, 0.1) + data[i, k, 1] = np.random.normal(yc, 0.1) + labels[i, :] = i + return data.reshape((-1, 2)), labels.ravel() + + +def plot_sandwich_data(x, y, axis=plt, colors='rbgmky'): + for idx, val in enumerate(np.unique(y)): + xi = x[y == val] + axis.scatter(*xi.T, s=50, facecolors='none', edgecolors=colors[idx]) + + +def plot_neighborhood_graph(x, nn, y, axis=plt, colors='rbgmky'): + for i, a in enumerate(x): + b = x[nn[i, 1]] + axis.plot((a[0], b[0]), (a[1], b[1]), colors[y[i]]) + + +if __name__ == '__main__': + sandwich_demo() diff --git a/_downloads/bd873dc20743b4004d594a33f6abf089/plot_metric_learning_examples.py b/_downloads/bd873dc20743b4004d594a33f6abf089/plot_metric_learning_examples.py new file mode 100644 index 00000000..32759636 --- /dev/null +++ b/_downloads/bd873dc20743b4004d594a33f6abf089/plot_metric_learning_examples.py @@ -0,0 +1,495 @@ +""" +Algorithms walkthrough +~~~~~~~~~~~~~~~~~~~~~~ + +This is a small walkthrough which illustrates most of the Metric Learning +algorithms implemented in metric-learn by using them on synthetic data, +with some visualizations to provide intuitions into what they are designed +to achieve. +""" + +# License: BSD 3 clause +# Authors: Bhargav Srinivasa Desikan +# William de Vazelhes + +###################################################################### +# Imports +# ^^^^^^^ +# .. note:: +# +# In order to show the charts of the examples you need a graphical +# ``matplotlib`` backend installed. For intance, use ``pip install pyqt5`` +# to get Qt graphical interface or use your favorite one. + +from sklearn.manifold import TSNE + +import metric_learn +import numpy as np +from sklearn.datasets import make_classification, make_regression + +# visualisation imports +import matplotlib.pyplot as plt +np.random.seed(42) + + +###################################################################### +# Loading our dataset and setting up plotting +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# We will be using a synthetic dataset to illustrate the plotting, +# using the function `sklearn.datasets.make_classification` from +# scikit-learn. The dataset will contain: +# - 100 points in 3 classes with 2 clusters per class +# - 5 features, among which 3 are informative (correlated with the class +# labels) and two are random noise with large magnitude + +X, y = make_classification(n_samples=100, n_classes=3, n_clusters_per_class=2, + n_informative=3, class_sep=4., n_features=5, + n_redundant=0, shuffle=True, + scale=[1, 1, 20, 20, 20]) + +########################################################################### +# Note that the dimensionality of the data is 5, so to plot the +# transformed data in 2D, we will use the t-sne algorithm. (See +# `sklearn.manifold.TSNE`). + + +def plot_tsne(X, y, colormap=plt.cm.Paired): + plt.figure(figsize=(8, 6)) + + # clean the figure + plt.clf() + + tsne = TSNE() + X_embedded = tsne.fit_transform(X) + plt.scatter(X_embedded[:, 0], X_embedded[:, 1], c=y, cmap=colormap) + + plt.xticks(()) + plt.yticks(()) + + plt.show() + +################################### +# Let's now plot the dataset as is. + + +plot_tsne(X, y) + +######################################################################### +# We can see that the classes appear mixed up: this is because t-sne +# is based on preserving the original neighborhood of points in the embedding +# space, but this original neighborhood is based on the euclidean +# distance in the input space, in which the contribution of the noisy +# features is high. So even if points from the same class are close to each +# other in some subspace of the input space, this is not the case when +# considering all dimensions of the input space. +# +# Metric Learning +# ^^^^^^^^^^^^^^^ +# +# Why is Metric Learning useful? We can, with prior knowledge of which +# points are supposed to be closer, figure out a better way to compute +# distances between points for the task at hand. Especially in higher +# dimensions when Euclidean distances are a poor way to measure distance, this +# becomes very useful. +# +# Basically, we learn this distance: +# :math:`D(x, x') = \sqrt{(x-x')^\top M(x-x')}`. And we learn the parameters +# :math:`M` of this distance to satisfy certain constraints on the distance +# between points, for example requiring that points of the same class are +# close together and points of different class are far away. +# +# For more information, check the :ref:`intro_metric_learning` section +# from the documentation. Some good reading material can also be found +# `here `__. It serves as a +# good literature review of Metric Learning. +# +# We will briefly explain the metric learning algorithms implemented by +# metric-learn, before providing some examples for its usage, and also +# discuss how to perform metric learning with weaker supervision than class +# labels. +# +# Metric-learn can be easily integrated with your other machine learning +# pipelines, and follows scikit-learn conventions. +# + + +###################################################################### +# Large Margin Nearest Neighbour +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# LMNN is a metric learning algorithm primarily designed for k-nearest +# neighbor classification. The algorithm is based on semidefinite +# programming, a sub-class of convex programming (as most Metric Learning +# algorithms are). +# +# The main intuition behind LMNN is to learn a pseudometric under which +# all data instances in the training set are surrounded by at least k +# instances that share the same class label. If this is achieved, the +# leave-one-out error (a special case of cross validation) is minimized. +# You'll notice that the points from the same labels are closer together, +# but they are not necessary in a same cluster. This is particular to LMNN +# and we'll see that some other algorithms implicitly enforce points from +# the same class to cluster together. +# +# - See more in the :ref:`User Guide ` +# - See more in the documentation of the class :py:class:`LMNN +# ` + + +###################################################################### +# Fit and then transform! +# ----------------------- +# + +# setting up LMNN +lmnn = metric_learn.LMNN(n_neighbors=5, learn_rate=1e-6) + +# fit the data! +lmnn.fit(X, y) + +# transform our input space +X_lmnn = lmnn.transform(X) + + +###################################################################### +# So what have we learned? The matrix :math:`M` we talked about before. + + +###################################################################### +# Now let us plot the transformed space - this tells us what the original +# space looks like after being transformed with the new learned metric. +# + +plot_tsne(X_lmnn, y) + + +###################################################################### +# Pretty neat, huh? +# +# The rest of this notebook will briefly explain the other Metric Learning +# algorithms before plotting them. Also, while we have first run ``fit`` +# and then ``transform`` to see our data transformed, we can also use +# ``fit_transform``. The rest of the examples and illustrations will use +# ``fit_transform``. + +###################################################################### +# Information Theoretic Metric Learning +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# ITML uses a regularizer that automatically enforces a Semi-Definite +# Positive Matrix condition - the LogDet divergence. It uses soft +# must-link or cannot-link constraints, and a simple algorithm based on +# Bregman projections. Unlike LMNN, ITML will implicitly enforce points from +# the same class to belong to the same cluster, as you can see below. +# +# - See more in the :ref:`User Guide ` +# - See more in the documentation of the class :py:class:`ITML +# ` + +itml = metric_learn.ITML_Supervised() +X_itml = itml.fit_transform(X, y) + +plot_tsne(X_itml, y) + + +###################################################################### +# Mahalanobis Metric for Clustering +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# MMC is an algorithm that will try to minimize the distance between similar +# points, while ensuring that the sum of distances between dissimilar points is +# higher than a threshold. This is done by optimizing a cost function +# subject to an inequality constraint. +# +# - See more in the :ref:`User Guide ` +# - See more in the documentation of the class :py:class:`MMC +# ` + +mmc = metric_learn.MMC_Supervised() +X_mmc = mmc.fit_transform(X, y) + +plot_tsne(X_mmc, y) + +###################################################################### +# Sparse Determinant Metric Learning +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# Implements an efficient sparse metric learning algorithm in high +# dimensional space via an :math:`l_1`-penalized log-determinant +# regularization. Compared to the most existing distance metric learning +# algorithms, the algorithm exploits the sparsity nature underlying the +# intrinsic high dimensional feature space. +# +# - See more in the :ref:`User Guide ` +# - See more in the documentation of the class :py:class:`SDML +# ` + +sdml = metric_learn.SDML_Supervised(sparsity_param=0.1, balance_param=0.0015, + prior='covariance') +X_sdml = sdml.fit_transform(X, y) + +plot_tsne(X_sdml, y) + + +###################################################################### +# Least Squares Metric Learning +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# LSML is a simple, yet effective, algorithm that learns a Mahalanobis +# metric from a given set of relative comparisons. This is done by +# formulating and minimizing a convex loss function that corresponds to +# the sum of squared hinge loss of violated constraints. +# +# - See more in the :ref:`User Guide ` +# - See more in the documentation of the class :py:class:`LSML +# ` + +lsml = metric_learn.LSML_Supervised(tol=0.0001, max_iter=10000, + prior='covariance') +X_lsml = lsml.fit_transform(X, y) + +plot_tsne(X_lsml, y) + + +###################################################################### +# Neighborhood Components Analysis +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# NCA is an extremly popular metric learning algorithm. +# +# Neighborhood components analysis aims at "learning" a distance metric +# by finding a linear transformation of input data such that the average +# leave-one-out (LOO) classification performance of a soft-nearest +# neighbors rule is maximized in the transformed space. The key insight to +# the algorithm is that a matrix :math:`A` corresponding to the +# transformation can be found by defining a differentiable objective function +# for :math:`A`, followed by use of an iterative solver such as +# `scipy.optimize.fmin_l_bfgs_b`. Like LMNN, this algorithm does not try to +# cluster points from the same class in a unique cluster, because it +# enforces conditions at a local neighborhood scale. +# +# - See more in the :ref:`User Guide ` +# - See more in the documentation of the class :py:class:`NCA +# ` + +nca = metric_learn.NCA(max_iter=1000) +X_nca = nca.fit_transform(X, y) + +plot_tsne(X_nca, y) + +###################################################################### +# Local Fisher Discriminant Analysis +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# LFDA is a linear supervised dimensionality reduction method. It is +# particularly useful when dealing with multimodality, where one ore more +# classes consist of separate clusters in input space. The core +# optimization problem of LFDA is solved as a generalized eigenvalue +# problem. Like LMNN, and NCA, this algorithm does not try to cluster points +# from the same class in a unique cluster. +# +# - See more in the :ref:`User Guide ` +# - See more in the documentation of the class :py:class:`LFDA +# ` + +lfda = metric_learn.LFDA(k=2, n_components=2) +X_lfda = lfda.fit_transform(X, y) + +plot_tsne(X_lfda, y) + + +###################################################################### +# Relative Components Analysis +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# RCA is another one of the older algorithms. It learns a full rank +# Mahalanobis distance metric based on a weighted sum of in-class +# covariance matrices. It applies a global linear transformation to assign +# large weights to relevant dimensions and low weights to irrelevant +# dimensions. Those relevant dimensions are estimated using "chunklets", +# subsets of points that are known to belong to the same class. +# +# - See more in the :ref:`User Guide ` +# - See more in the documentation of the class :py:class:`RCA +# ` + +rca = metric_learn.RCA_Supervised(n_chunks=30, chunk_size=2) +X_rca = rca.fit_transform(X, y) + +plot_tsne(X_rca, y) + +###################################################################### +# Regression example: Metric Learning for Kernel Regression +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# The previous algorithms took as input a dataset with class labels. Metric +# learning can also be useful for regression, when the labels are real numbers. +# An algorithm very similar to NCA but for regression is Metric +# Learning for Kernel Regression (MLKR). It will optimize for the average +# leave-one-out *regression* performance from a soft-nearest neighbors +# regression. +# +# - See more in the :ref:`User Guide ` +# - See more in the documentation of the class :py:class:`MLKR +# ` +# +# To illustrate MLKR, let's use the dataset +# `sklearn.datasets.make_regression` the same way as we did with the +# classification before. The dataset will contain: 100 points of 5 features +# each, among which 3 are informative (i.e., used to generate the +# regression target from a linear model), and two are random noise with the +# same magnitude. + +X_reg, y_reg = make_regression(n_samples=100, n_informative=3, n_features=5, + shuffle=True) + +###################################################################### +# Let's plot the dataset as is + +plot_tsne(X_reg, y_reg, plt.cm.Oranges) + +###################################################################### +# And let's plot the dataset after transformation by MLKR: +mlkr = metric_learn.MLKR() +X_mlkr = mlkr.fit_transform(X_reg, y_reg) +plot_tsne(X_mlkr, y_reg, plt.cm.Oranges) + +###################################################################### +# Points that have the same value to regress are now closer to each +# other ! This would improve the performance of +# `sklearn.neighbors.KNeighborsRegressor` for instance. + + +###################################################################### +# Metric Learning from Weaker Supervision +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# To learn the metric, so far we have always given the labels of the +# data to supervise the algorithms. However, in many applications, +# it is easier to obtain information about whether two samples are +# similar or dissimilar. For instance, when annotating a dataset of face +# images, it is easier for an annotator to tell if two faces belong to the same +# person or not, rather than finding the ID of the face among a huge database +# of every person's faces. +# Note that for some problems (e.g., in information +# retrieval where the goal is to rank documents by similarity to a query +# document), there is no notion of individual label but one can gather +# information on which pairs of points are similar or dissimilar. +# Fortunately, one of the strength of metric learning is the ability to +# learn from such weaker supervision. Indeed, some of the algorithms we've +# used above have alternate ways to pass some supervision about the metric +# we want to learn. The way to go is to pass a 2D array `pairs` of pairs, +# as well as an array of labels `pairs_labels` such that for each `i` between +# `0` and `n_pairs` we want `X[pairs[i, 0], :]` and `X[pairs[i, 1], :]` to be +# similar if `pairs_labels[i] == 1`, and we want them to be dissimilar if +# `pairs_labels[i] == -1`. In other words, we +# want to enforce a metric that projects similar points closer together and +# dissimilar points further away from each other. This kind of input is +# possible for ITML, SDML, and MMC. See :ref:`weakly_supervised_section` for +# details on other kinds of weak supervision that some algorithms can work +# with. +# +# For the purpose of this example, we're going to explicitly create these +# pairwise constraints through the labels we have, i.e. `y`. +# Do keep in mind that we are doing this method because we know the labels +# - we can actually create the constraints any way we want to depending on +# the data! +# +# Note that this is what metric-learn did under the hood in the previous +# examples (do check out the +# `constraints` module!) - but we'll try our own version of this. We're +# going to go ahead and assume that two points labeled the same will be +# closer than two points in different labels. + + +def create_constraints(labels): + import itertools + import random + + # aggregate indices of same class + zeros = np.where(y == 0)[0] + ones = np.where(y == 1)[0] + twos = np.where(y == 2)[0] + # make permutations of all those points in the same class + zeros_ = list(itertools.combinations(zeros, 2)) + ones_ = list(itertools.combinations(ones, 2)) + twos_ = list(itertools.combinations(twos, 2)) + # put them together! + sim = np.array(zeros_ + ones_ + twos_) + + # similarily, put together indices in different classes + dis = [] + for zero in zeros: + for one in ones: + dis.append((zero, one)) + for two in twos: + dis.append((zero, two)) + for one in ones: + for two in twos: + dis.append((one, two)) + + # pick up just enough dissimilar examples as we have similar examples + dis = np.array(random.sample(dis, len(sim))) + + # return an array of pairs of indices of shape=(2*len(sim), 2), and the + # corresponding labels, array of shape=(2*len(sim)) + # Each pair of similar points have a label of +1 and each pair of + # dissimilar points have a label of -1 + return (np.vstack([np.column_stack([sim[:, 0], sim[:, 1]]), + np.column_stack([dis[:, 0], dis[:, 1]])]), + np.concatenate([np.ones(len(sim)), -np.ones(len(sim))])) + + +pairs, pairs_labels = create_constraints(y) + + +###################################################################### +# Now that we've created our constraints, let's see what it looks like! +# + +print(pairs) +print(pairs_labels) + + +###################################################################### +# Using our constraints, let's now train ITML again. Note that we are no +# longer calling the supervised class :py:class:`ITML_Supervised +# ` but the more generic +# (weakly-supervised) :py:class:`ITML `, which +# takes the dataset `X` through the `preprocessor` argument (see +# :ref:`this section ` of the documentation to learn +# about more advanced uses of `preprocessor`) and the pair information `pairs` +# and `pairs_labels` in the fit method. + +itml = metric_learn.ITML(preprocessor=X) +itml.fit(pairs, pairs_labels) + +X_itml = itml.transform(X) + +plot_tsne(X_itml, y) + + +###################################################################### +# And that's the result of ITML after being trained on our manually +# constructed constraints! A bit different from our old result, but not too +# different. +# +# RCA and LSML also have their own specific ways of taking in inputs - +# it's worth one's while to poke around in the constraints.py file to see +# how exactly this is going on. +# +# Finally, one of the main advantages of metric-learn is its out-of-the box +# compatibility with scikit-learn, for doing `model selection +# `__, +# cross-validation, and scoring for instance. Indeed, supervised algorithms are +# regular `sklearn.base.TransformerMixin` that can be plugged into any +# pipeline or cross-validation procedure. And weakly-supervised estimators are +# also compatible with scikit-learn, since their input dataset format described +# above allows to be sliced along the first dimension when doing +# cross-validations (see also this :ref:`section `). You +# can also look at some :ref:`use cases ` where you could combine +# metric-learn with scikit-learn estimators. + +######################################################################## +# This brings us to the end of this tutorial! Have fun Metric Learning :) diff --git a/_downloads/ddf41593144dd5f65569fa0eb7654029/plot_metric_learning_examples.ipynb b/_downloads/ddf41593144dd5f65569fa0eb7654029/plot_metric_learning_examples.ipynb new file mode 100644 index 00000000..5ec19486 --- /dev/null +++ b/_downloads/ddf41593144dd5f65569fa0eb7654029/plot_metric_learning_examples.ipynb @@ -0,0 +1,434 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Algorithms walkthrough\n\nThis is a small walkthrough which illustrates most of the Metric Learning\nalgorithms implemented in metric-learn by using them on synthetic data,\nwith some visualizations to provide intuitions into what they are designed\nto achieve.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# License: BSD 3 clause\n# Authors: Bhargav Srinivasa Desikan \n# William de Vazelhes " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports\n

Note

In order to show the charts of the examples you need a graphical\n ``matplotlib`` backend installed. For intance, use ``pip install pyqt5``\n to get Qt graphical interface or use your favorite one.

\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from sklearn.manifold import TSNE\n\nimport metric_learn\nimport numpy as np\nfrom sklearn.datasets import make_classification, make_regression\n\n# visualisation imports\nimport matplotlib.pyplot as plt\nnp.random.seed(42)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading our dataset and setting up plotting\n\nWe will be using a synthetic dataset to illustrate the plotting,\nusing the function `sklearn.datasets.make_classification` from\nscikit-learn. The dataset will contain:\n- 100 points in 3 classes with 2 clusters per class\n- 5 features, among which 3 are informative (correlated with the class\nlabels) and two are random noise with large magnitude\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "X, y = make_classification(n_samples=100, n_classes=3, n_clusters_per_class=2,\n n_informative=3, class_sep=4., n_features=5,\n n_redundant=0, shuffle=True,\n scale=[1, 1, 20, 20, 20])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that the dimensionality of the data is 5, so to plot the\ntransformed data in 2D, we will use the t-sne algorithm. (See\n`sklearn.manifold.TSNE`).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def plot_tsne(X, y, colormap=plt.cm.Paired):\n plt.figure(figsize=(8, 6))\n\n # clean the figure\n plt.clf()\n\n tsne = TSNE()\n X_embedded = tsne.fit_transform(X)\n plt.scatter(X_embedded[:, 0], X_embedded[:, 1], c=y, cmap=colormap)\n\n plt.xticks(())\n plt.yticks(())\n\n plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's now plot the dataset as is.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "plot_tsne(X, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that the classes appear mixed up: this is because t-sne\nis based on preserving the original neighborhood of points in the embedding\nspace, but this original neighborhood is based on the euclidean\ndistance in the input space, in which the contribution of the noisy\nfeatures is high. So even if points from the same class are close to each\nother in some subspace of the input space, this is not the case when\nconsidering all dimensions of the input space.\n\n## Metric Learning\n\nWhy is Metric Learning useful? We can, with prior knowledge of which\npoints are supposed to be closer, figure out a better way to compute\ndistances between points for the task at hand. Especially in higher\ndimensions when Euclidean distances are a poor way to measure distance, this\nbecomes very useful.\n\nBasically, we learn this distance:\n$D(x, x') = \\sqrt{(x-x')^\\top M(x-x')}$. And we learn the parameters\n$M$ of this distance to satisfy certain constraints on the distance\nbetween points, for example requiring that points of the same class are\nclose together and points of different class are far away.\n\nFor more information, check the `intro_metric_learning` section\nfrom the documentation. Some good reading material can also be found\n[here](https://arxiv.org/pdf/1306.6709.pdf)_. It serves as a\ngood literature review of Metric Learning.\n\nWe will briefly explain the metric learning algorithms implemented by\nmetric-learn, before providing some examples for its usage, and also\ndiscuss how to perform metric learning with weaker supervision than class\nlabels.\n\nMetric-learn can be easily integrated with your other machine learning\npipelines, and follows scikit-learn conventions.\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Large Margin Nearest Neighbour\n\nLMNN is a metric learning algorithm primarily designed for k-nearest\nneighbor classification. The algorithm is based on semidefinite\nprogramming, a sub-class of convex programming (as most Metric Learning\nalgorithms are).\n\nThe main intuition behind LMNN is to learn a pseudometric under which\nall data instances in the training set are surrounded by at least k\ninstances that share the same class label. If this is achieved, the\nleave-one-out error (a special case of cross validation) is minimized.\nYou'll notice that the points from the same labels are closer together,\nbut they are not necessary in a same cluster. This is particular to LMNN\nand we'll see that some other algorithms implicitly enforce points from\nthe same class to cluster together.\n\n- See more in the `User Guide `\n- See more in the documentation of the class :py:class:`LMNN\n `\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Fit and then transform!\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# setting up LMNN\nlmnn = metric_learn.LMNN(n_neighbors=5, learn_rate=1e-6)\n\n# fit the data!\nlmnn.fit(X, y)\n\n# transform our input space\nX_lmnn = lmnn.transform(X)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So what have we learned? The matrix $M$ we talked about before.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let us plot the transformed space - this tells us what the original\nspace looks like after being transformed with the new learned metric.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "plot_tsne(X_lmnn, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pretty neat, huh?\n\nThe rest of this notebook will briefly explain the other Metric Learning\nalgorithms before plotting them. Also, while we have first run ``fit``\nand then ``transform`` to see our data transformed, we can also use\n``fit_transform``. The rest of the examples and illustrations will use\n``fit_transform``.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Information Theoretic Metric Learning\n\nITML uses a regularizer that automatically enforces a Semi-Definite\nPositive Matrix condition - the LogDet divergence. It uses soft\nmust-link or cannot-link constraints, and a simple algorithm based on\nBregman projections. Unlike LMNN, ITML will implicitly enforce points from\nthe same class to belong to the same cluster, as you can see below.\n\n- See more in the `User Guide `\n- See more in the documentation of the class :py:class:`ITML\n `\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "itml = metric_learn.ITML_Supervised()\nX_itml = itml.fit_transform(X, y)\n\nplot_tsne(X_itml, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mahalanobis Metric for Clustering\n\nMMC is an algorithm that will try to minimize the distance between similar\npoints, while ensuring that the sum of distances between dissimilar points is\nhigher than a threshold. This is done by optimizing a cost function\nsubject to an inequality constraint.\n\n- See more in the `User Guide `\n- See more in the documentation of the class :py:class:`MMC\n `\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "mmc = metric_learn.MMC_Supervised()\nX_mmc = mmc.fit_transform(X, y)\n\nplot_tsne(X_mmc, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sparse Determinant Metric Learning\n\nImplements an efficient sparse metric learning algorithm in high\ndimensional space via an $l_1$-penalized log-determinant\nregularization. Compared to the most existing distance metric learning\nalgorithms, the algorithm exploits the sparsity nature underlying the\nintrinsic high dimensional feature space.\n\n- See more in the `User Guide `\n- See more in the documentation of the class :py:class:`SDML\n `\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sdml = metric_learn.SDML_Supervised(sparsity_param=0.1, balance_param=0.0015,\n prior='covariance')\nX_sdml = sdml.fit_transform(X, y)\n\nplot_tsne(X_sdml, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Least Squares Metric Learning\n\nLSML is a simple, yet effective, algorithm that learns a Mahalanobis\nmetric from a given set of relative comparisons. This is done by\nformulating and minimizing a convex loss function that corresponds to\nthe sum of squared hinge loss of violated constraints.\n\n- See more in the `User Guide `\n- See more in the documentation of the class :py:class:`LSML\n `\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "lsml = metric_learn.LSML_Supervised(tol=0.0001, max_iter=10000,\n prior='covariance')\nX_lsml = lsml.fit_transform(X, y)\n\nplot_tsne(X_lsml, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Neighborhood Components Analysis\n\nNCA is an extremly popular metric learning algorithm.\n\nNeighborhood components analysis aims at \"learning\" a distance metric\nby finding a linear transformation of input data such that the average\nleave-one-out (LOO) classification performance of a soft-nearest\nneighbors rule is maximized in the transformed space. The key insight to\nthe algorithm is that a matrix $A$ corresponding to the\ntransformation can be found by defining a differentiable objective function\nfor $A$, followed by use of an iterative solver such as\n`scipy.optimize.fmin_l_bfgs_b`. Like LMNN, this algorithm does not try to\ncluster points from the same class in a unique cluster, because it\nenforces conditions at a local neighborhood scale.\n\n- See more in the `User Guide `\n- See more in the documentation of the class :py:class:`NCA\n `\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "nca = metric_learn.NCA(max_iter=1000)\nX_nca = nca.fit_transform(X, y)\n\nplot_tsne(X_nca, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Local Fisher Discriminant Analysis\n\nLFDA is a linear supervised dimensionality reduction method. It is\nparticularly useful when dealing with multimodality, where one ore more\nclasses consist of separate clusters in input space. The core\noptimization problem of LFDA is solved as a generalized eigenvalue\nproblem. Like LMNN, and NCA, this algorithm does not try to cluster points\nfrom the same class in a unique cluster.\n\n- See more in the `User Guide `\n- See more in the documentation of the class :py:class:`LFDA\n `\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "lfda = metric_learn.LFDA(k=2, n_components=2)\nX_lfda = lfda.fit_transform(X, y)\n\nplot_tsne(X_lfda, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Relative Components Analysis\n\nRCA is another one of the older algorithms. It learns a full rank\nMahalanobis distance metric based on a weighted sum of in-class\ncovariance matrices. It applies a global linear transformation to assign\nlarge weights to relevant dimensions and low weights to irrelevant\ndimensions. Those relevant dimensions are estimated using \"chunklets\",\nsubsets of points that are known to belong to the same class.\n\n- See more in the `User Guide `\n- See more in the documentation of the class :py:class:`RCA\n `\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "rca = metric_learn.RCA_Supervised(n_chunks=30, chunk_size=2)\nX_rca = rca.fit_transform(X, y)\n\nplot_tsne(X_rca, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Regression example: Metric Learning for Kernel Regression\n\nThe previous algorithms took as input a dataset with class labels. Metric\nlearning can also be useful for regression, when the labels are real numbers.\nAn algorithm very similar to NCA but for regression is Metric\nLearning for Kernel Regression (MLKR). It will optimize for the average\nleave-one-out *regression* performance from a soft-nearest neighbors\nregression.\n\n- See more in the `User Guide `\n- See more in the documentation of the class :py:class:`MLKR\n `\n\nTo illustrate MLKR, let's use the dataset\n`sklearn.datasets.make_regression` the same way as we did with the\nclassification before. The dataset will contain: 100 points of 5 features\neach, among which 3 are informative (i.e., used to generate the\nregression target from a linear model), and two are random noise with the\nsame magnitude.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "X_reg, y_reg = make_regression(n_samples=100, n_informative=3, n_features=5,\n shuffle=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's plot the dataset as is\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "plot_tsne(X_reg, y_reg, plt.cm.Oranges)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And let's plot the dataset after transformation by MLKR:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "mlkr = metric_learn.MLKR()\nX_mlkr = mlkr.fit_transform(X_reg, y_reg)\nplot_tsne(X_mlkr, y_reg, plt.cm.Oranges)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Points that have the same value to regress are now closer to each\nother ! This would improve the performance of\n`sklearn.neighbors.KNeighborsRegressor` for instance.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Metric Learning from Weaker Supervision\n\nTo learn the metric, so far we have always given the labels of the\ndata to supervise the algorithms. However, in many applications,\nit is easier to obtain information about whether two samples are\nsimilar or dissimilar. For instance, when annotating a dataset of face\nimages, it is easier for an annotator to tell if two faces belong to the same\nperson or not, rather than finding the ID of the face among a huge database\nof every person's faces.\nNote that for some problems (e.g., in information\nretrieval where the goal is to rank documents by similarity to a query\ndocument), there is no notion of individual label but one can gather\ninformation on which pairs of points are similar or dissimilar.\nFortunately, one of the strength of metric learning is the ability to\nlearn from such weaker supervision. Indeed, some of the algorithms we've\nused above have alternate ways to pass some supervision about the metric\nwe want to learn. The way to go is to pass a 2D array `pairs` of pairs,\nas well as an array of labels `pairs_labels` such that for each `i` between\n`0` and `n_pairs` we want `X[pairs[i, 0], :]` and `X[pairs[i, 1], :]` to be\nsimilar if `pairs_labels[i] == 1`, and we want them to be dissimilar if\n`pairs_labels[i] == -1`. In other words, we\nwant to enforce a metric that projects similar points closer together and\ndissimilar points further away from each other. This kind of input is\npossible for ITML, SDML, and MMC. See `weakly_supervised_section` for\ndetails on other kinds of weak supervision that some algorithms can work\nwith.\n\nFor the purpose of this example, we're going to explicitly create these\npairwise constraints through the labels we have, i.e. `y`.\nDo keep in mind that we are doing this method because we know the labels\n- we can actually create the constraints any way we want to depending on\nthe data!\n\nNote that this is what metric-learn did under the hood in the previous\nexamples (do check out the\n`constraints` module!) - but we'll try our own version of this. We're\ngoing to go ahead and assume that two points labeled the same will be\ncloser than two points in different labels.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def create_constraints(labels):\n import itertools\n import random\n\n # aggregate indices of same class\n zeros = np.where(y == 0)[0]\n ones = np.where(y == 1)[0]\n twos = np.where(y == 2)[0]\n # make permutations of all those points in the same class\n zeros_ = list(itertools.combinations(zeros, 2))\n ones_ = list(itertools.combinations(ones, 2))\n twos_ = list(itertools.combinations(twos, 2))\n # put them together!\n sim = np.array(zeros_ + ones_ + twos_)\n\n # similarily, put together indices in different classes\n dis = []\n for zero in zeros:\n for one in ones:\n dis.append((zero, one))\n for two in twos:\n dis.append((zero, two))\n for one in ones:\n for two in twos:\n dis.append((one, two))\n\n # pick up just enough dissimilar examples as we have similar examples\n dis = np.array(random.sample(dis, len(sim)))\n\n # return an array of pairs of indices of shape=(2*len(sim), 2), and the\n # corresponding labels, array of shape=(2*len(sim))\n # Each pair of similar points have a label of +1 and each pair of\n # dissimilar points have a label of -1\n return (np.vstack([np.column_stack([sim[:, 0], sim[:, 1]]),\n np.column_stack([dis[:, 0], dis[:, 1]])]),\n np.concatenate([np.ones(len(sim)), -np.ones(len(sim))]))\n\n\npairs, pairs_labels = create_constraints(y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we've created our constraints, let's see what it looks like!\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(pairs)\nprint(pairs_labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using our constraints, let's now train ITML again. Note that we are no\nlonger calling the supervised class :py:class:`ITML_Supervised\n` but the more generic\n(weakly-supervised) :py:class:`ITML `, which\ntakes the dataset `X` through the `preprocessor` argument (see\n`this section ` of the documentation to learn\nabout more advanced uses of `preprocessor`) and the pair information `pairs`\nand `pairs_labels` in the fit method.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "itml = metric_learn.ITML(preprocessor=X)\nitml.fit(pairs, pairs_labels)\n\nX_itml = itml.transform(X)\n\nplot_tsne(X_itml, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And that's the result of ITML after being trained on our manually\nconstructed constraints! A bit different from our old result, but not too\ndifferent.\n\nRCA and LSML also have their own specific ways of taking in inputs -\nit's worth one's while to poke around in the constraints.py file to see\nhow exactly this is going on.\n\nFinally, one of the main advantages of metric-learn is its out-of-the box\ncompatibility with scikit-learn, for doing [model selection](https://scikit-learn.org/stable/model_selection.html)_,\ncross-validation, and scoring for instance. Indeed, supervised algorithms are\nregular `sklearn.base.TransformerMixin` that can be plugged into any\npipeline or cross-validation procedure. And weakly-supervised estimators are\nalso compatible with scikit-learn, since their input dataset format described\nabove allows to be sliced along the first dimension when doing\ncross-validations (see also this `section `). You\ncan also look at some `use cases ` where you could combine\nmetric-learn with scikit-learn estimators.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This brings us to the end of this tutorial! Have fun Metric Learning :)\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/_images/sphx_glr_plot_metric_learning_examples_001.png b/_images/sphx_glr_plot_metric_learning_examples_001.png new file mode 100644 index 00000000..f1f6dd6f Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_001.png differ diff --git a/_images/sphx_glr_plot_metric_learning_examples_002.png b/_images/sphx_glr_plot_metric_learning_examples_002.png new file mode 100644 index 00000000..2c804e4c Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_002.png differ diff --git a/_images/sphx_glr_plot_metric_learning_examples_003.png b/_images/sphx_glr_plot_metric_learning_examples_003.png new file mode 100644 index 00000000..c4863861 Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_003.png differ diff --git a/_images/sphx_glr_plot_metric_learning_examples_004.png b/_images/sphx_glr_plot_metric_learning_examples_004.png new file mode 100644 index 00000000..b4296c65 Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_004.png differ diff --git a/_images/sphx_glr_plot_metric_learning_examples_005.png b/_images/sphx_glr_plot_metric_learning_examples_005.png new file mode 100644 index 00000000..7bde299d Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_005.png differ diff --git a/_images/sphx_glr_plot_metric_learning_examples_006.png b/_images/sphx_glr_plot_metric_learning_examples_006.png new file mode 100644 index 00000000..db83f33a Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_006.png differ diff --git a/_images/sphx_glr_plot_metric_learning_examples_007.png b/_images/sphx_glr_plot_metric_learning_examples_007.png new file mode 100644 index 00000000..5056b65e Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_007.png differ diff --git a/_images/sphx_glr_plot_metric_learning_examples_008.png b/_images/sphx_glr_plot_metric_learning_examples_008.png new file mode 100644 index 00000000..e9ca64a9 Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_008.png differ diff --git a/_images/sphx_glr_plot_metric_learning_examples_009.png b/_images/sphx_glr_plot_metric_learning_examples_009.png new file mode 100644 index 00000000..e470a170 Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_009.png differ diff --git a/_images/sphx_glr_plot_metric_learning_examples_010.png b/_images/sphx_glr_plot_metric_learning_examples_010.png new file mode 100644 index 00000000..875e9fcd Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_010.png differ diff --git a/_images/sphx_glr_plot_metric_learning_examples_011.png b/_images/sphx_glr_plot_metric_learning_examples_011.png new file mode 100644 index 00000000..ebc60f01 Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_011.png differ diff --git a/_images/sphx_glr_plot_metric_learning_examples_012.png b/_images/sphx_glr_plot_metric_learning_examples_012.png new file mode 100644 index 00000000..d014d101 Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_012.png differ diff --git a/_images/sphx_glr_plot_metric_learning_examples_thumb.png b/_images/sphx_glr_plot_metric_learning_examples_thumb.png new file mode 100644 index 00000000..95822ff7 Binary files /dev/null and b/_images/sphx_glr_plot_metric_learning_examples_thumb.png differ diff --git a/_images/sphx_glr_plot_sandwich_001.png b/_images/sphx_glr_plot_sandwich_001.png new file mode 100644 index 00000000..f77f0edb Binary files /dev/null and b/_images/sphx_glr_plot_sandwich_001.png differ diff --git a/_images/sphx_glr_plot_sandwich_thumb.png b/_images/sphx_glr_plot_sandwich_thumb.png new file mode 100644 index 00000000..1ee70a46 Binary files /dev/null and b/_images/sphx_glr_plot_sandwich_thumb.png differ diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 00000000..59efd81b --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,130 @@ + + + + + + Overview: module code — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+ +
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/base_metric.html b/_modules/metric_learn/base_metric.html new file mode 100644 index 00000000..78e6a941 --- /dev/null +++ b/_modules/metric_learn/base_metric.html @@ -0,0 +1,1131 @@ + + + + + + metric_learn.base_metric — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.base_metric

+"""
+Base module.
+"""
+
+from sklearn.base import BaseEstimator, ClassifierMixin
+from sklearn.utils.extmath import stable_cumsum
+from sklearn.utils.validation import _is_arraylike, check_is_fitted
+from sklearn.metrics import roc_auc_score, roc_curve, precision_recall_curve
+import numpy as np
+from abc import ABCMeta, abstractmethod
+from ._util import ArrayIndexer, check_input, validate_vector
+import warnings
+
+
+
+[docs] +class BaseMetricLearner(BaseEstimator, metaclass=ABCMeta): + """ + Base class for all metric-learners. + + Parameters + ---------- + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be gotten like this: X[indices]. + """ + +
+[docs] + def __init__(self, preprocessor=None): + self.preprocessor = preprocessor
+ + +
+[docs] + @abstractmethod + def score_pairs(self, pairs): + """ + Returns the score between pairs + (can be a similarity, or a distance/metric depending on the algorithm) + + .. deprecated:: 0.7.0 + Refer to `pair_distance` and `pair_score`. + + .. warning:: + This method will be removed in 0.8.0. Please refer to `pair_distance` + or `pair_score`. This change will occur in order to add learners + that don't necessarily learn a Mahalanobis distance. + + Parameters + ---------- + pairs : array-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2) + 3D Array of pairs to score, with each row corresponding to two points, + for 2D array of indices of pairs if the metric learner uses a + preprocessor. + + Returns + ------- + scores : `numpy.ndarray` of shape=(n_pairs,) + The score of every pair. + + See Also + -------- + get_metric : a method that returns a function to compute the metric between + two points. The difference between `score_pairs` is that it works on two + 1D arrays and cannot use a preprocessor. Besides, the returned function + is independent of the metric learner and hence is not modified if the + metric learner is. + """
+ + +
+[docs] + @abstractmethod + def pair_score(self, pairs): + """ + .. versionadded:: 0.7.0 Compute the similarity score between pairs + + Returns the similarity score between pairs of points (the larger the score, + the more similar the pair). For metric learners that learn a distance, + the score is simply the opposite of the distance between pairs. All + learners have access to this method. + + Parameters + ---------- + pairs : array-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2) + 3D Array of pairs to score, with each row corresponding to two points, + for 2D array of indices of pairs if the metric learner uses a + preprocessor. + + Returns + ------- + scores : `numpy.ndarray` of shape=(n_pairs,) + The score of every pair. + + See Also + -------- + get_metric : a method that returns a function to compute the metric between + two points. The difference with `pair_score` is that it works on two + 1D arrays and cannot use a preprocessor. Besides, the returned function + is independent of the metric learner and hence is not modified if the + metric learner is. + """
+ + +
+[docs] + @abstractmethod + def pair_distance(self, pairs): + """ + .. versionadded:: 0.7.0 Compute the distance between pairs + + Returns the (pseudo) distance between pairs, when available. For metric + learners that do not learn a (pseudo) distance, an error is thrown + instead. + + Parameters + ---------- + pairs : array-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2) + 3D Array of pairs for which to compute the distance, with each + row corresponding to two points, for 2D array of indices of pairs + if the metric learner uses a preprocessor. + + Returns + ------- + scores : `numpy.ndarray` of shape=(n_pairs,) + The distance between every pair. + + See Also + -------- + get_metric : a method that returns a function to compute the metric between + two points. The difference with `pair_distance` is that it works on two + 1D arrays and cannot use a preprocessor. Besides, the returned function + is independent of the metric learner and hence is not modified if the + metric learner is. + """
+ + + def _check_preprocessor(self): + """Initializes the preprocessor""" + if _is_arraylike(self.preprocessor): + self.preprocessor_ = ArrayIndexer(self.preprocessor) + elif callable(self.preprocessor) or self.preprocessor is None: + self.preprocessor_ = self.preprocessor + else: + raise ValueError("Invalid type for the preprocessor: {}. You should " + "provide either None, an array-like object, " + "or a callable.".format(type(self.preprocessor))) + + def _prepare_inputs(self, X, y=None, type_of_inputs='classic', + **kwargs): + """Initializes the preprocessor and processes inputs. See `check_input` + for more details. + + Parameters + ---------- + X : array-like + The input data array to check. + + y : array-like + The input labels array to check. + + type_of_inputs : `str` {'classic', 'tuples'} + The type of inputs to check. If 'classic', the input should be + a 2D array-like of points or a 1D array like of indicators of points. If + 'tuples', the input should be a 3D array-like of tuples or a 2D + array-like of indicators of tuples. + + **kwargs : dict + Arguments to pass to check_input. + + Returns + ------- + X : `numpy.ndarray` + The checked input data array. + + y : `numpy.ndarray` (optional) + The checked input labels array. + """ + self._check_preprocessor() + + check_is_fitted(self, ['preprocessor_']) + outs = check_input(X, y, + type_of_inputs=type_of_inputs, + preprocessor=self.preprocessor_, + estimator=self, + tuple_size=getattr(self, '_tuple_size', None), + **kwargs) + # Conform to SLEP010 + if not hasattr(self, 'n_features_in_'): + self.n_features_in_ = (outs if y is None else outs[0]).shape[1] + return outs + +
+[docs] + @abstractmethod + def get_metric(self): + """Returns a function that takes as input two 1D arrays and outputs + the value of the learned metric on these two points. Depending on the + algorithm, it can return a distance or a similarity function between + pairs. + + This function will be independent from the metric learner that learned it + (it will not be modified if the initial metric learner is modified), + and it can be directly plugged into the `metric` argument of + scikit-learn's estimators. + + Returns + ------- + metric_fun : function + The function described above. + + + Examples + -------- + .. doctest:: + + >>> from metric_learn import NCA + >>> from sklearn.datasets import make_classification + >>> from sklearn.neighbors import KNeighborsClassifier + >>> nca = NCA() + >>> X, y = make_classification() + >>> nca.fit(X, y) + >>> knn = KNeighborsClassifier(metric=nca.get_metric()) + >>> knn.fit(X, y) # doctest: +NORMALIZE_WHITESPACE + KNeighborsClassifier(algorithm='auto', leaf_size=30, + metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun + at 0x...>, + metric_params=None, n_jobs=None, n_neighbors=5, p=2, + weights='uniform') + + See Also + -------- + pair_distance : a method that returns the distance between several + pairs of points. Unlike `get_metric`, this is a method of the metric + learner and therefore can change if the metric learner changes. Besides, + it can use the metric learner's preprocessor, and works on concatenated + arrays. + + pair_score : a method that returns the similarity score between + several pairs of points. Unlike `get_metric`, this is a method of the + metric learner and therefore can change if the metric learner changes. + Besides, it can use the metric learner's preprocessor, and works on + concatenated arrays. + """
+
+ + + +
+[docs] +class MetricTransformer(metaclass=ABCMeta): + """ + Base class for all learners that can transform data into a new space + with the metric learned. + """ +
+[docs] + @abstractmethod + def transform(self, X): + """Applies the metric transformation. + + Parameters + ---------- + X : (n x d) matrix + Data to transform. + + Returns + ------- + transformed : (n x d) matrix + Input data transformed to the metric space by :math:`XL^{\\top}` + """
+
+ + + +
+[docs] +class MahalanobisMixin(BaseMetricLearner, MetricTransformer, + metaclass=ABCMeta): + r"""Mahalanobis metric learning algorithms. + + Algorithm that learns a Mahalanobis (pseudo) distance :math:`d_M(x, x')`, + defined between two column vectors :math:`x` and :math:`x'` by: :math:`d_M(x, + x') = \sqrt{(x-x')^T M (x-x')}`, where :math:`M` is a learned symmetric + positive semi-definite (PSD) matrix. The metric between points can then be + expressed as the euclidean distance between points embedded in a new space + through a linear transformation. Indeed, the above matrix can be decomposed + into the product of two transpose matrices (through SVD or Cholesky + decomposition): :math:`d_M(x, x')^2 = (x-x')^T M (x-x') = (x-x')^T L^T L + (x-x') = (L x - L x')^T (L x- L x')` + + Attributes + ---------- + components_ : `numpy.ndarray`, shape=(n_components, n_features) + The learned linear transformation ``L``. + """ + +
+[docs] + def score_pairs(self, pairs): + r""" + Returns the learned Mahalanobis distance between pairs. + + This distance is defined as: :math:`d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}` + where ``M`` is the learned Mahalanobis matrix, for every pair of points + ``x`` and ``x'``. This corresponds to the euclidean distance between + embeddings of the points in a new space, obtained through a linear + transformation. Indeed, we have also: :math:`d_M(x, x') = \\sqrt{(x_e - + x_e')^T (x_e- x_e')}`, with :math:`x_e = L x` (See + :class:`MahalanobisMixin`). + + .. deprecated:: 0.7.0 + Please use `pair_distance` instead. + + .. warning:: + This method will be removed in 0.8.0. Please refer to `pair_distance` + or `pair_score`. This change will occur in order to add learners + that don't necessarily learn a Mahalanobis distance. + + Parameters + ---------- + pairs : array-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2) + 3D Array of pairs to score, with each row corresponding to two points, + for 2D array of indices of pairs if the metric learner uses a + preprocessor. + + Returns + ------- + scores : `numpy.ndarray` of shape=(n_pairs,) + The learned Mahalanobis distance for every pair. + + See Also + -------- + get_metric : a method that returns a function to compute the metric between + two points. The difference with `score_pairs` is that it works on two + 1D arrays and cannot use a preprocessor. Besides, the returned function + is independent of the metric learner and hence is not modified if the + metric learner is. + + :ref:`mahalanobis_distances` : The section of the project documentation + that describes Mahalanobis Distances. + """ + dpr_msg = ("score_pairs will be deprecated in release 0.7.0. " + "Use pair_score to compute similarity scores, or " + "pair_distances to compute distances.") + warnings.warn(dpr_msg, category=FutureWarning) + return self.pair_distance(pairs)
+ + +
+[docs] + def pair_score(self, pairs): + """ + Returns the opposite of the learned Mahalanobis distance between pairs. + + Parameters + ---------- + pairs : array-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2) + 3D Array of pairs to score, with each row corresponding to two points, + for 2D array of indices of pairs if the metric learner uses a + preprocessor. + + Returns + ------- + scores : `numpy.ndarray` of shape=(n_pairs,) + The opposite of the learned Mahalanobis distance for every pair. + + See Also + -------- + get_metric : a method that returns a function to compute the metric between + two points. The difference with `pair_score` is that it works on two + 1D arrays and cannot use a preprocessor. Besides, the returned function + is independent of the metric learner and hence is not modified if the + metric learner is. + + :ref:`mahalanobis_distances` : The section of the project documentation + that describes Mahalanobis Distances. + """ + return -1 * self.pair_distance(pairs)
+ + +
+[docs] + def pair_distance(self, pairs): + """ + Returns the learned Mahalanobis distance between pairs. + + This distance is defined as: :math:`d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}` + where ``M`` is the learned Mahalanobis matrix, for every pair of points + ``x`` and ``x'``. This corresponds to the euclidean distance between + embeddings of the points in a new space, obtained through a linear + transformation. Indeed, we have also: :math:`d_M(x, x') = \\sqrt{(x_e - + x_e')^T (x_e- x_e')}`, with :math:`x_e = L x` (See + :class:`MahalanobisMixin`). + + Parameters + ---------- + pairs : array-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2) + 3D Array of pairs to score, with each row corresponding to two points, + for 2D array of indices of pairs if the metric learner uses a + preprocessor. + + Returns + ------- + scores : `numpy.ndarray` of shape=(n_pairs,) + The learned Mahalanobis distance for every pair. + + See Also + -------- + get_metric : a method that returns a function to compute the metric between + two points. The difference with `pair_distance` is that it works on two + 1D arrays and cannot use a preprocessor. Besides, the returned function + is independent of the metric learner and hence is not modified if the + metric learner is. + + :ref:`mahalanobis_distances` : The section of the project documentation + that describes Mahalanobis Distances. + """ + check_is_fitted(self, ['preprocessor_']) + pairs = check_input(pairs, type_of_inputs='tuples', + preprocessor=self.preprocessor_, + estimator=self, tuple_size=2) + pairwise_diffs = self.transform(pairs[:, 1, :] - pairs[:, 0, :]) + # (for MahalanobisMixin, the embedding is linear so we can just embed the + # difference) + return np.sqrt(np.sum(pairwise_diffs**2, axis=-1))
+ + +
+[docs] + def transform(self, X): + """Embeds data points in the learned linear embedding space. + + Transforms samples in ``X`` into ``X_embedded``, samples inside a new + embedding space such that: ``X_embedded = X.dot(L.T)``, where ``L`` is + the learned linear transformation (See :class:`MahalanobisMixin`). + + Parameters + ---------- + X : `numpy.ndarray`, shape=(n_samples, n_features) + The data points to embed. + + Returns + ------- + X_embedded : `numpy.ndarray`, shape=(n_samples, n_components) + The embedded data points. + """ + check_is_fitted(self, ['preprocessor_', 'components_']) + X_checked = check_input(X, type_of_inputs='classic', estimator=self, + preprocessor=self.preprocessor_, + accept_sparse=True) + return X_checked.dot(self.components_.T)
+ + +
+[docs] + def get_metric(self): + check_is_fitted(self, 'components_') + components_T = self.components_.T.copy() + + def metric_fun(u, v, squared=False): + """This function computes the metric between u and v, according to the + previously learned metric. + + Parameters + ---------- + u : array-like, shape=(n_features,) + The first point involved in the distance computation. + + v : array-like, shape=(n_features,) + The second point involved in the distance computation. + + squared : `bool` + If True, the function will return the squared metric between u and + v, which is faster to compute. + + Returns + ------- + distance : float + The distance between u and v according to the new metric. + """ + u = validate_vector(u) + v = validate_vector(v) + transformed_diff = (u - v).dot(components_T) + dist = np.dot(transformed_diff, transformed_diff.T) + if not squared: + dist = np.sqrt(dist) + return dist + + return metric_fun
+ + + get_metric.__doc__ = BaseMetricLearner.get_metric.__doc__ + +
+[docs] + def get_mahalanobis_matrix(self): + """Returns a copy of the Mahalanobis matrix learned by the metric learner. + + Returns + ------- + M : `numpy.ndarray`, shape=(n_features, n_features) + The copy of the learned Mahalanobis matrix. + """ + check_is_fitted(self, 'components_') + return self.components_.T.dot(self.components_)
+
+ + + +
+[docs] +class _PairsClassifierMixin(BaseMetricLearner, ClassifierMixin): + """Base class for pairs learners. + + Attributes + ---------- + threshold_ : `float` + If the distance metric between two points is lower than this threshold, + points will be classified as similar, otherwise they will be + classified as dissimilar. + """ + + classes_ = np.array([0, 1]) + _tuple_size = 2 # number of points in a tuple, 2 for pairs + +
+[docs] + def predict(self, pairs): + """Predicts the learned metric between input pairs. (For now it just + calls decision function). + + Returns the learned metric value between samples in every pair. It should + ideally be low for similar samples and high for dissimilar samples. + + Parameters + ---------- + pairs : array-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2) + 3D Array of pairs to predict, with each row corresponding to two + points, or 2D array of indices of pairs if the metric learner uses a + preprocessor. + + Returns + ------- + y_predicted : `numpy.ndarray` of floats, shape=(n_constraints,) + The predicted learned metric value between samples in every pair. + """ + check_is_fitted(self, 'preprocessor_') + + if "threshold_" not in vars(self): + msg = ("A threshold for this estimator has not been set, " + "call its set_threshold or calibrate_threshold method.") + raise AttributeError(msg) + return 2 * (- self.decision_function(pairs) <= self.threshold_) - 1
+ + +
+[docs] + def decision_function(self, pairs): + """Returns the decision function used to classify the pairs. + + Returns the opposite of the learned metric value between samples in every + pair, to be consistent with scikit-learn conventions. Hence it should + ideally be low for dissimilar samples and high for similar samples. + This is the decision function that is used to classify pairs as similar + (+1), or dissimilar (-1). + + Parameters + ---------- + pairs : array-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2) + 3D Array of pairs to predict, with each row corresponding to two + points, or 2D array of indices of pairs if the metric learner uses a + preprocessor. + + Returns + ------- + y_predicted : `numpy.ndarray` of floats, shape=(n_constraints,) + The predicted decision function value for each pair. + """ + check_is_fitted(self, 'preprocessor_') + pairs = check_input(pairs, type_of_inputs='tuples', + preprocessor=self.preprocessor_, + estimator=self, tuple_size=self._tuple_size) + return self.pair_score(pairs)
+ + +
+[docs] + def score(self, pairs, y): + """Computes score of pairs similarity prediction. + + Returns the ``roc_auc`` score of the fitted metric learner. It is + computed in the following way: for every value of a threshold + ``t`` we classify all pairs of samples where the predicted distance is + inferior to ``t`` as belonging to the "similar" class, and the other as + belonging to the "dissimilar" class, and we count false positive and + true positives as in a classical ``roc_auc`` curve. + + Parameters + ---------- + pairs : array-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2) + 3D Array of pairs, with each row corresponding to two points, + or 2D array of indices of pairs if the metric learner uses a + preprocessor. + + y : array-like, shape=(n_constraints,) + The corresponding labels. + + Returns + ------- + score : float + The ``roc_auc`` score. + """ + return roc_auc_score(y, self.decision_function(pairs))
+ + +
+[docs] + def set_threshold(self, threshold): + """Sets the threshold of the metric learner to the given value `threshold`. + + See more in the :ref:`User Guide <calibration>`. + + Parameters + ---------- + threshold : float + The threshold value we want to set. It is the value to which the + predicted distance for test pairs will be compared. If they are superior + to the threshold they will be classified as similar (+1), + and dissimilar (-1) if not. + + Returns + ------- + self : `_PairsClassifier` + The pairs classifier with the new threshold set. + """ + check_is_fitted(self, 'preprocessor_') + try: + self.threshold_ = float(threshold) + except TypeError: + raise ValueError('Parameter threshold must be a real number. ' + 'Got {} instead.'.format(type(threshold))) + except ValueError: + raise ValueError('Parameter threshold must be a real number. ' + 'Got {} instead.'.format(type(threshold))) + return self
+ + +
+[docs] + def calibrate_threshold(self, pairs_valid, y_valid, strategy='accuracy', + min_rate=None, beta=1.): + """Decision threshold calibration for pairwise binary classification + + Method that calibrates the decision threshold (cutoff point) of the metric + learner. This threshold will then be used when calling the method + `predict`. The methods for picking cutoff points make use of traditional + binary classification evaluation statistics such as the true positive and + true negative rates and F-scores. The threshold will be found to maximize + the chosen score on the validation set ``(pairs_valid, y_valid)``. + + See more in the :ref:`User Guide <calibration>`. + + Parameters + ---------- + strategy : str, optional (default='accuracy') + The strategy to use for choosing the cutoff threshold. + + 'accuracy' + Selects a decision threshold that maximizes the accuracy. + 'f_beta' + Selects a decision threshold that maximizes the f_beta score, + with beta given by the parameter `beta`. + 'max_tpr' + Selects a decision threshold that yields the highest true positive + rate with true negative rate at least equal to the value of the + parameter `min_rate`. + 'max_tnr' + Selects a decision threshold that yields the highest true negative + rate with true positive rate at least equal to the value of the + parameter `min_rate`. + + beta : float in [0, 1], optional (default=None) + Beta value to be used in case strategy == 'f_beta'. + + min_rate : float in [0, 1] or None, (default=None) + In case strategy is 'max_tpr' or 'max_tnr' this parameter must be set + to specify the minimal value for the true negative rate or true positive + rate respectively that needs to be achieved. + + pairs_valid : array-like, shape=(n_pairs_valid, 2, n_features) + The validation set of pairs to use to set the threshold. + + y_valid : array-like, shape=(n_pairs_valid,) + The labels of the pairs of the validation set to use to set the + threshold. They must be +1 for positive pairs and -1 for negative pairs. + + References + ---------- + .. [1] Receiver-operating characteristic (ROC) plots: a fundamental + evaluation tool in clinical medicine, MH Zweig, G Campbell - + Clinical chemistry, 1993 + + .. [2] Most of the code of this function is from scikit-learn's PR #10117 + + See Also + -------- + sklearn.calibration : scikit-learn's module for calibrating classifiers + """ + check_is_fitted(self, 'preprocessor_') + + self._validate_calibration_params(strategy, min_rate, beta) + + pairs_valid, y_valid = self._prepare_inputs(pairs_valid, y_valid, + type_of_inputs='tuples') + + n_samples = pairs_valid.shape[0] + if strategy == 'accuracy': + scores = self.decision_function(pairs_valid) + scores_sorted_idces = np.argsort(scores)[::-1] + scores_sorted = scores[scores_sorted_idces] + # true labels ordered by decision_function value: (higher first) + y_ordered = y_valid[scores_sorted_idces] + # we need to add a threshold that will reject all points + scores_sorted = np.concatenate([[scores_sorted[0] + 1], scores_sorted]) + + # finds the threshold that maximizes the accuracy: + cum_tp = stable_cumsum(y_ordered == 1) # cumulative number of true + # positives + # we need to add the point where all samples are rejected: + cum_tp = np.concatenate([[0.], cum_tp]) + cum_tn_inverted = stable_cumsum(y_ordered[::-1] == -1) + cum_tn = np.concatenate([[0.], cum_tn_inverted])[::-1] + cum_accuracy = (cum_tp + cum_tn) / n_samples + imax = np.argmax(cum_accuracy) + # we set the threshold to the lowest accepted score + # note: we are working with negative distances but we want the threshold + # to be with respect to the actual distances so we take minus sign + self.threshold_ = - scores_sorted[imax] + # note: if the best is to reject all points it's already one of the + # thresholds (scores_sorted[0]) + return self + + if strategy == 'f_beta': + precision, recall, thresholds = precision_recall_curve( + y_valid, self.decision_function(pairs_valid), pos_label=1) + + # here the thresholds are decreasing + # We ignore the warnings here, in the same taste as + # https://github.com/scikit-learn/scikit-learn/blob/62d205980446a1abc1065 + # f4332fd74eee57fcf73/sklearn/metrics/classification.py#L1284 + with np.errstate(divide='ignore', invalid='ignore'): + f_beta = ((1 + beta**2) * (precision * recall) / + (beta**2 * precision + recall)) + # We need to set nans to zero otherwise they will be considered higher + # than the others (also discussed in https://github.com/scikit-learn/ + # scikit-learn/pull/10117/files#r262115773) + f_beta[np.isnan(f_beta)] = 0. + imax = np.argmax(f_beta) + # we set the threshold to the lowest accepted score + # note: we are working with negative distances but we want the threshold + # to be with respect to the actual distances so we take minus sign + self.threshold_ = - thresholds[imax] + # Note: we don't need to deal with rejecting all points (i.e. threshold = + # max_scores + 1), since this can never happen to be optimal + # (see a more detailed discussion in test_calibrate_threshold_extreme) + return self + + fpr, tpr, thresholds = roc_curve(y_valid, + self.decision_function(pairs_valid), + pos_label=1) + # here the thresholds are decreasing + fpr, tpr, thresholds = fpr, tpr, thresholds + + if strategy in ['max_tpr', 'max_tnr']: + if strategy == 'max_tpr': + indices = np.where(1 - fpr >= min_rate)[0] + imax = np.argmax(tpr[indices]) + + if strategy == 'max_tnr': + indices = np.where(tpr >= min_rate)[0] + imax = np.argmax(1 - fpr[indices]) + + imax_valid = indices[imax] + # note: we are working with negative distances but we want the threshold + # to be with respect to the actual distances so we take minus sign + if indices[imax] == len(thresholds): # we want to accept everything + self.threshold_ = - (thresholds[imax_valid] - 1) + else: + # thanks to roc_curve, the first point will always be max_scores + # + 1, see: https://github.com/scikit-learn/scikit-learn/pull/13523 + self.threshold_ = - thresholds[imax_valid] + return self
+ + + @staticmethod + def _validate_calibration_params(strategy='accuracy', min_rate=None, + beta=1.): + """Ensure that calibration parameters have allowed values""" + if strategy not in ('accuracy', 'f_beta', 'max_tpr', + 'max_tnr'): + raise ValueError('Strategy can either be "accuracy", "f_beta" or ' + '"max_tpr" or "max_tnr". Got "{}" instead.' + .format(strategy)) + if strategy == 'max_tpr' or strategy == 'max_tnr': + if (min_rate is None or not isinstance(min_rate, (int, float)) or + not min_rate >= 0 or not min_rate <= 1): + raise ValueError('Parameter min_rate must be a number in' + '[0, 1]. ' + 'Got {} instead.'.format(min_rate)) + if strategy == 'f_beta': + if beta is None or not isinstance(beta, (int, float)): + raise ValueError('Parameter beta must be a real number. ' + 'Got {} instead.'.format(type(beta)))
+ + + +
+[docs] +class _TripletsClassifierMixin(BaseMetricLearner, ClassifierMixin): + """ + Base class for triplets learners. + """ + + classes_ = np.array([0, 1]) + _tuple_size = 3 # number of points in a tuple, 3 for triplets + +
+[docs] + def predict(self, triplets): + """Predicts the ordering between sample distances in input triplets. + + For each triplets, returns 1 if the first element is closer to the second + than to the last and -1 if not. + + Parameters + ---------- + triplets : array-like, shape=(n_triplets, 3, n_features) or (n_triplets, 3) + 3D array of triplets to predict, with each row corresponding to three + points, or 2D array of indices of triplets if the metric learner + uses a preprocessor. + + Returns + ------- + prediction : `numpy.ndarray` of floats, shape=(n_constraints,) + Predictions of the ordering of pairs, for each triplet. + """ + return 2 * (self.decision_function(triplets) > 0) - 1
+ + +
+[docs] + def decision_function(self, triplets): + """Predicts differences between sample distances in input triplets. + + For each triplet (X_a, X_b, X_c) in the samples, computes the difference + between the learned distance of the second pair (X_a, X_c) minus the + learned distance of the first pair (X_a, X_b). The higher it is, the more + probable it is that the pairs in the triplets are presented in the right + order, i.e. that the label of the triplet is 1. The lower it is, the more + probable it is that the label of the triplet is -1. + + Parameters + ---------- + triplet : array-like, shape=(n_triplets, 3, n_features) or \ + (n_triplets, 3) + 3D array of triplets to predict, with each row corresponding to three + points, or 2D array of indices of triplets if the metric learner + uses a preprocessor. + + Returns + ------- + decision_function : `numpy.ndarray` of floats, shape=(n_constraints,) + Metric differences. + """ + check_is_fitted(self, 'preprocessor_') + triplets = check_input(triplets, type_of_inputs='tuples', + preprocessor=self.preprocessor_, + estimator=self, tuple_size=self._tuple_size) + return (self.pair_score(triplets[:, :2]) - + self.pair_score(triplets[:, [0, 2]]))
+ + +
+[docs] + def score(self, triplets): + """Computes score on input triplets. + + Returns the accuracy score of the following classification task: a triplet + (X_a, X_b, X_c) is correctly classified if the predicted similarity between + the first pair (X_a, X_b) is higher than that of the second pair (X_a, X_c) + + Parameters + ---------- + triplets : array-like, shape=(n_triplets, 3, n_features) or \ + (n_triplets, 3) + 3D array of triplets to score, with each row corresponding to three + points, or 2D array of indices of triplets if the metric learner + uses a preprocessor. + + Returns + ------- + score : float + The triplets score. + """ + # Since the prediction is a vector of values in {-1, +1}, we need to + # rescale them to {0, 1} to compute the accuracy using the mean (because + # then 1 means a correctly classified result (pairs are in the right + # order), and a 0 an incorrectly classified result (pairs are in the + # wrong order). + return self.predict(triplets).mean() / 2 + 0.5
+
+ + + +
+[docs] +class _QuadrupletsClassifierMixin(BaseMetricLearner, ClassifierMixin): + """ + Base class for quadruplets learners. + """ + + classes_ = np.array([0, 1]) + _tuple_size = 4 # number of points in a tuple, 4 for quadruplets + +
+[docs] + def predict(self, quadruplets): + """Predicts the ordering between sample distances in input quadruplets. + + For each quadruplet, returns 1 if the quadruplet is in the right order ( + first pair is more similar than second pair), and -1 if not. + + Parameters + ---------- + quadruplets : array-like, shape=(n_quadruplets, 4, n_features) or \ + (n_quadruplets, 4) + 3D Array of quadruplets to predict, with each row corresponding to four + points, or 2D array of indices of quadruplets if the metric learner + uses a preprocessor. + + Returns + ------- + prediction : `numpy.ndarray` of floats, shape=(n_constraints,) + Predictions of the ordering of pairs, for each quadruplet. + """ + return np.sign(self.decision_function(quadruplets))
+ + +
+[docs] + def decision_function(self, quadruplets): + """Predicts differences between sample distances in input quadruplets. + + For each quadruplet in the samples, computes the difference between the + learned metric of the second pair minus the learned metric of the first + pair. The higher it is, the more probable it is that the pairs in the + quadruplet are presented in the right order, i.e. that the label of the + quadruplet is 1. The lower it is, the more probable it is that the label of + the quadruplet is -1. + + Parameters + ---------- + quadruplets : array-like, shape=(n_quadruplets, 4, n_features) or \ + (n_quadruplets, 4) + 3D Array of quadruplets to predict, with each row corresponding to four + points, or 2D array of indices of quadruplets if the metric learner + uses a preprocessor. + + Returns + ------- + decision_function : `numpy.ndarray` of floats, shape=(n_constraints,) + Metric differences. + """ + check_is_fitted(self, 'preprocessor_') + quadruplets = check_input(quadruplets, type_of_inputs='tuples', + preprocessor=self.preprocessor_, + estimator=self, tuple_size=self._tuple_size) + return (self.pair_score(quadruplets[:, :2]) - + self.pair_score(quadruplets[:, 2:]))
+ + +
+[docs] + def score(self, quadruplets): + """Computes score on input quadruplets + + Returns the accuracy score of the following classification task: a record + is correctly classified if the predicted similarity between the first two + samples is higher than that of the last two. + + Parameters + ---------- + quadruplets : array-like, shape=(n_quadruplets, 4, n_features) or \ + (n_quadruplets, 4) + 3D Array of quadruplets to score, with each row corresponding to four + points, or 2D array of indices of quadruplets if the metric learner + uses a preprocessor. + + Returns + ------- + score : float + The quadruplets score. + """ + # Since the prediction is a vector of values in {-1, +1}, we need to + # rescale them to {0, 1} to compute the accuracy using the mean (because + # then 1 means a correctly classified result (pairs are in the right + # order), and a 0 an incorrectly classified result (pairs are in the + # wrong order). + return self.predict(quadruplets).mean() / 2 + 0.5
+
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/constraints.html b/_modules/metric_learn/constraints.html new file mode 100644 index 00000000..377f4807 --- /dev/null +++ b/_modules/metric_learn/constraints.html @@ -0,0 +1,444 @@ + + + + + + metric_learn.constraints — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.constraints

+"""
+Helper module for generating different types of constraints
+from supervised data labels.
+"""
+import numpy as np
+import warnings
+from sklearn.utils import check_random_state
+from sklearn.neighbors import NearestNeighbors
+
+
+__all__ = ['Constraints']
+
+
+
+[docs] +class Constraints(object): + """ + Class to build constraints from labeled data. + + See more in the :ref:`User Guide <supervised_version>`. + + Parameters + ---------- + partial_labels : `numpy.ndarray` of ints, shape=(n_samples,) + Array of labels, with -1 indicating unknown label. + + Attributes + ---------- + partial_labels : `numpy.ndarray` of ints, shape=(n_samples,) + Array of labels, with -1 indicating unknown label. + """ + +
+[docs] + def __init__(self, partial_labels): + partial_labels = np.asanyarray(partial_labels, dtype=int) + self.partial_labels = partial_labels
+ + +
+[docs] + def positive_negative_pairs(self, n_constraints, same_length=False, + random_state=None, num_constraints='deprecated'): + """ + Generates positive pairs and negative pairs from labeled data. + + Positive pairs are formed by randomly drawing ``n_constraints`` pairs of + points with the same label. Negative pairs are formed by randomly drawing + ``n_constraints`` pairs of points with different label. + + In the case where it is not possible to generate enough positive or + negative pairs, a smaller number of pairs will be returned with a warning. + + Parameters + ---------- + n_constraints : int + Number of positive and negative constraints to generate. + + same_length : bool, optional (default=False) + If True, forces the number of positive and negative pairs to be + equal by ignoring some pairs from the larger set. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. + + num_constraints : Renamed to n_constraints. Will be deprecated in 0.7.0 + + Returns + ------- + a : array-like, shape=(n_constraints,) + 1D array of indicators for the left elements of positive pairs. + + b : array-like, shape=(n_constraints,) + 1D array of indicators for the right elements of positive pairs. + + c : array-like, shape=(n_constraints,) + 1D array of indicators for the left elements of negative pairs. + + d : array-like, shape=(n_constraints,) + 1D array of indicators for the right elements of negative pairs. + """ + if num_constraints != 'deprecated': + warnings.warn('"num_constraints" parameter has been renamed to' + ' "n_constraints". It has been deprecated in' + ' version 0.6.3 and will be removed in 0.7.0' + '', FutureWarning) + self.n_constraints = num_constraints + else: + self.n_constraints = n_constraints + random_state = check_random_state(random_state) + a, b = self._pairs(n_constraints, same_label=True, + random_state=random_state) + c, d = self._pairs(n_constraints, same_label=False, + random_state=random_state) + if same_length and len(a) != len(c): + n = min(len(a), len(c)) + return a[:n], b[:n], c[:n], d[:n] + return a, b, c, d
+ + +
+[docs] + def generate_knntriplets(self, X, k_genuine, k_impostor): + """ + Generates triplets from labeled data. + + For every point (X_a) the triplets (X_a, X_b, X_c) are constructed from all + the combinations of taking one of its `k_genuine`-nearest neighbors of the + same class (X_b) and taking one of its `k_impostor`-nearest neighbors of + other classes (X_c). + + In the case a class doesn't have enough points in the same class (other + classes) to yield `k_genuine` (`k_impostor`) neighbors a warning will be + raised and the maximum value of genuine (impostor) neighbors will be used + for that class. + + Parameters + ---------- + X : (n x d) matrix + Input data, where each row corresponds to a single instance. + + k_genuine : int + Number of neighbors of the same class to be taken into account. + + k_impostor : int + Number of neighbors of different classes to be taken into account. + + Returns + ------- + triplets : array-like, shape=(n_constraints, 3) + 2D array of triplets of indicators. + """ + # Ignore unlabeled samples + known_labels_mask = self.partial_labels >= 0 + known_labels = self.partial_labels[known_labels_mask] + X = X[known_labels_mask] + + labels, labels_count = np.unique(known_labels, return_counts=True) + len_input = known_labels.shape[0] + + # Handle the case where there are too few elements to yield k_genuine or + # k_impostor neighbors for every class. + + k_genuine_vec = np.full_like(labels, k_genuine) + k_impostor_vec = np.full_like(labels, k_impostor) + + for i, count in enumerate(labels_count): + if k_genuine + 1 > count: + k_genuine_vec[i] = count-1 + warnings.warn("The class {} has {} elements, which is not sufficient " + "to generate {} genuine neighbors as specified by " + "k_genuine. Will generate {} genuine neighbors instead." + "\n" + .format(labels[i], count, k_genuine+1, + k_genuine_vec[i])) + if k_impostor > len_input - count: + k_impostor_vec[i] = len_input - count + warnings.warn("The class {} has {} elements of other classes, which is" + " not sufficient to generate {} impostor neighbors as " + "specified by k_impostor. Will generate {} impostor " + "neighbors instead.\n" + .format(labels[i], k_impostor_vec[i], k_impostor, + k_impostor_vec[i])) + + # The total number of possible triplets combinations per label comes from + # taking one of the k_genuine_vec[i] genuine neighbors and one of the + # k_impostor_vec[i] impostor neighbors for the labels_count[i] elements + comb_per_label = labels_count * k_genuine_vec * k_impostor_vec + + # Get start and finish for later triplet assigning + # append zero at the begining for start and get cumulative sum + start_finish_indices = np.hstack((0, comb_per_label)).cumsum() + + # Total number of triplets is the sum of all possible combinations per + # label + num_triplets = start_finish_indices[-1] + triplets = np.empty((num_triplets, 3), dtype=np.intp) + + neigh = NearestNeighbors() + + for i, label in enumerate(labels): + + # generate mask for current label + gen_mask = known_labels == label + gen_indx = np.where(gen_mask) + + # get k_genuine genuine neighbors + neigh.fit(X=X[gen_indx]) + # Take elements of gen_indx according to the yielded k-neighbors + gen_relative_indx = neigh.kneighbors(n_neighbors=k_genuine_vec[i], + return_distance=False) + gen_neigh = np.take(gen_indx, gen_relative_indx) + + # generate mask for impostors of current label + imp_indx = np.where(~gen_mask) + + # get k_impostor impostor neighbors + neigh.fit(X=X[imp_indx]) + # Take elements of imp_indx according to the yielded k-neighbors + imp_relative_indx = neigh.kneighbors(n_neighbors=k_impostor_vec[i], + X=X[gen_mask], + return_distance=False) + imp_neigh = np.take(imp_indx, imp_relative_indx) + + # length = len_label*k_genuine*k_impostor + start, finish = start_finish_indices[i:i+2] + + triplets[start:finish, :] = comb(gen_indx, gen_neigh, imp_neigh, + k_genuine_vec[i], + k_impostor_vec[i]) + + return triplets
+ + + def _pairs(self, n_constraints, same_label=True, max_iter=10, + random_state=np.random): + known_label_idx, = np.where(self.partial_labels >= 0) + known_labels = self.partial_labels[known_label_idx] + num_labels = len(known_labels) + ab = set() + it = 0 + while it < max_iter and len(ab) < n_constraints: + nc = n_constraints - len(ab) + for aidx in random_state.randint(num_labels, size=nc): + if same_label: + mask = known_labels[aidx] == known_labels + mask[aidx] = False # avoid identity pairs + else: + mask = known_labels[aidx] != known_labels + b_choices, = np.where(mask) + if len(b_choices) > 0: + ab.add((aidx, random_state.choice(b_choices))) + it += 1 + if len(ab) < n_constraints: + warnings.warn("Only generated %d %s constraints (requested %d)" % ( + len(ab), 'positive' if same_label else 'negative', n_constraints)) + ab = np.array(list(ab)[:n_constraints], dtype=int) + return known_label_idx[ab.T] + +
+[docs] + def chunks(self, n_chunks=100, chunk_size=2, random_state=None, + num_chunks='deprecated'): + """ + Generates chunks from labeled data. + + Each of ``n_chunks`` chunks is composed of ``chunk_size`` points from + the same class drawn at random. Each point can belong to at most 1 chunk. + + In the case where there is not enough points to generate ``n_chunks`` + chunks of size ``chunk_size``, a ValueError will be raised. + + Parameters + ---------- + n_chunks : int, optional (default=100) + Number of chunks to generate. + + chunk_size : int, optional (default=2) + Number of points in each chunk. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. + + num_chunks : Renamed to n_chunks. Will be deprecated in 0.7.0 + + Returns + ------- + chunks : array-like, shape=(n_samples,) + 1D array of chunk indicators, where -1 indicates that the point does not + belong to any chunk. + """ + if num_chunks != 'deprecated': + warnings.warn('"num_chunks" parameter has been renamed to' + ' "n_chunks". It has been deprecated in' + ' version 0.6.3 and will be removed in 0.7.0' + '', FutureWarning) + n_chunks = num_chunks + random_state = check_random_state(random_state) + chunks = -np.ones_like(self.partial_labels, dtype=int) + uniq, lookup = np.unique(self.partial_labels, return_inverse=True) + unknown_uniq = np.where(uniq < 0)[0] + all_inds = [set(np.where(lookup == c)[0]) for c in range(len(uniq)) + if c not in unknown_uniq] + max_chunks = int(np.sum([len(s) // chunk_size for s in all_inds])) + if max_chunks < n_chunks: + raise ValueError(('Not enough possible chunks of %d elements in each' + ' class to form expected %d chunks - maximum number' + ' of chunks is %d' + ) % (chunk_size, n_chunks, max_chunks)) + idx = 0 + while idx < n_chunks and all_inds: + if len(all_inds) == 1: + c = 0 + else: + c = random_state.randint(0, high=len(all_inds) - 1) + inds = all_inds[c] + if len(inds) < chunk_size: + del all_inds[c] + continue + ii = random_state.choice(list(inds), chunk_size, replace=False) + inds.difference_update(ii) + chunks[ii] = idx + idx += 1 + return chunks
+
+ + + +def comb(A, B, C, sizeB, sizeC): + # generate_knntriplets helper function + # generate an array with all combinations of choosing + # an element from A, B and C + return np.vstack((np.tile(A, (sizeB*sizeC, 1)).ravel(order='F'), + np.tile(np.hstack(B), (sizeC, 1)).ravel(order='F'), + np.tile(C, (1, sizeB)).ravel())).T + + +def wrap_pairs(X, constraints): + a = np.array(constraints[0]) + b = np.array(constraints[1]) + c = np.array(constraints[2]) + d = np.array(constraints[3]) + constraints = np.vstack((np.column_stack((a, b)), np.column_stack((c, d)))) + y = np.concatenate([np.ones_like(a), -np.ones_like(c)]) + pairs = X[constraints] + return pairs, y +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/covariance.html b/_modules/metric_learn/covariance.html new file mode 100644 index 00000000..c71589be --- /dev/null +++ b/_modules/metric_learn/covariance.html @@ -0,0 +1,187 @@ + + + + + + metric_learn.covariance — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.covariance

+"""
+Covariance metric (baseline method)
+"""
+
+import numpy as np
+import scipy
+from sklearn.base import TransformerMixin
+
+from .base_metric import MahalanobisMixin
+from ._util import components_from_metric
+
+
+
+[docs] +class Covariance(MahalanobisMixin, TransformerMixin): + """Covariance metric (baseline method) + + This method does not "learn" anything, rather it calculates + the covariance matrix of the input data. + + This is a simple baseline method first introduced in + On the Generalized Distance in Statistics, P.C.Mahalanobis, 1936 + + Read more in the :ref:`User Guide <covariance>`. + + Attributes + ---------- + components_ : `numpy.ndarray`, shape=(n_features, n_features) + The linear transformation ``L`` deduced from the learned Mahalanobis + metric (See function `components_from_metric`.) + + Examples + -------- + >>> from metric_learn import Covariance + >>> from sklearn.datasets import load_iris + >>> iris = load_iris()['data'] + >>> cov = Covariance().fit(iris) + >>> x = cov.transform(iris) + + """ + +
+[docs] + def __init__(self, preprocessor=None): + super(Covariance, self).__init__(preprocessor)
+ + +
+[docs] + def fit(self, X, y=None): + """ + Calculates the covariance matrix of the input data. + + Parameters + ---------- + X : data matrix, (n x d) + y : unused + """ + X = self._prepare_inputs(X, ensure_min_samples=2) + M = np.atleast_2d(np.cov(X, rowvar=False)) + if M.size == 1: + M = 1. / M + else: + M = scipy.linalg.pinvh(M) + + self.components_ = components_from_metric(np.atleast_2d(M)) + return self
+
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/itml.html b/_modules/metric_learn/itml.html new file mode 100644 index 00000000..6ee1baa1 --- /dev/null +++ b/_modules/metric_learn/itml.html @@ -0,0 +1,540 @@ + + + + + + metric_learn.itml — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.itml

+"""
+Information Theoretic Metric Learning (ITML)
+"""
+
+import numpy as np
+from sklearn.metrics import pairwise_distances
+from sklearn.utils.validation import check_array
+from sklearn.base import TransformerMixin
+from .base_metric import _PairsClassifierMixin, MahalanobisMixin
+from .constraints import Constraints, wrap_pairs
+from ._util import components_from_metric, _initialize_metric_mahalanobis
+import warnings
+
+
+class _BaseITML(MahalanobisMixin):
+  """Information Theoretic Metric Learning (ITML)"""
+
+  _tuple_size = 2  # constraints are pairs
+
+  def __init__(self, gamma=1., max_iter=1000, tol=1e-3,
+               prior='identity', verbose=False,
+               preprocessor=None, random_state=None,
+               convergence_threshold='deprecated'):
+    if convergence_threshold != 'deprecated':
+      warnings.warn('"convergence_threshold" parameter has been '
+                    ' renamed to "tol". It has been deprecated in'
+                    ' version 0.6.3 and will be removed in 0.7.0'
+                    '', FutureWarning)
+      tol = convergence_threshold
+    self.convergence_threshold = 'deprecated'  # Avoid errors
+    self.gamma = gamma
+    self.max_iter = max_iter
+    self.tol = tol
+    self.prior = prior
+    self.verbose = verbose
+    self.random_state = random_state
+    super(_BaseITML, self).__init__(preprocessor)
+
+  def _fit(self, pairs, y, bounds=None):
+    pairs, y = self._prepare_inputs(pairs, y,
+                                    type_of_inputs='tuples')
+    # init bounds
+    if bounds is None:
+      X = np.unique(np.vstack(pairs), axis=0)
+      self.bounds_ = np.percentile(pairwise_distances(X), (5, 95))
+    else:
+      bounds = check_array(bounds, allow_nd=False, ensure_min_samples=0,
+                           ensure_2d=False)
+      bounds = bounds.ravel()
+      if bounds.size != 2:
+        raise ValueError("`bounds` should be an array-like of two elements.")
+      self.bounds_ = bounds
+    self.bounds_[self.bounds_ == 0] = 1e-9
+    # set the prior
+    # pairs will be deduplicated into X two times, TODO: avoid that
+    A = _initialize_metric_mahalanobis(pairs, self.prior, self.random_state,
+                                       strict_pd=True,
+                                       matrix_name='prior')
+    gamma = self.gamma
+    pos_pairs, neg_pairs = pairs[y == 1], pairs[y == -1]
+    num_pos = len(pos_pairs)
+    num_neg = len(neg_pairs)
+    _lambda = np.zeros(num_pos + num_neg)
+    lambdaold = np.zeros_like(_lambda)
+    gamma_proj = 1. if gamma is np.inf else gamma / (gamma + 1.)
+    pos_bhat = np.zeros(num_pos) + self.bounds_[0]
+    neg_bhat = np.zeros(num_neg) + self.bounds_[1]
+    pos_vv = pos_pairs[:, 0, :] - pos_pairs[:, 1, :]
+    neg_vv = neg_pairs[:, 0, :] - neg_pairs[:, 1, :]
+
+    for it in range(self.max_iter):
+      # update positives
+      for i, v in enumerate(pos_vv):
+        wtw = v.dot(A).dot(v)  # scalar
+        alpha = min(_lambda[i], gamma_proj * (1. / wtw - 1. / pos_bhat[i]))
+        _lambda[i] -= alpha
+        beta = alpha / (1 - alpha * wtw)
+        pos_bhat[i] = 1. / ((1 / pos_bhat[i]) + (alpha / gamma))
+        Av = A.dot(v)
+        A += np.outer(Av, Av * beta)
+
+      # update negatives
+      for i, v in enumerate(neg_vv):
+        wtw = v.dot(A).dot(v)  # scalar
+        alpha = min(_lambda[i + num_pos],
+                    gamma_proj * (1. / neg_bhat[i] - 1. / wtw))
+        _lambda[i + num_pos] -= alpha
+        beta = -alpha / (1 + alpha * wtw)
+        neg_bhat[i] = 1. / ((1 / neg_bhat[i]) - (alpha / gamma))
+        Av = A.dot(v)
+        A += np.outer(Av, Av * beta)
+
+      normsum = np.linalg.norm(_lambda) + np.linalg.norm(lambdaold)
+      if normsum == 0:
+        conv = np.inf
+        break
+      conv = np.abs(lambdaold - _lambda).sum() / normsum
+      if conv < self.tol:
+        break
+      lambdaold = _lambda.copy()
+      if self.verbose:
+        print('itml iter: %d, conv = %f' % (it, conv))
+
+    if self.verbose:
+      print('itml converged at iter: %d, conv = %f' % (it, conv))
+    self.n_iter_ = it
+
+    self.components_ = components_from_metric(A)
+    return self
+
+
+
+[docs] +class ITML(_BaseITML, _PairsClassifierMixin): + """Information Theoretic Metric Learning (ITML) + + `ITML` minimizes the (differential) relative entropy, aka Kullback-Leibler + divergence, between two multivariate Gaussians subject to constraints on the + associated Mahalanobis distance, which can be formulated into a Bregman + optimization problem by minimizing the LogDet divergence subject to + linear constraints. This algorithm can handle a wide variety of constraints + and can optionally incorporate a prior on the distance function. Unlike some + other methods, `ITML` does not rely on an eigenvalue computation or + semi-definite programming. + + Read more in the :ref:`User Guide <itml>`. + + Parameters + ---------- + gamma : float, optional (default=1.0) + Value for slack variables + + max_iter : int, optional (default=1000) + Maximum number of iteration of the optimization procedure. + + tol : float, optional (default=1e-3) + Convergence tolerance. + + prior : string or numpy array, optional (default='identity') + The Mahalanobis matrix to use as a prior. Possible options are + 'identity', 'covariance', 'random', and a numpy array of shape + (n_features, n_features). For ITML, the prior should be strictly + positive definite (PD). + + 'identity' + An identity matrix of shape (n_features, n_features). + + 'covariance' + The inverse covariance matrix. + + 'random' + The prior will be a random SPD matrix of shape + `(n_features, n_features)`, generated using + `sklearn.datasets.make_spd_matrix`. + + numpy array + A positive definite (PD) matrix of shape + (n_features, n_features), that will be used as such to set the + prior. + + verbose : bool, optional (default=False) + If True, prints information while learning + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be formed like this: X[indices]. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. If + ``prior='random'``, ``random_state`` is used to set the prior. + + convergence_threshold : Renamed to tol. Will be deprecated in 0.7.0 + + Attributes + ---------- + bounds_ : `numpy.ndarray`, shape=(2,) + Bounds on similarity, aside slack variables, s.t. + ``d(a, b) < bounds_[0]`` for all given pairs of similar points ``a`` + and ``b``, and ``d(c, d) > bounds_[1]`` for all given pairs of + dissimilar points ``c`` and ``d``, with ``d`` the learned distance. If + not provided at initialization, bounds_[0] and bounds_[1] are set at + train time to the 5th and 95th percentile of the pairwise distances among + all points present in the input `pairs`. + + n_iter_ : `int` + The number of iterations the solver has run. + + components_ : `numpy.ndarray`, shape=(n_features, n_features) + The linear transformation ``L`` deduced from the learned Mahalanobis + metric (See function `components_from_metric`.) + + threshold_ : `float` + If the distance metric between two points is lower than this threshold, + points will be classified as similar, otherwise they will be + classified as dissimilar. + + Examples + -------- + >>> from metric_learn import ITML + >>> pairs = [[[1.2, 7.5], [1.3, 1.5]], + >>> [[6.4, 2.6], [6.2, 9.7]], + >>> [[1.3, 4.5], [3.2, 4.6]], + >>> [[6.2, 5.5], [5.4, 5.4]]] + >>> y = [1, 1, -1, -1] + >>> # in this task we want points where the first feature is close to be + >>> # closer to each other, no matter how close the second feature is + >>> itml = ITML() + >>> itml.fit(pairs, y) + + References + ---------- + .. [1] Jason V. Davis, et al. `Information-theoretic Metric Learning + <http://www.prateekjain.org/publications/all_papers\ + /DavisKJSD07_ICML.pdf>`_. ICML 2007. + """ + +
+[docs] + def fit(self, pairs, y, bounds=None, calibration_params=None): + """Learn the ITML model. + + The threshold will be calibrated on the trainset using the parameters + `calibration_params`. + + Parameters + ---------- + pairs: array-like, shape=(n_constraints, 2, n_features) or \ + (n_constraints, 2) + 3D Array of pairs with each row corresponding to two points, + or 2D array of indices of pairs if the metric learner uses a + preprocessor. + + y: array-like, of shape (n_constraints,) + Labels of constraints. Should be -1 for dissimilar pair, 1 for similar. + + bounds : array-like of two numbers + Bounds on similarity, aside slack variables, s.t. + ``d(a, b) < bounds_[0]`` for all given pairs of similar points ``a`` + and ``b``, and ``d(c, d) > bounds_[1]`` for all given pairs of + dissimilar points ``c`` and ``d``, with ``d`` the learned distance. + If not provided at initialization, bounds_[0] and bounds_[1] will be + set to the 5th and 95th percentile of the pairwise distances among all + points present in the input `pairs`. + + calibration_params : `dict` or `None` + Dictionary of parameters to give to `calibrate_threshold` for the + threshold calibration step done at the end of `fit`. If `None` is + given, `calibrate_threshold` will use the default parameters. + + Returns + ------- + self : object + Returns the instance. + """ + calibration_params = (calibration_params if calibration_params is not + None else dict()) + self._validate_calibration_params(**calibration_params) + self._fit(pairs, y, bounds=bounds) + self.calibrate_threshold(pairs, y, **calibration_params) + return self
+
+ + + +
+[docs] +class ITML_Supervised(_BaseITML, TransformerMixin): + """Supervised version of Information Theoretic Metric Learning (ITML) + + `ITML_Supervised` creates pairs of similar sample by taking same class + samples, and pairs of dissimilar samples by taking different class + samples. It then passes these pairs to `ITML` for training. + + Parameters + ---------- + gamma : float, optional (default=1.0) + Value for slack variables + + max_iter : int, optional (default=1000) + Maximum number of iterations of the optimization procedure. + + tol : float, optional (default=1e-3) + Tolerance of the optimization procedure. + + n_constraints : int, optional (default=None) + Number of constraints to generate. If None, default to `20 * + num_classes**2`. + + prior : string or numpy array, optional (default='identity') + Initialization of the Mahalanobis matrix. Possible options are + 'identity', 'covariance', 'random', and a numpy array of shape + (n_features, n_features). For ITML, the prior should be strictly + positive definite (PD). + + 'identity' + An identity matrix of shape (n_features, n_features). + + 'covariance' + The inverse covariance matrix. + + 'random' + The prior will be a random SPD matrix of shape + `(n_features, n_features)`, generated using + `sklearn.datasets.make_spd_matrix`. + + numpy array + A positive definite (PD) matrix of shape + (n_features, n_features), that will be used as such to set the + prior. + + verbose : bool, optional (default=False) + If True, prints information while learning + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be formed like this: X[indices]. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. If + ``prior='random'``, ``random_state`` is used to set the prior. In any + case, `random_state` is also used to randomly sample constraints from + labels. + + num_constraints : Renamed to n_constraints. Will be deprecated in 0.7.0 + + convergence_threshold : Renamed to tol. Will be deprecated in 0.7.0 + + Attributes + ---------- + bounds_ : `numpy.ndarray`, shape=(2,) + Bounds on similarity, aside slack variables, s.t. + ``d(a, b) < bounds_[0]`` for all given pairs of similar points ``a`` + and ``b``, and ``d(c, d) > bounds_[1]`` for all given pairs of + dissimilar points ``c`` and ``d``, with ``d`` the learned distance. + If not provided at initialization, bounds_[0] and bounds_[1] are set at + train time to the 5th and 95th percentile of the pairwise distances + among all points in the training data `X`. + + n_iter_ : `int` + The number of iterations the solver has run. + + components_ : `numpy.ndarray`, shape=(n_features, n_features) + The linear transformation ``L`` deduced from the learned Mahalanobis + metric (See function `components_from_metric`.) + + Examples + -------- + >>> from metric_learn import ITML_Supervised + >>> from sklearn.datasets import load_iris + >>> iris_data = load_iris() + >>> X = iris_data['data'] + >>> Y = iris_data['target'] + >>> itml = ITML_Supervised(n_constraints=200) + >>> itml.fit(X, Y) + + See Also + -------- + metric_learn.ITML : The original weakly-supervised algorithm + :ref:`supervised_version` : The section of the project documentation + that describes the supervised version of weakly supervised estimators. + """ + +
+[docs] + def __init__(self, gamma=1.0, max_iter=1000, tol=1e-3, + n_constraints=None, prior='identity', + verbose=False, preprocessor=None, random_state=None, + num_constraints='deprecated', + convergence_threshold='deprecated'): + _BaseITML.__init__(self, gamma=gamma, max_iter=max_iter, + tol=tol, + prior=prior, verbose=verbose, + preprocessor=preprocessor, + random_state=random_state, + convergence_threshold=convergence_threshold) + if num_constraints != 'deprecated': + warnings.warn('"num_constraints" parameter has been renamed to' + ' "n_constraints". It has been deprecated in' + ' version 0.6.3 and will be removed in 0.7.0' + '', FutureWarning) + n_constraints = num_constraints + self.n_constraints = n_constraints + # Avoid test get_params from failing (all params passed sholud be set) + self.num_constraints = 'deprecated'
+ + +
+[docs] + def fit(self, X, y, bounds=None): + """Create constraints from labels and learn the ITML model. + + + Parameters + ---------- + X : (n x d) matrix + Input data, where each row corresponds to a single instance. + + y : (n) array-like + Data labels. + + bounds : array-like of two numbers + Bounds on similarity, aside slack variables, s.t. + ``d(a, b) < bounds_[0]`` for all given pairs of similar points ``a`` + and ``b``, and ``d(c, d) > bounds_[1]`` for all given pairs of + dissimilar points ``c`` and ``d``, with ``d`` the learned distance. + If not provided at initialization, bounds_[0] and bounds_[1] will be + set to the 5th and 95th percentile of the pairwise distances among all + points in the training data `X`. + """ + X, y = self._prepare_inputs(X, y, ensure_min_samples=2) + n_constraints = self.n_constraints + if n_constraints is None: + num_classes = len(np.unique(y)) + n_constraints = 20 * num_classes**2 + + c = Constraints(y) + pos_neg = c.positive_negative_pairs(n_constraints, + random_state=self.random_state) + pairs, y = wrap_pairs(X, pos_neg) + return _BaseITML._fit(self, pairs, y, bounds=bounds)
+
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/lfda.html b/_modules/metric_learn/lfda.html new file mode 100644 index 00000000..fdce45c5 --- /dev/null +++ b/_modules/metric_learn/lfda.html @@ -0,0 +1,298 @@ + + + + + + metric_learn.lfda — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.lfda

+"""
+Local Fisher Discriminant Analysis (LFDA)
+"""
+import numpy as np
+import scipy
+import warnings
+from sklearn.metrics import pairwise_distances
+from sklearn.base import TransformerMixin
+
+from ._util import _check_n_components
+from .base_metric import MahalanobisMixin
+
+
+
+[docs] +class LFDA(MahalanobisMixin, TransformerMixin): + ''' + Local Fisher Discriminant Analysis for Supervised Dimensionality Reduction + + LFDA is a linear supervised dimensionality reduction method. It is + particularly useful when dealing with multimodality, where one ore more + classes consist of separate clusters in input space. The core optimization + problem of LFDA is solved as a generalized eigenvalue problem. + + Read more in the :ref:`User Guide <lfda>`. + + Parameters + ---------- + n_components : int or None, optional (default=None) + Dimensionality of reduced space (if None, defaults to dimension of X). + + k : int, optional (default=None) + Number of nearest neighbors used in local scaling method. If None, + defaults to min(7, n_features - 1). + + embedding_type : str, optional (default: 'weighted') + Type of metric in the embedding space. + + 'weighted' + weighted eigenvectors + + 'orthonormalized' + orthonormalized + + 'plain' + raw eigenvectors + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be formed like this: X[indices]. + + Attributes + ---------- + components_ : `numpy.ndarray`, shape=(n_components, n_features) + The learned linear transformation ``L``. + + Examples + -------- + + >>> import numpy as np + >>> from metric_learn import LFDA + >>> from sklearn.datasets import load_iris + >>> iris_data = load_iris() + >>> X = iris_data['data'] + >>> Y = iris_data['target'] + >>> lfda = LFDA(k=2, dim=2) + >>> lfda.fit(X, Y) + + References + ---------- + .. [1] Masashi Sugiyama. `Dimensionality Reduction of Multimodal Labeled + Data by Local Fisher Discriminant Analysis + <http://www.ms.k.u-tokyo.ac.jp/2007/LFDA.pdf>`_. JMLR 2007. + + .. [2] Yuan Tang. `Local Fisher Discriminant Analysis on Beer Style + Clustering + <https://gastrograph.com/resources/whitepapers/local-fisher\ + -discriminant-analysis-on-beer-style-clustering.html#>`_. + ''' + +
+[docs] + def __init__(self, n_components=None, + k=None, embedding_type='weighted', preprocessor=None): + if embedding_type not in ('weighted', 'orthonormalized', 'plain'): + raise ValueError('Invalid embedding_type: %r' % embedding_type) + self.n_components = n_components + self.embedding_type = embedding_type + self.k = k + super(LFDA, self).__init__(preprocessor)
+ + +
+[docs] + def fit(self, X, y): + '''Fit the LFDA model. + + Parameters + ---------- + X : (n, d) array-like + Input data. + + y : (n,) array-like + Class labels, one per point of data. + ''' + X, y = self._prepare_inputs(X, y, ensure_min_samples=2) + unique_classes, y = np.unique(y, return_inverse=True) + n, d = X.shape + num_classes = len(unique_classes) + + dim = _check_n_components(d, self.n_components) + + if self.k is None: + k = min(7, d - 1) + elif self.k >= d: + warnings.warn('Chosen k (%d) too large, using %d instead.' + % (self.k, d - 1)) + k = d - 1 + else: + k = int(self.k) + tSb = np.zeros((d, d)) + tSw = np.zeros((d, d)) + + for c in range(num_classes): + Xc = X[y == c] + nc = Xc.shape[0] + + # classwise affinity matrix + dist = pairwise_distances(Xc, metric='l2', squared=True) + # distances to k-th nearest neighbor + k = min(k, nc - 1) + sigma = np.sqrt(np.partition(dist, k, axis=0)[:, k]) + + local_scale = np.outer(sigma, sigma) + with np.errstate(divide='ignore', invalid='ignore'): + A = np.exp(-dist / local_scale) + A[local_scale == 0] = 0 + + G = Xc.T.dot(A.sum(axis=0)[:, None] * Xc) - Xc.T.dot(A).dot(Xc) + tSb += G / n + (1 - nc / n) * Xc.T.dot(Xc) + _sum_outer(Xc) / n + tSw += G / nc + + tSb -= _sum_outer(X) / n - tSw + + # symmetrize + tSb = (tSb + tSb.T) / 2 + tSw = (tSw + tSw.T) / 2 + + vals, vecs = _eigh(tSb, tSw, dim) + order = np.argsort(-vals)[:dim] + vals = vals[order].real + vecs = vecs[:, order] + + if self.embedding_type == 'weighted': + vecs *= np.sqrt(vals) + elif self.embedding_type == 'orthonormalized': + vecs, _ = np.linalg.qr(vecs) + + self.components_ = vecs.T + return self
+
+ + + +def _sum_outer(x): + s = x.sum(axis=0) + return np.outer(s, s) + + +def _eigh(a, b, dim): + try: + return scipy.sparse.linalg.eigsh(a, k=dim, M=b, which='LA') + except np.linalg.LinAlgError: + pass # scipy already tried eigh for us + except (ValueError, scipy.sparse.linalg.ArpackNoConvergence): + try: + return scipy.linalg.eigh(a, b) + except np.linalg.LinAlgError: + pass + return scipy.linalg.eig(a, b) +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/lmnn.html b/_modules/metric_learn/lmnn.html new file mode 100644 index 00000000..e886c8a7 --- /dev/null +++ b/_modules/metric_learn/lmnn.html @@ -0,0 +1,470 @@ + + + + + + metric_learn.lmnn — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.lmnn

+"""
+Large Margin Nearest Neighbor Metric learning (LMNN)
+"""
+import numpy as np
+from collections import Counter
+from sklearn.metrics import euclidean_distances
+from sklearn.base import TransformerMixin
+import warnings
+
+from ._util import _initialize_components, _check_n_components
+from .base_metric import MahalanobisMixin
+
+
+
+[docs] +class LMNN(MahalanobisMixin, TransformerMixin): + """Large Margin Nearest Neighbor (LMNN) + + LMNN learns a Mahalanobis distance metric in the kNN classification + setting. The learned metric attempts to keep close k-nearest neighbors + from the same class, while keeping examples from different classes + separated by a large margin. This algorithm makes no assumptions about + the distribution of the data. + + Read more in the :ref:`User Guide <lmnn>`. + + Parameters + ---------- + init : string or numpy array, optional (default='auto') + Initialization of the linear transformation. Possible options are + 'auto', 'pca', 'identity', 'random', and a numpy array of shape + (n_features_a, n_features_b). + + 'auto' + Depending on ``n_components``, the most reasonable initialization + will be chosen. If ``n_components <= n_classes`` we use 'lda', as + it uses labels information. If not, but + ``n_components < min(n_features, n_samples)``, we use 'pca', as + it projects data in meaningful directions (those of higher + variance). Otherwise, we just use 'identity'. + + 'pca' + ``n_components`` principal components of the inputs passed + to :meth:`fit` will be used to initialize the transformation. + (See `sklearn.decomposition.PCA`) + + 'lda' + ``min(n_components, n_classes)`` most discriminative + components of the inputs passed to :meth:`fit` will be used to + initialize the transformation. (If ``n_components > n_classes``, + the rest of the components will be zero.) (See + `sklearn.discriminant_analysis.LinearDiscriminantAnalysis`) + + 'identity' + If ``n_components`` is strictly smaller than the + dimensionality of the inputs passed to :meth:`fit`, the identity + matrix will be truncated to the first ``n_components`` rows. + + 'random' + The initial transformation will be a random array of shape + `(n_components, n_features)`. Each value is sampled from the + standard normal distribution. + + numpy array + n_features_b must match the dimensionality of the inputs passed to + :meth:`fit` and n_features_a must be less than or equal to that. + If ``n_components`` is not None, n_features_a must match it. + + n_neighbors : int, optional (default=3) + Number of neighbors to consider, not including self-edges. + + min_iter : int, optional (default=50) + Minimum number of iterations of the optimization procedure. + + max_iter : int, optional (default=1000) + Maximum number of iterations of the optimization procedure. + + learn_rate : float, optional (default=1e-7) + Learning rate of the optimization procedure + + tol : float, optional (default=0.001) + Tolerance of the optimization procedure. If the objective value varies + less than `tol`, we consider the algorithm has converged and stop it. + + verbose : bool, optional (default=False) + Whether to print the progress of the optimization procedure. + + regularization: float, optional (default=0.5) + Relative weight between pull and push terms, with 0.5 meaning equal + weight. + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be formed like this: X[indices]. + + n_components : int or None, optional (default=None) + Dimensionality of reduced space (if None, defaults to dimension of X). + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. If + ``init='random'``, ``random_state`` is used to initialize the random + transformation. If ``init='pca'``, ``random_state`` is passed as an + argument to PCA when initializing the transformation. + + k : Renamed to n_neighbors. Will be deprecated in 0.7.0 + + Attributes + ---------- + n_iter_ : `int` + The number of iterations the solver has run. + + components_ : `numpy.ndarray`, shape=(n_components, n_features) + The learned linear transformation ``L``. + + Examples + -------- + + >>> import numpy as np + >>> from metric_learn import LMNN + >>> from sklearn.datasets import load_iris + >>> iris_data = load_iris() + >>> X = iris_data['data'] + >>> Y = iris_data['target'] + >>> lmnn = LMNN(n_neighbors=5, learn_rate=1e-6) + >>> lmnn.fit(X, Y, verbose=False) + + References + ---------- + .. [1] K. Q. Weinberger, J. Blitzer, L. K. Saul. `Distance Metric + Learning for Large Margin Nearest Neighbor Classification + <http://papers.nips.cc/paper/2795-distance-metric\ + -learning-for-large-margin-nearest-neighbor-classification>`_. NIPS + 2005. + """ + +
+[docs] + def __init__(self, init='auto', n_neighbors=3, min_iter=50, max_iter=1000, + learn_rate=1e-7, regularization=0.5, convergence_tol=0.001, + verbose=False, preprocessor=None, + n_components=None, random_state=None, k='deprecated'): + self.init = init + if k != 'deprecated': + warnings.warn('"num_chunks" parameter has been renamed to' + ' "n_chunks". It has been deprecated in' + ' version 0.6.3 and will be removed in 0.7.0' + '', FutureWarning) + n_neighbors = k + self.k = 'deprecated' # To avoid no_attribute error + self.n_neighbors = n_neighbors + self.min_iter = min_iter + self.max_iter = max_iter + self.learn_rate = learn_rate + self.regularization = regularization + self.convergence_tol = convergence_tol + self.verbose = verbose + self.n_components = n_components + self.random_state = random_state + super(LMNN, self).__init__(preprocessor)
+ + +
+[docs] + def fit(self, X, y): + k = self.n_neighbors + reg = self.regularization + learn_rate = self.learn_rate + + X, y = self._prepare_inputs(X, y, dtype=float, + ensure_min_samples=2) + num_pts, d = X.shape + output_dim = _check_n_components(d, self.n_components) + unique_labels, label_inds = np.unique(y, return_inverse=True) + if len(label_inds) != num_pts: + raise ValueError('Must have one label per point.') + self.labels_ = np.arange(len(unique_labels)) + + self.components_ = _initialize_components(output_dim, X, y, self.init, + self.verbose, + random_state=self.random_state) + required_k = np.bincount(label_inds).min() + if self.n_neighbors > required_k: + raise ValueError('not enough class labels for specified k' + ' (smallest class has %d)' % required_k) + + target_neighbors = self._select_targets(X, label_inds) + + # sum outer products + dfG = _sum_outer_products(X, target_neighbors.flatten(), + np.repeat(np.arange(X.shape[0]), k)) + + # initialize L + L = self.components_ + + # first iteration: we compute variables (including objective and gradient) + # at initialization point + G, objective, total_active = self._loss_grad(X, L, dfG, k, + reg, target_neighbors, + label_inds) + + it = 1 # we already made one iteration + + if self.verbose: + print("iter | objective | objective difference | active constraints", + "| learning rate") + + # main loop + for it in range(2, self.max_iter): + # then at each iteration, we try to find a value of L that has better + # objective than the previous L, following the gradient: + while True: + # the next point next_L to try out is found by a gradient step + L_next = L - learn_rate * G + # we compute the objective at next point + # we copy variables that can be modified by _loss_grad, because if we + # retry we don t want to modify them several times + (G_next, objective_next, total_active_next) = ( + self._loss_grad(X, L_next, dfG, k, reg, target_neighbors, + label_inds)) + assert not np.isnan(objective) + delta_obj = objective_next - objective + if delta_obj > 0: + # if we did not find a better objective, we retry with an L closer to + # the starting point, by decreasing the learning rate (making the + # gradient step smaller) + learn_rate /= 2 + else: + # otherwise, if we indeed found a better obj, we get out of the loop + break + # when the better L is found (and the related variables), we set the + # old variables to these new ones before next iteration and we + # slightly increase the learning rate + L = L_next + G, objective, total_active = G_next, objective_next, total_active_next + learn_rate *= 1.01 + + if self.verbose: + print(it, objective, delta_obj, total_active, learn_rate) + + # check for convergence + if it > self.min_iter and abs(delta_obj) < self.convergence_tol: + if self.verbose: + print("LMNN converged with objective", objective) + break + else: + if self.verbose: + print("LMNN didn't converge in %d steps." % self.max_iter) + + # store the last L + self.components_ = L + self.n_iter_ = it + return self
+ + + def _loss_grad(self, X, L, dfG, k, reg, target_neighbors, label_inds): + # Compute pairwise distances under current metric + Lx = L.dot(X.T).T + + # we need to find the furthest neighbor: + Ni = 1 + _inplace_paired_L2(Lx[target_neighbors], Lx[:, None, :]) + furthest_neighbors = np.take_along_axis(target_neighbors, + Ni.argmax(axis=1)[:, None], 1) + impostors = self._find_impostors(furthest_neighbors.ravel(), X, + label_inds, L) + + g0 = _inplace_paired_L2(*Lx[impostors]) + + # we reorder the target neighbors + g1, g2 = Ni[impostors] + # compute the gradient + total_active = 0 + df = np.zeros((X.shape[1], X.shape[1])) + for nn_idx in reversed(range(k)): # note: reverse not useful here + act1 = g0 < g1[:, nn_idx] + act2 = g0 < g2[:, nn_idx] + total_active += act1.sum() + act2.sum() + + targets = target_neighbors[:, nn_idx] + PLUS, pweight = _count_edges(act1, act2, impostors, targets) + df += _sum_outer_products(X, PLUS[:, 0], PLUS[:, 1], pweight) + + in_imp, out_imp = impostors + df -= _sum_outer_products(X, in_imp[act1], out_imp[act1]) + df -= _sum_outer_products(X, in_imp[act2], out_imp[act2]) + + # do the gradient update + assert not np.isnan(df).any() + G = dfG * reg + df * (1 - reg) + G = L.dot(G) + # compute the objective function + objective = total_active * (1 - reg) + objective += G.flatten().dot(L.flatten()) + return 2 * G, objective, total_active + + def _select_targets(self, X, label_inds): + target_neighbors = np.empty((X.shape[0], self.n_neighbors), dtype=int) + for label in self.labels_: + inds, = np.nonzero(label_inds == label) + dd = euclidean_distances(X[inds], squared=True) + np.fill_diagonal(dd, np.inf) + nn = np.argsort(dd)[..., :self.n_neighbors] + target_neighbors[inds] = inds[nn] + return target_neighbors + + def _find_impostors(self, furthest_neighbors, X, label_inds, L): + Lx = X.dot(L.T) + margin_radii = 1 + _inplace_paired_L2(Lx[furthest_neighbors], Lx) + impostors = [] + for label in self.labels_[:-1]: + in_inds, = np.nonzero(label_inds == label) + out_inds, = np.nonzero(label_inds > label) + dist = euclidean_distances(Lx[out_inds], Lx[in_inds], squared=True) + i1, j1 = np.nonzero(dist < margin_radii[out_inds][:, None]) + i2, j2 = np.nonzero(dist < margin_radii[in_inds]) + i = np.hstack((i1, i2)) + j = np.hstack((j1, j2)) + if i.size > 0: + # get unique (i,j) pairs using index trickery + shape = (i.max() + 1, j.max() + 1) + tmp = np.ravel_multi_index((i, j), shape) + i, j = np.unravel_index(np.unique(tmp), shape) + impostors.append(np.vstack((in_inds[j], out_inds[i]))) + if len(impostors) == 0: + # No impostors detected + return impostors + return np.hstack(impostors)
+ + + +def _inplace_paired_L2(A, B): + '''Equivalent to ((A-B)**2).sum(axis=-1), but modifies A in place.''' + A -= B + return np.einsum('...ij,...ij->...i', A, A) + + +def _count_edges(act1, act2, impostors, targets): + imp = impostors[0, act1] + c = Counter(zip(imp, targets[imp])) + imp = impostors[1, act2] + c.update(zip(imp, targets[imp])) + if c: + active_pairs = np.array(list(c.keys())) + else: + active_pairs = np.empty((0, 2), dtype=int) + return active_pairs, np.array(list(c.values())) + + +def _sum_outer_products(data, a_inds, b_inds, weights=None): + Xab = data[a_inds] - data[b_inds] + if weights is not None: + return np.dot(Xab.T, Xab * weights[:, None]) + return np.dot(Xab.T, Xab) +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/lsml.html b/_modules/metric_learn/lsml.html new file mode 100644 index 00000000..a7beb236 --- /dev/null +++ b/_modules/metric_learn/lsml.html @@ -0,0 +1,481 @@ + + + + + + metric_learn.lsml — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.lsml

+"""
+Metric Learning from Relative Comparisons by Minimizing Squared Residual (LSML)
+"""
+
+import numpy as np
+import scipy.linalg
+from sklearn.base import TransformerMixin
+
+from .base_metric import _QuadrupletsClassifierMixin, MahalanobisMixin
+from .constraints import Constraints
+from ._util import components_from_metric, _initialize_metric_mahalanobis
+import warnings
+
+
+class _BaseLSML(MahalanobisMixin):
+
+  _tuple_size = 4  # constraints are quadruplets
+
+  def __init__(self, tol=1e-3, max_iter=1000, prior='identity',
+               verbose=False, preprocessor=None, random_state=None):
+    self.prior = prior
+    self.tol = tol
+    self.max_iter = max_iter
+    self.verbose = verbose
+    self.random_state = random_state
+    super(_BaseLSML, self).__init__(preprocessor)
+
+  def _fit(self, quadruplets, weights=None):
+    quadruplets = self._prepare_inputs(quadruplets,
+                                       type_of_inputs='tuples')
+
+    # check to make sure that no two constrained vectors are identical
+    vab = quadruplets[:, 0, :] - quadruplets[:, 1, :]
+    vcd = quadruplets[:, 2, :] - quadruplets[:, 3, :]
+    if vab.shape != vcd.shape:
+      raise ValueError('Constraints must have same length')
+    if weights is None:
+      self.w_ = np.ones(vab.shape[0])
+    else:
+      self.w_ = weights
+    self.w_ /= self.w_.sum()  # weights must sum to 1
+    M, prior_inv = _initialize_metric_mahalanobis(
+        quadruplets, self.prior,
+        return_inverse=True, strict_pd=True, matrix_name='prior',
+        random_state=self.random_state)
+
+    step_sizes = np.logspace(-10, 0, 10)
+    # Keep track of the best step size and the loss at that step.
+    l_best = 0
+    s_best = self._total_loss(M, vab, vcd, prior_inv)
+    if self.verbose:
+      print('initial loss', s_best)
+    for it in range(1, self.max_iter + 1):
+      grad = self._gradient(M, vab, vcd, prior_inv)
+      grad_norm = scipy.linalg.norm(grad)
+      if grad_norm < self.tol:
+        break
+      if self.verbose:
+        print('gradient norm', grad_norm)
+      M_best = None
+      for step_size in step_sizes:
+        step_size /= grad_norm
+        new_metric = M - step_size * grad
+        w, v = scipy.linalg.eigh(new_metric)
+        new_metric = v.dot((np.maximum(w, 1e-8) * v).T)
+        cur_s = self._total_loss(new_metric, vab, vcd, prior_inv)
+        if cur_s < s_best:
+          l_best = step_size
+          s_best = cur_s
+          M_best = new_metric
+      if self.verbose:
+        print('iter', it, 'cost', s_best, 'best step', l_best * grad_norm)
+      if M_best is None:
+        break
+      M = M_best
+    else:
+      if self.verbose:
+        print("Didn't converge after", it, "iterations. Final loss:", s_best)
+    self.n_iter_ = it
+
+    self.components_ = components_from_metric(M)
+    return self
+
+  def _comparison_loss(self, metric, vab, vcd):
+    dab = np.sum(vab.dot(metric) * vab, axis=1)
+    dcd = np.sum(vcd.dot(metric) * vcd, axis=1)
+    violations = dab > dcd
+    return self.w_[violations].dot((np.sqrt(dab[violations]) -
+                                    np.sqrt(dcd[violations]))**2)
+
+  def _total_loss(self, metric, vab, vcd, prior_inv):
+    # Regularization loss
+    sign, logdet = np.linalg.slogdet(metric)
+    reg_loss = np.sum(metric * prior_inv) - sign * logdet
+    return self._comparison_loss(metric, vab, vcd) + reg_loss
+
+  def _gradient(self, metric, vab, vcd, prior_inv):
+    dMetric = prior_inv - np.linalg.inv(metric)
+    dabs = np.sum(vab.dot(metric) * vab, axis=1)
+    dcds = np.sum(vcd.dot(metric) * vcd, axis=1)
+    violations = dabs > dcds
+    # TODO: vectorize
+    for vab, dab, vcd, dcd in zip(vab[violations], dabs[violations],
+                                  vcd[violations], dcds[violations]):
+      dMetric += ((1 - np.sqrt(dcd / dab)) * np.outer(vab, vab) +
+                  (1 - np.sqrt(dab / dcd)) * np.outer(vcd, vcd))
+    return dMetric
+
+
+
+[docs] +class LSML(_BaseLSML, _QuadrupletsClassifierMixin): + """Least Squared-residual Metric Learning (LSML) + + `LSML` proposes a simple, yet effective, algorithm that minimizes a convex + objective function corresponding to the sum of squared residuals of + constraints. This algorithm uses the constraints in the form of the + relative distance comparisons, such method is especially useful where + pairwise constraints are not natural to obtain, thus pairwise constraints + based algorithms become infeasible to be deployed. Furthermore, its sparsity + extension leads to more stable estimation when the dimension is high and + only a small amount of constraints is given. + + Read more in the :ref:`User Guide <lsml>`. + + Parameters + ---------- + prior : string or numpy array, optional (default='identity') + Prior to set for the metric. Possible options are + 'identity', 'covariance', 'random', and a numpy array of + shape (n_features, n_features). For LSML, the prior should be strictly + positive definite (PD). + + 'identity' + An identity matrix of shape (n_features, n_features). + + 'covariance' + The inverse covariance matrix. + + 'random' + The initial Mahalanobis matrix will be a random positive definite + (PD) matrix of shape `(n_features, n_features)`, generated using + `sklearn.datasets.make_spd_matrix`. + + numpy array + A positive definite (PD) matrix of shape + (n_features, n_features), that will be used as such to set the + prior. + + tol : float, optional (default=1e-3) + Convergence tolerance of the optimization procedure. + + max_iter : int, optional (default=1000) + Maximum number of iteration of the optimization procedure. + + verbose : bool, optional (default=False) + If True, prints information while learning + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be formed like this: X[indices]. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. If + ``init='random'``, ``random_state`` is used to set the random + prior. + + Attributes + ---------- + n_iter_ : `int` + The number of iterations the solver has run. + + components_ : `numpy.ndarray`, shape=(n_features, n_features) + The linear transformation ``L`` deduced from the learned Mahalanobis + metric (See function `components_from_metric`.) + + Examples + -------- + >>> from metric_learn import LSML + >>> quadruplets = [[[1.2, 7.5], [1.3, 1.5], [6.4, 2.6], [6.2, 9.7]], + >>> [[1.3, 4.5], [3.2, 4.6], [6.2, 5.5], [5.4, 5.4]], + >>> [[3.2, 7.5], [3.3, 1.5], [8.4, 2.6], [8.2, 9.7]], + >>> [[3.3, 4.5], [5.2, 4.6], [8.2, 5.5], [7.4, 5.4]]] + >>> # we want to make closer points where the first feature is close, and + >>> # further if the second feature is close + >>> lsml = LSML() + >>> lsml.fit(quadruplets) + + References + ---------- + .. [1] Liu et al. `Metric Learning from Relative Comparisons by Minimizing + Squared Residual + <http://www.cs.ucla.edu/~weiwang/paper/ICDM12.pdf>`_. ICDM 2012. + + .. [2] Code adapted from https://gist.github.com/kcarnold/5439917 + + See Also + -------- + metric_learn.LSML : The original weakly-supervised algorithm + + :ref:`supervised_version` : The section of the project documentation + that describes the supervised version of weakly supervised estimators. + """ + +
+[docs] + def fit(self, quadruplets, weights=None): + """Learn the LSML model. + + Parameters + ---------- + quadruplets : array-like, shape=(n_constraints, 4, n_features) or \ + (n_constraints, 4) + 3D array-like of quadruplets of points or 2D array of quadruplets of + indicators. In order to supervise the algorithm in the right way, we + should have the four samples ordered in a way such that: + d(pairs[i, 0],X[i, 1]) < d(X[i, 2], X[i, 3]) for all 0 <= i < + n_constraints. + + weights : (n_constraints,) array of floats, optional + scale factor for each constraint + + Returns + ------- + self : object + Returns the instance. + """ + return self._fit(quadruplets, weights=weights)
+
+ + + +
+[docs] +class LSML_Supervised(_BaseLSML, TransformerMixin): + """Supervised version of Least Squared-residual Metric Learning (LSML) + + `LSML_Supervised` creates quadruplets from labeled samples by taking two + samples from the same class, and two samples from different classes. + This way it builds quadruplets where the two first points must be more + similar than the two last points. + + Parameters + ---------- + tol : float, optional (default=1e-3) + Convergence tolerance of the optimization procedure. + + max_iter : int, optional (default=1000) + Number of maximum iterations of the optimization procedure. + + prior : string or numpy array, optional (default='identity') + Prior to set for the metric. Possible options are + 'identity', 'covariance', 'random', and a numpy array of + shape (n_features, n_features). For LSML, the prior should be strictly + positive definite (PD). + + 'identity' + An identity matrix of shape (n_features, n_features). + + 'covariance' + The inverse covariance matrix. + + 'random' + The initial Mahalanobis matrix will be a random positive definite + (PD) matrix of shape `(n_features, n_features)`, generated using + `sklearn.datasets.make_spd_matrix`. + + numpy array + A positive definite (PD) matrix of shape + (n_features, n_features), that will be used as such to set the + prior. + + n_constraints: int, optional (default=None) + Number of constraints to generate. If None, default to `20 * + num_classes**2`. + + weights : (n_constraints,) array of floats, optional (default=None) + Relative weight given to each constraint. If None, defaults to uniform + weights. + + verbose : bool, optional (default=False) + If True, prints information while learning + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be formed like this: X[indices]. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. If + ``init='random'``, ``random_state`` is used to set the random + prior. In any case, `random_state` is also used to randomly sample + constraints from labels. + + num_constraints : Renamed to n_constraints. Will be deprecated in 0.7.0 + + Examples + -------- + >>> from metric_learn import LSML_Supervised + >>> from sklearn.datasets import load_iris + >>> iris_data = load_iris() + >>> X = iris_data['data'] + >>> Y = iris_data['target'] + >>> lsml = LSML_Supervised(n_constraints=200) + >>> lsml.fit(X, Y) + + Attributes + ---------- + n_iter_ : `int` + The number of iterations the solver has run. + + components_ : `numpy.ndarray`, shape=(n_features, n_features) + The linear transformation ``L`` deduced from the learned Mahalanobis + metric (See function `components_from_metric`.) + """ + +
+[docs] + def __init__(self, tol=1e-3, max_iter=1000, prior='identity', + n_constraints=None, weights=None, + verbose=False, preprocessor=None, random_state=None, + num_constraints='deprecated'): + _BaseLSML.__init__(self, tol=tol, max_iter=max_iter, prior=prior, + verbose=verbose, preprocessor=preprocessor, + random_state=random_state) + if num_constraints != 'deprecated': + warnings.warn('"num_constraints" parameter has been renamed to' + ' "n_constraints". It has been deprecated in' + ' version 0.6.3 and will be removed in 0.7.0' + '', FutureWarning) + self.n_constraints = num_constraints + else: + self.n_constraints = n_constraints + # Avoid test get_params from failing (all params passed sholud be set) + self.num_constraints = 'deprecated' + self.weights = weights
+ + +
+[docs] + def fit(self, X, y): + """Create constraints from labels and learn the LSML model. + + Parameters + ---------- + X : (n x d) matrix + Input data, where each row corresponds to a single instance. + + y : (n) array-like + Data labels. + """ + X, y = self._prepare_inputs(X, y, ensure_min_samples=2) + n_constraints = self.n_constraints + if n_constraints is None: + num_classes = len(np.unique(y)) + n_constraints = 20 * num_classes**2 + + c = Constraints(y) + pos_neg = c.positive_negative_pairs(n_constraints, same_length=True, + random_state=self.random_state) + return _BaseLSML._fit(self, X[np.column_stack(pos_neg)], + weights=self.weights)
+
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/mlkr.html b/_modules/metric_learn/mlkr.html new file mode 100644 index 00000000..03894a22 --- /dev/null +++ b/_modules/metric_learn/mlkr.html @@ -0,0 +1,335 @@ + + + + + + metric_learn.mlkr — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.mlkr

+"""
+Metric Learning for Kernel Regression (MLKR)
+"""
+import time
+import sys
+import warnings
+import numpy as np
+from scipy.optimize import minimize
+from scipy.special import logsumexp
+from sklearn.base import TransformerMixin
+from sklearn.exceptions import ConvergenceWarning
+from sklearn.metrics import pairwise_distances
+
+from .base_metric import MahalanobisMixin
+from ._util import _initialize_components, _check_n_components
+
+EPS = np.finfo(float).eps
+
+
+
+[docs] +class MLKR(MahalanobisMixin, TransformerMixin): + """Metric Learning for Kernel Regression (MLKR) + + MLKR is an algorithm for supervised metric learning, which learns a + distance function by directly minimizing the leave-one-out regression error. + This algorithm can also be viewed as a supervised variation of PCA and can be + used for dimensionality reduction and high dimensional data visualization. + + Read more in the :ref:`User Guide <mlkr>`. + + Parameters + ---------- + n_components : int or None, optional (default=None) + Dimensionality of reduced space (if None, defaults to dimension of X). + + init : string or numpy array, optional (default='auto') + Initialization of the linear transformation. Possible options are + 'auto', 'pca', 'identity', 'random', and a numpy array of shape + (n_features_a, n_features_b). + + 'auto' + Depending on ``n_components``, the most reasonable initialization + will be chosen. If ``n_components < min(n_features, n_samples)``, + we use 'pca', as it projects data in meaningful directions (those + of higher variance). Otherwise, we just use 'identity'. + + 'pca' + ``n_components`` principal components of the inputs passed + to :meth:`fit` will be used to initialize the transformation. + (See `sklearn.decomposition.PCA`) + + 'identity' + If ``n_components`` is strictly smaller than the + dimensionality of the inputs passed to :meth:`fit`, the identity + matrix will be truncated to the first ``n_components`` rows. + + 'random' + The initial transformation will be a random array of shape + `(n_components, n_features)`. Each value is sampled from the + standard normal distribution. + + numpy array + n_features_b must match the dimensionality of the inputs passed to + :meth:`fit` and n_features_a must be less than or equal to that. + If ``n_components`` is not None, n_features_a must match it. + + tol : float, optional (default=None) + Convergence tolerance for the optimization. + + max_iter : int, optional (default=1000) + Cap on number of conjugate gradient iterations. + + verbose : bool, optional (default=False) + Whether to print progress messages or not. + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be formed like this: X[indices]. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. If + ``init='random'``, ``random_state`` is used to initialize the random + transformation. If ``init='pca'``, ``random_state`` is passed as an + argument to PCA when initializing the transformation. + + Attributes + ---------- + n_iter_ : `int` + The number of iterations the solver has run. + + components_ : `numpy.ndarray`, shape=(n_components, n_features) + The learned linear transformation ``L``. + + Examples + -------- + + >>> from metric_learn import MLKR + >>> from sklearn.datasets import load_iris + >>> iris_data = load_iris() + >>> X = iris_data['data'] + >>> Y = iris_data['target'] + >>> mlkr = MLKR() + >>> mlkr.fit(X, Y) + + References + ---------- + .. [1] K.Q. Weinberger and G. Tesauto. `Metric Learning for Kernel + Regression <http://proceedings.mlr.press/v2/weinberger07a\ + /weinberger07a.pdf>`_. AISTATS 2007. + """ + +
+[docs] + def __init__(self, n_components=None, init='auto', + tol=None, max_iter=1000, verbose=False, + preprocessor=None, random_state=None): + self.n_components = n_components + self.init = init + self.tol = tol + self.max_iter = max_iter + self.verbose = verbose + self.random_state = random_state + super(MLKR, self).__init__(preprocessor)
+ + +
+[docs] + def fit(self, X, y): + """ + Fit MLKR model + + Parameters + ---------- + X : (n x d) array of samples + y : (n) data labels + """ + X, y = self._prepare_inputs(X, y, y_numeric=True, + ensure_min_samples=2) + n, d = X.shape + if y.shape[0] != n: + raise ValueError('Data and label lengths mismatch: %d != %d' + % (n, y.shape[0])) + + m = _check_n_components(d, self.n_components) + m = self.n_components + if m is None: + m = d + # if the init is the default (None), we raise a warning + A = _initialize_components(m, X, y, init=self.init, + random_state=self.random_state, + # MLKR works on regression targets: + has_classes=False) + + # Measure the total training time + train_time = time.time() + + self.n_iter_ = 0 + res = minimize(self._loss, A.ravel(), (X, y), method='L-BFGS-B', + jac=True, tol=self.tol, + options=dict(maxiter=self.max_iter)) + self.components_ = res.x.reshape(A.shape) + + # Stop timer + train_time = time.time() - train_time + if self.verbose: + cls_name = self.__class__.__name__ + # Warn the user if the algorithm did not converge + if not res.success: + warnings.warn('[{}] MLKR did not converge: {}' + .format(cls_name, res.message), ConvergenceWarning) + print('[{}] Training took {:8.2f}s.'.format(cls_name, train_time)) + + return self
+ + + def _loss(self, flatA, X, y): + + if self.n_iter_ == 0 and self.verbose: + header_fields = ['Iteration', 'Objective Value', 'Time(s)'] + header_fmt = '{:>10} {:>20} {:>10}' + header = header_fmt.format(*header_fields) + cls_name = self.__class__.__name__ + print('[{cls}]'.format(cls=cls_name)) + print('[{cls}] {header}\n[{cls}] {sep}'.format(cls=cls_name, + header=header, + sep='-' * len(header))) + + start_time = time.time() + + A = flatA.reshape((-1, X.shape[1])) + X_embedded = np.dot(X, A.T) + dist = pairwise_distances(X_embedded, squared=True) + np.fill_diagonal(dist, np.inf) + softmax = np.exp(- dist - logsumexp(- dist, axis=1)[:, np.newaxis]) + yhat = softmax.dot(y) + ydiff = yhat - y + cost = (ydiff ** 2).sum() + + # also compute the gradient + W = softmax * ydiff[:, np.newaxis] * (y - yhat[:, np.newaxis]) + W_sym = W + W.T + np.fill_diagonal(W_sym, - W.sum(axis=0)) + grad = 4 * (X_embedded.T.dot(W_sym)).dot(X) + + if self.verbose: + start_time = time.time() - start_time + values_fmt = '[{cls}] {n_iter:>10} {loss:>20.6e} {start_time:>10.2f}' + print(values_fmt.format(cls=self.__class__.__name__, + n_iter=self.n_iter_, loss=cost, + start_time=start_time)) + sys.stdout.flush() + + self.n_iter_ += 1 + + return cost, grad.ravel()
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/mmc.html b/_modules/metric_learn/mmc.html new file mode 100644 index 00000000..10a11f61 --- /dev/null +++ b/_modules/metric_learn/mmc.html @@ -0,0 +1,734 @@ + + + + + + metric_learn.mmc — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.mmc

+"""Mahalanobis Metric for Clustering (MMC)"""
+import numpy as np
+from sklearn.base import TransformerMixin
+from sklearn.utils.validation import assert_all_finite
+
+from .base_metric import _PairsClassifierMixin, MahalanobisMixin
+from .constraints import Constraints, wrap_pairs
+from ._util import components_from_metric, _initialize_metric_mahalanobis
+import warnings
+
+
+class _BaseMMC(MahalanobisMixin):
+
+  _tuple_size = 2  # constraints are pairs
+
+  def __init__(self, max_iter=100, max_proj=10000, tol=1e-3,
+               init='identity', diagonal=False,
+               diagonal_c=1.0, verbose=False, preprocessor=None,
+               random_state=None,
+               convergence_threshold='deprecated'):
+    if convergence_threshold != 'deprecated':
+      warnings.warn('"convergence_threshold" parameter has been '
+                    ' renamed to "tol". It has been deprecated in'
+                    ' version 0.6.3 and will be removed in 0.7.0'
+                    '', FutureWarning)
+      tol = convergence_threshold
+    self.convergence_threshold = 'deprecated'  # Avoid errors
+    self.max_iter = max_iter
+    self.max_proj = max_proj
+    self.tol = tol
+    self.init = init
+    self.diagonal = diagonal
+    self.diagonal_c = diagonal_c
+    self.verbose = verbose
+    self.random_state = random_state
+    super(_BaseMMC, self).__init__(preprocessor)
+
+  def _fit(self, pairs, y):
+    pairs, y = self._prepare_inputs(pairs, y,
+                                    type_of_inputs='tuples')
+
+    self.A_ = _initialize_metric_mahalanobis(pairs, self.init,
+                                             random_state=self.random_state,
+                                             matrix_name='init')
+
+    if self.diagonal:
+      return self._fit_diag(pairs, y)
+    else:
+      return self._fit_full(pairs, y)
+
+  def _fit_full(self, pairs, y):
+    """Learn full metric using MMC.
+
+    Parameters
+    ----------
+    X : (n x d) data matrix
+      Each row corresponds to a single instance.
+    constraints : 4-tuple of arrays
+      (a,b,c,d) indices into X, with (a,b) specifying similar and (c,d)
+      dissimilar pairs.
+    """
+    num_dim = pairs.shape[2]
+
+    error2 = 1e10
+    eps = 0.01        # error-bound of iterative projection on C1 and C2
+    A = self.A_
+
+    pos_pairs, neg_pairs = pairs[y == 1], pairs[y == -1]
+
+    # Create weight vector from similar samples
+    pos_diff = pos_pairs[:, 0, :] - pos_pairs[:, 1, :]
+    w = np.einsum('ij,ik->jk', pos_diff, pos_diff).ravel()
+    # `w` is the sum of all outer products of the rows in `pos_diff`.
+    # The above `einsum` is equivalent to the much more inefficient:
+    # w = np.apply_along_axis(
+    #         lambda x: np.outer(x,x).ravel(),
+    #         1,
+    #         X[a] - X[b]
+    #     ).sum(axis = 0)
+    t = w.dot(A.ravel()) / 100.0
+
+    w_norm = np.linalg.norm(w)
+    w1 = w / w_norm  # make `w` a unit vector
+    t1 = t / w_norm  # distance from origin to `w^T*x=t` plane
+
+    cycle = 1
+    alpha = 0.1  # initial step size along gradient
+    grad1 = self._fS1(pos_pairs, A)            # gradient of similarity
+    # constraint function
+    grad2 = self._fD1(neg_pairs, A)            # gradient of dissimilarity
+    # constraint function
+    # gradient of fD1 orthogonal to fS1:
+    M = self._grad_projection(grad1, grad2)
+
+    A_old = A.copy()
+
+    for cycle in range(self.max_iter):
+
+      # projection of constraints C1 and C2
+      satisfy = False
+
+      for it in range(self.max_proj):
+
+        # First constraint:
+        # f(A) = \sum_{i,j \in S} d_ij' A d_ij <= t              (1)
+        # (1) can be rewritten as a linear constraint: w^T x = t,
+        # where x is the unrolled matrix of A,
+        # w is also an unrolled matrix of W where
+        # W_{kl}= \sum_{i,j \in S}d_ij^k * d_ij^l
+        x0 = A.ravel()
+        if w.dot(x0) <= t:
+          x = x0
+        else:
+          x = x0 + (t1 - w1.dot(x0)) * w1
+          A[:] = x.reshape(num_dim, num_dim)
+
+        # Second constraint:
+        # PSD constraint A >= 0
+        # project A onto domain A>0
+        l, V = np.linalg.eigh((A + A.T) / 2)
+        A[:] = np.dot(V * np.maximum(0, l[None, :]), V.T)
+
+        fDC2 = w.dot(A.ravel())
+        error2 = (fDC2 - t) / t
+        if error2 < eps:
+          satisfy = True
+          break
+
+      # third constraint: gradient ascent
+      # max: g(A) >= 1
+      # here we suppose g(A) = fD(A) = \sum_{I,J \in D} sqrt(d_ij' A d_ij)
+
+      obj_previous = self._fD(neg_pairs, A_old)  # g(A_old)
+      obj = self._fD(neg_pairs, A)               # g(A)
+
+      if satisfy and (obj > obj_previous or cycle == 0):
+
+        # If projection of 1 and 2 is successful, and such projection
+        # improves objective function, slightly increase learning rate
+        # and update from the current A.
+        alpha *= 1.05
+        A_old[:] = A
+        grad2 = self._fS1(pos_pairs, A)
+        grad1 = self._fD1(neg_pairs, A)
+        M = self._grad_projection(grad1, grad2)
+        A += alpha * M
+
+      else:
+
+        # If projection of 1 and 2 failed, or obj <= obj_previous due
+        # to projection of 1 and 2, shrink learning rate and re-update
+        # from the previous A.
+        alpha /= 2
+        A[:] = A_old + alpha * M
+
+      delta = np.linalg.norm(alpha * M) / np.linalg.norm(A_old)
+      if delta < self.tol:
+        break
+      if self.verbose:
+        print('mmc iter: %d, conv = %f, projections = %d' %
+              (cycle, delta, it + 1))
+
+    if delta > self.tol:
+      self.converged_ = False
+      if self.verbose:
+        print('mmc did not converge, conv = %f' % (delta,))
+    else:
+      self.converged_ = True
+      if self.verbose:
+        print('mmc converged at iter %d, conv = %f' % (cycle, delta))
+    self.A_[:] = A_old
+    self.n_iter_ = cycle
+
+    self.components_ = components_from_metric(self.A_)
+    return self
+
+  def _fit_diag(self, pairs, y):
+    """Learn diagonal metric using MMC.
+    Parameters
+    ----------
+    X : (n x d) data matrix
+      Each row corresponds to a single instance.
+    constraints : 4-tuple of arrays
+      (a,b,c,d) indices into X, with (a,b) specifying similar and (c,d)
+      dissimilar pairs.
+    """
+    num_dim = pairs.shape[2]
+    pos_pairs, neg_pairs = pairs[y == 1], pairs[y == -1]
+    s_sum = np.sum((pos_pairs[:, 0, :] - pos_pairs[:, 1, :]) ** 2, axis=0)
+
+    it = 0
+    error = 1.0
+    eps = 1e-6
+    reduction = 2.0
+    w = np.diag(self.A_).copy()
+
+    while error > self.tol and it < self.max_iter:
+
+      fD0, fD_1st_d, fD_2nd_d = self._D_constraint(neg_pairs, w)
+      obj_initial = np.dot(s_sum, w) + self.diagonal_c * fD0
+      fS_1st_d = s_sum  # first derivative of the similarity constraints
+
+      # gradient of the objective:
+      gradient = fS_1st_d - self.diagonal_c * fD_1st_d
+      # Hessian of the objective:
+      hessian = -self.diagonal_c * fD_2nd_d + eps * np.eye(num_dim)
+      step = np.dot(np.linalg.inv(hessian), gradient)
+
+      # Newton-Rapshon update
+      # search over optimal lambda
+      lambd = 1  # initial step-size
+      w_tmp = np.maximum(0, w - lambd * step)
+      obj = (np.dot(s_sum, w_tmp) + self.diagonal_c *
+             self._D_objective(neg_pairs, w_tmp))
+      assert_all_finite(obj)
+      obj_previous = np.inf  # just to get the while-loop started
+
+      inner_it = 0
+      while obj < obj_previous:
+        obj_previous = obj
+        w_previous = w_tmp.copy()
+        lambd /= reduction
+        w_tmp = np.maximum(0, w - lambd * step)
+        obj = (np.dot(s_sum, w_tmp) + self.diagonal_c *
+               self._D_objective(neg_pairs, w_tmp))
+        inner_it += 1
+        assert_all_finite(obj)
+
+      w[:] = w_previous
+      error = np.abs((obj_previous - obj_initial) / obj_previous)
+      if self.verbose:
+        print('mmc iter: %d, conv = %f' % (it, error))
+      it += 1
+
+    self.A_ = np.diag(w)
+
+    self.components_ = components_from_metric(self.A_)
+    return self
+
+  def _fD(self, neg_pairs, A):
+    r"""The value of the dissimilarity constraint function.
+
+    f = f(\sum_{ij \in D} distance(x_i, x_j))
+    i.e. distance can be L1:  \sqrt{(x_i-x_j)A(x_i-x_j)'}
+    """
+    diff = neg_pairs[:, 0, :] - neg_pairs[:, 1, :]
+    return np.log(np.sum(np.sqrt(np.sum(np.dot(diff, A) * diff, axis=1))) +
+                  1e-6)
+
+  def _fD1(self, neg_pairs, A):
+    r"""The gradient of the dissimilarity constraint function w.r.t. A.
+
+    For example, let distance by L1 norm:
+    f = f(\sum_{ij \in D} \sqrt{(x_i-x_j)A(x_i-x_j)'})
+    df/dA_{kl} = f'* d(\sum_{ij \in D} \sqrt{(x_i-x_j)^k*(x_i-x_j)^l})/dA_{kl}
+
+    Note that d_ij*A*d_ij' = tr(d_ij*A*d_ij') = tr(d_ij'*d_ij*A)
+    so, d(d_ij*A*d_ij')/dA = d_ij'*d_ij
+        df/dA = f'(\sum_{ij \in D} \sqrt{tr(d_ij'*d_ij*A)})
+                * 0.5*(\sum_{ij \in D} (1/sqrt{tr(d_ij'*d_ij*A)})*(d_ij'*d_ij))
+    """
+    diff = neg_pairs[:, 0, :] - neg_pairs[:, 1, :]
+    # outer products of all rows in `diff`
+    M = np.einsum('ij,ik->ijk', diff, diff)
+    # faster version of: dist = np.sqrt(np.sum(M * A[None,:,:], axis=(1,2)))
+    dist = np.sqrt(np.einsum('ijk,jk', M, A))
+    # faster version of: sum_deri = np.sum(M /
+    # (2 * (dist[:,None,None] + 1e-6)), axis=0)
+    sum_deri = np.einsum('ijk,i->jk', M, 0.5 / (dist + 1e-6))
+    sum_dist = dist.sum()
+    return sum_deri / (sum_dist + 1e-6)
+
+  def _fS1(self, pos_pairs, A):
+    r"""The gradient of the similarity constraint function w.r.t. A.
+
+    f = \sum_{ij}(x_i-x_j)A(x_i-x_j)' = \sum_{ij}d_ij*A*d_ij'
+    df/dA = d(d_ij*A*d_ij')/dA
+
+    Note that d_ij*A*d_ij' = tr(d_ij*A*d_ij') = tr(d_ij'*d_ij*A)
+    so, d(d_ij*A*d_ij')/dA = d_ij'*d_ij
+    """
+    diff = pos_pairs[:, 0, :] - pos_pairs[:, 1, :]
+    # sum of outer products of all rows in `diff`:
+    return np.einsum('ij,ik->jk', diff, diff)
+
+  def _grad_projection(self, grad1, grad2):
+    grad2 = grad2 / np.linalg.norm(grad2)
+    gtemp = grad1 - np.sum(grad1 * grad2) * grad2
+    gtemp /= np.linalg.norm(gtemp)
+    return gtemp
+
+  def _D_objective(self, neg_pairs, w):
+    return np.log(np.sum(np.sqrt(np.sum(((neg_pairs[:, 0, :] -
+                                          neg_pairs[:, 1, :]) ** 2) *
+                                        w[None, :], axis=1) + 1e-6)))
+
+  def _D_constraint(self, neg_pairs, w):
+    """Compute the value, 1st derivative, second derivative (Hessian) of
+    a dissimilarity constraint function gF(sum_ij distance(d_ij A d_ij))
+    where A is a diagonal matrix (in the form of a column vector 'w').
+    """
+    diff = neg_pairs[:, 0, :] - neg_pairs[:, 1, :]
+    diff_sq = diff * diff
+    dist = np.sqrt(diff_sq.dot(w))
+    sum_deri1 = np.einsum('ij,i', diff_sq, 0.5 / np.maximum(dist, 1e-6))
+    sum_deri2 = np.einsum(
+        'ij,ik->jk',
+        diff_sq,
+        diff_sq / (-4 * np.maximum(1e-6, dist**3))[:, None]
+    )
+    sum_dist = dist.sum()
+    return (
+        np.log(sum_dist),
+        sum_deri1 / sum_dist,
+        sum_deri2 / sum_dist -
+        np.outer(sum_deri1, sum_deri1) / (sum_dist * sum_dist)
+    )
+
+
+
+[docs] +class MMC(_BaseMMC, _PairsClassifierMixin): + """Mahalanobis Metric for Clustering (MMC) + + MMC minimizes the sum of squared distances between similar points, while + enforcing the sum of distances between dissimilar ones to be greater than + one. This leads to a convex and, thus, local-minima-free optimization + problem that can be solved efficiently. + However, the algorithm involves the computation of eigenvalues, which is the + main speed-bottleneck. Since it has initially been designed for clustering + applications, one of the implicit assumptions of MMC is that all classes form + a compact set, i.e., follow a unimodal distribution, which restricts the + possible use-cases of this method. However, it is one of the earliest and a + still often cited technique. + + Read more in the :ref:`User Guide <mmc>`. + + Parameters + ---------- + max_iter : int, optional (default=100) + Maximum number of iterations of the optimization procedure. + + max_proj : int, optional (default=10000) + Maximum number of projection steps. + + tol : float, optional (default=1e-3) + Convergence threshold for the optimization procedure. + + init : string or numpy array, optional (default='identity') + Initialization of the Mahalanobis matrix. Possible options are + 'identity', 'covariance', 'random', and a numpy array of + shape (n_features, n_features). + + 'identity' + An identity matrix of shape (n_features, n_features). + + 'covariance' + The (pseudo-)inverse of the covariance matrix. + + 'random' + The initial Mahalanobis matrix will be a random SPD matrix of + shape + `(n_features, n_features)`, generated using + `sklearn.datasets.make_spd_matrix`. + + numpy array + An SPD matrix of shape (n_features, n_features), that will + be used as such to initialize the metric. + + diagonal : bool, optional (default=False) + If True, a diagonal metric will be learned, + i.e., a simple scaling of dimensions. The initialization will then + be the diagonal coefficients of the matrix given as 'init'. + + diagonal_c : float, optional (default=1.0) + Weight of the dissimilarity constraint for diagonal + metric learning. Ignored if ``diagonal=False``. + + verbose : bool, optional (default=False) + If True, prints information while learning + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be gotten like this: X[indices]. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. If + ``init='random'``, ``random_state`` is used to initialize the random + transformation. + + convergence_threshold : Renamed to tol. Will be deprecated in 0.7.0 + + Attributes + ---------- + n_iter_ : `int` + The number of iterations the solver has run. + + components_ : `numpy.ndarray`, shape=(n_features, n_features) + The linear transformation ``L`` deduced from the learned Mahalanobis + metric (See function `components_from_metric`.) + + threshold_ : `float` + If the distance metric between two points is lower than this threshold, + points will be classified as similar, otherwise they will be + classified as dissimilar. + + Examples + -------- + >>> from metric_learn import MMC + >>> pairs = [[[1.2, 7.5], [1.3, 1.5]], + >>> [[6.4, 2.6], [6.2, 9.7]], + >>> [[1.3, 4.5], [3.2, 4.6]], + >>> [[6.2, 5.5], [5.4, 5.4]]] + >>> y = [1, 1, -1, -1] + >>> # in this task we want points where the first feature is close to be + >>> # closer to each other, no matter how close the second feature is + >>> mmc = MMC() + >>> mmc.fit(pairs, y) + + References + ---------- + .. [1] Xing, Jordan, Russell, Ng. `Distance metric learning with application + to clustering with side-information + <http://papers.nips.cc/paper/2164-distance-metric-\ + learning-with-application-to-clustering-with-side-information.pdf>`_. + NIPS 2002. + + See Also + -------- + metric_learn.MMC : The original weakly-supervised algorithm + :ref:`supervised_version` : The section of the project documentation + that describes the supervised version of weakly supervised estimators. + """ + +
+[docs] + def fit(self, pairs, y, calibration_params=None): + """Learn the MMC model. + + The threshold will be calibrated on the trainset using the parameters + `calibration_params`. + + Parameters + ---------- + pairs : array-like, shape=(n_constraints, 2, n_features) or \ + (n_constraints, 2) + 3D Array of pairs with each row corresponding to two points, + or 2D array of indices of pairs if the metric learner uses a + preprocessor. + + y : array-like, of shape (n_constraints,) + Labels of constraints. Should be -1 for dissimilar pair, 1 for similar. + + calibration_params : `dict` or `None` + Dictionary of parameters to give to `calibrate_threshold` for the + threshold calibration step done at the end of `fit`. If `None` is + given, `calibrate_threshold` will use the default parameters. + + Returns + ------- + self : object + Returns the instance. + """ + calibration_params = (calibration_params if calibration_params is not + None else dict()) + self._validate_calibration_params(**calibration_params) + self._fit(pairs, y) + self.calibrate_threshold(pairs, y, **calibration_params) + return self
+
+ + + +
+[docs] +class MMC_Supervised(_BaseMMC, TransformerMixin): + """Supervised version of Mahalanobis Metric for Clustering (MMC) + + `MMC_Supervised` creates pairs of similar sample by taking same class + samples, and pairs of dissimilar samples by taking different class + samples. It then passes these pairs to `MMC` for training. + + Parameters + ---------- + max_iter : int, optional (default=100) + Maximum number of iterations of the optimization procedure. + + max_proj : int, optional (default=10000) + Maximum number of projection steps. + + tol : float, optional (default=1e-3) + Convergence threshold for the optimization procedure. + + n_constraints: int, optional (default=None) + Number of constraints to generate. If None, default to `20 * + num_classes**2`. + + init : string or numpy array, optional (default='identity') + Initialization of the Mahalanobis matrix. Possible options are + 'identity', 'covariance', 'random', and a numpy array of + shape (n_features, n_features). + + 'identity' + An identity matrix of shape (n_features, n_features). + + 'covariance' + The (pseudo-)inverse of the covariance matrix. + + 'random' + The initial Mahalanobis matrix will be a random SPD matrix of + shape `(n_features, n_features)`, generated using + `sklearn.datasets.make_spd_matrix`. + + numpy array + A numpy array of shape (n_features, n_features), that will + be used as such to initialize the metric. + + diagonal : bool, optional (default=False) + If True, a diagonal metric will be learned, + i.e., a simple scaling of dimensions. The initialization will then + be the diagonal coefficients of the matrix given as 'init'. + + diagonal_c : float, optional (default=1.0) + Weight of the dissimilarity constraint for diagonal + metric learning. Ignored if ``diagonal=False``. + + verbose : bool, optional (default=False) + If True, prints information while learning + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be formed like this: X[indices]. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. If + ``init='random'``, ``random_state`` is used to initialize the random + Mahalanobis matrix. In any case, `random_state` is also used to + randomly sample constraints from labels. + + num_constraints : Renamed to n_constraints. Will be deprecated in 0.7.0 + + convergence_threshold : Renamed to tol. Will be deprecated in 0.7.0 + + Examples + -------- + >>> from metric_learn import MMC_Supervised + >>> from sklearn.datasets import load_iris + >>> iris_data = load_iris() + >>> X = iris_data['data'] + >>> Y = iris_data['target'] + >>> mmc = MMC_Supervised(n_constraints=200) + >>> mmc.fit(X, Y) + + Attributes + ---------- + n_iter_ : `int` + The number of iterations the solver has run. + + components_ : `numpy.ndarray`, shape=(n_features, n_features) + The linear transformation ``L`` deduced from the learned Mahalanobis + metric (See function `components_from_metric`.) + """ + +
+[docs] + def __init__(self, max_iter=100, max_proj=10000, tol=1e-6, + n_constraints=None, init='identity', + diagonal=False, diagonal_c=1.0, verbose=False, + preprocessor=None, random_state=None, + num_constraints='deprecated', + convergence_threshold='deprecated'): + _BaseMMC.__init__(self, max_iter=max_iter, max_proj=max_proj, + tol=tol, + init=init, diagonal=diagonal, + diagonal_c=diagonal_c, verbose=verbose, + preprocessor=preprocessor, + random_state=random_state, + convergence_threshold=convergence_threshold) + if num_constraints != 'deprecated': + warnings.warn('"num_constraints" parameter has been renamed to' + ' "n_constraints". It has been deprecated in' + ' version 0.6.3 and will be removed in 0.7.0' + '', FutureWarning) + self.n_constraints = num_constraints + else: + self.n_constraints = n_constraints + # Avoid test get_params from failing (all params passed sholud be set) + self.num_constraints = 'deprecated'
+ + +
+[docs] + def fit(self, X, y): + """Create constraints from labels and learn the MMC model. + + Parameters + ---------- + X : (n x d) matrix + Input data, where each row corresponds to a single instance. + + y : (n) array-like + Data labels. + """ + X, y = self._prepare_inputs(X, y, ensure_min_samples=2) + n_constraints = self.n_constraints + if n_constraints is None: + num_classes = len(np.unique(y)) + n_constraints = 20 * num_classes**2 + + c = Constraints(y) + pos_neg = c.positive_negative_pairs(n_constraints, + random_state=self.random_state) + pairs, y = wrap_pairs(X, pos_neg) + return _BaseMMC._fit(self, pairs, y)
+
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/nca.html b/_modules/metric_learn/nca.html new file mode 100644 index 00000000..0360824b --- /dev/null +++ b/_modules/metric_learn/nca.html @@ -0,0 +1,352 @@ + + + + + + metric_learn.nca — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.nca

+"""
+Neighborhood Components Analysis (NCA)
+"""
+
+import warnings
+import time
+import sys
+import numpy as np
+from scipy.optimize import minimize
+from scipy.special import logsumexp
+from sklearn.base import TransformerMixin
+from sklearn.exceptions import ConvergenceWarning
+from sklearn.metrics import pairwise_distances
+
+from ._util import _initialize_components, _check_n_components
+from .base_metric import MahalanobisMixin
+
+EPS = np.finfo(float).eps
+
+
+
+[docs] +class NCA(MahalanobisMixin, TransformerMixin): + """Neighborhood Components Analysis (NCA) + + NCA is a distance metric learning algorithm which aims to improve the + accuracy of nearest neighbors classification compared to the standard + Euclidean distance. The algorithm directly maximizes a stochastic variant + of the leave-one-out k-nearest neighbors(KNN) score on the training set. + It can also learn a low-dimensional linear transformation of data that can + be used for data visualization and fast classification. + + Read more in the :ref:`User Guide <nca>`. + + Parameters + ---------- + init : string or numpy array, optional (default='auto') + Initialization of the linear transformation. Possible options are + 'auto', 'pca', 'identity', 'random', and a numpy array of shape + (n_features_a, n_features_b). + + 'auto' + Depending on ``n_components``, the most reasonable initialization + will be chosen. If ``n_components <= n_classes`` we use 'lda', as + it uses labels information. If not, but + ``n_components < min(n_features, n_samples)``, we use 'pca', as + it projects data in meaningful directions (those of higher + variance). Otherwise, we just use 'identity'. + + 'pca' + ``n_components`` principal components of the inputs passed + to :meth:`fit` will be used to initialize the transformation. + (See `sklearn.decomposition.PCA`) + + 'lda' + ``min(n_components, n_classes)`` most discriminative + components of the inputs passed to :meth:`fit` will be used to + initialize the transformation. (If ``n_components > n_classes``, + the rest of the components will be zero.) (See + `sklearn.discriminant_analysis.LinearDiscriminantAnalysis`) + + 'identity' + If ``n_components`` is strictly smaller than the + dimensionality of the inputs passed to :meth:`fit`, the identity + matrix will be truncated to the first ``n_components`` rows. + + 'random' + The initial transformation will be a random array of shape + `(n_components, n_features)`. Each value is sampled from the + standard normal distribution. + + numpy array + n_features_b must match the dimensionality of the inputs passed to + :meth:`fit` and n_features_a must be less than or equal to that. + If ``n_components`` is not None, n_features_a must match it. + + n_components : int or None, optional (default=None) + Dimensionality of reduced space (if None, defaults to dimension of X). + + max_iter : int, optional (default=100) + Maximum number of iterations done by the optimization algorithm. + + tol : float, optional (default=None) + Convergence tolerance for the optimization. + + verbose : bool, optional (default=False) + Whether to print progress messages or not. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. If + ``init='random'``, ``random_state`` is used to initialize the random + transformation. If ``init='pca'``, ``random_state`` is passed as an + argument to PCA when initializing the transformation. + + Examples + -------- + + >>> import numpy as np + >>> from metric_learn import NCA + >>> from sklearn.datasets import load_iris + >>> iris_data = load_iris() + >>> X = iris_data['data'] + >>> Y = iris_data['target'] + >>> nca = NCA(max_iter=1000) + >>> nca.fit(X, Y) + + Attributes + ---------- + n_iter_ : `int` + The number of iterations the solver has run. + + components_ : `numpy.ndarray`, shape=(n_components, n_features) + The learned linear transformation ``L``. + + References + ---------- + .. [1] J. Goldberger, G. Hinton, S. Roweis, R. Salakhutdinov. `Neighbourhood + Components Analysis + <http://www.cs.nyu.edu/~roweis/papers/ncanips.pdf>`_. + NIPS 2005. + + .. [2] Wikipedia entry on `Neighborhood Components Analysis + <https://en.wikipedia.org/wiki/Neighbourhood_components_analysis>`_ + """ + +
+[docs] + def __init__(self, init='auto', n_components=None, + max_iter=100, tol=None, verbose=False, preprocessor=None, + random_state=None): + self.n_components = n_components + self.init = init + self.max_iter = max_iter + self.tol = tol + self.verbose = verbose + self.random_state = random_state + super(NCA, self).__init__(preprocessor)
+ + +
+[docs] + def fit(self, X, y): + """ + X: data matrix, (n x d) + y: scalar labels, (n) + """ + X, labels = self._prepare_inputs(X, y, ensure_min_samples=2) + n, d = X.shape + n_components = _check_n_components(d, self.n_components) + + # Measure the total training time + train_time = time.time() + + # Initialize A + A = _initialize_components(n_components, X, labels, self.init, + self.verbose, self.random_state) + + # Run NCA + mask = labels[:, np.newaxis] == labels[np.newaxis, :] + optimizer_params = {'method': 'L-BFGS-B', + 'fun': self._loss_grad_lbfgs, + 'args': (X, mask, -1.0), + 'jac': True, + 'x0': A.ravel(), + 'options': dict(maxiter=self.max_iter), + 'tol': self.tol + } + + # Call the optimizer + self.n_iter_ = 0 + opt_result = minimize(**optimizer_params) + + self.components_ = opt_result.x.reshape(-1, X.shape[1]) + self.n_iter_ = opt_result.nit + + # Stop timer + train_time = time.time() - train_time + if self.verbose: + cls_name = self.__class__.__name__ + + # Warn the user if the algorithm did not converge + if not opt_result.success: + warnings.warn('[{}] NCA did not converge: {}'.format( + cls_name, opt_result.message), ConvergenceWarning) + + print('[{}] Training took {:8.2f}s.'.format(cls_name, train_time)) + + return self
+ + + def _loss_grad_lbfgs(self, A, X, mask, sign=1.0): + + if self.n_iter_ == 0 and self.verbose: + header_fields = ['Iteration', 'Objective Value', 'Time(s)'] + header_fmt = '{:>10} {:>20} {:>10}' + header = header_fmt.format(*header_fields) + cls_name = self.__class__.__name__ + print('[{cls}]'.format(cls=cls_name)) + print('[{cls}] {header}\n[{cls}] {sep}'.format(cls=cls_name, + header=header, + sep='-' * len(header))) + + start_time = time.time() + + A = A.reshape(-1, X.shape[1]) + X_embedded = np.dot(X, A.T) # (n_samples, n_components) + # Compute softmax distances + p_ij = pairwise_distances(X_embedded, squared=True) + np.fill_diagonal(p_ij, np.inf) + p_ij = np.exp(-p_ij - logsumexp(-p_ij, axis=1)[:, np.newaxis]) + # (n_samples, n_samples) + + # Compute loss + masked_p_ij = p_ij * mask + p = masked_p_ij.sum(axis=1, keepdims=True) # (n_samples, 1) + loss = p.sum() + + # Compute gradient of loss w.r.t. `transform` + weighted_p_ij = masked_p_ij - p_ij * p + weighted_p_ij_sym = weighted_p_ij + weighted_p_ij.T + np.fill_diagonal(weighted_p_ij_sym, - weighted_p_ij.sum(axis=0)) + gradient = 2 * (X_embedded.T.dot(weighted_p_ij_sym)).dot(X) + + if self.verbose: + start_time = time.time() - start_time + values_fmt = '[{cls}] {n_iter:>10} {loss:>20.6e} {start_time:>10.2f}' + print(values_fmt.format(cls=self.__class__.__name__, + n_iter=self.n_iter_, loss=loss, + start_time=start_time)) + sys.stdout.flush() + + self.n_iter_ += 1 + return sign * loss, sign * gradient.ravel()
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/rca.html b/_modules/metric_learn/rca.html new file mode 100644 index 00000000..db06e668 --- /dev/null +++ b/_modules/metric_learn/rca.html @@ -0,0 +1,353 @@ + + + + + + metric_learn.rca — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.rca

+"""
+Relative Components Analysis (RCA)
+"""
+
+import numpy as np
+import warnings
+from sklearn.base import TransformerMixin
+
+from ._util import _check_n_components
+from .base_metric import MahalanobisMixin
+from .constraints import Constraints
+
+
+# mean center each chunklet separately
+def _chunk_mean_centering(data, chunks):
+  n_chunks = chunks.max() + 1
+  chunk_mask = chunks != -1
+  # We need to ensure the data is float so that we can substract the
+  # mean on it
+  chunk_data = data[chunk_mask].astype(float, copy=False)
+  chunk_labels = chunks[chunk_mask]
+  for c in range(n_chunks):
+    mask = chunk_labels == c
+    chunk_data[mask] -= chunk_data[mask].mean(axis=0)
+
+  return chunk_mask, chunk_data
+
+
+
+[docs] +class RCA(MahalanobisMixin, TransformerMixin): + """Relevant Components Analysis (RCA) + + RCA learns a full rank Mahalanobis distance metric based on a weighted sum of + in-chunklets covariance matrices. It applies a global linear transformation + to assign large weights to relevant dimensions and low weights to irrelevant + dimensions. Those relevant dimensions are estimated using "chunklets", + subsets of points that are known to belong to the same class. + + Read more in the :ref:`User Guide <rca>`. + + Parameters + ---------- + n_components : int or None, optional (default=None) + Dimensionality of reduced space (if None, defaults to dimension of X). + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be formed like this: X[indices]. + + Examples + -------- + >>> from metric_learn import RCA + >>> X = [[-0.05, 3.0],[0.05, -3.0], + >>> [0.1, -3.55],[-0.1, 3.55], + >>> [-0.95, -0.05],[0.95, 0.05], + >>> [0.4, 0.05],[-0.4, -0.05]] + >>> chunks = [0, 0, 1, 1, 2, 2, 3, 3] + >>> rca = RCA() + >>> rca.fit(X, chunks) + + References + ---------- + .. [1] Noam Shental, et al. `Adjustment learning and relevant component + analysis <http://citeseerx.ist.\ + psu.edu/viewdoc/download?doi=10.1.1.19.2871&rep=rep1&type=pdf>`_ . + ECCV 2002. + + + Attributes + ---------- + components_ : `numpy.ndarray`, shape=(n_components, n_features) + The learned linear transformation ``L``. + """ + +
+[docs] + def __init__(self, n_components=None, preprocessor=None): + self.n_components = n_components + super(RCA, self).__init__(preprocessor)
+ + + def _check_dimension(self, rank, X): + d = X.shape[1] + + if rank < d: + warnings.warn('The inner covariance matrix is not invertible, ' + 'so the transformation matrix may contain Nan values. ' + 'You should remove any linearly dependent features and/or ' + 'reduce the dimensionality of your input, ' + 'for instance using `sklearn.decomposition.PCA` as a ' + 'preprocessing step.') + + dim = _check_n_components(d, self.n_components) + return dim + +
+[docs] + def fit(self, X, chunks): + """Learn the RCA model. + + Parameters + ---------- + data : (n x d) data matrix + Each row corresponds to a single instance + + chunks : (n,) array of ints + When ``chunks[i] == -1``, point i doesn't belong to any chunklet. + When ``chunks[i] == j``, point i belongs to chunklet j. + """ + X, chunks = self._prepare_inputs(X, chunks, ensure_min_samples=2) + + chunks = np.asanyarray(chunks, dtype=int) + chunk_mask, chunked_data = _chunk_mean_centering(X, chunks) + + inner_cov = np.atleast_2d(np.cov(chunked_data, rowvar=0, bias=1)) + dim = self._check_dimension(np.linalg.matrix_rank(inner_cov), X) + + # Fisher Linear Discriminant projection + if dim < X.shape[1]: + total_cov = np.cov(X[chunk_mask], rowvar=0) + tmp = np.linalg.lstsq(total_cov, inner_cov, rcond=None)[0] + vals, vecs = np.linalg.eig(tmp) + inds = np.argsort(vals)[:dim] + A = vecs[:, inds] + inner_cov = np.atleast_2d(A.T.dot(inner_cov).dot(A)) + self.components_ = _inv_sqrtm(inner_cov).dot(A.T) + else: + self.components_ = _inv_sqrtm(inner_cov).T + + return self
+
+ + + +def _inv_sqrtm(x): + '''Computes x^(-1/2)''' + vals, vecs = np.linalg.eigh(x) + return (vecs / np.sqrt(vals)).dot(vecs.T) + + +
+[docs] +class RCA_Supervised(RCA): + """Supervised version of Relevant Components Analysis (RCA) + + `RCA_Supervised` creates chunks of similar points by first sampling a + class, taking `chunk_size` elements in it, and repeating the process + `n_chunks` times. + + Parameters + ---------- + n_components : int or None, optional (default=None) + Dimensionality of reduced space (if None, defaults to dimension of X). + + n_chunks: int, optional (default=100) + Number of chunks to generate. + + chunk_size: int, optional (default=2) + Number of points per chunk. + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be formed like this: X[indices]. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. + It is used to randomly sample constraints from labels. + + num_chunks : Renamed to n_chunks. Will be deprecated in 0.7.0 + + Examples + -------- + >>> from metric_learn import RCA_Supervised + >>> from sklearn.datasets import load_iris + >>> iris_data = load_iris() + >>> X = iris_data['data'] + >>> Y = iris_data['target'] + >>> rca = RCA_Supervised(n_chunks=30, chunk_size=2) + >>> rca.fit(X, Y) + + Attributes + ---------- + components_ : `numpy.ndarray`, shape=(n_components, n_features) + The learned linear transformation ``L``. + """ + +
+[docs] + def __init__(self, n_components=None, n_chunks=100, chunk_size=2, + preprocessor=None, random_state=None, + num_chunks='deprecated'): + """Initialize the supervised version of `RCA`.""" + RCA.__init__(self, n_components=n_components, preprocessor=preprocessor) + if num_chunks != 'deprecated': + warnings.warn('"num_chunks" parameter has been renamed to' + ' "n_chunks". It has been deprecated in' + ' version 0.6.3 and will be removed in 0.7.0' + '', FutureWarning) + n_chunks = num_chunks + self.num_chunks = 'deprecated' # To avoid no_attribute error + self.n_chunks = n_chunks + self.chunk_size = chunk_size + self.random_state = random_state
+ + +
+[docs] + def fit(self, X, y): + """Create constraints from labels and learn the RCA model. + Needs n_constraints specified in constructor. (Not true?) + + Parameters + ---------- + X : (n x d) data matrix + each row corresponds to a single instance + + y : (n) data labels + """ + X, y = self._prepare_inputs(X, y, ensure_min_samples=2) + chunks = Constraints(y).chunks(n_chunks=self.n_chunks, + chunk_size=self.chunk_size, + random_state=self.random_state) + + if self.n_chunks * (self.chunk_size - 1) < X.shape[1]: + warnings.warn('Due to the parameters of RCA_Supervised, ' + 'the inner covariance matrix is not invertible, ' + 'so the transformation matrix will contain Nan values. ' + 'Increase the number or size of the chunks to correct ' + 'this problem.' + ) + + return RCA.fit(self, X, chunks)
+
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/scml.html b/_modules/metric_learn/scml.html new file mode 100644 index 00000000..039d831b --- /dev/null +++ b/_modules/metric_learn/scml.html @@ -0,0 +1,796 @@ + + + + + + metric_learn.scml — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.scml

+"""
+Sparse Compositional Metric Learning (SCML)
+"""
+
+from __future__ import print_function, absolute_import, division
+import numpy as np
+from .base_metric import _TripletsClassifierMixin, MahalanobisMixin
+from ._util import components_from_metric
+from sklearn.base import TransformerMixin
+from .constraints import Constraints
+from sklearn.preprocessing import normalize
+from sklearn.neighbors import NearestNeighbors
+from sklearn.cluster import KMeans
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
+from sklearn.utils import check_array, check_random_state
+import warnings
+
+
+class _BaseSCML(MahalanobisMixin):
+
+  _tuple_size = 3   # constraints are triplets
+  _authorized_basis = ['triplet_diffs']
+
+  def __init__(self, beta=1e-5, basis='triplet_diffs', n_basis=None,
+               gamma=5e-3, max_iter=10000, output_iter=500, batch_size=10,
+               verbose=False, preprocessor=None, random_state=None):
+    self.beta = beta
+    self.basis = basis
+    self.n_basis = n_basis
+    self.gamma = gamma
+    self.max_iter = max_iter
+    self.output_iter = output_iter
+    self.batch_size = batch_size
+    self.verbose = verbose
+    self.preprocessor = preprocessor
+    self.random_state = random_state
+    super(_BaseSCML, self).__init__(preprocessor)
+
+  def _fit(self, triplets, basis=None, n_basis=None):
+    """
+    Optimization procedure to find a sparse vector of weights to
+    construct the metric from the basis set. This is based on the
+    dual averaging method.
+    """
+
+    if not isinstance(self.max_iter, int):
+      raise ValueError("max_iter should be an integer, instead it is of type"
+                       " %s" % type(self.max_iter))
+    if not isinstance(self.output_iter, int):
+      raise ValueError("output_iter should be an integer, instead it is of "
+                       "type %s" % type(self.output_iter))
+    if not isinstance(self.batch_size, int):
+      raise ValueError("batch_size should be an integer, instead it is of type"
+                       " %s" % type(self.batch_size))
+
+    if self.output_iter > self.max_iter:
+      raise ValueError("The value of output_iter must be equal or smaller than"
+                       " max_iter.")
+
+    # Currently prepare_inputs makes triplets contain points and not indices
+    triplets = self._prepare_inputs(triplets, type_of_inputs='tuples')
+
+    # TODO:
+    # This algorithm is built to work with indices, but in order to be
+    # compliant with the current handling of inputs it is converted
+    # back to indices by the following function. This should be improved
+    # in the future.
+    triplets, X = self._to_index_points(triplets)
+
+    if basis is None:
+      basis, n_basis = self._initialize_basis(triplets, X)
+
+    dist_diff = self._compute_dist_diff(triplets, X, basis)
+
+    n_triplets = triplets.shape[0]
+
+    # weight vector
+    w = np.zeros((1, n_basis))
+    # avarage obj gradient wrt weights
+    avg_grad_w = np.zeros((1, n_basis))
+
+    # l2 norm in time of all obj gradients wrt weights
+    ada_grad_w = np.zeros((1, n_basis))
+    # slack for not dividing by zero
+    delta = 0.001
+
+    best_obj = np.inf
+
+    rng = check_random_state(self.random_state)
+    rand_int = rng.randint(low=0, high=n_triplets,
+                           size=(self.max_iter, self.batch_size))
+    for iter in range(self.max_iter):
+
+      idx = rand_int[iter]
+
+      slack_val = 1 + np.matmul(dist_diff[idx, :], w.T)
+      slack_mask = np.squeeze(slack_val > 0, axis=1)
+
+      grad_w = np.sum(dist_diff[idx[slack_mask], :],
+                      axis=0, keepdims=True)/self.batch_size
+      avg_grad_w = (iter * avg_grad_w + grad_w) / (iter+1)
+
+      ada_grad_w = np.sqrt(np.square(ada_grad_w) + np.square(grad_w))
+
+      scale_f = -(iter+1) / (self.gamma * (delta + ada_grad_w))
+
+      # proximal operator with negative trimming equivalent
+      w = scale_f * np.minimum(avg_grad_w + self.beta, 0)
+
+      if (iter + 1) % self.output_iter == 0:
+        # regularization part of obj function
+        obj1 = np.sum(w)*self.beta
+
+        # Every triplet distance difference in the space given by L
+        # plus a slack of one
+        slack_val = 1 + np.matmul(dist_diff, w.T)
+        # Mask of places with positive slack
+        slack_mask = slack_val > 0
+
+        # loss function of learning task part of obj function
+        obj2 = np.sum(slack_val[slack_mask])/n_triplets
+
+        obj = obj1 + obj2
+        if self.verbose:
+          count = np.sum(slack_mask)
+          print("[%s] iter %d\t obj %.6f\t num_imp %d" %
+                (self.__class__.__name__, (iter+1), obj, count))
+
+        # update the best
+        if obj < best_obj:
+          best_obj = obj
+          best_w = w
+
+    if self.verbose:
+      print("max iteration reached.")
+
+    # return L matrix yielded from best weights
+    self.n_iter_ = iter
+    self.components_ = self._components_from_basis_weights(basis, best_w)
+
+    return self
+
+  def _compute_dist_diff(self, triplets, X, basis):
+    """
+    Helper function to compute the distance difference of every triplet in the
+    space yielded by the basis set.
+    """
+    # Transformation of data by the basis set
+    XB = np.matmul(X, basis.T)
+
+    n_triplets = triplets.shape[0]
+    # get all positive and negative pairs with lowest index first
+    # np.array (2*n_triplets,2)
+    triplets_pairs_sorted = np.sort(np.vstack((triplets[:, [0, 1]],
+                                               triplets[:, [0, 2]])),
+                                    kind='stable')
+    # calculate all unique pairs and their indices
+    uniqPairs, indices = np.unique(triplets_pairs_sorted, return_inverse=True,
+                                   axis=0)
+    # calculate L2 distance acording to bases only for unique pairs
+    dist = np.square(XB[uniqPairs[:, 0], :] - XB[uniqPairs[:, 1], :])
+
+    # return the diference of distances between all positive and negative
+    # pairs
+    return dist[indices[:n_triplets]] - dist[indices[n_triplets:]]
+
+  def _components_from_basis_weights(self, basis, w):
+    """
+    Get components matrix (L) from computed mahalanobis matrix.
+    """
+
+    # get rid of inactive bases
+    # TODO: Maybe have a tolerance over zero?
+    active_idx, = w > 0
+    w = w[..., active_idx]
+    basis = basis[active_idx, :]
+
+    n_basis, n_features = basis.shape
+
+    if n_basis < n_features:  # if metric is low-rank
+      warnings.warn("The number of bases with nonzero weight is less than the "
+                    "number of features of the input, in consequence the "
+                    "learned transformation reduces the dimension to %d."
+                    % n_basis)
+      return np.sqrt(w.T)*basis  # equivalent to np.diag(np.sqrt(w)).dot(basis)
+
+    else:   # if metric is full rank
+      return components_from_metric(np.matmul(basis.T, w.T*basis))
+
+  def _to_index_points(self, triplets):
+    shape = triplets.shape
+    X, triplets = np.unique(np.vstack(triplets), return_inverse=True, axis=0)
+    triplets = triplets.reshape(shape[:2])
+    return triplets, X
+
+  def _initialize_basis(self, triplets, X):
+    """ Checks if the basis array is well constructed or constructs it based
+    on one of the available options.
+    """
+    n_features = X.shape[1]
+
+    if isinstance(self.basis, np.ndarray):
+      # TODO: should copy?
+      basis = check_array(self.basis, copy=True)
+      if basis.shape[1] != n_features:
+        raise ValueError('The dimensionality ({}) of the provided bases must'
+                         ' match the dimensionality of the data '
+                         '({}).'.format(basis.shape[1], n_features))
+    elif self.basis not in self._authorized_basis:
+      raise ValueError(
+          "`basis` must be one of the options '{}' "
+          "or an array of shape (n_basis, n_features)."
+          .format("', '".join(self._authorized_basis)))
+    if self.basis == 'triplet_diffs':
+      basis, n_basis = self._generate_bases_dist_diff(triplets, X)
+
+    return basis, n_basis
+
+  def _generate_bases_dist_diff(self, triplets, X):
+    """ Constructs the basis set from the differences of positive and negative
+    pairs from the triplets constraints.
+
+    The basis set is constructed iteratively by taking n_features triplets,
+    then adding and substracting respectively all the outerproducts of the
+    positive and negative pairs, and finally selecting the eigenvectors
+    of this matrix with positive eigenvalue. This is done until n_basis are
+    selected.
+    """
+    n_features = X.shape[1]
+    n_triplets = triplets.shape[0]
+
+    if self.n_basis is None:
+      # TODO: Get a good default n_basis directive
+      n_basis = n_features*80
+      warnings.warn('As no value for `n_basis` was selected, the number of '
+                    'basis will be set to n_basis= %d' % n_basis)
+    elif isinstance(self.n_basis, int):
+      n_basis = self.n_basis
+    else:
+      raise ValueError("n_basis should be an integer, instead it is of type %s"
+                       % type(self.n_basis))
+
+    if n_features > n_triplets:
+      raise ValueError(
+        "Number of features (%s) is greater than the number of triplets(%s).\n"
+        "Consider using dimensionality reduction or using another basis "
+        "generation scheme." % (n_features, n_triplets))
+
+    basis = np.zeros((n_basis, n_features))
+
+    # get all positive and negative pairs with lowest index first
+    # np.array (2*n_triplets,2)
+    triplets_pairs_sorted = np.sort(np.vstack((triplets[:, [0, 1]],
+                                               triplets[:, [0, 2]])),
+                                    kind='stable')
+    # calculate all unique pairs and their indices
+    uniqPairs, indices = np.unique(triplets_pairs_sorted, return_inverse=True,
+                                   axis=0)
+    # calculate differences only for unique pairs
+    diff = X[uniqPairs[:, 0], :] - X[uniqPairs[:, 1], :]
+
+    diff_pos = diff[indices[:n_triplets], :]
+    diff_neg = diff[indices[n_triplets:], :]
+
+    rng = check_random_state(self.random_state)
+
+    start = 0
+    finish = 0
+    while finish != n_basis:
+      # Select triplets to yield diff
+      select_triplet = rng.choice(n_triplets, size=n_features, replace=False)
+
+      # select n_features positive differences
+      d_pos = diff_pos[select_triplet, :]
+
+      # select n_features negative differences
+      d_neg = diff_neg[select_triplet, :]
+
+      # Yield matrix
+      diff_sum = d_pos.T.dot(d_pos) - d_neg.T.dot(d_neg)
+
+      # Calculate eigenvalue and eigenvectors
+      w, v = np.linalg.eigh(diff_sum.T.dot(diff_sum))
+
+      # Add eigenvectors with positive eigenvalue to basis set
+      pos_eig_mask = w > 0
+      start = finish
+      finish += pos_eig_mask.sum()
+
+      try:
+        basis[start:finish, :] = v[pos_eig_mask]
+      except ValueError:
+        # if finish is greater than n_basis
+        basis[start:, :] = v[pos_eig_mask][:n_basis-start]
+        break
+
+      # TODO: maybe add a warning in case there are no added bases, this could
+      # be caused by a bad triplet set. This would cause an infinite loop
+
+    return basis, n_basis
+
+
+
+[docs] +class SCML(_BaseSCML, _TripletsClassifierMixin): + """Sparse Compositional Metric Learning (SCML) + + `SCML` learns an squared Mahalanobis distance from triplet constraints by + optimizing sparse positive weights assigned to a set of :math:`K` rank-one + PSD bases. This can be formulated as an optimization problem with only + :math:`K` parameters, that can be solved with an efficient stochastic + composite scheme. + + Read more in the :ref:`User Guide <scml>`. + + .. warning:: + SCML is still a bit experimental, don't hesitate to report if + something fails/doesn't work as expected. + + Parameters + ---------- + beta: float (default=1e-5) + L1 regularization parameter. + + basis : string or array-like, optional (default='triplet_diffs') + Set of bases to construct the metric. Possible options are + 'triplet_diffs', and an array-like of shape (n_basis, n_features). + + 'triplet_diffs' + The basis set is constructed iteratively from differences between points + of `n_features` positive or negative pairs randomly sampled from the + triplets constraints. Requires the number of training triplets to be + great or equal to `n_features`. + + array-like + A matrix of shape (n_basis, n_features), that will be used as + the basis set for the metric construction. + + n_basis : int, optional + Number of basis to be yielded. In case it is not set it will be set based + on `basis`. If no value is selected a default will be computed based on + the input. + + gamma: float (default = 5e-3) + Learning rate for the optimization algorithm. + + max_iter : int (default = 10000) + Number of iterations for the algorithm. + + output_iter : int (default = 5000) + Number of iterations to check current weights performance and output this + information in case verbose is True. + + verbose : bool, optional + If True, prints information while learning. + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get triplets from indices. If array-like, + triplets will be formed like this: X[indices]. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. + + Attributes + ---------- + components_ : `numpy.ndarray`, shape=(n_features, n_features) + The linear transformation ``L`` deduced from the learned Mahalanobis + metric (See function `_components_from_basis_weights`.) + + Examples + -------- + >>> from metric_learn import SCML + >>> triplets = [[[1.2, 7.5], [1.3, 1.5], [6.2, 9.7]], + >>> [[1.3, 4.5], [3.2, 4.6], [5.4, 5.4]], + >>> [[3.2, 7.5], [3.3, 1.5], [8.2, 9.7]], + >>> [[3.3, 4.5], [5.2, 4.6], [7.4, 5.4]]] + >>> scml = SCML() + >>> scml.fit(triplets) + + References + ---------- + .. [1] Y. Shi, A. Bellet and F. Sha. `Sparse Compositional Metric Learning. + <http://researchers.lille.inria.fr/abellet/papers/aaai14.pdf>`_. \ + (AAAI), 2014. + + .. [2] Adapted from original `Matlab implementation. \ + <https://github.com/bellet/SCML>`_. + + See Also + -------- + metric_learn.SCML_Supervised : The supervised version of the algorithm. + + :ref:`supervised_version` : The section of the project documentation + that describes the supervised version of weakly supervised estimators. + """ + +
+[docs] + def fit(self, triplets): + """Learn the SCML model. + + Parameters + ---------- + triplets : array-like, shape=(n_constraints, 3, n_features) or \ + (n_constraints, 3) + 3D array-like of triplets of points or 2D array of triplets of + indicators. Triplets are assumed to be ordered such that: + d(triplets[i, 0],triplets[i, 1]) < d(triplets[i, 0], triplets[i, 2]). + + Returns + ------- + self : object + Returns the instance. + """ + + return self._fit(triplets)
+
+ + + +
+[docs] +class SCML_Supervised(_BaseSCML, TransformerMixin): + """Supervised version of Sparse Compositional Metric Learning (SCML) + + `SCML_Supervised` creates triplets by taking `k_genuine` neighbours + of the same class and `k_impostor` neighbours from different classes for each + point and then runs the SCML algorithm on these triplets. + + Read more in the :ref:`User Guide <scml>`. + + .. warning:: + SCML is still a bit experimental, don't hesitate to report if + something fails/doesn't work as expected. + + Parameters + ---------- + beta: float (default=1e-5) + L1 regularization parameter. + + basis : string or an array-like, optional (default='lda') + Set of bases to construct the metric. Possible options are + 'lda', and an array-like of shape (n_basis, n_features). + + 'lda' + The `n_basis` basis set is constructed from the LDA of significant + local regions in the feature space via clustering, for each region + center k-nearest neighbors are used to obtain the LDA scalings, + which correspond to the locally discriminative basis. + + array-like + A matrix of shape (n_basis, n_features), that will be used as + the basis set for the metric construction. + + n_basis : int, optional + Number of basis to be yielded. In case it is not set it will be set based + on `basis`. If no value is selected a default will be computed based on + the input. + + gamma: float (default = 5e-3) + Learning rate for the optimization algorithm. + + max_iter : int (default = 100000) + Number of iterations for the algorithm. + + output_iter : int (default = 5000) + Number of iterations to check current weights performance and output this + information in case verbose is True. + + verbose : bool, optional + If True, prints information while learning. + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get triplets from indices. If array-like, + triplets will be formed like this: X[indices]. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. + + Attributes + ---------- + components_ : `numpy.ndarray`, shape=(n_features, n_features) + The linear transformation ``L`` deduced from the learned Mahalanobis + metric (See function `_components_from_basis_weights`.) + + Examples + -------- + >>> from metric_learn import SCML_Supervised + >>> from sklearn.datasets import load_iris + >>> iris_data = load_iris() + >>> X = iris_data['data'] + >>> Y = iris_data['target'] + >>> scml = SCML_Supervised(random_state=33) + >>> scml.fit(X, Y) + SCML_Supervised(random_state=33) + >>> scml.score_pairs([[X[0], X[1]], [X[0], X[2]]]) + array([1.84640733, 1.55984363]) + >>> scml.get_metric()(X[0], X[1]) + 1.8464073327922157 + + References + ---------- + .. [1] Y. Shi, A. Bellet and F. Sha. `Sparse Compositional Metric Learning. + <http://researchers.lille.inria.fr/abellet/papers/aaai14.pdf>`_. \ + (AAAI), 2014. + + .. [2] Adapted from original `Matlab implementation. \ + <https://github.com/bellet/SCML>`_. + + See Also + -------- + metric_learn.SCML : The weakly supervised version of this + algorithm. + """ + # Add supervised authorized basis construction options + _authorized_basis = _BaseSCML._authorized_basis + ['lda'] + +
+[docs] + def __init__(self, k_genuine=3, k_impostor=10, beta=1e-5, basis='lda', + n_basis=None, gamma=5e-3, max_iter=10000, output_iter=500, + batch_size=10, verbose=False, preprocessor=None, + random_state=None): + self.k_genuine = k_genuine + self.k_impostor = k_impostor + _BaseSCML.__init__(self, beta=beta, basis=basis, n_basis=n_basis, + max_iter=max_iter, output_iter=output_iter, + batch_size=batch_size, verbose=verbose, + preprocessor=preprocessor, random_state=random_state)
+ + +
+[docs] + def fit(self, X, y): + """Create constraints from labels and learn the SCML model. + + Parameters + ---------- + X : (n x d) matrix + Input data, where each row corresponds to a single instance. + + y : (n) array-like + Data labels. + + Returns + ------- + self : object + Returns the instance. + """ + X, y = self._prepare_inputs(X, y, ensure_min_samples=2) + + basis, n_basis = self._initialize_basis_supervised(X, y) + + if not isinstance(self.k_genuine, int): + raise ValueError("k_genuine should be an integer, instead it is of type" + " %s" % type(self.k_genuine)) + if not isinstance(self.k_impostor, int): + raise ValueError("k_impostor should be an integer, instead it is of " + "type %s" % type(self.k_impostor)) + + constraints = Constraints(y) + triplets = constraints.generate_knntriplets(X, self.k_genuine, + self.k_impostor) + + triplets = X[triplets] + + return self._fit(triplets, basis, n_basis)
+ + + def _initialize_basis_supervised(self, X, y): + """ Constructs the basis set following one of the supervised options in + case one is selected. + """ + + if isinstance(self.basis, str) and self.basis == 'lda': + basis, n_basis = self._generate_bases_LDA(X, y) + else: + basis, n_basis = None, None + + return basis, n_basis + + def _generate_bases_LDA(self, X, y): + """ Generates bases for the 'lda' option. + + The basis set is constructed using Linear Discriminant Analysis of + significant local regions in the feature space via clustering, for + each region center k-nearest neighbors are used to obtain the LDA scalings, + which correspond to the locally discriminative basis. Currently this is + done at two scales `k={10,20}` if `n_feature < 50` or else `k={20,50}`. + """ + + labels, class_count = np.unique(y, return_counts=True) + n_class = len(labels) + + n_features = X.shape[1] + # Number of basis yielded from each LDA + num_eig = min(n_class-1, n_features) + + if self.n_basis is None: + # TODO: Get a good default n_basis directive + n_basis = min(20*n_features, X.shape[0]*2*num_eig - 1) + warnings.warn('As no value for `n_basis` was selected, the number of ' + 'basis will be set to n_basis= %d' % n_basis) + + elif isinstance(self.n_basis, int): + n_basis = self.n_basis + else: + raise ValueError("n_basis should be an integer, instead it is of type %s" + % type(self.n_basis)) + + # Number of clusters needed for 2 scales given the number of basis + # yielded by every LDA + n_clusters = int(np.ceil(n_basis/(2 * num_eig))) + + if n_basis < n_class: + warnings.warn("The number of basis is less than the number of classes, " + "which may lead to poor discriminative performance.") + elif n_basis >= X.shape[0]*2*num_eig: + raise ValueError("Not enough samples to generate %d LDA bases, n_basis" + "should be smaller than %d" % + (n_basis, X.shape[0]*2*num_eig)) + + kmeans = KMeans(n_clusters=n_clusters, n_init=10, + random_state=self.random_state, algorithm='elkan').fit(X) + cX = kmeans.cluster_centers_ + + n_scales = 2 + if n_features > 50: + scales = [20, 50] + else: + scales = [10, 20] + + k_class = np.vstack((np.minimum(class_count, scales[0]), + np.minimum(class_count, scales[1]))) + + idx_set = [np.zeros((n_clusters, sum(k_class[0, :])), dtype=np.int64), + np.zeros((n_clusters, sum(k_class[1, :])), dtype=np.int64)] + + start_finish_indices = np.hstack((np.zeros((2, 1), np.int64), + k_class)).cumsum(axis=1) + + neigh = NearestNeighbors() + + for c in range(n_class): + sel_c = np.where(y == labels[c]) + + # get k_class same class neighbors + neigh.fit(X=X[sel_c]) + # Only take the neighbors once for the biggest scale + neighbors = neigh.kneighbors(X=cX, n_neighbors=k_class[-1, c], + return_distance=False) + + # add index set of neighbors for every cluster center for both scales + for s, k in enumerate(k_class[:, c]): + start, finish = start_finish_indices[s, c:c+2] + idx_set[s][:, start:finish] = np.take(sel_c, neighbors[:, :k]) + + # Compute basis for every cluster in both scales + basis = np.zeros((n_basis, n_features)) + lda = LinearDiscriminantAnalysis() + start_finish_indices = np.hstack((np.vstack((0, n_clusters * num_eig)), + np.full((2, n_clusters), + num_eig))).cumsum(axis=1) + + for s in range(n_scales): + for c in range(n_clusters): + lda.fit(X[idx_set[s][c, :]], y[idx_set[s][c, :]]) + start, finish = start_finish_indices[s, c:c+2] + normalized_scalings = normalize(lda.scalings_.T) + try: + basis[start: finish, :] = normalized_scalings + except ValueError: + # handle tail + basis[start:, :] = normalized_scalings[:n_basis-start] + break + + return basis, n_basis
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/metric_learn/sdml.html b/_modules/metric_learn/sdml.html new file mode 100644 index 00000000..d4c4ff9b --- /dev/null +++ b/_modules/metric_learn/sdml.html @@ -0,0 +1,478 @@ + + + + + + metric_learn.sdml — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for metric_learn.sdml

+"""
+Sparse High-Dimensional Metric Learning (SDML)
+"""
+
+import warnings
+import numpy as np
+from sklearn.base import TransformerMixin
+from scipy.linalg import pinvh
+from sklearn.covariance import graphical_lasso
+from sklearn.exceptions import ConvergenceWarning
+
+from .base_metric import MahalanobisMixin, _PairsClassifierMixin
+from .constraints import Constraints, wrap_pairs
+from ._util import components_from_metric, _initialize_metric_mahalanobis
+try:
+  from inverse_covariance import quic
+except ImportError:
+  HAS_SKGGM = False
+else:
+  HAS_SKGGM = True
+
+
+class _BaseSDML(MahalanobisMixin):
+
+  _tuple_size = 2  # constraints are pairs
+
+  def __init__(self, balance_param=0.5, sparsity_param=0.01, prior='identity',
+               verbose=False, preprocessor=None,
+               random_state=None):
+    self.balance_param = balance_param
+    self.sparsity_param = sparsity_param
+    self.prior = prior
+    self.verbose = verbose
+    self.random_state = random_state
+    super(_BaseSDML, self).__init__(preprocessor)
+
+  def _fit(self, pairs, y):
+    if not HAS_SKGGM:
+      if self.verbose:
+        print("SDML will use scikit-learn's graphical lasso solver.")
+    else:
+      if self.verbose:
+        print("SDML will use skggm's graphical lasso solver.")
+    pairs, y = self._prepare_inputs(pairs, y,
+                                    type_of_inputs='tuples')
+    n_features = pairs.shape[2]
+    if n_features < 2:
+      raise ValueError(f"Cannot fit SDML with {n_features} feature(s)")
+
+    # set up (the inverse of) the prior M
+    # if the prior is the default (None), we raise a warning
+    _, prior_inv = _initialize_metric_mahalanobis(
+        pairs, self.prior,
+        return_inverse=True, strict_pd=True, matrix_name='prior',
+        random_state=self.random_state)
+    diff = pairs[:, 0] - pairs[:, 1]
+    loss_matrix = (diff.T * y).dot(diff)
+    emp_cov = prior_inv + self.balance_param * loss_matrix
+
+    # our initialization will be the matrix with emp_cov's eigenvalues,
+    # with a constant added so that they are all positive (plus an epsilon
+    # to ensure definiteness). This is empirical.
+    w, V = np.linalg.eigh(emp_cov)
+    min_eigval = np.min(w)
+    if min_eigval < 0.:
+      warnings.warn("Warning, the input matrix of graphical lasso is not "
+                    "positive semi-definite (PSD). The algorithm may diverge, "
+                    "and lead to degenerate solutions. "
+                    "To prevent that, try to decrease the balance parameter "
+                    "`balance_param` and/or to set prior='identity'.",
+                    ConvergenceWarning)
+      w -= min_eigval  # we translate the eigenvalues to make them all positive
+    w += 1e-10  # we add a small offset to avoid definiteness problems
+    sigma0 = (V * w).dot(V.T)
+    try:
+      if HAS_SKGGM:
+        theta0 = pinvh(sigma0)
+        M, _, _, _, _, _ = quic(emp_cov, lam=self.sparsity_param,
+                                msg=self.verbose,
+                                Theta0=theta0, Sigma0=sigma0)
+      else:
+        _, M = graphical_lasso(emp_cov, alpha=self.sparsity_param,
+                               verbose=self.verbose,
+                               cov_init=sigma0)
+      raised_error = None
+      w_mahalanobis, _ = np.linalg.eigh(M)
+      not_spd = any(w_mahalanobis < 0.)
+      not_finite = not np.isfinite(M).all()
+    # TODO: Narrow this to the specific exceptions we expect.
+    except Exception as e:
+      raised_error = e
+      not_spd = False  # not_spd not applicable here so we set to False
+      not_finite = False  # not_finite not applicable here so we set to False
+    if raised_error is not None or not_spd or not_finite:
+      msg = ("There was a problem in SDML when using {}'s graphical "
+             "lasso solver.").format("skggm" if HAS_SKGGM else "scikit-learn")
+      if not HAS_SKGGM:
+        skggm_advice = (" skggm's graphical lasso can sometimes converge "
+                        "on non SPD cases where scikit-learn's graphical "
+                        "lasso fails to converge. Try to install skggm and "
+                        "rerun the algorithm (see the README.md for the "
+                        "right version of skggm).")
+        msg += skggm_advice
+      if raised_error is not None:
+        msg += " The following error message was thrown: {}.".format(
+            raised_error)
+      raise RuntimeError(msg)
+
+    self.components_ = components_from_metric(np.atleast_2d(M))
+    return self
+
+
+
+[docs] +class SDML(_BaseSDML, _PairsClassifierMixin): + r"""Sparse Distance Metric Learning (SDML) + + SDML is an efficient sparse metric learning in high-dimensional space via + double regularization: an L1-penalization on the off-diagonal elements of the + Mahalanobis matrix :math:`\mathbf{M}`, and a log-determinant divergence + between :math:`\mathbf{M}` and :math:`\mathbf{M_0}` (set as either + :math:`\mathbf{I}` or :math:`\mathbf{\Omega}^{-1}`, where + :math:`\mathbf{\Omega}` is the covariance matrix). + + Read more in the :ref:`User Guide <sdml>`. + + Parameters + ---------- + balance_param : float, optional (default=0.5) + Trade off between sparsity and M0 prior. + + sparsity_param : float, optional (default=0.01) + Trade off between optimizer and sparseness (see graph_lasso). + + prior : string or numpy array, optional (default='identity') + Prior to set for the metric. Possible options are + 'identity', 'covariance', 'random', and a numpy array of + shape (n_features, n_features). For SDML, the prior should be strictly + positive definite (PD). + + 'identity' + An identity matrix of shape (n_features, n_features). + + 'covariance' + The inverse covariance matrix. + + 'random' + The prior will be a random positive definite (PD) matrix of shape + `(n_features, n_features)`, generated using + `sklearn.datasets.make_spd_matrix`. + + numpy array + A positive definite (PD) matrix of shape + (n_features, n_features), that will be used as such to set the + prior. + + verbose : bool, optional (default=False) + If True, prints information while learning. + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be gotten like this: X[indices]. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. If + ``prior='random'``, ``random_state`` is used to set the prior. + + Attributes + ---------- + components_ : `numpy.ndarray`, shape=(n_features, n_features) + The linear transformation ``L`` deduced from the learned Mahalanobis + metric (See function `components_from_metric`.) + + threshold_ : `float` + If the distance metric between two points is lower than this threshold, + points will be classified as similar, otherwise they will be + classified as dissimilar. + + Examples + -------- + >>> from metric_learn import SDML_Supervised + >>> from sklearn.datasets import load_iris + >>> iris_data = load_iris() + >>> X = iris_data['data'] + >>> Y = iris_data['target'] + >>> sdml = SDML_Supervised(n_constraints=200) + >>> sdml.fit(X, Y) + + References + ---------- + .. [1] Qi et al. `An efficient sparse metric learning in high-dimensional + space via L1-penalized log-determinant regularization + <http://www.machinelearning.org/archive/icml2009/papers/46.pdf>`_. + ICML 2009. + + .. [2] Code adapted from https://gist.github.com/kcarnold/5439945 + """ + +
+[docs] + def fit(self, pairs, y, calibration_params=None): + """Learn the SDML model. + + The threshold will be calibrated on the trainset using the parameters + `calibration_params`. + + Parameters + ---------- + pairs : array-like, shape=(n_constraints, 2, n_features) or \ + (n_constraints, 2) + 3D Array of pairs with each row corresponding to two points, + or 2D array of indices of pairs if the metric learner uses a + preprocessor. + + y : array-like, of shape (n_constraints,) + Labels of constraints. Should be -1 for dissimilar pair, 1 for similar. + + calibration_params : `dict` or `None` + Dictionary of parameters to give to `calibrate_threshold` for the + threshold calibration step done at the end of `fit`. If `None` is + given, `calibrate_threshold` will use the default parameters. + + Returns + ------- + self : object + Returns the instance. + """ + calibration_params = (calibration_params if calibration_params is not + None else dict()) + self._validate_calibration_params(**calibration_params) + self._fit(pairs, y) + self.calibrate_threshold(pairs, y, **calibration_params) + return self
+
+ + + +
+[docs] +class SDML_Supervised(_BaseSDML, TransformerMixin): + """Supervised version of Sparse Distance Metric Learning (SDML) + + `SDML_Supervised` creates pairs of similar sample by taking same class + samples, and pairs of dissimilar samples by taking different class + samples. It then passes these pairs to `SDML` for training. + + Parameters + ---------- + balance_param : float, optional (default=0.5) + Trade off between sparsity and M0 prior. + + sparsity_param : float, optional (default=0.01) + Trade off between optimizer and sparseness (see graph_lasso). + + prior : string or numpy array, optional (default='identity') + Prior to set for the metric. Possible options are + 'identity', 'covariance', 'random', and a numpy array of + shape (n_features, n_features). For SDML, the prior should be strictly + positive definite (PD). + + 'identity' + An identity matrix of shape (n_features, n_features). + + 'covariance' + The inverse covariance matrix. + + 'random' + The prior will be a random SPD matrix of shape + `(n_features, n_features)`, generated using + `sklearn.datasets.make_spd_matrix`. + + numpy array + A positive definite (PD) matrix of shape + (n_features, n_features), that will be used as such to set the + prior. + + n_constraints : int, optional (default=None) + Number of constraints to generate. If None, defaults to `20 * + num_classes**2`. + + verbose : bool, optional (default=False) + If True, prints information while learning. + + preprocessor : array-like, shape=(n_samples, n_features) or callable + The preprocessor to call to get tuples from indices. If array-like, + tuples will be formed like this: X[indices]. + + random_state : int or numpy.RandomState or None, optional (default=None) + A pseudo random number generator object or a seed for it if int. If + ``init='random'``, ``random_state`` is used to set the random + prior. In any case, `random_state` is also used to randomly sample + constraints from labels. + + num_constraints : Renamed to n_constraints. Will be deprecated in 0.7.0 + + Attributes + ---------- + components_ : `numpy.ndarray`, shape=(n_features, n_features) + The linear transformation ``L`` deduced from the learned Mahalanobis + metric (See function `components_from_metric`.) + + See Also + -------- + metric_learn.SDML : The original weakly-supervised algorithm + :ref:`supervised_version` : The section of the project documentation + that describes the supervised version of weakly supervised estimators. + """ + +
+[docs] + def __init__(self, balance_param=0.5, sparsity_param=0.01, prior='identity', + n_constraints=None, verbose=False, preprocessor=None, + random_state=None, num_constraints='deprecated'): + _BaseSDML.__init__(self, balance_param=balance_param, + sparsity_param=sparsity_param, prior=prior, + verbose=verbose, + preprocessor=preprocessor, random_state=random_state) + if num_constraints != 'deprecated': + warnings.warn('"num_constraints" parameter has been renamed to' + ' "n_constraints". It has been deprecated in' + ' version 0.6.3 and will be removed in 0.7.0' + '', FutureWarning) + self.n_constraints = num_constraints + else: + self.n_constraints = n_constraints + # Avoid test get_params from failing (all params passed sholud be set) + self.num_constraints = 'deprecated'
+ + +
+[docs] + def fit(self, X, y): + """Create constraints from labels and learn the SDML model. + + Parameters + ---------- + X : array-like, shape (n, d) + data matrix, where each row corresponds to a single instance + + y : array-like, shape (n,) + data labels, one for each instance + + Returns + ------- + self : object + Returns the instance. + """ + X, y = self._prepare_inputs(X, y, ensure_min_samples=2) + n_constraints = self.n_constraints + if n_constraints is None: + num_classes = len(np.unique(y)) + n_constraints = 20 * num_classes**2 + + c = Constraints(y) + pos_neg = c.positive_negative_pairs(n_constraints, + random_state=self.random_state) + pairs, y = wrap_pairs(X, pos_neg) + return _BaseSDML._fit(self, pairs, y)
+
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_sources/auto_examples/index.rst.txt b/_sources/auto_examples/index.rst.txt new file mode 100644 index 00000000..077f3b80 --- /dev/null +++ b/_sources/auto_examples/index.rst.txt @@ -0,0 +1,77 @@ +:orphan: + +Examples +======== + +Below is a gallery of example metric-learn use cases. + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/images/thumb/sphx_glr_plot_sandwich_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_plot_sandwich.py` + +.. raw:: html + +
Sandwich demo
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/images/thumb/sphx_glr_plot_metric_learning_examples_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_plot_metric_learning_examples.py` + +.. raw:: html + +
Algorithms walkthrough
+
+ + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_sandwich + /auto_examples/plot_metric_learning_examples + + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-gallery + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download all examples in Python source code: auto_examples_python.zip ` + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download all examples in Jupyter notebooks: auto_examples_jupyter.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/_sources/auto_examples/plot_metric_learning_examples.rst.txt b/_sources/auto_examples/plot_metric_learning_examples.rst.txt new file mode 100644 index 00000000..cbb135f2 --- /dev/null +++ b/_sources/auto_examples/plot_metric_learning_examples.rst.txt @@ -0,0 +1,885 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/plot_metric_learning_examples.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_plot_metric_learning_examples.py: + + +Algorithms walkthrough +~~~~~~~~~~~~~~~~~~~~~~ + +This is a small walkthrough which illustrates most of the Metric Learning +algorithms implemented in metric-learn by using them on synthetic data, +with some visualizations to provide intuitions into what they are designed +to achieve. + +.. GENERATED FROM PYTHON SOURCE LINES 10-15 + +.. code-block:: default + + + # License: BSD 3 clause + # Authors: Bhargav Srinivasa Desikan + # William de Vazelhes + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 16-23 + +Imports +^^^^^^^ +.. note:: + + In order to show the charts of the examples you need a graphical + ``matplotlib`` backend installed. For intance, use ``pip install pyqt5`` + to get Qt graphical interface or use your favorite one. + +.. GENERATED FROM PYTHON SOURCE LINES 23-35 + +.. code-block:: default + + + from sklearn.manifold import TSNE + + import metric_learn + import numpy as np + from sklearn.datasets import make_classification, make_regression + + # visualisation imports + import matplotlib.pyplot as plt + np.random.seed(42) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 36-45 + +Loading our dataset and setting up plotting +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We will be using a synthetic dataset to illustrate the plotting, +using the function `sklearn.datasets.make_classification` from +scikit-learn. The dataset will contain: +- 100 points in 3 classes with 2 clusters per class +- 5 features, among which 3 are informative (correlated with the class +labels) and two are random noise with large magnitude + +.. GENERATED FROM PYTHON SOURCE LINES 45-51 + +.. code-block:: default + + + X, y = make_classification(n_samples=100, n_classes=3, n_clusters_per_class=2, + n_informative=3, class_sep=4., n_features=5, + n_redundant=0, shuffle=True, + scale=[1, 1, 20, 20, 20]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 52-55 + +Note that the dimensionality of the data is 5, so to plot the +transformed data in 2D, we will use the t-sne algorithm. (See +`sklearn.manifold.TSNE`). + +.. GENERATED FROM PYTHON SOURCE LINES 55-72 + +.. code-block:: default + + + + def plot_tsne(X, y, colormap=plt.cm.Paired): + plt.figure(figsize=(8, 6)) + + # clean the figure + plt.clf() + + tsne = TSNE() + X_embedded = tsne.fit_transform(X) + plt.scatter(X_embedded[:, 0], X_embedded[:, 1], c=y, cmap=colormap) + + plt.xticks(()) + plt.yticks(()) + + plt.show() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 73-74 + +Let's now plot the dataset as is. + +.. GENERATED FROM PYTHON SOURCE LINES 74-78 + +.. code-block:: default + + + + plot_tsne(X, y) + + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_metric_learning_examples_001.png + :alt: plot metric learning examples + :srcset: /auto_examples/images/sphx_glr_plot_metric_learning_examples_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 79-115 + +We can see that the classes appear mixed up: this is because t-sne +is based on preserving the original neighborhood of points in the embedding +space, but this original neighborhood is based on the euclidean +distance in the input space, in which the contribution of the noisy +features is high. So even if points from the same class are close to each +other in some subspace of the input space, this is not the case when +considering all dimensions of the input space. + +Metric Learning +^^^^^^^^^^^^^^^ + +Why is Metric Learning useful? We can, with prior knowledge of which +points are supposed to be closer, figure out a better way to compute +distances between points for the task at hand. Especially in higher +dimensions when Euclidean distances are a poor way to measure distance, this +becomes very useful. + +Basically, we learn this distance: +:math:`D(x, x') = \sqrt{(x-x')^\top M(x-x')}`. And we learn the parameters +:math:`M` of this distance to satisfy certain constraints on the distance +between points, for example requiring that points of the same class are +close together and points of different class are far away. + +For more information, check the :ref:`intro_metric_learning` section +from the documentation. Some good reading material can also be found +`here `__. It serves as a +good literature review of Metric Learning. + +We will briefly explain the metric learning algorithms implemented by +metric-learn, before providing some examples for its usage, and also +discuss how to perform metric learning with weaker supervision than class +labels. + +Metric-learn can be easily integrated with your other machine learning +pipelines, and follows scikit-learn conventions. + + +.. GENERATED FROM PYTHON SOURCE LINES 118-138 + +Large Margin Nearest Neighbour +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +LMNN is a metric learning algorithm primarily designed for k-nearest +neighbor classification. The algorithm is based on semidefinite +programming, a sub-class of convex programming (as most Metric Learning +algorithms are). + +The main intuition behind LMNN is to learn a pseudometric under which +all data instances in the training set are surrounded by at least k +instances that share the same class label. If this is achieved, the +leave-one-out error (a special case of cross validation) is minimized. +You'll notice that the points from the same labels are closer together, +but they are not necessary in a same cluster. This is particular to LMNN +and we'll see that some other algorithms implicitly enforce points from +the same class to cluster together. + +- See more in the :ref:`User Guide ` +- See more in the documentation of the class :py:class:`LMNN + ` + +.. GENERATED FROM PYTHON SOURCE LINES 141-144 + +Fit and then transform! +----------------------- + + +.. GENERATED FROM PYTHON SOURCE LINES 144-155 + +.. code-block:: default + + + # setting up LMNN + lmnn = metric_learn.LMNN(n_neighbors=5, learn_rate=1e-6) + + # fit the data! + lmnn.fit(X, y) + + # transform our input space + X_lmnn = lmnn.transform(X) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 156-157 + +So what have we learned? The matrix :math:`M` we talked about before. + +.. GENERATED FROM PYTHON SOURCE LINES 160-163 + +Now let us plot the transformed space - this tells us what the original +space looks like after being transformed with the new learned metric. + + +.. GENERATED FROM PYTHON SOURCE LINES 163-167 + +.. code-block:: default + + + plot_tsne(X_lmnn, y) + + + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_metric_learning_examples_002.png + :alt: plot metric learning examples + :srcset: /auto_examples/images/sphx_glr_plot_metric_learning_examples_002.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 168-175 + +Pretty neat, huh? + +The rest of this notebook will briefly explain the other Metric Learning +algorithms before plotting them. Also, while we have first run ``fit`` +and then ``transform`` to see our data transformed, we can also use +``fit_transform``. The rest of the examples and illustrations will use +``fit_transform``. + +.. GENERATED FROM PYTHON SOURCE LINES 177-189 + +Information Theoretic Metric Learning +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +ITML uses a regularizer that automatically enforces a Semi-Definite +Positive Matrix condition - the LogDet divergence. It uses soft +must-link or cannot-link constraints, and a simple algorithm based on +Bregman projections. Unlike LMNN, ITML will implicitly enforce points from +the same class to belong to the same cluster, as you can see below. + +- See more in the :ref:`User Guide ` +- See more in the documentation of the class :py:class:`ITML + ` + +.. GENERATED FROM PYTHON SOURCE LINES 189-196 + +.. code-block:: default + + + itml = metric_learn.ITML_Supervised() + X_itml = itml.fit_transform(X, y) + + plot_tsne(X_itml, y) + + + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_metric_learning_examples_003.png + :alt: plot metric learning examples + :srcset: /auto_examples/images/sphx_glr_plot_metric_learning_examples_003.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 197-208 + +Mahalanobis Metric for Clustering +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +MMC is an algorithm that will try to minimize the distance between similar +points, while ensuring that the sum of distances between dissimilar points is +higher than a threshold. This is done by optimizing a cost function +subject to an inequality constraint. + +- See more in the :ref:`User Guide ` +- See more in the documentation of the class :py:class:`MMC + ` + +.. GENERATED FROM PYTHON SOURCE LINES 208-214 + +.. code-block:: default + + + mmc = metric_learn.MMC_Supervised() + X_mmc = mmc.fit_transform(X, y) + + plot_tsne(X_mmc, y) + + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_metric_learning_examples_004.png + :alt: plot metric learning examples + :srcset: /auto_examples/images/sphx_glr_plot_metric_learning_examples_004.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 215-227 + +Sparse Determinant Metric Learning +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Implements an efficient sparse metric learning algorithm in high +dimensional space via an :math:`l_1`-penalized log-determinant +regularization. Compared to the most existing distance metric learning +algorithms, the algorithm exploits the sparsity nature underlying the +intrinsic high dimensional feature space. + +- See more in the :ref:`User Guide ` +- See more in the documentation of the class :py:class:`SDML + ` + +.. GENERATED FROM PYTHON SOURCE LINES 227-235 + +.. code-block:: default + + + sdml = metric_learn.SDML_Supervised(sparsity_param=0.1, balance_param=0.0015, + prior='covariance') + X_sdml = sdml.fit_transform(X, y) + + plot_tsne(X_sdml, y) + + + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_metric_learning_examples_005.png + :alt: plot metric learning examples + :srcset: /auto_examples/images/sphx_glr_plot_metric_learning_examples_005.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + /Users/william.vezelhes/miniconda3/envs/docenvbis/lib/python3.11/site-packages/sklearn/covariance/_graph_lasso.py:329: FutureWarning: The cov_init parameter is deprecated in 1.3 and will be removed in 1.5. It does not have any effect. + warnings.warn( + + + + +.. GENERATED FROM PYTHON SOURCE LINES 236-247 + +Least Squares Metric Learning +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +LSML is a simple, yet effective, algorithm that learns a Mahalanobis +metric from a given set of relative comparisons. This is done by +formulating and minimizing a convex loss function that corresponds to +the sum of squared hinge loss of violated constraints. + +- See more in the :ref:`User Guide ` +- See more in the documentation of the class :py:class:`LSML + ` + +.. GENERATED FROM PYTHON SOURCE LINES 247-255 + +.. code-block:: default + + + lsml = metric_learn.LSML_Supervised(tol=0.0001, max_iter=10000, + prior='covariance') + X_lsml = lsml.fit_transform(X, y) + + plot_tsne(X_lsml, y) + + + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_metric_learning_examples_006.png + :alt: plot metric learning examples + :srcset: /auto_examples/images/sphx_glr_plot_metric_learning_examples_006.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 256-275 + +Neighborhood Components Analysis +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +NCA is an extremly popular metric learning algorithm. + +Neighborhood components analysis aims at "learning" a distance metric +by finding a linear transformation of input data such that the average +leave-one-out (LOO) classification performance of a soft-nearest +neighbors rule is maximized in the transformed space. The key insight to +the algorithm is that a matrix :math:`A` corresponding to the +transformation can be found by defining a differentiable objective function +for :math:`A`, followed by use of an iterative solver such as +`scipy.optimize.fmin_l_bfgs_b`. Like LMNN, this algorithm does not try to +cluster points from the same class in a unique cluster, because it +enforces conditions at a local neighborhood scale. + +- See more in the :ref:`User Guide ` +- See more in the documentation of the class :py:class:`NCA + ` + +.. GENERATED FROM PYTHON SOURCE LINES 275-281 + +.. code-block:: default + + + nca = metric_learn.NCA(max_iter=1000) + X_nca = nca.fit_transform(X, y) + + plot_tsne(X_nca, y) + + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_metric_learning_examples_007.png + :alt: plot metric learning examples + :srcset: /auto_examples/images/sphx_glr_plot_metric_learning_examples_007.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 282-295 + +Local Fisher Discriminant Analysis +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +LFDA is a linear supervised dimensionality reduction method. It is +particularly useful when dealing with multimodality, where one ore more +classes consist of separate clusters in input space. The core +optimization problem of LFDA is solved as a generalized eigenvalue +problem. Like LMNN, and NCA, this algorithm does not try to cluster points +from the same class in a unique cluster. + +- See more in the :ref:`User Guide ` +- See more in the documentation of the class :py:class:`LFDA + ` + +.. GENERATED FROM PYTHON SOURCE LINES 295-302 + +.. code-block:: default + + + lfda = metric_learn.LFDA(k=2, n_components=2) + X_lfda = lfda.fit_transform(X, y) + + plot_tsne(X_lfda, y) + + + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_metric_learning_examples_008.png + :alt: plot metric learning examples + :srcset: /auto_examples/images/sphx_glr_plot_metric_learning_examples_008.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 303-316 + +Relative Components Analysis +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +RCA is another one of the older algorithms. It learns a full rank +Mahalanobis distance metric based on a weighted sum of in-class +covariance matrices. It applies a global linear transformation to assign +large weights to relevant dimensions and low weights to irrelevant +dimensions. Those relevant dimensions are estimated using "chunklets", +subsets of points that are known to belong to the same class. + +- See more in the :ref:`User Guide ` +- See more in the documentation of the class :py:class:`RCA + ` + +.. GENERATED FROM PYTHON SOURCE LINES 316-322 + +.. code-block:: default + + + rca = metric_learn.RCA_Supervised(n_chunks=30, chunk_size=2) + X_rca = rca.fit_transform(X, y) + + plot_tsne(X_rca, y) + + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_metric_learning_examples_009.png + :alt: plot metric learning examples + :srcset: /auto_examples/images/sphx_glr_plot_metric_learning_examples_009.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 323-343 + +Regression example: Metric Learning for Kernel Regression +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The previous algorithms took as input a dataset with class labels. Metric +learning can also be useful for regression, when the labels are real numbers. +An algorithm very similar to NCA but for regression is Metric +Learning for Kernel Regression (MLKR). It will optimize for the average +leave-one-out *regression* performance from a soft-nearest neighbors +regression. + +- See more in the :ref:`User Guide ` +- See more in the documentation of the class :py:class:`MLKR + ` + +To illustrate MLKR, let's use the dataset +`sklearn.datasets.make_regression` the same way as we did with the +classification before. The dataset will contain: 100 points of 5 features +each, among which 3 are informative (i.e., used to generate the +regression target from a linear model), and two are random noise with the +same magnitude. + +.. GENERATED FROM PYTHON SOURCE LINES 343-347 + +.. code-block:: default + + + X_reg, y_reg = make_regression(n_samples=100, n_informative=3, n_features=5, + shuffle=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 348-349 + +Let's plot the dataset as is + +.. GENERATED FROM PYTHON SOURCE LINES 349-352 + +.. code-block:: default + + + plot_tsne(X_reg, y_reg, plt.cm.Oranges) + + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_metric_learning_examples_010.png + :alt: plot metric learning examples + :srcset: /auto_examples/images/sphx_glr_plot_metric_learning_examples_010.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 353-354 + +And let's plot the dataset after transformation by MLKR: + +.. GENERATED FROM PYTHON SOURCE LINES 354-358 + +.. code-block:: default + + mlkr = metric_learn.MLKR() + X_mlkr = mlkr.fit_transform(X_reg, y_reg) + plot_tsne(X_mlkr, y_reg, plt.cm.Oranges) + + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_metric_learning_examples_011.png + :alt: plot metric learning examples + :srcset: /auto_examples/images/sphx_glr_plot_metric_learning_examples_011.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 359-362 + +Points that have the same value to regress are now closer to each +other ! This would improve the performance of +`sklearn.neighbors.KNeighborsRegressor` for instance. + +.. GENERATED FROM PYTHON SOURCE LINES 365-404 + +Metric Learning from Weaker Supervision +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To learn the metric, so far we have always given the labels of the +data to supervise the algorithms. However, in many applications, +it is easier to obtain information about whether two samples are +similar or dissimilar. For instance, when annotating a dataset of face +images, it is easier for an annotator to tell if two faces belong to the same +person or not, rather than finding the ID of the face among a huge database +of every person's faces. +Note that for some problems (e.g., in information +retrieval where the goal is to rank documents by similarity to a query +document), there is no notion of individual label but one can gather +information on which pairs of points are similar or dissimilar. +Fortunately, one of the strength of metric learning is the ability to +learn from such weaker supervision. Indeed, some of the algorithms we've +used above have alternate ways to pass some supervision about the metric +we want to learn. The way to go is to pass a 2D array `pairs` of pairs, +as well as an array of labels `pairs_labels` such that for each `i` between +`0` and `n_pairs` we want `X[pairs[i, 0], :]` and `X[pairs[i, 1], :]` to be +similar if `pairs_labels[i] == 1`, and we want them to be dissimilar if +`pairs_labels[i] == -1`. In other words, we +want to enforce a metric that projects similar points closer together and +dissimilar points further away from each other. This kind of input is +possible for ITML, SDML, and MMC. See :ref:`weakly_supervised_section` for +details on other kinds of weak supervision that some algorithms can work +with. + +For the purpose of this example, we're going to explicitly create these +pairwise constraints through the labels we have, i.e. `y`. +Do keep in mind that we are doing this method because we know the labels +- we can actually create the constraints any way we want to depending on +the data! + +Note that this is what metric-learn did under the hood in the previous +examples (do check out the +`constraints` module!) - but we'll try our own version of this. We're +going to go ahead and assume that two points labeled the same will be +closer than two points in different labels. + +.. GENERATED FROM PYTHON SOURCE LINES 404-447 + +.. code-block:: default + + + + def create_constraints(labels): + import itertools + import random + + # aggregate indices of same class + zeros = np.where(y == 0)[0] + ones = np.where(y == 1)[0] + twos = np.where(y == 2)[0] + # make permutations of all those points in the same class + zeros_ = list(itertools.combinations(zeros, 2)) + ones_ = list(itertools.combinations(ones, 2)) + twos_ = list(itertools.combinations(twos, 2)) + # put them together! + sim = np.array(zeros_ + ones_ + twos_) + + # similarily, put together indices in different classes + dis = [] + for zero in zeros: + for one in ones: + dis.append((zero, one)) + for two in twos: + dis.append((zero, two)) + for one in ones: + for two in twos: + dis.append((one, two)) + + # pick up just enough dissimilar examples as we have similar examples + dis = np.array(random.sample(dis, len(sim))) + + # return an array of pairs of indices of shape=(2*len(sim), 2), and the + # corresponding labels, array of shape=(2*len(sim)) + # Each pair of similar points have a label of +1 and each pair of + # dissimilar points have a label of -1 + return (np.vstack([np.column_stack([sim[:, 0], sim[:, 1]]), + np.column_stack([dis[:, 0], dis[:, 1]])]), + np.concatenate([np.ones(len(sim)), -np.ones(len(sim))])) + + + pairs, pairs_labels = create_constraints(y) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 448-450 + +Now that we've created our constraints, let's see what it looks like! + + +.. GENERATED FROM PYTHON SOURCE LINES 450-455 + +.. code-block:: default + + + print(pairs) + print(pairs_labels) + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + [[ 0 6] + [ 0 9] + [ 0 10] + ... + [77 65] + [72 1] + [55 71]] + [ 1. 1. 1. ... -1. -1. -1.] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 456-464 + +Using our constraints, let's now train ITML again. Note that we are no +longer calling the supervised class :py:class:`ITML_Supervised +` but the more generic +(weakly-supervised) :py:class:`ITML `, which +takes the dataset `X` through the `preprocessor` argument (see +:ref:`this section ` of the documentation to learn +about more advanced uses of `preprocessor`) and the pair information `pairs` +and `pairs_labels` in the fit method. + +.. GENERATED FROM PYTHON SOURCE LINES 464-473 + +.. code-block:: default + + + itml = metric_learn.ITML(preprocessor=X) + itml.fit(pairs, pairs_labels) + + X_itml = itml.transform(X) + + plot_tsne(X_itml, y) + + + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_metric_learning_examples_012.png + :alt: plot metric learning examples + :srcset: /auto_examples/images/sphx_glr_plot_metric_learning_examples_012.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 474-493 + +And that's the result of ITML after being trained on our manually +constructed constraints! A bit different from our old result, but not too +different. + +RCA and LSML also have their own specific ways of taking in inputs - +it's worth one's while to poke around in the constraints.py file to see +how exactly this is going on. + +Finally, one of the main advantages of metric-learn is its out-of-the box +compatibility with scikit-learn, for doing `model selection +`__, +cross-validation, and scoring for instance. Indeed, supervised algorithms are +regular `sklearn.base.TransformerMixin` that can be plugged into any +pipeline or cross-validation procedure. And weakly-supervised estimators are +also compatible with scikit-learn, since their input dataset format described +above allows to be sliced along the first dimension when doing +cross-validations (see also this :ref:`section `). You +can also look at some :ref:`use cases ` where you could combine +metric-learn with scikit-learn estimators. + +.. GENERATED FROM PYTHON SOURCE LINES 495-496 + +This brings us to the end of this tutorial! Have fun Metric Learning :) + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 32.400 seconds) + + +.. _sphx_glr_download_auto_examples_plot_metric_learning_examples.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + + + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: plot_metric_learning_examples.py ` + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: plot_metric_learning_examples.ipynb ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/_sources/auto_examples/plot_sandwich.rst.txt b/_sources/auto_examples/plot_sandwich.rst.txt new file mode 100644 index 00000000..69909c2c --- /dev/null +++ b/_sources/auto_examples/plot_sandwich.rst.txt @@ -0,0 +1,178 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/plot_sandwich.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_plot_sandwich.py: + + +Sandwich demo +============= + +Sandwich demo based on code from http://nbviewer.ipython.org/6576096 + +.. GENERATED FROM PYTHON SOURCE LINES 10-15 + +.. note:: + + In order to show the charts of the examples you need a graphical + ``matplotlib`` backend installed. For intance, use ``pip install pyqt5`` + to get Qt graphical interface or use your favorite one. + +.. GENERATED FROM PYTHON SOURCE LINES 15-106 + +.. code-block:: default + + + import numpy as np + from matplotlib import pyplot as plt + from sklearn.metrics import pairwise_distances + from sklearn.neighbors import NearestNeighbors + + from metric_learn import (LMNN, ITML_Supervised, LSML_Supervised, + SDML_Supervised) + + + def sandwich_demo(): + x, y = sandwich_data() + knn = nearest_neighbors(x, k=2) + ax = plt.subplot(3, 1, 1) # take the whole top row + plot_sandwich_data(x, y, ax) + plot_neighborhood_graph(x, knn, y, ax) + ax.set_title('input space') + ax.set_aspect('equal') + ax.set_xticks([]) + ax.set_yticks([]) + + mls = [ + LMNN(), + ITML_Supervised(n_constraints=200), + SDML_Supervised(n_constraints=200, balance_param=0.001), + LSML_Supervised(n_constraints=200), + ] + + for ax_num, ml in enumerate(mls, start=3): + ml.fit(x, y) + tx = ml.transform(x) + ml_knn = nearest_neighbors(tx, k=2) + ax = plt.subplot(3, 2, ax_num) + plot_sandwich_data(tx, y, axis=ax) + plot_neighborhood_graph(tx, ml_knn, y, axis=ax) + ax.set_title(ml.__class__.__name__) + ax.set_xticks([]) + ax.set_yticks([]) + plt.show() + + + # TODO: use this somewhere + def visualize_class_separation(X, labels): + _, (ax1, ax2) = plt.subplots(ncols=2) + label_order = np.argsort(labels) + ax1.imshow(pairwise_distances(X[label_order]), interpolation='nearest') + ax2.imshow(pairwise_distances(labels[label_order, None]), + interpolation='nearest') + + + def nearest_neighbors(X, k=5): + knn = NearestNeighbors(n_neighbors=k) + knn.fit(X) + return knn.kneighbors(X, return_distance=False) + + + def sandwich_data(): + # number of distinct classes + num_classes = 6 + # number of points per class + num_points = 9 + # distance between layers, the points of each class are in a layer + dist = 0.7 + + data = np.zeros((num_classes, num_points, 2), dtype=float) + labels = np.zeros((num_classes, num_points), dtype=int) + + x_centers = np.arange(num_points, dtype=float) - num_points / 2 + y_centers = dist * (np.arange(num_classes, dtype=float) - num_classes / 2) + for i, yc in enumerate(y_centers): + for k, xc in enumerate(x_centers): + data[i, k, 0] = np.random.normal(xc, 0.1) + data[i, k, 1] = np.random.normal(yc, 0.1) + labels[i, :] = i + return data.reshape((-1, 2)), labels.ravel() + + + def plot_sandwich_data(x, y, axis=plt, colors='rbgmky'): + for idx, val in enumerate(np.unique(y)): + xi = x[y == val] + axis.scatter(*xi.T, s=50, facecolors='none', edgecolors=colors[idx]) + + + def plot_neighborhood_graph(x, nn, y, axis=plt, colors='rbgmky'): + for i, a in enumerate(x): + b = x[nn[i, 1]] + axis.plot((a[0], b[0]), (a[1], b[1]), colors[y[i]]) + + + if __name__ == '__main__': + sandwich_demo() + + + +.. image-sg:: /auto_examples/images/sphx_glr_plot_sandwich_001.png + :alt: input space, LMNN, ITML_Supervised, SDML_Supervised, LSML_Supervised + :srcset: /auto_examples/images/sphx_glr_plot_sandwich_001.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + /Users/william.vezelhes/metric-learn/metric_learn/constraints.py:224: UserWarning: Only generated 199 positive constraints (requested 200) + warnings.warn("Only generated %d %s constraints (requested %d)" % ( + /Users/william.vezelhes/miniconda3/envs/docenvbis/lib/python3.11/site-packages/sklearn/covariance/_graph_lasso.py:329: FutureWarning: The cov_init parameter is deprecated in 1.3 and will be removed in 1.5. It does not have any effect. + warnings.warn( + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 3.314 seconds) + + +.. _sphx_glr_download_auto_examples_plot_sandwich.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + + + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: plot_sandwich.py ` + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: plot_sandwich.ipynb ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/_sources/auto_examples/sg_execution_times.rst.txt b/_sources/auto_examples/sg_execution_times.rst.txt new file mode 100644 index 00000000..274c9981 --- /dev/null +++ b/_sources/auto_examples/sg_execution_times.rst.txt @@ -0,0 +1,15 @@ + +:orphan: + +.. _sphx_glr_auto_examples_sg_execution_times: + + +Computation times +================= +**00:35.715** total execution time for **auto_examples** files: + ++-------------------------------------------------------------------------------------------------------+-----------+--------+ +| :ref:`sphx_glr_auto_examples_plot_metric_learning_examples.py` (``plot_metric_learning_examples.py``) | 00:32.400 | 0.0 MB | ++-------------------------------------------------------------------------------------------------------+-----------+--------+ +| :ref:`sphx_glr_auto_examples_plot_sandwich.py` (``plot_sandwich.py``) | 00:03.314 | 0.0 MB | ++-------------------------------------------------------------------------------------------------------+-----------+--------+ diff --git a/_sources/generated/metric_learn.Constraints.rst.txt b/_sources/generated/metric_learn.Constraints.rst.txt new file mode 100644 index 00000000..2d6a743d --- /dev/null +++ b/_sources/generated/metric_learn.Constraints.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.Constraints +====================================== + +.. currentmodule:: metric_learn + +.. autoclass:: Constraints + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.Constraints.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.Covariance.rst.txt b/_sources/generated/metric_learn.Covariance.rst.txt new file mode 100644 index 00000000..3fa789ea --- /dev/null +++ b/_sources/generated/metric_learn.Covariance.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.Covariance +===================================== + +.. currentmodule:: metric_learn + +.. autoclass:: Covariance + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.Covariance.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.ITML.rst.txt b/_sources/generated/metric_learn.ITML.rst.txt new file mode 100644 index 00000000..68c9b7b5 --- /dev/null +++ b/_sources/generated/metric_learn.ITML.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.ITML +=============================== + +.. currentmodule:: metric_learn + +.. autoclass:: ITML + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.ITML.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.ITML_Supervised.rst.txt b/_sources/generated/metric_learn.ITML_Supervised.rst.txt new file mode 100644 index 00000000..5ca79a9f --- /dev/null +++ b/_sources/generated/metric_learn.ITML_Supervised.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.ITML_Supervised +========================================== + +.. currentmodule:: metric_learn + +.. autoclass:: ITML_Supervised + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.ITML_Supervised.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.LFDA.rst.txt b/_sources/generated/metric_learn.LFDA.rst.txt new file mode 100644 index 00000000..caa2ef2a --- /dev/null +++ b/_sources/generated/metric_learn.LFDA.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.LFDA +=============================== + +.. currentmodule:: metric_learn + +.. autoclass:: LFDA + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.LFDA.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.LMNN.rst.txt b/_sources/generated/metric_learn.LMNN.rst.txt new file mode 100644 index 00000000..9fd2a928 --- /dev/null +++ b/_sources/generated/metric_learn.LMNN.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.LMNN +=============================== + +.. currentmodule:: metric_learn + +.. autoclass:: LMNN + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.LMNN.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.LSML.rst.txt b/_sources/generated/metric_learn.LSML.rst.txt new file mode 100644 index 00000000..e67e7cf9 --- /dev/null +++ b/_sources/generated/metric_learn.LSML.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.LSML +=============================== + +.. currentmodule:: metric_learn + +.. autoclass:: LSML + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.LSML.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.LSML_Supervised.rst.txt b/_sources/generated/metric_learn.LSML_Supervised.rst.txt new file mode 100644 index 00000000..49309714 --- /dev/null +++ b/_sources/generated/metric_learn.LSML_Supervised.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.LSML_Supervised +========================================== + +.. currentmodule:: metric_learn + +.. autoclass:: LSML_Supervised + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.LSML_Supervised.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.MLKR.rst.txt b/_sources/generated/metric_learn.MLKR.rst.txt new file mode 100644 index 00000000..505e17f2 --- /dev/null +++ b/_sources/generated/metric_learn.MLKR.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.MLKR +=============================== + +.. currentmodule:: metric_learn + +.. autoclass:: MLKR + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.MLKR.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.MMC.rst.txt b/_sources/generated/metric_learn.MMC.rst.txt new file mode 100644 index 00000000..ec9751f4 --- /dev/null +++ b/_sources/generated/metric_learn.MMC.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.MMC +============================== + +.. currentmodule:: metric_learn + +.. autoclass:: MMC + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.MMC.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.MMC_Supervised.rst.txt b/_sources/generated/metric_learn.MMC_Supervised.rst.txt new file mode 100644 index 00000000..c1b3f43a --- /dev/null +++ b/_sources/generated/metric_learn.MMC_Supervised.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.MMC_Supervised +========================================= + +.. currentmodule:: metric_learn + +.. autoclass:: MMC_Supervised + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.MMC_Supervised.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.NCA.rst.txt b/_sources/generated/metric_learn.NCA.rst.txt new file mode 100644 index 00000000..f4e4eb75 --- /dev/null +++ b/_sources/generated/metric_learn.NCA.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.NCA +============================== + +.. currentmodule:: metric_learn + +.. autoclass:: NCA + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.NCA.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.RCA.rst.txt b/_sources/generated/metric_learn.RCA.rst.txt new file mode 100644 index 00000000..29469b3f --- /dev/null +++ b/_sources/generated/metric_learn.RCA.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.RCA +============================== + +.. currentmodule:: metric_learn + +.. autoclass:: RCA + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.RCA.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.RCA_Supervised.rst.txt b/_sources/generated/metric_learn.RCA_Supervised.rst.txt new file mode 100644 index 00000000..318beb6f --- /dev/null +++ b/_sources/generated/metric_learn.RCA_Supervised.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.RCA_Supervised +========================================= + +.. currentmodule:: metric_learn + +.. autoclass:: RCA_Supervised + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.RCA_Supervised.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.SCML.rst.txt b/_sources/generated/metric_learn.SCML.rst.txt new file mode 100644 index 00000000..d850564f --- /dev/null +++ b/_sources/generated/metric_learn.SCML.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.SCML +=============================== + +.. currentmodule:: metric_learn + +.. autoclass:: SCML + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.SCML.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.SCML_Supervised.rst.txt b/_sources/generated/metric_learn.SCML_Supervised.rst.txt new file mode 100644 index 00000000..1e3d3672 --- /dev/null +++ b/_sources/generated/metric_learn.SCML_Supervised.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.SCML_Supervised +========================================== + +.. currentmodule:: metric_learn + +.. autoclass:: SCML_Supervised + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.SCML_Supervised.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.SDML.rst.txt b/_sources/generated/metric_learn.SDML.rst.txt new file mode 100644 index 00000000..728b03fa --- /dev/null +++ b/_sources/generated/metric_learn.SDML.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.SDML +=============================== + +.. currentmodule:: metric_learn + +.. autoclass:: SDML + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.SDML.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.SDML_Supervised.rst.txt b/_sources/generated/metric_learn.SDML_Supervised.rst.txt new file mode 100644 index 00000000..ba72bd29 --- /dev/null +++ b/_sources/generated/metric_learn.SDML_Supervised.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn`.SDML_Supervised +========================================== + +.. currentmodule:: metric_learn + +.. autoclass:: SDML_Supervised + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.SDML_Supervised.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.base_metric.BaseMetricLearner.rst.txt b/_sources/generated/metric_learn.base_metric.BaseMetricLearner.rst.txt new file mode 100644 index 00000000..67cbaff9 --- /dev/null +++ b/_sources/generated/metric_learn.base_metric.BaseMetricLearner.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn.base_metric`.BaseMetricLearner +======================================================== + +.. currentmodule:: metric_learn.base_metric + +.. autoclass:: BaseMetricLearner + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.base_metric.BaseMetricLearner.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.base_metric.MahalanobisMixin.rst.txt b/_sources/generated/metric_learn.base_metric.MahalanobisMixin.rst.txt new file mode 100644 index 00000000..eb3ce343 --- /dev/null +++ b/_sources/generated/metric_learn.base_metric.MahalanobisMixin.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn.base_metric`.MahalanobisMixin +======================================================= + +.. currentmodule:: metric_learn.base_metric + +.. autoclass:: MahalanobisMixin + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.base_metric.MahalanobisMixin.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.base_metric.MetricTransformer.rst.txt b/_sources/generated/metric_learn.base_metric.MetricTransformer.rst.txt new file mode 100644 index 00000000..32f8abae --- /dev/null +++ b/_sources/generated/metric_learn.base_metric.MetricTransformer.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn.base_metric`.MetricTransformer +======================================================== + +.. currentmodule:: metric_learn.base_metric + +.. autoclass:: MetricTransformer + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.base_metric.MetricTransformer.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.base_metric._PairsClassifierMixin.rst.txt b/_sources/generated/metric_learn.base_metric._PairsClassifierMixin.rst.txt new file mode 100644 index 00000000..719a2937 --- /dev/null +++ b/_sources/generated/metric_learn.base_metric._PairsClassifierMixin.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn.base_metric`._PairsClassifierMixin +============================================================ + +.. currentmodule:: metric_learn.base_metric + +.. autoclass:: _PairsClassifierMixin + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.base_metric._PairsClassifierMixin.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.base_metric._QuadrupletsClassifierMixin.rst.txt b/_sources/generated/metric_learn.base_metric._QuadrupletsClassifierMixin.rst.txt new file mode 100644 index 00000000..651d762d --- /dev/null +++ b/_sources/generated/metric_learn.base_metric._QuadrupletsClassifierMixin.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn.base_metric`._QuadrupletsClassifierMixin +================================================================== + +.. currentmodule:: metric_learn.base_metric + +.. autoclass:: _QuadrupletsClassifierMixin + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.base_metric._QuadrupletsClassifierMixin.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/generated/metric_learn.base_metric._TripletsClassifierMixin.rst.txt b/_sources/generated/metric_learn.base_metric._TripletsClassifierMixin.rst.txt new file mode 100644 index 00000000..288edcd2 --- /dev/null +++ b/_sources/generated/metric_learn.base_metric._TripletsClassifierMixin.rst.txt @@ -0,0 +1,16 @@ +:mod:`metric_learn.base_metric`._TripletsClassifierMixin +=============================================================== + +.. currentmodule:: metric_learn.base_metric + +.. autoclass:: _TripletsClassifierMixin + :members: + :undoc-members: + :inherited-members: + :special-members: __init__ + +.. include:: metric_learn.base_metric._TripletsClassifierMixin.examples + +.. raw:: html + +
\ No newline at end of file diff --git a/_sources/getting_started.rst.txt b/_sources/getting_started.rst.txt new file mode 100644 index 00000000..90b7c7ee --- /dev/null +++ b/_sources/getting_started.rst.txt @@ -0,0 +1,47 @@ +############### +Getting started +############### + +Installation and Setup +====================== + +**Installation** + +metric-learn can be installed in either of the following ways: + +- If you use Anaconda: ``conda install -c conda-forge metric-learn``. See more options `here `_. + +- To install from PyPI: ``pip install metric-learn``. + +- For a manual install of the latest code, download the source repository and run ``python setup.py install``. You may then run ``pytest test`` to run all tests (you will need to have the ``pytest`` package installed). + +**Dependencies** + +- Python 3.6+ (the last version supporting Python 2 and Python 3.5 was + `v0.5.0 `_) +- numpy>= 1.11.0, scipy>= 0.17.0, scikit-learn>=0.21.3 + +**Optional dependencies** + +- For SDML, using skggm will allow the algorithm to solve problematic cases + (install from commit `a0ed406 `_). + ``pip install 'git+https://github.com/skggm/skggm.git@a0ed406586c4364ea3297a658f415e13b5cbdaf8'`` to install the required version of skggm from GitHub. +- For running the examples only: matplotlib + +Quick start +=========== + +This example loads the iris dataset, and evaluates a k-nearest neighbors +algorithm on an embedding space learned with `NCA`. + +:: + + from metric_learn import NCA + from sklearn.datasets import load_iris + from sklearn.model_selection import cross_val_score + from sklearn.pipeline import make_pipeline + from sklearn.neighbors import KNeighborsClassifier + + X, y = load_iris(return_X_y=True) + clf = make_pipeline(NCA(), KNeighborsClassifier()) + cross_val_score(clf, X, y) diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 00000000..f9dfd83d --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,67 @@ +metric-learn: Metric Learning in Python +======================================= +|GitHub Actions Build Status| |License| |PyPI version| |Code coverage| + +`metric-learn `_ +contains efficient Python implementations of several popular supervised and +weakly-supervised metric learning algorithms. As part of `scikit-learn-contrib +`_, the API of metric-learn is compatible with `scikit-learn +`_, the leading library for machine learning in +Python. This allows to use all the scikit-learn routines (for pipelining, +model selection, etc) with metric learning algorithms through a unified +interface. + +If you use metric-learn in a scientific publication, we would appreciate +citations to the following paper: + +`metric-learn: Metric Learning Algorithms in Python +`_, de Vazelhes +*et al.*, Journal of Machine Learning Research, 21(138):1-6, 2020. + +Bibtex entry:: + + @article{metric-learn, + title = {metric-learn: {M}etric {L}earning {A}lgorithms in {P}ython}, + author = {{de Vazelhes}, William and {Carey}, CJ and {Tang}, Yuan and + {Vauquier}, Nathalie and {Bellet}, Aur{\'e}lien}, + journal = {Journal of Machine Learning Research}, + year = {2020}, + volume = {21}, + number = {138}, + pages = {1--6} + } + + +Documentation outline +--------------------- + +.. toctree:: + :maxdepth: 2 + + getting_started + +.. toctree:: + :maxdepth: 2 + + user_guide + +.. toctree:: + :maxdepth: 2 + + Package Contents + +.. toctree:: + :maxdepth: 2 + + auto_examples/index + +:ref:`genindex` | :ref:`search` + +.. |GitHub Actions Build Status| image:: https://github.com/scikit-learn-contrib/metric-learn/workflows/CI/badge.svg + :target: https://github.com/scikit-learn-contrib/metric-learn/actions?query=event%3Apush+branch%3Amaster +.. |PyPI version| image:: https://badge.fury.io/py/metric-learn.svg + :target: http://badge.fury.io/py/metric-learn +.. |License| image:: http://img.shields.io/:license-mit-blue.svg?style=flat + :target: http://badges.mit-license.org +.. |Code coverage| image:: https://codecov.io/gh/scikit-learn-contrib/metric-learn/branch/master/graph/badge.svg + :target: https://codecov.io/gh/scikit-learn-contrib/metric-learn diff --git a/_sources/introduction.rst.txt b/_sources/introduction.rst.txt new file mode 100644 index 00000000..e9ff0015 --- /dev/null +++ b/_sources/introduction.rst.txt @@ -0,0 +1,125 @@ +.. _intro_metric_learning: + +======================== +What is Metric Learning? +======================== + +Many approaches in machine learning require a measure of distance between data +points. Traditionally, practitioners would choose a standard distance metric +(Euclidean, City-Block, Cosine, etc.) using a priori knowledge of the +domain. However, it is often difficult to design metrics that are well-suited +to the particular data and task of interest. + +Distance metric learning (or simply, metric learning) aims at +automatically constructing task-specific distance metrics from (weakly) +supervised data, in a machine learning manner. The learned distance metric can +then be used to perform various tasks (e.g., k-NN classification, clustering, +information retrieval). + +Problem Setting +=============== + +Metric learning problems fall into two main categories depending on the type +of supervision available about the training data: + +- :doc:`Supervised learning `: the algorithm has access to + a set of data points, each of them belonging to a class (label) as in a + standard classification problem. + Broadly speaking, the goal in this setting is to learn a distance metric + that puts points with the same label close together while pushing away + points with different labels. +- :doc:`Weakly supervised learning `: the + algorithm has access to a set of data points with supervision only + at the tuple level (typically pairs, triplets, or quadruplets of + data points). A classic example of such weaker supervision is a set of + positive and negative pairs: in this case, the goal is to learn a distance + metric that puts positive pairs close together and negative pairs far away. + +Based on the above (weakly) supervised data, the metric learning problem is +generally formulated as an optimization problem where one seeks to find the +parameters of a distance function that optimize some objective function +measuring the agreement with the training data. + +.. _mahalanobis_distances: + +Mahalanobis Distances +===================== + +In the metric-learn package, all algorithms currently implemented learn +so-called Mahalanobis distances. Given a real-valued parameter matrix +:math:`L` of shape ``(num_dims, n_features)`` where ``n_features`` is the +number features describing the data, the Mahalanobis distance associated with +:math:`L` is defined as follows: + +.. math:: D(x, x') = \sqrt{(Lx-Lx')^\top(Lx-Lx')} + +In other words, a Mahalanobis distance is a Euclidean distance after a +linear transformation of the feature space defined by :math:`L` (taking +:math:`L` to be the identity matrix recovers the standard Euclidean distance). +Mahalanobis distance metric learning can thus be seen as learning a new +embedding space of dimension ``num_dims``. Note that when ``num_dims`` is +smaller than ``n_features``, this achieves dimensionality reduction. + +Strictly speaking, Mahalanobis distances are "pseudo-metrics": they satisfy +three of the `properties of a metric `_ (non-negativity, symmetry, triangle inequality) but not +necessarily the identity of indiscernibles. + +.. note:: + + Mahalanobis distances can also be parameterized by a `positive semi-definite + (PSD) matrix + `_ + :math:`M`: + + .. math:: D(x, x') = \sqrt{(x-x')^\top M(x-x')} + + Using the fact that a PSD matrix :math:`M` can always be decomposed as + :math:`M=L^\top L` for some :math:`L`, one can show that both + parameterizations are equivalent. In practice, an algorithm may thus solve + the metric learning problem with respect to either :math:`M` or :math:`L`. + +.. _use_cases: + +Use-cases +========= + +There are many use-cases for metric learning. We list here a few popular +examples (for code illustrating some of these use-cases, see the +:doc:`examples ` section of the documentation): + +- `Nearest neighbors models + `_: the learned + metric can be used to improve nearest neighbors learning models for + classification, regression, anomaly detection... +- `Clustering `_: + metric learning provides a way to bias the clusters found by algorithms like + K-Means towards the intended semantics. +- Information retrieval: the learned metric can be used to retrieve the + elements of a database that are semantically closest to a query element. +- Dimensionality reduction: metric learning may be seen as a way to reduce the + data dimension in a (weakly) supervised setting. +- More generally, the learned transformation :math:`L` can be used to project + the data into a new embedding space before feeding it into another machine + learning algorithm. + +The API of metric-learn is compatible with `scikit-learn +`_, the leading library for machine +learning in Python. This allows to easily pipeline metric learners with other +scikit-learn estimators to realize the above use-cases, to perform joint +hyperparameter tuning, etc. + +Further reading +=============== + +For more information about metric learning and its applications, one can refer +to the following resources: + +- **Tutorial:** `Similarity and Distance Metric Learning with Applications to + Computer Vision + `_ (2015) +- **Surveys:** `A Survey on Metric Learning for Feature Vectors and Structured + Data `_ (2013), `Metric Learning: A + Survey `_ (2012) +- **Book:** `Metric Learning + `_ (2015) diff --git a/_sources/metric_learn.rst.txt b/_sources/metric_learn.rst.txt new file mode 100644 index 00000000..4d0676b9 --- /dev/null +++ b/_sources/metric_learn.rst.txt @@ -0,0 +1,60 @@ +metric_learn package +==================== + +Module Contents +--------------- + +Base Classes +------------ + +.. autosummary:: + :toctree: generated/ + :template: class.rst + + metric_learn.Constraints + metric_learn.base_metric.BaseMetricLearner + metric_learn.base_metric.MetricTransformer + metric_learn.base_metric.MahalanobisMixin + metric_learn.base_metric._PairsClassifierMixin + metric_learn.base_metric._TripletsClassifierMixin + metric_learn.base_metric._QuadrupletsClassifierMixin + +Supervised Learning Algorithms +------------------------------ +.. autosummary:: + :toctree: generated/ + :template: class.rst + + metric_learn.LFDA + metric_learn.LMNN + metric_learn.MLKR + metric_learn.NCA + metric_learn.RCA + metric_learn.ITML_Supervised + metric_learn.LSML_Supervised + metric_learn.MMC_Supervised + metric_learn.SDML_Supervised + metric_learn.RCA_Supervised + metric_learn.SCML_Supervised + +Weakly Supervised Learning Algorithms +------------------------------------- + +.. autosummary:: + :toctree: generated/ + :template: class.rst + + metric_learn.ITML + metric_learn.LSML + metric_learn.MMC + metric_learn.SDML + metric_learn.SCML + +Unsupervised Learning Algorithms +-------------------------------- + +.. autosummary:: + :toctree: generated/ + :template: class.rst + + metric_learn.Covariance \ No newline at end of file diff --git a/_sources/preprocessor.rst.txt b/_sources/preprocessor.rst.txt new file mode 100644 index 00000000..ad1ffd8f --- /dev/null +++ b/_sources/preprocessor.rst.txt @@ -0,0 +1,111 @@ +.. _preprocessor_section: + +============ +Preprocessor +============ + +Estimators in metric-learn all have a ``preprocessor`` option at instantiation. +Filling this argument allows them to take more compact input representation +when fitting, predicting etc... + +If ``preprocessor=None``, no preprocessor will be used and the user must +provide the classical representation to the fit/predict/score/etc... methods of +the estimators (see the documentation of the particular estimator to know the +type of input it accepts). Otherwise, two types of objects can be put in this +argument: + +Array-like +---------- +You can specify ``preprocessor=X`` where ``X`` is an array-like containing the +dataset of points. In this case, the fit/predict/score/etc... methods of the +estimator will be able to take as inputs an array-like of indices, replacing +under the hood each index by the corresponding sample. + + +Example with a supervised metric learner: + +>>> from metric_learn import NCA +>>> +>>> X = np.array([[-0.7 , -0.23], +>>> [-0.43, -0.49], +>>> [ 0.14, -0.37]]) # array of 3 samples of 2 features +>>> points_indices = np.array([2, 0, 1, 0]) +>>> y = np.array([1, 0, 1, 1]) +>>> +>>> nca = NCA(preprocessor=X) +>>> nca.fit(points_indices, y) +>>> # under the hood the algorithm will create +>>> # points = np.array([[ 0.14, -0.37], +>>> # [-0.7 , -0.23], +>>> # [-0.43, -0.49], +>>> # [ 0.14, -0.37]]) and fit on it + + +Example with a weakly supervised metric learner: + +>>> from metric_learn import MMC +>>> X = np.array([[-0.7 , -0.23], +>>> [-0.43, -0.49], +>>> [ 0.14, -0.37]]) # array of 3 samples of 2 features +>>> pairs_indices = np.array([[2, 0], [1, 0]]) +>>> y_pairs = np.array([1, -1]) +>>> +>>> mmc = MMC(preprocessor=X) +>>> mmc.fit(pairs_indices, y_pairs) +>>> # under the hood the algorithm will create +>>> # pairs = np.array([[[ 0.14, -0.37], [-0.7 , -0.23]], +>>> # [[-0.43, -0.49], [-0.7 , -0.23]]]) and fit on it + +Callable +-------- +Alternatively, you can provide a callable as ``preprocessor``. Then the +estimator will accept indicators of points instead of points. Under the hood, +the estimator will call this callable on the indicators you provide as input +when fitting, predicting etc... Using a callable can be really useful to +represent lazily a dataset of images stored on the file system for instance. +The callable should take as an input a 1D array-like, and return a 2D +array-like. For supervised learners it will be applied on the whole 1D array of +indicators at once, and for weakly supervised learners it will be applied on +each column of the 2D array of tuples. + +Example with a supervised metric learner: + +>>> def find_images(file_paths): +>>> # each file contains a small image to use as an input datapoint +>>> return np.row_stack([imread(f).ravel() for f in file_paths]) +>>> +>>> nca = NCA(preprocessor=find_images) +>>> nca.fit(['img01.png', 'img00.png', 'img02.png'], [1, 0, 1]) +>>> # under the hood preprocessor(indicators) will be called + + +Example with a weakly supervised metric learner: + +>>> pairs_images_paths = [['img02.png', 'img00.png'], +>>> ['img01.png', 'img00.png']] +>>> y_pairs = np.array([1, -1]) +>>> +>>> mmc = NCA(preprocessor=find_images) +>>> mmc.fit(pairs_images_paths, y_pairs) +>>> # under the hood preprocessor(pairs_indicators[i]) will be called for each +>>> # i in [0, 1] + + +.. note:: Note that when you fill the ``preprocessor`` option, it allows you + to give more compact inputs, but the classical way of providing inputs + stays valid (2D array-like for supervised learners and 3D array-like of + tuples for weakly supervised learners). If a classical input + is provided, the metric learner will not use the preprocessor. + + Example: This will work: + + >>> from metric_learn import MMC + >>> def preprocessor_wip(array): + >>> raise NotImplementedError("This preprocessor does nothing yet.") + >>> + >>> pairs = np.array([[[ 0.14, -0.37], [-0.7 , -0.23]], + >>> [[-0.43, -0.49], [-0.7 , -0.23]]]) + >>> y_pairs = np.array([1, -1]) + >>> + >>> mmc = MMC(preprocessor=preprocessor_wip) + >>> mmc.fit(pairs, y_pairs) # preprocessor_wip will not be called here diff --git a/_sources/supervised.rst.txt b/_sources/supervised.rst.txt new file mode 100644 index 00000000..a847a33c --- /dev/null +++ b/_sources/supervised.rst.txt @@ -0,0 +1,434 @@ +========================== +Supervised Metric Learning +========================== + +Supervised metric learning algorithms take as inputs points `X` and target +labels `y`, and learn a distance matrix that make points from the same class +(for classification) or with close target value (for regression) close to each +other, and points from different classes or with distant target values far away +from each other. + +General API +=========== + +Supervised metric learning algorithms essentially use the same API as +scikit-learn. + +Input data +---------- +In order to train a model, you need two `array-like `_ objects, `X` and `y`. `X` +should be a 2D array-like of shape `(n_samples, n_features)`, where +`n_samples` is the number of points of your dataset and `n_features` is the +number of attributes describing each point. `y` should be a 1D +array-like +of shape `(n_samples,)`, containing for each point in `X` the class it +belongs to (or the value to regress for this sample, if you use `MLKR` for +instance). + +Here is an example of a dataset of two dogs and one +cat (the classes are 'dog' and 'cat') an animal being represented by +two numbers. + +>>> import numpy as np +>>> X = np.array([[2.3, 3.6], [0.2, 0.5], [6.7, 2.1]]) +>>> y = np.array(['dog', 'cat', 'dog']) + +.. note:: + + You can also use a preprocessor instead of directly giving the inputs as + 2D arrays. See the :ref:`preprocessor_section` section for more details. + +Fit, transform, and so on +------------------------- +The goal of supervised metric-learning algorithms is to transform +points in a new space, in which the distance between two points from the +same class will be small, and the distance between two points from different +classes will be large. To do so, we fit the metric learner (example: +`NCA`). + +>>> from metric_learn import NCA +>>> nca = NCA(random_state=42) +>>> nca.fit(X, y) +NCA(init='auto', max_iter=100, n_components=None, + preprocessor=None, random_state=42, tol=None, verbose=False) + + +Now that the estimator is fitted, you can use it on new data for several +purposes. + +First, you can transform the data in the learned space, using `transform`: +Here we transform two points in the new embedding space. + +>>> X_new = np.array([[9.4, 4.1], [2.1, 4.4]]) +>>> nca.transform(X_new) +array([[ 5.91884732, 10.25406973], + [ 3.1545886 , 6.80350083]]) + +Also, as explained before, our metric learners has learn a distance between +points. You can use this distance in two main ways: + +- You can either return the distance between pairs of points using the + `pair_distance` function: + +>>> nca.pair_distance([[[3.5, 3.6], [5.6, 2.4]], [[1.2, 4.2], [2.1, 6.4]], [[3.3, 7.8], [10.9, 0.1]]]) +array([0.49627072, 3.65287282, 6.06079877]) + +- Or you can return a function that will return the distance (in the new + space) between two 1D arrays (the coordinates of the points in the original + space), similarly to distance functions in `scipy.spatial.distance`. + +>>> metric_fun = nca.get_metric() +>>> metric_fun([3.5, 3.6], [5.6, 2.4]) +0.4962707194621285 + +- Alternatively, you can use `pair_score` to return the **score** between + pairs of points (the larger the score, the more similar the pair). + For Mahalanobis learners, it is equal to the opposite of the distance. + +>>> score = nca.pair_score([[[3.5, 3.6], [5.6, 2.4]], [[1.2, 4.2], [2.1, 6.4]], [[3.3, 7.8], [10.9, 0.1]]]) +>>> score +array([-0.49627072, -3.65287282, -6.06079877]) + +This is useful because `pair_score` matches the **score** semantic of +scikit-learn's `Classification metrics +`_. + +.. note:: + + If the metric learner that you use learns a :ref:`Mahalanobis distance + ` (like it is the case for all algorithms + currently in metric-learn), you can get the plain learned Mahalanobis + matrix using `get_mahalanobis_matrix`. + + >>> nca.get_mahalanobis_matrix() + array([[0.43680409, 0.89169412], + [0.89169412, 1.9542479 ]]) + + +Scikit-learn compatibility +-------------------------- + +All supervised algorithms are scikit-learn estimators +(`sklearn.base.BaseEstimator`) and transformers +(`sklearn.base.TransformerMixin`) so they are compatible with pipelines +(`sklearn.pipeline.Pipeline`) and +scikit-learn model selection routines +(`sklearn.model_selection.cross_val_score`, +`sklearn.model_selection.GridSearchCV`, etc). +You can also use some of the scoring functions from `sklearn.metrics`. + +Algorithms +========== + +.. _lmnn: + +:py:class:`LMNN ` +----------------------------------------- + +Large Margin Nearest Neighbor Metric Learning +(:py:class:`LMNN `) + +`LMNN` learns a Mahalanobis distance metric in the kNN classification +setting. The learned metric attempts to keep close k-nearest neighbors +from the same class, while keeping examples from different classes +separated by a large margin. This algorithm makes no assumptions about +the distribution of the data. + +The distance is learned by solving the following optimization problem: + +.. math:: + + \min_\mathbf{L}\sum_{i, j}\eta_{ij}||\mathbf{L(x_i-x_j)}||^2 + + c\sum_{i, j, l}\eta_{ij}(1-y_{ij})[1+||\mathbf{L(x_i-x_j)}||^2-|| + \mathbf{L(x_i-x_l)}||^2]_+) + +where :math:`\mathbf{x}_i` is a data point, :math:`\mathbf{x}_j` is one +of its k-nearest neighbors sharing the same label, and :math:`\mathbf{x}_l` +are all the other instances within that region with different labels, +:math:`\eta_{ij}, y_{ij} \in \{0, 1\}` are both the indicators, +:math:`\eta_{ij}` represents :math:`\mathbf{x}_{j}` is the k-nearest +neighbors (with same labels) of :math:`\mathbf{x}_{i}`, :math:`y_{ij}=0` +indicates :math:`\mathbf{x}_{i}, \mathbf{x}_{j}` belong to different classes, +:math:`[\cdot]_+=\max(0, \cdot)` is the Hinge loss. + +.. rubric:: Example Code + +:: + + import numpy as np + from metric_learn import LMNN + from sklearn.datasets import load_iris + + iris_data = load_iris() + X = iris_data['data'] + Y = iris_data['target'] + + lmnn = LMNN(n_neighbors=5, learn_rate=1e-6) + lmnn.fit(X, Y, verbose=False) + +.. rubric:: References + + +.. container:: hatnote hatnote-gray + + [1]. Weinberger et al. `Distance Metric Learning for Large Margin Nearest Neighbor Classification `_. JMLR 2009. + + [2]. `Wikipedia entry on Large Margin Nearest Neighbor `_. + + +.. _nca: + +:py:class:`NCA ` +-------------------------------------- + +Neighborhood Components Analysis (:py:class:`NCA `) + +`NCA` is a distance metric learning algorithm which aims to improve the +accuracy of nearest neighbors classification compared to the standard +Euclidean distance. The algorithm directly maximizes a stochastic variant +of the leave-one-out k-nearest neighbors (KNN) score on the training set. +It can also learn a low-dimensional linear transformation of data that can +be used for data visualization and fast classification. + +They use the decomposition :math:`\mathbf{M} = \mathbf{L}^T\mathbf{L}` and +define the probability :math:`p_{ij}` that :math:`\mathbf{x}_i` is the +neighbor of :math:`\mathbf{x}_j` by calculating the softmax likelihood of +the Mahalanobis distance: + +.. math:: + + p_{ij} = \frac{\exp(-|| \mathbf{Lx}_i - \mathbf{Lx}_j ||_2^2)} + {\sum_{l\neq i}\exp(-||\mathbf{Lx}_i - \mathbf{Lx}_l||_2^2)}, + \qquad p_{ii}=0 + +Then the probability that :math:`\mathbf{x}_i` will be correctly classified +by the stochastic nearest neighbors rule is: + +.. math:: + + p_{i} = \sum_{j:j\neq i, y_j=y_i}p_{ij} + +The optimization problem is to find matrix :math:`\mathbf{L}` that maximizes +the sum of probability of being correctly classified: + +.. math:: + + \mathbf{L} = \text{argmax}\sum_i p_i + +.. rubric:: Example Code + +:: + + import numpy as np + from metric_learn import NCA + from sklearn.datasets import load_iris + + iris_data = load_iris() + X = iris_data['data'] + Y = iris_data['target'] + + nca = NCA(max_iter=1000) + nca.fit(X, Y) + +.. rubric:: References + + +.. container:: hatnote hatnote-gray + + [1]. Goldberger et al. `Neighbourhood Components Analysis `_. NIPS 2005. + + [2]. `Wikipedia entry on Neighborhood Components Analysis `_. + + +.. _lfda: + +:py:class:`LFDA ` +----------------------------------------- + +Local Fisher Discriminant Analysis (:py:class:`LFDA `) + +`LFDA` is a linear supervised dimensionality reduction method which effectively combines the ideas of `Linear Discriminant Analysis ` and Locality-Preserving Projection . It is +particularly useful when dealing with multi-modality, where one ore more classes +consist of separate clusters in input space. The core optimization problem of +LFDA is solved as a generalized eigenvalue problem. + + +The algorithm define the Fisher local within-/between-class scatter matrix +:math:`\mathbf{S}^{(w)}/ \mathbf{S}^{(b)}` in a pairwise fashion: + +.. math:: + + \mathbf{S}^{(w)} = \frac{1}{2}\sum_{i,j=1}^nW_{ij}^{(w)}(\mathbf{x}_i - + \mathbf{x}_j)(\mathbf{x}_i - \mathbf{x}_j)^T,\\ + \mathbf{S}^{(b)} = \frac{1}{2}\sum_{i,j=1}^nW_{ij}^{(b)}(\mathbf{x}_i - + \mathbf{x}_j)(\mathbf{x}_i - \mathbf{x}_j)^T,\\ + +where + +.. math:: + + W_{ij}^{(w)} = \left\{\begin{aligned}0 \qquad y_i\neq y_j \\ + \,\,\mathbf{A}_{i,j}/n_l \qquad y_i = y_j\end{aligned}\right.\\ + W_{ij}^{(b)} = \left\{\begin{aligned}1/n \qquad y_i\neq y_j \\ + \,\,\mathbf{A}_{i,j}(1/n-1/n_l) \qquad y_i = y_j\end{aligned}\right.\\ + +here :math:`\mathbf{A}_{i,j}` is the :math:`(i,j)`-th entry of the affinity +matrix :math:`\mathbf{A}`:, which can be calculated with local scaling methods, `n` and `n_l` are the total number of points and the number of points per cluster `l` respectively. + +Then the learning problem becomes derive the LFDA transformation matrix +:math:`\mathbf{L}_{LFDA}`: + +.. math:: + + \mathbf{L}_{LFDA} = \arg\max_\mathbf{L} + [\text{tr}((\mathbf{L}^T\mathbf{S}^{(w)} + \mathbf{L})^{-1}\mathbf{L}^T\mathbf{S}^{(b)}\mathbf{L})] + +That is, it is looking for a transformation matrix :math:`\mathbf{L}` such that +nearby data pairs in the same class are made close and the data pairs in +different classes are separated from each other; far apart data pairs in the +same class are not imposed to be close. + +.. rubric:: Example Code + +:: + + import numpy as np + from metric_learn import LFDA + from sklearn.datasets import load_iris + + iris_data = load_iris() + X = iris_data['data'] + Y = iris_data['target'] + + lfda = LFDA(k=2, dim=2) + lfda.fit(X, Y) + +.. note:: + LDFA suffers from a problem called “sign indeterminacy”, which means the sign of the ``components`` and the output from transform depend on a random state. This is directly related to the calculation of eigenvectors in the algorithm. The same input ran in different times might lead to different transforms, but both valid. + + To work around this, fit instances of this class to data once, then keep the instance around to do transformations. + +.. rubric:: References + + +.. container:: hatnote hatnote-gray + + [1]. Sugiyama. `Dimensionality Reduction of Multimodal Labeled Data by Local Fisher Discriminant Analysis `_. JMLR 2007. + + [2]. Tang. `Local Fisher Discriminant Analysis on Beer Style Clustering `_. + +.. _mlkr: + +:py:class:`MLKR ` +----------------------------------------- + +Metric Learning for Kernel Regression (:py:class:`MLKR `) + +`MLKR` is an algorithm for supervised metric learning, which learns a +distance function by directly minimizing the leave-one-out regression error. +This algorithm can also be viewed as a supervised variation of PCA and can be +used for dimensionality reduction and high dimensional data visualization. + +Theoretically, `MLKR` can be applied with many types of kernel functions and +distance metrics, we hereafter focus the exposition on a particular instance +of the Gaussian kernel and Mahalanobis metric, as these are used in our +empirical development. The Gaussian kernel is denoted as: + +.. math:: + + k_{ij} = \frac{1}{\sqrt{2\pi}\sigma}\exp(-\frac{d(\mathbf{x}_i, + \mathbf{x}_j)}{\sigma^2}) + +where :math:`d(\cdot, \cdot)` is the squared distance under some metrics, +here in the fashion of Mahalanobis, it should be :math:`d(\mathbf{x}_i, +\mathbf{x}_j) = ||\mathbf{L}(\mathbf{x}_i - \mathbf{x}_j)||`, the transition +matrix :math:`\mathbf{L}` is derived from the decomposition of Mahalanobis +matrix :math:`\mathbf{M=L^TL}`. + +Since :math:`\sigma^2` can be integrated into :math:`d(\cdot)`, we can set +:math:`\sigma^2=1` for the sake of simplicity. Here we use the cumulative +leave-one-out quadratic regression error of the training samples as the +loss function: + +.. math:: + + \mathcal{L} = \sum_i(y_i - \hat{y}_i)^2 + +where the prediction :math:`\hat{y}_i` is derived from kernel regression by +calculating a weighted average of all the training samples: + +.. math:: + + \hat{y}_i = \frac{\sum_{j\neq i}y_jk_{ij}}{\sum_{j\neq i}k_{ij}} + +.. rubric:: Example Code + +:: + + from metric_learn import MLKR + from sklearn.datasets import load_iris + + iris_data = load_iris() + X = iris_data['data'] + Y = iris_data['target'] + + mlkr = MLKR() + mlkr.fit(X, Y) + +.. rubric:: References + + +.. container:: hatnote hatnote-gray + + [1]. Weinberger et al. `Metric Learning for Kernel Regression `_. AISTATS 2007. + + +.. _supervised_version: + +Supervised versions of weakly-supervised algorithms +--------------------------------------------------- + +Each :ref:`weakly-supervised algorithm ` +has a supervised version of the form `*_Supervised` where similarity tuples are +randomly generated from the labels information and passed to the underlying +algorithm. + +.. warning:: + Supervised versions of weakly-supervised algorithms interpret label -1 + (or any negative label) as a point with unknown label. + Those points are discarded in the learning process. + +For pairs learners (see :ref:`learning_on_pairs`), pairs (tuple of two points +from the dataset), and pair labels (`int` indicating whether the two points +are similar (+1) or dissimilar (-1)), are sampled with the function +`metric_learn.constraints.positive_negative_pairs`. To sample positive pairs +(of label +1), this method will look at all the samples from the same label and +sample randomly a pair among them. To sample negative pairs (of label -1), this +method will look at all the samples from a different class and sample randomly +a pair among them. The method will try to build `n_constraints` positive +pairs and `n_constraints` negative pairs, but sometimes it cannot find enough +of one of those, so forcing `same_length=True` will return both times the +minimum of the two lenghts. + +For using quadruplets learners (see :ref:`learning_on_quadruplets`) in a +supervised way, positive and negative pairs are sampled as above and +concatenated so that we have a 3D array of +quadruplets, where for each quadruplet the two first points are from the same +class, and the two last points are from a different class (so indeed the two +last points should be less similar than the two first points). + +.. rubric:: Example Code + +:: + + from metric_learn import MMC_Supervised + from sklearn.datasets import load_iris + + iris_data = load_iris() + X = iris_data['data'] + Y = iris_data['target'] + + mmc = MMC_Supervised(n_constraints=200) + mmc.fit(X, Y) diff --git a/_sources/unsupervised.rst.txt b/_sources/unsupervised.rst.txt new file mode 100644 index 00000000..110b07f9 --- /dev/null +++ b/_sources/unsupervised.rst.txt @@ -0,0 +1,40 @@ +============================ +Unsupervised Metric Learning +============================ + +Unsupervised metric learning algorithms only take as input an (unlabeled) +dataset `X`. For now, in metric-learn, there only is `Covariance`, which is a +simple baseline algorithm (see below). + + +Algorithms +========== +.. _covariance: + +Covariance +---------- + +`Covariance` does not "learn" anything, rather it calculates +the covariance matrix of the input data. This is a simple baseline method. +It can be used for ZCA whitening of the data (see the Wikipedia page of +`whitening transformation `_). + +.. rubric:: Example Code + +:: + + from metric_learn import Covariance + from sklearn.datasets import load_iris + + iris = load_iris()['data'] + + cov = Covariance().fit(iris) + x = cov.transform(iris) + +.. rubric:: References + + +.. container:: hatnote hatnote-gray + + [1]. On the Generalized Distance in Statistics, P.C.Mahalanobis, 1936. \ No newline at end of file diff --git a/_sources/user_guide.rst.txt b/_sources/user_guide.rst.txt new file mode 100644 index 00000000..5472107a --- /dev/null +++ b/_sources/user_guide.rst.txt @@ -0,0 +1,16 @@ +.. title:: User guide: contents + +.. _user_guide: + +========== +User Guide +========== + +.. toctree:: + :numbered: + + introduction.rst + supervised.rst + weakly_supervised.rst + unsupervised.rst + preprocessor.rst \ No newline at end of file diff --git a/_sources/weakly_supervised.rst.txt b/_sources/weakly_supervised.rst.txt new file mode 100644 index 00000000..76f7c14e --- /dev/null +++ b/_sources/weakly_supervised.rst.txt @@ -0,0 +1,974 @@ +.. _weakly_supervised_section: + +================================= +Weakly Supervised Metric Learning +================================= + +Weakly supervised algorithms work on weaker information about the data points +than supervised algorithms. Rather than labeled points, they take as input +similarity judgments on tuples of data points, for instance pairs of similar +and dissimilar points. Refer to the documentation of each algorithm for its +particular form of input data. + + +General API +=========== + +Input data +---------- + +In the following paragraph we talk about tuples for sake of generality. These +can be pairs, triplets, quadruplets etc, depending on the particular metric +learning algorithm we use. + +Basic form +^^^^^^^^^^ + +Every weakly supervised algorithm will take as input tuples of +points, and if needed labels for theses tuples. The tuples of points can +also be called "constraints". They are a set of points that we consider (ex: +two points, three points, etc...). The label is some information we have +about this set of points (e.g. "these two points are similar"). Note that +some information can be contained in the ordering of these tuples (see for +instance the section :ref:`learning_on_quadruplets`). For more details about +specific forms of tuples, refer to the appropriate sections +(:ref:`learning_on_pairs` or :ref:`learning_on_quadruplets`). + +The `tuples` argument is the first argument of every method (like the `X` +argument for classical algorithms in scikit-learn). The second argument is the +label of the tuple: its semantic depends on the algorithm used. For instance +for pairs learners `y` is a label indicating whether the pair is of similar +samples or dissimilar samples. + +Then one can fit a Weakly Supervised Metric Learner on this tuple, like this: + +>>> my_algo.fit(tuples, y) + +Like in a classical setting we split the points `X` between train and test, +here we split the `tuples` between train and test. + +>>> from sklearn.model_selection import train_test_split +>>> pairs_train, pairs_test, y_train, y_test = train_test_split(pairs, y) + +These are two data structures that can be used to represent tuple in metric +learn: + +3D array of tuples +^^^^^^^^^^^^^^^^^^ + +The most intuitive way to represent tuples is to provide the algorithm with a +3D array-like of tuples of shape `(n_tuples, tuple_size, n_features)`, where +`n_tuples` is the number of tuples, `tuple_size` is the number of elements +in a tuple (2 for pairs, 3 for triplets for instance), and `n_features` is +the number of features of each point. + +.. rubric:: Example Code + +Here is an artificial dataset of 4 pairs of 2 points of 3 features each: + +>>> import numpy as np +>>> tuples = np.array([[[-0.12, -1.21, -0.20], +>>> [+0.05, -0.19, -0.05]], +>>> +>>> [[-2.16, +0.11, -0.02], +>>> [+1.58, +0.16, +0.93]], +>>> +>>> [[+1.58, +0.16, +0.93], # same as tuples[1, 1, :] +>>> [+0.89, -0.34, +2.41]], +>>> +>>> [[-0.12, -1.21, -0.20], # same as tuples[0, 0, :] +>>> [-2.16, +0.11, -0.02]]]) # same as tuples[1, 0, :] +>>> y = np.array([-1, 1, 1, -1]) + +.. warning:: This way of specifying pairs is not recommended for a large number + of tuples, as it is redundant (see the comments in the example) and hence + takes a lot of memory. Indeed each feature vector of a point will be + replicated as many times as a point is involved in a tuple. The second way + to specify pairs is more efficient + + +2D array of indicators + preprocessor +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Instead of forming each point in each tuple, a more efficient representation +would be to keep the dataset of points `X` aside, and just represent tuples +as a collection of tuples of *indices* from the points in `X`. Since we loose +the feature dimension there, the resulting array is 2D. + +.. rubric:: Example Code + +An equivalent representation of the above pairs would be: + +>>> X = np.array([[-0.12, -1.21, -0.20], +>>> [+0.05, -0.19, -0.05], +>>> [-2.16, +0.11, -0.02], +>>> [+1.58, +0.16, +0.93], +>>> [+0.89, -0.34, +2.41]]) +>>> +>>> tuples_indices = np.array([[0, 1], +>>> [2, 3], +>>> [3, 4], +>>> [0, 2]]) +>>> y = np.array([-1, 1, 1, -1]) + +In order to fit metric learning algorithms with this type of input, we need to +give the original dataset of points `X` to the estimator so that it knows +the points the indices refer to. We do this when initializing the estimator, +through the argument `preprocessor` (see below :ref:`fit_ws`) + + +.. note:: + + Instead of an array-like, you can give a callable in the argument + `preprocessor`, which will go fetch and form the tuples. This allows to + give more general indicators than just indices from an array (for instance + paths in the filesystem, name of records in a database etc...) See section + :ref:`preprocessor_section` for more details on how to use the preprocessor. + +.. _fit_ws: + +Fit, transform, and so on +------------------------- + +The goal of weakly-supervised metric-learning algorithms is to transform +points in a new space, in which the tuple-wise constraints between points +are respected. + +>>> from metric_learn import MMC +>>> mmc = MMC(random_state=42) +>>> mmc.fit(tuples, y) +MMC(A0='deprecated', tol=0.001, diagonal=False, + diagonal_c=1.0, init='auto', max_iter=100, max_proj=10000, + preprocessor=None, random_state=42, verbose=False) + +Or alternatively (using a preprocessor): + +>>> from metric_learn import MMC +>>> mmc = MMC(preprocessor=X, random_state=42) +>>> mmc.fit(pairs_indice, y) + + +Now that the estimator is fitted, you can use it on new data for several +purposes. + +First, you can transform the data in the learned space, using `transform`: +Here we transform two points in the new embedding space. + +>>> X_new = np.array([[9.4, 4.1, 4.2], [2.1, 4.4, 2.3]]) +>>> mmc.transform(X_new) +array([[-3.24667162e+01, 4.62622348e-07, 3.88325421e-08], + [-3.61531114e+01, 4.86778289e-07, 2.12654397e-08]]) + +Also, as explained before, our metric learner has learned a distance between +points. You can use this distance in two main ways: + +- You can either return the distance between pairs of points using the + `pair_distance` function: + +>>> mmc.pair_distance([[[3.5, 3.6, 5.2], [5.6, 2.4, 6.7]], +... [[1.2, 4.2, 7.7], [2.1, 6.4, 0.9]]]) +array([7.27607365, 0.88853014]) + +- Or you can return a function that will return the distance + (in the new space) between two 1D arrays (the coordinates of the points in + the original space), similarly to distance functions in + `scipy.spatial.distance`. To do that, use the `get_metric` method. + +>>> metric_fun = mmc.get_metric() +>>> metric_fun([3.5, 3.6, 5.2], [5.6, 2.4, 6.7]) +7.276073646278203 + +- Alternatively, you can use `pair_score` to return the **score** between + pairs of points (the larger the score, the more similar the pair). + For Mahalanobis learners, it is equal to the opposite of the distance. + +>>> score = mmc.pair_score([[[3.5, 3.6], [5.6, 2.4]], [[1.2, 4.2], [2.1, 6.4]], [[3.3, 7.8], [10.9, 0.1]]]) +>>> score +array([-0.49627072, -3.65287282, -6.06079877]) + + This is useful because `pair_score` matches the **score** semantic of + scikit-learn's `Classification metrics + `_. + +.. note:: + + If the metric learner that you use learns a :ref:`Mahalanobis distance + ` (like it is the case for all algorithms + currently in metric-learn), you can get the plain Mahalanobis matrix using + `get_mahalanobis_matrix`. + +>>> mmc.get_mahalanobis_matrix() +array([[ 0.58603894, -5.69883982, -1.66614919], + [-5.69883982, 55.41743549, 16.20219519], + [-1.66614919, 16.20219519, 4.73697721]]) + +.. _sklearn_compat_ws: + +Prediction and scoring +---------------------- + +Since weakly supervised are also able, after being fitted, to predict for a +given tuple what is its label (for pairs) or ordering (for quadruplets). See +the appropriate section for more details, either :ref:`this +one ` for pairs, or :ref:`this one +` for quadruplets. + +They also implement a default scoring method, `score`, that can be +used to evaluate the performance of a metric-learner on a test dataset. See +the appropriate section for more details, either :ref:`this +one ` for pairs, or :ref:`this one ` +for quadruplets. + +Scikit-learn compatibility +-------------------------- + +Weakly supervised estimators are compatible with scikit-learn routines for +model selection (`sklearn.model_selection.cross_val_score`, +`sklearn.model_selection.GridSearchCV`, etc). + +Example: + +>>> from metric_learn import MMC +>>> import numpy as np +>>> from sklearn.datasets import load_iris +>>> from sklearn.model_selection import cross_val_score +>>> rng = np.random.RandomState(42) +>>> X, _ = load_iris(return_X_y=True) +>>> # let's sample 30 random pairs and labels of pairs +>>> pairs_indices = rng.randint(X.shape[0], size=(30, 2)) +>>> y = 2 * rng.randint(2, size=30) - 1 +>>> mmc = MMC(preprocessor=X) +>>> cross_val_score(mmc, pairs_indices, y) + +.. _learning_on_pairs: + +Learning on pairs +================= + +Some metric learning algorithms learn on pairs of samples. In this case, one +should provide the algorithm with `n_samples` pairs of points, with a +corresponding target containing `n_samples` values being either +1 or -1. +These values indicate whether the given pairs are similar points or +dissimilar points. + +Fitting +------- +Here is an example for fitting on pairs (see :ref:`fit_ws` for more details on +the input data format and how to fit, in the general case of learning on +tuples). + +>>> from metric_learn import MMC +>>> pairs = np.array([[[1.2, 3.2], [2.3, 5.5]], +>>> [[4.5, 2.3], [2.1, 2.3]]]) +>>> y_pairs = np.array([1, -1]) +>>> mmc = MMC(random_state=42) +>>> mmc.fit(pairs, y_pairs) +MMC(tol=0.001, diagonal=False, + diagonal_c=1.0, init='auto', max_iter=100, max_proj=10000, preprocessor=None, + random_state=42, verbose=False) + +Here, we learned a metric that puts the two first points closer +together in the transformed space, and the two next points further away from +each other. + +.. _pairs_predicting: + +Prediction +---------- + +When a pairs learner is fitted, it is also able to predict, for an unseen +pair, whether it is a pair of similar or dissimilar points. + +>>> mmc.predict([[[0.6, 1.6], [1.15, 2.75]], +... [[3.2, 1.1], [5.4, 6.1]]]) +array([1, -1]) + +.. _calibration: + +Prediction threshold +^^^^^^^^^^^^^^^^^^^^ + +Predicting whether a new pair represents similar or dissimilar +samples requires to set a threshold on the learned distance, so that points +closer (in the learned space) than this threshold are predicted as similar, +and points further away are predicted as dissimilar. Several methods are +possible for this thresholding. + +- **Calibration at fit time**: The threshold is set with `calibrate_threshold` + (see below) on the training set. You can specify the calibration + parameters directly + in the `fit` method with the `threshold_params` parameter (see the + documentation of the `fit` method of any metric learner that learns on pairs + of points for more information). Note that calibrating on the training set + may cause some overfitting. If you want to avoid that, calibrate the + threshold after fitting, on a validation set. + + >>> mmc.fit(pairs, y) # will fit the threshold automatically after fitting + +- **Calibration on validation set**: calling `calibrate_threshold` will + calibrate the threshold to achieve a particular score on a validation set, + the score being among the classical scores for classification (accuracy, f1 + score...). + + >>> mmc.calibrate_threshold(pairs, y) + +- **Manual threshold**: calling `set_threshold` will set the threshold to a + particular value. + + >>> mmc.set_threshold(0.4) + +See also: `sklearn.calibration`. + +.. _pairs_scoring: + +Scoring +------- + +Pair metric learners can also return a `decision_function` for a set of pairs. +It is basically the "score" that will be thresholded to find the prediction +for the pair. This score corresponds to the opposite of the distance in the +new space (higher score means points are similar, and lower score dissimilar). + +>>> mmc.decision_function([[[0.6, 1.6], [1.15, 2.75]], +... [[3.2, 1.1], [5.4, 6.1]]]) +array([-0.12811124, -0.74750256]) + +This allows to use common scoring functions for binary classification, like +`sklearn.metrics.accuracy_score` for instance, which +can be used inside cross-validation routines: + +>>> from sklearn.model_selection import cross_val_score +>>> pairs_test = np.array([[[0.6, 1.6], [1.15, 2.75]], +... [[3.2, 1.1], [5.4, 6.1]], +... [[7.7, 5.6], [1.23, 8.4]]]) +>>> y_test = np.array([-1., 1., -1.]) +>>> cross_val_score(mmc, pairs_test, y_test, scoring='accuracy') +array([1., 0., 1.]) + +Pairs learners also have a default score, which basically +returns the `sklearn.metrics.roc_auc_score` (which is threshold-independent). + +>>> pairs_test = np.array([[[0.6, 1.6], [1.15, 2.75]], +... [[3.2, 1.1], [5.4, 6.1]], +... [[7.7, 5.6], [1.23, 8.4]]]) +>>> y_test = np.array([1., -1., -1.]) +>>> mmc.score(pairs_test, y_test) +1.0 + +.. note:: + See :ref:`fit_ws` for more details on metric learners functions that are + not specific to learning on pairs, like `transform`, `pair_distance`, + `pair_score`, `get_metric` and `get_mahalanobis_matrix`. + +Algorithms +---------- + +.. _itml: + +:py:class:`ITML ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Information Theoretic Metric Learning (:py:class:`ITML `) + +`ITML` minimizes the (differential) relative entropy, aka Kullback–Leibler +divergence, between two multivariate Gaussians subject to constraints on the +associated Mahalanobis distance, which can be formulated into a Bregman +optimization problem by minimizing the LogDet divergence subject to +linear constraints. This algorithm can handle a wide variety of constraints +and can optionally incorporate a prior on the distance function. Unlike some +other methods, `ITML` does not rely on an eigenvalue computation or +semi-definite programming. + + +Given a Mahalanobis distance parameterized by :math:`M`, its corresponding +multivariate Gaussian is denoted as: + +.. math:: + p(\mathbf{x}; \mathbf{M}) = \frac{1}{Z}\exp(-\frac{1}{2}d_\mathbf{M} + (\mathbf{x}, \mu)) + = \frac{1}{Z}\exp(-\frac{1}{2}((\mathbf{x} - \mu)^T\mathbf{M} + (\mathbf{x} - \mu)) + +where :math:`Z` is the normalization constant, the inverse of Mahalanobis +matrix :math:`\mathbf{M}^{-1}` is the covariance of the Gaussian. + +Given pairs of similar points :math:`S` and pairs of dissimilar points +:math:`D`, the distance metric learning problem is to minimize the LogDet +divergence, which is equivalent as minimizing :math:`\textbf{KL}(p(\mathbf{x}; +\mathbf{M}_0) || p(\mathbf{x}; \mathbf{M}))`: + +.. math:: + + \min_\mathbf{A} D_{\ell \mathrm{d}}\left(M, M_{0}\right) = + \operatorname{tr}\left(M M_{0}^{-1}\right)-\log \operatorname{det} + \left(M M_{0}^{-1}\right)-n\\ + \text{subject to } \quad d_\mathbf{M}(\mathbf{x}_i, \mathbf{x}_j) + \leq u \qquad (\mathbf{x}_i, \mathbf{x}_j)\in S \\ + d_\mathbf{M}(\mathbf{x}_i, \mathbf{x}_j) \geq l \qquad (\mathbf{x}_i, + \mathbf{x}_j)\in D + + +where :math:`u` and :math:`l` is the upper and the lower bound of distance +for similar and dissimilar pairs respectively, and :math:`\mathbf{M}_0` +is the prior distance metric, set to identity matrix by default, +:math:`D_{\ell \mathrm{d}}(\cdot)` is the log determinant. + +.. rubric:: Example Code + +:: + + from metric_learn import ITML + + pairs = [[[1.2, 7.5], [1.3, 1.5]], + [[6.4, 2.6], [6.2, 9.7]], + [[1.3, 4.5], [3.2, 4.6]], + [[6.2, 5.5], [5.4, 5.4]]] + y = [1, 1, -1, -1] + + # in this task we want points where the first feature is close to be closer + # to each other, no matter how close the second feature is + + + itml = ITML() + itml.fit(pairs, y) + +.. rubric:: References + + +.. container:: hatnote hatnote-gray + + [1]. Jason V. Davis, et al. `Information-theoretic Metric Learning `_. ICML 2007. + + [2]. Adapted from Matlab code at http://www.cs.utexas.edu/users/pjain/itml/ . + + +.. _sdml: + +:py:class:`SDML ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sparse High-Dimensional Metric Learning +(:py:class:`SDML `) + +`SDML` is an efficient sparse metric learning in high-dimensional space via +double regularization: an L1-penalization on the off-diagonal elements of the +Mahalanobis matrix :math:`\mathbf{M}`, and a log-determinant divergence between +:math:`\mathbf{M}` and :math:`\mathbf{M_0}` (set as either :math:`\mathbf{I}` +or :math:`\mathbf{\Omega}^{-1}`, where :math:`\mathbf{\Omega}` is the +covariance matrix). + +The formulated optimization on the semidefinite matrix :math:`\mathbf{M}` +is convex: + +.. math:: + + \min_{\mathbf{M}} = \text{tr}((\mathbf{M}_0 + \eta \mathbf{XLX}^{T}) + \cdot \mathbf{M}) - \log\det \mathbf{M} + \lambda ||\mathbf{M}||_{1, off} + +where :math:`\mathbf{X}=[\mathbf{x}_1, \mathbf{x}_2, ..., \mathbf{x}_n]` is +the training data, the incidence matrix :math:`\mathbf{K}_{ij} = 1` if +:math:`(\mathbf{x}_i, \mathbf{x}_j)` is a similar pair, otherwise -1. The +Laplacian matrix :math:`\mathbf{L}=\mathbf{D}-\mathbf{K}` is calculated from +:math:`\mathbf{K}` and :math:`\mathbf{D}`, a diagonal matrix whose entries are +the sums of the row elements of :math:`\mathbf{K}`., :math:`||\cdot||_{1, off}` +is the off-diagonal L1 norm. + + +.. rubric:: Example Code + +:: + + from metric_learn import SDML + + pairs = [[[1.2, 7.5], [1.3, 1.5]], + [[6.4, 2.6], [6.2, 9.7]], + [[1.3, 4.5], [3.2, 4.6]], + [[6.2, 5.5], [5.4, 5.4]]] + y = [1, 1, -1, -1] + + # in this task we want points where the first feature is close to be closer + # to each other, no matter how close the second feature is + + sdml = SDML() + sdml.fit(pairs, y) + +.. rubric:: References + + +.. container:: hatnote hatnote-gray + + [1]. Qi et al. `An efficient sparse metric learning in high-dimensional space via L1-penalized log-determinant regularization `_. ICML 2009. + + [2]. Code adapted from https://gist.github.com/kcarnold/5439945 . + +.. _rca: + +:py:class:`RCA ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Relative Components Analysis (:py:class:`RCA `) + +`RCA` learns a full rank Mahalanobis distance metric based on a weighted sum of +in-chunklets covariance matrices. It applies a global linear transformation to +assign large weights to relevant dimensions and low weights to irrelevant +dimensions. Those relevant dimensions are estimated using "chunklets", subsets +of points that are known to belong to the same class. + +For a training set with :math:`n` training points in :math:`k` chunklets, the +algorithm is efficient since it simply amounts to computing + +.. math:: + + \mathbf{C} = \frac{1}{n}\sum_{j=1}^k\sum_{i=1}^{n_j} + (\mathbf{x}_{ji}-\hat{\mathbf{m}}_j) + (\mathbf{x}_{ji}-\hat{\mathbf{m}}_j)^T + + +where chunklet :math:`j` consists of :math:`\{\mathbf{x}_{ji}\}_{i=1}^{n_j}` +with a mean :math:`\hat{m}_j`. The inverse of :math:`\mathbf{C}^{-1}` is used +as the Mahalanobis matrix. + +.. rubric:: Example Code + +:: + + from metric_learn import RCA + + X = [[-0.05, 3.0],[0.05, -3.0], + [0.1, -3.55],[-0.1, 3.55], + [-0.95, -0.05],[0.95, 0.05], + [0.4, 0.05],[-0.4, -0.05]] + chunks = [0, 0, 1, 1, 2, 2, 3, 3] + + rca = RCA() + rca.fit(X, chunks) + +.. rubric:: References + + +.. container:: hatnote hatnote-gray + + [1]. Shental et al. `Adjustment learning and relevant component analysis `_. ECCV 2002. + + [2]. Bar-Hillel et al. `Learning distance functions using equivalence relations `_. ICML 2003. + + [3]. Bar-Hillel et al. `Learning a Mahalanobis metric from equivalence constraints `_. JMLR 2005. + +.. _mmc: + +:py:class:`MMC ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Metric Learning with Application for Clustering with Side Information +(:py:class:`MMC `) + +`MMC` minimizes the sum of squared distances between similar points, while +enforcing the sum of distances between dissimilar ones to be greater than one. +This leads to a convex and, thus, local-minima-free optimization problem that +can be solved efficiently. +However, the algorithm involves the computation of eigenvalues, which is the +main speed-bottleneck. Since it has initially been designed for clustering +applications, one of the implicit assumptions of MMC is that all classes form +a compact set, i.e., follow a unimodal distribution, which restricts the +possible use-cases of this method. However, it is one of the earliest and a +still often cited technique. + +The algorithm aims at minimizing the sum of distances between all the similar +points, while constrains the sum of distances between dissimilar points: + +.. math:: + + \min_{\mathbf{M}\in\mathbb{S}_+^d}\sum_{(\mathbf{x}_i, + \mathbf{x}_j)\in S} d_{\mathbf{M}}(\mathbf{x}_i, \mathbf{x}_j) + \qquad \qquad \text{s.t.} \qquad \sum_{(\mathbf{x}_i, \mathbf{x}_j) + \in D} d^2_{\mathbf{M}}(\mathbf{x}_i, \mathbf{x}_j) \geq 1 + +.. rubric:: Example Code + +:: + + from metric_learn import MMC + + pairs = [[[1.2, 7.5], [1.3, 1.5]], + [[6.4, 2.6], [6.2, 9.7]], + [[1.3, 4.5], [3.2, 4.6]], + [[6.2, 5.5], [5.4, 5.4]]] + y = [1, 1, -1, -1] + + # in this task we want points where the first feature is close to be closer + # to each other, no matter how close the second feature is + + mmc = MMC() + mmc.fit(pairs, y) + +.. rubric:: References + + +.. container:: hatnote hatnote-gray + + [1]. Xing et al. `Distance metric learning with application to clustering with side-information `_. NIPS 2002. + + [2]. Adapted from Matlab code http://www.cs.cmu.edu/%7Eepxing/papers/Old_papers/code_Metric_online.tar.gz . + +.. _learning_on_triplets: + +Learning on triplets +==================== + +Some metric learning algorithms learn on triplets of samples. In this case, +one should provide the algorithm with `n_samples` triplets of points. The +semantic of each triplet is that the first point should be closer to the +second point than to the third one. + +Fitting +------- +Here is an example for fitting on triplets (see :ref:`fit_ws` for more +details on the input data format and how to fit, in the general case of +learning on tuples). + +>>> from metric_learn import SCML +>>> triplets = np.array([[[1.2, 3.2], [2.3, 5.5], [2.1, 0.6]], +>>> [[4.5, 2.3], [2.1, 2.3], [7.3, 3.4]]]) +>>> scml = SCML(random_state=42) +>>> scml.fit(triplets) +SCML(beta=1e-5, B=None, max_iter=100000, verbose=False, + preprocessor=None, random_state=None) + +Or alternatively (using a preprocessor): + +>>> X = np.array([[[1.2, 3.2], +>>> [2.3, 5.5], +>>> [2.1, 0.6], +>>> [4.5, 2.3], +>>> [2.1, 2.3], +>>> [7.3, 3.4]]) +>>> triplets_indices = np.array([[0, 1, 2], [3, 4, 5]]) +>>> scml = SCML(preprocessor=X, random_state=42) +>>> scml.fit(triplets_indices) +SCML(beta=1e-5, B=None, max_iter=100000, verbose=False, + preprocessor=array([[1.2, 3.2], + [2.3, 5.5], + [2.4, 6.7], + [2.1, 0.6], + [4.5, 2.3], + [2.1, 2.3], + [0.6, 1.2], + [7.3, 3.4]]), + random_state=None) + + +Here, we want to learn a metric that, for each of the two +`triplets`, will make the first point closer to the +second point than to the third one. + +.. _triplets_predicting: + +Prediction +---------- + +When a triplets learner is fitted, it is also able to predict, for an +upcoming triplet, whether the first point is closer to the second point +than to the third one (+1), or not (-1). + +>>> triplets_test = np.array( +... [[[5.6, 5.3], [2.2, 2.1], [1.2, 3.4]], +... [[6.0, 4.2], [4.3, 1.2], [0.1, 7.8]]]) +>>> scml.predict(triplets_test) +array([-1., 1.]) + +.. _triplets_scoring: + +Scoring +------- + +Triplet metric learners can also return a `decision_function` for a set of triplets, +which corresponds to the distance between the first two points minus the distance +between the first and last points of the triplet (the higher the value, the more +similar the first point to the second point compared to the last one). This "score" +can be interpreted as a measure of likeliness of having a +1 prediction for this +triplet. + +>>> scml.decision_function(triplets_test) +array([-1.75700306, 4.98982131]) + +In the above example, for the first triplet in `triplets_test`, the first +point is predicted less similar to the second point than to the last point +(they are further away in the transformed space). + +Unlike pairs learners, triplets learners do not allow to give a `y` when fitting: we +assume that the ordering of points within triplets is such that the training triplets +are all positive. Therefore, it is not possible to use scikit-learn scoring functions +(such as 'f1_score') for triplets learners. + +However, triplets learners do have a default scoring function, which will +basically return the accuracy score on a given test set, i.e. the proportion +of triplets that have the right predicted ordering. + +>>> scml.score(triplets_test) +0.5 + +.. note:: + See :ref:`fit_ws` for more details on metric learners functions that are + not specific to learning on pairs, like `transform`, `pair_distance`, + `pair_score`, `get_metric` and `get_mahalanobis_matrix`. + + + + +Algorithms +---------- + +.. _scml: + +:py:class:`SCML ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sparse Compositional Metric Learning +(:py:class:`SCML `) + +`SCML` learns a squared Mahalanobis distance from triplet constraints by +optimizing sparse positive weights assigned to a set of :math:`K` rank-one +PSD bases. This can be formulated as an optimization problem with only +:math:`K` parameters, that can be solved with an efficient stochastic +composite scheme. + +The Mahalanobis matrix :math:`M` is built from a basis set :math:`B = \{b_i\}_{i=\{1,...,K\}}` +weighted by a :math:`K` dimensional vector :math:`w = \{w_i\}_{i=\{1,...,K\}}` as: + +.. math:: + + M = \sum_{i=1}^K w_i b_i b_i^T = B \cdot diag(w) \cdot B^T \quad w_i \geq 0 + +Learning :math:`M` in this form makes it PSD by design, as it is a +nonnegative sum of PSD matrices. The basis set :math:`B` is fixed in advance +and it is possible to construct it from the data. The optimization problem +over :math:`w` is formulated as a classic margin-based hinge loss function +involving the set :math:`C` of triplets. A regularization :math:`\ell_1` +is added to yield a sparse combination. The formulation is the following: + +.. math:: + + \min_{w\geq 0} \sum_{(x_i,x_j,x_k)\in C} [1 + d_w(x_i,x_j)-d_w(x_i,x_k)]_+ + \beta||w||_1 + +where :math:`[\cdot]_+` is the hinge loss. + +.. rubric:: Example Code + +:: + + from metric_learn import SCML + + triplets = [[[1.2, 7.5], [1.3, 1.5], [6.2, 9.7]], + [[1.3, 4.5], [3.2, 4.6], [5.4, 5.4]], + [[3.2, 7.5], [3.3, 1.5], [8.2, 9.7]], + [[3.3, 4.5], [5.2, 4.6], [7.4, 5.4]]] + + scml = SCML() + scml.fit(triplets) + +.. rubric:: References + + +.. container:: hatnote hatnote-gray + + [1]. Y. Shi, A. Bellet and F. Sha. `Sparse Compositional Metric Learning. `_. (AAAI), 2014. + + [2]. Adapted from original `Matlab implementation. `_. + + +.. _learning_on_quadruplets: + +Learning on quadruplets +======================= + +Some metric learning algorithms learn on quadruplets of samples. In this case, +one should provide the algorithm with `n_samples` quadruplets of points. The +semantic of each quadruplet is that the first two points should be closer +together than the last two points. + +Fitting +------- +Here is an example for fitting on quadruplets (see :ref:`fit_ws` for more +details on the input data format and how to fit, in the general case of +learning on tuples). + +>>> from metric_learn import LSML +>>> quadruplets = np.array([[[1.2, 3.2], [2.3, 5.5], [2.4, 6.7], [2.1, 0.6]], +>>> [[4.5, 2.3], [2.1, 2.3], [0.6, 1.2], [7.3, 3.4]]]) +>>> lsml = LSML(random_state=42) +>>> lsml.fit(quadruplets) +LSML(max_iter=1000, preprocessor=None, prior=None, random_state=42, tol=0.001, + verbose=False) + +Or alternatively (using a preprocessor): + +>>> X = np.array([[1.2, 3.2], +>>> [2.3, 5.5], +>>> [2.4, 6.7], +>>> [2.1, 0.6], +>>> [4.5, 2.3], +>>> [2.1, 2.3], +>>> [0.6, 1.2], +>>> [7.3, 3.4]]) +>>> quadruplets_indices = np.array([[0, 1, 2, 3], [4, 5, 6, 7]]) +>>> lsml = LSML(preprocessor=X, random_state=42) +>>> lsml.fit(quadruplets_indices) +LSML(max_iter=1000, + preprocessor=array([[1.2, 3.2], + [2.3, 5.5], + [2.4, 6.7], + [2.1, 0.6], + [4.5, 2.3], + [2.1, 2.3], + [0.6, 1.2], + [7.3, 3.4]]), + prior=None, random_state=42, tol=0.001, verbose=False) + + +Here, we want to learn a metric that, for each of the two +`quadruplets`, will put the two first points closer together than the two +last points. + +.. _quadruplets_predicting: + +Prediction +---------- + +When a quadruplets learner is fitted, it is also able to predict, for an +upcoming quadruplet, whether the two first points are more similar than the +two last points (+1), or not (-1). + +>>> quadruplets_test = np.array( +... [[[5.6, 5.3], [2.2, 2.1], [0.4, 0.6], [1.2, 3.4]], +... [[6.0, 4.2], [4.3, 1.2], [4.5, 0.6], [0.1, 7.8]]]) +>>> lsml.predict(quadruplets_test) +array([-1., 1.]) + +.. _quadruplets_scoring: + +Scoring +------- + +Quadruplet metric learners can also return a `decision_function` for a set of +quadruplets, which corresponds to the distance between the first pair of points minus +the distance between the second pair of points of the triplet (the higher the value, +the more similar the first pair is than the last pair). +This "score" can be interpreted as a measure of likeliness of having a +1 prediction +for this quadruplet. + +>>> lsml.decision_function(quadruplets_test) +array([-1.75700306, 4.98982131]) + +In the above example, for the first quadruplet in `quadruplets_test`, the +two first points are predicted less similar than the two last points (they +are further away in the transformed space). + +Like triplet learners, quadruplets learners do not allow to give a `y` when fitting: we +assume that the ordering of points within triplets is such that the training triplets +are all positive. Therefore, it is not possible to use scikit-learn scoring functions +(such as 'f1_score') for triplets learners. + +However, quadruplets learners do have a default scoring function, which will +basically return the accuracy score on a given test set, i.e. the proportion +of quadruplets have the right predicted ordering. + +>>> lsml.score(quadruplets_test) +0.5 + +.. note:: + See :ref:`fit_ws` for more details on metric learners functions that are + not specific to learning on pairs, like `transform`, `pair_distance`, + `pair_score`, `get_metric` and `get_mahalanobis_matrix`. + + + + +Algorithms +---------- + +.. _lsml: + +:py:class:`LSML ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Metric Learning from Relative Comparisons by Minimizing Squared Residual +(:py:class:`LSML `) + +`LSML` proposes a simple, yet effective, algorithm that minimizes a convex +objective function corresponding to the sum of squared residuals of +constraints. This algorithm uses the constraints in the form of the +relative distance comparisons, such method is especially useful where +pairwise constraints are not natural to obtain, thus pairwise constraints +based algorithms become infeasible to be deployed. Furthermore, its sparsity +extension leads to more stable estimation when the dimension is high and +only a small amount of constraints is given. + +The loss function of each constraint +:math:`d(\mathbf{x}_i, \mathbf{x}_j) < d(\mathbf{x}_k, \mathbf{x}_l)` is +denoted as: + +.. math:: + + H(d_\mathbf{M}(\mathbf{x}_i, \mathbf{x}_j) + - d_\mathbf{M}(\mathbf{x}_k, \mathbf{x}_l)) + +where :math:`H(\cdot)` is the squared Hinge loss function defined as: + +.. math:: + + H(x) = \left\{\begin{aligned}0 \qquad x\leq 0 \\ + \,\,x^2 \qquad x>0\end{aligned}\right.\\ + +The summed loss function :math:`L(C)` is the simple sum over all constraints +:math:`C = \{(\mathbf{x}_i , \mathbf{x}_j , \mathbf{x}_k , \mathbf{x}_l) +: d(\mathbf{x}_i , \mathbf{x}_j) < d(\mathbf{x}_k , \mathbf{x}_l)\}`. The +original paper suggested here should be a weighted sum since the confidence +or probability of each constraint might differ. However, for the sake of +simplicity and assumption of no extra knowledge provided, we just deploy +the simple sum here as well as what the authors did in the experiments. + +The distance metric learning problem becomes minimizing the summed loss +function of all constraints plus a regularization term w.r.t. the prior +knowledge: + +.. math:: + + \min_\mathbf{M}(D_{ld}(\mathbf{M, M_0}) + \sum_{(\mathbf{x}_i, + \mathbf{x}_j, \mathbf{x}_k, \mathbf{x}_l)\in C}H(d_\mathbf{M}( + \mathbf{x}_i, \mathbf{x}_j) - d_\mathbf{M}(\mathbf{x}_k, \mathbf{x}_l))\\ + +where :math:`\mathbf{M}_0` is the prior metric matrix, set as identity +by default, :math:`D_{ld}(\mathbf{\cdot, \cdot})` is the LogDet divergence: + +.. math:: + + D_{ld}(\mathbf{M, M_0}) = \text{tr}(\mathbf{MM_0}) − \text{logdet} + (\mathbf{M}) + +.. rubric:: Example Code + +:: + + from metric_learn import LSML + + quadruplets = [[[1.2, 7.5], [1.3, 1.5], [6.4, 2.6], [6.2, 9.7]], + [[1.3, 4.5], [3.2, 4.6], [6.2, 5.5], [5.4, 5.4]], + [[3.2, 7.5], [3.3, 1.5], [8.4, 2.6], [8.2, 9.7]], + [[3.3, 4.5], [5.2, 4.6], [8.2, 5.5], [7.4, 5.4]]] + + # we want to make closer points where the first feature is close, and + # further if the second feature is close + + lsml = LSML() + lsml.fit(quadruplets) + +.. rubric:: References + + +.. container:: hatnote hatnote-gray + + [1]. Liu et al. `Metric Learning from Relative Comparisons by Minimizing Squared Residual `_. ICDM 2012. + + [2]. Code adapted from https://gist.github.com/kcarnold/5439917 . + + diff --git a/_static/_sphinx_javascript_frameworks_compat.js b/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..81415803 --- /dev/null +++ b/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 00000000..30fee9d0 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/binder_badge_logo.svg b/_static/binder_badge_logo.svg new file mode 100644 index 00000000..327f6b63 --- /dev/null +++ b/_static/binder_badge_logo.svg @@ -0,0 +1 @@ + launchlaunchbinderbinder \ No newline at end of file diff --git a/_static/broken_example.png b/_static/broken_example.png new file mode 100644 index 00000000..4fea24e7 Binary files /dev/null and b/_static/broken_example.png differ diff --git a/_static/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 00000000..c718cee4 --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff b/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff2 b/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff b/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff2 b/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/_static/css/fonts/fontawesome-webfont.eot b/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/_static/css/fonts/fontawesome-webfont.svg b/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/css/fonts/fontawesome-webfont.ttf b/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/_static/css/fonts/fontawesome-webfont.woff b/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/_static/css/fonts/fontawesome-webfont.woff2 b/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/_static/css/fonts/lato-bold-italic.woff b/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff differ diff --git a/_static/css/fonts/lato-bold-italic.woff2 b/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/_static/css/fonts/lato-bold.woff b/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/_static/css/fonts/lato-bold.woff differ diff --git a/_static/css/fonts/lato-bold.woff2 b/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/_static/css/fonts/lato-bold.woff2 differ diff --git a/_static/css/fonts/lato-normal-italic.woff b/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff differ diff --git a/_static/css/fonts/lato-normal-italic.woff2 b/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/_static/css/fonts/lato-normal.woff b/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/_static/css/fonts/lato-normal.woff differ diff --git a/_static/css/fonts/lato-normal.woff2 b/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff2 differ diff --git a/_static/css/styles.css b/_static/css/styles.css new file mode 100644 index 00000000..6d350ae4 --- /dev/null +++ b/_static/css/styles.css @@ -0,0 +1,36 @@ +.hatnote { + border-color: #e1e4e5 ; + border-style: solid ; + border-width: 1px ; + font-size: x-small ; + font-style: italic ; + margin-left: auto ; + margin-right: auto ; + margin-bottom: 24px; + padding: 12px; +} +.hatnote-gray { + background-color: #f5f5f5 +} +.hatnote li { + list-style-type: square; + margin-left: 12px !important; +} +.hatnote ul { + list-style-type: square; + margin-left: 0px !important; + margin-bottom: 0px !important; +} +.deprecated { + color: #b94a48; + background-color: #F3E5E5; + border-color: #eed3d7; + margin-top: 0.5rem; + padding: 0.5rem; + border-radius: 0.5rem; + margin-bottom: 0.5rem; +} + +.deprecated p { + margin-bottom: 0 !important; +} \ No newline at end of file diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 00000000..19a446a0 --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 00000000..3c89f433 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '0.7.0', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/jquery.js b/_static/jquery.js new file mode 100644 index 00000000..c4c6022f --- /dev/null +++ b/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/html5shiv.min.js b/_static/js/html5shiv.min.js new file mode 100644 index 00000000..cd1c674f --- /dev/null +++ b/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/theme.js b/_static/js/theme.js new file mode 100644 index 00000000..1fddb6ee --- /dev/null +++ b/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t + +launchlaunchlitelite \ No newline at end of file diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 00000000..250f5665 --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, is available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/no_image.png b/_static/no_image.png new file mode 100644 index 00000000..8c2d48d5 Binary files /dev/null and b/_static/no_image.png differ diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 00000000..0d49244e --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 00000000..7918c3fa --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sg_gallery-binder.css b/_static/sg_gallery-binder.css new file mode 100644 index 00000000..420005d2 --- /dev/null +++ b/_static/sg_gallery-binder.css @@ -0,0 +1,11 @@ +/* CSS for binder integration */ + +div.binder-badge { + margin: 1em auto; + vertical-align: middle; +} + +div.lite-badge { + margin: 1em auto; + vertical-align: middle; +} diff --git a/_static/sg_gallery-dataframe.css b/_static/sg_gallery-dataframe.css new file mode 100644 index 00000000..fac74c43 --- /dev/null +++ b/_static/sg_gallery-dataframe.css @@ -0,0 +1,47 @@ +/* Pandas dataframe css */ +/* Taken from: https://github.com/spatialaudio/nbsphinx/blob/fb3ba670fc1ba5f54d4c487573dbc1b4ecf7e9ff/src/nbsphinx.py#L587-L619 */ +html[data-theme="light"] { + --sg-text-color: #000; + --sg-tr-odd-color: #f5f5f5; + --sg-tr-hover-color: rgba(66, 165, 245, 0.2); +} +html[data-theme="dark"] { + --sg-text-color: #fff; + --sg-tr-odd-color: #373737; + --sg-tr-hover-color: rgba(30, 81, 122, 0.2); +} + +table.dataframe { + border: none !important; + border-collapse: collapse; + border-spacing: 0; + border-color: transparent; + color: var(--sg-text-color); + font-size: 12px; + table-layout: fixed; + width: auto; +} +table.dataframe thead { + border-bottom: 1px solid var(--sg-text-color); + vertical-align: bottom; +} +table.dataframe tr, +table.dataframe th, +table.dataframe td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} +table.dataframe th { + font-weight: bold; +} +table.dataframe tbody tr:nth-child(odd) { + background: var(--sg-tr-odd-color); +} +table.dataframe tbody tr:hover { + background: var(--sg-tr-hover-color); +} diff --git a/_static/sg_gallery-rendered-html.css b/_static/sg_gallery-rendered-html.css new file mode 100644 index 00000000..93dc2ffb --- /dev/null +++ b/_static/sg_gallery-rendered-html.css @@ -0,0 +1,224 @@ +/* Adapted from notebook/static/style/style.min.css */ +html[data-theme="light"] { + --sg-text-color: #000; + --sg-background-color: #ffffff; + --sg-code-background-color: #eff0f1; + --sg-tr-hover-color: rgba(66, 165, 245, 0.2); + --sg-tr-odd-color: #f5f5f5; +} +html[data-theme="dark"] { + --sg-text-color: #fff; + --sg-background-color: #121212; + --sg-code-background-color: #2f2f30; + --sg-tr-hover-color: rgba(66, 165, 245, 0.2); + --sg-tr-odd-color: #1f1f1f; +} + +.rendered_html { + color: var(--sg-text-color); + /* any extras will just be numbers: */ +} +.rendered_html em { + font-style: italic; +} +.rendered_html strong { + font-weight: bold; +} +.rendered_html u { + text-decoration: underline; +} +.rendered_html :link { + text-decoration: underline; +} +.rendered_html :visited { + text-decoration: underline; +} +.rendered_html h1 { + font-size: 185.7%; + margin: 1.08em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h2 { + font-size: 157.1%; + margin: 1.27em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h3 { + font-size: 128.6%; + margin: 1.55em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h4 { + font-size: 100%; + margin: 2em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h5 { + font-size: 100%; + margin: 2em 0 0 0; + font-weight: bold; + line-height: 1.0; + font-style: italic; +} +.rendered_html h6 { + font-size: 100%; + margin: 2em 0 0 0; + font-weight: bold; + line-height: 1.0; + font-style: italic; +} +.rendered_html h1:first-child { + margin-top: 0.538em; +} +.rendered_html h2:first-child { + margin-top: 0.636em; +} +.rendered_html h3:first-child { + margin-top: 0.777em; +} +.rendered_html h4:first-child { + margin-top: 1em; +} +.rendered_html h5:first-child { + margin-top: 1em; +} +.rendered_html h6:first-child { + margin-top: 1em; +} +.rendered_html ul:not(.list-inline), +.rendered_html ol:not(.list-inline) { + padding-left: 2em; +} +.rendered_html ul { + list-style: disc; +} +.rendered_html ul ul { + list-style: square; + margin-top: 0; +} +.rendered_html ul ul ul { + list-style: circle; +} +.rendered_html ol { + list-style: decimal; +} +.rendered_html ol ol { + list-style: upper-alpha; + margin-top: 0; +} +.rendered_html ol ol ol { + list-style: lower-alpha; +} +.rendered_html ol ol ol ol { + list-style: lower-roman; +} +.rendered_html ol ol ol ol ol { + list-style: decimal; +} +.rendered_html * + ul { + margin-top: 1em; +} +.rendered_html * + ol { + margin-top: 1em; +} +.rendered_html hr { + color: var(--sg-text-color); + background-color: var(--sg-text-color); +} +.rendered_html pre { + margin: 1em 2em; + padding: 0px; + background-color: var(--sg-background-color); +} +.rendered_html code { + background-color: var(--sg-code-background-color); +} +.rendered_html p code { + padding: 1px 5px; +} +.rendered_html pre code { + background-color: var(--sg-background-color); +} +.rendered_html pre, +.rendered_html code { + border: 0; + color: var(--sg-text-color); + font-size: 100%; +} +.rendered_html blockquote { + margin: 1em 2em; +} +.rendered_html table { + margin-left: auto; + margin-right: auto; + border: none; + border-collapse: collapse; + border-spacing: 0; + color: var(--sg-text-color); + font-size: 12px; + table-layout: fixed; +} +.rendered_html thead { + border-bottom: 1px solid var(--sg-text-color); + vertical-align: bottom; +} +.rendered_html tr, +.rendered_html th, +.rendered_html td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} +.rendered_html th { + font-weight: bold; +} +.rendered_html tbody tr:nth-child(odd) { + background: var(--sg-tr-odd-color); +} +.rendered_html tbody tr:hover { + color: var(--sg-text-color); + background: var(--sg-tr-hover-color); +} +.rendered_html * + table { + margin-top: 1em; +} +.rendered_html p { + text-align: left; +} +.rendered_html * + p { + margin-top: 1em; +} +.rendered_html img { + display: block; + margin-left: auto; + margin-right: auto; +} +.rendered_html * + img { + margin-top: 1em; +} +.rendered_html img, +.rendered_html svg { + max-width: 100%; + height: auto; +} +.rendered_html img.unconfined, +.rendered_html svg.unconfined { + max-width: none; +} +.rendered_html .alert { + margin-bottom: initial; +} +.rendered_html * + .alert { + margin-top: 1em; +} +[dir="rtl"] .rendered_html p { + text-align: right; +} diff --git a/_static/sg_gallery.css b/_static/sg_gallery.css new file mode 100644 index 00000000..72227837 --- /dev/null +++ b/_static/sg_gallery.css @@ -0,0 +1,342 @@ +/* +Sphinx-Gallery has compatible CSS to fix default sphinx themes +Tested for Sphinx 1.3.1 for all themes: default, alabaster, sphinxdoc, +scrolls, agogo, traditional, nature, haiku, pyramid +Tested for Read the Docs theme 0.1.7 */ + +/* Define light colors */ +:root, html[data-theme="light"], body[data-theme="light"]{ + --sg-tooltip-foreground: black; + --sg-tooltip-background: rgba(250, 250, 250, 0.9); + --sg-tooltip-border: #ccc transparent; + --sg-thumb-box-shadow-color: #6c757d40; + --sg-thumb-hover-border: #0069d9; + --sg-script-out: #888; + --sg-script-pre: #fafae2; + --sg-pytb-foreground: #000; + --sg-pytb-background: #ffe4e4; + --sg-pytb-border-color: #f66; + --sg-download-a-background-color: #ffc; + --sg-download-a-background-image: linear-gradient(to bottom, #ffc, #d5d57e); + --sg-download-a-border-color: 1px solid #c2c22d; + --sg-download-a-color: #000; + --sg-download-a-hover-background-color: #d5d57e; + --sg-download-a-hover-box-shadow-1: rgba(255, 255, 255, 0.1); + --sg-download-a-hover-box-shadow-2: rgba(0, 0, 0, 0.25); +} +@media(prefers-color-scheme: light) { + :root[data-theme="auto"], html[data-theme="auto"], body[data-theme="auto"] { + --sg-tooltip-foreground: black; + --sg-tooltip-background: rgba(250, 250, 250, 0.9); + --sg-tooltip-border: #ccc transparent; + --sg-thumb-box-shadow-color: #6c757d40; + --sg-thumb-hover-border: #0069d9; + --sg-script-out: #888; + --sg-script-pre: #fafae2; + --sg-pytb-foreground: #000; + --sg-pytb-background: #ffe4e4; + --sg-pytb-border-color: #f66; + --sg-download-a-background-color: #ffc; + --sg-download-a-background-image: linear-gradient(to bottom, #ffc, #d5d57e); + --sg-download-a-border-color: 1px solid #c2c22d; + --sg-download-a-color: #000; + --sg-download-a-hover-background-color: #d5d57e; + --sg-download-a-hover-box-shadow-1: rgba(255, 255, 255, 0.1); + --sg-download-a-hover-box-shadow-2: rgba(0, 0, 0, 0.25); + } +} + +html[data-theme="dark"], body[data-theme="dark"] { + --sg-tooltip-foreground: white; + --sg-tooltip-background: rgba(10, 10, 10, 0.9); + --sg-tooltip-border: #333 transparent; + --sg-thumb-box-shadow-color: #79848d40; + --sg-thumb-hover-border: #003975; + --sg-script-out: rgb(179, 179, 179); + --sg-script-pre: #2e2e22; + --sg-pytb-foreground: #fff; + --sg-pytb-background: #1b1717; + --sg-pytb-border-color: #622; + --sg-download-a-background-color: #443; + --sg-download-a-background-image: linear-gradient(to bottom, #443, #221); + --sg-download-a-border-color: 1px solid #3a3a0d; + --sg-download-a-color: #fff; + --sg-download-a-hover-background-color: #616135; + --sg-download-a-hover-box-shadow-1: rgba(0, 0, 0, 0.1); + --sg-download-a-hover-box-shadow-2: rgba(255, 255, 255, 0.25); +} +@media(prefers-color-scheme: dark){ + html[data-theme="auto"], body[data-theme="auto"] { + --sg-tooltip-foreground: white; + --sg-tooltip-background: rgba(10, 10, 10, 0.9); + --sg-tooltip-border: #333 transparent; + --sg-thumb-box-shadow-color: #79848d40; + --sg-thumb-hover-border: #003975; + --sg-script-out: rgb(179, 179, 179); + --sg-script-pre: #2e2e22; + --sg-pytb-foreground: #fff; + --sg-pytb-background: #1b1717; + --sg-pytb-border-color: #622; + --sg-download-a-background-color: #443; + --sg-download-a-background-image: linear-gradient(to bottom, #443, #221); + --sg-download-a-border-color: 1px solid #3a3a0d; + --sg-download-a-color: #fff; + --sg-download-a-hover-background-color: #616135; + --sg-download-a-hover-box-shadow-1: rgba(0, 0, 0, 0.1); + --sg-download-a-hover-box-shadow-2: rgba(255, 255, 255, 0.25); + } +} + +.sphx-glr-thumbnails { + width: 100%; + margin: 0px 0px 20px 0px; + + /* align thumbnails on a grid */ + justify-content: space-between; + display: grid; + /* each grid column should be at least 160px (this will determine + the actual number of columns) and then take as much of the + remaining width as possible */ + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + gap: 15px; +} +.sphx-glr-thumbnails .toctree-wrapper { + /* hide empty toctree divs added to the DOM + by sphinx even though the toctree is hidden + (they would fill grid places with empty divs) */ + display: none; +} +.sphx-glr-thumbcontainer { + background: transparent; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + box-shadow: 0 0 10px var(--sg-thumb-box-shadow-color); + + /* useful to absolutely position link in div */ + position: relative; + + /* thumbnail width should include padding and borders + and take all available space */ + box-sizing: border-box; + width: 100%; + padding: 10px; + border: 1px solid transparent; + + /* align content in thumbnail */ + display: flex; + flex-direction: column; + align-items: center; + gap: 7px; +} +.sphx-glr-thumbcontainer p { + position: absolute; + top: 0; + left: 0; +} +.sphx-glr-thumbcontainer p, +.sphx-glr-thumbcontainer p a { + /* link should cover the whole thumbnail div */ + width: 100%; + height: 100%; +} +.sphx-glr-thumbcontainer p a span { + /* text within link should be masked + (we are just interested in the href) */ + display: none; +} +.sphx-glr-thumbcontainer:hover { + border: 1px solid; + border-color: var(--sg-thumb-hover-border); + cursor: pointer; +} +.sphx-glr-thumbcontainer a.internal { + bottom: 0; + display: block; + left: 0; + box-sizing: border-box; + padding: 150px 10px 0; + position: absolute; + right: 0; + top: 0; +} +/* Next one is to avoid Sphinx traditional theme to cover all the +thumbnail with its default link Background color */ +.sphx-glr-thumbcontainer a.internal:hover { + background-color: transparent; +} + +.sphx-glr-thumbcontainer p { + margin: 0 0 0.1em 0; +} +.sphx-glr-thumbcontainer .figure { + margin: 10px; + width: 160px; +} +.sphx-glr-thumbcontainer img { + display: inline; + max-height: 112px; + max-width: 160px; +} +.sphx-glr-thumbcontainer[tooltip]:hover:after { + background: var(--sg-tooltip-background); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + color: var(--sg-tooltip-foreground); + content: attr(tooltip); + padding: 10px; + z-index: 98; + width: 100%; + height: 100%; + position: absolute; + pointer-events: none; + top: 0; + box-sizing: border-box; + overflow: hidden; + backdrop-filter: blur(3px); +} + +.sphx-glr-script-out { + color: var(--sg-script-out); + display: flex; + gap: 0.5em; +} +.sphx-glr-script-out::before { + content: "Out:"; + /* These numbers come from the pre style in the pydata sphinx theme. This + * turns out to match perfectly on the rtd theme, but be a bit too low for + * the pydata sphinx theme. As I could not find a dimension to use that was + * scaled the same way, I just picked one option that worked pretty close for + * both. */ + line-height: 1.4; + padding-top: 10px; +} +.sphx-glr-script-out .highlight { + background-color: transparent; + /* These options make the div expand... */ + flex-grow: 1; + /* ... but also keep it from overflowing its flex container. */ + overflow: auto; +} +.sphx-glr-script-out .highlight pre { + background-color: var(--sg-script-pre); + border: 0; + max-height: 30em; + overflow: auto; + padding-left: 1ex; + /* This margin is necessary in the pydata sphinx theme because pre has a box + * shadow which would be clipped by the overflow:auto in the parent div + * above. */ + margin: 2px; + word-break: break-word; +} +.sphx-glr-script-out + p { + margin-top: 1.8em; +} +blockquote.sphx-glr-script-out { + margin-left: 0pt; +} +.sphx-glr-script-out.highlight-pytb .highlight pre { + color: var(--sg-pytb-foreground); + background-color: var(--sg-pytb-background); + border: 1px solid var(--sg-pytb-border-color); + margin-top: 10px; + padding: 7px; +} + +div.sphx-glr-footer { + text-align: center; +} + +div.sphx-glr-download { + margin: 1em auto; + vertical-align: middle; +} + +div.sphx-glr-download a { + background-color: var(--sg-download-a-background-color); + background-image: var(--sg-download-a-background-image); + border-radius: 4px; + border: 1px solid var(--sg-download-a-border-color); + color: var(--sg-download-a-color); + display: inline-block; + font-weight: bold; + padding: 1ex; + text-align: center; +} + +div.sphx-glr-download code.download { + display: inline-block; + white-space: normal; + word-break: normal; + overflow-wrap: break-word; + /* border and background are given by the enclosing 'a' */ + border: none; + background: none; +} + +div.sphx-glr-download a:hover { + box-shadow: inset 0 1px 0 var(--sg-download-a-hover-box-shadow-1), 0 1px 5px var(--sg-download-a-hover-box-shadow-2); + text-decoration: none; + background-image: none; + background-color: var(--sg-download-a-hover-background-color); +} + +.sphx-glr-example-title:target::before { + display: block; + content: ""; + margin-top: -50px; + height: 50px; + visibility: hidden; +} + +ul.sphx-glr-horizontal { + list-style: none; + padding: 0; +} +ul.sphx-glr-horizontal li { + display: inline; +} +ul.sphx-glr-horizontal img { + height: auto !important; +} + +.sphx-glr-single-img { + margin: auto; + display: block; + max-width: 100%; +} + +.sphx-glr-multi-img { + max-width: 42%; + height: auto; +} + +div.sphx-glr-animation { + margin: auto; + display: block; + max-width: 100%; +} +div.sphx-glr-animation .animation { + display: block; +} + +p.sphx-glr-signature a.reference.external { + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + padding: 3px; + font-size: 75%; + text-align: right; + margin-left: auto; + display: table; +} + +.sphx-glr-clear { + clear: both; +} + +a.sphx-glr-backref-instance { + text-decoration: none; +} diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/auto_examples/index.html b/auto_examples/index.html new file mode 100644 index 00000000..7503ddd2 --- /dev/null +++ b/auto_examples/index.html @@ -0,0 +1,148 @@ + + + + + + + Examples — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Examples

+

Below is a gallery of example metric-learn use cases.

+
+

Sandwich demo

+
Sandwich demo
+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ +

Gallery generated by Sphinx-Gallery

+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/auto_examples/plot_metric_learning_examples.html b/auto_examples/plot_metric_learning_examples.html new file mode 100644 index 00000000..6bf39b4b --- /dev/null +++ b/auto_examples/plot_metric_learning_examples.html @@ -0,0 +1,603 @@ + + + + + + + Algorithms walkthrough — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + +
+

Algorithms walkthrough

+

This is a small walkthrough which illustrates most of the Metric Learning +algorithms implemented in metric-learn by using them on synthetic data, +with some visualizations to provide intuitions into what they are designed +to achieve.

+
# License: BSD 3 clause
+# Authors: Bhargav Srinivasa Desikan <bhargavvader@gmail.com>
+#          William de Vazelhes <wdevazelhes@gmail.com>
+
+
+
+

Imports

+
+

Note

+

In order to show the charts of the examples you need a graphical +matplotlib backend installed. For intance, use pip install pyqt5 +to get Qt graphical interface or use your favorite one.

+
+
from sklearn.manifold import TSNE
+
+import metric_learn
+import numpy as np
+from sklearn.datasets import make_classification, make_regression
+
+# visualisation imports
+import matplotlib.pyplot as plt
+np.random.seed(42)
+
+
+
+
+

Loading our dataset and setting up plotting

+

We will be using a synthetic dataset to illustrate the plotting, +using the function sklearn.datasets.make_classification from +scikit-learn. The dataset will contain: +- 100 points in 3 classes with 2 clusters per class +- 5 features, among which 3 are informative (correlated with the class +labels) and two are random noise with large magnitude

+
X, y = make_classification(n_samples=100, n_classes=3, n_clusters_per_class=2,
+                           n_informative=3, class_sep=4., n_features=5,
+                           n_redundant=0, shuffle=True,
+                           scale=[1, 1, 20, 20, 20])
+
+
+

Note that the dimensionality of the data is 5, so to plot the +transformed data in 2D, we will use the t-sne algorithm. (See +sklearn.manifold.TSNE).

+
def plot_tsne(X, y, colormap=plt.cm.Paired):
+    plt.figure(figsize=(8, 6))
+
+    # clean the figure
+    plt.clf()
+
+    tsne = TSNE()
+    X_embedded = tsne.fit_transform(X)
+    plt.scatter(X_embedded[:, 0], X_embedded[:, 1], c=y, cmap=colormap)
+
+    plt.xticks(())
+    plt.yticks(())
+
+    plt.show()
+
+
+

Let’s now plot the dataset as is.

+
plot_tsne(X, y)
+
+
+plot metric learning examples

We can see that the classes appear mixed up: this is because t-sne +is based on preserving the original neighborhood of points in the embedding +space, but this original neighborhood is based on the euclidean +distance in the input space, in which the contribution of the noisy +features is high. So even if points from the same class are close to each +other in some subspace of the input space, this is not the case when +considering all dimensions of the input space.

+
+
+

Metric Learning

+

Why is Metric Learning useful? We can, with prior knowledge of which +points are supposed to be closer, figure out a better way to compute +distances between points for the task at hand. Especially in higher +dimensions when Euclidean distances are a poor way to measure distance, this +becomes very useful.

+

Basically, we learn this distance: +\(D(x, x') = \sqrt{(x-x')^\top M(x-x')}\). And we learn the parameters +\(M\) of this distance to satisfy certain constraints on the distance +between points, for example requiring that points of the same class are +close together and points of different class are far away.

+

For more information, check the What is Metric Learning? section +from the documentation. Some good reading material can also be found +here. It serves as a +good literature review of Metric Learning.

+

We will briefly explain the metric learning algorithms implemented by +metric-learn, before providing some examples for its usage, and also +discuss how to perform metric learning with weaker supervision than class +labels.

+

Metric-learn can be easily integrated with your other machine learning +pipelines, and follows scikit-learn conventions.

+
+
+

Large Margin Nearest Neighbour

+

LMNN is a metric learning algorithm primarily designed for k-nearest +neighbor classification. The algorithm is based on semidefinite +programming, a sub-class of convex programming (as most Metric Learning +algorithms are).

+

The main intuition behind LMNN is to learn a pseudometric under which +all data instances in the training set are surrounded by at least k +instances that share the same class label. If this is achieved, the +leave-one-out error (a special case of cross validation) is minimized. +You’ll notice that the points from the same labels are closer together, +but they are not necessary in a same cluster. This is particular to LMNN +and we’ll see that some other algorithms implicitly enforce points from +the same class to cluster together.

+
    +
  • See more in the User Guide

  • +
  • See more in the documentation of the class LMNN

  • +
+
+

Fit and then transform!

+
# setting up LMNN
+lmnn = metric_learn.LMNN(n_neighbors=5, learn_rate=1e-6)
+
+# fit the data!
+lmnn.fit(X, y)
+
+# transform our input space
+X_lmnn = lmnn.transform(X)
+
+
+

So what have we learned? The matrix \(M\) we talked about before.

+

Now let us plot the transformed space - this tells us what the original +space looks like after being transformed with the new learned metric.

+
plot_tsne(X_lmnn, y)
+
+
+plot metric learning examples

Pretty neat, huh?

+

The rest of this notebook will briefly explain the other Metric Learning +algorithms before plotting them. Also, while we have first run fit +and then transform to see our data transformed, we can also use +fit_transform. The rest of the examples and illustrations will use +fit_transform.

+
+
+
+

Information Theoretic Metric Learning

+

ITML uses a regularizer that automatically enforces a Semi-Definite +Positive Matrix condition - the LogDet divergence. It uses soft +must-link or cannot-link constraints, and a simple algorithm based on +Bregman projections. Unlike LMNN, ITML will implicitly enforce points from +the same class to belong to the same cluster, as you can see below.

+
    +
  • See more in the User Guide

  • +
  • See more in the documentation of the class ITML

  • +
+
itml = metric_learn.ITML_Supervised()
+X_itml = itml.fit_transform(X, y)
+
+plot_tsne(X_itml, y)
+
+
+plot metric learning examples
+
+

Mahalanobis Metric for Clustering

+

MMC is an algorithm that will try to minimize the distance between similar +points, while ensuring that the sum of distances between dissimilar points is +higher than a threshold. This is done by optimizing a cost function +subject to an inequality constraint.

+
    +
  • See more in the User Guide

  • +
  • See more in the documentation of the class MMC

  • +
+
mmc = metric_learn.MMC_Supervised()
+X_mmc = mmc.fit_transform(X, y)
+
+plot_tsne(X_mmc, y)
+
+
+plot metric learning examples
+
+

Sparse Determinant Metric Learning

+

Implements an efficient sparse metric learning algorithm in high +dimensional space via an \(l_1\)-penalized log-determinant +regularization. Compared to the most existing distance metric learning +algorithms, the algorithm exploits the sparsity nature underlying the +intrinsic high dimensional feature space.

+
    +
  • See more in the User Guide

  • +
  • See more in the documentation of the class SDML

  • +
+
sdml = metric_learn.SDML_Supervised(sparsity_param=0.1, balance_param=0.0015,
+                                    prior='covariance')
+X_sdml = sdml.fit_transform(X, y)
+
+plot_tsne(X_sdml, y)
+
+
+plot metric learning examples
/Users/william.vezelhes/miniconda3/envs/docenvbis/lib/python3.11/site-packages/sklearn/covariance/_graph_lasso.py:329: FutureWarning: The cov_init parameter is deprecated in 1.3 and will be removed in 1.5. It does not have any effect.
+  warnings.warn(
+
+
+
+
+

Least Squares Metric Learning

+

LSML is a simple, yet effective, algorithm that learns a Mahalanobis +metric from a given set of relative comparisons. This is done by +formulating and minimizing a convex loss function that corresponds to +the sum of squared hinge loss of violated constraints.

+
    +
  • See more in the User Guide

  • +
  • See more in the documentation of the class LSML

  • +
+
lsml = metric_learn.LSML_Supervised(tol=0.0001, max_iter=10000,
+                                    prior='covariance')
+X_lsml = lsml.fit_transform(X, y)
+
+plot_tsne(X_lsml, y)
+
+
+plot metric learning examples
+
+

Neighborhood Components Analysis

+

NCA is an extremly popular metric learning algorithm.

+

Neighborhood components analysis aims at “learning” a distance metric +by finding a linear transformation of input data such that the average +leave-one-out (LOO) classification performance of a soft-nearest +neighbors rule is maximized in the transformed space. The key insight to +the algorithm is that a matrix \(A\) corresponding to the +transformation can be found by defining a differentiable objective function +for \(A\), followed by use of an iterative solver such as +scipy.optimize.fmin_l_bfgs_b. Like LMNN, this algorithm does not try to +cluster points from the same class in a unique cluster, because it +enforces conditions at a local neighborhood scale.

+
    +
  • See more in the User Guide

  • +
  • See more in the documentation of the class NCA

  • +
+
nca = metric_learn.NCA(max_iter=1000)
+X_nca = nca.fit_transform(X, y)
+
+plot_tsne(X_nca, y)
+
+
+plot metric learning examples
+
+

Local Fisher Discriminant Analysis

+

LFDA is a linear supervised dimensionality reduction method. It is +particularly useful when dealing with multimodality, where one ore more +classes consist of separate clusters in input space. The core +optimization problem of LFDA is solved as a generalized eigenvalue +problem. Like LMNN, and NCA, this algorithm does not try to cluster points +from the same class in a unique cluster.

+
    +
  • See more in the User Guide

  • +
  • See more in the documentation of the class LFDA

  • +
+
lfda = metric_learn.LFDA(k=2, n_components=2)
+X_lfda = lfda.fit_transform(X, y)
+
+plot_tsne(X_lfda, y)
+
+
+plot metric learning examples
+
+

Relative Components Analysis

+

RCA is another one of the older algorithms. It learns a full rank +Mahalanobis distance metric based on a weighted sum of in-class +covariance matrices. It applies a global linear transformation to assign +large weights to relevant dimensions and low weights to irrelevant +dimensions. Those relevant dimensions are estimated using “chunklets”, +subsets of points that are known to belong to the same class.

+
    +
  • See more in the User Guide

  • +
  • See more in the documentation of the class RCA

  • +
+
rca = metric_learn.RCA_Supervised(n_chunks=30, chunk_size=2)
+X_rca = rca.fit_transform(X, y)
+
+plot_tsne(X_rca, y)
+
+
+plot metric learning examples
+
+

Regression example: Metric Learning for Kernel Regression

+

The previous algorithms took as input a dataset with class labels. Metric +learning can also be useful for regression, when the labels are real numbers. +An algorithm very similar to NCA but for regression is Metric +Learning for Kernel Regression (MLKR). It will optimize for the average +leave-one-out regression performance from a soft-nearest neighbors +regression.

+
    +
  • See more in the User Guide

  • +
  • See more in the documentation of the class MLKR

  • +
+

To illustrate MLKR, let’s use the dataset +sklearn.datasets.make_regression the same way as we did with the +classification before. The dataset will contain: 100 points of 5 features +each, among which 3 are informative (i.e., used to generate the +regression target from a linear model), and two are random noise with the +same magnitude.

+
X_reg, y_reg = make_regression(n_samples=100, n_informative=3, n_features=5,
+                               shuffle=True)
+
+
+

Let’s plot the dataset as is

+
plot_tsne(X_reg, y_reg, plt.cm.Oranges)
+
+
+plot metric learning examples

And let’s plot the dataset after transformation by MLKR:

+
mlkr = metric_learn.MLKR()
+X_mlkr = mlkr.fit_transform(X_reg, y_reg)
+plot_tsne(X_mlkr, y_reg, plt.cm.Oranges)
+
+
+plot metric learning examples

Points that have the same value to regress are now closer to each +other ! This would improve the performance of +sklearn.neighbors.KNeighborsRegressor for instance.

+
+
+

Metric Learning from Weaker Supervision

+

To learn the metric, so far we have always given the labels of the +data to supervise the algorithms. However, in many applications, +it is easier to obtain information about whether two samples are +similar or dissimilar. For instance, when annotating a dataset of face +images, it is easier for an annotator to tell if two faces belong to the same +person or not, rather than finding the ID of the face among a huge database +of every person’s faces. +Note that for some problems (e.g., in information +retrieval where the goal is to rank documents by similarity to a query +document), there is no notion of individual label but one can gather +information on which pairs of points are similar or dissimilar. +Fortunately, one of the strength of metric learning is the ability to +learn from such weaker supervision. Indeed, some of the algorithms we’ve +used above have alternate ways to pass some supervision about the metric +we want to learn. The way to go is to pass a 2D array pairs of pairs, +as well as an array of labels pairs_labels such that for each i between +0 and n_pairs we want X[pairs[i, 0], :] and X[pairs[i, 1], :] to be +similar if pairs_labels[i] == 1, and we want them to be dissimilar if +pairs_labels[i] == -1. In other words, we +want to enforce a metric that projects similar points closer together and +dissimilar points further away from each other. This kind of input is +possible for ITML, SDML, and MMC. See Weakly Supervised Metric Learning for +details on other kinds of weak supervision that some algorithms can work +with.

+

For the purpose of this example, we’re going to explicitly create these +pairwise constraints through the labels we have, i.e. y. +Do keep in mind that we are doing this method because we know the labels +- we can actually create the constraints any way we want to depending on +the data!

+

Note that this is what metric-learn did under the hood in the previous +examples (do check out the +constraints module!) - but we’ll try our own version of this. We’re +going to go ahead and assume that two points labeled the same will be +closer than two points in different labels.

+
def create_constraints(labels):
+    import itertools
+    import random
+
+    # aggregate indices of same class
+    zeros = np.where(y == 0)[0]
+    ones = np.where(y == 1)[0]
+    twos = np.where(y == 2)[0]
+    # make permutations of all those points in the same class
+    zeros_ = list(itertools.combinations(zeros, 2))
+    ones_ = list(itertools.combinations(ones, 2))
+    twos_ = list(itertools.combinations(twos, 2))
+    # put them together!
+    sim = np.array(zeros_ + ones_ + twos_)
+
+    # similarily, put together indices in different classes
+    dis = []
+    for zero in zeros:
+        for one in ones:
+            dis.append((zero, one))
+        for two in twos:
+            dis.append((zero, two))
+    for one in ones:
+        for two in twos:
+            dis.append((one, two))
+
+    # pick up just enough dissimilar examples as we have similar examples
+    dis = np.array(random.sample(dis, len(sim)))
+
+    # return an array of pairs of indices of shape=(2*len(sim), 2), and the
+    # corresponding labels, array of shape=(2*len(sim))
+    # Each pair of similar points have a label of +1 and each pair of
+    # dissimilar points have a label of -1
+    return (np.vstack([np.column_stack([sim[:, 0], sim[:, 1]]),
+                       np.column_stack([dis[:, 0], dis[:, 1]])]),
+            np.concatenate([np.ones(len(sim)), -np.ones(len(sim))]))
+
+
+pairs, pairs_labels = create_constraints(y)
+
+
+

Now that we’ve created our constraints, let’s see what it looks like!

+
print(pairs)
+print(pairs_labels)
+
+
+
[[ 0  6]
+ [ 0  9]
+ [ 0 10]
+ ...
+ [77 65]
+ [72  1]
+ [55 71]]
+[ 1.  1.  1. ... -1. -1. -1.]
+
+
+

Using our constraints, let’s now train ITML again. Note that we are no +longer calling the supervised class ITML_Supervised but the more generic +(weakly-supervised) ITML, which +takes the dataset X through the preprocessor argument (see +this section of the documentation to learn +about more advanced uses of preprocessor) and the pair information pairs +and pairs_labels in the fit method.

+
itml = metric_learn.ITML(preprocessor=X)
+itml.fit(pairs, pairs_labels)
+
+X_itml = itml.transform(X)
+
+plot_tsne(X_itml, y)
+
+
+plot metric learning examples

And that’s the result of ITML after being trained on our manually +constructed constraints! A bit different from our old result, but not too +different.

+

RCA and LSML also have their own specific ways of taking in inputs - +it’s worth one’s while to poke around in the constraints.py file to see +how exactly this is going on.

+

Finally, one of the main advantages of metric-learn is its out-of-the box +compatibility with scikit-learn, for doing model selection, +cross-validation, and scoring for instance. Indeed, supervised algorithms are +regular sklearn.base.TransformerMixin that can be plugged into any +pipeline or cross-validation procedure. And weakly-supervised estimators are +also compatible with scikit-learn, since their input dataset format described +above allows to be sliced along the first dimension when doing +cross-validations (see also this section). You +can also look at some use cases where you could combine +metric-learn with scikit-learn estimators.

+

This brings us to the end of this tutorial! Have fun Metric Learning :)

+

Total running time of the script: (0 minutes 32.400 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/auto_examples/plot_sandwich.html b/auto_examples/plot_sandwich.html new file mode 100644 index 00000000..35eae29c --- /dev/null +++ b/auto_examples/plot_sandwich.html @@ -0,0 +1,251 @@ + + + + + + + Sandwich demo — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + +
+

Sandwich demo

+

Sandwich demo based on code from http://nbviewer.ipython.org/6576096

+
+

Note

+

In order to show the charts of the examples you need a graphical +matplotlib backend installed. For intance, use pip install pyqt5 +to get Qt graphical interface or use your favorite one.

+
+
import numpy as np
+from matplotlib import pyplot as plt
+from sklearn.metrics import pairwise_distances
+from sklearn.neighbors import NearestNeighbors
+
+from metric_learn import (LMNN, ITML_Supervised, LSML_Supervised,
+                          SDML_Supervised)
+
+
+def sandwich_demo():
+  x, y = sandwich_data()
+  knn = nearest_neighbors(x, k=2)
+  ax = plt.subplot(3, 1, 1)  # take the whole top row
+  plot_sandwich_data(x, y, ax)
+  plot_neighborhood_graph(x, knn, y, ax)
+  ax.set_title('input space')
+  ax.set_aspect('equal')
+  ax.set_xticks([])
+  ax.set_yticks([])
+
+  mls = [
+      LMNN(),
+      ITML_Supervised(n_constraints=200),
+      SDML_Supervised(n_constraints=200, balance_param=0.001),
+      LSML_Supervised(n_constraints=200),
+  ]
+
+  for ax_num, ml in enumerate(mls, start=3):
+    ml.fit(x, y)
+    tx = ml.transform(x)
+    ml_knn = nearest_neighbors(tx, k=2)
+    ax = plt.subplot(3, 2, ax_num)
+    plot_sandwich_data(tx, y, axis=ax)
+    plot_neighborhood_graph(tx, ml_knn, y, axis=ax)
+    ax.set_title(ml.__class__.__name__)
+    ax.set_xticks([])
+    ax.set_yticks([])
+  plt.show()
+
+
+# TODO: use this somewhere
+def visualize_class_separation(X, labels):
+  _, (ax1, ax2) = plt.subplots(ncols=2)
+  label_order = np.argsort(labels)
+  ax1.imshow(pairwise_distances(X[label_order]), interpolation='nearest')
+  ax2.imshow(pairwise_distances(labels[label_order, None]),
+             interpolation='nearest')
+
+
+def nearest_neighbors(X, k=5):
+  knn = NearestNeighbors(n_neighbors=k)
+  knn.fit(X)
+  return knn.kneighbors(X, return_distance=False)
+
+
+def sandwich_data():
+  # number of distinct classes
+  num_classes = 6
+  # number of points per class
+  num_points = 9
+  # distance between layers, the points of each class are in a layer
+  dist = 0.7
+
+  data = np.zeros((num_classes, num_points, 2), dtype=float)
+  labels = np.zeros((num_classes, num_points), dtype=int)
+
+  x_centers = np.arange(num_points, dtype=float) - num_points / 2
+  y_centers = dist * (np.arange(num_classes, dtype=float) - num_classes / 2)
+  for i, yc in enumerate(y_centers):
+    for k, xc in enumerate(x_centers):
+      data[i, k, 0] = np.random.normal(xc, 0.1)
+      data[i, k, 1] = np.random.normal(yc, 0.1)
+    labels[i, :] = i
+  return data.reshape((-1, 2)), labels.ravel()
+
+
+def plot_sandwich_data(x, y, axis=plt, colors='rbgmky'):
+  for idx, val in enumerate(np.unique(y)):
+    xi = x[y == val]
+    axis.scatter(*xi.T, s=50, facecolors='none', edgecolors=colors[idx])
+
+
+def plot_neighborhood_graph(x, nn, y, axis=plt, colors='rbgmky'):
+  for i, a in enumerate(x):
+    b = x[nn[i, 1]]
+    axis.plot((a[0], b[0]), (a[1], b[1]), colors[y[i]])
+
+
+if __name__ == '__main__':
+  sandwich_demo()
+
+
+input space, LMNN, ITML_Supervised, SDML_Supervised, LSML_Supervised
/Users/william.vezelhes/metric-learn/metric_learn/constraints.py:224: UserWarning: Only generated 199 positive constraints (requested 200)
+  warnings.warn("Only generated %d %s constraints (requested %d)" % (
+/Users/william.vezelhes/miniconda3/envs/docenvbis/lib/python3.11/site-packages/sklearn/covariance/_graph_lasso.py:329: FutureWarning: The cov_init parameter is deprecated in 1.3 and will be removed in 1.5. It does not have any effect.
+  warnings.warn(
+
+
+

Total running time of the script: (0 minutes 3.314 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/auto_examples/sg_execution_times.html b/auto_examples/sg_execution_times.html new file mode 100644 index 00000000..bc8abf3a --- /dev/null +++ b/auto_examples/sg_execution_times.html @@ -0,0 +1,134 @@ + + + + + + + Computation times — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Computation times

+

00:35.715 total execution time for auto_examples files:

+ + + + + + + + + + + +

Algorithms walkthrough (plot_metric_learning_examples.py)

00:32.400

0.0 MB

Sandwich demo (plot_sandwich.py)

00:03.314

0.0 MB

+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/.gitignore b/doc/.gitignore deleted file mode 100644 index 69fa449d..00000000 --- a/doc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_build/ diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 9e36845f..00000000 --- a/doc/Makefile +++ /dev/null @@ -1,192 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - @echo " coverage to run coverage check of the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/metric-learn.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/metric-learn.qhc" - -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/metric-learn" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/metric-learn" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/doc/_templates/.gitignore b/doc/_templates/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/doc/conf.py b/doc/conf.py deleted file mode 100644 index 8c6a79c2..00000000 --- a/doc/conf.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- - -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.autosummary', - 'sphinx.ext.todo', - 'sphinx.ext.viewcode', - 'sphinx.ext.mathjax', - 'numpydoc', -] - -templates_path = ['_templates'] -source_suffix = '.rst' -master_doc = 'index' - -# General information about the project. -project = u'metric-learn' -copyright = u'2015, CJ Carey and Yuan Tang' -author = u'CJ Carey and Yuan Tang' -version = '0.1.0' -release = '0.1.0' -language = 'en' - -exclude_patterns = ['_build'] -pygments_style = 'sphinx' -todo_include_todos = True -numpydoc_show_class_members = False - -# Options for HTML output -html_theme = 'sphinx_rtd_theme' -html_static_path = ['_static'] -htmlhelp_basename = 'metric-learndoc' - diff --git a/doc/index.rst b/doc/index.rst deleted file mode 100644 index b9c0c209..00000000 --- a/doc/index.rst +++ /dev/null @@ -1,79 +0,0 @@ -metric-learn: Metric Learning in Python -======================================= -|License| |PyPI version| - -Distance metrics are widely used in the machine learning literature. -Traditionally, practicioners would choose a standard distance metric -(Euclidean, City-Block, Cosine, etc.) using a priori knowledge of -the domain. -Distance metric learning (or simply, metric learning) is the sub-field of -machine learning dedicated to automatically constructing optimal distance -metrics. - -This package contains efficient Python implementations of several popular -metric learning algorithms. - -.. toctree:: - :caption: Algorithms - :maxdepth: 1 - - metric_learn.lmnn - metric_learn.itml - metric_learn.sdml - metric_learn.lsml - metric_learn.nca - metric_learn.lfda - metric_learn.rca - -Each metric supports the following methods: - -- ``fit(...)``, which learns the model. -- ``transformer()``, which returns a transformation matrix - :math:`L \in \mathbb{R}^{D \times d}`, which can be used to convert a - data matrix :math:`X \in \mathbb{R}^{n \times d}` to the - :math:`D`-dimensional learned metric space :math:`X L^{\top}`, - in which standard Euclidean distances may be used. -- ``transform(X)``, which applies the aforementioned transformation. -- ``metric()``, which returns a Mahalanobis matrix - :math:`M = L^{\top}L` such that distance between vectors ``x`` and - ``y`` can be computed as :math:`\left(x-y\right)M\left(x-y\right)`. - - -Installation and Setup -====================== - -Run ``pip install metric-learn`` to download and install from PyPI. - -Alternately, download the source repository and run: - -- ``python setup.py install`` for default installation. -- ``python setup.py test`` to run all tests. - -**Dependencies** - -- Python 2.6+ -- numpy, scipy, scikit-learn -- (for running the examples only: matplotlib) - -**Notes** - -If a recent version of the Shogun Python modular (``modshogun``) library -is available, the LMNN implementation will use the fast C++ version from -there. The two implementations differ slightly, and the C++ version is -more complete. - -Naviagtion ----------- - -:ref:`genindex` | :ref:`modindex` | :ref:`search` - -.. toctree:: - :maxdepth: 4 - :hidden: - - Package Overview - -.. |PyPI version| image:: https://badge.fury.io/py/metric-learn.svg - :target: http://badge.fury.io/py/metric-learn -.. |License| image:: http://img.shields.io/:license-mit-blue.svg?style=flat - :target: http://badges.mit-license.org diff --git a/doc/make.bat b/doc/make.bat deleted file mode 100644 index 6623532f..00000000 --- a/doc/make.bat +++ /dev/null @@ -1,263 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -set I18NSPHINXOPTS=%SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - echo. coverage to run coverage check of the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -REM Check if sphinx-build is available and fallback to Python version if any -%SPHINXBUILD% 2> nul -if errorlevel 9009 goto sphinx_python -goto sphinx_ok - -:sphinx_python - -set SPHINXBUILD=python -m sphinx.__init__ -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -:sphinx_ok - - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\metric-learn.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\metric-learn.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %~dp0 - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %~dp0 - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "coverage" ( - %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage - if errorlevel 1 exit /b 1 - echo. - echo.Testing of coverage in the sources finished, look at the ^ -results in %BUILDDIR%/coverage/python.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end diff --git a/doc/metric_learn.base_metric.rst b/doc/metric_learn.base_metric.rst deleted file mode 100644 index 050a360b..00000000 --- a/doc/metric_learn.base_metric.rst +++ /dev/null @@ -1,7 +0,0 @@ -metric_learn.base_metric module -=============================== - -.. automodule:: metric_learn.base_metric - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/metric_learn.itml.rst b/doc/metric_learn.itml.rst deleted file mode 100644 index 6f4cf740..00000000 --- a/doc/metric_learn.itml.rst +++ /dev/null @@ -1,31 +0,0 @@ -Information Theoretic Metric Learning (ITML) -============================================ - -.. automodule:: metric_learn.itml - :members: - :undoc-members: - :inherited-members: - :show-inheritance: - -Example Code ------------- - -:: - - import numpy as np - from metric_learn import ITML - from sklearn.datasets import load_iris - - iris_data = load_iris() - X = iris_data['data'] - Y = iris_data['target'] - - itml = ITML() - - num_constraints = 200 - C = ITML.prepare_constraints(Y, X.shape[0], num_constraints) - itml.fit(X, C, verbose=False) - -References ----------- -`Information-theoretic Metric Learning `_ Jason V. Davis, et al. diff --git a/doc/metric_learn.lfda.rst b/doc/metric_learn.lfda.rst deleted file mode 100644 index 95cde90d..00000000 --- a/doc/metric_learn.lfda.rst +++ /dev/null @@ -1,30 +0,0 @@ -Local Fisher Discriminant Analysis (LFDA) -========================================= - -.. automodule:: metric_learn.lfda - :members: - :undoc-members: - :inherited-members: - :show-inheritance: - -Example Code ------------- - -:: - - import numpy as np - from metric_learn import LFDA - from sklearn.datasets import load_iris - - iris_data = load_iris() - X = iris_data['data'] - Y = iris_data['target'] - - lfda = LFDA(k=2, dim=2) - lfda.fit(X, Y) - -References ------------------- -`Dimensionality Reduction of Multimodal Labeled Data by Local Fisher Discriminant Analysis `_ Masashi Sugiyama. - -`Local Fisher Discriminant Analysis on Beer Style Clustering `_ Yuan Tang. diff --git a/doc/metric_learn.lmnn.rst b/doc/metric_learn.lmnn.rst deleted file mode 100644 index 4062bfa0..00000000 --- a/doc/metric_learn.lmnn.rst +++ /dev/null @@ -1,33 +0,0 @@ -Large Margin Nearest Neighbor (LMNN) -==================================== - -.. automodule:: metric_learn.lmnn - :members: - :undoc-members: - :inherited-members: - :show-inheritance: - -Example Code ------------- - -:: - - import numpy as np - from metric_learn import LMNN - from sklearn.datasets import load_iris - - iris_data = load_iris() - X = iris_data['data'] - Y = iris_data['target'] - - lmnn = LMNN(k=5, learn_rate=1e-6) - lmnn.fit(X, Y, verbose=False) - -If a recent version of the Shogun Python modular (``modshogun``) library -is available, the LMNN implementation will use the fast C++ version from -there. Otherwise, the included pure-Python version will be used. -The two implementations differ slightly, and the C++ version is more complete. - -References ----------- -`Distance Metric Learning for Large Margin Nearest Neighbor Classification `_ Kilian Q. Weinberger, John Blitzer, Lawrence K. Saul diff --git a/doc/metric_learn.lsml.rst b/doc/metric_learn.lsml.rst deleted file mode 100644 index 4409e562..00000000 --- a/doc/metric_learn.lsml.rst +++ /dev/null @@ -1,29 +0,0 @@ -Least Squares Metric Learning (LSML) -==================================== - -.. automodule:: metric_learn.lsml - :members: - :undoc-members: - :inherited-members: - :show-inheritance: - -Example Code ------------- - -:: - - import numpy as np - from metric_learn import LSML - from sklearn.datasets import load_iris - - iris_data = load_iris() - X = iris_data['data'] - Y = iris_data['target'] - - lsml = LSML() - C = LSML.prepare_constraints(Y, 200) - isml.fit(X, C, verbose=False) - -References ----------- - diff --git a/doc/metric_learn.nca.rst b/doc/metric_learn.nca.rst deleted file mode 100644 index 6a2675e5..00000000 --- a/doc/metric_learn.nca.rst +++ /dev/null @@ -1,28 +0,0 @@ -Neighborhood Components Analysis (NCA) -====================================== - -.. automodule:: metric_learn.nca - :members: - :undoc-members: - :inherited-members: - :show-inheritance: - -Example Code ------------- - -:: - - import numpy as np - from metric_learn import NCA - from sklearn.datasets import load_iris - - iris_data = load_iris() - X = iris_data['data'] - Y = iris_data['target'] - - nca = NCA(max_iter=1000, learning_rate=0.01) - nca.fit(X, Y) - -References ----------- - diff --git a/doc/metric_learn.rca.rst b/doc/metric_learn.rca.rst deleted file mode 100644 index a73c6e7c..00000000 --- a/doc/metric_learn.rca.rst +++ /dev/null @@ -1,29 +0,0 @@ -Relative Components Analysis (RCA) -================================== - -.. automodule:: metric_learn.rca - :members: - :undoc-members: - :inherited-members: - :show-inheritance: - -Example Code ------------- - -:: - - import numpy as np - from metric_learn import RCA - from sklearn.datasets import load_iris - - iris_data = load_iris() - X = iris_data['data'] - Y = iris_data['target'] - - rca = RCA() - C = RCA.prepare_constraints(Y, num_chunks=30, chunk_size=2) - rca.fit(X, C) - -References ------------------- -`Adjustment learning and relevant component analysis `_ Noam Shental, et al. diff --git a/doc/metric_learn.rst b/doc/metric_learn.rst deleted file mode 100644 index 226fd324..00000000 --- a/doc/metric_learn.rst +++ /dev/null @@ -1,24 +0,0 @@ -metric_learn package -==================== - -Submodules ----------- - -.. toctree:: - - metric_learn.base_metric - metric_learn.itml - metric_learn.lfda - metric_learn.lmnn - metric_learn.lsml - metric_learn.nca - metric_learn.rca - metric_learn.sdml - -Module contents ---------------- - -.. automodule:: metric_learn - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/metric_learn.sdml.rst b/doc/metric_learn.sdml.rst deleted file mode 100644 index de48fec5..00000000 --- a/doc/metric_learn.sdml.rst +++ /dev/null @@ -1,28 +0,0 @@ -Sparse Determinant Metric Learning (SDML) -========================================= - -.. automodule:: metric_learn.sdml - :members: - :undoc-members: - :inherited-members: - :show-inheritance: - -Example Code ------------- - -:: - - import numpy as np - from metric_learn import SDML - from sklearn.datasets import load_iris - - iris_data = load_iris() - X = iris_data['data'] - Y = iris_data['target'] - - sdml = SDML() - W = SDML.prepare_constraints(Y, X.shape[0], 1500) - sdml.fit(X, W) - -References ------------------- diff --git a/examples/sandwich.py b/examples/sandwich.py deleted file mode 100644 index 3f12618c..00000000 --- a/examples/sandwich.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -Sandwich demo based on code from http://nbviewer.ipython.org/6576096 -""" - -import numpy as np -from numpy.random import normal -import matplotlib.pyplot as pyplot -from sklearn.metrics import pairwise_distances -from sklearn.neighbors import NearestNeighbors - -from metric_learn import ITML, LMNN, LSML, SDML - - -def sandwich_demo(): - x, y = sandwich_data() - knn = nearest_neighbors(x, k=2) - ax = pyplot.subplot(3, 1, 1) # take the whole top row - plot_sandwich_data(x, y, ax) - plot_neighborhood_graph(x, knn, y, ax) - ax.set_title('input space') - ax.set_aspect('equal') - ax.set_xticks([]) - ax.set_yticks([]) - - num_constraints = 60 - mls = [ - (LMNN(), (x, y)), - (ITML(), (x, ITML.prepare_constraints(y, len(x), num_constraints))), - (SDML(), (x, SDML.prepare_constraints(y, len(x), num_constraints))), - (LSML(), (x, LSML.prepare_constraints(y, num_constraints))) - ] - - for ax_num, (ml,args) in zip(xrange(3,7), mls): - ml.fit(*args) - tx = ml.transform() - ml_knn = nearest_neighbors(tx, k=2) - ax = pyplot.subplot(3,2,ax_num) - plot_sandwich_data(tx, y, ax) - plot_neighborhood_graph(tx, ml_knn, y, ax) - ax.set_title('%s space' % ml.__class__.__name__) - ax.set_xticks([]) - ax.set_yticks([]) - pyplot.show() - - -# TODO: use this somewhere -def visualize_class_separation(X, labels): - _, (ax1,ax2) = pyplot.subplots(ncols=2) - label_order = np.argsort(labels) - ax1.imshow(pairwise_distances(X[label_order]), interpolation='nearest') - ax2.imshow(pairwise_distances(labels[label_order,None]), - interpolation='nearest') - pyplot.show() - - -def nearest_neighbors(X, k=5): - knn = NearestNeighbors(n_neighbors=k) - knn.fit(X) - return knn.kneighbors(X, return_distance=False) - - -def sandwich_data(): - # number of distinct classes - num_classes = 6 - # number of points per class - num_points = 9 - # distance between layers, the points of each class are in a layer - dist = 0.7 - # memory pre-allocation - x = np.zeros((num_classes*num_points, 2)) - y = np.zeros(num_classes*num_points, dtype=int) - for i,j in zip(xrange(num_classes), xrange(-num_classes//2,num_classes//2+1)): - for k,l in zip(xrange(num_points), xrange(-num_points//2,num_points//2+1)): - x[i*num_points + k, :] = np.array([normal(l, 0.1), normal(dist*j, 0.1)]) - y[i*num_points:i*num_points + num_points] = i - return x,y - - -def plot_sandwich_data(x, y, axis=pyplot, cols='rbgmky'): - for idx,val in enumerate(np.unique(y)): - xi = x[y==val] - axis.scatter(xi[:,0], xi[:,1], s=50, facecolors='none',edgecolors=cols[idx]) - - -def plot_neighborhood_graph(x, nn, y, axis=pyplot, cols='rbgmky'): - for i in xrange(x.shape[0]): - xs = [x[i,0], x[nn[i,1], 0]] - ys = [x[i,1], x[nn[i,1], 1]] - axis.plot(xs, ys, cols[y[i]]) - - -if __name__ == '__main__': - sandwich_demo() diff --git a/generated/metric_learn.Constraints.html b/generated/metric_learn.Constraints.html new file mode 100644 index 00000000..80c0020f --- /dev/null +++ b/generated/metric_learn.Constraints.html @@ -0,0 +1,285 @@ + + + + + + + metric_learn.Constraints — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.Constraints

+
+
+class metric_learn.Constraints(partial_labels)[source]
+

Class to build constraints from labeled data.

+

See more in the User Guide.

+
+
Parameters:
+
+
partial_labelsnumpy.ndarray of ints, shape=(n_samples,)

Array of labels, with -1 indicating unknown label.

+
+
+
+
Attributes:
+
+
partial_labelsnumpy.ndarray of ints, shape=(n_samples,)

Array of labels, with -1 indicating unknown label.

+
+
+
+
+

Methods

+ + + + + + + + + + + + +

chunks([n_chunks, chunk_size, random_state, ...])

Generates chunks from labeled data.

generate_knntriplets(X, k_genuine, k_impostor)

Generates triplets from labeled data.

positive_negative_pairs(n_constraints[, ...])

Generates positive pairs and negative pairs from labeled data.

+
+
+__init__(partial_labels)[source]
+
+ +
+
+chunks(n_chunks=100, chunk_size=2, random_state=None, num_chunks='deprecated')[source]
+

Generates chunks from labeled data.

+

Each of n_chunks chunks is composed of chunk_size points from +the same class drawn at random. Each point can belong to at most 1 chunk.

+

In the case where there is not enough points to generate n_chunks +chunks of size chunk_size, a ValueError will be raised.

+
+
Parameters:
+
+
n_chunksint, optional (default=100)

Number of chunks to generate.

+
+
chunk_sizeint, optional (default=2)

Number of points in each chunk.

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int.

+
+
num_chunksRenamed to n_chunks. Will be deprecated in 0.7.0
+
+
+
Returns:
+
+
chunksarray-like, shape=(n_samples,)

1D array of chunk indicators, where -1 indicates that the point does not +belong to any chunk.

+
+
+
+
+
+ +
+
+generate_knntriplets(X, k_genuine, k_impostor)[source]
+

Generates triplets from labeled data.

+

For every point (X_a) the triplets (X_a, X_b, X_c) are constructed from all +the combinations of taking one of its k_genuine-nearest neighbors of the +same class (X_b) and taking one of its k_impostor-nearest neighbors of +other classes (X_c).

+

In the case a class doesn’t have enough points in the same class (other +classes) to yield k_genuine (k_impostor) neighbors a warning will be +raised and the maximum value of genuine (impostor) neighbors will be used +for that class.

+
+
Parameters:
+
+
X(n x d) matrix

Input data, where each row corresponds to a single instance.

+
+
k_genuineint

Number of neighbors of the same class to be taken into account.

+
+
k_impostorint

Number of neighbors of different classes to be taken into account.

+
+
+
+
Returns:
+
+
tripletsarray-like, shape=(n_constraints, 3)

2D array of triplets of indicators.

+
+
+
+
+
+ +
+
+positive_negative_pairs(n_constraints, same_length=False, random_state=None, num_constraints='deprecated')[source]
+

Generates positive pairs and negative pairs from labeled data.

+

Positive pairs are formed by randomly drawing n_constraints pairs of +points with the same label. Negative pairs are formed by randomly drawing +n_constraints pairs of points with different label.

+

In the case where it is not possible to generate enough positive or +negative pairs, a smaller number of pairs will be returned with a warning.

+
+
Parameters:
+
+
n_constraintsint

Number of positive and negative constraints to generate.

+
+
same_lengthbool, optional (default=False)

If True, forces the number of positive and negative pairs to be +equal by ignoring some pairs from the larger set.

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int.

+
+
num_constraintsRenamed to n_constraints. Will be deprecated in 0.7.0
+
+
+
Returns:
+
+
aarray-like, shape=(n_constraints,)

1D array of indicators for the left elements of positive pairs.

+
+
barray-like, shape=(n_constraints,)

1D array of indicators for the right elements of positive pairs.

+
+
carray-like, shape=(n_constraints,)

1D array of indicators for the left elements of negative pairs.

+
+
darray-like, shape=(n_constraints,)

1D array of indicators for the right elements of negative pairs.

+
+
+
+
+
+ +
+ +
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.Covariance.html b/generated/metric_learn.Covariance.html new file mode 100644 index 00000000..9f14a6d0 --- /dev/null +++ b/generated/metric_learn.Covariance.html @@ -0,0 +1,543 @@ + + + + + + + metric_learn.Covariance — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.Covariance

+
+
+class metric_learn.Covariance(preprocessor=None)[source]
+

Covariance metric (baseline method)

+

This method does not “learn” anything, rather it calculates +the covariance matrix of the input data.

+

This is a simple baseline method first introduced in +On the Generalized Distance in Statistics, P.C.Mahalanobis, 1936

+

Read more in the User Guide.

+

Examples

+
>>> from metric_learn import Covariance
+>>> from sklearn.datasets import load_iris
+>>> iris = load_iris()['data']
+>>> cov = Covariance().fit(iris)
+>>> x = cov.transform(iris)
+
+
+
+
Attributes:
+
+
components_numpy.ndarray, shape=(n_features, n_features)

The linear transformation L deduced from the learned Mahalanobis +metric (See function components_from_metric.)

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

fit(X[, y])

Calculates the covariance matrix of the input data.

fit_transform(X[, y])

Fit to data, then transform it.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_output(*[, transform])

Set output container.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(preprocessor=None)[source]
+
+ +
+
+fit(X, y=None)[source]
+

Calculates the covariance matrix of the input data.

+
+
Parameters:
+
+
Xdata matrix, (n x d)
+
yunused
+
+
+
+
+ +
+
+fit_transform(X, y=None, **fit_params)
+

Fit to data, then transform it.

+

Fits transformer to X and y with optional parameters fit_params +and returns a transformed version of X.

+
+
Parameters:
+
+
Xarray-like of shape (n_samples, n_features)

Input samples.

+
+
yarray-like of shape (n_samples,) or (n_samples, n_outputs), default=None

Target values (None for unsupervised transformations).

+
+
**fit_paramsdict

Additional fit parameters.

+
+
+
+
Returns:
+
+
X_newndarray array of shape (n_samples, n_features_new)

Transformed array.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_output(*, transform=None)
+

Set output container.

+

See Introducing the set_output API +for an example on how to use the API.

+
+
Parameters:
+
+
transform{“default”, “pandas”}, default=None

Configure output of transform and fit_transform.

+
    +
  • “default”: Default output format of a transformer

  • +
  • “pandas”: DataFrame output

  • +
  • None: Transform configuration is unchanged

  • +
+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.ITML.html b/generated/metric_learn.ITML.html new file mode 100644 index 00000000..f9ec026a --- /dev/null +++ b/generated/metric_learn.ITML.html @@ -0,0 +1,970 @@ + + + + + + + metric_learn.ITML — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.ITML

+
+
+class metric_learn.ITML(gamma=1.0, max_iter=1000, tol=0.001, prior='identity', verbose=False, preprocessor=None, random_state=None, convergence_threshold='deprecated')[source]
+

Information Theoretic Metric Learning (ITML)

+

ITML minimizes the (differential) relative entropy, aka Kullback-Leibler +divergence, between two multivariate Gaussians subject to constraints on the +associated Mahalanobis distance, which can be formulated into a Bregman +optimization problem by minimizing the LogDet divergence subject to +linear constraints. This algorithm can handle a wide variety of constraints +and can optionally incorporate a prior on the distance function. Unlike some +other methods, ITML does not rely on an eigenvalue computation or +semi-definite programming.

+

Read more in the User Guide.

+
+
Parameters:
+
+
gammafloat, optional (default=1.0)

Value for slack variables

+
+
max_iterint, optional (default=1000)

Maximum number of iteration of the optimization procedure.

+
+
tolfloat, optional (default=1e-3)

Convergence tolerance.

+
+
priorstring or numpy array, optional (default=’identity’)

The Mahalanobis matrix to use as a prior. Possible options are +‘identity’, ‘covariance’, ‘random’, and a numpy array of shape +(n_features, n_features). For ITML, the prior should be strictly +positive definite (PD).

+
+
‘identity’

An identity matrix of shape (n_features, n_features).

+
+
‘covariance’

The inverse covariance matrix.

+
+
‘random’

The prior will be a random SPD matrix of shape +(n_features, n_features), generated using +sklearn.datasets.make_spd_matrix.

+
+
numpy array

A positive definite (PD) matrix of shape +(n_features, n_features), that will be used as such to set the +prior.

+
+
+
+
verbosebool, optional (default=False)

If True, prints information while learning

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be formed like this: X[indices].

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int. If +prior='random', random_state is used to set the prior.

+
+
convergence_thresholdRenamed to tol. Will be deprecated in 0.7.0
+
+
+
+

References

+
+
+[1] +

Jason V. Davis, et al. Information-theoretic Metric Learning. ICML 2007.

+
+
+

Examples

+
>>> from metric_learn import ITML
+>>> pairs = [[[1.2, 7.5], [1.3, 1.5]],
+>>>         [[6.4, 2.6], [6.2, 9.7]],
+>>>         [[1.3, 4.5], [3.2, 4.6]],
+>>>         [[6.2, 5.5], [5.4, 5.4]]]
+>>> y = [1, 1, -1, -1]
+>>> # in this task we want points where the first feature is close to be
+>>> # closer to each other, no matter how close the second feature is
+>>> itml = ITML()
+>>> itml.fit(pairs, y)
+
+
+
+
Attributes:
+
+
bounds_numpy.ndarray, shape=(2,)

Bounds on similarity, aside slack variables, s.t. +d(a, b) < bounds_[0] for all given pairs of similar points a +and b, and d(c, d) > bounds_[1] for all given pairs of +dissimilar points c and d, with d the learned distance. If +not provided at initialization, bounds_[0] and bounds_[1] are set at +train time to the 5th and 95th percentile of the pairwise distances among +all points present in the input pairs.

+
+
n_iter_int

The number of iterations the solver has run.

+
+
components_numpy.ndarray, shape=(n_features, n_features)

The linear transformation L deduced from the learned Mahalanobis +metric (See function components_from_metric.)

+
+
threshold_float

If the distance metric between two points is lower than this threshold, +points will be classified as similar, otherwise they will be +classified as dissimilar.

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

calibrate_threshold(pairs_valid, y_valid[, ...])

Decision threshold calibration for pairwise binary classification

decision_function(pairs)

Returns the decision function used to classify the pairs.

fit(pairs, y[, bounds, calibration_params])

Learn the ITML model.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

predict(pairs)

Predicts the learned metric between input pairs.

score(pairs, y)

Computes score of pairs similarity prediction.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_decision_function_request(*[, pairs])

Request metadata passed to the decision_function method.

set_fit_request(*[, bounds, ...])

Request metadata passed to the fit method.

set_params(**params)

Set the parameters of this estimator.

set_predict_request(*[, pairs])

Request metadata passed to the predict method.

set_score_request(*[, pairs])

Request metadata passed to the score method.

set_threshold(threshold)

Sets the threshold of the metric learner to the given value threshold.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(gamma=1.0, max_iter=1000, tol=0.001, prior='identity', verbose=False, preprocessor=None, random_state=None, convergence_threshold='deprecated')
+
+ +
+
+calibrate_threshold(pairs_valid, y_valid, strategy='accuracy', min_rate=None, beta=1.0)
+

Decision threshold calibration for pairwise binary classification

+

Method that calibrates the decision threshold (cutoff point) of the metric +learner. This threshold will then be used when calling the method +predict. The methods for picking cutoff points make use of traditional +binary classification evaluation statistics such as the true positive and +true negative rates and F-scores. The threshold will be found to maximize +the chosen score on the validation set (pairs_valid, y_valid).

+

See more in the User Guide.

+
+
Parameters:
+
+
strategystr, optional (default=’accuracy’)

The strategy to use for choosing the cutoff threshold.

+
+
‘accuracy’

Selects a decision threshold that maximizes the accuracy.

+
+
‘f_beta’

Selects a decision threshold that maximizes the f_beta score, +with beta given by the parameter beta.

+
+
‘max_tpr’

Selects a decision threshold that yields the highest true positive +rate with true negative rate at least equal to the value of the +parameter min_rate.

+
+
‘max_tnr’

Selects a decision threshold that yields the highest true negative +rate with true positive rate at least equal to the value of the +parameter min_rate.

+
+
+
+
betafloat in [0, 1], optional (default=None)

Beta value to be used in case strategy == ‘f_beta’.

+
+
min_ratefloat in [0, 1] or None, (default=None)

In case strategy is ‘max_tpr’ or ‘max_tnr’ this parameter must be set +to specify the minimal value for the true negative rate or true positive +rate respectively that needs to be achieved.

+
+
pairs_validarray-like, shape=(n_pairs_valid, 2, n_features)

The validation set of pairs to use to set the threshold.

+
+
y_validarray-like, shape=(n_pairs_valid,)

The labels of the pairs of the validation set to use to set the +threshold. They must be +1 for positive pairs and -1 for negative pairs.

+
+
+
+
+
+

See also

+
+
sklearn.calibration

scikit-learn’s module for calibrating classifiers

+
+
+
+

References

+
+
+[1] +

Receiver-operating characteristic (ROC) plots: a fundamental +evaluation tool in clinical medicine, MH Zweig, G Campbell - +Clinical chemistry, 1993

+
+
+[2] +

Most of the code of this function is from scikit-learn’s PR #10117

+
+
+
+ +
+
+classes_ = array([0, 1])
+
+ +
+
+decision_function(pairs)
+

Returns the decision function used to classify the pairs.

+

Returns the opposite of the learned metric value between samples in every +pair, to be consistent with scikit-learn conventions. Hence it should +ideally be low for dissimilar samples and high for similar samples. +This is the decision function that is used to classify pairs as similar +(+1), or dissimilar (-1).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to predict, with each row corresponding to two +points, or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
y_predictednumpy.ndarray of floats, shape=(n_constraints,)

The predicted decision function value for each pair.

+
+
+
+
+
+ +
+
+fit(pairs, y, bounds=None, calibration_params=None)[source]
+

Learn the ITML model.

+

The threshold will be calibrated on the trainset using the parameters +calibration_params.

+
+
Parameters:
+
+
pairs: array-like, shape=(n_constraints, 2, n_features) or (n_constraints, 2)

3D Array of pairs with each row corresponding to two points, +or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
y: array-like, of shape (n_constraints,)

Labels of constraints. Should be -1 for dissimilar pair, 1 for similar.

+
+
boundsarray-like of two numbers

Bounds on similarity, aside slack variables, s.t. +d(a, b) < bounds_[0] for all given pairs of similar points a +and b, and d(c, d) > bounds_[1] for all given pairs of +dissimilar points c and d, with d the learned distance. +If not provided at initialization, bounds_[0] and bounds_[1] will be +set to the 5th and 95th percentile of the pairwise distances among all +points present in the input pairs.

+
+
calibration_paramsdict or None

Dictionary of parameters to give to calibrate_threshold for the +threshold calibration step done at the end of fit. If None is +given, calibrate_threshold will use the default parameters.

+
+
+
+
Returns:
+
+
selfobject

Returns the instance.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+predict(pairs)
+

Predicts the learned metric between input pairs. (For now it just +calls decision function).

+

Returns the learned metric value between samples in every pair. It should +ideally be low for similar samples and high for dissimilar samples.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to predict, with each row corresponding to two +points, or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
y_predictednumpy.ndarray of floats, shape=(n_constraints,)

The predicted learned metric value between samples in every pair.

+
+
+
+
+
+ +
+
+score(pairs, y)
+

Computes score of pairs similarity prediction.

+

Returns the roc_auc score of the fitted metric learner. It is +computed in the following way: for every value of a threshold +t we classify all pairs of samples where the predicted distance is +inferior to t as belonging to the “similar” class, and the other as +belonging to the “dissimilar” class, and we count false positive and +true positives as in a classical roc_auc curve.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs, with each row corresponding to two points, +or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
yarray-like, shape=(n_constraints,)

The corresponding labels.

+
+
+
+
Returns:
+
+
scorefloat

The roc_auc score.

+
+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_decision_function_request(*, pairs: bool | None | str = '$UNCHANGED$') ITML
+

Request metadata passed to the decision_function method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to decision_function if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to decision_function.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in decision_function.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_fit_request(*, bounds: bool | None | str = '$UNCHANGED$', calibration_params: bool | None | str = '$UNCHANGED$', pairs: bool | None | str = '$UNCHANGED$') ITML
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
boundsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for bounds parameter in fit.

+
+
calibration_paramsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for calibration_params parameter in fit.

+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in fit.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_predict_request(*, pairs: bool | None | str = '$UNCHANGED$') ITML
+

Request metadata passed to the predict method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to predict if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to predict.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in predict.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_score_request(*, pairs: bool | None | str = '$UNCHANGED$') ITML
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in score.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_threshold(threshold)
+

Sets the threshold of the metric learner to the given value threshold.

+

See more in the User Guide.

+
+
Parameters:
+
+
thresholdfloat

The threshold value we want to set. It is the value to which the +predicted distance for test pairs will be compared. If they are superior +to the threshold they will be classified as similar (+1), +and dissimilar (-1) if not.

+
+
+
+
Returns:
+
+
self_PairsClassifier

The pairs classifier with the new threshold set.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.ITML

+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.ITML_Supervised.html b/generated/metric_learn.ITML_Supervised.html new file mode 100644 index 00000000..e48e50c0 --- /dev/null +++ b/generated/metric_learn.ITML_Supervised.html @@ -0,0 +1,684 @@ + + + + + + + metric_learn.ITML_Supervised — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.ITML_Supervised

+
+
+class metric_learn.ITML_Supervised(gamma=1.0, max_iter=1000, tol=0.001, n_constraints=None, prior='identity', verbose=False, preprocessor=None, random_state=None, num_constraints='deprecated', convergence_threshold='deprecated')[source]
+

Supervised version of Information Theoretic Metric Learning (ITML)

+

ITML_Supervised creates pairs of similar sample by taking same class +samples, and pairs of dissimilar samples by taking different class +samples. It then passes these pairs to ITML for training.

+
+
Parameters:
+
+
gammafloat, optional (default=1.0)

Value for slack variables

+
+
max_iterint, optional (default=1000)

Maximum number of iterations of the optimization procedure.

+
+
tolfloat, optional (default=1e-3)

Tolerance of the optimization procedure.

+
+
n_constraintsint, optional (default=None)

Number of constraints to generate. If None, default to 20 * +num_classes**2.

+
+
priorstring or numpy array, optional (default=’identity’)

Initialization of the Mahalanobis matrix. Possible options are +‘identity’, ‘covariance’, ‘random’, and a numpy array of shape +(n_features, n_features). For ITML, the prior should be strictly +positive definite (PD).

+
+
‘identity’

An identity matrix of shape (n_features, n_features).

+
+
‘covariance’

The inverse covariance matrix.

+
+
‘random’

The prior will be a random SPD matrix of shape +(n_features, n_features), generated using +sklearn.datasets.make_spd_matrix.

+
+
numpy array

A positive definite (PD) matrix of shape +(n_features, n_features), that will be used as such to set the +prior.

+
+
+
+
verbosebool, optional (default=False)

If True, prints information while learning

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be formed like this: X[indices].

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int. If +prior='random', random_state is used to set the prior. In any +case, random_state is also used to randomly sample constraints from +labels.

+
+
num_constraintsRenamed to n_constraints. Will be deprecated in 0.7.0
+
convergence_thresholdRenamed to tol. Will be deprecated in 0.7.0
+
+
+
+
+

See also

+
+
metric_learn.ITML

The original weakly-supervised algorithm

+
+
Supervised versions of weakly-supervised algorithms

The section of the project documentation that describes the supervised version of weakly supervised estimators.

+
+
+
+

Examples

+
>>> from metric_learn import ITML_Supervised
+>>> from sklearn.datasets import load_iris
+>>> iris_data = load_iris()
+>>> X = iris_data['data']
+>>> Y = iris_data['target']
+>>> itml = ITML_Supervised(n_constraints=200)
+>>> itml.fit(X, Y)
+
+
+
+
Attributes:
+
+
bounds_numpy.ndarray, shape=(2,)

Bounds on similarity, aside slack variables, s.t. +d(a, b) < bounds_[0] for all given pairs of similar points a +and b, and d(c, d) > bounds_[1] for all given pairs of +dissimilar points c and d, with d the learned distance. +If not provided at initialization, bounds_[0] and bounds_[1] are set at +train time to the 5th and 95th percentile of the pairwise distances +among all points in the training data X.

+
+
n_iter_int

The number of iterations the solver has run.

+
+
components_numpy.ndarray, shape=(n_features, n_features)

The linear transformation L deduced from the learned Mahalanobis +metric (See function components_from_metric.)

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

fit(X, y[, bounds])

Create constraints from labels and learn the ITML model.

fit_transform(X[, y])

Fit to data, then transform it.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_fit_request(*[, bounds])

Request metadata passed to the fit method.

set_output(*[, transform])

Set output container.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(gamma=1.0, max_iter=1000, tol=0.001, n_constraints=None, prior='identity', verbose=False, preprocessor=None, random_state=None, num_constraints='deprecated', convergence_threshold='deprecated')[source]
+
+ +
+
+fit(X, y, bounds=None)[source]
+

Create constraints from labels and learn the ITML model.

+
+
Parameters:
+
+
X(n x d) matrix

Input data, where each row corresponds to a single instance.

+
+
y(n) array-like

Data labels.

+
+
boundsarray-like of two numbers

Bounds on similarity, aside slack variables, s.t. +d(a, b) < bounds_[0] for all given pairs of similar points a +and b, and d(c, d) > bounds_[1] for all given pairs of +dissimilar points c and d, with d the learned distance. +If not provided at initialization, bounds_[0] and bounds_[1] will be +set to the 5th and 95th percentile of the pairwise distances among all +points in the training data X.

+
+
+
+
+
+ +
+
+fit_transform(X, y=None, **fit_params)
+

Fit to data, then transform it.

+

Fits transformer to X and y with optional parameters fit_params +and returns a transformed version of X.

+
+
Parameters:
+
+
Xarray-like of shape (n_samples, n_features)

Input samples.

+
+
yarray-like of shape (n_samples,) or (n_samples, n_outputs), default=None

Target values (None for unsupervised transformations).

+
+
**fit_paramsdict

Additional fit parameters.

+
+
+
+
Returns:
+
+
X_newndarray array of shape (n_samples, n_features_new)

Transformed array.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_fit_request(*, bounds: bool | None | str = '$UNCHANGED$') ITML_Supervised
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
boundsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for bounds parameter in fit.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_output(*, transform=None)
+

Set output container.

+

See Introducing the set_output API +for an example on how to use the API.

+
+
Parameters:
+
+
transform{“default”, “pandas”}, default=None

Configure output of transform and fit_transform.

+
    +
  • “default”: Default output format of a transformer

  • +
  • “pandas”: DataFrame output

  • +
  • None: Transform configuration is unchanged

  • +
+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.ITML_Supervised

+
+

Sandwich demo

+
Sandwich demo
+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.LFDA.html b/generated/metric_learn.LFDA.html new file mode 100644 index 00000000..3cf8e391 --- /dev/null +++ b/generated/metric_learn.LFDA.html @@ -0,0 +1,601 @@ + + + + + + + metric_learn.LFDA — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.LFDA

+
+
+class metric_learn.LFDA(n_components=None, k=None, embedding_type='weighted', preprocessor=None)[source]
+

Local Fisher Discriminant Analysis for Supervised Dimensionality Reduction

+

LFDA is a linear supervised dimensionality reduction method. It is +particularly useful when dealing with multimodality, where one ore more +classes consist of separate clusters in input space. The core optimization +problem of LFDA is solved as a generalized eigenvalue problem.

+

Read more in the User Guide.

+
+
Parameters:
+
+
n_componentsint or None, optional (default=None)

Dimensionality of reduced space (if None, defaults to dimension of X).

+
+
kint, optional (default=None)

Number of nearest neighbors used in local scaling method. If None, +defaults to min(7, n_features - 1).

+
+
embedding_typestr, optional (default: ‘weighted’)

Type of metric in the embedding space.

+
+
‘weighted’

weighted eigenvectors

+
+
‘orthonormalized’

orthonormalized

+
+
‘plain’

raw eigenvectors

+
+
+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be formed like this: X[indices].

+
+
+
+
+

References

+ +

Examples

+
>>> import numpy as np
+>>> from metric_learn import LFDA
+>>> from sklearn.datasets import load_iris
+>>> iris_data = load_iris()
+>>> X = iris_data['data']
+>>> Y = iris_data['target']
+>>> lfda = LFDA(k=2, dim=2)
+>>> lfda.fit(X, Y)
+
+
+
+
Attributes:
+
+
components_numpy.ndarray, shape=(n_components, n_features)

The learned linear transformation L.

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

fit(X, y)

Fit the LFDA model.

fit_transform(X[, y])

Fit to data, then transform it.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_output(*[, transform])

Set output container.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(n_components=None, k=None, embedding_type='weighted', preprocessor=None)[source]
+
+ +
+
+fit(X, y)[source]
+

Fit the LFDA model.

+
+
Parameters:
+
+
X(n, d) array-like

Input data.

+
+
y(n,) array-like

Class labels, one per point of data.

+
+
+
+
+
+ +
+
+fit_transform(X, y=None, **fit_params)
+

Fit to data, then transform it.

+

Fits transformer to X and y with optional parameters fit_params +and returns a transformed version of X.

+
+
Parameters:
+
+
Xarray-like of shape (n_samples, n_features)

Input samples.

+
+
yarray-like of shape (n_samples,) or (n_samples, n_outputs), default=None

Target values (None for unsupervised transformations).

+
+
**fit_paramsdict

Additional fit parameters.

+
+
+
+
Returns:
+
+
X_newndarray array of shape (n_samples, n_features_new)

Transformed array.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_output(*, transform=None)
+

Set output container.

+

See Introducing the set_output API +for an example on how to use the API.

+
+
Parameters:
+
+
transform{“default”, “pandas”}, default=None

Configure output of transform and fit_transform.

+
    +
  • “default”: Default output format of a transformer

  • +
  • “pandas”: DataFrame output

  • +
  • None: Transform configuration is unchanged

  • +
+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.LFDA

+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.LMNN.html b/generated/metric_learn.LMNN.html new file mode 100644 index 00000000..9fcf4850 --- /dev/null +++ b/generated/metric_learn.LMNN.html @@ -0,0 +1,640 @@ + + + + + + + metric_learn.LMNN — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.LMNN

+
+
+class metric_learn.LMNN(init='auto', n_neighbors=3, min_iter=50, max_iter=1000, learn_rate=1e-07, regularization=0.5, convergence_tol=0.001, verbose=False, preprocessor=None, n_components=None, random_state=None, k='deprecated')[source]
+

Large Margin Nearest Neighbor (LMNN)

+

LMNN learns a Mahalanobis distance metric in the kNN classification +setting. The learned metric attempts to keep close k-nearest neighbors +from the same class, while keeping examples from different classes +separated by a large margin. This algorithm makes no assumptions about +the distribution of the data.

+

Read more in the User Guide.

+
+
Parameters:
+
+
initstring or numpy array, optional (default=’auto’)

Initialization of the linear transformation. Possible options are +‘auto’, ‘pca’, ‘identity’, ‘random’, and a numpy array of shape +(n_features_a, n_features_b).

+
+
‘auto’

Depending on n_components, the most reasonable initialization +will be chosen. If n_components <= n_classes we use ‘lda’, as +it uses labels information. If not, but +n_components < min(n_features, n_samples), we use ‘pca’, as +it projects data in meaningful directions (those of higher +variance). Otherwise, we just use ‘identity’.

+
+
‘pca’

n_components principal components of the inputs passed +to fit() will be used to initialize the transformation. +(See sklearn.decomposition.PCA)

+
+
‘lda’

min(n_components, n_classes) most discriminative +components of the inputs passed to fit() will be used to +initialize the transformation. (If n_components > n_classes, +the rest of the components will be zero.) (See +sklearn.discriminant_analysis.LinearDiscriminantAnalysis)

+
+
‘identity’

If n_components is strictly smaller than the +dimensionality of the inputs passed to fit(), the identity +matrix will be truncated to the first n_components rows.

+
+
‘random’

The initial transformation will be a random array of shape +(n_components, n_features). Each value is sampled from the +standard normal distribution.

+
+
numpy array

n_features_b must match the dimensionality of the inputs passed to +fit() and n_features_a must be less than or equal to that. +If n_components is not None, n_features_a must match it.

+
+
+
+
n_neighborsint, optional (default=3)

Number of neighbors to consider, not including self-edges.

+
+
min_iterint, optional (default=50)

Minimum number of iterations of the optimization procedure.

+
+
max_iterint, optional (default=1000)

Maximum number of iterations of the optimization procedure.

+
+
learn_ratefloat, optional (default=1e-7)

Learning rate of the optimization procedure

+
+
tolfloat, optional (default=0.001)

Tolerance of the optimization procedure. If the objective value varies +less than tol, we consider the algorithm has converged and stop it.

+
+
verbosebool, optional (default=False)

Whether to print the progress of the optimization procedure.

+
+
regularization: float, optional (default=0.5)

Relative weight between pull and push terms, with 0.5 meaning equal +weight.

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be formed like this: X[indices].

+
+
n_componentsint or None, optional (default=None)

Dimensionality of reduced space (if None, defaults to dimension of X).

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int. If +init='random', random_state is used to initialize the random +transformation. If init='pca', random_state is passed as an +argument to PCA when initializing the transformation.

+
+
kRenamed to n_neighbors. Will be deprecated in 0.7.0
+
+
+
+

References

+
+
+[1] +

K. Q. Weinberger, J. Blitzer, L. K. Saul. Distance Metric +Learning for Large Margin Nearest Neighbor Classification. NIPS +2005.

+
+
+

Examples

+
>>> import numpy as np
+>>> from metric_learn import LMNN
+>>> from sklearn.datasets import load_iris
+>>> iris_data = load_iris()
+>>> X = iris_data['data']
+>>> Y = iris_data['target']
+>>> lmnn = LMNN(n_neighbors=5, learn_rate=1e-6)
+>>> lmnn.fit(X, Y, verbose=False)
+
+
+
+
Attributes:
+
+
n_iter_int

The number of iterations the solver has run.

+
+
components_numpy.ndarray, shape=(n_components, n_features)

The learned linear transformation L.

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

fit_transform(X[, y])

Fit to data, then transform it.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_output(*[, transform])

Set output container.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+ + + + + + +

fit

+
+
+__init__(init='auto', n_neighbors=3, min_iter=50, max_iter=1000, learn_rate=1e-07, regularization=0.5, convergence_tol=0.001, verbose=False, preprocessor=None, n_components=None, random_state=None, k='deprecated')[source]
+
+ +
+
+fit(X, y)[source]
+
+ +
+
+fit_transform(X, y=None, **fit_params)
+

Fit to data, then transform it.

+

Fits transformer to X and y with optional parameters fit_params +and returns a transformed version of X.

+
+
Parameters:
+
+
Xarray-like of shape (n_samples, n_features)

Input samples.

+
+
yarray-like of shape (n_samples,) or (n_samples, n_outputs), default=None

Target values (None for unsupervised transformations).

+
+
**fit_paramsdict

Additional fit parameters.

+
+
+
+
Returns:
+
+
X_newndarray array of shape (n_samples, n_features_new)

Transformed array.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_output(*, transform=None)
+

Set output container.

+

See Introducing the set_output API +for an example on how to use the API.

+
+
Parameters:
+
+
transform{“default”, “pandas”}, default=None

Configure output of transform and fit_transform.

+
    +
  • “default”: Default output format of a transformer

  • +
  • “pandas”: DataFrame output

  • +
  • None: Transform configuration is unchanged

  • +
+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.LMNN

+
+

Sandwich demo

+
Sandwich demo
+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.LSML.html b/generated/metric_learn.LSML.html new file mode 100644 index 00000000..423a6ad5 --- /dev/null +++ b/generated/metric_learn.LSML.html @@ -0,0 +1,853 @@ + + + + + + + metric_learn.LSML — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.LSML

+
+
+class metric_learn.LSML(tol=0.001, max_iter=1000, prior='identity', verbose=False, preprocessor=None, random_state=None)[source]
+

Least Squared-residual Metric Learning (LSML)

+

LSML proposes a simple, yet effective, algorithm that minimizes a convex +objective function corresponding to the sum of squared residuals of +constraints. This algorithm uses the constraints in the form of the +relative distance comparisons, such method is especially useful where +pairwise constraints are not natural to obtain, thus pairwise constraints +based algorithms become infeasible to be deployed. Furthermore, its sparsity +extension leads to more stable estimation when the dimension is high and +only a small amount of constraints is given.

+

Read more in the User Guide.

+
+
Parameters:
+
+
priorstring or numpy array, optional (default=’identity’)

Prior to set for the metric. Possible options are +‘identity’, ‘covariance’, ‘random’, and a numpy array of +shape (n_features, n_features). For LSML, the prior should be strictly +positive definite (PD).

+
+
‘identity’

An identity matrix of shape (n_features, n_features).

+
+
‘covariance’

The inverse covariance matrix.

+
+
‘random’

The initial Mahalanobis matrix will be a random positive definite +(PD) matrix of shape (n_features, n_features), generated using +sklearn.datasets.make_spd_matrix.

+
+
numpy array

A positive definite (PD) matrix of shape +(n_features, n_features), that will be used as such to set the +prior.

+
+
+
+
tolfloat, optional (default=1e-3)

Convergence tolerance of the optimization procedure.

+
+
max_iterint, optional (default=1000)

Maximum number of iteration of the optimization procedure.

+
+
verbosebool, optional (default=False)

If True, prints information while learning

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be formed like this: X[indices].

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int. If +init='random', random_state is used to set the random +prior.

+
+
+
+
+
+

See also

+
+
metric_learn.LSML

The original weakly-supervised algorithm

+
+
Supervised versions of weakly-supervised algorithms

The section of the project documentation that describes the supervised version of weakly supervised estimators.

+
+
+
+

References

+ +

Examples

+
>>> from metric_learn import LSML
+>>> quadruplets = [[[1.2, 7.5], [1.3, 1.5], [6.4, 2.6], [6.2, 9.7]],
+>>>                [[1.3, 4.5], [3.2, 4.6], [6.2, 5.5], [5.4, 5.4]],
+>>>                [[3.2, 7.5], [3.3, 1.5], [8.4, 2.6], [8.2, 9.7]],
+>>>                [[3.3, 4.5], [5.2, 4.6], [8.2, 5.5], [7.4, 5.4]]]
+>>> # we want to make closer points where the first feature is close, and
+>>> # further if the second feature is close
+>>> lsml = LSML()
+>>> lsml.fit(quadruplets)
+
+
+
+
Attributes:
+
+
n_iter_int

The number of iterations the solver has run.

+
+
components_numpy.ndarray, shape=(n_features, n_features)

The linear transformation L deduced from the learned Mahalanobis +metric (See function components_from_metric.)

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

decision_function(quadruplets)

Predicts differences between sample distances in input quadruplets.

fit(quadruplets[, weights])

Learn the LSML model.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

predict(quadruplets)

Predicts the ordering between sample distances in input quadruplets.

score(quadruplets)

Computes score on input quadruplets

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_decision_function_request(*[, quadruplets])

Request metadata passed to the decision_function method.

set_fit_request(*[, quadruplets, weights])

Request metadata passed to the fit method.

set_params(**params)

Set the parameters of this estimator.

set_predict_request(*[, quadruplets])

Request metadata passed to the predict method.

set_score_request(*[, quadruplets])

Request metadata passed to the score method.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(tol=0.001, max_iter=1000, prior='identity', verbose=False, preprocessor=None, random_state=None)
+
+ +
+
+classes_ = array([0, 1])
+
+ +
+
+decision_function(quadruplets)
+

Predicts differences between sample distances in input quadruplets.

+

For each quadruplet in the samples, computes the difference between the +learned metric of the second pair minus the learned metric of the first +pair. The higher it is, the more probable it is that the pairs in the +quadruplet are presented in the right order, i.e. that the label of the +quadruplet is 1. The lower it is, the more probable it is that the label of +the quadruplet is -1.

+
+
Parameters:
+
+
quadrupletsarray-like, shape=(n_quadruplets, 4, n_features) or (n_quadruplets, 4)

3D Array of quadruplets to predict, with each row corresponding to four +points, or 2D array of indices of quadruplets if the metric learner +uses a preprocessor.

+
+
+
+
Returns:
+
+
decision_functionnumpy.ndarray of floats, shape=(n_constraints,)

Metric differences.

+
+
+
+
+
+ +
+
+fit(quadruplets, weights=None)[source]
+

Learn the LSML model.

+
+
Parameters:
+
+
quadrupletsarray-like, shape=(n_constraints, 4, n_features) or (n_constraints, 4)

3D array-like of quadruplets of points or 2D array of quadruplets of +indicators. In order to supervise the algorithm in the right way, we +should have the four samples ordered in a way such that: +d(pairs[i, 0],X[i, 1]) < d(X[i, 2], X[i, 3]) for all 0 <= i < +n_constraints.

+
+
weights(n_constraints,) array of floats, optional

scale factor for each constraint

+
+
+
+
Returns:
+
+
selfobject

Returns the instance.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+predict(quadruplets)
+

Predicts the ordering between sample distances in input quadruplets.

+

For each quadruplet, returns 1 if the quadruplet is in the right order ( +first pair is more similar than second pair), and -1 if not.

+
+
Parameters:
+
+
quadrupletsarray-like, shape=(n_quadruplets, 4, n_features) or (n_quadruplets, 4)

3D Array of quadruplets to predict, with each row corresponding to four +points, or 2D array of indices of quadruplets if the metric learner +uses a preprocessor.

+
+
+
+
Returns:
+
+
predictionnumpy.ndarray of floats, shape=(n_constraints,)

Predictions of the ordering of pairs, for each quadruplet.

+
+
+
+
+
+ +
+
+score(quadruplets)
+

Computes score on input quadruplets

+

Returns the accuracy score of the following classification task: a record +is correctly classified if the predicted similarity between the first two +samples is higher than that of the last two.

+
+
Parameters:
+
+
quadrupletsarray-like, shape=(n_quadruplets, 4, n_features) or (n_quadruplets, 4)

3D Array of quadruplets to score, with each row corresponding to four +points, or 2D array of indices of quadruplets if the metric learner +uses a preprocessor.

+
+
+
+
Returns:
+
+
scorefloat

The quadruplets score.

+
+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_decision_function_request(*, quadruplets: bool | None | str = '$UNCHANGED$') LSML
+

Request metadata passed to the decision_function method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to decision_function if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to decision_function.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
quadrupletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for quadruplets parameter in decision_function.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_fit_request(*, quadruplets: bool | None | str = '$UNCHANGED$', weights: bool | None | str = '$UNCHANGED$') LSML
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
quadrupletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for quadruplets parameter in fit.

+
+
weightsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for weights parameter in fit.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_predict_request(*, quadruplets: bool | None | str = '$UNCHANGED$') LSML
+

Request metadata passed to the predict method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to predict if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to predict.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
quadrupletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for quadruplets parameter in predict.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_score_request(*, quadruplets: bool | None | str = '$UNCHANGED$') LSML
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
quadrupletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for quadruplets parameter in score.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.LSML

+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.LSML_Supervised.html b/generated/metric_learn.LSML_Supervised.html new file mode 100644 index 00000000..08dd618a --- /dev/null +++ b/generated/metric_learn.LSML_Supervised.html @@ -0,0 +1,614 @@ + + + + + + + metric_learn.LSML_Supervised — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.LSML_Supervised

+
+
+class metric_learn.LSML_Supervised(tol=0.001, max_iter=1000, prior='identity', n_constraints=None, weights=None, verbose=False, preprocessor=None, random_state=None, num_constraints='deprecated')[source]
+

Supervised version of Least Squared-residual Metric Learning (LSML)

+

LSML_Supervised creates quadruplets from labeled samples by taking two +samples from the same class, and two samples from different classes. +This way it builds quadruplets where the two first points must be more +similar than the two last points.

+
+
Parameters:
+
+
tolfloat, optional (default=1e-3)

Convergence tolerance of the optimization procedure.

+
+
max_iterint, optional (default=1000)

Number of maximum iterations of the optimization procedure.

+
+
priorstring or numpy array, optional (default=’identity’)

Prior to set for the metric. Possible options are +‘identity’, ‘covariance’, ‘random’, and a numpy array of +shape (n_features, n_features). For LSML, the prior should be strictly +positive definite (PD).

+
+
‘identity’

An identity matrix of shape (n_features, n_features).

+
+
‘covariance’

The inverse covariance matrix.

+
+
‘random’

The initial Mahalanobis matrix will be a random positive definite +(PD) matrix of shape (n_features, n_features), generated using +sklearn.datasets.make_spd_matrix.

+
+
numpy array

A positive definite (PD) matrix of shape +(n_features, n_features), that will be used as such to set the +prior.

+
+
+
+
n_constraints: int, optional (default=None)

Number of constraints to generate. If None, default to 20 * +num_classes**2.

+
+
weights(n_constraints,) array of floats, optional (default=None)

Relative weight given to each constraint. If None, defaults to uniform +weights.

+
+
verbosebool, optional (default=False)

If True, prints information while learning

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be formed like this: X[indices].

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int. If +init='random', random_state is used to set the random +prior. In any case, random_state is also used to randomly sample +constraints from labels.

+
+
num_constraintsRenamed to n_constraints. Will be deprecated in 0.7.0
+
+
+
+

Examples

+
>>> from metric_learn import LSML_Supervised
+>>> from sklearn.datasets import load_iris
+>>> iris_data = load_iris()
+>>> X = iris_data['data']
+>>> Y = iris_data['target']
+>>> lsml = LSML_Supervised(n_constraints=200)
+>>> lsml.fit(X, Y)
+
+
+
+
Attributes:
+
+
n_iter_int

The number of iterations the solver has run.

+
+
components_numpy.ndarray, shape=(n_features, n_features)

The linear transformation L deduced from the learned Mahalanobis +metric (See function components_from_metric.)

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

fit(X, y)

Create constraints from labels and learn the LSML model.

fit_transform(X[, y])

Fit to data, then transform it.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_output(*[, transform])

Set output container.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(tol=0.001, max_iter=1000, prior='identity', n_constraints=None, weights=None, verbose=False, preprocessor=None, random_state=None, num_constraints='deprecated')[source]
+
+ +
+
+fit(X, y)[source]
+

Create constraints from labels and learn the LSML model.

+
+
Parameters:
+
+
X(n x d) matrix

Input data, where each row corresponds to a single instance.

+
+
y(n) array-like

Data labels.

+
+
+
+
+
+ +
+
+fit_transform(X, y=None, **fit_params)
+

Fit to data, then transform it.

+

Fits transformer to X and y with optional parameters fit_params +and returns a transformed version of X.

+
+
Parameters:
+
+
Xarray-like of shape (n_samples, n_features)

Input samples.

+
+
yarray-like of shape (n_samples,) or (n_samples, n_outputs), default=None

Target values (None for unsupervised transformations).

+
+
**fit_paramsdict

Additional fit parameters.

+
+
+
+
Returns:
+
+
X_newndarray array of shape (n_samples, n_features_new)

Transformed array.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_output(*, transform=None)
+

Set output container.

+

See Introducing the set_output API +for an example on how to use the API.

+
+
Parameters:
+
+
transform{“default”, “pandas”}, default=None

Configure output of transform and fit_transform.

+
    +
  • “default”: Default output format of a transformer

  • +
  • “pandas”: DataFrame output

  • +
  • None: Transform configuration is unchanged

  • +
+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.LSML_Supervised

+
+

Sandwich demo

+
Sandwich demo
+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.MLKR.html b/generated/metric_learn.MLKR.html new file mode 100644 index 00000000..64f26755 --- /dev/null +++ b/generated/metric_learn.MLKR.html @@ -0,0 +1,620 @@ + + + + + + + metric_learn.MLKR — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.MLKR

+
+
+class metric_learn.MLKR(n_components=None, init='auto', tol=None, max_iter=1000, verbose=False, preprocessor=None, random_state=None)[source]
+

Metric Learning for Kernel Regression (MLKR)

+

MLKR is an algorithm for supervised metric learning, which learns a +distance function by directly minimizing the leave-one-out regression error. +This algorithm can also be viewed as a supervised variation of PCA and can be +used for dimensionality reduction and high dimensional data visualization.

+

Read more in the User Guide.

+
+
Parameters:
+
+
n_componentsint or None, optional (default=None)

Dimensionality of reduced space (if None, defaults to dimension of X).

+
+
initstring or numpy array, optional (default=’auto’)

Initialization of the linear transformation. Possible options are +‘auto’, ‘pca’, ‘identity’, ‘random’, and a numpy array of shape +(n_features_a, n_features_b).

+
+
‘auto’

Depending on n_components, the most reasonable initialization +will be chosen. If n_components < min(n_features, n_samples), +we use ‘pca’, as it projects data in meaningful directions (those +of higher variance). Otherwise, we just use ‘identity’.

+
+
‘pca’

n_components principal components of the inputs passed +to fit() will be used to initialize the transformation. +(See sklearn.decomposition.PCA)

+
+
‘identity’

If n_components is strictly smaller than the +dimensionality of the inputs passed to fit(), the identity +matrix will be truncated to the first n_components rows.

+
+
‘random’

The initial transformation will be a random array of shape +(n_components, n_features). Each value is sampled from the +standard normal distribution.

+
+
numpy array

n_features_b must match the dimensionality of the inputs passed to +fit() and n_features_a must be less than or equal to that. +If n_components is not None, n_features_a must match it.

+
+
+
+
tolfloat, optional (default=None)

Convergence tolerance for the optimization.

+
+
max_iterint, optional (default=1000)

Cap on number of conjugate gradient iterations.

+
+
verbosebool, optional (default=False)

Whether to print progress messages or not.

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be formed like this: X[indices].

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int. If +init='random', random_state is used to initialize the random +transformation. If init='pca', random_state is passed as an +argument to PCA when initializing the transformation.

+
+
+
+
+

References

+
+
+[1] +

K.Q. Weinberger and G. Tesauto. Metric Learning for Kernel +Regression. AISTATS 2007.

+
+
+

Examples

+
>>> from metric_learn import MLKR
+>>> from sklearn.datasets import load_iris
+>>> iris_data = load_iris()
+>>> X = iris_data['data']
+>>> Y = iris_data['target']
+>>> mlkr = MLKR()
+>>> mlkr.fit(X, Y)
+
+
+
+
Attributes:
+
+
n_iter_int

The number of iterations the solver has run.

+
+
components_numpy.ndarray, shape=(n_components, n_features)

The learned linear transformation L.

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

fit(X, y)

Fit MLKR model

fit_transform(X[, y])

Fit to data, then transform it.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_output(*[, transform])

Set output container.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(n_components=None, init='auto', tol=None, max_iter=1000, verbose=False, preprocessor=None, random_state=None)[source]
+
+ +
+
+fit(X, y)[source]
+

Fit MLKR model

+
+
Parameters:
+
+
X(n x d) array of samples
+
y(n) data labels
+
+
+
+
+ +
+
+fit_transform(X, y=None, **fit_params)
+

Fit to data, then transform it.

+

Fits transformer to X and y with optional parameters fit_params +and returns a transformed version of X.

+
+
Parameters:
+
+
Xarray-like of shape (n_samples, n_features)

Input samples.

+
+
yarray-like of shape (n_samples,) or (n_samples, n_outputs), default=None

Target values (None for unsupervised transformations).

+
+
**fit_paramsdict

Additional fit parameters.

+
+
+
+
Returns:
+
+
X_newndarray array of shape (n_samples, n_features_new)

Transformed array.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_output(*, transform=None)
+

Set output container.

+

See Introducing the set_output API +for an example on how to use the API.

+
+
Parameters:
+
+
transform{“default”, “pandas”}, default=None

Configure output of transform and fit_transform.

+
    +
  • “default”: Default output format of a transformer

  • +
  • “pandas”: DataFrame output

  • +
  • None: Transform configuration is unchanged

  • +
+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.MLKR

+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.MMC.html b/generated/metric_learn.MMC.html new file mode 100644 index 00000000..121a87c0 --- /dev/null +++ b/generated/metric_learn.MMC.html @@ -0,0 +1,972 @@ + + + + + + + metric_learn.MMC — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.MMC

+
+
+class metric_learn.MMC(max_iter=100, max_proj=10000, tol=0.001, init='identity', diagonal=False, diagonal_c=1.0, verbose=False, preprocessor=None, random_state=None, convergence_threshold='deprecated')[source]
+

Mahalanobis Metric for Clustering (MMC)

+

MMC minimizes the sum of squared distances between similar points, while +enforcing the sum of distances between dissimilar ones to be greater than +one. This leads to a convex and, thus, local-minima-free optimization +problem that can be solved efficiently. +However, the algorithm involves the computation of eigenvalues, which is the +main speed-bottleneck. Since it has initially been designed for clustering +applications, one of the implicit assumptions of MMC is that all classes form +a compact set, i.e., follow a unimodal distribution, which restricts the +possible use-cases of this method. However, it is one of the earliest and a +still often cited technique.

+

Read more in the User Guide.

+
+
Parameters:
+
+
max_iterint, optional (default=100)

Maximum number of iterations of the optimization procedure.

+
+
max_projint, optional (default=10000)

Maximum number of projection steps.

+
+
tolfloat, optional (default=1e-3)

Convergence threshold for the optimization procedure.

+
+
initstring or numpy array, optional (default=’identity’)

Initialization of the Mahalanobis matrix. Possible options are +‘identity’, ‘covariance’, ‘random’, and a numpy array of +shape (n_features, n_features).

+
+
‘identity’

An identity matrix of shape (n_features, n_features).

+
+
‘covariance’

The (pseudo-)inverse of the covariance matrix.

+
+
‘random’

The initial Mahalanobis matrix will be a random SPD matrix of +shape +(n_features, n_features), generated using +sklearn.datasets.make_spd_matrix.

+
+
numpy array

An SPD matrix of shape (n_features, n_features), that will +be used as such to initialize the metric.

+
+
+
+
diagonalbool, optional (default=False)

If True, a diagonal metric will be learned, +i.e., a simple scaling of dimensions. The initialization will then +be the diagonal coefficients of the matrix given as ‘init’.

+
+
diagonal_cfloat, optional (default=1.0)

Weight of the dissimilarity constraint for diagonal +metric learning. Ignored if diagonal=False.

+
+
verbosebool, optional (default=False)

If True, prints information while learning

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be gotten like this: X[indices].

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int. If +init='random', random_state is used to initialize the random +transformation.

+
+
convergence_thresholdRenamed to tol. Will be deprecated in 0.7.0
+
+
+
+
+

See also

+
+
metric_learn.MMC

The original weakly-supervised algorithm

+
+
Supervised versions of weakly-supervised algorithms

The section of the project documentation that describes the supervised version of weakly supervised estimators.

+
+
+
+

References

+
+ +
+

Examples

+
>>> from metric_learn import MMC
+>>> pairs = [[[1.2, 7.5], [1.3, 1.5]],
+>>>          [[6.4, 2.6], [6.2, 9.7]],
+>>>          [[1.3, 4.5], [3.2, 4.6]],
+>>>          [[6.2, 5.5], [5.4, 5.4]]]
+>>> y = [1, 1, -1, -1]
+>>> # in this task we want points where the first feature is close to be
+>>> # closer to each other, no matter how close the second feature is
+>>> mmc = MMC()
+>>> mmc.fit(pairs, y)
+
+
+
+
Attributes:
+
+
n_iter_int

The number of iterations the solver has run.

+
+
components_numpy.ndarray, shape=(n_features, n_features)

The linear transformation L deduced from the learned Mahalanobis +metric (See function components_from_metric.)

+
+
threshold_float

If the distance metric between two points is lower than this threshold, +points will be classified as similar, otherwise they will be +classified as dissimilar.

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

calibrate_threshold(pairs_valid, y_valid[, ...])

Decision threshold calibration for pairwise binary classification

decision_function(pairs)

Returns the decision function used to classify the pairs.

fit(pairs, y[, calibration_params])

Learn the MMC model.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

predict(pairs)

Predicts the learned metric between input pairs.

score(pairs, y)

Computes score of pairs similarity prediction.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_decision_function_request(*[, pairs])

Request metadata passed to the decision_function method.

set_fit_request(*[, calibration_params, pairs])

Request metadata passed to the fit method.

set_params(**params)

Set the parameters of this estimator.

set_predict_request(*[, pairs])

Request metadata passed to the predict method.

set_score_request(*[, pairs])

Request metadata passed to the score method.

set_threshold(threshold)

Sets the threshold of the metric learner to the given value threshold.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(max_iter=100, max_proj=10000, tol=0.001, init='identity', diagonal=False, diagonal_c=1.0, verbose=False, preprocessor=None, random_state=None, convergence_threshold='deprecated')
+
+ +
+
+calibrate_threshold(pairs_valid, y_valid, strategy='accuracy', min_rate=None, beta=1.0)
+

Decision threshold calibration for pairwise binary classification

+

Method that calibrates the decision threshold (cutoff point) of the metric +learner. This threshold will then be used when calling the method +predict. The methods for picking cutoff points make use of traditional +binary classification evaluation statistics such as the true positive and +true negative rates and F-scores. The threshold will be found to maximize +the chosen score on the validation set (pairs_valid, y_valid).

+

See more in the User Guide.

+
+
Parameters:
+
+
strategystr, optional (default=’accuracy’)

The strategy to use for choosing the cutoff threshold.

+
+
‘accuracy’

Selects a decision threshold that maximizes the accuracy.

+
+
‘f_beta’

Selects a decision threshold that maximizes the f_beta score, +with beta given by the parameter beta.

+
+
‘max_tpr’

Selects a decision threshold that yields the highest true positive +rate with true negative rate at least equal to the value of the +parameter min_rate.

+
+
‘max_tnr’

Selects a decision threshold that yields the highest true negative +rate with true positive rate at least equal to the value of the +parameter min_rate.

+
+
+
+
betafloat in [0, 1], optional (default=None)

Beta value to be used in case strategy == ‘f_beta’.

+
+
min_ratefloat in [0, 1] or None, (default=None)

In case strategy is ‘max_tpr’ or ‘max_tnr’ this parameter must be set +to specify the minimal value for the true negative rate or true positive +rate respectively that needs to be achieved.

+
+
pairs_validarray-like, shape=(n_pairs_valid, 2, n_features)

The validation set of pairs to use to set the threshold.

+
+
y_validarray-like, shape=(n_pairs_valid,)

The labels of the pairs of the validation set to use to set the +threshold. They must be +1 for positive pairs and -1 for negative pairs.

+
+
+
+
+
+

See also

+
+
sklearn.calibration

scikit-learn’s module for calibrating classifiers

+
+
+
+

References

+
+
+[1] +

Receiver-operating characteristic (ROC) plots: a fundamental +evaluation tool in clinical medicine, MH Zweig, G Campbell - +Clinical chemistry, 1993

+
+
+[2] +

Most of the code of this function is from scikit-learn’s PR #10117

+
+
+
+ +
+
+classes_ = array([0, 1])
+
+ +
+
+decision_function(pairs)
+

Returns the decision function used to classify the pairs.

+

Returns the opposite of the learned metric value between samples in every +pair, to be consistent with scikit-learn conventions. Hence it should +ideally be low for dissimilar samples and high for similar samples. +This is the decision function that is used to classify pairs as similar +(+1), or dissimilar (-1).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to predict, with each row corresponding to two +points, or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
y_predictednumpy.ndarray of floats, shape=(n_constraints,)

The predicted decision function value for each pair.

+
+
+
+
+
+ +
+
+fit(pairs, y, calibration_params=None)[source]
+

Learn the MMC model.

+

The threshold will be calibrated on the trainset using the parameters +calibration_params.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_constraints, 2, n_features) or (n_constraints, 2)

3D Array of pairs with each row corresponding to two points, +or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
yarray-like, of shape (n_constraints,)

Labels of constraints. Should be -1 for dissimilar pair, 1 for similar.

+
+
calibration_paramsdict or None

Dictionary of parameters to give to calibrate_threshold for the +threshold calibration step done at the end of fit. If None is +given, calibrate_threshold will use the default parameters.

+
+
+
+
Returns:
+
+
selfobject

Returns the instance.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+predict(pairs)
+

Predicts the learned metric between input pairs. (For now it just +calls decision function).

+

Returns the learned metric value between samples in every pair. It should +ideally be low for similar samples and high for dissimilar samples.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to predict, with each row corresponding to two +points, or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
y_predictednumpy.ndarray of floats, shape=(n_constraints,)

The predicted learned metric value between samples in every pair.

+
+
+
+
+
+ +
+
+score(pairs, y)
+

Computes score of pairs similarity prediction.

+

Returns the roc_auc score of the fitted metric learner. It is +computed in the following way: for every value of a threshold +t we classify all pairs of samples where the predicted distance is +inferior to t as belonging to the “similar” class, and the other as +belonging to the “dissimilar” class, and we count false positive and +true positives as in a classical roc_auc curve.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs, with each row corresponding to two points, +or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
yarray-like, shape=(n_constraints,)

The corresponding labels.

+
+
+
+
Returns:
+
+
scorefloat

The roc_auc score.

+
+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_decision_function_request(*, pairs: bool | None | str = '$UNCHANGED$') MMC
+

Request metadata passed to the decision_function method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to decision_function if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to decision_function.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in decision_function.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_fit_request(*, calibration_params: bool | None | str = '$UNCHANGED$', pairs: bool | None | str = '$UNCHANGED$') MMC
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
calibration_paramsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for calibration_params parameter in fit.

+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in fit.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_predict_request(*, pairs: bool | None | str = '$UNCHANGED$') MMC
+

Request metadata passed to the predict method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to predict if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to predict.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in predict.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_score_request(*, pairs: bool | None | str = '$UNCHANGED$') MMC
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in score.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_threshold(threshold)
+

Sets the threshold of the metric learner to the given value threshold.

+

See more in the User Guide.

+
+
Parameters:
+
+
thresholdfloat

The threshold value we want to set. It is the value to which the +predicted distance for test pairs will be compared. If they are superior +to the threshold they will be classified as similar (+1), +and dissimilar (-1) if not.

+
+
+
+
Returns:
+
+
self_PairsClassifier

The pairs classifier with the new threshold set.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.MMC

+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.MMC_Supervised.html b/generated/metric_learn.MMC_Supervised.html new file mode 100644 index 00000000..e3b9ce2f --- /dev/null +++ b/generated/metric_learn.MMC_Supervised.html @@ -0,0 +1,615 @@ + + + + + + + metric_learn.MMC_Supervised — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.MMC_Supervised

+
+
+class metric_learn.MMC_Supervised(max_iter=100, max_proj=10000, tol=1e-06, n_constraints=None, init='identity', diagonal=False, diagonal_c=1.0, verbose=False, preprocessor=None, random_state=None, num_constraints='deprecated', convergence_threshold='deprecated')[source]
+

Supervised version of Mahalanobis Metric for Clustering (MMC)

+

MMC_Supervised creates pairs of similar sample by taking same class +samples, and pairs of dissimilar samples by taking different class +samples. It then passes these pairs to MMC for training.

+
+
Parameters:
+
+
max_iterint, optional (default=100)

Maximum number of iterations of the optimization procedure.

+
+
max_projint, optional (default=10000)

Maximum number of projection steps.

+
+
tolfloat, optional (default=1e-3)

Convergence threshold for the optimization procedure.

+
+
n_constraints: int, optional (default=None)

Number of constraints to generate. If None, default to 20 * +num_classes**2.

+
+
initstring or numpy array, optional (default=’identity’)

Initialization of the Mahalanobis matrix. Possible options are +‘identity’, ‘covariance’, ‘random’, and a numpy array of +shape (n_features, n_features).

+
+
‘identity’

An identity matrix of shape (n_features, n_features).

+
+
‘covariance’

The (pseudo-)inverse of the covariance matrix.

+
+
‘random’

The initial Mahalanobis matrix will be a random SPD matrix of +shape (n_features, n_features), generated using +sklearn.datasets.make_spd_matrix.

+
+
numpy array

A numpy array of shape (n_features, n_features), that will +be used as such to initialize the metric.

+
+
+
+
diagonalbool, optional (default=False)

If True, a diagonal metric will be learned, +i.e., a simple scaling of dimensions. The initialization will then +be the diagonal coefficients of the matrix given as ‘init’.

+
+
diagonal_cfloat, optional (default=1.0)

Weight of the dissimilarity constraint for diagonal +metric learning. Ignored if diagonal=False.

+
+
verbosebool, optional (default=False)

If True, prints information while learning

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be formed like this: X[indices].

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int. If +init='random', random_state is used to initialize the random +Mahalanobis matrix. In any case, random_state is also used to +randomly sample constraints from labels.

+
+
num_constraintsRenamed to n_constraints. Will be deprecated in 0.7.0
+
convergence_thresholdRenamed to tol. Will be deprecated in 0.7.0
+
+
+
+

Examples

+
>>> from metric_learn import MMC_Supervised
+>>> from sklearn.datasets import load_iris
+>>> iris_data = load_iris()
+>>> X = iris_data['data']
+>>> Y = iris_data['target']
+>>> mmc = MMC_Supervised(n_constraints=200)
+>>> mmc.fit(X, Y)
+
+
+
+
Attributes:
+
+
n_iter_int

The number of iterations the solver has run.

+
+
components_numpy.ndarray, shape=(n_features, n_features)

The linear transformation L deduced from the learned Mahalanobis +metric (See function components_from_metric.)

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

fit(X, y)

Create constraints from labels and learn the MMC model.

fit_transform(X[, y])

Fit to data, then transform it.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_output(*[, transform])

Set output container.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(max_iter=100, max_proj=10000, tol=1e-06, n_constraints=None, init='identity', diagonal=False, diagonal_c=1.0, verbose=False, preprocessor=None, random_state=None, num_constraints='deprecated', convergence_threshold='deprecated')[source]
+
+ +
+
+fit(X, y)[source]
+

Create constraints from labels and learn the MMC model.

+
+
Parameters:
+
+
X(n x d) matrix

Input data, where each row corresponds to a single instance.

+
+
y(n) array-like

Data labels.

+
+
+
+
+
+ +
+
+fit_transform(X, y=None, **fit_params)
+

Fit to data, then transform it.

+

Fits transformer to X and y with optional parameters fit_params +and returns a transformed version of X.

+
+
Parameters:
+
+
Xarray-like of shape (n_samples, n_features)

Input samples.

+
+
yarray-like of shape (n_samples,) or (n_samples, n_outputs), default=None

Target values (None for unsupervised transformations).

+
+
**fit_paramsdict

Additional fit parameters.

+
+
+
+
Returns:
+
+
X_newndarray array of shape (n_samples, n_features_new)

Transformed array.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_output(*, transform=None)
+

Set output container.

+

See Introducing the set_output API +for an example on how to use the API.

+
+
Parameters:
+
+
transform{“default”, “pandas”}, default=None

Configure output of transform and fit_transform.

+
    +
  • “default”: Default output format of a transformer

  • +
  • “pandas”: DataFrame output

  • +
  • None: Transform configuration is unchanged

  • +
+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.MMC_Supervised

+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.NCA.html b/generated/metric_learn.NCA.html new file mode 100644 index 00000000..e1acee66 --- /dev/null +++ b/generated/metric_learn.NCA.html @@ -0,0 +1,626 @@ + + + + + + + metric_learn.NCA — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.NCA

+
+
+class metric_learn.NCA(init='auto', n_components=None, max_iter=100, tol=None, verbose=False, preprocessor=None, random_state=None)[source]
+

Neighborhood Components Analysis (NCA)

+

NCA is a distance metric learning algorithm which aims to improve the +accuracy of nearest neighbors classification compared to the standard +Euclidean distance. The algorithm directly maximizes a stochastic variant +of the leave-one-out k-nearest neighbors(KNN) score on the training set. +It can also learn a low-dimensional linear transformation of data that can +be used for data visualization and fast classification.

+

Read more in the User Guide.

+
+
Parameters:
+
+
initstring or numpy array, optional (default=’auto’)

Initialization of the linear transformation. Possible options are +‘auto’, ‘pca’, ‘identity’, ‘random’, and a numpy array of shape +(n_features_a, n_features_b).

+
+
‘auto’

Depending on n_components, the most reasonable initialization +will be chosen. If n_components <= n_classes we use ‘lda’, as +it uses labels information. If not, but +n_components < min(n_features, n_samples), we use ‘pca’, as +it projects data in meaningful directions (those of higher +variance). Otherwise, we just use ‘identity’.

+
+
‘pca’

n_components principal components of the inputs passed +to fit() will be used to initialize the transformation. +(See sklearn.decomposition.PCA)

+
+
‘lda’

min(n_components, n_classes) most discriminative +components of the inputs passed to fit() will be used to +initialize the transformation. (If n_components > n_classes, +the rest of the components will be zero.) (See +sklearn.discriminant_analysis.LinearDiscriminantAnalysis)

+
+
‘identity’

If n_components is strictly smaller than the +dimensionality of the inputs passed to fit(), the identity +matrix will be truncated to the first n_components rows.

+
+
‘random’

The initial transformation will be a random array of shape +(n_components, n_features). Each value is sampled from the +standard normal distribution.

+
+
numpy array

n_features_b must match the dimensionality of the inputs passed to +fit() and n_features_a must be less than or equal to that. +If n_components is not None, n_features_a must match it.

+
+
+
+
n_componentsint or None, optional (default=None)

Dimensionality of reduced space (if None, defaults to dimension of X).

+
+
max_iterint, optional (default=100)

Maximum number of iterations done by the optimization algorithm.

+
+
tolfloat, optional (default=None)

Convergence tolerance for the optimization.

+
+
verbosebool, optional (default=False)

Whether to print progress messages or not.

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int. If +init='random', random_state is used to initialize the random +transformation. If init='pca', random_state is passed as an +argument to PCA when initializing the transformation.

+
+
+
+
+

References

+
+
+[1] +

J. Goldberger, G. Hinton, S. Roweis, R. Salakhutdinov. Neighbourhood +Components Analysis. +NIPS 2005.

+
+
+[2] +

Wikipedia entry on Neighborhood Components Analysis

+
+
+

Examples

+
>>> import numpy as np
+>>> from metric_learn import NCA
+>>> from sklearn.datasets import load_iris
+>>> iris_data = load_iris()
+>>> X = iris_data['data']
+>>> Y = iris_data['target']
+>>> nca = NCA(max_iter=1000)
+>>> nca.fit(X, Y)
+
+
+
+
Attributes:
+
+
n_iter_int

The number of iterations the solver has run.

+
+
components_numpy.ndarray, shape=(n_components, n_features)

The learned linear transformation L.

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

fit(X, y)

X: data matrix, (n x d) y: scalar labels, (n)

fit_transform(X[, y])

Fit to data, then transform it.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_output(*[, transform])

Set output container.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(init='auto', n_components=None, max_iter=100, tol=None, verbose=False, preprocessor=None, random_state=None)[source]
+
+ +
+
+fit(X, y)[source]
+

X: data matrix, (n x d) +y: scalar labels, (n)

+
+ +
+
+fit_transform(X, y=None, **fit_params)
+

Fit to data, then transform it.

+

Fits transformer to X and y with optional parameters fit_params +and returns a transformed version of X.

+
+
Parameters:
+
+
Xarray-like of shape (n_samples, n_features)

Input samples.

+
+
yarray-like of shape (n_samples,) or (n_samples, n_outputs), default=None

Target values (None for unsupervised transformations).

+
+
**fit_paramsdict

Additional fit parameters.

+
+
+
+
Returns:
+
+
X_newndarray array of shape (n_samples, n_features_new)

Transformed array.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_output(*, transform=None)
+

Set output container.

+

See Introducing the set_output API +for an example on how to use the API.

+
+
Parameters:
+
+
transform{“default”, “pandas”}, default=None

Configure output of transform and fit_transform.

+
    +
  • “default”: Default output format of a transformer

  • +
  • “pandas”: DataFrame output

  • +
  • None: Transform configuration is unchanged

  • +
+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.NCA

+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.RCA.html b/generated/metric_learn.RCA.html new file mode 100644 index 00000000..9760ec4f --- /dev/null +++ b/generated/metric_learn.RCA.html @@ -0,0 +1,632 @@ + + + + + + + metric_learn.RCA — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.RCA

+
+
+class metric_learn.RCA(n_components=None, preprocessor=None)[source]
+

Relevant Components Analysis (RCA)

+

RCA learns a full rank Mahalanobis distance metric based on a weighted sum of +in-chunklets covariance matrices. It applies a global linear transformation +to assign large weights to relevant dimensions and low weights to irrelevant +dimensions. Those relevant dimensions are estimated using “chunklets”, +subsets of points that are known to belong to the same class.

+

Read more in the User Guide.

+
+
Parameters:
+
+
n_componentsint or None, optional (default=None)

Dimensionality of reduced space (if None, defaults to dimension of X).

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be formed like this: X[indices].

+
+
+
+
+

References

+
+
+[1] +

Noam Shental, et al. Adjustment learning and relevant component +analysis . +ECCV 2002.

+
+
+

Examples

+
>>> from metric_learn import RCA
+>>> X = [[-0.05,  3.0],[0.05, -3.0],
+>>>     [0.1, -3.55],[-0.1, 3.55],
+>>>     [-0.95, -0.05],[0.95, 0.05],
+>>>     [0.4,  0.05],[-0.4, -0.05]]
+>>> chunks = [0, 0, 1, 1, 2, 2, 3, 3]
+>>> rca = RCA()
+>>> rca.fit(X, chunks)
+
+
+
+
Attributes:
+
+
components_numpy.ndarray, shape=(n_components, n_features)

The learned linear transformation L.

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

fit(X, chunks)

Learn the RCA model.

fit_transform(X[, y])

Fit to data, then transform it.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_fit_request(*[, chunks])

Request metadata passed to the fit method.

set_output(*[, transform])

Set output container.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(n_components=None, preprocessor=None)[source]
+
+ +
+
+fit(X, chunks)[source]
+

Learn the RCA model.

+
+
Parameters:
+
+
data(n x d) data matrix

Each row corresponds to a single instance

+
+
chunks(n,) array of ints

When chunks[i] == -1, point i doesn’t belong to any chunklet. +When chunks[i] == j, point i belongs to chunklet j.

+
+
+
+
+
+ +
+
+fit_transform(X, y=None, **fit_params)
+

Fit to data, then transform it.

+

Fits transformer to X and y with optional parameters fit_params +and returns a transformed version of X.

+
+
Parameters:
+
+
Xarray-like of shape (n_samples, n_features)

Input samples.

+
+
yarray-like of shape (n_samples,) or (n_samples, n_outputs), default=None

Target values (None for unsupervised transformations).

+
+
**fit_paramsdict

Additional fit parameters.

+
+
+
+
Returns:
+
+
X_newndarray array of shape (n_samples, n_features_new)

Transformed array.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_fit_request(*, chunks: bool | None | str = '$UNCHANGED$') RCA
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
chunksstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for chunks parameter in fit.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_output(*, transform=None)
+

Set output container.

+

See Introducing the set_output API +for an example on how to use the API.

+
+
Parameters:
+
+
transform{“default”, “pandas”}, default=None

Configure output of transform and fit_transform.

+
    +
  • “default”: Default output format of a transformer

  • +
  • “pandas”: DataFrame output

  • +
  • None: Transform configuration is unchanged

  • +
+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.RCA

+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.RCA_Supervised.html b/generated/metric_learn.RCA_Supervised.html new file mode 100644 index 00000000..7caa64fb --- /dev/null +++ b/generated/metric_learn.RCA_Supervised.html @@ -0,0 +1,627 @@ + + + + + + + metric_learn.RCA_Supervised — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.RCA_Supervised

+
+
+class metric_learn.RCA_Supervised(n_components=None, n_chunks=100, chunk_size=2, preprocessor=None, random_state=None, num_chunks='deprecated')[source]
+

Supervised version of Relevant Components Analysis (RCA)

+

RCA_Supervised creates chunks of similar points by first sampling a +class, taking chunk_size elements in it, and repeating the process +n_chunks times.

+
+
Parameters:
+
+
n_componentsint or None, optional (default=None)

Dimensionality of reduced space (if None, defaults to dimension of X).

+
+
n_chunks: int, optional (default=100)

Number of chunks to generate.

+
+
chunk_size: int, optional (default=2)

Number of points per chunk.

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be formed like this: X[indices].

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int. +It is used to randomly sample constraints from labels.

+
+
num_chunksRenamed to n_chunks. Will be deprecated in 0.7.0
+
+
+
+

Examples

+
>>> from metric_learn import RCA_Supervised
+>>> from sklearn.datasets import load_iris
+>>> iris_data = load_iris()
+>>> X = iris_data['data']
+>>> Y = iris_data['target']
+>>> rca = RCA_Supervised(n_chunks=30, chunk_size=2)
+>>> rca.fit(X, Y)
+
+
+
+
Attributes:
+
+
components_numpy.ndarray, shape=(n_components, n_features)

The learned linear transformation L.

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

fit(X, y)

Create constraints from labels and learn the RCA model.

fit_transform(X[, y])

Fit to data, then transform it.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_fit_request(*[, chunks])

Request metadata passed to the fit method.

set_output(*[, transform])

Set output container.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(n_components=None, n_chunks=100, chunk_size=2, preprocessor=None, random_state=None, num_chunks='deprecated')[source]
+

Initialize the supervised version of RCA.

+
+ +
+
+fit(X, y)[source]
+

Create constraints from labels and learn the RCA model. +Needs n_constraints specified in constructor. (Not true?)

+
+
Parameters:
+
+
X(n x d) data matrix

each row corresponds to a single instance

+
+
y(n) data labels
+
+
+
+
+ +
+
+fit_transform(X, y=None, **fit_params)
+

Fit to data, then transform it.

+

Fits transformer to X and y with optional parameters fit_params +and returns a transformed version of X.

+
+
Parameters:
+
+
Xarray-like of shape (n_samples, n_features)

Input samples.

+
+
yarray-like of shape (n_samples,) or (n_samples, n_outputs), default=None

Target values (None for unsupervised transformations).

+
+
**fit_paramsdict

Additional fit parameters.

+
+
+
+
Returns:
+
+
X_newndarray array of shape (n_samples, n_features_new)

Transformed array.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_fit_request(*, chunks: bool | None | str = '$UNCHANGED$') RCA_Supervised
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
chunksstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for chunks parameter in fit.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_output(*, transform=None)
+

Set output container.

+

See Introducing the set_output API +for an example on how to use the API.

+
+
Parameters:
+
+
transform{“default”, “pandas”}, default=None

Configure output of transform and fit_transform.

+
    +
  • “default”: Default output format of a transformer

  • +
  • “pandas”: DataFrame output

  • +
  • None: Transform configuration is unchanged

  • +
+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.RCA_Supervised

+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.SCML.html b/generated/metric_learn.SCML.html new file mode 100644 index 00000000..cc714c99 --- /dev/null +++ b/generated/metric_learn.SCML.html @@ -0,0 +1,838 @@ + + + + + + + metric_learn.SCML — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.SCML

+
+
+class metric_learn.SCML(beta=1e-05, basis='triplet_diffs', n_basis=None, gamma=0.005, max_iter=10000, output_iter=500, batch_size=10, verbose=False, preprocessor=None, random_state=None)[source]
+

Sparse Compositional Metric Learning (SCML)

+

SCML learns an squared Mahalanobis distance from triplet constraints by +optimizing sparse positive weights assigned to a set of \(K\) rank-one +PSD bases. This can be formulated as an optimization problem with only +\(K\) parameters, that can be solved with an efficient stochastic +composite scheme.

+

Read more in the User Guide.

+
+

Warning

+

SCML is still a bit experimental, don’t hesitate to report if +something fails/doesn’t work as expected.

+
+
+
Parameters:
+
+
beta: float (default=1e-5)

L1 regularization parameter.

+
+
basisstring or array-like, optional (default=’triplet_diffs’)

Set of bases to construct the metric. Possible options are +‘triplet_diffs’, and an array-like of shape (n_basis, n_features).

+
+
‘triplet_diffs’

The basis set is constructed iteratively from differences between points +of n_features positive or negative pairs randomly sampled from the +triplets constraints. Requires the number of training triplets to be +great or equal to n_features.

+
+
array-like

A matrix of shape (n_basis, n_features), that will be used as +the basis set for the metric construction.

+
+
+
+
n_basisint, optional

Number of basis to be yielded. In case it is not set it will be set based +on basis. If no value is selected a default will be computed based on +the input.

+
+
gamma: float (default = 5e-3)

Learning rate for the optimization algorithm.

+
+
max_iterint (default = 10000)

Number of iterations for the algorithm.

+
+
output_iterint (default = 5000)

Number of iterations to check current weights performance and output this +information in case verbose is True.

+
+
verbosebool, optional

If True, prints information while learning.

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get triplets from indices. If array-like, +triplets will be formed like this: X[indices].

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int.

+
+
+
+
+
+

See also

+
+
metric_learn.SCML_Supervised

The supervised version of the algorithm.

+
+
Supervised versions of weakly-supervised algorithms

The section of the project documentation that describes the supervised version of weakly supervised estimators.

+
+
+
+

References

+
+
+[1] +

Y. Shi, A. Bellet and F. Sha. Sparse Compositional Metric Learning.. (AAAI), 2014.

+
+
+[2] +

Adapted from original Matlab implementation..

+
+
+

Examples

+
>>> from metric_learn import SCML
+>>> triplets = [[[1.2, 7.5], [1.3, 1.5], [6.2, 9.7]],
+>>>             [[1.3, 4.5], [3.2, 4.6], [5.4, 5.4]],
+>>>             [[3.2, 7.5], [3.3, 1.5], [8.2, 9.7]],
+>>>             [[3.3, 4.5], [5.2, 4.6], [7.4, 5.4]]]
+>>> scml = SCML()
+>>> scml.fit(triplets)
+
+
+
+
Attributes:
+
+
components_numpy.ndarray, shape=(n_features, n_features)

The linear transformation L deduced from the learned Mahalanobis +metric (See function _components_from_basis_weights.)

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

decision_function(triplets)

Predicts differences between sample distances in input triplets.

fit(triplets)

Learn the SCML model.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

predict(triplets)

Predicts the ordering between sample distances in input triplets.

score(triplets)

Computes score on input triplets.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_decision_function_request(*[, triplets])

Request metadata passed to the decision_function method.

set_fit_request(*[, triplets])

Request metadata passed to the fit method.

set_params(**params)

Set the parameters of this estimator.

set_predict_request(*[, triplets])

Request metadata passed to the predict method.

set_score_request(*[, triplets])

Request metadata passed to the score method.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(beta=1e-05, basis='triplet_diffs', n_basis=None, gamma=0.005, max_iter=10000, output_iter=500, batch_size=10, verbose=False, preprocessor=None, random_state=None)
+
+ +
+
+classes_ = array([0, 1])
+
+ +
+
+decision_function(triplets)
+

Predicts differences between sample distances in input triplets.

+

For each triplet (X_a, X_b, X_c) in the samples, computes the difference +between the learned distance of the second pair (X_a, X_c) minus the +learned distance of the first pair (X_a, X_b). The higher it is, the more +probable it is that the pairs in the triplets are presented in the right +order, i.e. that the label of the triplet is 1. The lower it is, the more +probable it is that the label of the triplet is -1.

+
+
Parameters:
+
+
tripletarray-like, shape=(n_triplets, 3, n_features) or (n_triplets, 3)

3D array of triplets to predict, with each row corresponding to three +points, or 2D array of indices of triplets if the metric learner +uses a preprocessor.

+
+
+
+
Returns:
+
+
decision_functionnumpy.ndarray of floats, shape=(n_constraints,)

Metric differences.

+
+
+
+
+
+ +
+
+fit(triplets)[source]
+

Learn the SCML model.

+
+
Parameters:
+
+
tripletsarray-like, shape=(n_constraints, 3, n_features) or (n_constraints, 3)

3D array-like of triplets of points or 2D array of triplets of +indicators. Triplets are assumed to be ordered such that: +d(triplets[i, 0],triplets[i, 1]) < d(triplets[i, 0], triplets[i, 2]).

+
+
+
+
Returns:
+
+
selfobject

Returns the instance.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+predict(triplets)
+

Predicts the ordering between sample distances in input triplets.

+

For each triplets, returns 1 if the first element is closer to the second +than to the last and -1 if not.

+
+
Parameters:
+
+
tripletsarray-like, shape=(n_triplets, 3, n_features) or (n_triplets, 3)

3D array of triplets to predict, with each row corresponding to three +points, or 2D array of indices of triplets if the metric learner +uses a preprocessor.

+
+
+
+
Returns:
+
+
predictionnumpy.ndarray of floats, shape=(n_constraints,)

Predictions of the ordering of pairs, for each triplet.

+
+
+
+
+
+ +
+
+score(triplets)
+

Computes score on input triplets.

+

Returns the accuracy score of the following classification task: a triplet +(X_a, X_b, X_c) is correctly classified if the predicted similarity between +the first pair (X_a, X_b) is higher than that of the second pair (X_a, X_c)

+
+
Parameters:
+
+
tripletsarray-like, shape=(n_triplets, 3, n_features) or (n_triplets, 3)

3D array of triplets to score, with each row corresponding to three +points, or 2D array of indices of triplets if the metric learner +uses a preprocessor.

+
+
+
+
Returns:
+
+
scorefloat

The triplets score.

+
+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_decision_function_request(*, triplets: bool | None | str = '$UNCHANGED$') SCML
+

Request metadata passed to the decision_function method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to decision_function if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to decision_function.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
tripletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for triplets parameter in decision_function.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_fit_request(*, triplets: bool | None | str = '$UNCHANGED$') SCML
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
tripletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for triplets parameter in fit.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_predict_request(*, triplets: bool | None | str = '$UNCHANGED$') SCML
+

Request metadata passed to the predict method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to predict if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to predict.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
tripletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for triplets parameter in predict.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_score_request(*, triplets: bool | None | str = '$UNCHANGED$') SCML
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
tripletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for triplets parameter in score.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.SCML_Supervised.html b/generated/metric_learn.SCML_Supervised.html new file mode 100644 index 00000000..81f925b4 --- /dev/null +++ b/generated/metric_learn.SCML_Supervised.html @@ -0,0 +1,629 @@ + + + + + + + metric_learn.SCML_Supervised — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.SCML_Supervised

+
+
+class metric_learn.SCML_Supervised(k_genuine=3, k_impostor=10, beta=1e-05, basis='lda', n_basis=None, gamma=0.005, max_iter=10000, output_iter=500, batch_size=10, verbose=False, preprocessor=None, random_state=None)[source]
+

Supervised version of Sparse Compositional Metric Learning (SCML)

+

SCML_Supervised creates triplets by taking k_genuine neighbours +of the same class and k_impostor neighbours from different classes for each +point and then runs the SCML algorithm on these triplets.

+

Read more in the User Guide.

+
+

Warning

+

SCML is still a bit experimental, don’t hesitate to report if +something fails/doesn’t work as expected.

+
+
+
Parameters:
+
+
beta: float (default=1e-5)

L1 regularization parameter.

+
+
basisstring or an array-like, optional (default=’lda’)

Set of bases to construct the metric. Possible options are +‘lda’, and an array-like of shape (n_basis, n_features).

+
+
‘lda’

The n_basis basis set is constructed from the LDA of significant +local regions in the feature space via clustering, for each region +center k-nearest neighbors are used to obtain the LDA scalings, +which correspond to the locally discriminative basis.

+
+
array-like

A matrix of shape (n_basis, n_features), that will be used as +the basis set for the metric construction.

+
+
+
+
n_basisint, optional

Number of basis to be yielded. In case it is not set it will be set based +on basis. If no value is selected a default will be computed based on +the input.

+
+
gamma: float (default = 5e-3)

Learning rate for the optimization algorithm.

+
+
max_iterint (default = 100000)

Number of iterations for the algorithm.

+
+
output_iterint (default = 5000)

Number of iterations to check current weights performance and output this +information in case verbose is True.

+
+
verbosebool, optional

If True, prints information while learning.

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get triplets from indices. If array-like, +triplets will be formed like this: X[indices].

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int.

+
+
+
+
+
+

See also

+
+
metric_learn.SCML

The weakly supervised version of this algorithm.

+
+
+
+

References

+
+
+[1] +

Y. Shi, A. Bellet and F. Sha. Sparse Compositional Metric Learning.. (AAAI), 2014.

+
+
+[2] +

Adapted from original Matlab implementation..

+
+
+

Examples

+
>>> from metric_learn import SCML_Supervised
+>>> from sklearn.datasets import load_iris
+>>> iris_data = load_iris()
+>>> X = iris_data['data']
+>>> Y = iris_data['target']
+>>> scml = SCML_Supervised(random_state=33)
+>>> scml.fit(X, Y)
+SCML_Supervised(random_state=33)
+>>> scml.score_pairs([[X[0], X[1]], [X[0], X[2]]])
+array([1.84640733, 1.55984363])
+>>> scml.get_metric()(X[0], X[1])
+1.8464073327922157
+
+
+
+
Attributes:
+
+
components_numpy.ndarray, shape=(n_features, n_features)

The linear transformation L deduced from the learned Mahalanobis +metric (See function _components_from_basis_weights.)

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

fit(X, y)

Create constraints from labels and learn the SCML model.

fit_transform(X[, y])

Fit to data, then transform it.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_output(*[, transform])

Set output container.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(k_genuine=3, k_impostor=10, beta=1e-05, basis='lda', n_basis=None, gamma=0.005, max_iter=10000, output_iter=500, batch_size=10, verbose=False, preprocessor=None, random_state=None)[source]
+
+ +
+
+fit(X, y)[source]
+

Create constraints from labels and learn the SCML model.

+
+
Parameters:
+
+
X(n x d) matrix

Input data, where each row corresponds to a single instance.

+
+
y(n) array-like

Data labels.

+
+
+
+
Returns:
+
+
selfobject

Returns the instance.

+
+
+
+
+
+ +
+
+fit_transform(X, y=None, **fit_params)
+

Fit to data, then transform it.

+

Fits transformer to X and y with optional parameters fit_params +and returns a transformed version of X.

+
+
Parameters:
+
+
Xarray-like of shape (n_samples, n_features)

Input samples.

+
+
yarray-like of shape (n_samples,) or (n_samples, n_outputs), default=None

Target values (None for unsupervised transformations).

+
+
**fit_paramsdict

Additional fit parameters.

+
+
+
+
Returns:
+
+
X_newndarray array of shape (n_samples, n_features_new)

Transformed array.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_output(*, transform=None)
+

Set output container.

+

See Introducing the set_output API +for an example on how to use the API.

+
+
Parameters:
+
+
transform{“default”, “pandas”}, default=None

Configure output of transform and fit_transform.

+
    +
  • “default”: Default output format of a transformer

  • +
  • “pandas”: DataFrame output

  • +
  • None: Transform configuration is unchanged

  • +
+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.SDML.html b/generated/metric_learn.SDML.html new file mode 100644 index 00000000..7abaacd4 --- /dev/null +++ b/generated/metric_learn.SDML.html @@ -0,0 +1,948 @@ + + + + + + + metric_learn.SDML — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.SDML

+
+
+class metric_learn.SDML(balance_param=0.5, sparsity_param=0.01, prior='identity', verbose=False, preprocessor=None, random_state=None)[source]
+

Sparse Distance Metric Learning (SDML)

+

SDML is an efficient sparse metric learning in high-dimensional space via +double regularization: an L1-penalization on the off-diagonal elements of the +Mahalanobis matrix \(\mathbf{M}\), and a log-determinant divergence +between \(\mathbf{M}\) and \(\mathbf{M_0}\) (set as either +\(\mathbf{I}\) or \(\mathbf{\Omega}^{-1}\), where +\(\mathbf{\Omega}\) is the covariance matrix).

+

Read more in the User Guide.

+
+
Parameters:
+
+
balance_paramfloat, optional (default=0.5)

Trade off between sparsity and M0 prior.

+
+
sparsity_paramfloat, optional (default=0.01)

Trade off between optimizer and sparseness (see graph_lasso).

+
+
priorstring or numpy array, optional (default=’identity’)

Prior to set for the metric. Possible options are +‘identity’, ‘covariance’, ‘random’, and a numpy array of +shape (n_features, n_features). For SDML, the prior should be strictly +positive definite (PD).

+
+
‘identity’

An identity matrix of shape (n_features, n_features).

+
+
‘covariance’

The inverse covariance matrix.

+
+
‘random’

The prior will be a random positive definite (PD) matrix of shape +(n_features, n_features), generated using +sklearn.datasets.make_spd_matrix.

+
+
numpy array

A positive definite (PD) matrix of shape +(n_features, n_features), that will be used as such to set the +prior.

+
+
+
+
verbosebool, optional (default=False)

If True, prints information while learning.

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be gotten like this: X[indices].

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int. If +prior='random', random_state is used to set the prior.

+
+
+
+
+

References

+ +

Examples

+
>>> from metric_learn import SDML_Supervised
+>>> from sklearn.datasets import load_iris
+>>> iris_data = load_iris()
+>>> X = iris_data['data']
+>>> Y = iris_data['target']
+>>> sdml = SDML_Supervised(n_constraints=200)
+>>> sdml.fit(X, Y)
+
+
+
+
Attributes:
+
+
components_numpy.ndarray, shape=(n_features, n_features)

The linear transformation L deduced from the learned Mahalanobis +metric (See function components_from_metric.)

+
+
threshold_float

If the distance metric between two points is lower than this threshold, +points will be classified as similar, otherwise they will be +classified as dissimilar.

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

calibrate_threshold(pairs_valid, y_valid[, ...])

Decision threshold calibration for pairwise binary classification

decision_function(pairs)

Returns the decision function used to classify the pairs.

fit(pairs, y[, calibration_params])

Learn the SDML model.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

predict(pairs)

Predicts the learned metric between input pairs.

score(pairs, y)

Computes score of pairs similarity prediction.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_decision_function_request(*[, pairs])

Request metadata passed to the decision_function method.

set_fit_request(*[, calibration_params, pairs])

Request metadata passed to the fit method.

set_params(**params)

Set the parameters of this estimator.

set_predict_request(*[, pairs])

Request metadata passed to the predict method.

set_score_request(*[, pairs])

Request metadata passed to the score method.

set_threshold(threshold)

Sets the threshold of the metric learner to the given value threshold.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(balance_param=0.5, sparsity_param=0.01, prior='identity', verbose=False, preprocessor=None, random_state=None)
+
+ +
+
+calibrate_threshold(pairs_valid, y_valid, strategy='accuracy', min_rate=None, beta=1.0)
+

Decision threshold calibration for pairwise binary classification

+

Method that calibrates the decision threshold (cutoff point) of the metric +learner. This threshold will then be used when calling the method +predict. The methods for picking cutoff points make use of traditional +binary classification evaluation statistics such as the true positive and +true negative rates and F-scores. The threshold will be found to maximize +the chosen score on the validation set (pairs_valid, y_valid).

+

See more in the User Guide.

+
+
Parameters:
+
+
strategystr, optional (default=’accuracy’)

The strategy to use for choosing the cutoff threshold.

+
+
‘accuracy’

Selects a decision threshold that maximizes the accuracy.

+
+
‘f_beta’

Selects a decision threshold that maximizes the f_beta score, +with beta given by the parameter beta.

+
+
‘max_tpr’

Selects a decision threshold that yields the highest true positive +rate with true negative rate at least equal to the value of the +parameter min_rate.

+
+
‘max_tnr’

Selects a decision threshold that yields the highest true negative +rate with true positive rate at least equal to the value of the +parameter min_rate.

+
+
+
+
betafloat in [0, 1], optional (default=None)

Beta value to be used in case strategy == ‘f_beta’.

+
+
min_ratefloat in [0, 1] or None, (default=None)

In case strategy is ‘max_tpr’ or ‘max_tnr’ this parameter must be set +to specify the minimal value for the true negative rate or true positive +rate respectively that needs to be achieved.

+
+
pairs_validarray-like, shape=(n_pairs_valid, 2, n_features)

The validation set of pairs to use to set the threshold.

+
+
y_validarray-like, shape=(n_pairs_valid,)

The labels of the pairs of the validation set to use to set the +threshold. They must be +1 for positive pairs and -1 for negative pairs.

+
+
+
+
+
+

See also

+
+
sklearn.calibration

scikit-learn’s module for calibrating classifiers

+
+
+
+

References

+
+
+[1] +

Receiver-operating characteristic (ROC) plots: a fundamental +evaluation tool in clinical medicine, MH Zweig, G Campbell - +Clinical chemistry, 1993

+
+
+[2] +

Most of the code of this function is from scikit-learn’s PR #10117

+
+
+
+ +
+
+classes_ = array([0, 1])
+
+ +
+
+decision_function(pairs)
+

Returns the decision function used to classify the pairs.

+

Returns the opposite of the learned metric value between samples in every +pair, to be consistent with scikit-learn conventions. Hence it should +ideally be low for dissimilar samples and high for similar samples. +This is the decision function that is used to classify pairs as similar +(+1), or dissimilar (-1).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to predict, with each row corresponding to two +points, or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
y_predictednumpy.ndarray of floats, shape=(n_constraints,)

The predicted decision function value for each pair.

+
+
+
+
+
+ +
+
+fit(pairs, y, calibration_params=None)[source]
+

Learn the SDML model.

+

The threshold will be calibrated on the trainset using the parameters +calibration_params.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_constraints, 2, n_features) or (n_constraints, 2)

3D Array of pairs with each row corresponding to two points, +or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
yarray-like, of shape (n_constraints,)

Labels of constraints. Should be -1 for dissimilar pair, 1 for similar.

+
+
calibration_paramsdict or None

Dictionary of parameters to give to calibrate_threshold for the +threshold calibration step done at the end of fit. If None is +given, calibrate_threshold will use the default parameters.

+
+
+
+
Returns:
+
+
selfobject

Returns the instance.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+predict(pairs)
+

Predicts the learned metric between input pairs. (For now it just +calls decision function).

+

Returns the learned metric value between samples in every pair. It should +ideally be low for similar samples and high for dissimilar samples.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to predict, with each row corresponding to two +points, or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
y_predictednumpy.ndarray of floats, shape=(n_constraints,)

The predicted learned metric value between samples in every pair.

+
+
+
+
+
+ +
+
+score(pairs, y)
+

Computes score of pairs similarity prediction.

+

Returns the roc_auc score of the fitted metric learner. It is +computed in the following way: for every value of a threshold +t we classify all pairs of samples where the predicted distance is +inferior to t as belonging to the “similar” class, and the other as +belonging to the “dissimilar” class, and we count false positive and +true positives as in a classical roc_auc curve.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs, with each row corresponding to two points, +or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
yarray-like, shape=(n_constraints,)

The corresponding labels.

+
+
+
+
Returns:
+
+
scorefloat

The roc_auc score.

+
+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_decision_function_request(*, pairs: bool | None | str = '$UNCHANGED$') SDML
+

Request metadata passed to the decision_function method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to decision_function if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to decision_function.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in decision_function.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_fit_request(*, calibration_params: bool | None | str = '$UNCHANGED$', pairs: bool | None | str = '$UNCHANGED$') SDML
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
calibration_paramsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for calibration_params parameter in fit.

+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in fit.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_predict_request(*, pairs: bool | None | str = '$UNCHANGED$') SDML
+

Request metadata passed to the predict method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to predict if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to predict.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in predict.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_score_request(*, pairs: bool | None | str = '$UNCHANGED$') SDML
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in score.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_threshold(threshold)
+

Sets the threshold of the metric learner to the given value threshold.

+

See more in the User Guide.

+
+
Parameters:
+
+
thresholdfloat

The threshold value we want to set. It is the value to which the +predicted distance for test pairs will be compared. If they are superior +to the threshold they will be classified as similar (+1), +and dissimilar (-1) if not.

+
+
+
+
Returns:
+
+
self_PairsClassifier

The pairs classifier with the new threshold set.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.SDML

+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.SDML_Supervised.html b/generated/metric_learn.SDML_Supervised.html new file mode 100644 index 00000000..da408ece --- /dev/null +++ b/generated/metric_learn.SDML_Supervised.html @@ -0,0 +1,613 @@ + + + + + + + metric_learn.SDML_Supervised — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.SDML_Supervised

+
+
+class metric_learn.SDML_Supervised(balance_param=0.5, sparsity_param=0.01, prior='identity', n_constraints=None, verbose=False, preprocessor=None, random_state=None, num_constraints='deprecated')[source]
+

Supervised version of Sparse Distance Metric Learning (SDML)

+

SDML_Supervised creates pairs of similar sample by taking same class +samples, and pairs of dissimilar samples by taking different class +samples. It then passes these pairs to SDML for training.

+
+
Parameters:
+
+
balance_paramfloat, optional (default=0.5)

Trade off between sparsity and M0 prior.

+
+
sparsity_paramfloat, optional (default=0.01)

Trade off between optimizer and sparseness (see graph_lasso).

+
+
priorstring or numpy array, optional (default=’identity’)

Prior to set for the metric. Possible options are +‘identity’, ‘covariance’, ‘random’, and a numpy array of +shape (n_features, n_features). For SDML, the prior should be strictly +positive definite (PD).

+
+
‘identity’

An identity matrix of shape (n_features, n_features).

+
+
‘covariance’

The inverse covariance matrix.

+
+
‘random’

The prior will be a random SPD matrix of shape +(n_features, n_features), generated using +sklearn.datasets.make_spd_matrix.

+
+
numpy array

A positive definite (PD) matrix of shape +(n_features, n_features), that will be used as such to set the +prior.

+
+
+
+
n_constraintsint, optional (default=None)

Number of constraints to generate. If None, defaults to 20 * +num_classes**2.

+
+
verbosebool, optional (default=False)

If True, prints information while learning.

+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be formed like this: X[indices].

+
+
random_stateint or numpy.RandomState or None, optional (default=None)

A pseudo random number generator object or a seed for it if int. If +init='random', random_state is used to set the random +prior. In any case, random_state is also used to randomly sample +constraints from labels.

+
+
num_constraintsRenamed to n_constraints. Will be deprecated in 0.7.0
+
+
+
+
+

See also

+
+
metric_learn.SDML

The original weakly-supervised algorithm

+
+
Supervised versions of weakly-supervised algorithms

The section of the project documentation that describes the supervised version of weakly supervised estimators.

+
+
+
+
+
Attributes:
+
+
components_numpy.ndarray, shape=(n_features, n_features)

The linear transformation L deduced from the learned Mahalanobis +metric (See function components_from_metric.)

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

fit(X, y)

Create constraints from labels and learn the SDML model.

fit_transform(X[, y])

Fit to data, then transform it.

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_output(*[, transform])

Set output container.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(balance_param=0.5, sparsity_param=0.01, prior='identity', n_constraints=None, verbose=False, preprocessor=None, random_state=None, num_constraints='deprecated')[source]
+
+ +
+
+fit(X, y)[source]
+

Create constraints from labels and learn the SDML model.

+
+
Parameters:
+
+
Xarray-like, shape (n, d)

data matrix, where each row corresponds to a single instance

+
+
yarray-like, shape (n,)

data labels, one for each instance

+
+
+
+
Returns:
+
+
selfobject

Returns the instance.

+
+
+
+
+
+ +
+
+fit_transform(X, y=None, **fit_params)
+

Fit to data, then transform it.

+

Fits transformer to X and y with optional parameters fit_params +and returns a transformed version of X.

+
+
Parameters:
+
+
Xarray-like of shape (n_samples, n_features)

Input samples.

+
+
yarray-like of shape (n_samples,) or (n_samples, n_outputs), default=None

Target values (None for unsupervised transformations).

+
+
**fit_paramsdict

Additional fit parameters.

+
+
+
+
Returns:
+
+
X_newndarray array of shape (n_samples, n_features_new)

Transformed array.

+
+
+
+
+
+ +
+
+get_mahalanobis_matrix()
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_output(*, transform=None)
+

Set output container.

+

See Introducing the set_output API +for an example on how to use the API.

+
+
Parameters:
+
+
transform{“default”, “pandas”}, default=None

Configure output of transform and fit_transform.

+
    +
  • “default”: Default output format of a transformer

  • +
  • “pandas”: DataFrame output

  • +
  • None: Transform configuration is unchanged

  • +
+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.SDML_Supervised

+
+

Sandwich demo

+
Sandwich demo
+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.base_metric.BaseMetricLearner.html b/generated/metric_learn.base_metric.BaseMetricLearner.html new file mode 100644 index 00000000..bae6a6f2 --- /dev/null +++ b/generated/metric_learn.base_metric.BaseMetricLearner.html @@ -0,0 +1,424 @@ + + + + + + + metric_learn.base_metric.BaseMetricLearner — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.base_metric.BaseMetricLearner

+
+
+class metric_learn.base_metric.BaseMetricLearner(preprocessor=None)[source]
+

Base class for all metric-learners.

+
+
Parameters:
+
+
preprocessorarray-like, shape=(n_samples, n_features) or callable

The preprocessor to call to get tuples from indices. If array-like, +tuples will be gotten like this: X[indices].

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + +

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

+

New in version 0.7.0: Compute the distance between pairs

+
+

pair_score(pairs)

+

New in version 0.7.0: Compute the similarity score between pairs

+
+

score_pairs(pairs)

Returns the score between pairs (can be a similarity, or a distance/metric depending on the algorithm)

set_params(**params)

Set the parameters of this estimator.

+
+
+__init__(preprocessor=None)[source]
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+abstract get_metric()[source]
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+abstract pair_distance(pairs)[source]
+
+

New in version 0.7.0: Compute the distance between pairs

+
+

Returns the (pseudo) distance between pairs, when available. For metric +learners that do not learn a (pseudo) distance, an error is thrown +instead.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs for which to compute the distance, with each +row corresponding to two points, for 2D array of indices of pairs +if the metric learner uses a preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The distance between every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
+
+
+ +
+
+abstract pair_score(pairs)[source]
+
+

New in version 0.7.0: Compute the similarity score between pairs

+
+

Returns the similarity score between pairs of points (the larger the score, +the more similar the pair). For metric learners that learn a distance, +the score is simply the opposite of the distance between pairs. All +learners have access to this method.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The score of every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
+
+
+ +
+
+abstract score_pairs(pairs)[source]
+

Returns the score between pairs +(can be a similarity, or a distance/metric depending on the algorithm)

+
+

Deprecated since version 0.7.0: Refer to pair_distance and pair_score.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The score of every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference between score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.base_metric.BaseMetricLearner

+
+

Sandwich demo

+
Sandwich demo
+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.base_metric.MahalanobisMixin.html b/generated/metric_learn.base_metric.MahalanobisMixin.html new file mode 100644 index 00000000..aba8bcb4 --- /dev/null +++ b/generated/metric_learn.base_metric.MahalanobisMixin.html @@ -0,0 +1,478 @@ + + + + + + + metric_learn.base_metric.MahalanobisMixin — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.base_metric.MahalanobisMixin

+
+
+class metric_learn.base_metric.MahalanobisMixin(preprocessor=None)[source]
+

Mahalanobis metric learning algorithms.

+

Algorithm that learns a Mahalanobis (pseudo) distance \(d_M(x, x')\), +defined between two column vectors \(x\) and \(x'\) by: \(d_M(x, +x') = \sqrt{(x-x')^T M (x-x')}\), where \(M\) is a learned symmetric +positive semi-definite (PSD) matrix. The metric between points can then be +expressed as the euclidean distance between points embedded in a new space +through a linear transformation. Indeed, the above matrix can be decomposed +into the product of two transpose matrices (through SVD or Cholesky +decomposition): \(d_M(x, x')^2 = (x-x')^T M (x-x') = (x-x')^T L^T L +(x-x') = (L x - L x')^T (L x- L x')\)

+
+
Attributes:
+
+
components_numpy.ndarray, shape=(n_components, n_features)

The learned linear transformation L.

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

get_mahalanobis_matrix()

Returns a copy of the Mahalanobis matrix learned by the metric learner.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

Returns the learned Mahalanobis distance between pairs.

pair_score(pairs)

Returns the opposite of the learned Mahalanobis distance between pairs.

score_pairs(pairs)

Returns the learned Mahalanobis distance between pairs.

set_params(**params)

Set the parameters of this estimator.

transform(X)

Embeds data points in the learned linear embedding space.

+
+
+__init__(preprocessor=None)
+
+ +
+
+get_mahalanobis_matrix()[source]
+

Returns a copy of the Mahalanobis matrix learned by the metric learner.

+
+
Returns:
+
+
Mnumpy.ndarray, shape=(n_features, n_features)

The copy of the learned Mahalanobis matrix.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+get_metric()[source]
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+pair_distance(pairs)[source]
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+pair_score(pairs)[source]
+

Returns the opposite of the learned Mahalanobis distance between pairs.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The opposite of the learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+score_pairs(pairs)[source]
+

Returns the learned Mahalanobis distance between pairs.

+

This distance is defined as: \(d_M(x, x') = \\sqrt{(x-x')^T M (x-x')}\) +where M is the learned Mahalanobis matrix, for every pair of points +x and x'. This corresponds to the euclidean distance between +embeddings of the points in a new space, obtained through a linear +transformation. Indeed, we have also: \(d_M(x, x') = \\sqrt{(x_e - +x_e')^T (x_e- x_e')}\), with \(x_e = L x\) (See +MahalanobisMixin).

+
+

Deprecated since version 0.7.0: Please use pair_distance instead.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The learned Mahalanobis distance for every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
Mahalanobis Distances

The section of the project documentation that describes Mahalanobis Distances.

+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+transform(X)[source]
+

Embeds data points in the learned linear embedding space.

+

Transforms samples in X into X_embedded, samples inside a new +embedding space such that: X_embedded = X.dot(L.T), where L is +the learned linear transformation (See MahalanobisMixin).

+
+
Parameters:
+
+
Xnumpy.ndarray, shape=(n_samples, n_features)

The data points to embed.

+
+
+
+
Returns:
+
+
X_embeddednumpy.ndarray, shape=(n_samples, n_components)

The embedded data points.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.base_metric.MahalanobisMixin

+
+

Sandwich demo

+
Sandwich demo
+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.base_metric.MetricTransformer.html b/generated/metric_learn.base_metric.MetricTransformer.html new file mode 100644 index 00000000..73298bff --- /dev/null +++ b/generated/metric_learn.base_metric.MetricTransformer.html @@ -0,0 +1,192 @@ + + + + + + + metric_learn.base_metric.MetricTransformer — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.base_metric.MetricTransformer

+
+
+class metric_learn.base_metric.MetricTransformer[source]
+

Base class for all learners that can transform data into a new space +with the metric learned.

+

Methods

+ + + + + + +

transform(X)

Applies the metric transformation.

+
+
+abstract transform(X)[source]
+

Applies the metric transformation.

+
+
Parameters:
+
+
X(n x d) matrix

Data to transform.

+
+
+
+
Returns:
+
+
transformed(n x d) matrix

Input data transformed to the metric space by \(XL^{\top}\)

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.base_metric.MetricTransformer

+
+

Sandwich demo

+
Sandwich demo
+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.base_metric._PairsClassifierMixin.html b/generated/metric_learn.base_metric._PairsClassifierMixin.html new file mode 100644 index 00000000..0caf244a --- /dev/null +++ b/generated/metric_learn.base_metric._PairsClassifierMixin.html @@ -0,0 +1,753 @@ + + + + + + + metric_learn.base_metric._PairsClassifierMixin — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.base_metric._PairsClassifierMixin

+
+
+class metric_learn.base_metric._PairsClassifierMixin(preprocessor=None)[source]
+

Base class for pairs learners.

+
+
Attributes:
+
+
threshold_float

If the distance metric between two points is lower than this threshold, +points will be classified as similar, otherwise they will be +classified as dissimilar.

+
+
+
+
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

calibrate_threshold(pairs_valid, y_valid[, ...])

Decision threshold calibration for pairwise binary classification

decision_function(pairs)

Returns the decision function used to classify the pairs.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

+

New in version 0.7.0: Compute the distance between pairs

+
+

pair_score(pairs)

+

New in version 0.7.0: Compute the similarity score between pairs

+
+

predict(pairs)

Predicts the learned metric between input pairs.

score(pairs, y)

Computes score of pairs similarity prediction.

score_pairs(pairs)

Returns the score between pairs (can be a similarity, or a distance/metric depending on the algorithm)

set_decision_function_request(*[, pairs])

Request metadata passed to the decision_function method.

set_params(**params)

Set the parameters of this estimator.

set_predict_request(*[, pairs])

Request metadata passed to the predict method.

set_score_request(*[, pairs])

Request metadata passed to the score method.

set_threshold(threshold)

Sets the threshold of the metric learner to the given value threshold.

+
+
+__init__(preprocessor=None)
+
+ +
+
+calibrate_threshold(pairs_valid, y_valid, strategy='accuracy', min_rate=None, beta=1.0)[source]
+

Decision threshold calibration for pairwise binary classification

+

Method that calibrates the decision threshold (cutoff point) of the metric +learner. This threshold will then be used when calling the method +predict. The methods for picking cutoff points make use of traditional +binary classification evaluation statistics such as the true positive and +true negative rates and F-scores. The threshold will be found to maximize +the chosen score on the validation set (pairs_valid, y_valid).

+

See more in the User Guide.

+
+
Parameters:
+
+
strategystr, optional (default=’accuracy’)

The strategy to use for choosing the cutoff threshold.

+
+
‘accuracy’

Selects a decision threshold that maximizes the accuracy.

+
+
‘f_beta’

Selects a decision threshold that maximizes the f_beta score, +with beta given by the parameter beta.

+
+
‘max_tpr’

Selects a decision threshold that yields the highest true positive +rate with true negative rate at least equal to the value of the +parameter min_rate.

+
+
‘max_tnr’

Selects a decision threshold that yields the highest true negative +rate with true positive rate at least equal to the value of the +parameter min_rate.

+
+
+
+
betafloat in [0, 1], optional (default=None)

Beta value to be used in case strategy == ‘f_beta’.

+
+
min_ratefloat in [0, 1] or None, (default=None)

In case strategy is ‘max_tpr’ or ‘max_tnr’ this parameter must be set +to specify the minimal value for the true negative rate or true positive +rate respectively that needs to be achieved.

+
+
pairs_validarray-like, shape=(n_pairs_valid, 2, n_features)

The validation set of pairs to use to set the threshold.

+
+
y_validarray-like, shape=(n_pairs_valid,)

The labels of the pairs of the validation set to use to set the +threshold. They must be +1 for positive pairs and -1 for negative pairs.

+
+
+
+
+
+

See also

+
+
sklearn.calibration

scikit-learn’s module for calibrating classifiers

+
+
+
+

References

+
+
+[1] +

Receiver-operating characteristic (ROC) plots: a fundamental +evaluation tool in clinical medicine, MH Zweig, G Campbell - +Clinical chemistry, 1993

+
+
+[2] +

Most of the code of this function is from scikit-learn’s PR #10117

+
+
+
+ +
+
+classes_ = array([0, 1])
+
+ +
+
+decision_function(pairs)[source]
+

Returns the decision function used to classify the pairs.

+

Returns the opposite of the learned metric value between samples in every +pair, to be consistent with scikit-learn conventions. Hence it should +ideally be low for dissimilar samples and high for similar samples. +This is the decision function that is used to classify pairs as similar +(+1), or dissimilar (-1).

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to predict, with each row corresponding to two +points, or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
y_predictednumpy.ndarray of floats, shape=(n_constraints,)

The predicted decision function value for each pair.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+abstract get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+abstract pair_distance(pairs)
+
+

New in version 0.7.0: Compute the distance between pairs

+
+

Returns the (pseudo) distance between pairs, when available. For metric +learners that do not learn a (pseudo) distance, an error is thrown +instead.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs for which to compute the distance, with each +row corresponding to two points, for 2D array of indices of pairs +if the metric learner uses a preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The distance between every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
+
+
+ +
+
+abstract pair_score(pairs)
+
+

New in version 0.7.0: Compute the similarity score between pairs

+
+

Returns the similarity score between pairs of points (the larger the score, +the more similar the pair). For metric learners that learn a distance, +the score is simply the opposite of the distance between pairs. All +learners have access to this method.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The score of every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
+
+
+ +
+
+predict(pairs)[source]
+

Predicts the learned metric between input pairs. (For now it just +calls decision function).

+

Returns the learned metric value between samples in every pair. It should +ideally be low for similar samples and high for dissimilar samples.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to predict, with each row corresponding to two +points, or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
y_predictednumpy.ndarray of floats, shape=(n_constraints,)

The predicted learned metric value between samples in every pair.

+
+
+
+
+
+ +
+
+score(pairs, y)[source]
+

Computes score of pairs similarity prediction.

+

Returns the roc_auc score of the fitted metric learner. It is +computed in the following way: for every value of a threshold +t we classify all pairs of samples where the predicted distance is +inferior to t as belonging to the “similar” class, and the other as +belonging to the “dissimilar” class, and we count false positive and +true positives as in a classical roc_auc curve.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs, with each row corresponding to two points, +or 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
yarray-like, shape=(n_constraints,)

The corresponding labels.

+
+
+
+
Returns:
+
+
scorefloat

The roc_auc score.

+
+
+
+
+
+ +
+
+abstract score_pairs(pairs)
+

Returns the score between pairs +(can be a similarity, or a distance/metric depending on the algorithm)

+
+

Deprecated since version 0.7.0: Refer to pair_distance and pair_score.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The score of every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference between score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
+
+
+ +
+
+set_decision_function_request(*, pairs: bool | None | str = '$UNCHANGED$') _PairsClassifierMixin
+

Request metadata passed to the decision_function method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to decision_function if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to decision_function.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in decision_function.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_predict_request(*, pairs: bool | None | str = '$UNCHANGED$') _PairsClassifierMixin
+

Request metadata passed to the predict method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to predict if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to predict.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in predict.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_score_request(*, pairs: bool | None | str = '$UNCHANGED$') _PairsClassifierMixin
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
pairsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for pairs parameter in score.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_threshold(threshold)[source]
+

Sets the threshold of the metric learner to the given value threshold.

+

See more in the User Guide.

+
+
Parameters:
+
+
thresholdfloat

The threshold value we want to set. It is the value to which the +predicted distance for test pairs will be compared. If they are superior +to the threshold they will be classified as similar (+1), +and dissimilar (-1) if not.

+
+
+
+
Returns:
+
+
self_PairsClassifier

The pairs classifier with the new threshold set.

+
+
+
+
+
+ +
+ +
+

Examples using metric_learn.base_metric._PairsClassifierMixin

+
+

Algorithms walkthrough

+
Algorithms walkthrough
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.base_metric._QuadrupletsClassifierMixin.html b/generated/metric_learn.base_metric._QuadrupletsClassifierMixin.html new file mode 100644 index 00000000..e1e27e25 --- /dev/null +++ b/generated/metric_learn.base_metric._QuadrupletsClassifierMixin.html @@ -0,0 +1,634 @@ + + + + + + + metric_learn.base_metric._QuadrupletsClassifierMixin — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.base_metric._QuadrupletsClassifierMixin

+
+
+class metric_learn.base_metric._QuadrupletsClassifierMixin(preprocessor=None)[source]
+

Base class for quadruplets learners.

+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

decision_function(quadruplets)

Predicts differences between sample distances in input quadruplets.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

+

New in version 0.7.0: Compute the distance between pairs

+
+

pair_score(pairs)

+

New in version 0.7.0: Compute the similarity score between pairs

+
+

predict(quadruplets)

Predicts the ordering between sample distances in input quadruplets.

score(quadruplets)

Computes score on input quadruplets

score_pairs(pairs)

Returns the score between pairs (can be a similarity, or a distance/metric depending on the algorithm)

set_decision_function_request(*[, quadruplets])

Request metadata passed to the decision_function method.

set_params(**params)

Set the parameters of this estimator.

set_predict_request(*[, quadruplets])

Request metadata passed to the predict method.

set_score_request(*[, quadruplets])

Request metadata passed to the score method.

+
+
+__init__(preprocessor=None)
+
+ +
+
+classes_ = array([0, 1])
+
+ +
+
+decision_function(quadruplets)[source]
+

Predicts differences between sample distances in input quadruplets.

+

For each quadruplet in the samples, computes the difference between the +learned metric of the second pair minus the learned metric of the first +pair. The higher it is, the more probable it is that the pairs in the +quadruplet are presented in the right order, i.e. that the label of the +quadruplet is 1. The lower it is, the more probable it is that the label of +the quadruplet is -1.

+
+
Parameters:
+
+
quadrupletsarray-like, shape=(n_quadruplets, 4, n_features) or (n_quadruplets, 4)

3D Array of quadruplets to predict, with each row corresponding to four +points, or 2D array of indices of quadruplets if the metric learner +uses a preprocessor.

+
+
+
+
Returns:
+
+
decision_functionnumpy.ndarray of floats, shape=(n_constraints,)

Metric differences.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+abstract get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+abstract pair_distance(pairs)
+
+

New in version 0.7.0: Compute the distance between pairs

+
+

Returns the (pseudo) distance between pairs, when available. For metric +learners that do not learn a (pseudo) distance, an error is thrown +instead.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs for which to compute the distance, with each +row corresponding to two points, for 2D array of indices of pairs +if the metric learner uses a preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The distance between every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
+
+
+ +
+
+abstract pair_score(pairs)
+
+

New in version 0.7.0: Compute the similarity score between pairs

+
+

Returns the similarity score between pairs of points (the larger the score, +the more similar the pair). For metric learners that learn a distance, +the score is simply the opposite of the distance between pairs. All +learners have access to this method.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The score of every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
+
+
+ +
+
+predict(quadruplets)[source]
+

Predicts the ordering between sample distances in input quadruplets.

+

For each quadruplet, returns 1 if the quadruplet is in the right order ( +first pair is more similar than second pair), and -1 if not.

+
+
Parameters:
+
+
quadrupletsarray-like, shape=(n_quadruplets, 4, n_features) or (n_quadruplets, 4)

3D Array of quadruplets to predict, with each row corresponding to four +points, or 2D array of indices of quadruplets if the metric learner +uses a preprocessor.

+
+
+
+
Returns:
+
+
predictionnumpy.ndarray of floats, shape=(n_constraints,)

Predictions of the ordering of pairs, for each quadruplet.

+
+
+
+
+
+ +
+
+score(quadruplets)[source]
+

Computes score on input quadruplets

+

Returns the accuracy score of the following classification task: a record +is correctly classified if the predicted similarity between the first two +samples is higher than that of the last two.

+
+
Parameters:
+
+
quadrupletsarray-like, shape=(n_quadruplets, 4, n_features) or (n_quadruplets, 4)

3D Array of quadruplets to score, with each row corresponding to four +points, or 2D array of indices of quadruplets if the metric learner +uses a preprocessor.

+
+
+
+
Returns:
+
+
scorefloat

The quadruplets score.

+
+
+
+
+
+ +
+
+abstract score_pairs(pairs)
+

Returns the score between pairs +(can be a similarity, or a distance/metric depending on the algorithm)

+
+

Deprecated since version 0.7.0: Refer to pair_distance and pair_score.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The score of every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference between score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
+
+
+ +
+
+set_decision_function_request(*, quadruplets: bool | None | str = '$UNCHANGED$') _QuadrupletsClassifierMixin
+

Request metadata passed to the decision_function method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to decision_function if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to decision_function.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
quadrupletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for quadruplets parameter in decision_function.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_predict_request(*, quadruplets: bool | None | str = '$UNCHANGED$') _QuadrupletsClassifierMixin
+

Request metadata passed to the predict method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to predict if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to predict.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
quadrupletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for quadruplets parameter in predict.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_score_request(*, quadruplets: bool | None | str = '$UNCHANGED$') _QuadrupletsClassifierMixin
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
quadrupletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for quadruplets parameter in score.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+ +
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/generated/metric_learn.base_metric._TripletsClassifierMixin.html b/generated/metric_learn.base_metric._TripletsClassifierMixin.html new file mode 100644 index 00000000..0377ca7a --- /dev/null +++ b/generated/metric_learn.base_metric._TripletsClassifierMixin.html @@ -0,0 +1,634 @@ + + + + + + + metric_learn.base_metric._TripletsClassifierMixin — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn.base_metric._TripletsClassifierMixin

+
+
+class metric_learn.base_metric._TripletsClassifierMixin(preprocessor=None)[source]
+

Base class for triplets learners.

+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

decision_function(triplets)

Predicts differences between sample distances in input triplets.

get_metadata_routing()

Get metadata routing of this object.

get_metric()

Returns a function that takes as input two 1D arrays and outputs the value of the learned metric on these two points.

get_params([deep])

Get parameters for this estimator.

pair_distance(pairs)

+

New in version 0.7.0: Compute the distance between pairs

+
+

pair_score(pairs)

+

New in version 0.7.0: Compute the similarity score between pairs

+
+

predict(triplets)

Predicts the ordering between sample distances in input triplets.

score(triplets)

Computes score on input triplets.

score_pairs(pairs)

Returns the score between pairs (can be a similarity, or a distance/metric depending on the algorithm)

set_decision_function_request(*[, triplets])

Request metadata passed to the decision_function method.

set_params(**params)

Set the parameters of this estimator.

set_predict_request(*[, triplets])

Request metadata passed to the predict method.

set_score_request(*[, triplets])

Request metadata passed to the score method.

+
+
+__init__(preprocessor=None)
+
+ +
+
+classes_ = array([0, 1])
+
+ +
+
+decision_function(triplets)[source]
+

Predicts differences between sample distances in input triplets.

+

For each triplet (X_a, X_b, X_c) in the samples, computes the difference +between the learned distance of the second pair (X_a, X_c) minus the +learned distance of the first pair (X_a, X_b). The higher it is, the more +probable it is that the pairs in the triplets are presented in the right +order, i.e. that the label of the triplet is 1. The lower it is, the more +probable it is that the label of the triplet is -1.

+
+
Parameters:
+
+
tripletarray-like, shape=(n_triplets, 3, n_features) or (n_triplets, 3)

3D array of triplets to predict, with each row corresponding to three +points, or 2D array of indices of triplets if the metric learner +uses a preprocessor.

+
+
+
+
Returns:
+
+
decision_functionnumpy.ndarray of floats, shape=(n_constraints,)

Metric differences.

+
+
+
+
+
+ +
+
+get_metadata_routing()
+

Get metadata routing of this object.

+

Please check User Guide on how the routing +mechanism works.

+
+
Returns:
+
+
routingMetadataRequest

A MetadataRequest encapsulating +routing information.

+
+
+
+
+
+ +
+
+abstract get_metric()
+

Returns a function that takes as input two 1D arrays and outputs +the value of the learned metric on these two points. Depending on the +algorithm, it can return a distance or a similarity function between +pairs.

+

This function will be independent from the metric learner that learned it +(it will not be modified if the initial metric learner is modified), +and it can be directly plugged into the metric argument of +scikit-learn’s estimators.

+
+
Returns:
+
+
metric_funfunction

The function described above.

+
+
+
+
+
+

See also

+
+
pair_distance

a method that returns the distance between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
pair_score

a method that returns the similarity score between several pairs of points. Unlike get_metric, this is a method of the metric learner and therefore can change if the metric learner changes. Besides, it can use the metric learner’s preprocessor, and works on concatenated arrays.

+
+
+
+

Examples

+
>>> from metric_learn import NCA
+>>> from sklearn.datasets import make_classification
+>>> from sklearn.neighbors import KNeighborsClassifier
+>>> nca = NCA()
+>>> X, y = make_classification()
+>>> nca.fit(X, y)
+>>> knn = KNeighborsClassifier(metric=nca.get_metric())
+>>> knn.fit(X, y) 
+KNeighborsClassifier(algorithm='auto', leaf_size=30,
+  metric=<function MahalanobisMixin.get_metric.<locals>.metric_fun
+          at 0x...>,
+  metric_params=None, n_jobs=None, n_neighbors=5, p=2,
+  weights='uniform')
+
+
+
+ +
+
+get_params(deep=True)
+

Get parameters for this estimator.

+
+
Parameters:
+
+
deepbool, default=True

If True, will return the parameters for this estimator and +contained subobjects that are estimators.

+
+
+
+
Returns:
+
+
paramsdict

Parameter names mapped to their values.

+
+
+
+
+
+ +
+
+abstract pair_distance(pairs)
+
+

New in version 0.7.0: Compute the distance between pairs

+
+

Returns the (pseudo) distance between pairs, when available. For metric +learners that do not learn a (pseudo) distance, an error is thrown +instead.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs for which to compute the distance, with each +row corresponding to two points, for 2D array of indices of pairs +if the metric learner uses a preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The distance between every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_distance is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
+
+
+ +
+
+abstract pair_score(pairs)
+
+

New in version 0.7.0: Compute the similarity score between pairs

+
+

Returns the similarity score between pairs of points (the larger the score, +the more similar the pair). For metric learners that learn a distance, +the score is simply the opposite of the distance between pairs. All +learners have access to this method.

+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The score of every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference with pair_score is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
+
+
+ +
+
+predict(triplets)[source]
+

Predicts the ordering between sample distances in input triplets.

+

For each triplets, returns 1 if the first element is closer to the second +than to the last and -1 if not.

+
+
Parameters:
+
+
tripletsarray-like, shape=(n_triplets, 3, n_features) or (n_triplets, 3)

3D array of triplets to predict, with each row corresponding to three +points, or 2D array of indices of triplets if the metric learner +uses a preprocessor.

+
+
+
+
Returns:
+
+
predictionnumpy.ndarray of floats, shape=(n_constraints,)

Predictions of the ordering of pairs, for each triplet.

+
+
+
+
+
+ +
+
+score(triplets)[source]
+

Computes score on input triplets.

+

Returns the accuracy score of the following classification task: a triplet +(X_a, X_b, X_c) is correctly classified if the predicted similarity between +the first pair (X_a, X_b) is higher than that of the second pair (X_a, X_c)

+
+
Parameters:
+
+
tripletsarray-like, shape=(n_triplets, 3, n_features) or (n_triplets, 3)

3D array of triplets to score, with each row corresponding to three +points, or 2D array of indices of triplets if the metric learner +uses a preprocessor.

+
+
+
+
Returns:
+
+
scorefloat

The triplets score.

+
+
+
+
+
+ +
+
+abstract score_pairs(pairs)
+

Returns the score between pairs +(can be a similarity, or a distance/metric depending on the algorithm)

+
+

Deprecated since version 0.7.0: Refer to pair_distance and pair_score.

+
+
+

Warning

+

This method will be removed in 0.8.0. Please refer to pair_distance +or pair_score. This change will occur in order to add learners +that don’t necessarily learn a Mahalanobis distance.

+
+
+
Parameters:
+
+
pairsarray-like, shape=(n_pairs, 2, n_features) or (n_pairs, 2)

3D Array of pairs to score, with each row corresponding to two points, +for 2D array of indices of pairs if the metric learner uses a +preprocessor.

+
+
+
+
Returns:
+
+
scoresnumpy.ndarray of shape=(n_pairs,)

The score of every pair.

+
+
+
+
+
+

See also

+
+
get_metric

a method that returns a function to compute the metric between two points. The difference between score_pairs is that it works on two 1D arrays and cannot use a preprocessor. Besides, the returned function is independent of the metric learner and hence is not modified if the metric learner is.

+
+
+
+
+ +
+
+set_decision_function_request(*, triplets: bool | None | str = '$UNCHANGED$') _TripletsClassifierMixin
+

Request metadata passed to the decision_function method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to decision_function if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to decision_function.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
tripletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for triplets parameter in decision_function.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_params(**params)
+

Set the parameters of this estimator.

+

The method works on simple estimators as well as on nested objects +(such as Pipeline). The latter have +parameters of the form <component>__<parameter> so that it’s +possible to update each component of a nested object.

+
+
Parameters:
+
+
**paramsdict

Estimator parameters.

+
+
+
+
Returns:
+
+
selfestimator instance

Estimator instance.

+
+
+
+
+
+ +
+
+set_predict_request(*, triplets: bool | None | str = '$UNCHANGED$') _TripletsClassifierMixin
+

Request metadata passed to the predict method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to predict if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to predict.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
tripletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for triplets parameter in predict.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+
+set_score_request(*, triplets: bool | None | str = '$UNCHANGED$') _TripletsClassifierMixin
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
+
tripletsstr, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED

Metadata routing for triplets parameter in score.

+
+
+
+
Returns:
+
+
selfobject

The updated object.

+
+
+
+
+
+ +
+ +
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 00000000..a0312ed0 --- /dev/null +++ b/genindex.html @@ -0,0 +1,994 @@ + + + + + + Index — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Index

+ +
+ _ + | B + | C + | D + | F + | G + | I + | L + | M + | N + | P + | R + | S + | T + +
+

_

+ + + +
+ +

B

+ + +
+ +

C

+ + + +
+ +

D

+ + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

I

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + +
+ + + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/getting_started.html b/getting_started.html new file mode 100644 index 00000000..eb4b2823 --- /dev/null +++ b/getting_started.html @@ -0,0 +1,169 @@ + + + + + + + Getting started — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Getting started

+
+

Installation and Setup

+

Installation

+

metric-learn can be installed in either of the following ways:

+
    +
  • If you use Anaconda: conda install -c conda-forge metric-learn. See more options here.

  • +
  • To install from PyPI: pip install metric-learn.

  • +
  • For a manual install of the latest code, download the source repository and run python setup.py install. You may then run pytest test to run all tests (you will need to have the pytest package installed).

  • +
+

Dependencies

+
    +
  • Python 3.6+ (the last version supporting Python 2 and Python 3.5 was +v0.5.0)

  • +
  • numpy>= 1.11.0, scipy>= 0.17.0, scikit-learn>=0.21.3

  • +
+

Optional dependencies

+
    +
  • For SDML, using skggm will allow the algorithm to solve problematic cases +(install from commit a0ed406). +pip install 'git+https://github.com/skggm/skggm.git@a0ed406586c4364ea3297a658f415e13b5cbdaf8' to install the required version of skggm from GitHub.

  • +
  • For running the examples only: matplotlib

  • +
+
+
+

Quick start

+

This example loads the iris dataset, and evaluates a k-nearest neighbors +algorithm on an embedding space learned with NCA.

+
from metric_learn import NCA
+from sklearn.datasets import load_iris
+from sklearn.model_selection import cross_val_score
+from sklearn.pipeline import make_pipeline
+from sklearn.neighbors import KNeighborsClassifier
+
+X, y = load_iris(return_X_y=True)
+clf = make_pipeline(NCA(), KNeighborsClassifier())
+cross_val_score(clf, X, y)
+
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..d98e5966 --- /dev/null +++ b/index.html @@ -0,0 +1,190 @@ + + + + + + + metric-learn: Metric Learning in Python — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric-learn: Metric Learning in Python

+

GitHub Actions Build Status License PyPI version Code coverage

+

metric-learn +contains efficient Python implementations of several popular supervised and +weakly-supervised metric learning algorithms. As part of scikit-learn-contrib, the API of metric-learn is compatible with scikit-learn, the leading library for machine learning in +Python. This allows to use all the scikit-learn routines (for pipelining, +model selection, etc) with metric learning algorithms through a unified +interface.

+

If you use metric-learn in a scientific publication, we would appreciate +citations to the following paper:

+

metric-learn: Metric Learning Algorithms in Python, de Vazelhes +et al., Journal of Machine Learning Research, 21(138):1-6, 2020.

+

Bibtex entry:

+
@article{metric-learn,
+  title = {metric-learn: {M}etric {L}earning {A}lgorithms in {P}ython},
+  author = {{de Vazelhes}, William and {Carey}, CJ and {Tang}, Yuan and
+            {Vauquier}, Nathalie and {Bellet}, Aur{\'e}lien},
+  journal = {Journal of Machine Learning Research},
+  year = {2020},
+  volume = {21},
+  number = {138},
+  pages = {1--6}
+}
+
+
+
+

Documentation outline

+ + + +
+ +
+

Index | Search Page

+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/introduction.html b/introduction.html new file mode 100644 index 00000000..8191f897 --- /dev/null +++ b/introduction.html @@ -0,0 +1,243 @@ + + + + + + + 1. What is Metric Learning? — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

1. What is Metric Learning?

+

Many approaches in machine learning require a measure of distance between data +points. Traditionally, practitioners would choose a standard distance metric +(Euclidean, City-Block, Cosine, etc.) using a priori knowledge of the +domain. However, it is often difficult to design metrics that are well-suited +to the particular data and task of interest.

+

Distance metric learning (or simply, metric learning) aims at +automatically constructing task-specific distance metrics from (weakly) +supervised data, in a machine learning manner. The learned distance metric can +then be used to perform various tasks (e.g., k-NN classification, clustering, +information retrieval).

+
+

1.1. Problem Setting

+

Metric learning problems fall into two main categories depending on the type +of supervision available about the training data:

+
    +
  • Supervised learning: the algorithm has access to +a set of data points, each of them belonging to a class (label) as in a +standard classification problem. +Broadly speaking, the goal in this setting is to learn a distance metric +that puts points with the same label close together while pushing away +points with different labels.

  • +
  • Weakly supervised learning: the +algorithm has access to a set of data points with supervision only +at the tuple level (typically pairs, triplets, or quadruplets of +data points). A classic example of such weaker supervision is a set of +positive and negative pairs: in this case, the goal is to learn a distance +metric that puts positive pairs close together and negative pairs far away.

  • +
+

Based on the above (weakly) supervised data, the metric learning problem is +generally formulated as an optimization problem where one seeks to find the +parameters of a distance function that optimize some objective function +measuring the agreement with the training data.

+
+
+

1.2. Mahalanobis Distances

+

In the metric-learn package, all algorithms currently implemented learn +so-called Mahalanobis distances. Given a real-valued parameter matrix +\(L\) of shape (num_dims, n_features) where n_features is the +number features describing the data, the Mahalanobis distance associated with +\(L\) is defined as follows:

+
+\[D(x, x') = \sqrt{(Lx-Lx')^\top(Lx-Lx')}\]
+

In other words, a Mahalanobis distance is a Euclidean distance after a +linear transformation of the feature space defined by \(L\) (taking +\(L\) to be the identity matrix recovers the standard Euclidean distance). +Mahalanobis distance metric learning can thus be seen as learning a new +embedding space of dimension num_dims. Note that when num_dims is +smaller than n_features, this achieves dimensionality reduction.

+

Strictly speaking, Mahalanobis distances are “pseudo-metrics”: they satisfy +three of the properties of a metric (non-negativity, symmetry, triangle inequality) but not +necessarily the identity of indiscernibles.

+
+

Note

+

Mahalanobis distances can also be parameterized by a positive semi-definite +(PSD) matrix +\(M\):

+
+\[D(x, x') = \sqrt{(x-x')^\top M(x-x')}\]
+

Using the fact that a PSD matrix \(M\) can always be decomposed as +\(M=L^\top L\) for some \(L\), one can show that both +parameterizations are equivalent. In practice, an algorithm may thus solve +the metric learning problem with respect to either \(M\) or \(L\).

+
+
+
+

1.3. Use-cases

+

There are many use-cases for metric learning. We list here a few popular +examples (for code illustrating some of these use-cases, see the +examples section of the documentation):

+
    +
  • Nearest neighbors models: the learned +metric can be used to improve nearest neighbors learning models for +classification, regression, anomaly detection…

  • +
  • Clustering: +metric learning provides a way to bias the clusters found by algorithms like +K-Means towards the intended semantics.

  • +
  • Information retrieval: the learned metric can be used to retrieve the +elements of a database that are semantically closest to a query element.

  • +
  • Dimensionality reduction: metric learning may be seen as a way to reduce the +data dimension in a (weakly) supervised setting.

  • +
  • More generally, the learned transformation \(L\) can be used to project +the data into a new embedding space before feeding it into another machine +learning algorithm.

  • +
+

The API of metric-learn is compatible with scikit-learn, the leading library for machine +learning in Python. This allows to easily pipeline metric learners with other +scikit-learn estimators to realize the above use-cases, to perform joint +hyperparameter tuning, etc.

+
+
+

1.4. Further reading

+

For more information about metric learning and its applications, one can refer +to the following resources:

+ +
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/metric_learn.html b/metric_learn.html new file mode 100644 index 00000000..4c5f9d66 --- /dev/null +++ b/metric_learn.html @@ -0,0 +1,268 @@ + + + + + + + metric_learn package — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

metric_learn package

+
+

Module Contents

+
+
+

Base Classes

+ + + + + + + + + + + + + + + + + + + + + + + + +

metric_learn.Constraints(partial_labels)

Class to build constraints from labeled data.

metric_learn.base_metric.BaseMetricLearner([...])

Base class for all metric-learners.

metric_learn.base_metric.MetricTransformer()

Base class for all learners that can transform data into a new space with the metric learned.

metric_learn.base_metric.MahalanobisMixin([...])

Mahalanobis metric learning algorithms.

metric_learn.base_metric._PairsClassifierMixin([...])

Base class for pairs learners.

metric_learn.base_metric._TripletsClassifierMixin([...])

Base class for triplets learners.

metric_learn.base_metric._QuadrupletsClassifierMixin([...])

Base class for quadruplets learners.

+
+
+

Supervised Learning Algorithms

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

metric_learn.LFDA([n_components, k, ...])

Local Fisher Discriminant Analysis for Supervised Dimensionality Reduction

metric_learn.LMNN([init, n_neighbors, ...])

Large Margin Nearest Neighbor (LMNN)

metric_learn.MLKR([n_components, init, tol, ...])

Metric Learning for Kernel Regression (MLKR)

metric_learn.NCA([init, n_components, ...])

Neighborhood Components Analysis (NCA)

metric_learn.RCA([n_components, preprocessor])

Relevant Components Analysis (RCA)

metric_learn.ITML_Supervised([gamma, ...])

Supervised version of Information Theoretic Metric Learning (ITML)

metric_learn.LSML_Supervised([tol, ...])

Supervised version of Least Squared-residual Metric Learning (LSML)

metric_learn.MMC_Supervised([max_iter, ...])

Supervised version of Mahalanobis Metric for Clustering (MMC)

metric_learn.SDML_Supervised([...])

Supervised version of Sparse Distance Metric Learning (SDML)

metric_learn.RCA_Supervised([n_components, ...])

Supervised version of Relevant Components Analysis (RCA)

metric_learn.SCML_Supervised([k_genuine, ...])

Supervised version of Sparse Compositional Metric Learning (SCML)

+
+
+

Weakly Supervised Learning Algorithms

+ + + + + + + + + + + + + + + + + + +

metric_learn.ITML([gamma, max_iter, tol, ...])

Information Theoretic Metric Learning (ITML)

metric_learn.LSML([tol, max_iter, prior, ...])

Least Squared-residual Metric Learning (LSML)

metric_learn.MMC([max_iter, max_proj, tol, ...])

Mahalanobis Metric for Clustering (MMC)

metric_learn.SDML([balance_param, ...])

Sparse Distance Metric Learning (SDML)

metric_learn.SCML([beta, basis, n_basis, ...])

Sparse Compositional Metric Learning (SCML)

+
+
+

Unsupervised Learning Algorithms

+ + + + + + +

metric_learn.Covariance([preprocessor])

Covariance metric (baseline method)

+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/metric_learn/__init__.py b/metric_learn/__init__.py deleted file mode 100644 index 0326b878..00000000 --- a/metric_learn/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from itml import ITML -from lmnn import LMNN -from lsml import LSML -from sdml import SDML -from nca import NCA -from lfda import LFDA -from rca import RCA diff --git a/metric_learn/base_metric.py b/metric_learn/base_metric.py deleted file mode 100644 index 96d87077..00000000 --- a/metric_learn/base_metric.py +++ /dev/null @@ -1,47 +0,0 @@ -from numpy.linalg import inv,cholesky - - -class BaseMetricLearner(object): - def __init__(self): - raise NotImplementedError('BaseMetricLearner should not be instantiated') - - def metric(self): - """Computes the Mahalanobis matrix from the transformation matrix. - - .. math:: M = L^{\\top} L - - Returns - ------- - M : (d x d) matrix - """ - L = self.transformer() - return L.T.dot(L) - - def transformer(self): - """Computes the transformation matrix from the Mahalanobis matrix. - - L = inv(cholesky(M)) - - Returns - ------- - L : (d x d) matrix - """ - return inv(cholesky(self.metric())) - - def transform(self, X=None): - """Applies the metric transformation. - - Parameters - ---------- - X : (n x d) matrix, optional - Data to transform. If not supplied, the training data will be used. - - Returns - ------- - transformed : (n x d) matrix - Input data transformed to the metric space by :math:`XL^{\\top}` - """ - if X is None: - X = self.X - L = self.transformer() - return X.dot(L.T) diff --git a/metric_learn/itml.py b/metric_learn/itml.py deleted file mode 100644 index 874435eb..00000000 --- a/metric_learn/itml.py +++ /dev/null @@ -1,135 +0,0 @@ -""" -Information Theoretic Metric Learning, Kulis et al., ICML 2007 - -ITML minimizes the differential relative entropy between two multivariate -Gaussians under constraints on the distance function, -which can be formulated into a Bregman optimization problem by minimizing the -LogDet divergence subject to linear constraints. -This algorithm can handle a wide variety of constraints and can optionally -incorporate a prior on the distance function. -Unlike some other methods, ITML does not rely on an eigenvalue computation -or semi-definite programming. -""" - -import numpy as np -from sklearn.metrics import pairwise_distances -from base_metric import BaseMetricLearner - - -class ITML(BaseMetricLearner): - """Information Theoretic Metric Learning (ITML)""" - def __init__(self, gamma=1., max_iters=1000, convergence_threshold=1e-3): - """Initialize the learner. - - Parameters - ---------- - gamma : float, optional - value for slack variables - max_iters : int, optional - convergence_threshold : float, optional - """ - self.gamma = gamma - self.max_iters = max_iters - self.convergence_threshold = convergence_threshold - - def _process_inputs(self, X, constraints, bounds, A0): - self.X = X - # check to make sure that no two constrained vectors are identical - a,b,c,d = constraints - ident = _vector_norm(self.X[a] - self.X[b]) > 1e-9 - a, b = a[ident], b[ident] - ident = _vector_norm(self.X[c] - self.X[d]) > 1e-9 - c, d = c[ident], d[ident] - # init bounds - if bounds is None: - self.bounds = np.percentile(pairwise_distances(X), (5, 95)) - else: - assert len(bounds) == 2 - self.bounds = bounds - # init metric - if A0 is None: - self.A = np.identity(X.shape[1]) - else: - self.A = A0 - return a,b,c,d - - def fit(self, X, constraints, bounds=None, A0=None, verbose=False): - """Learn the ITML model. - - Parameters - ---------- - X : (n x d) data matrix - each row corresponds to a single instance - constraints : tuple of arrays - (a,b,c,d) indices into X, such that d(X[a],X[b]) < d(X[c],X[d]) - bounds : list (pos,neg) pairs, optional - bounds on similarity, s.t. d(X[a],X[b]) < pos and d(X[c],X[d]) > neg - A0 : (d x d) matrix, optional - initial regularization matrix, defaults to identity - """ - a,b,c,d = self._process_inputs(X, constraints, bounds, A0) - gamma = self.gamma - num_pos = len(a) - num_neg = len(c) - _lambda = np.zeros(num_pos + num_neg) - lambdaold = np.zeros_like(_lambda) - gamma_proj = 1. if gamma is np.inf else gamma/(gamma+1.) - pos_bhat = np.zeros(num_pos) + self.bounds[0] - neg_bhat = np.zeros(num_neg) + self.bounds[1] - A = self.A - - for it in xrange(self.max_iters): - # update positives - vv = self.X[a] - self.X[b] - for i,v in enumerate(vv): - wtw = v.dot(A).dot(v) # scalar - alpha = min(_lambda[i], gamma_proj*(1./wtw - 1./pos_bhat[i])) - _lambda[i] -= alpha - beta = alpha/(1 - alpha*wtw) - pos_bhat[i] = 1./((1 / pos_bhat[i]) + (alpha / gamma)) - A += beta * A.dot(np.outer(v,v)).dot(A) - - # update negatives - vv = self.X[c] - self.X[d] - for i,v in enumerate(vv): - wtw = v.dot(A).dot(v) # scalar - alpha = min(_lambda[i+num_pos],gamma_proj*(1./neg_bhat[i] - 1./wtw)) - _lambda[i+num_pos] -= alpha - beta = -alpha/(1 + alpha*wtw) - neg_bhat[i] = 1./((1 / neg_bhat[i]) - (alpha / gamma)) - A += beta * A.dot(np.outer(v,v)).dot(A) - - normsum = np.linalg.norm(_lambda) + np.linalg.norm(lambdaold) - if normsum == 0: - conv = np.inf - break - conv = np.abs(lambdaold - _lambda).sum() / normsum - if conv < self.convergence_threshold: - break - lambdaold = _lambda.copy() - if verbose: - print 'itml iter: %d, conv = %f' % (it, conv) - if verbose: - print 'itml converged at iter: %d, conv = %f' % (it, conv) - return self - - def metric(self): - return self.A - - @classmethod - def prepare_constraints(self, labels, num_points, num_constraints): - ac,bd = np.random.randint(num_points, size=(2,num_constraints)) - pos = labels[ac] == labels[bd] - a,c = ac[pos], ac[~pos] - b,d = bd[pos], bd[~pos] - return a,b,c,d - -# hack around lack of axis kwarg in older numpy versions -try: - np.linalg.norm([[4]], axis=1) -except TypeError: - def _vector_norm(X): - return np.apply_along_axis(np.linalg.norm, 1, X) -else: - def _vector_norm(X): - return np.linalg.norm(X, axis=1) diff --git a/metric_learn/lfda.py b/metric_learn/lfda.py deleted file mode 100644 index d900acce..00000000 --- a/metric_learn/lfda.py +++ /dev/null @@ -1,115 +0,0 @@ -""" -Local Fisher Discriminant Analysis (LFDA) - -Local Fisher Discriminant Analysis for Supervised Dimensionality Reduction -Sugiyama, ICML 2006 - -LFDA is a linear supervised dimensionality reduction method. -It is particularly useful when dealing with multimodality, -where one ore more classes consist of separate clusters in input space. -The core optimization problem of LFDA is solved as a generalized -eigenvalue problem. -""" -from __future__ import division -import numpy as np -import scipy -from sklearn.metrics import pairwise_distances -from base_metric import BaseMetricLearner - - -class LFDA(BaseMetricLearner): - ''' - Local Fisher Discriminant Analysis for Supervised Dimensionality Reduction - Sugiyama, ICML 2006 - ''' - def __init__(self, dim=None, k=7, metric='weighted'): - ''' - dim : dimensionality of reduced space (defaults to dimension of X) - k : nearest neighbor used in local scaling method (default: 7) - metric : type of metric in the embedding space (default: 'weighted') - 'weighted' - weighted eigenvectors - 'orthonormalized' - orthonormalized - 'plain' - raw eigenvectors - ''' - if metric not in ('weighted', 'orthonormalized', 'plain'): - raise ValueError('Invalid metric: %r' % metric) - self.dim = dim - self.metric = metric - self.k = k - - def transformer(self): - return self._transformer - - def _process_inputs(self, X, Y): - X = np.asanyarray(X) - self.X = X - n, d = X.shape - unique_classes, Y = np.unique(Y, return_inverse=True) - num_classes = len(unique_classes) - - if self.dim is None: - self.dim = d - elif not 0 < self.dim <= d: - raise ValueError('Invalid embedding dimension, must be in [1,%d]' % d) - - if not 0 < self.k < d: - raise ValueError('Invalid k, must be in [0,%d]' % (d-1)) - - return X, Y, num_classes, n, d - - def fit(self, X, Y): - ''' - X: (n, d) array-like of samples - Y: (n,) array-like of class labels - ''' - X, Y, num_classes, n, d = self._process_inputs(X, Y) - tSb = np.zeros((d,d)) - tSw = np.zeros((d,d)) - - for c in xrange(num_classes): - Xc = X[Y==c] - nc = Xc.shape[0] - - # classwise affinity matrix - dist = pairwise_distances(Xc, metric='l2', squared=True) - # distances to k-th nearest neighbor - k = min(self.k, nc-1) - sigma = np.sqrt(np.partition(dist, k, axis=0)[:,k]) - - local_scale = np.outer(sigma, sigma) - with np.errstate(divide='ignore', invalid='ignore'): - A = np.exp(-dist/local_scale) - A[local_scale==0] = 0 - - G = Xc.T.dot(A.sum(axis=0)[:,None] * Xc) - Xc.T.dot(A).dot(Xc) - tSb += G/n + (1-nc/n)*Xc.T.dot(Xc) + _sum_outer(Xc)/n - tSw += G/nc - - tSb -= _sum_outer(X)/n - tSw - - # symmetrize - tSb += tSb.T - tSb /= 2 - tSw += tSw.T - tSw /= 2 - - if self.dim == d: - vals, vecs = scipy.linalg.eigh(tSb, tSw) - else: - vals, vecs = scipy.sparse.linalg.eigsh(tSb, k=self.dim, M=tSw, which='LA') - - order = np.argsort(-vals)[:self.dim] - vals = vals[order] - vecs = vecs[:,order] - - if self.metric == 'weighted': - vecs *= np.sqrt(vals) - elif self.metric == 'orthonormalized': - vecs, _ = np.linalg.qr(vecs) - - self._transformer = vecs.T - - -def _sum_outer(x): - s = x.sum(axis=0) - return np.outer(s, s) diff --git a/metric_learn/lmnn.py b/metric_learn/lmnn.py deleted file mode 100644 index 04d87a40..00000000 --- a/metric_learn/lmnn.py +++ /dev/null @@ -1,259 +0,0 @@ -""" -Large-margin nearest neighbor metric learning. (Weinberger 2005) - -LMNN learns a Mahanalobis distance metric in the kNN classification setting -using semidefinite programming. -The learned metric attempts to keep k-nearest neighbors in the same class, -while keeping examples from different classes separated by a large margin. -This algorithm makes no assumptions about the distribution of the data. -""" -#TODO: periodic recalculation of impostors, PCA initialization - -import numpy as np -from collections import Counter -from sklearn.metrics import pairwise_distances -from base_metric import BaseMetricLearner - - -# commonality between LMNN implementations -class _base_LMNN(BaseMetricLearner): - def __init__(self, **kwargs): - self.params = kwargs - - def transformer(self): - return self.L - - -# slower Python version -class python_LMNN(_base_LMNN): - def __init__(self, k=3, min_iter=50, max_iter=1000, learn_rate=1e-7, - regularization=0.5, convergence_tol=0.001): - """Initialize the LMNN object - - k: number of neighbors to consider. (does not include self-edges) - regularization: weighting of pull and push terms - """ - _base_LMNN.__init__(self, k=k, min_iter=min_iter, max_iter=max_iter, - learn_rate=learn_rate, regularization=regularization, - convergence_tol=convergence_tol) - - def _process_inputs(self, X, labels): - num_pts = X.shape[0] - assert len(labels) == num_pts - unique_labels, self.label_inds = np.unique(labels, return_inverse=True) - self.labels = np.arange(len(unique_labels)) - self.X = X - self.L = np.eye(X.shape[1]) - required_k = np.bincount(self.label_inds).min() - k = self.params['k'] - assert k <= required_k, ('not enough class labels for specified k' + - ' (smallest class has %d)' % required_k) - - def fit(self, X, labels, verbose=False): - k = self.params['k'] - reg = self.params['regularization'] - learn_rate = self.params['learn_rate'] - convergence_tol = self.params['convergence_tol'] - min_iter = self.params['min_iter'] - self._process_inputs(X, labels) - - target_neighbors = self._select_targets() - impostors = self._find_impostors(target_neighbors[:,-1]) - - # sum outer products - dfG = _sum_outer_products(self.X, target_neighbors.flatten(), - np.repeat(np.arange(self.X.shape[0]), k)) - df = np.zeros_like(dfG) - - # storage - a1 = [None]*k - a2 = [None]*k - for nn_idx in xrange(k): - a1[nn_idx] = np.array([]) - a2[nn_idx] = np.array([]) - - # initialize gradient and L - G = dfG * reg + df * (1-reg) - L = self.L - objective = np.inf - - # main loop - for it in xrange(1, self.params['max_iter']): - df_old = df.copy() - a1_old = [a.copy() for a in a1] - a2_old = [a.copy() for a in a2] - objective_old = objective - # Compute pairwise distances under current metric - Lx = L.dot(self.X.T).T - g0 = _inplace_paired_L2(*Lx[impostors]) - Ni = 1 + _inplace_paired_L2(Lx[target_neighbors], Lx[:,None,:]) - g1,g2 = Ni[impostors] - - # compute the gradient - total_active = 0 - for nn_idx in reversed(xrange(k)): - act1 = g0 < g1[:,nn_idx] - act2 = g0 < g2[:,nn_idx] - total_active += act1.sum() + act2.sum() - - if it > 1: - plus1 = act1 & ~a1[nn_idx] - minus1 = a1[nn_idx] & ~act1 - plus2 = act2 & ~a2[nn_idx] - minus2 = a2[nn_idx] & ~act2 - else: - plus1 = act1 - plus2 = act2 - minus1 = np.zeros(0, dtype=int) - minus2 = np.zeros(0, dtype=int) - - targets = target_neighbors[:,nn_idx] - PLUS, pweight = _count_edges(plus1, plus2, impostors, targets) - df += _sum_outer_products(self.X, PLUS[:,0], PLUS[:,1], pweight) - MINUS, mweight = _count_edges(minus1, minus2, impostors, targets) - df -= _sum_outer_products(self.X, MINUS[:,0], MINUS[:,1], mweight) - - in_imp, out_imp = impostors - df += _sum_outer_products(self.X, in_imp[minus1], out_imp[minus1]) - df += _sum_outer_products(self.X, in_imp[minus2], out_imp[minus2]) - - df -= _sum_outer_products(self.X, in_imp[plus1], out_imp[plus1]) - df -= _sum_outer_products(self.X, in_imp[plus2], out_imp[plus2]) - - a1[nn_idx] = act1 - a2[nn_idx] = act2 - - # do the gradient update - assert not np.isnan(df).any() - G = dfG * reg + df * (1-reg) - - # compute the objective function - objective = total_active * (1-reg) - objective += G.flatten().dot(L.T.dot(L).flatten()) - assert not np.isnan(objective) - delta_obj = objective - objective_old - - if verbose: - print it, objective, delta_obj, total_active, learn_rate - - # update step size - if delta_obj > 0: - # we're getting worse... roll back! - learn_rate /= 2.0 - df = df_old - a1 = a1_old - a2 = a2_old - objective = objective_old - else: - # update L - L -= learn_rate * 2 * L.dot(G) - learn_rate *= 1.01 - - # check for convergence - if it > min_iter and abs(delta_obj) < convergence_tol: - if verbose: - print "LMNN converged with objective", objective - break - else: - if verbose: - print "LMNN didn't converge in %(max_iter)d steps." % self.params - - # store the last L - self.L = L - return self - - def metric(self): - return self.L.T.dot(self.L) - - def transform(self, X=None): - if X is None: - X = self.X - return self.L.dot(X.T).T - - def _select_targets(self): - k = self.params['k'] - target_neighbors = np.empty((self.X.shape[0], k), dtype=int) - for label in self.labels: - inds, = np.nonzero(self.label_inds == label) - dd = pairwise_distances(self.X[inds]) - np.fill_diagonal(dd, np.inf) - nn = np.argsort(dd)[...,:k] - target_neighbors[inds] = inds[nn] - return target_neighbors - - def _find_impostors(self, furthest_neighbors): - Lx = self.transform() - margin_radii = 1 + _inplace_paired_L2(Lx[furthest_neighbors], Lx) - impostors = [] - for label in self.labels[:-1]: - in_inds, = np.nonzero(self.label_inds == label) - out_inds, = np.nonzero(self.label_inds > label) - dist = pairwise_distances(Lx[out_inds], Lx[in_inds]) - i1,j1 = np.nonzero(dist < margin_radii[out_inds][:,None]) - i2,j2 = np.nonzero(dist < margin_radii[in_inds]) - i = np.hstack((i1,i2)) - j = np.hstack((j1,j2)) - if i.size > 0: - # get unique (i,j) pairs using index trickery - shape = (i.max()+1, j.max()+1) - tmp = np.ravel_multi_index((i,j), shape) - i,j = np.unravel_index(np.unique(tmp), shape) - impostors.append(np.vstack((in_inds[j], out_inds[i]))) - return np.hstack(impostors) - - -def _inplace_paired_L2(A, B): - '''Equivalent to ((A-B)**2).sum(axis=-1), but modifies A in place.''' - A -= B - return np.einsum('...ij,...ij->...i', A, A) - - -def _count_edges(act1, act2, impostors, targets): - imp = impostors[0,act1] - c = Counter(zip(imp, targets[imp])) - imp = impostors[1,act2] - c.update(zip(imp, targets[imp])) - if c: - active_pairs = np.array(c.keys()) - else: - active_pairs = np.empty((0,2), dtype=int) - return active_pairs, np.array(c.values()) - - -def _sum_outer_products(data, a_inds, b_inds, weights=None): - Xab = data[a_inds] - data[b_inds] - if weights is not None: - return np.dot(Xab.T, Xab * weights[:,None]) - return np.dot(Xab.T, Xab) - - -try: - # use the fast C++ version, if available - from modshogun import LMNN as shogun_LMNN - from modshogun import RealFeatures, MulticlassLabels - - class LMNN(_base_LMNN): - def __init__(self, k=3, min_iter=50, max_iter=1000, learn_rate=1e-7, - regularization=0.5, convergence_tol=0.001, use_pca=True): - _base_LMNN.__init__(self, k=k, min_iter=min_iter, max_iter=max_iter, - learn_rate=learn_rate, regularization=regularization, - convergence_tol=convergence_tol, use_pca=use_pca) - - def fit(self, X, labels, verbose=False): - self.X = X - self.L = np.eye(X.shape[1]) - labels = MulticlassLabels(labels.astype(np.float64)) - self._lmnn = shogun_LMNN(RealFeatures(X.T), labels, self.params['k']) - self._lmnn.set_maxiter(self.params['max_iter']) - self._lmnn.set_obj_threshold(self.params['convergence_tol']) - self._lmnn.set_regularization(self.params['regularization']) - self._lmnn.set_stepsize(self.params['learn_rate']) - if self.params['use_pca']: - self._lmnn.train() - else: - self._lmnn.train(self.L) - self.L = self._lmnn.get_linear_transform() - return self - -except ImportError: - LMNN = python_LMNN diff --git a/metric_learn/lsml.py b/metric_learn/lsml.py deleted file mode 100644 index 02064045..00000000 --- a/metric_learn/lsml.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -Liu et al. -"Metric Learning from Relative Comparisons by Minimizing Squared Residual". -ICDM 2012. - -Adapted from https://gist.github.com/kcarnold/5439917 -Paper: http://www.cs.ucla.edu/~weiwang/paper/ICDM12.pdf -""" - -from random import choice -import numpy as np -import scipy.linalg -from base_metric import BaseMetricLearner - - -class LSML(BaseMetricLearner): - def __init__(self, tol=1e-3, max_iter=1000): - """Initialize the learner. - - Parameters - ---------- - tol : float, optional - max_iter : int, optional - """ - self.tol = tol - self.max_iter = max_iter - - def _prepare_inputs(self, X, constraints, weights, prior): - self.X = X - self.vab = np.diff(X[constraints[:,:2]], axis=1)[:,0] - self.vcd = np.diff(X[constraints[:,2:]], axis=1)[:,0] - if weights is None: - self.w = np.ones(constraints.shape[0]) - else: - self.w = weights - self.w /= self.w.sum() # weights must sum to 1 - if prior is None: - self.M = np.cov(X.T) - else: - self.M = prior - - def metric(self): - return self.M - - def fit(self, X, constraints, weights=None, prior=None, verbose=False): - """Learn the LSML model. - - Parameters - ---------- - X : (n x d) data matrix - each row corresponds to a single instance - constraints : (m x 4) matrix of ints - (a,b,c,d) indices into X, such that d(X[a],X[b]) < d(X[c],X[d]) - weights : (m,) array of floats, optional - scale factor for each constraint - prior : (d x d) matrix, optional - guess at a metric [default: covariance(X)] - verbose : bool, optional - if True, prints information while learning - """ - self._prepare_inputs(X, constraints, weights, prior) - prior_inv = scipy.linalg.inv(self.M) - s_best = self._total_loss(self.M, prior_inv) - step_sizes = np.logspace(-10, 0, 10) - if verbose: - print 'initial loss', s_best - for it in xrange(1, self.max_iter+1): - grad = self._gradient(self.M, prior_inv) - grad_norm = scipy.linalg.norm(grad) - if grad_norm < self.tol: - break - if verbose: - print 'gradient norm', grad_norm - M_best = None - for step_size in step_sizes: - step_size /= grad_norm - new_metric = self.M - step_size * grad - w, v = scipy.linalg.eigh(new_metric) - new_metric = v.dot((np.maximum(w, 1e-8) * v).T) - cur_s = self._total_loss(new_metric, prior_inv) - if cur_s < s_best: - l_best = step_size - s_best = cur_s - M_best = new_metric - if verbose: - print 'iter', it, 'cost', s_best, 'best step', l_best * grad_norm - if M_best is None: - break - self.M = M_best - else: - print "Didn't converge after %d iterations. Final loss: %f" % (it, s_best) - return self - - def _comparison_loss(self, metric): - dab = np.sum(self.vab.dot(metric) * self.vab, axis=1) - dcd = np.sum(self.vcd.dot(metric) * self.vcd, axis=1) - violations = dab > dcd - return self.w[violations].dot((np.sqrt(dab[violations]) - - np.sqrt(dcd[violations]))**2) - - def _total_loss(self, metric, prior_inv): - return (self._comparison_loss(metric) + - _regularization_loss(metric, prior_inv)) - - def _gradient(self, metric, prior_inv): - dMetric = prior_inv - scipy.linalg.inv(metric) - dabs = np.sum(self.vab.dot(metric) * self.vab, axis=1) - dcds = np.sum(self.vcd.dot(metric) * self.vcd, axis=1) - violations = dabs > dcds - # TODO: vectorize - for vab, dab, vcd, dcd in zip(self.vab[violations], dabs[violations], - self.vcd[violations], dcds[violations]): - dMetric += ((1-np.sqrt(dcd/dab))*np.outer(vab, vab) + - (1-np.sqrt(dab/dcd))*np.outer(vcd, vcd)) - return dMetric - - @classmethod - def prepare_constraints(cls, labels, num_constraints): - C = np.empty((num_constraints,4), dtype=int) - a, c = np.random.randint(len(labels), size=(2,num_constraints)) - for i,(al,cl) in enumerate(zip(labels[a],labels[c])): - C[i,1] = choice(np.nonzero(labels == al)[0]) - C[i,3] = choice(np.nonzero(labels != cl)[0]) - C[:,0] = a - C[:,2] = c - return C - - -def _regularization_loss(metric, prior_inv): - sign, logdet = np.linalg.slogdet(metric) - return np.sum(metric * prior_inv) - sign * logdet diff --git a/metric_learn/nca.py b/metric_learn/nca.py deleted file mode 100644 index 79a3f7a8..00000000 --- a/metric_learn/nca.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Neighborhood Components Analysis (NCA) -Ported to Python from https://github.com/vomjom/nca -""" - -import numpy as np -from base_metric import BaseMetricLearner - - -class NCA(BaseMetricLearner): - def __init__(self, max_iter=100, learning_rate=0.01): - self.max_iter = max_iter - self.learning_rate = learning_rate - self.A = None - - def transformer(self): - return self.A - - def fit(self, X, labels): - """ - X: data matrix, (n x d) - labels: scalar labels, (n) - """ - n, d = X.shape - # Initialize A to a scaling matrix - A = np.zeros((d, d)) - np.fill_diagonal(A, 1./(X.max(axis=0)-X.min(axis=0))) - - # Run NCA - dX = X[:,None] - X[None] # shape (n, n, d) - tmp = np.einsum('...i,...j->...ij', dX, dX) # shape (n, n, d, d) - masks = labels[:,None] == labels[None] - for it in xrange(self.max_iter): - for i, label in enumerate(labels): - mask = masks[i] - Ax = A.dot(X.T).T # shape (n, d) - - softmax = np.exp(-((Ax[i] - Ax)**2).sum(axis=1)) # shape (n) - softmax[i] = 0 - softmax /= softmax.sum() - - t = softmax[:, None, None] * tmp[i] # shape (n, d, d) - d = softmax[mask].sum() * t.sum(axis=0) - t[mask].sum(axis=0) - A += self.learning_rate * A.dot(d) - - self.X = X - self.A = A - return self diff --git a/metric_learn/rca.py b/metric_learn/rca.py deleted file mode 100644 index 0478fee5..00000000 --- a/metric_learn/rca.py +++ /dev/null @@ -1,112 +0,0 @@ -"""Relative Components Analysis (RCA) - -RCA learns a full rank Mahalanobis distance metric based on a -weighted sum of in-class covariance matrices. -It applies a global linear transformation to assign large weights to -relevant dimensions and low weights to irrelevant dimensions. -Those relevant dimensions are estimated using "chunklets", -subsets of points that are known to belong to the same class. - -'Learning distance functions using equivalence relations', ICML 2003 -""" -import numpy as np -import random -from base_metric import BaseMetricLearner - - -class RCA(BaseMetricLearner): - """Relevant Components Analysis (RCA)""" - def __init__(self, dim=None): - """Initialize the learner. - - Parameters - ---------- - dim : int, optional - embedding dimension (default: original dimension of data) - """ - self.dim = dim - - def transformer(self): - return self._transformer - - def _process_inputs(self, X, Y): - X = np.asanyarray(X) - self.X = X - n, d = X.shape - - if self.dim is None: - self.dim = d - elif not 0 < self.dim <= d: - raise ValueError('Invalid embedding dimension, must be in [1,%d]' % d) - - Y = np.asanyarray(Y) - num_chunks = Y.max() + 1 - - return X, Y, num_chunks, d - - def fit(self, data, chunks): - """Learn the RCA model. - - Parameters - ---------- - X : (n x d) data matrix - each row corresponds to a single instance - chunks : (n,) array of ints - when ``chunks[i] == -1``, point i doesn't belong to any chunklet, - when ``chunks[i] == j``, point i belongs to chunklet j. - """ - data, chunks, num_chunks, d = self._process_inputs(data, chunks) - - # mean center - data -= data.mean(axis=0) - - # mean center each chunklet separately - chunk_mask = chunks != -1 - chunk_data = data[chunk_mask] - chunk_labels = chunks[chunk_mask] - for c in xrange(num_chunks): - mask = chunk_labels == c - chunk_data[mask] -= chunk_data[mask].mean(axis=0) - - # "inner" covariance of chunk deviations - inner_cov = np.cov(chunk_data, rowvar=0, bias=1) - - # Fisher Linear Discriminant projection - if self.dim < d: - total_cov = np.cov(data[chunk_mask], rowvar=0) - tmp = np.linalg.lstsq(total_cov, inner_cov)[0] - vals, vecs = np.linalg.eig(tmp) - inds = np.argsort(vals)[:self.dim] - A = vecs[:,inds] - inner_cov = A.T.dot(inner_cov).dot(A) - self._transformer = _inv_sqrtm(inner_cov).dot(A.T) - else: - self._transformer = _inv_sqrtm(inner_cov).T - - @classmethod - def prepare_constraints(cls, Y, num_chunks=100, chunk_size=2, seed=None): - random.seed(seed) - chunks = -np.ones_like(Y, dtype=int) - uniq, lookup = np.unique(Y, return_inverse=True) - all_inds = [set(np.where(lookup==c)[0]) for c in xrange(len(uniq))] - idx = 0 - while idx < num_chunks and all_inds: - c = random.randint(0, len(all_inds)-1) - inds = all_inds[c] - if len(inds) < chunk_size: - del all_inds[c] - continue - ii = random.sample(inds, chunk_size) - inds.difference_update(ii) - chunks[ii] = idx - idx += 1 - if idx < num_chunks: - raise ValueError('Unable to make %d chunks of %d examples each' % - (num_chunks, chunk_size)) - return chunks - - -def _inv_sqrtm(x): - '''Computes x^(-1/2)''' - vals, vecs = np.linalg.eigh(x) - return (vecs / np.sqrt(vals)).dot(vecs.T) diff --git a/metric_learn/sdml.py b/metric_learn/sdml.py deleted file mode 100644 index 6b6f218c..00000000 --- a/metric_learn/sdml.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -Qi et al. -An efficient sparse metric learning in high-dimensional space via -L1-penalized log-determinant regularization. -ICML 2009 - -Adapted from https://gist.github.com/kcarnold/5439945 -Paper: http://lms.comp.nus.edu.sg/sites/default/files/publication-attachments/icml09-guojun.pdf -""" - -from random import choice -import numpy as np -from sklearn.covariance import graph_lasso -from sklearn.utils.extmath import pinvh -from scipy.sparse.csgraph import laplacian -from base_metric import BaseMetricLearner - - -class SDML(BaseMetricLearner): - def __init__(self, balance_param=0.5, sparsity_param=0.01, use_cov=True): - ''' - balance_param: trade off between sparsity and M0 prior - sparsity_param: trade off between optimizer and sparseness (see graph_lasso) - ''' - self.balance_param = balance_param - self.sparsity_param = sparsity_param - self.use_cov = use_cov - - def _prepare_inputs(self, X, W): - self.X = X - # set up prior M - if self.use_cov: - self.M = np.cov(X.T) - else: - self.M = np.identity(X.shape[1]) - L = laplacian(W, normed=False) - self.loss_matrix = self.X.T.dot(L.dot(self.X)) - - def metric(self): - return self.M - - def fit(self, X, W, verbose=False): - """ - X: data matrix, (n x d) - W: connectivity graph, (n x n). +1 for positive pairs, -1 for negative. - """ - self._prepare_inputs(X, W) - P = pinvh(self.M) + self.balance_param * self.loss_matrix - emp_cov = pinvh(P) - # hack: ensure positive semidefinite - emp_cov = emp_cov.T.dot(emp_cov) - self.M, _ = graph_lasso(emp_cov, self.sparsity_param, verbose=verbose) - return self - - @classmethod - def prepare_constraints(self, labels, num_points, num_constraints): - a, c = np.random.randint(len(labels), size=(2,num_constraints)) - b, d = np.empty((2, num_constraints), dtype=int) - for i,(al,cl) in enumerate(zip(labels[a],labels[c])): - b[i] = choice(np.nonzero(labels == al)[0]) - d[i] = choice(np.nonzero(labels != cl)[0]) - W = np.zeros((num_points,num_points)) - W[a,b] = 1 - W[c,d] = -1 - # make W symmetric - W[b,a] = 1 - W[d,c] = -1 - return W diff --git a/objects.inv b/objects.inv new file mode 100644 index 00000000..1dcd06d5 Binary files /dev/null and b/objects.inv differ diff --git a/preprocessor.html b/preprocessor.html new file mode 100644 index 00000000..e66d45c4 --- /dev/null +++ b/preprocessor.html @@ -0,0 +1,240 @@ + + + + + + + 5. Preprocessor — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

5. Preprocessor

+

Estimators in metric-learn all have a preprocessor option at instantiation. +Filling this argument allows them to take more compact input representation +when fitting, predicting etc…

+

If preprocessor=None, no preprocessor will be used and the user must +provide the classical representation to the fit/predict/score/etc… methods of +the estimators (see the documentation of the particular estimator to know the +type of input it accepts). Otherwise, two types of objects can be put in this +argument:

+
+

5.1. Array-like

+

You can specify preprocessor=X where X is an array-like containing the +dataset of points. In this case, the fit/predict/score/etc… methods of the +estimator will be able to take as inputs an array-like of indices, replacing +under the hood each index by the corresponding sample.

+

Example with a supervised metric learner:

+
>>> from metric_learn import NCA
+>>>
+>>> X = np.array([[-0.7 , -0.23],
+>>>               [-0.43, -0.49],
+>>>               [ 0.14, -0.37]])  # array of 3 samples of 2 features
+>>> points_indices = np.array([2, 0, 1, 0])
+>>> y = np.array([1, 0, 1, 1])
+>>>
+>>> nca = NCA(preprocessor=X)
+>>> nca.fit(points_indices, y)
+>>> # under the hood the algorithm will create
+>>> # points = np.array([[ 0.14, -0.37],
+>>> #                    [-0.7 , -0.23],
+>>> #                    [-0.43, -0.49],
+>>> #                    [ 0.14, -0.37]]) and fit on it
+
+
+

Example with a weakly supervised metric learner:

+
>>> from metric_learn import MMC
+>>> X = np.array([[-0.7 , -0.23],
+>>>               [-0.43, -0.49],
+>>>               [ 0.14, -0.37]])  # array of 3 samples of 2 features
+>>> pairs_indices = np.array([[2, 0], [1, 0]])
+>>> y_pairs = np.array([1, -1])
+>>>
+>>> mmc = MMC(preprocessor=X)
+>>> mmc.fit(pairs_indices, y_pairs)
+>>> # under the hood the algorithm will create
+>>> # pairs = np.array([[[ 0.14, -0.37], [-0.7 , -0.23]],
+>>> #                    [[-0.43, -0.49], [-0.7 , -0.23]]]) and fit on it
+
+
+
+
+

5.2. Callable

+

Alternatively, you can provide a callable as preprocessor. Then the +estimator will accept indicators of points instead of points. Under the hood, +the estimator will call this callable on the indicators you provide as input +when fitting, predicting etc… Using a callable can be really useful to +represent lazily a dataset of images stored on the file system for instance. +The callable should take as an input a 1D array-like, and return a 2D +array-like. For supervised learners it will be applied on the whole 1D array of +indicators at once, and for weakly supervised learners it will be applied on +each column of the 2D array of tuples.

+

Example with a supervised metric learner:

+
>>> def find_images(file_paths):
+>>>    # each file contains a small image to use as an input datapoint
+>>>    return np.row_stack([imread(f).ravel() for f in file_paths])
+>>>
+>>> nca = NCA(preprocessor=find_images)
+>>> nca.fit(['img01.png', 'img00.png', 'img02.png'], [1, 0, 1])
+>>> # under the hood preprocessor(indicators) will be called
+
+
+

Example with a weakly supervised metric learner:

+
>>> pairs_images_paths = [['img02.png', 'img00.png'],
+>>>                       ['img01.png', 'img00.png']]
+>>> y_pairs = np.array([1, -1])
+>>>
+>>> mmc = NCA(preprocessor=find_images)
+>>> mmc.fit(pairs_images_paths, y_pairs)
+>>> # under the hood preprocessor(pairs_indicators[i]) will be called for each
+>>> # i in [0, 1]
+
+
+
+

Note

+

Note that when you fill the preprocessor option, it allows you +to give more compact inputs, but the classical way of providing inputs +stays valid (2D array-like for supervised learners and 3D array-like of +tuples for weakly supervised learners). If a classical input +is provided, the metric learner will not use the preprocessor.

+

Example: This will work:

+
>>> from metric_learn import MMC
+>>> def preprocessor_wip(array):
+>>>    raise NotImplementedError("This preprocessor does nothing yet.")
+>>>
+>>> pairs = np.array([[[ 0.14, -0.37], [-0.7 , -0.23]],
+>>>                   [[-0.43, -0.49], [-0.7 , -0.23]]])
+>>> y_pairs = np.array([1, -1])
+>>>
+>>> mmc = MMC(preprocessor=preprocessor_wip)
+>>> mmc.fit(pairs, y_pairs)  # preprocessor_wip will not be called here
+
+
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 00000000..84e47378 --- /dev/null +++ b/search.html @@ -0,0 +1,137 @@ + + + + + + Search — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 00000000..d05a9a50 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["auto_examples/index", "auto_examples/plot_metric_learning_examples", "auto_examples/plot_sandwich", "auto_examples/sg_execution_times", "generated/metric_learn.Constraints", "generated/metric_learn.Covariance", "generated/metric_learn.ITML", "generated/metric_learn.ITML_Supervised", "generated/metric_learn.LFDA", "generated/metric_learn.LMNN", "generated/metric_learn.LSML", "generated/metric_learn.LSML_Supervised", "generated/metric_learn.MLKR", "generated/metric_learn.MMC", "generated/metric_learn.MMC_Supervised", "generated/metric_learn.NCA", "generated/metric_learn.RCA", "generated/metric_learn.RCA_Supervised", "generated/metric_learn.SCML", "generated/metric_learn.SCML_Supervised", "generated/metric_learn.SDML", "generated/metric_learn.SDML_Supervised", "generated/metric_learn.base_metric.BaseMetricLearner", "generated/metric_learn.base_metric.MahalanobisMixin", "generated/metric_learn.base_metric.MetricTransformer", "generated/metric_learn.base_metric._PairsClassifierMixin", "generated/metric_learn.base_metric._QuadrupletsClassifierMixin", "generated/metric_learn.base_metric._TripletsClassifierMixin", "getting_started", "index", "introduction", "metric_learn", "preprocessor", "supervised", "unsupervised", "user_guide", "weakly_supervised"], "filenames": ["auto_examples/index.rst", "auto_examples/plot_metric_learning_examples.rst", "auto_examples/plot_sandwich.rst", "auto_examples/sg_execution_times.rst", "generated/metric_learn.Constraints.rst", "generated/metric_learn.Covariance.rst", "generated/metric_learn.ITML.rst", "generated/metric_learn.ITML_Supervised.rst", "generated/metric_learn.LFDA.rst", "generated/metric_learn.LMNN.rst", "generated/metric_learn.LSML.rst", "generated/metric_learn.LSML_Supervised.rst", "generated/metric_learn.MLKR.rst", "generated/metric_learn.MMC.rst", "generated/metric_learn.MMC_Supervised.rst", "generated/metric_learn.NCA.rst", "generated/metric_learn.RCA.rst", "generated/metric_learn.RCA_Supervised.rst", "generated/metric_learn.SCML.rst", "generated/metric_learn.SCML_Supervised.rst", "generated/metric_learn.SDML.rst", "generated/metric_learn.SDML_Supervised.rst", "generated/metric_learn.base_metric.BaseMetricLearner.rst", "generated/metric_learn.base_metric.MahalanobisMixin.rst", "generated/metric_learn.base_metric.MetricTransformer.rst", "generated/metric_learn.base_metric._PairsClassifierMixin.rst", "generated/metric_learn.base_metric._QuadrupletsClassifierMixin.rst", "generated/metric_learn.base_metric._TripletsClassifierMixin.rst", "getting_started.rst", "index.rst", "introduction.rst", "metric_learn.rst", "preprocessor.rst", "supervised.rst", "unsupervised.rst", "user_guide.rst", "weakly_supervised.rst"], "titles": ["Examples", "Algorithms walkthrough", "Sandwich demo", "Computation times", "metric_learn.Constraints", "metric_learn.Covariance", "metric_learn.ITML", "metric_learn.ITML_Supervised", "metric_learn.LFDA", "metric_learn.LMNN", "metric_learn.LSML", "metric_learn.LSML_Supervised", "metric_learn.MLKR", "metric_learn.MMC", "metric_learn.MMC_Supervised", "metric_learn.NCA", "metric_learn.RCA", "metric_learn.RCA_Supervised", "metric_learn.SCML", "metric_learn.SCML_Supervised", "metric_learn.SDML", "metric_learn.SDML_Supervised", "metric_learn.base_metric.BaseMetricLearner", "metric_learn.base_metric.MahalanobisMixin", "metric_learn.base_metric.MetricTransformer", "metric_learn.base_metric._PairsClassifierMixin", "metric_learn.base_metric._QuadrupletsClassifierMixin", "metric_learn.base_metric._TripletsClassifierMixin", "Getting started", "metric-learn: Metric Learning in Python", "1. What is Metric Learning?", "metric_learn package", "5. Preprocessor", "2. Supervised Metric Learning", "4. Unsupervised Metric Learning", "User guide: contents", "3. Weakly Supervised Metric Learning"], "terms": {"below": [0, 1, 34, 36], "i": [0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 32, 33, 34, 35, 36], "galleri": [0, 1, 2], "metric": [0, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 32, 35], "learn": [0, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 32, 35], "us": [0, 1, 2, 4, 5, 18, 19, 26, 27, 28, 29, 32, 33, 34, 35, 36], "case": [0, 1, 4, 6, 7, 11, 13, 14, 18, 19, 20, 21, 25, 28, 32, 33, 35, 36], "sandwich": [0, 3, 7, 9, 11, 21, 22, 23, 24], "demo": [0, 3, 7, 9, 11, 21, 22, 23, 24], "algorithm": [0, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 35], "walkthrough": [0, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25], "download": [0, 1, 2, 28], "all": [0, 1, 4, 6, 7, 10, 13, 20, 22, 24, 25, 26, 27, 28, 29, 30, 32, 33, 36], "python": [0, 1, 2, 28, 30], "sourc": [0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28], "code": [0, 1, 2, 6, 10, 13, 20, 25, 28, 30, 33, 34, 36], "auto_examples_python": 0, "zip": 0, "jupyt": [0, 1, 2], "notebook": [0, 1, 2], "auto_examples_jupyt": 0, "gener": [0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 30, 34, 35], "sphinx": [0, 1, 2], "go": [1, 2, 36], "end": [1, 2, 6, 13, 20, 33, 36], "full": [1, 2, 16, 36], "thi": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 32, 33, 34, 36], "small": [1, 10, 32, 33, 36], "which": [1, 6, 12, 13, 15, 19, 20, 22, 25, 26, 27, 33, 34, 36], "illustr": [1, 30], "most": [1, 4, 6, 9, 12, 13, 15, 20, 25, 36], "implement": [1, 18, 19, 29, 30, 36], "them": [1, 30, 32, 33], "synthet": 1, "data": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 30, 34, 35], "some": [1, 4, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27, 30, 33, 36], "visual": [1, 12, 15, 33], "provid": [1, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27, 30, 32, 36], "intuit": [1, 36], "what": [1, 29, 35, 36], "thei": [1, 6, 13, 20, 25, 30, 33, 36], "ar": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33, 36], "design": [1, 13, 30, 36], "achiev": [1, 6, 13, 20, 25, 30, 36], "licens": 1, "bsd": 1, "3": [1, 2, 4, 6, 7, 9, 10, 11, 13, 14, 16, 17, 18, 19, 20, 25, 26, 27, 28, 32, 33, 36], "claus": 1, "author": [1, 29, 36], "bhargav": 1, "srinivasa": 1, "desikan": 1, "bhargavvad": 1, "gmail": 1, "com": [1, 10, 20, 28, 36], "william": [1, 2, 29], "de": [1, 29], "vazelh": [1, 29], "wdevazelh": 1, "In": [1, 2, 4, 6, 7, 10, 11, 13, 14, 18, 19, 20, 21, 25, 30, 32, 33, 36], "order": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "show": [1, 2, 30], "chart": [1, 2], "you": [1, 2, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27, 28, 29, 32, 33, 36], "need": [1, 2, 6, 13, 17, 20, 25, 28, 33, 36], "graphic": [1, 2], "matplotlib": [1, 2, 28], "backend": [1, 2], "instal": [1, 2, 29], "For": [1, 2, 4, 6, 7, 10, 11, 13, 18, 20, 21, 22, 25, 26, 27, 28, 30, 32, 33, 34, 36], "intanc": [1, 2], "pip": [1, 2, 28], "pyqt5": [1, 2], "get": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 33, 36], "qt": [1, 2], "interfac": [1, 2, 29], "your": [1, 2, 33], "favorit": [1, 2], "one": [1, 2, 4, 8, 12, 13, 15, 18, 21, 30, 33, 36], "sklearn": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 33, 34, 36], "manifold": 1, "tsne": 1, "metric_learn": [1, 2, 28, 32, 33, 34, 36], "numpi": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 33, 36], "np": [1, 2, 8, 9, 15, 32, 33, 36], "make_classif": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "make_regress": 1, "visualis": 1, "pyplot": [1, 2], "plt": [1, 2], "random": [1, 2, 4, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 33, 36], "seed": [1, 4, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21], "42": [1, 33, 36], "we": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 25, 29, 30, 33, 36], "function": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33, 36], "scikit": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 35], "The": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 32, 33, 36], "contain": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 32, 33, 36], "100": [1, 4, 13, 14, 15, 17, 33, 36], "point": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 32, 33, 36], "class": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, 33, 36], "2": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 32, 33, 36], "per": [1, 2, 8, 17, 33], "5": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 33, 36], "featur": [1, 6, 10, 13, 19, 30, 32, 36], "among": [1, 6, 7, 33, 36], "correl": 1, "label": [1, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 25, 26, 27, 30, 33, 36], "two": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 32, 33, 36], "nois": 1, "magnitud": 1, "x": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 32, 33, 34, 36], "y": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 32, 33, 36], "n_sampl": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 33, 36], "n_class": [1, 9, 15], "n_clusters_per_class": 1, "n_inform": 1, "class_sep": 1, "4": [1, 6, 10, 13, 16, 18, 26, 33, 36], "n_featur": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33, 36], "n_redund": 1, "0": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 32, 33, 36], "shuffl": 1, "true": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 33, 36], "scale": [1, 8, 10, 13, 14, 19, 33], "1": [1, 2, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 26, 27, 28, 29, 32, 33, 34, 36], "20": [1, 7, 11, 14, 21, 36], "note": [1, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27, 30, 32, 36], "dimension": [1, 8, 9, 12, 15, 16, 17, 20, 30, 33, 36], "so": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 35], "2d": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 33, 35], "t": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "sne": 1, "see": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 25, 26, 27, 28, 30, 32, 33, 34, 36], "def": [1, 2, 32], "plot_tsn": 1, "colormap": 1, "cm": 1, "pair": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 32, 33, 35], "figur": 1, "figsiz": 1, "8": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "6": [1, 2, 6, 9, 10, 13, 18, 28, 29, 33, 36], "clean": 1, "clf": [1, 28], "x_embed": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23], "fit_transform": [1, 5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21], "scatter": [1, 2, 33], "c": [1, 4, 5, 6, 7, 28, 33, 34, 36], "cmap": 1, "xtick": 1, "ytick": 1, "let": [1, 36], "": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "now": [1, 6, 13, 20, 25, 33, 34, 36], "can": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 32, 33, 34, 36], "appear": 1, "mix": 1, "becaus": [1, 33, 36], "base": [1, 2, 10, 16, 18, 19, 22, 24, 25, 26, 27, 29, 30, 33, 36], "preserv": [1, 33], "origin": [1, 6, 7, 10, 13, 16, 17, 18, 19, 20, 21, 25, 26, 27, 33, 36], "embed": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 28, 30, 33, 36], "space": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 28, 30, 33, 36], "euclidean": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 30, 33], "distanc": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 34, 35, 36], "input": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 32, 34, 35], "contribut": 1, "noisi": 1, "high": [1, 6, 10, 12, 13, 20, 25, 33, 36], "even": 1, "same": [1, 4, 7, 9, 11, 14, 16, 19, 21, 30, 33, 36], "close": [1, 6, 9, 10, 13, 30, 33, 36], "each": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 32, 33, 36], "other": [1, 4, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27, 30, 33, 36], "subspac": 1, "when": [1, 6, 8, 9, 10, 12, 13, 15, 16, 20, 22, 25, 26, 27, 30, 32, 33, 36], "consid": [1, 9, 36], "dimens": [1, 8, 9, 10, 12, 13, 14, 15, 16, 17, 30, 36], "why": 1, "prior": [1, 6, 7, 10, 11, 20, 21, 36], "knowledg": [1, 30, 36], "suppos": 1, "closer": [1, 6, 10, 13, 18, 27, 36], "out": [1, 12, 15, 33], "better": 1, "wai": [1, 6, 10, 11, 13, 20, 25, 28, 30, 32, 33, 36], "comput": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 36], "between": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33, 36], "task": [1, 6, 10, 13, 18, 26, 27, 30, 36], "hand": 1, "especi": [1, 10, 36], "higher": [1, 9, 10, 12, 15, 18, 26, 27, 36], "poor": 1, "measur": [1, 30, 36], "becom": [1, 10, 33, 36], "veri": 1, "basic": [1, 35], "d": [1, 2, 4, 5, 6, 7, 8, 10, 11, 12, 14, 15, 16, 17, 18, 19, 21, 24, 30, 33, 36], "sqrt": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 30, 33], "top": [1, 2, 24, 30], "m": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 29, 30, 33, 36], "And": 1, "paramet": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 30, 36], "satisfi": [1, 30], "certain": 1, "constraint": [1, 2, 6, 7, 10, 11, 13, 14, 17, 18, 19, 20, 21, 33, 36], "requir": [1, 18, 28, 30, 36], "togeth": [1, 30, 36], "differ": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33, 36], "far": [1, 30, 33], "awai": [1, 30, 33, 36], "more": [1, 4, 5, 6, 8, 9, 10, 11, 12, 13, 15, 16, 18, 19, 20, 22, 25, 26, 27, 28, 30, 32, 33, 36], "check": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "section": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 30, 33, 36], "document": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 30, 32, 36], "good": 1, "read": [1, 5, 6, 8, 9, 10, 12, 13, 15, 16, 18, 19, 20, 35], "materi": 1, "also": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 30, 33, 36], "found": [1, 6, 13, 20, 25, 30], "here": [1, 28, 30, 32, 33, 36], "It": [1, 2, 6, 7, 8, 13, 14, 15, 16, 17, 20, 21, 25, 33, 34, 36], "serv": 1, "literatur": 1, "review": 1, "briefli": 1, "explain": [1, 33, 36], "befor": [1, 30, 33, 36], "its": [1, 4, 10, 30, 33, 36], "usag": 1, "discuss": 1, "how": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "perform": [1, 18, 19, 30, 36], "than": [1, 6, 9, 10, 11, 12, 13, 15, 18, 20, 25, 26, 27, 30, 33, 36], "easili": [1, 30], "integr": [1, 33], "machin": [1, 29, 30], "pipelin": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 33], "follow": [1, 6, 10, 13, 18, 20, 25, 26, 27, 28, 29, 30, 33, 36], "convent": [1, 6, 13, 20, 25], "lmnn": [1, 2, 35], "primarili": 1, "k": [1, 2, 8, 9, 12, 15, 18, 19, 28, 30, 33, 36], "neighbor": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 30, 33], "classif": [1, 6, 9, 10, 13, 15, 18, 20, 25, 26, 27, 30, 33, 36], "semidefinit": [1, 36], "program": [1, 6, 36], "sub": [1, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27], "convex": [1, 10, 13, 36], "main": [1, 13, 30, 33, 36], "behind": 1, "pseudometr": 1, "under": [1, 32, 33], "instanc": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 33, 36], "train": [1, 6, 7, 14, 15, 18, 21, 30, 33, 36], "surround": 1, "share": [1, 33], "If": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 32, 33, 36], "leav": [1, 12, 15, 33], "error": [1, 6, 7, 10, 12, 13, 16, 17, 18, 20, 22, 25, 26, 27, 33], "special": 1, "cross": [1, 36], "valid": [1, 6, 13, 20, 25, 32, 33, 36], "minim": [1, 6, 10, 12, 13, 20, 25, 33, 36], "ll": 1, "notic": 1, "necessari": 1, "particular": [1, 30, 32, 33, 36], "implicitli": 1, "enforc": [1, 13, 36], "user": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 32, 36], "guid": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29], "n_neighbor": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33], "learn_rat": [1, 9, 33], "1e": [1, 6, 7, 9, 10, 11, 13, 14, 18, 19, 33, 36], "x_lmnn": 1, "have": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 32, 33, 36], "matrix": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 30, 33, 34, 36], "talk": [1, 36], "about": [1, 9, 30, 33, 36], "u": [1, 36], "tell": 1, "look": [1, 33], "like": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33, 35, 36], "after": [1, 30, 36], "being": [1, 33, 36], "new": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 30, 33, 36], "pretti": 1, "neat": 1, "huh": 1, "rest": [1, 9, 15], "while": [1, 6, 7, 9, 10, 11, 13, 14, 18, 19, 20, 21, 30, 33, 36], "first": [1, 5, 6, 9, 10, 11, 12, 13, 15, 17, 18, 26, 27, 33, 36], "run": [1, 2, 6, 7, 9, 10, 11, 12, 13, 14, 15, 19, 28], "itml": [1, 7, 35], "regular": [1, 9, 18, 19, 20, 36], "automat": [1, 30, 36], "semi": [1, 6, 23, 30, 36], "definit": [1, 6, 7, 10, 11, 20, 21, 23, 30, 36], "posit": [1, 2, 4, 6, 7, 10, 11, 13, 18, 20, 21, 23, 25, 30, 33, 36], "condit": 1, "logdet": [1, 6, 36], "diverg": [1, 6, 20, 36], "soft": 1, "must": [1, 6, 9, 11, 12, 13, 15, 20, 25, 32], "link": 1, "cannot": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33], "simpl": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 34, 36], "bregman": [1, 6, 36], "project": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 30, 33], "unlik": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "belong": [1, 4, 6, 13, 16, 20, 25, 30, 33, 36], "itml_supervis": [1, 2], "x_itml": 1, "mmc": [1, 14, 32, 33, 35], "an": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 25, 26, 27, 28, 30, 32, 33, 34, 36], "try": [1, 33], "similar": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33, 36], "ensur": 1, "sum": [1, 10, 13, 16, 33, 36], "dissimilar": [1, 6, 7, 13, 14, 20, 21, 25, 33, 36], "threshold": [1, 6, 13, 14, 20, 25, 35], "done": [1, 6, 13, 15, 20], "optim": [1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 30, 33, 36], "cost": 1, "subject": [1, 6, 36], "inequ": [1, 30], "mmc_supervis": [1, 33], "x_mmc": 1, "effici": [1, 13, 18, 20, 29, 36], "via": [1, 19, 20, 36], "l_1": 1, "penal": [1, 20, 36], "log": [1, 20, 36], "compar": [1, 6, 13, 15, 20, 25, 33, 36], "exist": [1, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27], "exploit": 1, "sparsiti": [1, 10, 20, 21, 36], "natur": [1, 10, 36], "underli": [1, 33], "intrins": 1, "sdml": [1, 21, 28, 35], "sdml_supervis": [1, 2, 20], "sparsity_param": [1, 20, 21], "balance_param": [1, 2, 20, 21], "0015": 1, "covari": [1, 2, 6, 7, 10, 11, 13, 14, 16, 20, 21, 35, 36], "x_sdml": 1, "vezelh": [1, 2], "miniconda3": [1, 2], "env": [1, 2], "docenvbi": [1, 2], "lib": [1, 2], "python3": [1, 2], "11": [1, 2, 28, 36], "site": [1, 2], "packag": [1, 2, 28, 29, 30], "_graph_lasso": [1, 2], "py": [1, 2, 3, 28], "329": [1, 2], "futurewarn": [1, 2], "cov_init": [1, 2], "deprec": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "remov": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "doe": [1, 2, 4, 5, 6, 32, 34, 36], "ani": [1, 2, 4, 7, 11, 14, 16, 21, 33, 36], "effect": [1, 2, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27, 33, 36], "warn": [1, 2, 4], "lsml": [1, 11, 35], "yet": [1, 10, 32, 36], "given": [1, 6, 7, 10, 11, 13, 14, 16, 17, 18, 20, 25, 26, 27, 30, 36], "comparison": [1, 10, 36], "formul": [1, 6, 18, 30, 36], "loss": [1, 33, 36], "correspond": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 36], "hing": [1, 33, 36], "violat": 1, "lsml_supervis": [1, 2], "tol": [1, 6, 7, 9, 10, 11, 12, 13, 14, 15, 33, 36], "0001": 1, "max_it": [1, 6, 7, 9, 10, 11, 12, 13, 14, 15, 18, 19, 33, 36], "10000": [1, 13, 14, 18, 19, 36], "x_lsml": 1, "nca": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 32, 35], "extremli": 1, "popular": [1, 29, 30], "aim": [1, 15, 30, 33, 36], "find": [1, 30, 33, 36], "linear": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 30, 33, 36], "averag": [1, 33], "loo": 1, "rule": [1, 33], "maxim": [1, 6, 13, 15, 20, 25, 33], "kei": 1, "insight": 1, "A": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 30, 33, 36], "defin": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 30, 33, 36], "differenti": [1, 6, 36], "object": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 32, 33, 36], "iter": [1, 6, 7, 9, 10, 11, 12, 13, 14, 15, 18, 19], "solver": [1, 6, 7, 9, 10, 11, 12, 13, 14, 15], "scipi": [1, 28, 33, 36], "fmin_l_bfgs_b": 1, "uniqu": [1, 2], "1000": [1, 6, 7, 9, 10, 11, 12, 15, 33, 36], "x_nca": 1, "lfda": [1, 35], "reduct": [1, 8, 12, 30, 33], "method": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 32, 33, 34, 36], "particularli": [1, 8, 33], "deal": [1, 8, 33], "multimod": [1, 8, 33], "where": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 25, 30, 32, 33, 36], "ore": [1, 8, 33], "consist": [1, 6, 8, 13, 20, 25, 33, 36], "separ": [1, 8, 9, 33], "core": [1, 8, 33], "problem": [1, 6, 8, 13, 18, 33, 35, 36], "solv": [1, 8, 13, 18, 28, 30, 33, 36], "eigenvalu": [1, 6, 8, 13, 33, 36], "n_compon": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 33], "x_lfda": 1, "rca": [1, 17, 35], "anoth": [1, 30], "older": 1, "rank": [1, 16, 18, 36], "weight": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "matric": [1, 16, 23, 36], "appli": [1, 16, 24, 32, 33, 36], "global": [1, 16, 36], "assign": [1, 16, 18, 36], "relev": [1, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27, 36], "low": [1, 6, 13, 15, 16, 20, 25, 33, 36], "irrelev": [1, 16, 36], "those": [1, 9, 12, 15, 16, 33, 36], "estim": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 32, 33, 36], "chunklet": [1, 16, 36], "subset": [1, 16, 36], "known": [1, 16, 36], "rca_supervis": 1, "n_chunk": [1, 4, 17], "30": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "chunk_siz": [1, 4, 17], "x_rca": 1, "previou": 1, "took": 1, "real": [1, 30], "number": [1, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 29, 30, 33, 36], "mlkr": [1, 35], "To": [1, 28, 33, 36], "did": [1, 36], "e": [1, 6, 7, 10, 13, 14, 16, 17, 18, 20, 25, 26, 27, 29, 30, 36], "target": [1, 5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 20, 21, 33, 36], "model": [1, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 29, 30, 33, 36], "x_reg": 1, "y_reg": 1, "orang": 1, "x_mlkr": 1, "valu": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33, 36], "would": [1, 29, 30, 36], "improv": [1, 15, 30, 33], "kneighborsregressor": 1, "alwai": [1, 30], "howev": [1, 13, 30, 36], "mani": [1, 30, 33, 36], "applic": [1, 13, 30, 36], "easier": 1, "obtain": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 36], "whether": [1, 9, 12, 15, 33, 36], "sampl": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 25, 26, 27, 32, 33, 36], "annot": 1, "face": 1, "imag": [1, 32], "person": 1, "rather": [1, 5, 34, 36], "id": 1, "huge": 1, "databas": [1, 30, 36], "everi": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "g": [1, 6, 7, 10, 12, 13, 15, 16, 17, 18, 20, 25, 26, 27, 30, 36], "retriev": [1, 30], "goal": [1, 30, 33, 36], "queri": [1, 30], "notion": 1, "individu": 1, "gather": 1, "fortun": 1, "strength": 1, "abil": 1, "inde": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 33, 36], "ve": 1, "abov": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33, 36], "altern": [1, 32, 33, 36], "pass": [1, 6, 7, 9, 10, 12, 13, 14, 15, 16, 17, 18, 20, 21, 25, 26, 27, 33], "want": [1, 6, 10, 13, 20, 25, 36], "arrai": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 35], "well": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 36], "pairs_label": 1, "n_pair": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "word": [1, 30], "further": [1, 10, 35, 36], "kind": 1, "possibl": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "weakli": [1, 7, 10, 13, 18, 19, 21, 29, 30, 32, 35], "detail": [1, 33, 36], "weak": 1, "work": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 33, 36], "purpos": [1, 33, 36], "re": 1, "explicitli": 1, "creat": [1, 7, 11, 14, 17, 19, 21, 32], "pairwis": [1, 6, 7, 10, 13, 20, 25, 33, 36], "through": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 29, 36], "do": [1, 22, 25, 26, 27, 33, 36], "keep": [1, 9, 33, 36], "mind": 1, "know": [1, 32, 36], "actual": 1, "depend": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 30, 33, 36], "hood": [1, 32], "modul": [1, 6, 13, 20, 25, 29], "own": 1, "version": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 35], "ahead": 1, "assum": [1, 18, 36], "create_constraint": 1, "itertool": 1, "aggreg": 1, "indic": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 33, 35], "zero": [1, 2, 9, 15], "ones": [1, 13, 36], "make": [1, 6, 9, 10, 13, 20, 25, 33, 36], "permut": 1, "zeros_": 1, "list": [1, 30], "combin": [1, 4, 33, 36], "ones_": 1, "twos_": 1, "put": [1, 30, 32, 36], "sim": 1, "similarili": 1, "di": 1, "append": 1, "pick": [1, 6, 13, 20, 25], "just": [1, 6, 9, 12, 13, 15, 20, 25, 36], "enough": [1, 4, 33], "len": 1, "return": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 32, 33, 36], "shape": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33, 36], "vstack": 1, "column_stack": 1, "concaten": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33], "print": [1, 6, 7, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21], "9": [1, 2, 6, 10, 13, 18, 33, 36], "10": [1, 18, 19, 33, 36], "77": 1, "65": 1, "72": 1, "55": [1, 16, 36], "71": 1, "again": 1, "longer": 1, "call": [1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 25, 30, 32, 33, 36], "take": [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 32, 33, 34, 36], "preprocessor": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 33, 35], "argument": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 36], "advanc": [1, 36], "result": [1, 36], "manual": [1, 28, 36], "construct": [1, 4, 18, 19, 30, 36], "bit": [1, 18, 19], "old": 1, "too": 1, "specif": [1, 30, 36], "worth": 1, "poke": 1, "around": [1, 33], "file": [1, 3, 32], "exactli": 1, "final": 1, "advantag": 1, "box": 1, "compat": [1, 29, 30, 35], "select": [1, 6, 13, 18, 19, 20, 25, 29, 33, 36], "score": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 33, 35], "transformermixin": [1, 33], "plug": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "procedur": [1, 6, 7, 9, 10, 11, 13, 14], "sinc": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "format": [1, 5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21, 36], "describ": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33], "allow": [1, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27, 28, 29, 30, 32, 36], "slice": 1, "along": 1, "could": 1, "bring": 1, "tutori": [1, 30], "fun": 1, "total": [1, 2, 3, 33], "time": [1, 2, 6, 7, 17, 33, 36], "script": [1, 2], "minut": [1, 2], "32": [1, 3], "400": [1, 3], "second": [1, 2, 6, 10, 13, 18, 26, 27, 36], "plot_metric_learning_exampl": [1, 3], "ipynb": [1, 2], "exampl": [2, 5, 18, 19, 26, 27, 28, 29, 30, 32, 33, 34, 36], "from": [2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 30, 32, 33, 34, 36], "http": [2, 10, 20, 28, 33, 36], "nbviewer": 2, "ipython": 2, "org": [2, 33], "6576096": 2, "import": [2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 32, 33, 34, 36], "pairwise_dist": 2, "nearestneighbor": 2, "sandwich_demo": 2, "sandwich_data": 2, "knn": [2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33], "nearest_neighbor": 2, "ax": 2, "subplot": 2, "whole": [2, 32], "row": [2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "plot_sandwich_data": 2, "plot_neighborhood_graph": 2, "set_titl": 2, "set_aspect": 2, "equal": [2, 4, 6, 9, 12, 13, 15, 18, 20, 25, 33, 36], "set_xtick": 2, "set_ytick": 2, "ml": 2, "n_constraint": [2, 4, 6, 7, 10, 11, 13, 14, 17, 18, 20, 21, 25, 26, 27, 33], "200": [2, 7, 11, 14, 20, 33], "001": [2, 6, 7, 9, 10, 11, 13, 36], "ax_num": 2, "enumer": 2, "start": [2, 29], "fit": [2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 34, 35], "tx": 2, "transform": [2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 30, 34, 35], "ml_knn": 2, "axi": 2, "__class__": 2, "__name__": 2, "todo": 2, "somewher": 2, "visualize_class_separ": 2, "_": [2, 33, 36], "ax1": 2, "ax2": 2, "ncol": 2, "label_ord": 2, "argsort": 2, "imshow": 2, "interpol": 2, "nearest": [2, 4, 8, 9, 15, 19, 28, 30, 33], "none": [2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 33, 36], "kneighbor": 2, "return_dist": 2, "fals": [2, 4, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 25, 26, 27, 33, 36], "distinct": 2, "num_class": [2, 7, 11, 14, 21], "num_point": 2, "layer": 2, "dist": 2, "7": [2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 33, 36], "dtype": 2, "float": [2, 6, 7, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 25, 26, 27], "int": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 33], "x_center": 2, "arang": 2, "y_center": 2, "yc": 2, "xc": 2, "normal": [2, 9, 12, 15, 36], "reshap": 2, "ravel": [2, 32], "color": 2, "rbgmky": 2, "idx": 2, "val": 2, "xi": 2, "50": [2, 9], "facecolor": 2, "edgecolor": 2, "nn": [2, 30], "b": [2, 4, 6, 7, 33, 36], "plot": [2, 6, 13, 20, 25], "__main__": 2, "224": 2, "userwarn": 2, "onli": [2, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27, 28, 30, 34, 36], "199": 2, "request": [2, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27], "314": [2, 3], "plot_sandwich": [2, 3], "00": 3, "35": 3, "715": 3, "execut": 3, "auto_exampl": 3, "mb": 3, "03": 3, "partial_label": 4, "build": [4, 11, 33], "ndarrai": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "unknown": [4, 33], "attribut": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 25, 33], "__init__": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "chunk": [4, 16, 17, 36], "random_st": [4, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 33, 36], "num_chunk": [4, 17], "compos": 4, "drawn": 4, "size": [4, 36], "valueerror": 4, "rais": [4, 6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27, 32], "option": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 25, 26, 27, 28, 32, 36], "default": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "randomst": [4, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 36], "pseudo": [4, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30], "renam": [4, 6, 7, 9, 11, 13, 14, 17, 21], "Will": [4, 6, 7, 9, 11, 13, 14, 17, 21], "1d": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 33, 36], "generate_knntriplet": 4, "k_genuin": [4, 19], "k_impostor": [4, 19], "triplet": [4, 18, 19, 27, 30, 35], "x_a": [4, 18, 27], "x_b": [4, 18, 27], "x_c": [4, 18, 27], "doesn": [4, 16, 18, 19], "yield": [4, 6, 13, 18, 19, 20, 25, 36], "maximum": [4, 6, 7, 9, 10, 11, 13, 14, 15], "genuin": 4, "impostor": 4, "n": [4, 5, 7, 8, 11, 12, 14, 15, 16, 17, 19, 21, 24, 33, 36], "singl": [4, 7, 11, 14, 16, 17, 19, 21], "taken": 4, "account": 4, "positive_negative_pair": [4, 33], "same_length": [4, 33], "num_constraint": [4, 7, 11, 14, 21], "neg": [4, 6, 13, 18, 20, 25, 30, 33], "form": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 35], "randomli": [4, 7, 11, 14, 17, 18, 21, 33], "draw": 4, "smaller": [4, 9, 12, 15, 30], "bool": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "forc": [4, 33], "ignor": [4, 6, 7, 10, 13, 14, 16, 17, 18, 20, 25, 26, 27], "larger": [4, 22, 25, 26, 27, 33, 36], "set": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 35, 36], "left": [4, 33, 36], "element": [4, 17, 18, 20, 27, 30, 36], "right": [4, 10, 18, 26, 27, 33, 36], "baselin": [5, 34], "anyth": [5, 34], "calcul": [5, 33, 34, 36], "introduc": [5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21], "On": [5, 34], "statist": [5, 6, 13, 20, 25, 34], "p": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 34, 36], "mahalanobi": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 34, 35, 36], "1936": [5, 34], "dataset": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 32, 33, 34, 36], "load_iri": [5, 7, 8, 9, 11, 12, 14, 15, 17, 19, 20, 28, 33, 34, 36], "iri": [5, 28, 34], "cov": [5, 34], "components_": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23], "l": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 29, 30, 33, 36], "deduc": [5, 6, 7, 10, 11, 13, 14, 18, 19, 20, 21], "components_from_metr": [5, 6, 7, 10, 11, 13, 14, 20, 21], "unus": 5, "fit_param": [5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21], "n_output": [5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21], "unsupervis": [5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21, 29, 35], "dict": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "addit": [5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21], "x_new": [5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21, 33, 36], "n_features_new": [5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21], "get_mahalanobis_matrix": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 33, 36], "copi": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23], "learner": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 30, 32, 33, 36], "get_metadata_rout": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "metadata": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "rout": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "pleas": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "mechan": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "metadatarequest": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "encapsul": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "inform": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33, 36], "get_metr": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "output": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33], "independ": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "modifi": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "initi": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "directli": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "metric_fun": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "pair_dist": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "sever": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 33, 36], "therefor": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "chang": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "besid": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "pair_scor": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "kneighborsclassifi": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28], "auto": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "leaf_siz": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "mahalanobismixin": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 25, 26, 27], "local": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "0x": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "metric_param": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "n_job": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "uniform": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "get_param": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "deep": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "subobject": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "param": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "name": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "map": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "d_m": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23], "x_e": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23], "3d": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 33, 35], "henc": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 36], "opposit": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "score_pair": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "instead": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 32, 33, 36], "refer": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30, 33, 34, 36], "occur": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "add": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "don": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "necessarili": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 30], "set_output": [5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21], "api": [5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21, 29, 30, 35], "panda": [5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21], "configur": [5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21], "datafram": [5, 7, 8, 9, 11, 12, 14, 15, 16, 17, 19, 21], "unchang": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 25, 26, 27], "self": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "set_param": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "nest": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "latter": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "compon": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 33, 36], "__": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "updat": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27], "emb": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23], "insid": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 25, 26, 27, 36], "dot": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23], "gamma": [6, 7, 18, 19], "ident": [6, 7, 9, 10, 11, 12, 13, 14, 15, 20, 21, 30, 36], "verbos": [6, 7, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 33, 36], "convergence_threshold": [6, 7, 13, 14], "theoret": [6, 7, 33, 36], "rel": [6, 9, 10, 11, 36], "entropi": [6, 36], "aka": [6, 36], "kullback": [6, 36], "leibler": [6, 36], "multivari": [6, 36], "gaussian": [6, 33, 36], "associ": [6, 30, 36], "handl": [6, 36], "wide": [6, 36], "varieti": [6, 36], "incorpor": [6, 36], "reli": [6, 36], "slack": [6, 7], "variabl": [6, 7], "converg": [6, 9, 10, 11, 12, 13, 14, 15], "toler": [6, 7, 9, 10, 11, 12, 15], "string": [6, 7, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21], "should": [6, 7, 10, 11, 13, 16, 17, 18, 20, 21, 25, 26, 27, 32, 33, 36], "strictli": [6, 7, 9, 10, 11, 12, 15, 20, 21, 30], "pd": [6, 7, 10, 11, 20, 21], "invers": [6, 7, 10, 11, 13, 14, 20, 21, 36], "spd": [6, 7, 13, 14, 21], "make_spd_matrix": [6, 7, 10, 11, 13, 14, 20, 21], "callabl": [6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 35, 36], "tupl": [6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 20, 21, 22, 30, 32, 33, 35], "jason": [6, 36], "v": [6, 36], "davi": [6, 36], "et": [6, 10, 16, 20, 29, 33, 36], "al": [6, 10, 16, 20, 29, 33, 36], "icml": [6, 20, 36], "2007": [6, 8, 12, 33, 36], "matter": [6, 13, 36], "bounds_": [6, 7], "bound": [6, 7, 36], "asid": [6, 7, 36], "5th": [6, 7], "95th": [6, 7], "percentil": [6, 7], "present": [6, 10, 18, 26, 27], "n_iter_": [6, 7, 9, 10, 11, 12, 13, 14, 15], "ha": [6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 25, 26, 27, 30, 33, 36], "threshold_": [6, 13, 20, 25], "lower": [6, 10, 13, 18, 20, 25, 26, 27, 36], "classifi": [6, 10, 13, 18, 20, 25, 26, 27, 33], "otherwis": [6, 7, 9, 10, 12, 13, 15, 16, 17, 18, 20, 25, 26, 27, 32, 36], "calibrate_threshold": [6, 13, 20, 25, 36], "pairs_valid": [6, 13, 20, 25], "y_valid": [6, 13, 20, 25], "strategi": [6, 13, 20, 25], "accuraci": [6, 10, 13, 15, 18, 20, 25, 26, 27, 33, 36], "min_rat": [6, 13, 20, 25], "beta": [6, 13, 18, 19, 20, 25, 36], "decis": [6, 13, 20, 25], "calibr": [6, 13, 20, 25, 36], "binari": [6, 13, 20, 25, 36], "cutoff": [6, 13, 20, 25], "predict": [6, 10, 13, 18, 20, 25, 26, 27, 32, 33, 35], "tradit": [6, 13, 20, 25], "evalu": [6, 13, 20, 25, 28, 36], "rate": [6, 9, 13, 18, 19, 20, 25], "f": [6, 13, 18, 19, 20, 25, 32, 36], "chosen": [6, 9, 12, 13, 15, 20, 25], "str": [6, 7, 8, 10, 13, 16, 17, 18, 20, 25, 26, 27], "choos": [6, 13, 20, 25, 30], "f_beta": [6, 13, 20, 25], "max_tpr": [6, 13, 20, 25], "highest": [6, 13, 20, 25], "least": [6, 10, 11, 13, 20, 25], "max_tnr": [6, 13, 20, 25], "specifi": [6, 13, 17, 20, 25, 32, 36], "respect": [6, 13, 20, 25, 30, 33, 36], "n_pairs_valid": [6, 13, 20, 25], "receiv": [6, 13, 20, 25], "oper": [6, 13, 20, 25], "characterist": [6, 13, 20, 25], "roc": [6, 13, 20, 25], "fundament": [6, 13, 20, 25], "tool": [6, 13, 20, 25], "clinic": [6, 13, 20, 25], "medicin": [6, 13, 20, 25], "mh": [6, 13, 20, 25], "zweig": [6, 13, 20, 25], "campbel": [6, 13, 20, 25], "chemistri": [6, 13, 20, 25], "1993": [6, 13, 20, 25], "pr": [6, 13, 20, 25], "10117": [6, 13, 20, 25], "classes_": [6, 10, 13, 18, 20, 25, 26, 27], "decision_funct": [6, 10, 13, 18, 20, 25, 26, 27, 36], "ideal": [6, 13, 20, 25], "y_predict": [6, 13, 20, 25], "calibration_param": [6, 13, 20], "trainset": [6, 13, 20], "dictionari": [6, 13, 20], "give": [6, 13, 20, 32, 33, 36], "step": [6, 13, 14, 20], "roc_auc": [6, 13, 20, 25], "inferior": [6, 13, 20, 25], "count": [6, 13, 20, 25], "classic": [6, 13, 20, 25, 30, 32, 36], "curv": [6, 13, 20, 25], "set_decision_function_request": [6, 10, 13, 18, 20, 25, 26, 27], "enable_metadata_rout": [6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27], "set_config": [6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27], "meta": [6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27], "alia": [6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27], "util": [6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27], "metadata_rout": [6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27], "retain": [6, 7, 10, 13, 16, 17, 18, 20, 25, 26, 27], "set_fit_request": [6, 7, 10, 13, 16, 17, 18, 20], "set_predict_request": [6, 10, 13, 18, 20, 25, 26, 27], "set_score_request": [6, 10, 13, 18, 20, 25, 26, 27], "set_threshold": [6, 13, 20, 25, 36], "test": [6, 13, 20, 25, 28, 36], "superior": [6, 13, 20, 25], "_pairsclassifi": [6, 13, 20, 25], "supervis": [7, 8, 10, 11, 12, 13, 14, 17, 18, 19, 21, 29, 30, 32, 35], "iris_data": [7, 8, 9, 11, 12, 14, 15, 17, 19, 20, 33], "embedding_typ": 8, "fisher": [8, 33], "discrimin": [8, 9, 15, 19, 33], "analysi": [8, 15, 16, 17, 33, 36], "cluster": [8, 13, 14, 19, 30, 33, 36], "reduc": [8, 9, 12, 15, 16, 17, 30], "min": [8, 9, 12, 15], "type": [8, 30, 32, 33, 36], "eigenvector": [8, 33], "orthonorm": 8, "plain": [8, 33, 36], "raw": 8, "masashi": 8, "sugiyama": [8, 33], "jmlr": [8, 33, 36], "yuan": [8, 29], "tang": [8, 29, 33], "beer": [8, 33], "style": [8, 33], "dim": [8, 33], "init": [9, 10, 11, 12, 13, 14, 15, 21, 33, 36], "min_it": 9, "07": [9, 36], "convergence_tol": 9, "larg": [9, 16, 33, 36], "margin": [9, 33, 36], "attempt": [9, 33], "assumpt": [9, 13, 33, 36], "distribut": [9, 12, 13, 15, 33, 36], "pca": [9, 12, 15, 33], "n_features_a": [9, 12, 15], "n_features_b": [9, 12, 15], "reason": [9, 12, 15], "lda": [9, 15, 19], "meaning": [9, 12, 15], "direct": [9, 12, 15], "varianc": [9, 12, 15], "princip": [9, 12, 15], "decomposit": [9, 12, 15, 23, 33], "discriminant_analysi": [9, 15], "lineardiscriminantanalysi": [9, 15], "truncat": [9, 12, 15], "standard": [9, 12, 15, 30, 33], "match": [9, 12, 15, 33, 36], "less": [9, 12, 15, 33, 36], "includ": 9, "edg": 9, "minimum": [9, 33], "vari": 9, "stop": 9, "progress": [9, 12, 15], "pull": 9, "push": [9, 30], "term": [9, 36], "mean": [9, 30, 33, 36], "q": [9, 12], "weinberg": [9, 12, 33], "j": [9, 15, 16, 33, 36], "blitzer": 9, "saul": 9, "nip": [9, 13, 15, 33, 36], "2005": [9, 15, 33, 36], "squar": [10, 11, 13, 18, 33, 36], "residu": [10, 11, 36], "propos": [10, 36], "thu": [10, 13, 30, 36], "infeas": [10, 36], "deploi": [10, 36], "furthermor": [10, 36], "extens": [10, 36], "lead": [10, 13, 29, 30, 33, 36], "stabl": [10, 36], "amount": [10, 36], "liu": [10, 36], "icdm": [10, 36], "2012": [10, 30, 36], "adapt": [10, 18, 19, 20, 36], "gist": [10, 20, 36], "github": [10, 20, 28, 36], "kcarnold": [10, 20, 36], "5439917": [10, 36], "quadruplet": [10, 11, 26, 30, 33, 35], "minu": [10, 18, 26, 27, 36], "probabl": [10, 18, 26, 27, 33, 36], "n_quadruplet": [10, 26], "four": [10, 26], "factor": 10, "record": [10, 26, 36], "correctli": [10, 18, 26, 27, 33], "last": [10, 11, 18, 26, 27, 28, 33, 36], "kernel": [12, 33], "regress": [12, 30, 33], "view": [12, 33], "variat": [12, 33], "cap": 12, "conjug": 12, "gradient": 12, "messag": [12, 15], "tesauto": 12, "aistat": [12, 33], "max_proj": [13, 14, 36], "diagon": [13, 14, 20, 36], "diagonal_c": [13, 14, 36], "greater": [13, 36], "minima": [13, 36], "free": [13, 36], "involv": [13, 36], "speed": [13, 36], "bottleneck": [13, 36], "been": [13, 36], "implicit": [13, 36], "compact": [13, 32, 36], "unimod": [13, 36], "restrict": [13, 36], "earliest": [13, 36], "still": [13, 18, 19, 36], "often": [13, 30, 36], "cite": [13, 36], "techniqu": [13, 36], "coeffici": [13, 14], "gotten": [13, 20, 22], "xing": [13, 36], "jordan": 13, "russel": 13, "ng": 13, "side": [13, 36], "2002": [13, 16, 36], "06": 14, "neighborhood": [15, 33], "stochast": [15, 18, 33, 36], "variant": [15, 33], "fast": [15, 33], "goldberg": [15, 33], "hinton": 15, "rowei": 15, "r": [15, 36], "salakhutdinov": 15, "neighbourhood": [15, 33], "wikipedia": [15, 33, 34], "entri": [15, 29, 33, 36], "scalar": 15, "noam": 16, "shental": [16, 36], "adjust": [16, 36], "eccv": [16, 36], "05": [16, 18, 19, 36], "95": [16, 36], "repeat": 17, "process": [17, 33], "constructor": 17, "Not": 17, "basi": [18, 19, 36], "triplet_diff": 18, "n_basi": [18, 19], "005": [18, 19], "output_it": [18, 19], "500": [18, 19], "batch_siz": [18, 19], "spars": [18, 19, 20, 21, 36], "composit": [18, 19, 36], "psd": [18, 23, 30, 36], "scheme": [18, 36], "experiment": [18, 19], "hesit": [18, 19], "report": [18, 19], "someth": [18, 19], "fail": [18, 19], "expect": [18, 19], "l1": [18, 19, 20, 36], "great": 18, "5e": [18, 19], "5000": [18, 19], "current": [18, 19, 30, 33, 36], "scml_supervis": 18, "shi": [18, 19, 36], "bellet": [18, 19, 29, 36], "sha": [18, 19, 36], "aaai": [18, 19, 36], "2014": [18, 19, 36], "matlab": [18, 19, 36], "_components_from_basis_weight": [18, 19], "n_triplet": [18, 27], "three": [18, 27, 30, 36], "scml": [19, 35], "neighbour": 19, "signific": 19, "region": [19, 33], "center": 19, "100000": [19, 36], "33": 19, "84640733": 19, "55984363": 19, "8464073327922157": 19, "01": [20, 21, 36], "doubl": [20, 36], "off": [20, 21, 36], "mathbf": [20, 33, 36], "determin": [20, 36], "m_0": [20, 36], "either": [20, 28, 30, 33, 36], "omega": [20, 36], "trade": [20, 21], "m0": [20, 21], "graph_lasso": [20, 21], "qi": [20, 36], "2009": [20, 33, 36], "5439945": [20, 36], "abstract": [22, 24, 25, 26, 27], "avail": [22, 25, 26, 27, 30], "thrown": [22, 25, 26, 27], "simpli": [22, 25, 26, 27, 30, 36], "access": [22, 25, 26, 27, 30], "column": [23, 32], "vector": [23, 30, 36], "symmetr": 23, "express": 23, "decompos": [23, 30], "product": 23, "transpos": 23, "svd": 23, "choleski": 23, "xl": 24, "anaconda": 28, "conda": 28, "forg": 28, "pypi": 28, "latest": 28, "repositori": 28, "mai": [28, 30, 36], "pytest": 28, "support": 28, "wa": 28, "v0": 28, "17": 28, "21": [28, 29, 36], "skggm": 28, "problemat": 28, "commit": 28, "a0ed406": 28, "git": 28, "a0ed406586c4364ea3297a658f415e13b5cbdaf8": 28, "load": 28, "model_select": [28, 33, 36], "cross_val_scor": [28, 33, 36], "make_pipelin": 28, "return_x_i": [28, 36], "As": 29, "part": 29, "contrib": 29, "librari": [29, 30], "routin": [29, 33, 36], "etc": [29, 30, 32, 33, 36], "unifi": 29, "scientif": 29, "public": 29, "appreci": 29, "citat": 29, "paper": [29, 36], "journal": 29, "research": 29, "138": 29, "2020": 29, "bibtex": 29, "articl": 29, "titl": 29, "etric": 29, "earn": 29, "lgorithm": 29, "ython": 29, "carei": 29, "cj": 29, "vauquier": 29, "nathali": 29, "aur": 29, "lien": 29, "year": 29, "volum": 29, "page": [29, 34], "setup": 29, "quick": 29, "content": 29, "index": [29, 32], "search": 29, "approach": 30, "tradition": 30, "practition": 30, "citi": 30, "block": 30, "cosin": 30, "priori": 30, "domain": 30, "difficult": 30, "suit": 30, "interest": 30, "manner": 30, "variou": 30, "fall": 30, "categori": 30, "broadli": 30, "speak": 30, "level": 30, "typic": 30, "weaker": [30, 36], "seek": 30, "agreement": 30, "num_dim": 30, "lx": [30, 33], "recov": 30, "seen": 30, "properti": 30, "non": 30, "symmetri": 30, "triangl": 30, "indiscern": 30, "parameter": [30, 36], "fact": 30, "both": [30, 33], "equival": [30, 36], "practic": 30, "There": 30, "few": 30, "anomali": 30, "detect": 30, "bia": 30, "toward": 30, "intend": 30, "semant": [30, 33, 36], "closest": 30, "feed": 30, "realiz": 30, "joint": 30, "hyperparamet": 30, "tune": 30, "resourc": 30, "vision": 30, "2015": 30, "survei": 30, "structur": [30, 36], "2013": 30, "book": 30, "instanti": 32, "fill": 32, "represent": [32, 36], "accept": 32, "abl": [32, 36], "replac": 32, "23": [32, 36], "43": 32, "49": 32, "14": 32, "37": 32, "points_indic": 32, "pairs_indic": [32, 36], "y_pair": [32, 36], "Then": [32, 33, 36], "realli": 32, "repres": [32, 33, 36], "lazili": 32, "store": 32, "system": 32, "onc": [32, 33], "find_imag": 32, "file_path": 32, "datapoint": 32, "row_stack": 32, "imread": 32, "img01": 32, "png": 32, "img00": 32, "img02": 32, "pairs_images_path": 32, "pairs_ind": 32, "stai": 32, "preprocessor_wip": 32, "notimplementederror": 32, "noth": 32, "distant": 33, "essenti": 33, "dog": 33, "cat": 33, "anim": 33, "91884732": 33, "25406973": 33, "1545886": 33, "80350083": 33, "our": [33, 36], "49627072": [33, 36], "65287282": [33, 36], "06079877": [33, 36], "Or": [33, 36], "coordin": [33, 36], "similarli": [33, 36], "spatial": [33, 36], "4962707194621285": 33, "43680409": 33, "89169412": 33, "9542479": 33, "baseestim": 33, "gridsearchcv": [33, 36], "min_": [33, 36], "sum_": [33, 36], "eta_": 33, "ij": [33, 36], "x_i": [33, 36], "x_j": [33, 36], "y_": 33, "x_l": 33, "_i": [33, 36], "_j": [33, 36], "_l": [33, 36], "within": [33, 36], "cdot": [33, 36], "max": 33, "p_": 33, "softmax": 33, "likelihood": 33, "frac": [33, 36], "exp": [33, 36], "_2": [33, 36], "neq": 33, "qquad": [33, 36], "ii": 33, "y_j": 33, "y_i": 33, "text": [33, 36], "argmax": 33, "sum_i": 33, "p_i": 33, "idea": 33, "en": 33, "wiki": 33, "linear_discriminant_analysi": 33, "multi": 33, "modal": 33, "w": [33, 36], "fashion": 33, "nw_": 33, "w_": 33, "begin": [33, 36], "align": [33, 36], "n_l": 33, "th": 33, "affin": 33, "deriv": 33, "arg": 33, "max_": 33, "tr": [33, 36], "That": 33, "nearbi": 33, "made": 33, "apart": 33, "impos": 33, "ldfa": 33, "suffer": 33, "sign": 33, "indeterminaci": 33, "state": 33, "relat": [33, 36], "ran": 33, "might": [33, 36], "hereaft": 33, "focu": 33, "exposit": 33, "empir": 33, "develop": 33, "denot": [33, 36], "k_": 33, "pi": 33, "sigma": 33, "transit": 33, "tl": 33, "sake": [33, 36], "simplic": [33, 36], "cumul": 33, "quadrat": 33, "mathcal": 33, "hat": [33, 36], "y_jk_": 33, "_supervis": 33, "interpret": [33, 36], "discard": 33, "sometim": 33, "lenght": 33, "unlabel": 34, "zca": 34, "whiten": 34, "judgment": 36, "paragraph": 36, "These": 36, "theses": 36, "ex": 36, "appropri": 36, "my_algo": 36, "split": 36, "train_test_split": 36, "pairs_train": 36, "pairs_test": 36, "y_train": 36, "y_test": 36, "n_tupl": 36, "tuple_s": 36, "artifici": 36, "12": 36, "19": 36, "16": 36, "02": 36, "58": 36, "93": 36, "89": 36, "34": 36, "41": 36, "recommend": 36, "redund": 36, "comment": 36, "lot": 36, "memori": 36, "replic": 36, "collect": 36, "loos": 36, "tuples_indic": 36, "fetch": 36, "path": 36, "filesystem": 36, "wise": 36, "a0": 36, "24667162e": 36, "62622348e": 36, "88325421e": 36, "08": 36, "61531114e": 36, "86778289e": 36, "12654397e": 36, "27607365": 36, "88853014": 36, "276073646278203": 36, "58603894": 36, "69883982": 36, "66614919": 36, "41743549": 36, "20219519": 36, "73697721": 36, "rng": 36, "randint": 36, "next": 36, "unseen": 36, "15": 36, "75": 36, "threshold_param": 36, "caus": 36, "overfit": 36, "avoid": 36, "f1": 36, "12811124": 36, "74750256": 36, "common": 36, "accuracy_scor": 36, "roc_auc_scor": 36, "z": 36, "d_": 36, "mu": 36, "constant": 36, "textbf": 36, "kl": 36, "_0": 36, "ell": 36, "mathrm": 36, "m_": 36, "operatornam": 36, "det": 36, "quad": 36, "leq": 36, "geq": 36, "upper": 36, "www": 36, "utexa": 36, "edu": 36, "pjain": 36, "eta": 36, "xlx": 36, "lambda": 36, "_1": 36, "_n": 36, "incid": 36, "laplacian": 36, "whose": 36, "norm": 36, "n_j": 36, "ji": 36, "bar": 36, "hillel": 36, "2003": 36, "constrain": 36, "mathbb": 36, "2_": 36, "cmu": 36, "7eepx": 36, "old_pap": 36, "code_metric_onlin": 36, "tar": 36, "gz": 36, "third": 36, "triplets_indic": 36, "upcom": 36, "triplets_test": 36, "likeli": 36, "75700306": 36, "98982131": 36, "f1_score": 36, "proport": 36, "built": 36, "b_i": 36, "w_i": 36, "diag": 36, "nonneg": 36, "fix": 36, "over": 36, "ell_1": 36, "ad": 36, "x_k": 36, "d_w": 36, "quadruplets_indic": 36, "quadruplets_test": 36, "_k": 36, "h": 36, "suggest": 36, "confid": 36, "extra": 36, "experi": 36, "plu": 36, "ld": 36, "mm_0": 36}, "objects": {"metric_learn": [[4, 0, 1, "", "Constraints"], [5, 0, 1, "", "Covariance"], [6, 0, 1, "", "ITML"], [7, 0, 1, "", "ITML_Supervised"], [8, 0, 1, "", "LFDA"], [9, 0, 1, "", "LMNN"], [10, 0, 1, "", "LSML"], [11, 0, 1, "", "LSML_Supervised"], [12, 0, 1, "", "MLKR"], [13, 0, 1, "", "MMC"], [14, 0, 1, "", "MMC_Supervised"], [15, 0, 1, "", "NCA"], [16, 0, 1, "", "RCA"], [17, 0, 1, "", "RCA_Supervised"], [18, 0, 1, "", "SCML"], [19, 0, 1, "", "SCML_Supervised"], [20, 0, 1, "", "SDML"], [21, 0, 1, "", "SDML_Supervised"]], "metric_learn.Constraints": [[4, 1, 1, "", "__init__"], [4, 1, 1, "", "chunks"], [4, 1, 1, "", "generate_knntriplets"], [4, 1, 1, "", "positive_negative_pairs"]], "metric_learn.Covariance": [[5, 1, 1, "", "__init__"], [5, 1, 1, "", "fit"], [5, 1, 1, "", "fit_transform"], [5, 1, 1, "", "get_mahalanobis_matrix"], [5, 1, 1, "", "get_metadata_routing"], [5, 1, 1, "", "get_metric"], [5, 1, 1, "", "get_params"], [5, 1, 1, "", "pair_distance"], [5, 1, 1, "", "pair_score"], [5, 1, 1, "", "score_pairs"], [5, 1, 1, "", "set_output"], [5, 1, 1, "", "set_params"], [5, 1, 1, "", "transform"]], "metric_learn.ITML": [[6, 1, 1, "", "__init__"], [6, 1, 1, "", "calibrate_threshold"], [6, 2, 1, "", "classes_"], [6, 1, 1, "", "decision_function"], [6, 1, 1, "", "fit"], [6, 1, 1, "", "get_mahalanobis_matrix"], [6, 1, 1, "", "get_metadata_routing"], [6, 1, 1, "", "get_metric"], [6, 1, 1, "", "get_params"], [6, 1, 1, "", "pair_distance"], [6, 1, 1, "", "pair_score"], [6, 1, 1, "", "predict"], [6, 1, 1, "", "score"], [6, 1, 1, "", "score_pairs"], [6, 1, 1, "", "set_decision_function_request"], [6, 1, 1, "", "set_fit_request"], [6, 1, 1, "", "set_params"], [6, 1, 1, "", "set_predict_request"], [6, 1, 1, "", "set_score_request"], [6, 1, 1, "", "set_threshold"], [6, 1, 1, "", "transform"]], "metric_learn.ITML_Supervised": [[7, 1, 1, "", "__init__"], [7, 1, 1, "", "fit"], [7, 1, 1, "", "fit_transform"], [7, 1, 1, "", "get_mahalanobis_matrix"], [7, 1, 1, "", "get_metadata_routing"], [7, 1, 1, "", "get_metric"], [7, 1, 1, "", "get_params"], [7, 1, 1, "", "pair_distance"], [7, 1, 1, "", "pair_score"], [7, 1, 1, "", "score_pairs"], [7, 1, 1, "", "set_fit_request"], [7, 1, 1, "", "set_output"], [7, 1, 1, "", "set_params"], [7, 1, 1, "", "transform"]], "metric_learn.LFDA": [[8, 1, 1, "", "__init__"], [8, 1, 1, "", "fit"], [8, 1, 1, "", "fit_transform"], [8, 1, 1, "", "get_mahalanobis_matrix"], [8, 1, 1, "", "get_metadata_routing"], [8, 1, 1, "", "get_metric"], [8, 1, 1, "", "get_params"], [8, 1, 1, "", "pair_distance"], [8, 1, 1, "", "pair_score"], [8, 1, 1, "", "score_pairs"], [8, 1, 1, "", "set_output"], [8, 1, 1, "", "set_params"], [8, 1, 1, "", "transform"]], "metric_learn.LMNN": [[9, 1, 1, "", "__init__"], [9, 1, 1, "", "fit"], [9, 1, 1, "", "fit_transform"], [9, 1, 1, "", "get_mahalanobis_matrix"], [9, 1, 1, "", "get_metadata_routing"], [9, 1, 1, "", "get_metric"], [9, 1, 1, "", "get_params"], [9, 1, 1, "", "pair_distance"], [9, 1, 1, "", "pair_score"], [9, 1, 1, "", "score_pairs"], [9, 1, 1, "", "set_output"], [9, 1, 1, "", "set_params"], [9, 1, 1, "", "transform"]], "metric_learn.LSML": [[10, 1, 1, "", "__init__"], [10, 2, 1, "", "classes_"], [10, 1, 1, "", "decision_function"], [10, 1, 1, "", "fit"], [10, 1, 1, "", "get_mahalanobis_matrix"], [10, 1, 1, "", "get_metadata_routing"], [10, 1, 1, "", "get_metric"], [10, 1, 1, "", "get_params"], [10, 1, 1, "", "pair_distance"], [10, 1, 1, "", "pair_score"], [10, 1, 1, "", "predict"], [10, 1, 1, "", "score"], [10, 1, 1, "", "score_pairs"], [10, 1, 1, "", "set_decision_function_request"], [10, 1, 1, "", "set_fit_request"], [10, 1, 1, "", "set_params"], [10, 1, 1, "", "set_predict_request"], [10, 1, 1, "", "set_score_request"], [10, 1, 1, "", "transform"]], "metric_learn.LSML_Supervised": [[11, 1, 1, "", "__init__"], [11, 1, 1, "", "fit"], [11, 1, 1, "", "fit_transform"], [11, 1, 1, "", "get_mahalanobis_matrix"], [11, 1, 1, "", "get_metadata_routing"], [11, 1, 1, "", "get_metric"], [11, 1, 1, "", "get_params"], [11, 1, 1, "", "pair_distance"], [11, 1, 1, "", "pair_score"], [11, 1, 1, "", "score_pairs"], [11, 1, 1, "", "set_output"], [11, 1, 1, "", "set_params"], [11, 1, 1, "", "transform"]], "metric_learn.MLKR": [[12, 1, 1, "", "__init__"], [12, 1, 1, "", "fit"], [12, 1, 1, "", "fit_transform"], [12, 1, 1, "", "get_mahalanobis_matrix"], [12, 1, 1, "", "get_metadata_routing"], [12, 1, 1, "", "get_metric"], [12, 1, 1, "", "get_params"], [12, 1, 1, "", "pair_distance"], [12, 1, 1, "", "pair_score"], [12, 1, 1, "", "score_pairs"], [12, 1, 1, "", "set_output"], [12, 1, 1, "", "set_params"], [12, 1, 1, "", "transform"]], "metric_learn.MMC": [[13, 1, 1, "", "__init__"], [13, 1, 1, "", "calibrate_threshold"], [13, 2, 1, "", "classes_"], [13, 1, 1, "", "decision_function"], [13, 1, 1, "", "fit"], [13, 1, 1, "", "get_mahalanobis_matrix"], [13, 1, 1, "", "get_metadata_routing"], [13, 1, 1, "", "get_metric"], [13, 1, 1, "", "get_params"], [13, 1, 1, "", "pair_distance"], [13, 1, 1, "", "pair_score"], [13, 1, 1, "", "predict"], [13, 1, 1, "", "score"], [13, 1, 1, "", "score_pairs"], [13, 1, 1, "", "set_decision_function_request"], [13, 1, 1, "", "set_fit_request"], [13, 1, 1, "", "set_params"], [13, 1, 1, "", "set_predict_request"], [13, 1, 1, "", "set_score_request"], [13, 1, 1, "", "set_threshold"], [13, 1, 1, "", "transform"]], "metric_learn.MMC_Supervised": [[14, 1, 1, "", "__init__"], [14, 1, 1, "", "fit"], [14, 1, 1, "", "fit_transform"], [14, 1, 1, "", "get_mahalanobis_matrix"], [14, 1, 1, "", "get_metadata_routing"], [14, 1, 1, "", "get_metric"], [14, 1, 1, "", "get_params"], [14, 1, 1, "", "pair_distance"], [14, 1, 1, "", "pair_score"], [14, 1, 1, "", "score_pairs"], [14, 1, 1, "", "set_output"], [14, 1, 1, "", "set_params"], [14, 1, 1, "", "transform"]], "metric_learn.NCA": [[15, 1, 1, "", "__init__"], [15, 1, 1, "", "fit"], [15, 1, 1, "", "fit_transform"], [15, 1, 1, "", "get_mahalanobis_matrix"], [15, 1, 1, "", "get_metadata_routing"], [15, 1, 1, "", "get_metric"], [15, 1, 1, "", "get_params"], [15, 1, 1, "", "pair_distance"], [15, 1, 1, "", "pair_score"], [15, 1, 1, "", "score_pairs"], [15, 1, 1, "", "set_output"], [15, 1, 1, "", "set_params"], [15, 1, 1, "", "transform"]], "metric_learn.RCA": [[16, 1, 1, "", "__init__"], [16, 1, 1, "", "fit"], [16, 1, 1, "", "fit_transform"], [16, 1, 1, "", "get_mahalanobis_matrix"], [16, 1, 1, "", "get_metadata_routing"], [16, 1, 1, "", "get_metric"], [16, 1, 1, "", "get_params"], [16, 1, 1, "", "pair_distance"], [16, 1, 1, "", "pair_score"], [16, 1, 1, "", "score_pairs"], [16, 1, 1, "", "set_fit_request"], [16, 1, 1, "", "set_output"], [16, 1, 1, "", "set_params"], [16, 1, 1, "", "transform"]], "metric_learn.RCA_Supervised": [[17, 1, 1, "", "__init__"], [17, 1, 1, "", "fit"], [17, 1, 1, "", "fit_transform"], [17, 1, 1, "", "get_mahalanobis_matrix"], [17, 1, 1, "", "get_metadata_routing"], [17, 1, 1, "", "get_metric"], [17, 1, 1, "", "get_params"], [17, 1, 1, "", "pair_distance"], [17, 1, 1, "", "pair_score"], [17, 1, 1, "", "score_pairs"], [17, 1, 1, "", "set_fit_request"], [17, 1, 1, "", "set_output"], [17, 1, 1, "", "set_params"], [17, 1, 1, "", "transform"]], "metric_learn.SCML": [[18, 1, 1, "", "__init__"], [18, 2, 1, "", "classes_"], [18, 1, 1, "", "decision_function"], [18, 1, 1, "", "fit"], [18, 1, 1, "", "get_mahalanobis_matrix"], [18, 1, 1, "", "get_metadata_routing"], [18, 1, 1, "", "get_metric"], [18, 1, 1, "", "get_params"], [18, 1, 1, "", "pair_distance"], [18, 1, 1, "", "pair_score"], [18, 1, 1, "", "predict"], [18, 1, 1, "", "score"], [18, 1, 1, "", "score_pairs"], [18, 1, 1, "", "set_decision_function_request"], [18, 1, 1, "", "set_fit_request"], [18, 1, 1, "", "set_params"], [18, 1, 1, "", "set_predict_request"], [18, 1, 1, "", "set_score_request"], [18, 1, 1, "", "transform"]], "metric_learn.SCML_Supervised": [[19, 1, 1, "", "__init__"], [19, 1, 1, "", "fit"], [19, 1, 1, "", "fit_transform"], [19, 1, 1, "", "get_mahalanobis_matrix"], [19, 1, 1, "", "get_metadata_routing"], [19, 1, 1, "", "get_metric"], [19, 1, 1, "", "get_params"], [19, 1, 1, "", "pair_distance"], [19, 1, 1, "", "pair_score"], [19, 1, 1, "", "score_pairs"], [19, 1, 1, "", "set_output"], [19, 1, 1, "", "set_params"], [19, 1, 1, "", "transform"]], "metric_learn.SDML": [[20, 1, 1, "", "__init__"], [20, 1, 1, "", "calibrate_threshold"], [20, 2, 1, "", "classes_"], [20, 1, 1, "", "decision_function"], [20, 1, 1, "", "fit"], [20, 1, 1, "", "get_mahalanobis_matrix"], [20, 1, 1, "", "get_metadata_routing"], [20, 1, 1, "", "get_metric"], [20, 1, 1, "", "get_params"], [20, 1, 1, "", "pair_distance"], [20, 1, 1, "", "pair_score"], [20, 1, 1, "", "predict"], [20, 1, 1, "", "score"], [20, 1, 1, "", "score_pairs"], [20, 1, 1, "", "set_decision_function_request"], [20, 1, 1, "", "set_fit_request"], [20, 1, 1, "", "set_params"], [20, 1, 1, "", "set_predict_request"], [20, 1, 1, "", "set_score_request"], [20, 1, 1, "", "set_threshold"], [20, 1, 1, "", "transform"]], "metric_learn.SDML_Supervised": [[21, 1, 1, "", "__init__"], [21, 1, 1, "", "fit"], [21, 1, 1, "", "fit_transform"], [21, 1, 1, "", "get_mahalanobis_matrix"], [21, 1, 1, "", "get_metadata_routing"], [21, 1, 1, "", "get_metric"], [21, 1, 1, "", "get_params"], [21, 1, 1, "", "pair_distance"], [21, 1, 1, "", "pair_score"], [21, 1, 1, "", "score_pairs"], [21, 1, 1, "", "set_output"], [21, 1, 1, "", "set_params"], [21, 1, 1, "", "transform"]], "metric_learn.base_metric": [[22, 0, 1, "", "BaseMetricLearner"], [23, 0, 1, "", "MahalanobisMixin"], [24, 0, 1, "", "MetricTransformer"], [25, 0, 1, "", "_PairsClassifierMixin"], [26, 0, 1, "", "_QuadrupletsClassifierMixin"], [27, 0, 1, "", "_TripletsClassifierMixin"]], "metric_learn.base_metric.BaseMetricLearner": [[22, 1, 1, "", "__init__"], [22, 1, 1, "", "get_metadata_routing"], [22, 1, 1, "", "get_metric"], [22, 1, 1, "", "get_params"], [22, 1, 1, "", "pair_distance"], [22, 1, 1, "", "pair_score"], [22, 1, 1, "", "score_pairs"], [22, 1, 1, "", "set_params"]], "metric_learn.base_metric.MahalanobisMixin": [[23, 1, 1, "", "__init__"], [23, 1, 1, "", "get_mahalanobis_matrix"], [23, 1, 1, "", "get_metadata_routing"], [23, 1, 1, "", "get_metric"], [23, 1, 1, "", "get_params"], [23, 1, 1, "", "pair_distance"], [23, 1, 1, "", "pair_score"], [23, 1, 1, "", "score_pairs"], [23, 1, 1, "", "set_params"], [23, 1, 1, "", "transform"]], "metric_learn.base_metric.MetricTransformer": [[24, 1, 1, "", "transform"]], "metric_learn.base_metric._PairsClassifierMixin": [[25, 1, 1, "", "__init__"], [25, 1, 1, "", "calibrate_threshold"], [25, 2, 1, "", "classes_"], [25, 1, 1, "", "decision_function"], [25, 1, 1, "", "get_metadata_routing"], [25, 1, 1, "", "get_metric"], [25, 1, 1, "", "get_params"], [25, 1, 1, "", "pair_distance"], [25, 1, 1, "", "pair_score"], [25, 1, 1, "", "predict"], [25, 1, 1, "", "score"], [25, 1, 1, "", "score_pairs"], [25, 1, 1, "", "set_decision_function_request"], [25, 1, 1, "", "set_params"], [25, 1, 1, "", "set_predict_request"], [25, 1, 1, "", "set_score_request"], [25, 1, 1, "", "set_threshold"]], "metric_learn.base_metric._QuadrupletsClassifierMixin": [[26, 1, 1, "", "__init__"], [26, 2, 1, "", "classes_"], [26, 1, 1, "", "decision_function"], [26, 1, 1, "", "get_metadata_routing"], [26, 1, 1, "", "get_metric"], [26, 1, 1, "", "get_params"], [26, 1, 1, "", "pair_distance"], [26, 1, 1, "", "pair_score"], [26, 1, 1, "", "predict"], [26, 1, 1, "", "score"], [26, 1, 1, "", "score_pairs"], [26, 1, 1, "", "set_decision_function_request"], [26, 1, 1, "", "set_params"], [26, 1, 1, "", "set_predict_request"], [26, 1, 1, "", "set_score_request"]], "metric_learn.base_metric._TripletsClassifierMixin": [[27, 1, 1, "", "__init__"], [27, 2, 1, "", "classes_"], [27, 1, 1, "", "decision_function"], [27, 1, 1, "", "get_metadata_routing"], [27, 1, 1, "", "get_metric"], [27, 1, 1, "", "get_params"], [27, 1, 1, "", "pair_distance"], [27, 1, 1, "", "pair_score"], [27, 1, 1, "", "predict"], [27, 1, 1, "", "score"], [27, 1, 1, "", "score_pairs"], [27, 1, 1, "", "set_decision_function_request"], [27, 1, 1, "", "set_params"], [27, 1, 1, "", "set_predict_request"], [27, 1, 1, "", "set_score_request"]]}, "objtypes": {"0": "py:class", "1": "py:method", "2": "py:attribute"}, "objnames": {"0": ["py", "class", "Python class"], "1": ["py", "method", "Python method"], "2": ["py", "attribute", "Python attribute"]}, "titleterms": {"exampl": [0, 1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25], "algorithm": [1, 31, 33, 34, 36], "walkthrough": 1, "import": 1, "load": 1, "our": 1, "dataset": 1, "set": [1, 30], "up": 1, "plot": 1, "metric": [1, 29, 30, 33, 34, 36], "learn": [1, 29, 30, 31, 33, 34, 36], "larg": 1, "margin": 1, "nearest": 1, "neighbour": 1, "fit": [1, 33, 36], "transform": [1, 33, 36], "inform": 1, "theoret": 1, "mahalanobi": [1, 30], "cluster": 1, "spars": 1, "determin": 1, "least": 1, "squar": 1, "neighborhood": 1, "compon": 1, "analysi": 1, "local": 1, "fisher": 1, "discrimin": 1, "rel": 1, "regress": 1, "kernel": 1, "from": 1, "weaker": 1, "supervis": [1, 31, 33, 36], "sandwich": 2, "demo": 2, "comput": 3, "time": 3, "metric_learn": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 31], "constraint": 4, "covari": [5, 34], "itml": [6, 36], "us": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 30], "itml_supervis": 7, "lfda": [8, 33], "lmnn": [9, 33], "lsml": [10, 36], "lsml_supervis": 11, "mlkr": [12, 33], "mmc": [13, 36], "mmc_supervis": 14, "nca": [15, 33], "rca": [16, 36], "rca_supervis": 17, "scml": [18, 36], "scml_supervis": 19, "sdml": [20, 36], "sdml_supervis": 21, "base_metr": [22, 23, 24, 25, 26, 27], "basemetriclearn": 22, "mahalanobismixin": 23, "metrictransform": 24, "_pairsclassifiermixin": 25, "_quadrupletsclassifiermixin": 26, "_tripletsclassifiermixin": 27, "get": 28, "start": 28, "instal": 28, "setup": 28, "quick": 28, "python": 29, "document": 29, "outlin": 29, "what": 30, "i": 30, "problem": 30, "distanc": 30, "case": 30, "further": 30, "read": 30, "packag": 31, "modul": 31, "content": 31, "base": 31, "class": 31, "weakli": [31, 33, 36], "unsupervis": [31, 34], "preprocessor": [32, 36], "arrai": [32, 36], "like": 32, "callabl": 32, "gener": [33, 36], "api": [33, 36], "input": [33, 36], "data": [33, 36], "so": [33, 36], "scikit": [33, 36], "compat": [33, 36], "version": 33, "user": 35, "guid": 35, "basic": 36, "form": 36, "3d": 36, "tupl": 36, "2d": 36, "indic": 36, "predict": 36, "score": 36, "pair": 36, "threshold": 36, "triplet": 36, "quadruplet": 36}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.todo": 2, "sphinx.ext.viewcode": 1, "sphinx.ext.intersphinx": 1, "sphinx": 60}, "alltitles": {"Examples": [[0, "examples"]], "Algorithms walkthrough": [[1, "algorithms-walkthrough"]], "Imports": [[1, "imports"]], "Loading our dataset and setting up plotting": [[1, "loading-our-dataset-and-setting-up-plotting"]], "Metric Learning": [[1, "metric-learning"]], "Large Margin Nearest Neighbour": [[1, "large-margin-nearest-neighbour"]], "Fit and then transform!": [[1, "fit-and-then-transform"]], "Information Theoretic Metric Learning": [[1, "information-theoretic-metric-learning"]], "Mahalanobis Metric for Clustering": [[1, "mahalanobis-metric-for-clustering"]], "Sparse Determinant Metric Learning": [[1, "sparse-determinant-metric-learning"]], "Least Squares Metric Learning": [[1, "least-squares-metric-learning"]], "Neighborhood Components Analysis": [[1, "neighborhood-components-analysis"]], "Local Fisher Discriminant Analysis": [[1, "local-fisher-discriminant-analysis"]], "Relative Components Analysis": [[1, "relative-components-analysis"]], "Regression example: Metric Learning for Kernel Regression": [[1, "regression-example-metric-learning-for-kernel-regression"]], "Metric Learning from Weaker Supervision": [[1, "metric-learning-from-weaker-supervision"]], "Sandwich demo": [[2, "sandwich-demo"]], "Computation times": [[3, "computation-times"]], "metric_learn.Constraints": [[4, "metric-learn-constraints"]], "metric_learn.Covariance": [[5, "metric-learn-covariance"]], "metric_learn.ITML": [[6, "metric-learn-itml"]], "Examples using metric_learn.ITML": [[6, "examples-using-metric-learn-itml"]], "metric_learn.ITML_Supervised": [[7, "metric-learn-itml-supervised"]], "Examples using metric_learn.ITML_Supervised": [[7, "examples-using-metric-learn-itml-supervised"]], "metric_learn.LFDA": [[8, "metric-learn-lfda"]], "Examples using metric_learn.LFDA": [[8, "examples-using-metric-learn-lfda"]], "metric_learn.LMNN": [[9, "metric-learn-lmnn"]], "Examples using metric_learn.LMNN": [[9, "examples-using-metric-learn-lmnn"]], "metric_learn.LSML": [[10, "metric-learn-lsml"]], "Examples using metric_learn.LSML": [[10, "examples-using-metric-learn-lsml"]], "metric_learn.LSML_Supervised": [[11, "metric-learn-lsml-supervised"]], "Examples using metric_learn.LSML_Supervised": [[11, "examples-using-metric-learn-lsml-supervised"]], "metric_learn.MLKR": [[12, "metric-learn-mlkr"]], "Examples using metric_learn.MLKR": [[12, "examples-using-metric-learn-mlkr"]], "metric_learn.MMC": [[13, "metric-learn-mmc"]], "Examples using metric_learn.MMC": [[13, "examples-using-metric-learn-mmc"]], "metric_learn.MMC_Supervised": [[14, "metric-learn-mmc-supervised"]], "Examples using metric_learn.MMC_Supervised": [[14, "examples-using-metric-learn-mmc-supervised"]], "metric_learn.NCA": [[15, "metric-learn-nca"]], "Examples using metric_learn.NCA": [[15, "examples-using-metric-learn-nca"]], "metric_learn.RCA": [[16, "metric-learn-rca"]], "Examples using metric_learn.RCA": [[16, "examples-using-metric-learn-rca"]], "metric_learn.RCA_Supervised": [[17, "metric-learn-rca-supervised"]], "Examples using metric_learn.RCA_Supervised": [[17, "examples-using-metric-learn-rca-supervised"]], "metric_learn.SCML": [[18, "metric-learn-scml"]], "metric_learn.SCML_Supervised": [[19, "metric-learn-scml-supervised"]], "metric_learn.SDML": [[20, "metric-learn-sdml"]], "Examples using metric_learn.SDML": [[20, "examples-using-metric-learn-sdml"]], "metric_learn.SDML_Supervised": [[21, "metric-learn-sdml-supervised"]], "Examples using metric_learn.SDML_Supervised": [[21, "examples-using-metric-learn-sdml-supervised"]], "metric_learn.base_metric.BaseMetricLearner": [[22, "metric-learn-base-metric-basemetriclearner"]], "Examples using metric_learn.base_metric.BaseMetricLearner": [[22, "examples-using-metric-learn-base-metric-basemetriclearner"]], "metric_learn.base_metric.MahalanobisMixin": [[23, "metric-learn-base-metric-mahalanobismixin"]], "Examples using metric_learn.base_metric.MahalanobisMixin": [[23, "examples-using-metric-learn-base-metric-mahalanobismixin"]], "metric_learn.base_metric.MetricTransformer": [[24, "metric-learn-base-metric-metrictransformer"]], "Examples using metric_learn.base_metric.MetricTransformer": [[24, "examples-using-metric-learn-base-metric-metrictransformer"]], "metric_learn.base_metric._PairsClassifierMixin": [[25, "metric-learn-base-metric-pairsclassifiermixin"]], "Examples using metric_learn.base_metric._PairsClassifierMixin": [[25, "examples-using-metric-learn-base-metric-pairsclassifiermixin"]], "metric_learn.base_metric._QuadrupletsClassifierMixin": [[26, "metric-learn-base-metric-quadrupletsclassifiermixin"]], "metric_learn.base_metric._TripletsClassifierMixin": [[27, "metric-learn-base-metric-tripletsclassifiermixin"]], "Getting started": [[28, "getting-started"]], "Installation and Setup": [[28, "installation-and-setup"]], "Quick start": [[28, "quick-start"]], "metric-learn: Metric Learning in Python": [[29, "metric-learn-metric-learning-in-python"]], "Documentation outline": [[29, "documentation-outline"]], "What is Metric Learning?": [[30, "what-is-metric-learning"]], "Problem Setting": [[30, "problem-setting"]], "Mahalanobis Distances": [[30, "mahalanobis-distances"]], "Use-cases": [[30, "use-cases"]], "Further reading": [[30, "further-reading"]], "metric_learn package": [[31, "metric-learn-package"]], "Module Contents": [[31, "module-contents"]], "Base Classes": [[31, "base-classes"]], "Supervised Learning Algorithms": [[31, "supervised-learning-algorithms"]], "Weakly Supervised Learning Algorithms": [[31, "weakly-supervised-learning-algorithms"]], "Unsupervised Learning Algorithms": [[31, "unsupervised-learning-algorithms"]], "Preprocessor": [[32, "preprocessor"]], "Array-like": [[32, "array-like"]], "Callable": [[32, "callable"]], "Supervised Metric Learning": [[33, "supervised-metric-learning"]], "General API": [[33, "general-api"], [36, "general-api"]], "Input data": [[33, "input-data"], [36, "input-data"]], "Fit, transform, and so on": [[33, "fit-transform-and-so-on"], [36, "fit-transform-and-so-on"]], "Scikit-learn compatibility": [[33, "scikit-learn-compatibility"], [36, "scikit-learn-compatibility"]], "Algorithms": [[33, "algorithms"], [34, "algorithms"], [36, "algorithms"], [36, "id10"], [36, "id16"]], "LMNN": [[33, "lmnn"]], "NCA": [[33, "nca"]], "LFDA": [[33, "lfda"]], "MLKR": [[33, "mlkr"]], "Supervised versions of weakly-supervised algorithms": [[33, "supervised-versions-of-weakly-supervised-algorithms"]], "Unsupervised Metric Learning": [[34, "unsupervised-metric-learning"]], "Covariance": [[34, "covariance"]], "User Guide": [[35, "user-guide"]], "Weakly Supervised Metric Learning": [[36, "weakly-supervised-metric-learning"]], "Basic form": [[36, "basic-form"]], "3D array of tuples": [[36, "d-array-of-tuples"]], "2D array of indicators + preprocessor": [[36, "d-array-of-indicators-preprocessor"]], "Prediction and scoring": [[36, "prediction-and-scoring"]], "Learning on pairs": [[36, "learning-on-pairs"]], "Fitting": [[36, "fitting"], [36, "id7"], [36, "id13"]], "Prediction": [[36, "prediction"], [36, "triplets-predicting"], [36, "quadruplets-predicting"]], "Prediction threshold": [[36, "prediction-threshold"]], "Scoring": [[36, "scoring"], [36, "triplets-scoring"], [36, "quadruplets-scoring"]], "ITML": [[36, "itml"]], "SDML": [[36, "sdml"]], "RCA": [[36, "rca"]], "MMC": [[36, "mmc"]], "Learning on triplets": [[36, "learning-on-triplets"]], "SCML": [[36, "scml"]], "Learning on quadruplets": [[36, "learning-on-quadruplets"]], "LSML": [[36, "lsml"]]}, "indexentries": {"constraints (class in metric_learn)": [[4, "metric_learn.Constraints"]], "__init__() (metric_learn.constraints method)": [[4, "metric_learn.Constraints.__init__"]], "chunks() (metric_learn.constraints method)": [[4, "metric_learn.Constraints.chunks"]], "generate_knntriplets() (metric_learn.constraints method)": [[4, "metric_learn.Constraints.generate_knntriplets"]], "positive_negative_pairs() (metric_learn.constraints method)": [[4, "metric_learn.Constraints.positive_negative_pairs"]], "covariance (class in metric_learn)": [[5, "metric_learn.Covariance"]], "__init__() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.__init__"]], "fit() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.fit"]], "fit_transform() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.fit_transform"]], "get_mahalanobis_matrix() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.get_metadata_routing"]], "get_metric() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.get_metric"]], "get_params() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.get_params"]], "pair_distance() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.pair_distance"]], "pair_score() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.pair_score"]], "score_pairs() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.score_pairs"]], "set_output() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.set_output"]], "set_params() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.set_params"]], "transform() (metric_learn.covariance method)": [[5, "metric_learn.Covariance.transform"]], "itml (class in metric_learn)": [[6, "metric_learn.ITML"]], "__init__() (metric_learn.itml method)": [[6, "metric_learn.ITML.__init__"]], "calibrate_threshold() (metric_learn.itml method)": [[6, "metric_learn.ITML.calibrate_threshold"]], "classes_ (metric_learn.itml attribute)": [[6, "metric_learn.ITML.classes_"]], "decision_function() (metric_learn.itml method)": [[6, "metric_learn.ITML.decision_function"]], "fit() (metric_learn.itml method)": [[6, "metric_learn.ITML.fit"]], "get_mahalanobis_matrix() (metric_learn.itml method)": [[6, "metric_learn.ITML.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.itml method)": [[6, "metric_learn.ITML.get_metadata_routing"]], "get_metric() (metric_learn.itml method)": [[6, "metric_learn.ITML.get_metric"]], "get_params() (metric_learn.itml method)": [[6, "metric_learn.ITML.get_params"]], "pair_distance() (metric_learn.itml method)": [[6, "metric_learn.ITML.pair_distance"]], "pair_score() (metric_learn.itml method)": [[6, "metric_learn.ITML.pair_score"]], "predict() (metric_learn.itml method)": [[6, "metric_learn.ITML.predict"]], "score() (metric_learn.itml method)": [[6, "metric_learn.ITML.score"]], "score_pairs() (metric_learn.itml method)": [[6, "metric_learn.ITML.score_pairs"]], "set_decision_function_request() (metric_learn.itml method)": [[6, "metric_learn.ITML.set_decision_function_request"]], "set_fit_request() (metric_learn.itml method)": [[6, "metric_learn.ITML.set_fit_request"]], "set_params() (metric_learn.itml method)": [[6, "metric_learn.ITML.set_params"]], "set_predict_request() (metric_learn.itml method)": [[6, "metric_learn.ITML.set_predict_request"]], "set_score_request() (metric_learn.itml method)": [[6, "metric_learn.ITML.set_score_request"]], "set_threshold() (metric_learn.itml method)": [[6, "metric_learn.ITML.set_threshold"]], "transform() (metric_learn.itml method)": [[6, "metric_learn.ITML.transform"]], "itml_supervised (class in metric_learn)": [[7, "metric_learn.ITML_Supervised"]], "__init__() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.__init__"]], "fit() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.fit"]], "fit_transform() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.fit_transform"]], "get_mahalanobis_matrix() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.get_metadata_routing"]], "get_metric() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.get_metric"]], "get_params() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.get_params"]], "pair_distance() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.pair_distance"]], "pair_score() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.pair_score"]], "score_pairs() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.score_pairs"]], "set_fit_request() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.set_fit_request"]], "set_output() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.set_output"]], "set_params() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.set_params"]], "transform() (metric_learn.itml_supervised method)": [[7, "metric_learn.ITML_Supervised.transform"]], "lfda (class in metric_learn)": [[8, "metric_learn.LFDA"]], "__init__() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.__init__"]], "fit() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.fit"]], "fit_transform() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.fit_transform"]], "get_mahalanobis_matrix() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.get_metadata_routing"]], "get_metric() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.get_metric"]], "get_params() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.get_params"]], "pair_distance() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.pair_distance"]], "pair_score() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.pair_score"]], "score_pairs() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.score_pairs"]], "set_output() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.set_output"]], "set_params() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.set_params"]], "transform() (metric_learn.lfda method)": [[8, "metric_learn.LFDA.transform"]], "lmnn (class in metric_learn)": [[9, "metric_learn.LMNN"]], "__init__() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.__init__"]], "fit() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.fit"]], "fit_transform() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.fit_transform"]], "get_mahalanobis_matrix() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.get_metadata_routing"]], "get_metric() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.get_metric"]], "get_params() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.get_params"]], "pair_distance() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.pair_distance"]], "pair_score() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.pair_score"]], "score_pairs() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.score_pairs"]], "set_output() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.set_output"]], "set_params() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.set_params"]], "transform() (metric_learn.lmnn method)": [[9, "metric_learn.LMNN.transform"]], "lsml (class in metric_learn)": [[10, "metric_learn.LSML"]], "__init__() (metric_learn.lsml method)": [[10, "metric_learn.LSML.__init__"]], "classes_ (metric_learn.lsml attribute)": [[10, "metric_learn.LSML.classes_"]], "decision_function() (metric_learn.lsml method)": [[10, "metric_learn.LSML.decision_function"]], "fit() (metric_learn.lsml method)": [[10, "metric_learn.LSML.fit"]], "get_mahalanobis_matrix() (metric_learn.lsml method)": [[10, "metric_learn.LSML.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.lsml method)": [[10, "metric_learn.LSML.get_metadata_routing"]], "get_metric() (metric_learn.lsml method)": [[10, "metric_learn.LSML.get_metric"]], "get_params() (metric_learn.lsml method)": [[10, "metric_learn.LSML.get_params"]], "pair_distance() (metric_learn.lsml method)": [[10, "metric_learn.LSML.pair_distance"]], "pair_score() (metric_learn.lsml method)": [[10, "metric_learn.LSML.pair_score"]], "predict() (metric_learn.lsml method)": [[10, "metric_learn.LSML.predict"]], "score() (metric_learn.lsml method)": [[10, "metric_learn.LSML.score"]], "score_pairs() (metric_learn.lsml method)": [[10, "metric_learn.LSML.score_pairs"]], "set_decision_function_request() (metric_learn.lsml method)": [[10, "metric_learn.LSML.set_decision_function_request"]], "set_fit_request() (metric_learn.lsml method)": [[10, "metric_learn.LSML.set_fit_request"]], "set_params() (metric_learn.lsml method)": [[10, "metric_learn.LSML.set_params"]], "set_predict_request() (metric_learn.lsml method)": [[10, "metric_learn.LSML.set_predict_request"]], "set_score_request() (metric_learn.lsml method)": [[10, "metric_learn.LSML.set_score_request"]], "transform() (metric_learn.lsml method)": [[10, "metric_learn.LSML.transform"]], "lsml_supervised (class in metric_learn)": [[11, "metric_learn.LSML_Supervised"]], "__init__() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.__init__"]], "fit() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.fit"]], "fit_transform() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.fit_transform"]], "get_mahalanobis_matrix() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.get_metadata_routing"]], "get_metric() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.get_metric"]], "get_params() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.get_params"]], "pair_distance() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.pair_distance"]], "pair_score() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.pair_score"]], "score_pairs() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.score_pairs"]], "set_output() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.set_output"]], "set_params() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.set_params"]], "transform() (metric_learn.lsml_supervised method)": [[11, "metric_learn.LSML_Supervised.transform"]], "mlkr (class in metric_learn)": [[12, "metric_learn.MLKR"]], "__init__() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.__init__"]], "fit() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.fit"]], "fit_transform() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.fit_transform"]], "get_mahalanobis_matrix() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.get_metadata_routing"]], "get_metric() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.get_metric"]], "get_params() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.get_params"]], "pair_distance() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.pair_distance"]], "pair_score() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.pair_score"]], "score_pairs() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.score_pairs"]], "set_output() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.set_output"]], "set_params() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.set_params"]], "transform() (metric_learn.mlkr method)": [[12, "metric_learn.MLKR.transform"]], "mmc (class in metric_learn)": [[13, "metric_learn.MMC"]], "__init__() (metric_learn.mmc method)": [[13, "metric_learn.MMC.__init__"]], "calibrate_threshold() (metric_learn.mmc method)": [[13, "metric_learn.MMC.calibrate_threshold"]], "classes_ (metric_learn.mmc attribute)": [[13, "metric_learn.MMC.classes_"]], "decision_function() (metric_learn.mmc method)": [[13, "metric_learn.MMC.decision_function"]], "fit() (metric_learn.mmc method)": [[13, "metric_learn.MMC.fit"]], "get_mahalanobis_matrix() (metric_learn.mmc method)": [[13, "metric_learn.MMC.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.mmc method)": [[13, "metric_learn.MMC.get_metadata_routing"]], "get_metric() (metric_learn.mmc method)": [[13, "metric_learn.MMC.get_metric"]], "get_params() (metric_learn.mmc method)": [[13, "metric_learn.MMC.get_params"]], "pair_distance() (metric_learn.mmc method)": [[13, "metric_learn.MMC.pair_distance"]], "pair_score() (metric_learn.mmc method)": [[13, "metric_learn.MMC.pair_score"]], "predict() (metric_learn.mmc method)": [[13, "metric_learn.MMC.predict"]], "score() (metric_learn.mmc method)": [[13, "metric_learn.MMC.score"]], "score_pairs() (metric_learn.mmc method)": [[13, "metric_learn.MMC.score_pairs"]], "set_decision_function_request() (metric_learn.mmc method)": [[13, "metric_learn.MMC.set_decision_function_request"]], "set_fit_request() (metric_learn.mmc method)": [[13, "metric_learn.MMC.set_fit_request"]], "set_params() (metric_learn.mmc method)": [[13, "metric_learn.MMC.set_params"]], "set_predict_request() (metric_learn.mmc method)": [[13, "metric_learn.MMC.set_predict_request"]], "set_score_request() (metric_learn.mmc method)": [[13, "metric_learn.MMC.set_score_request"]], "set_threshold() (metric_learn.mmc method)": [[13, "metric_learn.MMC.set_threshold"]], "transform() (metric_learn.mmc method)": [[13, "metric_learn.MMC.transform"]], "mmc_supervised (class in metric_learn)": [[14, "metric_learn.MMC_Supervised"]], "__init__() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.__init__"]], "fit() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.fit"]], "fit_transform() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.fit_transform"]], "get_mahalanobis_matrix() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.get_metadata_routing"]], "get_metric() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.get_metric"]], "get_params() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.get_params"]], "pair_distance() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.pair_distance"]], "pair_score() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.pair_score"]], "score_pairs() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.score_pairs"]], "set_output() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.set_output"]], "set_params() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.set_params"]], "transform() (metric_learn.mmc_supervised method)": [[14, "metric_learn.MMC_Supervised.transform"]], "nca (class in metric_learn)": [[15, "metric_learn.NCA"]], "__init__() (metric_learn.nca method)": [[15, "metric_learn.NCA.__init__"]], "fit() (metric_learn.nca method)": [[15, "metric_learn.NCA.fit"]], "fit_transform() (metric_learn.nca method)": [[15, "metric_learn.NCA.fit_transform"]], "get_mahalanobis_matrix() (metric_learn.nca method)": [[15, "metric_learn.NCA.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.nca method)": [[15, "metric_learn.NCA.get_metadata_routing"]], "get_metric() (metric_learn.nca method)": [[15, "metric_learn.NCA.get_metric"]], "get_params() (metric_learn.nca method)": [[15, "metric_learn.NCA.get_params"]], "pair_distance() (metric_learn.nca method)": [[15, "metric_learn.NCA.pair_distance"]], "pair_score() (metric_learn.nca method)": [[15, "metric_learn.NCA.pair_score"]], "score_pairs() (metric_learn.nca method)": [[15, "metric_learn.NCA.score_pairs"]], "set_output() (metric_learn.nca method)": [[15, "metric_learn.NCA.set_output"]], "set_params() (metric_learn.nca method)": [[15, "metric_learn.NCA.set_params"]], "transform() (metric_learn.nca method)": [[15, "metric_learn.NCA.transform"]], "rca (class in metric_learn)": [[16, "metric_learn.RCA"]], "__init__() (metric_learn.rca method)": [[16, "metric_learn.RCA.__init__"]], "fit() (metric_learn.rca method)": [[16, "metric_learn.RCA.fit"]], "fit_transform() (metric_learn.rca method)": [[16, "metric_learn.RCA.fit_transform"]], "get_mahalanobis_matrix() (metric_learn.rca method)": [[16, "metric_learn.RCA.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.rca method)": [[16, "metric_learn.RCA.get_metadata_routing"]], "get_metric() (metric_learn.rca method)": [[16, "metric_learn.RCA.get_metric"]], "get_params() (metric_learn.rca method)": [[16, "metric_learn.RCA.get_params"]], "pair_distance() (metric_learn.rca method)": [[16, "metric_learn.RCA.pair_distance"]], "pair_score() (metric_learn.rca method)": [[16, "metric_learn.RCA.pair_score"]], "score_pairs() (metric_learn.rca method)": [[16, "metric_learn.RCA.score_pairs"]], "set_fit_request() (metric_learn.rca method)": [[16, "metric_learn.RCA.set_fit_request"]], "set_output() (metric_learn.rca method)": [[16, "metric_learn.RCA.set_output"]], "set_params() (metric_learn.rca method)": [[16, "metric_learn.RCA.set_params"]], "transform() (metric_learn.rca method)": [[16, "metric_learn.RCA.transform"]], "rca_supervised (class in metric_learn)": [[17, "metric_learn.RCA_Supervised"]], "__init__() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.__init__"]], "fit() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.fit"]], "fit_transform() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.fit_transform"]], "get_mahalanobis_matrix() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.get_metadata_routing"]], "get_metric() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.get_metric"]], "get_params() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.get_params"]], "pair_distance() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.pair_distance"]], "pair_score() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.pair_score"]], "score_pairs() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.score_pairs"]], "set_fit_request() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.set_fit_request"]], "set_output() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.set_output"]], "set_params() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.set_params"]], "transform() (metric_learn.rca_supervised method)": [[17, "metric_learn.RCA_Supervised.transform"]], "scml (class in metric_learn)": [[18, "metric_learn.SCML"]], "__init__() (metric_learn.scml method)": [[18, "metric_learn.SCML.__init__"]], "classes_ (metric_learn.scml attribute)": [[18, "metric_learn.SCML.classes_"]], "decision_function() (metric_learn.scml method)": [[18, "metric_learn.SCML.decision_function"]], "fit() (metric_learn.scml method)": [[18, "metric_learn.SCML.fit"]], "get_mahalanobis_matrix() (metric_learn.scml method)": [[18, "metric_learn.SCML.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.scml method)": [[18, "metric_learn.SCML.get_metadata_routing"]], "get_metric() (metric_learn.scml method)": [[18, "metric_learn.SCML.get_metric"]], "get_params() (metric_learn.scml method)": [[18, "metric_learn.SCML.get_params"]], "pair_distance() (metric_learn.scml method)": [[18, "metric_learn.SCML.pair_distance"]], "pair_score() (metric_learn.scml method)": [[18, "metric_learn.SCML.pair_score"]], "predict() (metric_learn.scml method)": [[18, "metric_learn.SCML.predict"]], "score() (metric_learn.scml method)": [[18, "metric_learn.SCML.score"]], "score_pairs() (metric_learn.scml method)": [[18, "metric_learn.SCML.score_pairs"]], "set_decision_function_request() (metric_learn.scml method)": [[18, "metric_learn.SCML.set_decision_function_request"]], "set_fit_request() (metric_learn.scml method)": [[18, "metric_learn.SCML.set_fit_request"]], "set_params() (metric_learn.scml method)": [[18, "metric_learn.SCML.set_params"]], "set_predict_request() (metric_learn.scml method)": [[18, "metric_learn.SCML.set_predict_request"]], "set_score_request() (metric_learn.scml method)": [[18, "metric_learn.SCML.set_score_request"]], "transform() (metric_learn.scml method)": [[18, "metric_learn.SCML.transform"]], "scml_supervised (class in metric_learn)": [[19, "metric_learn.SCML_Supervised"]], "__init__() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.__init__"]], "fit() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.fit"]], "fit_transform() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.fit_transform"]], "get_mahalanobis_matrix() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.get_metadata_routing"]], "get_metric() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.get_metric"]], "get_params() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.get_params"]], "pair_distance() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.pair_distance"]], "pair_score() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.pair_score"]], "score_pairs() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.score_pairs"]], "set_output() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.set_output"]], "set_params() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.set_params"]], "transform() (metric_learn.scml_supervised method)": [[19, "metric_learn.SCML_Supervised.transform"]], "sdml (class in metric_learn)": [[20, "metric_learn.SDML"]], "__init__() (metric_learn.sdml method)": [[20, "metric_learn.SDML.__init__"]], "calibrate_threshold() (metric_learn.sdml method)": [[20, "metric_learn.SDML.calibrate_threshold"]], "classes_ (metric_learn.sdml attribute)": [[20, "metric_learn.SDML.classes_"]], "decision_function() (metric_learn.sdml method)": [[20, "metric_learn.SDML.decision_function"]], "fit() (metric_learn.sdml method)": [[20, "metric_learn.SDML.fit"]], "get_mahalanobis_matrix() (metric_learn.sdml method)": [[20, "metric_learn.SDML.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.sdml method)": [[20, "metric_learn.SDML.get_metadata_routing"]], "get_metric() (metric_learn.sdml method)": [[20, "metric_learn.SDML.get_metric"]], "get_params() (metric_learn.sdml method)": [[20, "metric_learn.SDML.get_params"]], "pair_distance() (metric_learn.sdml method)": [[20, "metric_learn.SDML.pair_distance"]], "pair_score() (metric_learn.sdml method)": [[20, "metric_learn.SDML.pair_score"]], "predict() (metric_learn.sdml method)": [[20, "metric_learn.SDML.predict"]], "score() (metric_learn.sdml method)": [[20, "metric_learn.SDML.score"]], "score_pairs() (metric_learn.sdml method)": [[20, "metric_learn.SDML.score_pairs"]], "set_decision_function_request() (metric_learn.sdml method)": [[20, "metric_learn.SDML.set_decision_function_request"]], "set_fit_request() (metric_learn.sdml method)": [[20, "metric_learn.SDML.set_fit_request"]], "set_params() (metric_learn.sdml method)": [[20, "metric_learn.SDML.set_params"]], "set_predict_request() (metric_learn.sdml method)": [[20, "metric_learn.SDML.set_predict_request"]], "set_score_request() (metric_learn.sdml method)": [[20, "metric_learn.SDML.set_score_request"]], "set_threshold() (metric_learn.sdml method)": [[20, "metric_learn.SDML.set_threshold"]], "transform() (metric_learn.sdml method)": [[20, "metric_learn.SDML.transform"]], "sdml_supervised (class in metric_learn)": [[21, "metric_learn.SDML_Supervised"]], "__init__() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.__init__"]], "fit() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.fit"]], "fit_transform() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.fit_transform"]], "get_mahalanobis_matrix() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.get_metadata_routing"]], "get_metric() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.get_metric"]], "get_params() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.get_params"]], "pair_distance() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.pair_distance"]], "pair_score() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.pair_score"]], "score_pairs() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.score_pairs"]], "set_output() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.set_output"]], "set_params() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.set_params"]], "transform() (metric_learn.sdml_supervised method)": [[21, "metric_learn.SDML_Supervised.transform"]], "basemetriclearner (class in metric_learn.base_metric)": [[22, "metric_learn.base_metric.BaseMetricLearner"]], "__init__() (metric_learn.base_metric.basemetriclearner method)": [[22, "metric_learn.base_metric.BaseMetricLearner.__init__"]], "get_metadata_routing() (metric_learn.base_metric.basemetriclearner method)": [[22, "metric_learn.base_metric.BaseMetricLearner.get_metadata_routing"]], "get_metric() (metric_learn.base_metric.basemetriclearner method)": [[22, "metric_learn.base_metric.BaseMetricLearner.get_metric"]], "get_params() (metric_learn.base_metric.basemetriclearner method)": [[22, "metric_learn.base_metric.BaseMetricLearner.get_params"]], "pair_distance() (metric_learn.base_metric.basemetriclearner method)": [[22, "metric_learn.base_metric.BaseMetricLearner.pair_distance"]], "pair_score() (metric_learn.base_metric.basemetriclearner method)": [[22, "metric_learn.base_metric.BaseMetricLearner.pair_score"]], "score_pairs() (metric_learn.base_metric.basemetriclearner method)": [[22, "metric_learn.base_metric.BaseMetricLearner.score_pairs"]], "set_params() (metric_learn.base_metric.basemetriclearner method)": [[22, "metric_learn.base_metric.BaseMetricLearner.set_params"]], "mahalanobismixin (class in metric_learn.base_metric)": [[23, "metric_learn.base_metric.MahalanobisMixin"]], "__init__() (metric_learn.base_metric.mahalanobismixin method)": [[23, "metric_learn.base_metric.MahalanobisMixin.__init__"]], "get_mahalanobis_matrix() (metric_learn.base_metric.mahalanobismixin method)": [[23, "metric_learn.base_metric.MahalanobisMixin.get_mahalanobis_matrix"]], "get_metadata_routing() (metric_learn.base_metric.mahalanobismixin method)": [[23, "metric_learn.base_metric.MahalanobisMixin.get_metadata_routing"]], "get_metric() (metric_learn.base_metric.mahalanobismixin method)": [[23, "metric_learn.base_metric.MahalanobisMixin.get_metric"]], "get_params() (metric_learn.base_metric.mahalanobismixin method)": [[23, "metric_learn.base_metric.MahalanobisMixin.get_params"]], "pair_distance() (metric_learn.base_metric.mahalanobismixin method)": [[23, "metric_learn.base_metric.MahalanobisMixin.pair_distance"]], "pair_score() (metric_learn.base_metric.mahalanobismixin method)": [[23, "metric_learn.base_metric.MahalanobisMixin.pair_score"]], "score_pairs() (metric_learn.base_metric.mahalanobismixin method)": [[23, "metric_learn.base_metric.MahalanobisMixin.score_pairs"]], "set_params() (metric_learn.base_metric.mahalanobismixin method)": [[23, "metric_learn.base_metric.MahalanobisMixin.set_params"]], "transform() (metric_learn.base_metric.mahalanobismixin method)": [[23, "metric_learn.base_metric.MahalanobisMixin.transform"]], "metrictransformer (class in metric_learn.base_metric)": [[24, "metric_learn.base_metric.MetricTransformer"]], "transform() (metric_learn.base_metric.metrictransformer method)": [[24, "metric_learn.base_metric.MetricTransformer.transform"]], "_pairsclassifiermixin (class in metric_learn.base_metric)": [[25, "metric_learn.base_metric._PairsClassifierMixin"]], "__init__() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.__init__"]], "calibrate_threshold() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.calibrate_threshold"]], "classes_ (metric_learn.base_metric._pairsclassifiermixin attribute)": [[25, "metric_learn.base_metric._PairsClassifierMixin.classes_"]], "decision_function() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.decision_function"]], "get_metadata_routing() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.get_metadata_routing"]], "get_metric() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.get_metric"]], "get_params() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.get_params"]], "pair_distance() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.pair_distance"]], "pair_score() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.pair_score"]], "predict() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.predict"]], "score() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.score"]], "score_pairs() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.score_pairs"]], "set_decision_function_request() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.set_decision_function_request"]], "set_params() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.set_params"]], "set_predict_request() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.set_predict_request"]], "set_score_request() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.set_score_request"]], "set_threshold() (metric_learn.base_metric._pairsclassifiermixin method)": [[25, "metric_learn.base_metric._PairsClassifierMixin.set_threshold"]], "_quadrupletsclassifiermixin (class in metric_learn.base_metric)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin"]], "__init__() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.__init__"]], "classes_ (metric_learn.base_metric._quadrupletsclassifiermixin attribute)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.classes_"]], "decision_function() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.decision_function"]], "get_metadata_routing() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.get_metadata_routing"]], "get_metric() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.get_metric"]], "get_params() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.get_params"]], "pair_distance() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.pair_distance"]], "pair_score() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.pair_score"]], "predict() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.predict"]], "score() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.score"]], "score_pairs() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.score_pairs"]], "set_decision_function_request() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.set_decision_function_request"]], "set_params() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.set_params"]], "set_predict_request() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.set_predict_request"]], "set_score_request() (metric_learn.base_metric._quadrupletsclassifiermixin method)": [[26, "metric_learn.base_metric._QuadrupletsClassifierMixin.set_score_request"]], "_tripletsclassifiermixin (class in metric_learn.base_metric)": [[27, "metric_learn.base_metric._TripletsClassifierMixin"]], "__init__() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.__init__"]], "classes_ (metric_learn.base_metric._tripletsclassifiermixin attribute)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.classes_"]], "decision_function() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.decision_function"]], "get_metadata_routing() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.get_metadata_routing"]], "get_metric() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.get_metric"]], "get_params() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.get_params"]], "pair_distance() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.pair_distance"]], "pair_score() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.pair_score"]], "predict() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.predict"]], "score() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.score"]], "score_pairs() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.score_pairs"]], "set_decision_function_request() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.set_decision_function_request"]], "set_params() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.set_params"]], "set_predict_request() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.set_predict_request"]], "set_score_request() (metric_learn.base_metric._tripletsclassifiermixin method)": [[27, "metric_learn.base_metric._TripletsClassifierMixin.set_score_request"]]}}) \ No newline at end of file diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 8d95aa1e..00000000 --- a/setup.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[bdist_wheel] -universal = 1 - -[metadata] -description-file = README.rst \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100755 index 1dcf10a1..00000000 --- a/setup.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from setuptools import setup - -version = "0.1.0" -setup(name='metric-learn', - version=version, - description='Python implementations of metric learning algorithms', - author=['CJ Carey', 'Yuan Tang'], - author_email='ccarey@cs.umass.edu', - url='http://github.com/all-umass/metric-learn', - license='MIT', - classifiers=[ - 'Development Status :: 4 - Beta', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python', - 'Operating System :: OS Independent', - 'Intended Audience :: Science/Research', - 'Topic :: Scientific/Engineering' - ], - packages=['metric_learn'], - install_requires=[ - 'numpy', - 'scipy', - 'scikit-learn' - ], - extras_require=dict( - docs=['sphinx', 'numpydoc'], - demo=['matplotlib'], - ), - test_suite='test', - keywords=[ - 'Metric Learning', - 'Large Margin Nearest Neighbor', - 'Information Theoretic Metric Learning', - 'Sparse Determinant Metric Learning', - 'Least Squares Metric Learning', - 'Neighborhood Components Analysis' - ]) diff --git a/supervised.html b/supervised.html new file mode 100644 index 00000000..61913b4d --- /dev/null +++ b/supervised.html @@ -0,0 +1,496 @@ + + + + + + + 2. Supervised Metric Learning — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

2. Supervised Metric Learning

+

Supervised metric learning algorithms take as inputs points X and target +labels y, and learn a distance matrix that make points from the same class +(for classification) or with close target value (for regression) close to each +other, and points from different classes or with distant target values far away +from each other.

+
+

2.1. General API

+

Supervised metric learning algorithms essentially use the same API as +scikit-learn.

+
+

2.1.1. Input data

+

In order to train a model, you need two array-like objects, X and y. X +should be a 2D array-like of shape (n_samples, n_features), where +n_samples is the number of points of your dataset and n_features is the +number of attributes describing each point. y should be a 1D +array-like +of shape (n_samples,), containing for each point in X the class it +belongs to (or the value to regress for this sample, if you use MLKR for +instance).

+

Here is an example of a dataset of two dogs and one +cat (the classes are ‘dog’ and ‘cat’) an animal being represented by +two numbers.

+
>>> import numpy as np
+>>> X = np.array([[2.3, 3.6], [0.2, 0.5], [6.7, 2.1]])
+>>> y = np.array(['dog', 'cat', 'dog'])
+
+
+
+

Note

+

You can also use a preprocessor instead of directly giving the inputs as +2D arrays. See the Preprocessor section for more details.

+
+
+
+

2.1.2. Fit, transform, and so on

+

The goal of supervised metric-learning algorithms is to transform +points in a new space, in which the distance between two points from the +same class will be small, and the distance between two points from different +classes will be large. To do so, we fit the metric learner (example: +NCA).

+
>>> from metric_learn import NCA
+>>> nca = NCA(random_state=42)
+>>> nca.fit(X, y)
+NCA(init='auto', max_iter=100, n_components=None,
+  preprocessor=None, random_state=42, tol=None, verbose=False)
+
+
+

Now that the estimator is fitted, you can use it on new data for several +purposes.

+

First, you can transform the data in the learned space, using transform: +Here we transform two points in the new embedding space.

+
>>> X_new = np.array([[9.4, 4.1], [2.1, 4.4]])
+>>> nca.transform(X_new)
+array([[ 5.91884732, 10.25406973],
+       [ 3.1545886 ,  6.80350083]])
+
+
+

Also, as explained before, our metric learners has learn a distance between +points. You can use this distance in two main ways:

+
    +
  • You can either return the distance between pairs of points using the +pair_distance function:

  • +
+
>>> nca.pair_distance([[[3.5, 3.6], [5.6, 2.4]], [[1.2, 4.2], [2.1, 6.4]], [[3.3, 7.8], [10.9, 0.1]]])
+array([0.49627072, 3.65287282, 6.06079877])
+
+
+
    +
  • Or you can return a function that will return the distance (in the new +space) between two 1D arrays (the coordinates of the points in the original +space), similarly to distance functions in scipy.spatial.distance.

  • +
+
>>> metric_fun = nca.get_metric()
+>>> metric_fun([3.5, 3.6], [5.6, 2.4])
+0.4962707194621285
+
+
+
    +
  • Alternatively, you can use pair_score to return the score between +pairs of points (the larger the score, the more similar the pair). +For Mahalanobis learners, it is equal to the opposite of the distance.

  • +
+
>>> score = nca.pair_score([[[3.5, 3.6], [5.6, 2.4]], [[1.2, 4.2], [2.1, 6.4]], [[3.3, 7.8], [10.9, 0.1]]])
+>>> score
+array([-0.49627072, -3.65287282, -6.06079877])
+
+
+

This is useful because pair_score matches the score semantic of +scikit-learn’s Classification metrics.

+
+

Note

+

If the metric learner that you use learns a Mahalanobis distance (like it is the case for all algorithms +currently in metric-learn), you can get the plain learned Mahalanobis +matrix using get_mahalanobis_matrix.

+
>>> nca.get_mahalanobis_matrix()
+array([[0.43680409, 0.89169412],
+       [0.89169412, 1.9542479 ]])
+
+
+
+
+
+

2.1.3. Scikit-learn compatibility

+

All supervised algorithms are scikit-learn estimators +(sklearn.base.BaseEstimator) and transformers +(sklearn.base.TransformerMixin) so they are compatible with pipelines +(sklearn.pipeline.Pipeline) and +scikit-learn model selection routines +(sklearn.model_selection.cross_val_score, +sklearn.model_selection.GridSearchCV, etc). +You can also use some of the scoring functions from sklearn.metrics.

+
+
+
+

2.2. Algorithms

+
+

2.2.1. LMNN

+

Large Margin Nearest Neighbor Metric Learning +(LMNN)

+

LMNN learns a Mahalanobis distance metric in the kNN classification +setting. The learned metric attempts to keep close k-nearest neighbors +from the same class, while keeping examples from different classes +separated by a large margin. This algorithm makes no assumptions about +the distribution of the data.

+

The distance is learned by solving the following optimization problem:

+
+\[\min_\mathbf{L}\sum_{i, j}\eta_{ij}||\mathbf{L(x_i-x_j)}||^2 + +c\sum_{i, j, l}\eta_{ij}(1-y_{ij})[1+||\mathbf{L(x_i-x_j)}||^2-|| +\mathbf{L(x_i-x_l)}||^2]_+)\]
+

where \(\mathbf{x}_i\) is a data point, \(\mathbf{x}_j\) is one +of its k-nearest neighbors sharing the same label, and \(\mathbf{x}_l\) +are all the other instances within that region with different labels, +\(\eta_{ij}, y_{ij} \in \{0, 1\}\) are both the indicators, +\(\eta_{ij}\) represents \(\mathbf{x}_{j}\) is the k-nearest +neighbors (with same labels) of \(\mathbf{x}_{i}\), \(y_{ij}=0\) +indicates \(\mathbf{x}_{i}, \mathbf{x}_{j}\) belong to different classes, +\([\cdot]_+=\max(0, \cdot)\) is the Hinge loss.

+

Example Code

+
import numpy as np
+from metric_learn import LMNN
+from sklearn.datasets import load_iris
+
+iris_data = load_iris()
+X = iris_data['data']
+Y = iris_data['target']
+
+lmnn = LMNN(n_neighbors=5, learn_rate=1e-6)
+lmnn.fit(X, Y, verbose=False)
+
+
+

References

+ +
+
+

2.2.2. NCA

+

Neighborhood Components Analysis (NCA)

+

NCA is a distance metric learning algorithm which aims to improve the +accuracy of nearest neighbors classification compared to the standard +Euclidean distance. The algorithm directly maximizes a stochastic variant +of the leave-one-out k-nearest neighbors (KNN) score on the training set. +It can also learn a low-dimensional linear transformation of data that can +be used for data visualization and fast classification.

+

They use the decomposition \(\mathbf{M} = \mathbf{L}^T\mathbf{L}\) and +define the probability \(p_{ij}\) that \(\mathbf{x}_i\) is the +neighbor of \(\mathbf{x}_j\) by calculating the softmax likelihood of +the Mahalanobis distance:

+
+\[p_{ij} = \frac{\exp(-|| \mathbf{Lx}_i - \mathbf{Lx}_j ||_2^2)} +{\sum_{l\neq i}\exp(-||\mathbf{Lx}_i - \mathbf{Lx}_l||_2^2)}, +\qquad p_{ii}=0\]
+

Then the probability that \(\mathbf{x}_i\) will be correctly classified +by the stochastic nearest neighbors rule is:

+
+\[p_{i} = \sum_{j:j\neq i, y_j=y_i}p_{ij}\]
+

The optimization problem is to find matrix \(\mathbf{L}\) that maximizes +the sum of probability of being correctly classified:

+
+\[\mathbf{L} = \text{argmax}\sum_i p_i\]
+

Example Code

+
import numpy as np
+from metric_learn import NCA
+from sklearn.datasets import load_iris
+
+iris_data = load_iris()
+X = iris_data['data']
+Y = iris_data['target']
+
+nca = NCA(max_iter=1000)
+nca.fit(X, Y)
+
+
+

References

+ +
+
+

2.2.3. LFDA

+

Local Fisher Discriminant Analysis (LFDA)

+

LFDA is a linear supervised dimensionality reduction method which effectively combines the ideas of Linear Discriminant Analysis <https://en.wikipedia.org/wiki/Linear_discriminant_analysis> and Locality-Preserving Projection . It is +particularly useful when dealing with multi-modality, where one ore more classes +consist of separate clusters in input space. The core optimization problem of +LFDA is solved as a generalized eigenvalue problem.

+

The algorithm define the Fisher local within-/between-class scatter matrix +\(\mathbf{S}^{(w)}/ \mathbf{S}^{(b)}\) in a pairwise fashion:

+
+\[\begin{split}\mathbf{S}^{(w)} = \frac{1}{2}\sum_{i,j=1}^nW_{ij}^{(w)}(\mathbf{x}_i - +\mathbf{x}_j)(\mathbf{x}_i - \mathbf{x}_j)^T,\\ +\mathbf{S}^{(b)} = \frac{1}{2}\sum_{i,j=1}^nW_{ij}^{(b)}(\mathbf{x}_i - +\mathbf{x}_j)(\mathbf{x}_i - \mathbf{x}_j)^T,\\\end{split}\]
+

where

+
+\[\begin{split}W_{ij}^{(w)} = \left\{\begin{aligned}0 \qquad y_i\neq y_j \\ +\,\,\mathbf{A}_{i,j}/n_l \qquad y_i = y_j\end{aligned}\right.\\ +W_{ij}^{(b)} = \left\{\begin{aligned}1/n \qquad y_i\neq y_j \\ +\,\,\mathbf{A}_{i,j}(1/n-1/n_l) \qquad y_i = y_j\end{aligned}\right.\\\end{split}\]
+

here \(\mathbf{A}_{i,j}\) is the \((i,j)\)-th entry of the affinity +matrix \(\mathbf{A}\):, which can be calculated with local scaling methods, n and n_l are the total number of points and the number of points per cluster l respectively.

+

Then the learning problem becomes derive the LFDA transformation matrix +\(\mathbf{L}_{LFDA}\):

+
+\[\mathbf{L}_{LFDA} = \arg\max_\mathbf{L} +[\text{tr}((\mathbf{L}^T\mathbf{S}^{(w)} +\mathbf{L})^{-1}\mathbf{L}^T\mathbf{S}^{(b)}\mathbf{L})]\]
+

That is, it is looking for a transformation matrix \(\mathbf{L}\) such that +nearby data pairs in the same class are made close and the data pairs in +different classes are separated from each other; far apart data pairs in the +same class are not imposed to be close.

+

Example Code

+
import numpy as np
+from metric_learn import LFDA
+from sklearn.datasets import load_iris
+
+iris_data = load_iris()
+X = iris_data['data']
+Y = iris_data['target']
+
+lfda = LFDA(k=2, dim=2)
+lfda.fit(X, Y)
+
+
+
+

Note

+

LDFA suffers from a problem called “sign indeterminacy”, which means the sign of the components and the output from transform depend on a random state. This is directly related to the calculation of eigenvectors in the algorithm. The same input ran in different times might lead to different transforms, but both valid.

+

To work around this, fit instances of this class to data once, then keep the instance around to do transformations.

+
+

References

+ +
+
+

2.2.4. MLKR

+

Metric Learning for Kernel Regression (MLKR)

+

MLKR is an algorithm for supervised metric learning, which learns a +distance function by directly minimizing the leave-one-out regression error. +This algorithm can also be viewed as a supervised variation of PCA and can be +used for dimensionality reduction and high dimensional data visualization.

+

Theoretically, MLKR can be applied with many types of kernel functions and +distance metrics, we hereafter focus the exposition on a particular instance +of the Gaussian kernel and Mahalanobis metric, as these are used in our +empirical development. The Gaussian kernel is denoted as:

+
+\[k_{ij} = \frac{1}{\sqrt{2\pi}\sigma}\exp(-\frac{d(\mathbf{x}_i, +\mathbf{x}_j)}{\sigma^2})\]
+

where \(d(\cdot, \cdot)\) is the squared distance under some metrics, +here in the fashion of Mahalanobis, it should be \(d(\mathbf{x}_i, +\mathbf{x}_j) = ||\mathbf{L}(\mathbf{x}_i - \mathbf{x}_j)||\), the transition +matrix \(\mathbf{L}\) is derived from the decomposition of Mahalanobis +matrix \(\mathbf{M=L^TL}\).

+

Since \(\sigma^2\) can be integrated into \(d(\cdot)\), we can set +\(\sigma^2=1\) for the sake of simplicity. Here we use the cumulative +leave-one-out quadratic regression error of the training samples as the +loss function:

+
+\[\mathcal{L} = \sum_i(y_i - \hat{y}_i)^2\]
+

where the prediction \(\hat{y}_i\) is derived from kernel regression by +calculating a weighted average of all the training samples:

+
+\[\hat{y}_i = \frac{\sum_{j\neq i}y_jk_{ij}}{\sum_{j\neq i}k_{ij}}\]
+

Example Code

+
from metric_learn import MLKR
+from sklearn.datasets import load_iris
+
+iris_data = load_iris()
+X = iris_data['data']
+Y = iris_data['target']
+
+mlkr = MLKR()
+mlkr.fit(X, Y)
+
+
+

References

+
+

[1]. Weinberger et al. Metric Learning for Kernel Regression. AISTATS 2007.

+
+
+
+

2.2.5. Supervised versions of weakly-supervised algorithms

+

Each weakly-supervised algorithm +has a supervised version of the form *_Supervised where similarity tuples are +randomly generated from the labels information and passed to the underlying +algorithm.

+
+

Warning

+

Supervised versions of weakly-supervised algorithms interpret label -1 +(or any negative label) as a point with unknown label. +Those points are discarded in the learning process.

+
+

For pairs learners (see Learning on pairs), pairs (tuple of two points +from the dataset), and pair labels (int indicating whether the two points +are similar (+1) or dissimilar (-1)), are sampled with the function +metric_learn.constraints.positive_negative_pairs. To sample positive pairs +(of label +1), this method will look at all the samples from the same label and +sample randomly a pair among them. To sample negative pairs (of label -1), this +method will look at all the samples from a different class and sample randomly +a pair among them. The method will try to build n_constraints positive +pairs and n_constraints negative pairs, but sometimes it cannot find enough +of one of those, so forcing same_length=True will return both times the +minimum of the two lenghts.

+

For using quadruplets learners (see Learning on quadruplets) in a +supervised way, positive and negative pairs are sampled as above and +concatenated so that we have a 3D array of +quadruplets, where for each quadruplet the two first points are from the same +class, and the two last points are from a different class (so indeed the two +last points should be less similar than the two first points).

+

Example Code

+
from metric_learn import MMC_Supervised
+from sklearn.datasets import load_iris
+
+iris_data = load_iris()
+X = iris_data['data']
+Y = iris_data['target']
+
+mmc = MMC_Supervised(n_constraints=200)
+mmc.fit(X, Y)
+
+
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/test/__init__.py b/test/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/test/metric_learn_test.py b/test/metric_learn_test.py deleted file mode 100644 index f4ca82c2..00000000 --- a/test/metric_learn_test.py +++ /dev/null @@ -1,118 +0,0 @@ -import unittest -import numpy as np -import scipy.sparse -from sklearn.metrics import pairwise_distances -from sklearn.datasets import load_iris -from numpy.testing import assert_array_almost_equal - -from metric_learn import LSML, ITML, LMNN, SDML, NCA, LFDA, RCA -# Import this specially for testing. -from metric_learn.lmnn import python_LMNN - - -def class_separation(X, labels): - unique_labels, label_inds = np.unique(labels, return_inverse=True) - ratio = 0 - for li in xrange(len(unique_labels)): - Xc = X[label_inds==li] - Xnc = X[label_inds!=li] - ratio += pairwise_distances(Xc).mean() / pairwise_distances(Xc,Xnc).mean() - return ratio / len(unique_labels) - - -class MetricTestCase(unittest.TestCase): - @classmethod - def setUpClass(self): - # runs once per test class - iris_data = load_iris() - self.iris_points = iris_data['data'] - self.iris_labels = iris_data['target'] - np.random.seed(1234) - - -class TestLSML(MetricTestCase): - def test_iris(self): - num_constraints = 200 - - C = LSML.prepare_constraints(self.iris_labels, num_constraints) - lsml = LSML().fit(self.iris_points, C, verbose=False) - - csep = class_separation(lsml.transform(), self.iris_labels) - self.assertLess(csep, 0.8) # it's pretty terrible - - -class TestITML(MetricTestCase): - def test_iris(self): - num_constraints = 200 - - n = self.iris_points.shape[0] - C = ITML.prepare_constraints(self.iris_labels, n, num_constraints) - itml = ITML().fit(self.iris_points, C, verbose=False) - - csep = class_separation(itml.transform(), self.iris_labels) - self.assertLess(csep, 0.4) # it's not great - - -class TestLMNN(MetricTestCase): - def test_iris(self): - k = 5 - - # Test both impls, if available. - for LMNN_cls in set((LMNN, python_LMNN)): - lmnn = LMNN_cls(k=k, learn_rate=1e-6) - lmnn.fit(self.iris_points, self.iris_labels, verbose=False) - - csep = class_separation(lmnn.transform(), self.iris_labels) - self.assertLess(csep, 0.25) - - -class TestSDML(MetricTestCase): - def test_iris(self): - num_constraints = 1500 - - n = self.iris_points.shape[0] - np.random.seed(1234) - W = SDML.prepare_constraints(self.iris_labels, n, num_constraints) - - # Test sparse graph inputs. - for graph in ((W, scipy.sparse.csr_matrix(W))): - sdml = SDML().fit(self.iris_points, graph) - csep = class_separation(sdml.transform(), self.iris_labels) - self.assertLess(csep, 0.25) - - -class TestNCA(MetricTestCase): - def test_iris(self): - n = self.iris_points.shape[0] - nca = NCA(max_iter=(100000//n), learning_rate=0.01) - nca.fit(self.iris_points, self.iris_labels) - - # Result copied from Iris example at - # https://github.com/vomjom/nca/blob/master/README.mkd - expected = [[-0.09935, -0.2215, 0.3383, 0.443], - [+0.2532, 0.5835, -0.8461, -0.8915], - [-0.729, -0.6386, 1.767, 1.832], - [-0.9405, -0.8461, 2.281, 2.794]] - assert_array_almost_equal(expected, nca.transformer(), decimal=3) - - -class TestLFDA(MetricTestCase): - def test_iris(self): - lfda = LFDA(k=2, dim=2) - lfda.fit(self.iris_points, self.iris_labels) - csep = class_separation(lfda.transform(), self.iris_labels) - self.assertLess(csep, 0.15) - - -class TestRCA(MetricTestCase): - def test_iris(self): - rca = RCA(dim=2) - chunks = RCA.prepare_constraints(self.iris_labels, num_chunks=30, - chunk_size=2, seed=1234) - rca.fit(self.iris_points, chunks) - csep = class_separation(rca.transform(), self.iris_labels) - self.assertLess(csep, 0.25) - - -if __name__ == '__main__': - unittest.main() diff --git a/unsupervised.html b/unsupervised.html new file mode 100644 index 00000000..102fd54b --- /dev/null +++ b/unsupervised.html @@ -0,0 +1,167 @@ + + + + + + + 4. Unsupervised Metric Learning — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

4. Unsupervised Metric Learning

+

Unsupervised metric learning algorithms only take as input an (unlabeled) +dataset X. For now, in metric-learn, there only is Covariance, which is a +simple baseline algorithm (see below).

+
+

4.1. Algorithms

+
+

4.1.1. Covariance

+

Covariance does not “learn” anything, rather it calculates +the covariance matrix of the input data. This is a simple baseline method. +It can be used for ZCA whitening of the data (see the Wikipedia page of +whitening transformation).

+

Example Code

+
from metric_learn import Covariance
+from sklearn.datasets import load_iris
+
+iris = load_iris()['data']
+
+cov = Covariance().fit(iris)
+x = cov.transform(iris)
+
+
+

References

+
+

[1]. On the Generalized Distance in Statistics, P.C.Mahalanobis, 1936.

+
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/user_guide.html b/user_guide.html new file mode 100644 index 00000000..b228c3cf --- /dev/null +++ b/user_guide.html @@ -0,0 +1,224 @@ + + + + + + + User guide: contents — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+ +
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/weakly_supervised.html b/weakly_supervised.html new file mode 100644 index 00000000..b0c1f00e --- /dev/null +++ b/weakly_supervised.html @@ -0,0 +1,982 @@ + + + + + + + 3. Weakly Supervised Metric Learning — metric-learn 0.7.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

3. Weakly Supervised Metric Learning

+

Weakly supervised algorithms work on weaker information about the data points +than supervised algorithms. Rather than labeled points, they take as input +similarity judgments on tuples of data points, for instance pairs of similar +and dissimilar points. Refer to the documentation of each algorithm for its +particular form of input data.

+
+

3.1. General API

+
+

3.1.1. Input data

+

In the following paragraph we talk about tuples for sake of generality. These +can be pairs, triplets, quadruplets etc, depending on the particular metric +learning algorithm we use.

+
+

3.1.1.1. Basic form

+

Every weakly supervised algorithm will take as input tuples of +points, and if needed labels for theses tuples. The tuples of points can +also be called “constraints”. They are a set of points that we consider (ex: +two points, three points, etc…). The label is some information we have +about this set of points (e.g. “these two points are similar”). Note that +some information can be contained in the ordering of these tuples (see for +instance the section Learning on quadruplets). For more details about +specific forms of tuples, refer to the appropriate sections +(Learning on pairs or Learning on quadruplets).

+

The tuples argument is the first argument of every method (like the X +argument for classical algorithms in scikit-learn). The second argument is the +label of the tuple: its semantic depends on the algorithm used. For instance +for pairs learners y is a label indicating whether the pair is of similar +samples or dissimilar samples.

+

Then one can fit a Weakly Supervised Metric Learner on this tuple, like this:

+
>>> my_algo.fit(tuples, y)
+
+
+

Like in a classical setting we split the points X between train and test, +here we split the tuples between train and test.

+
>>> from sklearn.model_selection import train_test_split
+>>> pairs_train, pairs_test, y_train, y_test = train_test_split(pairs, y)
+
+
+

These are two data structures that can be used to represent tuple in metric +learn:

+
+
+

3.1.1.2. 3D array of tuples

+

The most intuitive way to represent tuples is to provide the algorithm with a +3D array-like of tuples of shape (n_tuples, tuple_size, n_features), where +n_tuples is the number of tuples, tuple_size is the number of elements +in a tuple (2 for pairs, 3 for triplets for instance), and n_features is +the number of features of each point.

+

Example Code

+

Here is an artificial dataset of 4 pairs of 2 points of 3 features each:

+
>>> import numpy as np
+>>> tuples = np.array([[[-0.12, -1.21, -0.20],
+>>>                     [+0.05, -0.19, -0.05]],
+>>>
+>>>                    [[-2.16, +0.11, -0.02],
+>>>                     [+1.58, +0.16, +0.93]],
+>>>
+>>>                    [[+1.58, +0.16, +0.93],  # same as tuples[1, 1, :]
+>>>                     [+0.89, -0.34, +2.41]],
+>>>
+>>>                    [[-0.12, -1.21, -0.20],  # same as tuples[0, 0, :]
+>>>                     [-2.16, +0.11, -0.02]]])  # same as tuples[1, 0, :]
+>>> y = np.array([-1, 1, 1, -1])
+
+
+
+

Warning

+

This way of specifying pairs is not recommended for a large number +of tuples, as it is redundant (see the comments in the example) and hence +takes a lot of memory. Indeed each feature vector of a point will be +replicated as many times as a point is involved in a tuple. The second way +to specify pairs is more efficient

+
+
+
+

3.1.1.3. 2D array of indicators + preprocessor

+

Instead of forming each point in each tuple, a more efficient representation +would be to keep the dataset of points X aside, and just represent tuples +as a collection of tuples of indices from the points in X. Since we loose +the feature dimension there, the resulting array is 2D.

+

Example Code

+

An equivalent representation of the above pairs would be:

+
>>> X = np.array([[-0.12, -1.21, -0.20],
+>>>               [+0.05, -0.19, -0.05],
+>>>               [-2.16, +0.11, -0.02],
+>>>               [+1.58, +0.16, +0.93],
+>>>               [+0.89, -0.34, +2.41]])
+>>>
+>>> tuples_indices = np.array([[0, 1],
+>>>                            [2, 3],
+>>>                            [3, 4],
+>>>                            [0, 2]])
+>>> y = np.array([-1, 1, 1, -1])
+
+
+

In order to fit metric learning algorithms with this type of input, we need to +give the original dataset of points X to the estimator so that it knows +the points the indices refer to. We do this when initializing the estimator, +through the argument preprocessor (see below Fit, transform, and so on)

+
+

Note

+

Instead of an array-like, you can give a callable in the argument +preprocessor, which will go fetch and form the tuples. This allows to +give more general indicators than just indices from an array (for instance +paths in the filesystem, name of records in a database etc…) See section +Preprocessor for more details on how to use the preprocessor.

+
+
+
+
+

3.1.2. Fit, transform, and so on

+

The goal of weakly-supervised metric-learning algorithms is to transform +points in a new space, in which the tuple-wise constraints between points +are respected.

+
>>> from metric_learn import MMC
+>>> mmc = MMC(random_state=42)
+>>> mmc.fit(tuples, y)
+MMC(A0='deprecated', tol=0.001, diagonal=False,
+  diagonal_c=1.0, init='auto', max_iter=100, max_proj=10000,
+  preprocessor=None, random_state=42, verbose=False)
+
+
+

Or alternatively (using a preprocessor):

+
>>> from metric_learn import MMC
+>>> mmc = MMC(preprocessor=X, random_state=42)
+>>> mmc.fit(pairs_indice, y)
+
+
+

Now that the estimator is fitted, you can use it on new data for several +purposes.

+

First, you can transform the data in the learned space, using transform: +Here we transform two points in the new embedding space.

+
>>> X_new = np.array([[9.4, 4.1, 4.2], [2.1, 4.4, 2.3]])
+>>> mmc.transform(X_new)
+array([[-3.24667162e+01,  4.62622348e-07,  3.88325421e-08],
+       [-3.61531114e+01,  4.86778289e-07,  2.12654397e-08]])
+
+
+

Also, as explained before, our metric learner has learned a distance between +points. You can use this distance in two main ways:

+
    +
  • You can either return the distance between pairs of points using the +pair_distance function:

  • +
+
>>> mmc.pair_distance([[[3.5, 3.6, 5.2], [5.6, 2.4, 6.7]],
+...                  [[1.2, 4.2, 7.7], [2.1, 6.4, 0.9]]])
+array([7.27607365, 0.88853014])
+
+
+
    +
  • Or you can return a function that will return the distance +(in the new space) between two 1D arrays (the coordinates of the points in +the original space), similarly to distance functions in +scipy.spatial.distance. To do that, use the get_metric method.

  • +
+
>>> metric_fun = mmc.get_metric()
+>>> metric_fun([3.5, 3.6, 5.2], [5.6, 2.4, 6.7])
+7.276073646278203
+
+
+
    +
  • Alternatively, you can use pair_score to return the score between +pairs of points (the larger the score, the more similar the pair). +For Mahalanobis learners, it is equal to the opposite of the distance.

  • +
+
>>> score = mmc.pair_score([[[3.5, 3.6], [5.6, 2.4]], [[1.2, 4.2], [2.1, 6.4]], [[3.3, 7.8], [10.9, 0.1]]])
+>>> score
+array([-0.49627072, -3.65287282, -6.06079877])
+
+
+
+

This is useful because pair_score matches the score semantic of +scikit-learn’s Classification metrics.

+
+
+

Note

+

If the metric learner that you use learns a Mahalanobis distance (like it is the case for all algorithms +currently in metric-learn), you can get the plain Mahalanobis matrix using +get_mahalanobis_matrix.

+
+
>>> mmc.get_mahalanobis_matrix()
+array([[ 0.58603894, -5.69883982, -1.66614919],
+       [-5.69883982, 55.41743549, 16.20219519],
+       [-1.66614919, 16.20219519,  4.73697721]])
+
+
+
+
+

3.1.3. Prediction and scoring

+

Since weakly supervised are also able, after being fitted, to predict for a +given tuple what is its label (for pairs) or ordering (for quadruplets). See +the appropriate section for more details, either this +one for pairs, or this one for quadruplets.

+

They also implement a default scoring method, score, that can be +used to evaluate the performance of a metric-learner on a test dataset. See +the appropriate section for more details, either this +one for pairs, or this one +for quadruplets.

+
+
+

3.1.4. Scikit-learn compatibility

+

Weakly supervised estimators are compatible with scikit-learn routines for +model selection (sklearn.model_selection.cross_val_score, +sklearn.model_selection.GridSearchCV, etc).

+

Example:

+
>>> from metric_learn import MMC
+>>> import numpy as np
+>>> from sklearn.datasets import load_iris
+>>> from sklearn.model_selection import cross_val_score
+>>> rng = np.random.RandomState(42)
+>>> X, _ = load_iris(return_X_y=True)
+>>> # let's sample 30 random pairs and labels of pairs
+>>> pairs_indices = rng.randint(X.shape[0], size=(30, 2))
+>>> y = 2 * rng.randint(2, size=30) - 1
+>>> mmc = MMC(preprocessor=X)
+>>> cross_val_score(mmc, pairs_indices, y)
+
+
+
+
+
+

3.2. Learning on pairs

+

Some metric learning algorithms learn on pairs of samples. In this case, one +should provide the algorithm with n_samples pairs of points, with a +corresponding target containing n_samples values being either +1 or -1. +These values indicate whether the given pairs are similar points or +dissimilar points.

+
+

3.2.1. Fitting

+

Here is an example for fitting on pairs (see Fit, transform, and so on for more details on +the input data format and how to fit, in the general case of learning on +tuples).

+
>>> from metric_learn import MMC
+>>> pairs = np.array([[[1.2, 3.2], [2.3, 5.5]],
+>>>                   [[4.5, 2.3], [2.1, 2.3]]])
+>>> y_pairs = np.array([1, -1])
+>>> mmc = MMC(random_state=42)
+>>> mmc.fit(pairs, y_pairs)
+MMC(tol=0.001, diagonal=False,
+    diagonal_c=1.0, init='auto', max_iter=100, max_proj=10000, preprocessor=None,
+    random_state=42, verbose=False)
+
+
+

Here, we learned a metric that puts the two first points closer +together in the transformed space, and the two next points further away from +each other.

+
+
+

3.2.2. Prediction

+

When a pairs learner is fitted, it is also able to predict, for an unseen +pair, whether it is a pair of similar or dissimilar points.

+
>>> mmc.predict([[[0.6, 1.6], [1.15, 2.75]],
+...              [[3.2, 1.1], [5.4, 6.1]]])
+array([1, -1])
+
+
+
+

3.2.2.1. Prediction threshold

+

Predicting whether a new pair represents similar or dissimilar +samples requires to set a threshold on the learned distance, so that points +closer (in the learned space) than this threshold are predicted as similar, +and points further away are predicted as dissimilar. Several methods are +possible for this thresholding.

+
    +
  • Calibration at fit time: The threshold is set with calibrate_threshold +(see below) on the training set. You can specify the calibration +parameters directly +in the fit method with the threshold_params parameter (see the +documentation of the fit method of any metric learner that learns on pairs +of points for more information). Note that calibrating on the training set +may cause some overfitting. If you want to avoid that, calibrate the +threshold after fitting, on a validation set.

    +
    >>> mmc.fit(pairs, y) # will fit the threshold automatically after fitting
    +
    +
    +
  • +
  • Calibration on validation set: calling calibrate_threshold will +calibrate the threshold to achieve a particular score on a validation set, +the score being among the classical scores for classification (accuracy, f1 +score…).

    +
    >>> mmc.calibrate_threshold(pairs, y)
    +
    +
    +
  • +
  • Manual threshold: calling set_threshold will set the threshold to a +particular value.

    +
    >>> mmc.set_threshold(0.4)
    +
    +
    +
  • +
+

See also: sklearn.calibration.

+
+
+
+

3.2.3. Scoring

+

Pair metric learners can also return a decision_function for a set of pairs. +It is basically the “score” that will be thresholded to find the prediction +for the pair. This score corresponds to the opposite of the distance in the +new space (higher score means points are similar, and lower score dissimilar).

+
>>> mmc.decision_function([[[0.6, 1.6], [1.15, 2.75]],
+...                        [[3.2, 1.1], [5.4, 6.1]]])
+array([-0.12811124, -0.74750256])
+
+
+

This allows to use common scoring functions for binary classification, like +sklearn.metrics.accuracy_score for instance, which +can be used inside cross-validation routines:

+
>>> from sklearn.model_selection import cross_val_score
+>>> pairs_test = np.array([[[0.6, 1.6], [1.15, 2.75]],
+...                        [[3.2, 1.1], [5.4, 6.1]],
+...                        [[7.7, 5.6], [1.23, 8.4]]])
+>>> y_test = np.array([-1., 1., -1.])
+>>> cross_val_score(mmc, pairs_test, y_test, scoring='accuracy')
+array([1., 0., 1.])
+
+
+

Pairs learners also have a default score, which basically +returns the sklearn.metrics.roc_auc_score (which is threshold-independent).

+
>>> pairs_test = np.array([[[0.6, 1.6], [1.15, 2.75]],
+...                        [[3.2, 1.1], [5.4, 6.1]],
+...                        [[7.7, 5.6], [1.23, 8.4]]])
+>>> y_test = np.array([1., -1., -1.])
+>>> mmc.score(pairs_test, y_test)
+1.0
+
+
+
+

Note

+

See Fit, transform, and so on for more details on metric learners functions that are +not specific to learning on pairs, like transform, pair_distance, +pair_score, get_metric and get_mahalanobis_matrix.

+
+
+
+

3.2.4. Algorithms

+
+

3.2.4.1. ITML

+

Information Theoretic Metric Learning (ITML)

+

ITML minimizes the (differential) relative entropy, aka Kullback–Leibler +divergence, between two multivariate Gaussians subject to constraints on the +associated Mahalanobis distance, which can be formulated into a Bregman +optimization problem by minimizing the LogDet divergence subject to +linear constraints. This algorithm can handle a wide variety of constraints +and can optionally incorporate a prior on the distance function. Unlike some +other methods, ITML does not rely on an eigenvalue computation or +semi-definite programming.

+

Given a Mahalanobis distance parameterized by \(M\), its corresponding +multivariate Gaussian is denoted as:

+
+\[p(\mathbf{x}; \mathbf{M}) = \frac{1}{Z}\exp(-\frac{1}{2}d_\mathbf{M} +(\mathbf{x}, \mu)) += \frac{1}{Z}\exp(-\frac{1}{2}((\mathbf{x} - \mu)^T\mathbf{M} +(\mathbf{x} - \mu))\]
+

where \(Z\) is the normalization constant, the inverse of Mahalanobis +matrix \(\mathbf{M}^{-1}\) is the covariance of the Gaussian.

+

Given pairs of similar points \(S\) and pairs of dissimilar points +\(D\), the distance metric learning problem is to minimize the LogDet +divergence, which is equivalent as minimizing \(\textbf{KL}(p(\mathbf{x}; +\mathbf{M}_0) || p(\mathbf{x}; \mathbf{M}))\):

+
+\[\begin{split}\min_\mathbf{A} D_{\ell \mathrm{d}}\left(M, M_{0}\right) = +\operatorname{tr}\left(M M_{0}^{-1}\right)-\log \operatorname{det} +\left(M M_{0}^{-1}\right)-n\\ +\text{subject to } \quad d_\mathbf{M}(\mathbf{x}_i, \mathbf{x}_j) +\leq u \qquad (\mathbf{x}_i, \mathbf{x}_j)\in S \\ +d_\mathbf{M}(\mathbf{x}_i, \mathbf{x}_j) \geq l \qquad (\mathbf{x}_i, +\mathbf{x}_j)\in D\end{split}\]
+

where \(u\) and \(l\) is the upper and the lower bound of distance +for similar and dissimilar pairs respectively, and \(\mathbf{M}_0\) +is the prior distance metric, set to identity matrix by default, +\(D_{\ell \mathrm{d}}(\cdot)\) is the log determinant.

+

Example Code

+
from metric_learn import ITML
+
+pairs = [[[1.2, 7.5], [1.3, 1.5]],
+         [[6.4, 2.6], [6.2, 9.7]],
+         [[1.3, 4.5], [3.2, 4.6]],
+         [[6.2, 5.5], [5.4, 5.4]]]
+y = [1, 1, -1, -1]
+
+# in this task we want points where the first feature is close to be closer
+# to each other, no matter how close the second feature is
+
+
+itml = ITML()
+itml.fit(pairs, y)
+
+
+

References

+
+

[1]. Jason V. Davis, et al. Information-theoretic Metric Learning. ICML 2007.

+

[2]. Adapted from Matlab code at http://www.cs.utexas.edu/users/pjain/itml/ .

+
+
+
+

3.2.4.2. SDML

+

Sparse High-Dimensional Metric Learning +(SDML)

+

SDML is an efficient sparse metric learning in high-dimensional space via +double regularization: an L1-penalization on the off-diagonal elements of the +Mahalanobis matrix \(\mathbf{M}\), and a log-determinant divergence between +\(\mathbf{M}\) and \(\mathbf{M_0}\) (set as either \(\mathbf{I}\) +or \(\mathbf{\Omega}^{-1}\), where \(\mathbf{\Omega}\) is the +covariance matrix).

+

The formulated optimization on the semidefinite matrix \(\mathbf{M}\) +is convex:

+
+\[\min_{\mathbf{M}} = \text{tr}((\mathbf{M}_0 + \eta \mathbf{XLX}^{T}) +\cdot \mathbf{M}) - \log\det \mathbf{M} + \lambda ||\mathbf{M}||_{1, off}\]
+

where \(\mathbf{X}=[\mathbf{x}_1, \mathbf{x}_2, ..., \mathbf{x}_n]\) is +the training data, the incidence matrix \(\mathbf{K}_{ij} = 1\) if +\((\mathbf{x}_i, \mathbf{x}_j)\) is a similar pair, otherwise -1. The +Laplacian matrix \(\mathbf{L}=\mathbf{D}-\mathbf{K}\) is calculated from +\(\mathbf{K}\) and \(\mathbf{D}\), a diagonal matrix whose entries are +the sums of the row elements of \(\mathbf{K}\)., \(||\cdot||_{1, off}\) +is the off-diagonal L1 norm.

+

Example Code

+
from metric_learn import SDML
+
+pairs = [[[1.2, 7.5], [1.3, 1.5]],
+         [[6.4, 2.6], [6.2, 9.7]],
+         [[1.3, 4.5], [3.2, 4.6]],
+         [[6.2, 5.5], [5.4, 5.4]]]
+y = [1, 1, -1, -1]
+
+# in this task we want points where the first feature is close to be closer
+# to each other, no matter how close the second feature is
+
+sdml = SDML()
+sdml.fit(pairs, y)
+
+
+

References

+ +
+
+

3.2.4.3. RCA

+

Relative Components Analysis (RCA)

+

RCA learns a full rank Mahalanobis distance metric based on a weighted sum of +in-chunklets covariance matrices. It applies a global linear transformation to +assign large weights to relevant dimensions and low weights to irrelevant +dimensions. Those relevant dimensions are estimated using “chunklets”, subsets +of points that are known to belong to the same class.

+

For a training set with \(n\) training points in \(k\) chunklets, the +algorithm is efficient since it simply amounts to computing

+
+\[\mathbf{C} = \frac{1}{n}\sum_{j=1}^k\sum_{i=1}^{n_j} +(\mathbf{x}_{ji}-\hat{\mathbf{m}}_j) +(\mathbf{x}_{ji}-\hat{\mathbf{m}}_j)^T\]
+

where chunklet \(j\) consists of \(\{\mathbf{x}_{ji}\}_{i=1}^{n_j}\) +with a mean \(\hat{m}_j\). The inverse of \(\mathbf{C}^{-1}\) is used +as the Mahalanobis matrix.

+

Example Code

+
from metric_learn import RCA
+
+X = [[-0.05,  3.0],[0.05, -3.0],
+    [0.1, -3.55],[-0.1, 3.55],
+    [-0.95, -0.05],[0.95, 0.05],
+    [0.4,  0.05],[-0.4, -0.05]]
+chunks = [0, 0, 1, 1, 2, 2, 3, 3]
+
+rca = RCA()
+rca.fit(X, chunks)
+
+
+

References

+
+

[1]. Shental et al. Adjustment learning and relevant component analysis. ECCV 2002.

+

[2]. Bar-Hillel et al. Learning distance functions using equivalence relations. ICML 2003.

+

[3]. Bar-Hillel et al. Learning a Mahalanobis metric from equivalence constraints. JMLR 2005.

+
+
+
+

3.2.4.4. MMC

+

Metric Learning with Application for Clustering with Side Information +(MMC)

+

MMC minimizes the sum of squared distances between similar points, while +enforcing the sum of distances between dissimilar ones to be greater than one. +This leads to a convex and, thus, local-minima-free optimization problem that +can be solved efficiently. +However, the algorithm involves the computation of eigenvalues, which is the +main speed-bottleneck. Since it has initially been designed for clustering +applications, one of the implicit assumptions of MMC is that all classes form +a compact set, i.e., follow a unimodal distribution, which restricts the +possible use-cases of this method. However, it is one of the earliest and a +still often cited technique.

+

The algorithm aims at minimizing the sum of distances between all the similar +points, while constrains the sum of distances between dissimilar points:

+
+\[\min_{\mathbf{M}\in\mathbb{S}_+^d}\sum_{(\mathbf{x}_i, +\mathbf{x}_j)\in S} d_{\mathbf{M}}(\mathbf{x}_i, \mathbf{x}_j) +\qquad \qquad \text{s.t.} \qquad \sum_{(\mathbf{x}_i, \mathbf{x}_j) +\in D} d^2_{\mathbf{M}}(\mathbf{x}_i, \mathbf{x}_j) \geq 1\]
+

Example Code

+
from metric_learn import MMC
+
+pairs = [[[1.2, 7.5], [1.3, 1.5]],
+         [[6.4, 2.6], [6.2, 9.7]],
+         [[1.3, 4.5], [3.2, 4.6]],
+         [[6.2, 5.5], [5.4, 5.4]]]
+y = [1, 1, -1, -1]
+
+# in this task we want points where the first feature is close to be closer
+# to each other, no matter how close the second feature is
+
+mmc = MMC()
+mmc.fit(pairs, y)
+
+
+

References

+ +
+
+
+
+

3.3. Learning on triplets

+

Some metric learning algorithms learn on triplets of samples. In this case, +one should provide the algorithm with n_samples triplets of points. The +semantic of each triplet is that the first point should be closer to the +second point than to the third one.

+
+

3.3.1. Fitting

+

Here is an example for fitting on triplets (see Fit, transform, and so on for more +details on the input data format and how to fit, in the general case of +learning on tuples).

+
>>> from metric_learn import SCML
+>>> triplets = np.array([[[1.2, 3.2], [2.3, 5.5], [2.1, 0.6]],
+>>>                      [[4.5, 2.3], [2.1, 2.3], [7.3, 3.4]]])
+>>> scml = SCML(random_state=42)
+>>> scml.fit(triplets)
+SCML(beta=1e-5, B=None, max_iter=100000, verbose=False,
+    preprocessor=None, random_state=None)
+
+
+

Or alternatively (using a preprocessor):

+
>>> X = np.array([[[1.2, 3.2],
+>>>                [2.3, 5.5],
+>>>                [2.1, 0.6],
+>>>                [4.5, 2.3],
+>>>                [2.1, 2.3],
+>>>                [7.3, 3.4]])
+>>> triplets_indices = np.array([[0, 1, 2], [3, 4, 5]])
+>>> scml = SCML(preprocessor=X, random_state=42)
+>>> scml.fit(triplets_indices)
+SCML(beta=1e-5, B=None, max_iter=100000, verbose=False,
+   preprocessor=array([[1.2, 3.2],
+       [2.3, 5.5],
+       [2.4, 6.7],
+       [2.1, 0.6],
+       [4.5, 2.3],
+       [2.1, 2.3],
+       [0.6, 1.2],
+       [7.3, 3.4]]),
+    random_state=None)
+
+
+

Here, we want to learn a metric that, for each of the two +triplets, will make the first point closer to the +second point than to the third one.

+
+
+

3.3.2. Prediction

+

When a triplets learner is fitted, it is also able to predict, for an +upcoming triplet, whether the first point is closer to the second point +than to the third one (+1), or not (-1).

+
>>> triplets_test = np.array(
+... [[[5.6, 5.3], [2.2, 2.1], [1.2, 3.4]],
+...  [[6.0, 4.2], [4.3, 1.2], [0.1, 7.8]]])
+>>> scml.predict(triplets_test)
+array([-1.,  1.])
+
+
+
+
+

3.3.3. Scoring

+

Triplet metric learners can also return a decision_function for a set of triplets, +which corresponds to the distance between the first two points minus the distance +between the first and last points of the triplet (the higher the value, the more +similar the first point to the second point compared to the last one). This “score” +can be interpreted as a measure of likeliness of having a +1 prediction for this +triplet.

+
>>> scml.decision_function(triplets_test)
+array([-1.75700306,  4.98982131])
+
+
+

In the above example, for the first triplet in triplets_test, the first +point is predicted less similar to the second point than to the last point +(they are further away in the transformed space).

+

Unlike pairs learners, triplets learners do not allow to give a y when fitting: we +assume that the ordering of points within triplets is such that the training triplets +are all positive. Therefore, it is not possible to use scikit-learn scoring functions +(such as ‘f1_score’) for triplets learners.

+

However, triplets learners do have a default scoring function, which will +basically return the accuracy score on a given test set, i.e. the proportion +of triplets that have the right predicted ordering.

+
>>> scml.score(triplets_test)
+0.5
+
+
+
+

Note

+

See Fit, transform, and so on for more details on metric learners functions that are +not specific to learning on pairs, like transform, pair_distance, +pair_score, get_metric and get_mahalanobis_matrix.

+
+
+
+

3.3.4. Algorithms

+
+

3.3.4.1. SCML

+

Sparse Compositional Metric Learning +(SCML)

+

SCML learns a squared Mahalanobis distance from triplet constraints by +optimizing sparse positive weights assigned to a set of \(K\) rank-one +PSD bases. This can be formulated as an optimization problem with only +\(K\) parameters, that can be solved with an efficient stochastic +composite scheme.

+

The Mahalanobis matrix \(M\) is built from a basis set \(B = \{b_i\}_{i=\{1,...,K\}}\) +weighted by a \(K\) dimensional vector \(w = \{w_i\}_{i=\{1,...,K\}}\) as:

+
+\[M = \sum_{i=1}^K w_i b_i b_i^T = B \cdot diag(w) \cdot B^T \quad w_i \geq 0\]
+

Learning \(M\) in this form makes it PSD by design, as it is a +nonnegative sum of PSD matrices. The basis set \(B\) is fixed in advance +and it is possible to construct it from the data. The optimization problem +over \(w\) is formulated as a classic margin-based hinge loss function +involving the set \(C\) of triplets. A regularization \(\ell_1\) +is added to yield a sparse combination. The formulation is the following:

+
+\[\min_{w\geq 0} \sum_{(x_i,x_j,x_k)\in C} [1 + d_w(x_i,x_j)-d_w(x_i,x_k)]_+ + \beta||w||_1\]
+

where \([\cdot]_+\) is the hinge loss.

+

Example Code

+
from metric_learn import SCML
+
+triplets = [[[1.2, 7.5], [1.3, 1.5], [6.2, 9.7]],
+            [[1.3, 4.5], [3.2, 4.6], [5.4, 5.4]],
+            [[3.2, 7.5], [3.3, 1.5], [8.2, 9.7]],
+            [[3.3, 4.5], [5.2, 4.6], [7.4, 5.4]]]
+
+scml = SCML()
+scml.fit(triplets)
+
+
+

References

+
+

[1]. Y. Shi, A. Bellet and F. Sha. Sparse Compositional Metric Learning.. (AAAI), 2014.

+

[2]. Adapted from original Matlab implementation..

+
+
+
+
+
+

3.4. Learning on quadruplets

+

Some metric learning algorithms learn on quadruplets of samples. In this case, +one should provide the algorithm with n_samples quadruplets of points. The +semantic of each quadruplet is that the first two points should be closer +together than the last two points.

+
+

3.4.1. Fitting

+

Here is an example for fitting on quadruplets (see Fit, transform, and so on for more +details on the input data format and how to fit, in the general case of +learning on tuples).

+
>>> from metric_learn import LSML
+>>> quadruplets = np.array([[[1.2, 3.2], [2.3, 5.5], [2.4, 6.7], [2.1, 0.6]],
+>>>                         [[4.5, 2.3], [2.1, 2.3], [0.6, 1.2], [7.3, 3.4]]])
+>>> lsml = LSML(random_state=42)
+>>> lsml.fit(quadruplets)
+LSML(max_iter=1000, preprocessor=None, prior=None, random_state=42, tol=0.001,
+   verbose=False)
+
+
+

Or alternatively (using a preprocessor):

+
>>> X = np.array([[1.2, 3.2],
+>>>               [2.3, 5.5],
+>>>               [2.4, 6.7],
+>>>               [2.1, 0.6],
+>>>               [4.5, 2.3],
+>>>               [2.1, 2.3],
+>>>               [0.6, 1.2],
+>>>               [7.3, 3.4]])
+>>> quadruplets_indices = np.array([[0, 1, 2, 3], [4, 5, 6, 7]])
+>>> lsml = LSML(preprocessor=X, random_state=42)
+>>> lsml.fit(quadruplets_indices)
+LSML(max_iter=1000,
+   preprocessor=array([[1.2, 3.2],
+       [2.3, 5.5],
+       [2.4, 6.7],
+       [2.1, 0.6],
+       [4.5, 2.3],
+       [2.1, 2.3],
+       [0.6, 1.2],
+       [7.3, 3.4]]),
+   prior=None, random_state=42, tol=0.001, verbose=False)
+
+
+

Here, we want to learn a metric that, for each of the two +quadruplets, will put the two first points closer together than the two +last points.

+
+
+

3.4.2. Prediction

+

When a quadruplets learner is fitted, it is also able to predict, for an +upcoming quadruplet, whether the two first points are more similar than the +two last points (+1), or not (-1).

+
>>> quadruplets_test = np.array(
+... [[[5.6, 5.3], [2.2, 2.1], [0.4, 0.6], [1.2, 3.4]],
+...  [[6.0, 4.2], [4.3, 1.2], [4.5, 0.6], [0.1, 7.8]]])
+>>> lsml.predict(quadruplets_test)
+array([-1.,  1.])
+
+
+
+
+

3.4.3. Scoring

+

Quadruplet metric learners can also return a decision_function for a set of +quadruplets, which corresponds to the distance between the first pair of points minus +the distance between the second pair of points of the triplet (the higher the value, +the more similar the first pair is than the last pair). +This “score” can be interpreted as a measure of likeliness of having a +1 prediction +for this quadruplet.

+
>>> lsml.decision_function(quadruplets_test)
+array([-1.75700306,  4.98982131])
+
+
+

In the above example, for the first quadruplet in quadruplets_test, the +two first points are predicted less similar than the two last points (they +are further away in the transformed space).

+

Like triplet learners, quadruplets learners do not allow to give a y when fitting: we +assume that the ordering of points within triplets is such that the training triplets +are all positive. Therefore, it is not possible to use scikit-learn scoring functions +(such as ‘f1_score’) for triplets learners.

+

However, quadruplets learners do have a default scoring function, which will +basically return the accuracy score on a given test set, i.e. the proportion +of quadruplets have the right predicted ordering.

+
>>> lsml.score(quadruplets_test)
+0.5
+
+
+
+

Note

+

See Fit, transform, and so on for more details on metric learners functions that are +not specific to learning on pairs, like transform, pair_distance, +pair_score, get_metric and get_mahalanobis_matrix.

+
+
+
+

3.4.4. Algorithms

+
+

3.4.4.1. LSML

+

Metric Learning from Relative Comparisons by Minimizing Squared Residual +(LSML)

+

LSML proposes a simple, yet effective, algorithm that minimizes a convex +objective function corresponding to the sum of squared residuals of +constraints. This algorithm uses the constraints in the form of the +relative distance comparisons, such method is especially useful where +pairwise constraints are not natural to obtain, thus pairwise constraints +based algorithms become infeasible to be deployed. Furthermore, its sparsity +extension leads to more stable estimation when the dimension is high and +only a small amount of constraints is given.

+

The loss function of each constraint +\(d(\mathbf{x}_i, \mathbf{x}_j) < d(\mathbf{x}_k, \mathbf{x}_l)\) is +denoted as:

+
+\[H(d_\mathbf{M}(\mathbf{x}_i, \mathbf{x}_j) +- d_\mathbf{M}(\mathbf{x}_k, \mathbf{x}_l))\]
+

where \(H(\cdot)\) is the squared Hinge loss function defined as:

+
+\[\begin{split}H(x) = \left\{\begin{aligned}0 \qquad x\leq 0 \\ +\,\,x^2 \qquad x>0\end{aligned}\right.\\\end{split}\]
+

The summed loss function \(L(C)\) is the simple sum over all constraints +\(C = \{(\mathbf{x}_i , \mathbf{x}_j , \mathbf{x}_k , \mathbf{x}_l) +: d(\mathbf{x}_i , \mathbf{x}_j) < d(\mathbf{x}_k , \mathbf{x}_l)\}\). The +original paper suggested here should be a weighted sum since the confidence +or probability of each constraint might differ. However, for the sake of +simplicity and assumption of no extra knowledge provided, we just deploy +the simple sum here as well as what the authors did in the experiments.

+

The distance metric learning problem becomes minimizing the summed loss +function of all constraints plus a regularization term w.r.t. the prior +knowledge:

+
+\[\begin{split}\min_\mathbf{M}(D_{ld}(\mathbf{M, M_0}) + \sum_{(\mathbf{x}_i, +\mathbf{x}_j, \mathbf{x}_k, \mathbf{x}_l)\in C}H(d_\mathbf{M}( +\mathbf{x}_i, \mathbf{x}_j) - d_\mathbf{M}(\mathbf{x}_k, \mathbf{x}_l))\\\end{split}\]
+

where \(\mathbf{M}_0\) is the prior metric matrix, set as identity +by default, \(D_{ld}(\mathbf{\cdot, \cdot})\) is the LogDet divergence:

+
+\[D_{ld}(\mathbf{M, M_0}) = \text{tr}(\mathbf{MM_0}) − \text{logdet} +(\mathbf{M})\]
+

Example Code

+
from metric_learn import LSML
+
+quadruplets = [[[1.2, 7.5], [1.3, 1.5], [6.4, 2.6], [6.2, 9.7]],
+               [[1.3, 4.5], [3.2, 4.6], [6.2, 5.5], [5.4, 5.4]],
+               [[3.2, 7.5], [3.3, 1.5], [8.4, 2.6], [8.2, 9.7]],
+               [[3.3, 4.5], [5.2, 4.6], [8.2, 5.5], [7.4, 5.4]]]
+
+# we want to make closer points where the first feature is close, and
+# further if the second feature is close
+
+lsml = LSML()
+lsml.fit(quadruplets)
+
+
+

References

+ +
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2015-2023, CJ Carey, Yuan Tang, William de Vazelhes, Aurélien Bellet and Nathalie Vauquier.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file