web-dev-qa-db-fra.com

Les voisins les plus proches dans les données de grande dimension?

J'ai posé une question quelques jours en arrière sur la recherche des voisins les plus proches pour un vecteur donné. Mon vecteur a maintenant 21 dimensions et avant de continuer, parce que je ne suis pas du domaine de l'apprentissage automatique ni des mathématiques, je commence à me poser quelques questions fondamentales:

  • La distance euclidienne est-elle une bonne mesure pour trouver les voisins les plus proches en premier lieu? Si non, quelles sont mes options?
  • De plus, comment décide-t-on du bon seuil pour déterminer les k-voisins? Peut-on effectuer une analyse pour déterminer cette valeur?
  • Auparavant, on m'avait suggéré d'utiliser kd-Trees mais la page Wikipedia indique clairement que, pour les grandes dimensions, kd-Tree est presque équivalent à une recherche par force brute. Dans ce cas, quel est le meilleur moyen de trouver efficacement les voisins les plus proches dans un jeu de données d'un million de points?

Quelqu'un peut-il s'il vous plaît clarifier certains (ou tous) de ces questions?

139
Legend

J'étudie actuellement de tels problèmes - classification, recherche du plus proche voisin - pour la recherche d'informations musicales.

Vous pouvez être intéressé par les algorithmes le plus proche voisin approximatif (ANN). L'idée est de permettre à l'algorithme de retourner suffisamment les voisins proches (peut-être pas le plus proche voisin); Ce faisant, vous réduisez la complexité. Vous avez mentionné le kd-tree; c'est un exemple. Mais comme vous l'avez dit, kd-tree fonctionne mal dans les grandes dimensions. En fait, toutes les techniques d'indexation actuelles (basées sur le partitionnement d'espace) se dégradent en recherche linéaire de dimensions suffisamment élevées [1] [2] [3].

Parmi les ANN algorithmes proposés récemment, le plus populaire est peut-être le hachage sensible à la localité (LSH), qui mappe un ensemble de points dans un espace de grande dimension dans un ensemble de corbeilles, c'est-à-dire une table de hachage [1] [3]. Mais contrairement aux hachages traditionnels, un lieu sensible à la localité à proximité pointe vers le même bac.

LSH présente des avantages considérables. Tout d'abord, c'est simple. Vous venez de calculer le hachage pour tous les points de votre base de données, puis créez une table de hachage à partir de ceux-ci. Pour interroger, calculez simplement le hachage du point de requête, puis récupérez tous les points du même bac à partir de la table de hachage.

Deuxièmement, il existe une théorie rigoureuse qui soutient ses performances. On peut montrer que la durée de la requête est sublinear dans la taille de la base de données, c'est-à-dire plus rapide que la recherche linéaire. La rapidité dépend de la approximation que nous pouvons tolérer.

Enfin, LSH est compatible avec toute norme Lp pour 0 < p <= 2. Par conséquent, pour répondre à votre première question, vous pouvez utiliser LSH avec la métrique de distance euclidienne, ou avec la métrique de distance Manhattan (L1). Il existe également des variantes pour la similarité de distance et de cosinus de Hamming.

Malcolm Slaney et Michael Casey ont rédigé un survol décent pour IEEE Signal Processing Magazine en 2008 [4].

LSH a été appliqué apparemment partout. Vous voudrez peut-être essayer.


[1] Datar, Indyk, Immorlica, Mirrokni, "Schéma de hachage sensible à la localisation basé sur les distributions p-stables", 2004.

[2] Weber, Schek, Blott, "Une analyse quantitative et une étude de performance pour les méthodes de recherche de similarité dans des espaces de grande dimension", 1998.

[3] Gionis, Indyk, Motwani, "Recherche de similarité dans les grandes dimensions via le hachage", 1999.

[4] Slaney, Casey, "Un hachage tenant compte des localités pour trouver les voisins les plus proches", 2008.

171
Steve Tjoa

I. La métrique de distance

Premièrement, le nombre d'entités (colonnes) dans un jeu de données n'est pas un facteur dans la sélection d'une métrique de distance à utiliser dans kNN. Il existe de nombreuses études publiées qui traitent précisément de cette question, et les bases de comparaison habituelles sont:

  • la distribution statistique sous-jacente de vos données;

  • la relation entre les caractéristiques qui composent vos données (sont-elles indépendantes - c’est-à-dire, à quoi ressemble la matrice de covariance); et

  • l'espace de coordonnées à partir duquel vos données ont été obtenues.

Si vous ne connaissez pas la ou les distributions à partir desquelles vos données ont été échantillonnées, au moins une (bien documentée et exhaustive) étude conclut que la distance euclidienne est le meilleur choix.

Métrique Yclidean utilisée dans les moteurs de recommandation Web à grande échelle ainsi que dans la recherche universitaire actuelle. Les distances calculées par Euclidien ont une signification intuitive et les échelles de calcul - c’est-à-dire que la distance euclidienne est calculée de la même manière, que les deux points soient en deux dimensions ou dans un espace de vingt-deux dimensions.

Cela n'a échoué que quelques fois pour moi. Dans chacun de ces cas, la distance euclidienne a échoué car le système de coordonnées sous-jacent (cartésien) était un mauvais choix. Et vous le reconnaîtrez généralement parce que, par exemple, les longueurs de chemin (distances) ne sont plus additives - par exemple, lorsque l’espace métrique est un échiquier, la distance de Manhattan est meilleure que celle d’Euclidien, tout comme l’espace métrique est la Terre et vos distances sont trans -continental, une métrique de distance adaptée à un système de coordonnées polaires est une bonne idée (par exemple, Londres à Vienne est à 2,5 heures, Vienne à Saint-Pétersbourg à 3 heures supplémentaires, plus ou moins dans la même direction, mais de Londres à Pétersbourg n’est pas 5,5 heures, c’est un peu plus de 3 heures.)

Toutefois, mis à part les cas dans lesquels vos données appartiennent à un système de coordonnées non cartésien, le choix de la métrique de distance n’est généralement pas important. (Voir ceci article de blog d'un étudiant en informatique, comparant plusieurs mesures de distance en examinant leur effet sur le classifieur kNN - le chi carré donne les meilleurs résultats, mais les différences ne sont pas considérables; une étude plus complète est en cours. le document académique, Étude comparative des fonctions de distance pour les voisins les plus proches - Mahalanobis (essentiellement normalisé euclidien pour tenir compte de la covariance des dimensions) était le meilleur dans cette étude.

Une condition importante: pour que les calculs de métriques de distance soient significatifs, vous devez rééchelonner vos données - cela est rarement possible construire un modèle kNN pour générer des prévisions précises sans le faire. Par exemple, si vous construisez un modèle kNN pour prédire les performances sportives et que vos variables d’attente sont la hauteur (cm), le poids (kg), la graisse corporelle (%) et le pouls au repos (battements par minute), un point de données typique ressembler à quelque chose comme ceci: [180.4, 66.1, 11.3, 71]. Il est clair que le calcul de la distance sera dominé par la hauteur, tandis que la contribution du pourcentage de graisse corporelle sera presque négligeable. Autrement dit, si les données étaient rapportées différemment, de sorte que le poids corporel était exprimé en grammes plutôt qu'en kilogrammes, la valeur initiale de 86,1 serait de 86 100, ce qui aurait un effet important sur vos résultats. tu veux pas. La technique de mise à l'échelle la plus courante consiste probablement à soustraire la moyenne et à la diviser par l'écart type (moyenne et sd se rapportent à une colonne distincte ou à une caractéristique de cet ensemble de données; X désigne une entrée/cellule individuelle dans une ligne de données):

X_new = (X_old - mu) / sigma


II. La structure de données

Si vous êtes préoccupé par les performances de la structure kd-tree, A Voronoi Tessellation est un conteneur conceptuellement simple, mais qui améliorera considérablement les performances et évoluera mieux que kd. -Des arbres.

dat

Ce n’est pas le moyen le plus courant de conserver des données d’apprentissage kNN, bien que l’application de la vidéo à cet effet ainsi que les avantages en termes de performances qui en résultent soient bien documentés (voir par exemple this rapport de Microsoft Research ). L’importance pratique de cela est que, si vous utilisez un langage "traditionnel" (par exemple, dans le TIOBE Index ), vous devez trouver une bibliothèque pour effectuer la VT. Je sais que dans Python et R, il existe de nombreuses options pour chaque langue (par exemple, le package voronoi pour R disponible sur CRAN )

Utiliser un VT pour kNN fonctionne comme ceci:

A partir de vos données, sélectionnez au hasard w points - ce sont vos centres Voronoï. Une cellule de Voronoï encapsule tous les points voisins les plus proches de chaque centre. Imaginez si vous affectez une couleur différente à chacun des centres de Voronoï, de sorte que chaque point affecté à un centre donné soit peint de cette couleur. Tant que vous avez une densité suffisante, cette opération montrera bien les limites de chaque centre de Voronoï (en tant que limite séparant deux couleurs.

Comment sélectionner les centres Voronoï? J'utilise deux lignes directrices orthogonales. Après avoir sélectionné les points w de manière aléatoire, calculez le VT pour vos données d'entraînement. Vérifiez ensuite le nombre de points de données attribués à chaque centre de Voronoï. Ces valeurs doivent être à peu près identiques (densité de points uniforme dans l’espace de données). En deux dimensions, cela créerait un VT avec des tuiles de la même taille. C'est la première règle, en voici la seconde. Sélectionnez w par itération - exécutez votre algorithme kNN avec w en tant que paramètre variable et mesurez les performances (temps requis pour renvoyer une prédiction en interrogeant le VT).

Alors, imaginez que vous avez un million de points de données ..... Si les points étaient conservés dans une structure de données 2D ordinaire ou dans un arbre kd, vous effectueriez en moyenne quelques millions de calculs de distance pour each = nouveaux points de données dont vous souhaitez prédire la variable de réponse. Bien entendu, ces calculs sont effectués sur un seul jeu de données. Avec un V/T, la recherche du voisin le plus proche est effectuée en deux étapes l'une après l'autre, contre deux populations différentes de données - d'abord contre les centres de Voronoï, puis une fois que le centre est trouvé, les points à l'intérieur de la cellule correspondant à ces centres sont recherchés pour trouver le plus proche voisin réel (par calculs de distance successifs). Combinées, ces deux recherches sont beaucoup plus rapides qu'une recherche simple par force brute. C'est facile à voir: pour 1 million de points de données, supposons que vous sélectionniez 250 centres Voronoï pour mettre en mosaïque votre espace de données. En moyenne, chaque cellule de Voronoi aura 4 000 points de données. Ainsi, au lieu d'effectuer en moyenne 500 000 calculs de distance (force brute), vous effectuez beaucoup moins, en moyenne seulement 125 + 2 000.

III. Calcul du résultat (la variable de réponse prévue)

Le calcul de la valeur prédite à partir d’un ensemble de données d’apprentissage kNN se fait en deux étapes. Le premier identifie n, ou le nombre de voisins les plus proches à utiliser pour ce calcul. La seconde est comment pondérer leur contribution à la valeur prédite.

W/r/t le premier composant, vous pouvez déterminer la meilleure valeur de n en résolvant un problème d'optimisation (très similaire à l'optimisation par les moindres carrés). C'est la théorie. dans la pratique, la plupart des gens utilisent simplement n = 3. Quoi qu'il en soit, il est simple d'exécuter votre algorithme kNN sur un ensemble d'instances de test (pour calculer les valeurs prédites) pour n = 1, n = 2, n = 3, etc., et de tracer l'erreur en fonction de n. Si vous souhaitez simplement que n commence avec une valeur plausible, utilisez à nouveau n = 3.

La deuxième composante consiste à pondérer la contribution de chacun des voisins (en supposant que n> 1).

La technique de pondération la plus simple consiste simplement à multiplier chaque voisin par un coefficient de pondération, qui est simplement le 1/(dist * K), ou l'inverse de la distance de ce voisin à l'instance de test, souvent multiplié par une constante empiriquement dérivée, K. I je ne suis pas un adepte de cette technique car elle alourdit souvent les voisins les plus proches (et concomitamment sous-alourdit les plus éloignés); Cela signifie qu'une prévision donnée peut presque entièrement dépendre d'un seul voisin, ce qui augmente à son tour la sensibilité de l'algorithme au bruit.

Une meilleure fonction de pondération, qui évite sensiblement cette limitation, est le fonction gaussienne, qui en python ressemble à ceci:

def weight_gauss(dist, sig=2.0) :
    return math.e**(-dist**2/(2*sig**2))

Pour calculer une valeur prédite à l'aide de votre code kNN, identifiez les n voisins les plus proches du point de données dont vous souhaitez prédire la variable de réponse ("instance de test"), puis appelez la fonction weight_gauss, une fois pour chacun des n voisins, en passant dans la distance entre chaque voisin le point de test. Cette fonction renvoie le poids pour chaque voisin, qui est ensuite utilisé comme coefficient de ce voisin dans le calcul de la moyenne pondérée.

77
doug

Ce à quoi vous faites face est appelé malédiction de la dimensionnalité . Il est parfois utile d’exécuter un algorithme tel que PCA ou I CA pour vous assurer que vous avez vraiment besoin des 21 dimensions et éventuellement trouver une transformation linéaire qui vous permettrait d’utiliser moins de 21 avec une qualité de résultat à peu près identique.

Mise à jour: Je les ai rencontrés dans un livre intitulé Traitement du signal biomédical de Rangayyan (j'espère m'en souvenir correctement). L’ACI n’est pas une technique triviale, mais elle a été mise au point par des chercheurs finlandais et je pense que le code Matlab est disponible au public pour le téléchargement. La PCA est une technique plus largement utilisée et je pense que vous devriez pouvoir trouver son implémentation de logiciel R ou autre. La PCA est réalisée en résolvant les équations linéaires de manière itérative. Je l'ai fait il y a trop longtemps pour me rappeler comment. =)

L'idée est que vous divisez vos signaux en vecteurs propres indépendants (fonctions propres discrètes, vraiment) et leurs valeurs propres, 21 dans votre cas. Chaque valeur propre indique la quantité de contribution que chaque fonction propre fournit à chacune de vos mesures. Si une valeur propre est minuscule, vous pouvez très étroitement représenter les signaux sans utiliser la fonction propre correspondante, et c'est ainsi que vous vous débarrassez d'une dimension.

15
Phonon

Pour répondre à vos questions une à une:

  • Non, la distance euclidienne est une mauvaise métrique dans un espace de grande dimension. Dans les grandes dimensions, il y a peu de différence entre le voisin le plus proche et le plus éloigné.
  • Beaucoup d'articles/de recherches portent sur des données de grande dimension, mais la plupart de ces travaux nécessitent beaucoup de complexité mathématique.
  • L'arbre KD est mauvais pour les données de grande dimension ... à éviter absolument

Voici un bel article pour vous aider à démarrer dans la bonne direction. " Quand près du voisin le plus significatif ?" par Beyer et tous.

Je travaille avec des données textuelles de dimensions supérieures ou égales à 20K. Si vous souhaitez des conseils relatifs au texte, je pourrais peut-être vous aider.

8
BiGYaN

La similarité des cosinus est un moyen courant de comparer des vecteurs de grande dimension. Notez que comme il s’agit d’une similitude et non d’une distance, vous voudrez la maximiser et non la minimiser. Vous pouvez également utiliser un moyen spécifique au domaine pour comparer les données. Par exemple, si vos données étaient des séquences d'ADN, vous pouvez utiliser une similarité de séquence qui prend en compte les probabilités de mutations, etc.

Le nombre de voisins proches à utiliser varie en fonction du type de données, du niveau de bruit, etc. . Les gens comprennent intuitivement que plus il y a de données, moins vous avez besoin de voisins. Dans une situation hypothétique où vous avez toutes les données possibles, il vous suffit de rechercher le voisin unique le plus proche à classer.

La méthode k plus proche voisin est connue pour être coûteuse en calcul. C'est l'une des principales raisons pour lesquelles les utilisateurs se tournent vers d'autres algorithmes, tels que les machines à vecteurs de support.

5
Colin

les kd-trees ne fonctionneront pas très bien avec des données de grande dimension. Parce que l'étape d'élagage n'aide plus beaucoup, car Edge le plus proche - une déviation à 1 dimension - sera presque toujours plus petit que la déviation à toutes les dimensions par rapport aux voisins les plus proches connus.

Mais en plus, les kd-trees ne fonctionnent bien qu'avec les normes Lp pour tout ce que je sais, et il y a l'effet de concentration de distance qui fait que les algorithmes basés sur la distance se dégradent avec une dimensionnalité croissante.

Pour plus d’informations, vous pouvez vous renseigner sur la malédiction de la dimensionnalité et ses différentes variantes (il ya plus d’un côté!)

Je ne suis pas convaincu qu’il soit très courant d’approcher aveuglément les plus proches voisins euclidiens, par exemple. en utilisant LSH ou des projections aléatoires. Il peut être nécessaire d'utiliser une fonction de distance beaucoup plus précise en premier lieu!

4
Erich Schubert

Les arbres KD fonctionnent bien pour 21 dimensions, si vous quittez tôt, après avoir regardé, disons, 5% de tous les points. FLANN fait ceci (et d'autres accélérations) pour correspondre aux vecteurs SIFT de 128 dim.. (Malheureusement, FLANN ne fait que la métrique euclidienne, et le rapide et solide scipy.spatial.cKDTree ne fait que des métriques Lp; celles-ci peuvent ou non être adéquates pour votre data.) Il existe bien entendu ici un compromis entre vitesse et précision.

(Si vous pouviez décrire votre distribution de données Ndata, Nquery, cela pourrait aider les gens à essayer des données similaires.)

Ajout du 26 avril, les temps d'exécution de cKDTree avec cutoff sur mon ancien mac ppc, pour donner une idée très approximative de la faisabilité:

kdstats.py p=2 dim=21 N=1000000 nask=1000 nnear=2 cutoff=1000 eps=0 leafsize=10 clustype=uniformp
14 sec to build KDtree of 1000000 points
kdtree: 1000 queries looked at av 0.1 % of the 1000000 points, 0.31 % of 188315 boxes; better 0.0042 0.014 0.1 %
3.5 sec to query 1000 points
distances to 2 nearest: av 0.131  max 0.253

kdstats.py p=2 dim=21 N=1000000 nask=1000 nnear=2 cutoff=5000 eps=0 leafsize=10 clustype=uniformp
14 sec to build KDtree of 1000000 points
kdtree: 1000 queries looked at av 0.48 % of the 1000000 points, 1.1 % of 188315 boxes; better 0.0071 0.026 0.5 %
15 sec to query 1000 points
distances to 2 nearest: av 0.131  max 0.245
3
denis

Je pense que cosinus sur tf-idf des fonctions booléennes fonctionnerait bien pour la plupart des problèmes. C'est parce que son heuristique éprouvée est utilisée dans de nombreux moteurs de recherche comme Lucene. La distance euclidienne dans mon expérience montre de mauvais résultats pour des données de type texte. La sélection de poids différents et de k-exemples peut être effectuée à l'aide de données d'apprentissage et d'une sélection de paramètres de force brute.

3
yura

Vous pouvez essayer une courbe d'ordre z. C'est facile pour les 3 dimensions.

3
Bytemain

Cela dépend beaucoup de la raison pour laquelle vous voulez connaître les voisins les plus proches. Vous pouvez regarder dans l’algorithme de décalage moyen http://en.wikipedia.org/wiki/Mean-shift si vous voulez vraiment trouver les modes de votre ensemble de données. 

3
phunctor

la distance est probablement la meilleure solution pour la récupération exacte des données dans les données de grande dimension. Vous pouvez le voir comme une tessellation approximative de Voronoï.

3
Tim

J'ai rencontré le même problème et peux dire ce qui suit. 

  1. La distance euclidienne est une bonne métrique, mais elle est plus onéreuse en termes de calcul que la distance Manhattan , et donne parfois des résultats légèrement plus médiocres. Je choisirais donc la plus récente.

  2. La valeur de k peut être trouvée empiriquement. Vous pouvez essayer différentes valeurs et vérifier les courbes ROC résultantes ou une autre mesure de précision/rappel afin de trouver une valeur acceptable.

  3. Les distances euclidiennes et celles de Manhattan respectent l'inégalité Triangle . Vous pouvez donc les utiliser dans des arbres métriques. En effet, les performances des arbres KD sont gravement dégradées lorsque les données ont plus de 10 dimensions (j'ai moi-même rencontré ce problème). J'ai trouvé que VP-trees était une meilleure option.

2

La distance euclidienne est-elle une bonne mesure pour trouver les voisins les plus proches en premier lieu? Si non, quelles sont mes options?

Je suggérerais la mise en cluster souple de sous-espaces , une approche plutôt commune de nos jours, où les poids des entités sont calculés pour trouver les dimensions les plus pertinentes. Vous pouvez utiliser ces poids lorsque vous utilisez la distance euclidienne, par exemple. Voir malédiction de la dimensionnalité pour les problèmes courants et aussi cet article peut vous éclairer en quelque sorte:

Algorithme de classification de type k-means pour la classification en sous-espaces de jeux de données mixtes numériques et catégoriels