# -*- coding: utf-8 -*-
"""
Implements classic k-nn.
:githublink:`%|py|6`
"""
import numpy
import numpy.linalg
from scipy.spatial.distance import euclidean
[docs]class NuagePoints:
"""
Définit une classe de nuage de points.
On suppose qu'ils sont définis par une matrice,
chaque ligne est un élément.
:githublink:`%|py|16`
"""
[docs] def __init__(self):
"""
constructeur
:githublink:`%|py|21`
"""
pass
[docs] def fit(self, X, y=None):
"""
Follows sklearn API.
:param X: training set
:param y: labels
:githublink:`%|py|30`
"""
self.nuage = X
self.labels = y
[docs] def kneighbors(self, X, n_neighbors=1, return_distance=True):
"""
Return the k nearest neighbors.
:param X: test set
:param n_neighbors: number of neighbors
:param return_distance: return distance as well
:return: array (dist), array (indices)
:githublink:`%|py|42`
"""
if n_neighbors != 1:
raise NotImplementedError( # pragma: no cover
"Not implemented when n_neighbors != 1.")
if not return_distance:
raise NotImplementedError( # pragma: no cover
"Not implemented when return_distance is False.")
dist = numpy.zeros(X.shape[0])
ind = numpy.zeros(X.shape[0], dtype=numpy.int64)
for i in range(X.shape[0]):
row = X[i, :]
row.resize((1, X.shape[1]))
r = self.ppv(row)
dist[i], ind[i] = r
return dist, ind
@property
def shape(self):
"""
Retourne la dimension du nuage.
:githublink:`%|py|64`
"""
return self.nuage.shape
[docs] def distance(self, obj1, obj2):
"""
Retourne une distance entre deux éléments.
:param obj1: object 1
:param obj2: object 2
:return: distance
:githublink:`%|py|74`
"""
return euclidean(obj1, obj2)
[docs] def label(self, i):
"""
Retourne le label de l'object d'indice ``i``.
:param i: indice
:return: label or None if there is no label
:githublink:`%|py|83`
"""
return self.label[i] if self.label is not None else None
[docs] def ppv(self, obj):
"""
Retourne l'élément le plus proche de obj et sa distance avec obj.
:param obj: object
:return: ``tuple(dist, index)``
:githublink:`%|py|92`
"""
ones = numpy.ones((self.nuage.shape[0], 1))
mat = ones @ obj
if len(mat.shape) == 1:
mat.resize((mat.shape[0], 1))
delta = self.nuage - mat
norm = numpy.linalg.norm(delta, axis=1)
i = numpy.argmin(norm)
return norm[i], i