I. La métrique de distance
Premièrement, le nombre d'entités (colonnes) dans un ensemble de données n'est pas un facteur dans la sélection d'une mesure de distance à utiliser en kNN. Il existe de nombreuses études publiées portant précisément sur 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 n'avez aucune connaissance préalable des distributions à partir desquelles vos données ont été échantillonnées, au moins une étude (bien documentée et approfondie) conclut que la distance euclidienne est le meilleur choix.
Métrique YEuclidean utilisée dans les moteurs de recommandation Web à grande échelle ainsi que dans la recherche universitaire actuelle. Les distances calculées par Euclidienne 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é pour moi que quelques fois, chacun de ces cas La distance euclidienne a échoué parce que 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 qu'Euclidienne, de même lorsque l'espace métrique est la Terre et vos distances sont trans -vols continentaux, une mesure de distance adaptée à un système de coordonnées polaires est une bonne idée (par exemple, Londres à Vienne est de 2,5 heures, Vienne à Saint-Pétersbourg est encore 3 heures, plus ou moins dans la même direction, mais Londres à St . Pétersbourg n'est pas 5,5 heures, à la place, c'est un peu plus de 3 heures.)
Mais à part les cas où 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 ce billet de blog d'un étudiant CS, comparant plusieurs métriques de distance en examinant leur effet sur le classificateur kNN - le chi carré donne les meilleurs résultats, mais les différences ne sont pas grandes; Une étude plus complète se trouve dans l'article académique, Comparative Study of Fonctions de distance pour les voisins les plus proches - Mahalanobis (essentiellement euclidienne normalisée par pour tenir compte de la covariance de dimension) était la meilleure de cette étude.
Une condition importante: pour que les calculs de métrique de distance soient significatifs, vous devez redimensionnervos données - il est rarement possible de créer un modèle kNN pour générer des prédictions précises sans faire cela. Par exemple, si vous construisez un modèle kNN pour prédire les performances sportives et que vos variables d'attente sont la taille (cm), le poids (kg), la graisse corporelle (%) et le pouls au repos (battements par minute), alors un point de données typique pourrait ressemble à 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% de graisse corporelle sera presque négligeable. En d'autres termes, si au contraire, les données étaient déclarées différemment, de sorte que le poids corporel était en grammes plutôt qu'en kilogrammes, alors la valeur d'origine de 86,1 serait de 86,100, ce qui aurait un effet important sur vos résultats, ce qui est exactement ce que vous ne faites pas. veux pas.
X_new = (X_old - mu) / sigma
II. La structure des 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-Trees.
Ce n'est pas la manière la plus courante de conserver les données d'entraînement kNN, bien que l'application de VT à cette fin, ainsi que les avantages de performances qui en découlent, soient bien documentés (voir par exemple ce rapport Microsoft Research ). La signification pratique de ceci est que, à condition que vous utilisiez un langage «grand public» (par exemple, dans l' Index TIOBE ), vous devriez alors trouver une bibliothèque pour effectuer la TV. Je sais qu'en Python et R, il existe plusieurs options pour chaque langue (par exemple, le package voronoi pour R disponible sur CRAN )
L'utilisation d'un VT pour kNN fonctionne comme ceci:
À partir de vos données, sélectionnez aléatoirement w points - ce sont vos centres Voronoi. Une cellule Voronoi encapsule tous les points voisins les plus proches de chaque centre. Imaginez si vous attribuez une couleur différente à chacun des centres de Voronoi, de sorte que chaque point affecté à un centre donné soit peint de cette couleur. Tant que vous avez une densité suffisante, cela montrera bien les limites de chaque centre de Voronoi (comme la frontière qui sépare deux couleurs.
Comment sélectionner les centres Voronoi? J'utilise deux lignes directrices orthogonales. Après avoir sélectionné au hasard les points w, 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 Voronoi - ces valeurs doivent être à peu près les mêmes (étant donné la densité de points uniforme dans votre espace de données). En deux dimensions, cela provoquerait un VT avec des tuiles de même taille. C'est la première règle, voici la seconde. Sélectionnez w par itération - exécutez votre algorithme kNN avec w comme paramètre variable et mesurez les performances (temps nécessaire pour renvoyer une prédiction en interrogeant le VT).
Imaginez donc que vous ayez un million de points de données ..... Si les points étaient persistants dans une structure de données 2D ordinaire, ou dans un arbre kd, vous effectueriez en moyenne quelques millions de calculs de distance pour chaquenouveaux points de données dont vous souhaitez prédire la variable de réponse. Bien entendu, ces calculs sont effectués sur un seul ensemble de données. Avec un V / T, la recherche du plus proche voisin 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 Voronoi, puis une fois le centre le plus proche trouvé, les points à l'intérieur de la cellule correspondant à ce centre est recherché pour trouver le voisin le plus proche réel (par des calculs de distance successifs) Combinés, ces deux recherches sont beaucoup plus rapides qu'une seule recherche par force brute. C'est facile à voir: pour 1M de points de données, supposons que vous sélectionniez 250 centres Voronoi pour tesseler votre espace de données. En moyenne, chaque cellule Voronoi aura 4 000 points de données. Ainsi, au lieu d'effectuer en moyenne 500000 calculs de distance (force brute), vous effectuez beaucoup moins, en moyenne seulement 125 + 2000.
III. Calcul du résultat (la variable de réponse prédite)
Il y a deux étapes pour calculer la valeur prédite à partir d'un ensemble de données d'apprentissage kNN. La première consiste à identifier n, ou le nombre de voisins les plus proches à utiliser pour ce calcul. Le second est de savoir 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 des moindres carrés). C'est la théorie; en pratique, la plupart des gens utilisent simplement n = 3. Dans tous les cas, 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 voulez juste qu'une valeur plausible pour n commence, encore une fois, utilisez simplement n = 3.
La deuxième composante est de savoir comment pondérer la contribution de chacun des voisins (en supposant n> 1).
La technique de pondération la plus simple consiste simplement à multiplier chaque voisin par un coefficient de pondération, qui est juste le 1 / (dist * K), ou l'inverse de la distance de ce voisin à l'instance de test souvent multipliée par une constante dérivée empiriquement, K. I je ne suis pas fan de cette technique car elle surestime souvent les voisins les plus proches (et sous-pondère en même temps les plus éloignés); la signification de ceci est qu'une prédiction donnée peut être presque entièrement dépendante d'un seul voisin, ce qui à son tour augmente la sensibilité de l'algorithme au bruit.
Une fonction de pondération incontournable, qui évite considérablement cette limitation est la 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, vous devez identifier 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 appeler 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 retournera le poids pour chaque voisin, qui est ensuite utilisé comme coefficient de ce voisin dans le calcul de la moyenne pondérée.