La dernière fois a utilisé la méthode de correspondance des modèles pour identifier les nombres manuscrits, mais cette fois nous avons changé la méthode et la méthode du k-plus proche voisin. ) Sera utilisé.
Tout d'abord, les grandes lignes de la méthode sont les suivantes. Si les points noirs sont utilisés comme données cibles d'identification, comme indiqué dans la figure ci-dessous, k données d'enseignants proches les unes des autres sont recherchées et l'étiquette avec le plus grand nombre de décisions à la majorité est sélectionnée comme valeur estimée. Dans le cas de cet exemple, il y a 3 "5" et 2 "8", donc "5" sera adopté comme valeur estimée. Les caractéristiques sont qu'il s'agit d'une analyse supervisée et que toutes les données sont utilisées pour le calcul, ce qui consomme la taille de la mémoire et la quantité de calcul. Il existe plusieurs concepts de «proche» tels que la distance ordinaire (distance euclidienne) et la distance de Maharanobis (en utilisant la dispersion), mais cette fois nous utiliserons la distance ordinaire.

Je vais l'écrire en Python à la fois. Tout d'abord, importez les bibliothèques nécessaires. Je n'utiliserai pas la bibliothèque d'apprentissage automatique telle que sklearn cette fois. (Parce que je suis seul)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from collections import defaultdict
Définissez une classe appelée TrainDataSet. Puisqu'il s'agit de données d'enseignant, il contient l'étiquette de résultat (numéro manuscrit) et les données de pixels afin que vous puissiez facilement récupérer les données nécessaires, telles que l'extraction d'éléments spécifiques.
class TrainDataSet():
    def __init__(self, data):
        data = np.array(data)
        
        self.labels = data[:,0]
        self.data_set = data[:,1:]
        
    def __repr__(self):
        ret  = repr(self.labels) + "\n"
        ret += repr(self.data_set)
        return ret
        
    def get_data_num(self):
        return self.labels.size
        
    def get_labels(self, *args):
        if args is None:
            return self.labels
        else:
            return self.labels[args[0]]
    def get_data_set(self):
        return self.data_set
        
    def get_data_set_partial(self, *args):
        if args is None:
            return self.data_set
        else:
            return self.data_set[args[0]]
    def get_label(self, i):
        return self.labels[i]
    def get_data(self, i):
        return self.data_set[i,:]
    def get_data(self,i, j):
        return self.data_set[i][j]
Chargez ensuite les données. Si vous souhaitez l'essayer, vous pouvez télécharger les données à partir de ce qui suit. train.csv ... Données des enseignants (42000) test_small.csv ... Données cibles d'identification (200 pièces)
size = 28
master_data= np.loadtxt('train_master.csv',delimiter=',',skiprows=1)
test_data= np.loadtxt('test_small.csv',delimiter=',',skiprows=1)
train_data_set = TrainDataSet(master_data)
Il définit également une fonction qui agrège les résultats de k voisins et génère une liste du nombre de données disponibles pour chaque étiquette numérique.
def get_list_sorted_by_val(k_result, k_dist):
    result_dict = defaultdict(int)
    distance_dict = defaultdict(float)
    
    #Agréger par étiquette de numéro
    for i in k_result:
        result_dict[i] += 1
    
    #Distance totale agrégée pour chaque étiquette numérique
    for i in range(len(k_dist)):
        distance_dict[k_result[i]] += k_dist[i]
    
    #Conversion du type de dictionnaire en liste (pour le tri)
    result_list = []
    order = 0
    for key, val in result_dict.items():
        order += 1
        result_list.append([key, val, distance_dict[key]])
    
    #Convertir en type ndarray
    result_list = np.array(result_list) 
    return result_list
Maintenant que toutes les préparations sont terminées, le processus d'identification commence ici. Cette fois, sélectionnez k = 5 données comme voisinage.
k = 5
predicted_list = []    #Valeur prédite de l'étiquette numérique
k_result_list  = []    #k liste des quartiers
k_distances_list = []  #Liste des distances entre les nombres k et les données à identifier
# execute k-nearest neighbor method
for i in range(len(test_data)):
  
    #Faites la différence entre les données cibles d'identification et les données de l'enseignant
    diff_data = np.tile(test_data[i], (train_data_set.get_data_num(),1)) - train_data_set.get_data_set()
    
    sq_data   = diff_data ** 2       #Équerre chaque élément et effacer le signe
    sum_data  = sq_data.sum(axis=1)  #Additionnez chaque élément vectoriel
    distances = sum_data ** 0.5      #Prenez la route et utilisez-la comme distance
    ind = distances.argsort()        #Trier par ordre croissant de distance et extraire l'indice
    k_result = train_data_set.get_labels(ind[0:k]) #Retirez k pièces de la plus proche
    k_dist   = distances[ind[0:k]]   #Extraire les informations de distance k
    
    k_distances_list.append(k_dist)
    k_result_list.append(k_result)
    
    #Agrégé à partir de k données avec des étiquettes numériques,(Étiquette de numéro,Quantité,distance)Générer une liste de
    result_list = get_list_sorted_by_val(k_result, k_dist)
    candidate = result_list[result_list[:,1].argsort()[::-1]]
    counter = 0
    min = 0
    label_top = 0
    
    #S'il existe plusieurs étiquettes numériques avec le plus grand nombre, sélectionnez celle avec la distance totale la plus petite.
    result_dict = {}
    for d in candidate:
        if d[1] in result_dict:
            result_dict[d[1]] += [(d[0], d[2])]
        else:
            result_dict[d[1]] =  [(d[0], d[2])]
    for d in result_dict[np.max(result_dict.keys())]:
        if counter == 0:
            label_top = d[0]
            min = d[1]
        else:
            if d[1] < min:
                label_top = d[0]
                min = d[1]
        counter += 1
                
    #Mettez les résultats dans une liste
    predicted_list.append(label_top)
Affichez le résultat.
# disp calc result
print "[Predicted Data List]"
for i in range(len(predicted_list)):
    print ("%d" % i) + "\t" + str(predicted_list[i])
print "[Detail Predicted Data List]"
print "index k units of neighbors, distances for every k units"
for i in range(len(k_result_list)):
    print ("%d" % i) + "\t" + str(k_result_list[i]) + "\t" + str(k_distances_list[i])
Le fichier de résultat de sortie est ici, et le résultat de la comparaison de la valeur prédite identifiée comme la bonne réponse est [ici](https: //gist.github. Il est situé à l'adresse com / matsuken92 / 7ca89520ff4e9d2242b0). Cette fois, j'ai essayé d'identifier 200 pièces en utilisant la méthode du k plus proche voisin, mais le taux d'identification a considérablement augmenté à 97% (194/200)! Je pense que ce sera pratique si l'identification est si bonne. Dernière fois Dans le cas de la mise en correspondance de modèles effectuée, il était de 80%, donc c'est assez bon comparé à cela.
Les 6 données suivantes ont échoué, mais cela semble gênant même visuellement. La première donnée de la rangée inférieure est même visuelle de 6 ou 4. On peut dire que la plupart des nombres manuscrits peuvent être identifiés par la méthode du k plus proche voisin, sauf pour les plus subtils.
counter = 0
for d, num in zip(test_data, [3,76,128,132,147,165]):
    counter += 1
    X, Y = np.meshgrid(range(size),range(size))
    Z = test_data[num].reshape(size,size)
    Z = Z[::-1,:]
    flat_Z = Z.flatten()
    plot_digits(X, Y, Z, 2, 3, counter, "pred=%d" % predicted_list[num])

** détails des données d'échec **
| index | label | pred | k-nearest digits | remarks | 
|---|---|---|---|---|
| 3 | 0 | 9 | [ 0. 9. 9. 9. 2.] | Le quartier le plus proche est 0, mais ... c'est délicieux. | 
| 76 | 9 | 8 | [ 8. 8. 9. 8. 3.] | Il y a aussi un 9 mais ... | 
| 128 | 7 | 1 | [ 8. 1. 7. 8. 1.] | Ne mettez pas de lignes supplémentaires dans 7 ... | 
| 132 | 4??? | 6 | [ 6. 6. 6. 6. 6.] | C'est 4 ou 6 ou même visuellement subtile | 
| 147 | 4 | 7 | [ 7. 7. 7. 7. 7.] | Je me demande si c'est 7 | 
| 165 | 3 | 2 | [ 3. 2. 2. 2. 3.] | 3 était aussi une bonne ligne, mais ... |