(Ajouté le 25/02/2020) TODO: Les poids de k-NN sont calculés par la somme des distances sans utiliser l'inverse des distances. Il sera corrigé à l'inverse de la distance. (La méthode de calcul de KNeighborsClassifier n'est pas fausse, mais la méthode de calcul de ma propre fonction est fausse)
--Avec KNeighbors Classifier de sklearn, il était possible de placer un poids lourd du côté siple avec des données moins déséquilibrées.
Diagramme d'image après
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import sklearn
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, accuracy_score
%matplotlib inline
from sklearn.datasets import make_classification
data_base = make_classification(
n_samples = 10000, n_features = 2, n_informative = 2, n_redundant = 0,
n_repeated = 0, n_classes = 2, n_clusters_per_class = 2, weights = [0.9, 0.1],
flip_y = 0, class_sep = 0.5, hypercube = True, shift = 0.0,
scale = 1.0, shuffle = True, random_state =5)
df = pd.DataFrame(data_base[0], columns = ['f1', 'f2'])
df['class'] = data_base[1]
fig = plt.figure()
ax = fig.add_subplot()
for i in df.groupby('class'):
cls = i[1]
ax.plot(cls['f1'],
cls['f2'],
'o',
ms=2)
plt.show()
X = df[["f1","f2"]]
y = df["class"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
X_train = X_train.reset_index(drop=True)
X_test = X_test.reset_index(drop=True)
y_train = y_train.reset_index(drop=True)
y_test = y_test.reset_index(drop=True)
print("train", X_train.shape, y_train.shape)
print("test", X_test.shape, y_test.shape)
train (7000, 2) (7000,) test (3000, 2) (3000,)
from sklearn.neighbors import KNeighborsClassifier
clf = KNeighborsClassifier(n_neighbors=5)
clf.fit(X_train, y_train)
pred = clf.predict(X_test)
result = confusion_matrix(y_test, pred)
result2 = accuracy_score(y_test, pred)
print("confusion matrix \n",result)
print("accuracy \n", result2 )
confusion matrix [[2641 67] [ 167 125]] accuracy 0.922
size_and_weight = pd.DataFrame({
'class0': [sum(clf._y == 0),1/ (sum(clf._y == 0)/ len(clf._y))],
'class1': [sum(clf._y == 1),1/ (sum(clf._y == 1)/ len(clf._y))]}).T
size_and_weight.columns = ['sample_size', 'weight']
size_and_weight
sample_size | weight | |
---|---|---|
class0 | 6292.0 | 1.112524 |
class1 | 708.0 | 9.887006 |
weights_array = pd.Categorical(clf._y)
weights_array.categories = [size_and_weight.loc[('class0'),'weight'],
size_and_weight.loc[('class1'),'weight']]
clf = KNeighborsClassifier(n_neighbors=5)
clf.fit(X_train, y_train)
neigh_dist, neigh_ind = clf.kneighbors(X_test) #La trame de données de cette partie sera décrite plus loin.
weights_array = np.array(weights_array).reshape((-1, 1))[neigh_ind,0]
pd.DataFrame(weights_array).head()
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 1.112524 | 1.112524 | 1.112524 | 1.112524 | 1.112524 |
1 | 1.112524 | 1.112524 | 1.112524 | 1.112524 | 1.112524 |
2 | 1.112524 | 9.887006 | 1.112524 | 1.112524 | 1.112524 |
3 | 1.112524 | 1.112524 | 1.112524 | 1.112524 | 1.112524 |
4 | 1.112524 | 1.112524 | 1.112524 | 1.112524 | 1.112524 |
--Définissez les poids d'argument pour prendre en compte le poids et exécutez jusqu'à la prédiction
def tmp(array_):
global weights_array
array_ = array_ * weights_array
return array_
clf = KNeighborsClassifier(n_neighbors=5,weights=tmp)
clf.fit(X_train, y_train)
pred = clf.predict(X_test)
pred = clf.predict(X_test)
result = confusion_matrix(y_test, pred)
result2 = accuracy_score(y_test, pred)
print("confusion matrix \n",result)
print("accuracy \n", result2 )
confusion matrix [[2252 456] [ 80 212]] accuracy 0.8213333333333334
--KNeighborsClassifier classe les données de test dans la classe avec la plus grande distance totale. (Bien que ce soit un algorithme légèrement contre-intuitif que le résultat de l'estimation soit dans une classe distante, le calcul de la distance n'est appliqué qu'aux n données les plus proches, donc si le poids n'est pas appliqué, l'estimation est plus proche d'une décision majoritaire que la somme des distances. Il devient.)
Remplacez la somme par "élément produit de la somme et du tableau des poids"
Ce faisant, il est nécessaire de comprendre la correspondance entre les trames de données suivantes.
neigh_dist, neigh_ind = clf.kneighbors(X_test)
pd.DataFrame(neigh_dist).tail(5)
pd.DataFrame(neigh_ind).tail(5)
pd.DataFrame(clf._y.reshape((-1, 1))[neigh_ind,0]).tail(5)
À partir de la gauche de ↑, il devient Neighbor_dist, neigh_ind, "neigh_ind class"
--Discussion 1: Les formes des trois tableaux ci-dessus sont les mêmes. --Discussion 2: [Nombre de 3 lignes ci-dessus] = [Nombre de lignes de données de test] --Discussion 3: Nombre de colonnes = [n_neighbours = 5] --Discussion 4: Concernant neigh_dist, il augmente lorsque vous vous déplacez vers la droite. En d'autres termes, on considère que les cinq points les plus proches des données de test ont été extraits.
--DataFrame: Calculez les nombres suivants pour neigh_dist --index = 2998 # 2998e données de test --values = 0.015318 # Distance entre [1374ème donnée de X_train déterminée comme étant la distance la plus proche] et [données de test de l'index ci-dessus]
test_index = 2998
tmp1 = pd.DataFrame(X_test.iloc[test_index])
display(tmp1.T)
train_index = 1374
tmp2 = pd.DataFrame(X_train.iloc[train_index])
display(tmp2.T)
#Calculer la distance euclidienne
(
sum( (tmp1.values - tmp2.values) **2 )
**(1/2)
)
array([0.01531811])
--About neigh_dist.iloc [2998,0]: pourrait être calculé à partir des données d'apprentissage et des données de test.
sum(clf_knn._y == y_train) == len(y_train)
True
--Il s'est avéré que y_train et clf_knn._y correspondent.
index_ = neigh_ind[2998,:]
pd.DataFrame(clf._y[index_]).T
-Chapitre [Détails: À propos des arguments personnalisés] n'explique que le code source de la partie KNeighborsClassifier.predict, il peut donc être plus rapide de regarder le code source de git. Référence git sklearn
Recommended Posts