Guide d'apprentissage automatique Python à partir de zéro (3) - Classification kNN de l'apprentissage supervisé

introduire

Ce blog combinera des exemples pour présenter 监督学习/Supervised Learning/SLune autre grande branche : 分类/Classification. Pour être précis, l'algorithme de classification que nous utiliserons est 邻近算法/k-nearest neighbors/kNN.

Préparation avant de commencer

Avant de commencer, assurez-vous d'avoir les packages suivants dans votre environnement python :
pandas, numpy, sklearn, seaborn.

Tout le code de cet article peut être exécuté Anacondadans Jupyter Lab.

texte

分类/ClassificationQuelle est la nature du problème ?
Passons en revue les problèmes abordés dans le blog précédent 回归/Regression. L’essence du problème de régression est de trouver une droite de régression pour des points de données inconnus qui puisse les prédire avec la plus grande précision. Par exemple, étant donné une variable continue en entrée, nous pouvons obtenir la variable continue en sortie.

Les problèmes de classification sont similaires et nécessitent de trouver un modèle capable de décrire le plus précisément possible la relation entre les ensembles de fonctionnalités et les ensembles d'étiquettes. Mais la différence est que les ensembles d’étiquettes des problèmes de classification sont tous des variables non continues. Par exemple, compte tenu de l'âge d'une personne, celle-ci ne peut être classée que parmi les adultes ou les mineurs ; étant donné une photo avec un animal, nous devons identifier et distinguer avec précision le type d'animal. En d’autres termes, le problème de classification peut être compris comme, pour la cartographie inconnue fff
f : R n ↦ L f:\mathbb{R}^n\mapsto \mathbb{L}F:R.nL
, nous l'avons定义域/Domain(R n \mathbb{R}^nR.n est l'ensemble des fonctionnalités) et对应域/Codomain(L \mathbb{L}L est un tableau de jeux d'étiquettes). Nous souhaitons utiliser les données existantes pour trouver un modèle qui correspond le mieux aux données. Il convient de noter que l'ensemble d'étiquettesL \mathbb{L}L est un ensemble fini. Par conséquent, ce qui est différent de la fonction de régression est que la fonction de classification peut être非参数模型/nonparametric function, c'est-à-dire qu'elle ne nécessite pas de paramètres (tels que l'ensemble de poidsw dans la régression linéaire \bf ww ) peut réaliser une classification des données. L'exemple le plus simple est l'algorithme KNN qui sera présenté dans cet article.

Qu’est-ce que KNN ? Comment réalise-t-on la classification ?
On peut trouver la réponse dans son nom k-nearest neighbors: pour un nouveau point de données, l'algorithme déterminera de quelle donnée d'étiquette il est le plus proche, un peu comme "celui qui est proche du rouge est rouge, celui qui est proche de l'encre est noir". " Lorsque nous voyons quelque chose que nous n’avons jamais vu auparavant, nous, les humains, le comparons à la chose la plus similaire que nous ayons vue.

Pour une nouvelle fonctionnalité de données x = [ x 1 x 2 … xn ] x=[x_1\ x_2\ \dots \ x_n]X=[ x1 X2  Xn] , l'algorithme kNN doit prendre en comptekkk voisins les plus proches des caractéristiques des données, et utiliser les étiquettes de ces voisins pour déterminer l'étiquette des nouvelles données. En d’autres termes, nous dessinons une boule à N dimensions avec les données d’entrée inconnues comme centre de la boule, de sorte que les points de données dans la boule soient exactementkkk , puis kkà l'intérieur du ballonLes k points sont les voisins les plus proches des données d'entrée que l'algorithme doit prendre en compte. Il existe généralement deux méthodes de jugement :

  1. 多数决规则/Majority Rule. L'étiquette qui aura le plus d'étiquettes parmi les voisins sera sélectionnée ; en cas d'égalité, l'étiquette sera choisie au hasard. Dans l'exemple ci-dessous, les données du point d'interrogation seront classées comme B lorsque k=3 et comme A lorsque k=7.
    règle de la majorité
  2. 基于距离的规则/Distance-based Rule. Les voisins les plus proches ont un poids plus élevé : plus ils sont proches, plus le poids est élevé. Enfin, le label ayant la moyenne pondérée la plus élevée est sélectionné. Dans le graphique en bas à droite, les données vertes sont plus proches des données du point d'interrogation, elles ont donc un poids plus élevé dans la détermination de l'étiquette des données du point d'interrogation.
    règles basées sur la distance

Afin de mettre en œuvre la deuxième règle et de déterminer les voisins les plus proches, nous devons également définir une mesure de distance. Pour deux fonctionnalités de données xxxaay , la distance ddentre les deuxd a les définitions suivantes :
3.L 1 L_1L1曼哈顿距离/Manhattan Distanced ( X , y ) = ∑ i = 1 n ∣ xi − yi ∣ d(x,y)=\sum_{i=1}^{n} |{x_i-y_i}|( x ,oui )=je = 1n∣x _jeouije . Pour deux points sur le plan, cette formule calcule deux pointsxxxaaLa somme des différences de coordonnées y (la somme des longueurs des côtés rectangles du triangle rectangle dans la figure ci-dessous).
4.L 2 L_2L2欧几里得距离/Euclidian Distanced ( X , y ) = ∑ i = 1 n ∣ xi − yi ∣ 2 d(x,y)=\sqrt{\sum_{i=1}^{n} |{x_i-y_i}|^2}( x ,oui )=je = 1n∣x _jeouije2 . Pour deux points du plan, cette formule calcule la distance en ligne droite entre les deux points (la longueur de l'hypoténuse du triangle rectangle dans la figure ci-dessous).
5. L ∞ L_\infinL切比雪夫距离/Chebyshev Distanced ( X , y ) = max ⁡ 1 ≤ i ≤ n ∣ xi − yi ∣ d(x,y)=\max_{1\le i\le n}|x_i-y_i|( x ,oui )=maximum1 je n∣x _jeouije .. Pour deux points sur le plan, cette formule calcule deux pointsxxxaaLa valeur maximale de la différence de coordonnée y (le côté rectangle le plus long du triangle rectangle dans la figure ci-dessous).
formule de distance
De ce qui précède, nous pouvons également voir que KNN est un modèle非参数模型/nonparametric function, car la décision du modèle ne dépend pas du poids optimal, mais de toutes les données d'entrée. Par conséquent, afin de maintenir l’authenticité et l’exhaustivité des données, les modèles kNN sont généralement de plus grande taille.

Le modèle 超参/Hyperparametersn'a que le nombre de voisins kkk , et nous devons décider quelle règle de détermination d'étiquette et méthode de calcul de distance utiliser, donc dans de nombreux cas, nous pouvons essayer différentes combinaisons pour trouver le modèle le plus approprié.

Un dernier point : toutes les données ne se prêtent pas à la classification KNN. Lorsque les données ne sont pas bien séparées (c'est-à-dire que les données avec des étiquettes différentes se chevauchent beaucoup), les performances de kNN seront médiocres. À ce stade, nous devons envisager de changer de modèle 数据工程/Data Engineeringou d'ajouter des informations supplémentaires aux données pour séparer les étiquettes.

code

Après avoir compris le principe, nous pouvons utiliser Python pour implémenter l'algorithme de classification kNN ci-dessus.

Nous importons d’abord les bibliothèques requises.

import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np

L'ensemble de données que nous avons utilisé cette fois est sklearninclus dans le package et est utilisé pour classer les fleurs d'iris. Les données ont un total de 150 lignes et 4 colonnes. L'ensemble des caractéristiques comprend la longueur et la largeur des pétales et des sépales de la fleur. L'ensemble d'étiquettes est l'espèce à laquelle appartient l'iris (Setosa/Mountain Iris, Versicolour/iris panaché , Virginie/iris de Virginie). ).

from sklearn.datasets import load_iris 
iris = load_iris() # 从sklearn中引入数据集

iris_df = pd.DataFrame(iris.data, columns=iris.feature_names) # 创建DataFrame

iris_df['Iris species'] = iris.target # 在DataFrame里加入标签集
print(iris_df) # 看看长什么样

L'image ci-dessous montre la sortie du code ci-dessus. Nous pouvons voir que l'ensemble de fonctionnalités a quatre fonctionnalités (c'est-à-dire les quatre premières colonnes du DataFrame) et que l'ensemble d'étiquettes est l'espèce d'iris représentée par les nombres.
Trame de données
Nous pouvons faire une visualisation simple. seabornC'est une bibliothèque de dessins très utile qui peut nous faire gagner du temps en dessinant différentes permutations et combinaisons de variables. le code s'affiche comme ci-dessous :

import seaborn as sb

sb.set(style="ticks", color_codes=True) # 设置视觉效果

g = sb.pairplot(iris_df, hue="Iris species", diag_kind='hist')

On peut voir que l'image ci-dessous est le résultat dessiné par seaborn. À partir de la figure, nous pouvons observer la relation entre différentes variables. Comme mentionné ci-dessus, kNN doit avoir des classes d'étiquettes séparables. Dans l’ensemble, la classe 0 est bien séparée des autres classes, mais il semble y avoir un certain chevauchement entre les classes 1 et 2. On peut deviner à partir de cette simple observation que le modèle aura une précision plus élevée dans la classification de la classe 0 et une précision plus faible entre les classes 1 et 2.
qn
Ensuite, nous formons le modèle. La formation du modèle est également très simple, comme suit :

from sklearn.neighbors import KNeighborsClassifier
neighbors_num = 10 # 考虑的邻居数量
weights = 'uniform' # 多数决规则

classifier = KNeighborsClassifier(n_neighbors=neighbors_num, weights=weights)

classifier.fit(iris.data, iris.target) # 学习数据

Notre modèle a été entraîné, réfléchissons maintenant à la manière d'évaluer ses performances. sklearnLa méthode utilisée s'appelle 0-1损失函数/Zero-one Loss. Pour faire simple, la classification correcte est enregistrée comme 0 et la classification incorrecte est 1. Additionnez les scores de toutes les classifications et divisez-les par le nombre total de données. La définition est la suivante : E ˉ = 1 m ∑ t
∈ toutes les données 1 clf ( t ) ≠ t \bar{E} = \frac{1}{m}\sum_{t \in all\ data} {\bf 1}_{clf(t) \ne t}Eˉ=m1t toutes les données a t a 1c l f ( t )= t
En d’autres termes, la précision est 1 − E ˉ 1-\bar{E}1Eˉ . On peut l' sklearn.metricsutiliser

from sklearn import metrics 

Y_pred = classifier.predict(iris.data) # 模型预测的标签集

accuracy = metrics.accuracy_score(iris.target, Y_pred)

print('Training accuracy of kNN: {:.3f}'.format(accuracy))
# Training accuracy of kNN: 0.980

On voit que la précision est encore très élevée. Mais comment savoir quelles données sont mal classées ? Nous pouvons 混淆矩阵/Confusion Matrixtirer un jugement intuitif :

from sklearn.metrics import confusion_matrix

def show_confusion_matrix(true_labels, learned_labels, class_names):
	# 用sklearn创建混淆矩阵对象
    cmat = confusion_matrix(true_labels, learned_labels) 
    
	# 设置图像大小
    plt.figure(figsize=(14, 5))
    plt.tick_params(labelsize=8)
    
    # 画出热度图
    hm = sb.heatmap(cmat.T, square=True, annot=True, fmt='d', cbar=True,
                     xticklabels=class_names,
                     yticklabels=class_names, 
                     cmap="seismic", 
                     annot_kws={
    
    "size":12}, cbar_kws={
    
    'label': 'Counts'})

    # 添加图例
    hm.figure.axes[-1].yaxis.label.set_size(10)
    hm.figure.axes[-1].tick_params(labelsize=8)

	# 增加坐标轴标题
    plt.xlabel('True label', fontsize=9)
    plt.ylabel('Predicted label', fontsize=9)
    
    plt.show()

Y_test = iris.target # 真实标签
show_confusion_matrix(Y_test, Y_pred, iris.target_names)

Nous obtenons la matrice de confusion suivante. On peut voir que, tout comme notre hypothèse, le modèle a produit des erreurs lors de la distinction du type 1 (versicolor) et du type 2 (virginica). La précision de notre modèle est déjà assez élevée, mais si la précision est faible, nous devrions envisager d'ajouter davantage d'échantillons de données aux catégories où le modèle est sujet aux erreurs, ou fournir des fonctionnalités plus utiles pour les données (telles que l'épaisseur de la lame, etc. ) .
matrice de confusion
Bien entendu, le nombre choisi ci-dessus k=10est un nombre que nous avons choisi arbitrairement. Y a-t-il un meilleur nombre de voisins ? Nous pouvons essayer différentes valeurs k et 交叉验证/Cross-validationévaluer les performances de différents modèles, comme suit :

from sklearn.model_selection import cross_validate

features = iris.data # 特征集
labels = iris.target # 标签集

k_fold = 10

for k in [1,2,3,4,5,6,7,8,9,10,20,50]:
    classifier = KNeighborsClassifier(n_neighbors=k, weights='uniform')
    classifier.fit(features, labels)

    cv_results = cross_validate(classifier, features, labels, 
                                cv=k_fold, return_train_score=True)

    print('[{}-NN] Mean test score: {:.3f} (std: {:.3f})'
          '\nMean train score: {:.3f} (std: {:.3f})\n'.format(k,
                                                  np.mean(cv_results['test_score']),
                                                  np.std(cv_results['test_score']),
                                                  np.mean(cv_results['train_score']),
                                                  np.std(cv_results['train_score'])))
'''
[1-NN] Mean test score: 0.960 (std: 0.053)
Mean train score: 1.000 (std: 0.000)

[2-NN] Mean test score: 0.953 (std: 0.052)
Mean train score: 0.979 (std: 0.005)

[3-NN] Mean test score: 0.967 (std: 0.045)
Mean train score: 0.961 (std: 0.007)

[4-NN] Mean test score: 0.967 (std: 0.045)
Mean train score: 0.964 (std: 0.007)

[5-NN] Mean test score: 0.967 (std: 0.045)
Mean train score: 0.969 (std: 0.007)

[6-NN] Mean test score: 0.967 (std: 0.045)
Mean train score: 0.973 (std: 0.008)

[7-NN] Mean test score: 0.967 (std: 0.045)
Mean train score: 0.973 (std: 0.006)

[8-NN] Mean test score: 0.967 (std: 0.045)
Mean train score: 0.980 (std: 0.006)

[9-NN] Mean test score: 0.973 (std: 0.033)
Mean train score: 0.979 (std: 0.006)

[20-NN] Mean test score: 0.980 (std: 0.031)
Mean train score: 0.974 (std: 0.013)

[50-NN] Mean test score: 0.927 (std: 0.036)
Mean train score: 0.933 (std: 0.017)
'''

Comme le montre ce qui précède, k=1il semble être le modèle le mieux entraîné, mais dans ce cas, il est évident que le modèle est surajusté, car la précision d'entraînement du modèle est bien supérieure à la précision de validation. k=50La précision était bien inférieure car nous n'avions pas suffisamment d'échantillons (seulement 150) et considérions trop de voisins, ce qui rendait la prise de décision du modèle plus trompeuse. Nous devrions faire de notre mieux pour en choisir un avec une précision de formation et de vérification élevée et une petite différence, k=9c'est donc un meilleur choix.

Conclusion

K-均值聚类/K-means ClusteringDans le prochain blog, le blogueur présentera comment l'implémenter à l'aide d'algorithmes dans l'apprentissage non supervisé 分类/Classification. Si vous avez des questions ou des suggestions, n'hésitez pas à commenter ou à envoyer un message privé. Le codage n’est pas facile. Si vous aimez le contenu du blogueur, aimez-le et soutenez-le !

Je suppose que tu aimes

Origine blog.csdn.net/EricFrenzy/article/details/131468505
conseillé
Classement