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 ... |