Guía de aprendizaje automático de Python desde cero (3) - Clasificación kNN de aprendizaje supervisado

introducir

Este blog combinará ejemplos para presentar 监督学习/Supervised Learning/SLotra gran rama: 分类/Classification. Para ser precisos, el algoritmo de clasificación que utilizaremos es 邻近算法/k-nearest neighbors/kNN.

Preparación antes de empezar

Antes de comenzar, asegúrese de tener los siguientes paquetes en su entorno Python:
pandas, numpy, .sklearnseaborn

Todo el código de este artículo se puede ejecutar Anacondaen formato Jupyter Lab.

texto

分类/Classification¿Cuál es la naturaleza del problema?
Repasemos los temas tratados en el blog anterior 回归/Regression. La esencia del problema de regresión es encontrar una recta de regresión para puntos de datos desconocidos que pueda predecirlos con mayor precisión. Por ejemplo, dada alguna variable continua como entrada, podemos obtener la variable continua como salida.

Los problemas de clasificación son similares y requieren encontrar un modelo que pueda describir con mayor precisión la relación entre conjuntos de características y conjuntos de etiquetas. Pero la diferencia es que los conjuntos de etiquetas de los problemas de clasificación son todos variables no continuas. Por ejemplo, dada la edad de una persona, ésta sólo puede clasificarse como adulta o menor de edad; ante una fotografía con un animal, debemos identificar y distinguir con precisión el tipo de animal. En otras palabras, el problema de clasificación puede entenderse como, para el mapeo desconocido fff
f : R norte ↦ L f:\mathbb{R}^n\mapsto \mathbb{L}F:RnorteL
, lo tenemos定义域/Domain(R n \mathbb{R}^nRn es el conjunto de características) y对应域/Codomain(L \mathbb{L}L es una serie de conjuntos de etiquetas). Queremos utilizar los datos existentes para encontrar el modelo que mejor se ajuste a los datos. Cabe señalar que el conjunto de etiquetasL \mathbb{L}L es un conjunto finito. Por lo tanto, la diferencia con la función de regresión es que la función de clasificación puede ser非参数模型/nonparametric function, es decir, no requiere parámetros (como el conjunto de pesosw en la regresión lineal \bf ww ) puede lograr la clasificación de datos. El ejemplo más simple es el algoritmo KNN que se presentará en este artículo.

¿Qué es KNN? ¿Cómo logra la clasificación?
Podemos encontrar la respuesta por su nombre k-nearest neighbors: para un nuevo punto de datos, el algoritmo determinará a qué etiqueta de datos está más cerca, similar a "el que está cerca del rojo es rojo, el que está cerca de la tinta es negro". " Cuando vemos algo que nunca antes habíamos visto, los humanos lo comparamos con lo más parecido que hayamos visto.

Para una nueva característica de datos x = [ x 1 x 2 … xn ] x=[x_1\ x_2\ \dots \ x_n]X=[ x1 X2  Xnorte] , el algoritmo kNN necesita considerarkkk vecinos más cercanos a las características de los datos y utilice las etiquetas de estos vecinos para determinar la etiqueta de los nuevos datos. En otras palabras, dibujamos una bola N-dimensional con los datos desconocidos de entrada como el centro de la bola, de modo que los puntos de datos en la bola sean exactamentekkk , luego kkdentro de la pelotaLos k puntos son los vecinos más cercanos de los datos de entrada que el algoritmo debe considerar. Generalmente existen dos métodos de juicio:

  1. 多数决规则/Majority Rule. Se seleccionará la etiqueta que tenga más etiquetas entre los vecinos, si hay empate se elegirá la etiqueta de forma aleatoria. En el siguiente ejemplo, los datos del signo de interrogación se clasificarán como B cuando k=3 y como A cuando k=7.
    regla de la mayoría
  2. 基于距离的规则/Distance-based Rule. Los vecinos que están más cerca tienen un peso mayor: cuanto más cerca estén, mayor será el peso. Finalmente se selecciona la etiqueta con la media ponderada más alta. En el gráfico inferior derecho, los datos verdes están más cerca de los datos del signo de interrogación, por lo que tienen un mayor peso a la hora de determinar la etiqueta de datos del signo de interrogación.
    reglas basadas en la distancia

Para implementar la segunda regla y determinar los vecinos más cercanos, también necesitamos definir una medida de distancia. Para dos características de datos xxx y y y , la distancia ddentre los dosd tiene las siguientes definiciones:
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}|re ( x ,y )=yo = 1norte∣x _yoyyo . Para dos puntos en el plano, esta fórmula calcula dos puntosxxx y y La suma de las diferencias de las coordenadas y (la suma de las longitudes de los lados rectángulos del triángulo rectángulo en la figura siguiente).
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}re ( x ,y )=yo = 1norte∣x _yoyyo2 . Para dos puntos en el plano, esta fórmula calcula la distancia en línea recta entre los dos puntos (la longitud de la hipotenusa del triángulo rectángulo en la figura siguiente).
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|re ( x ,y )=máximo1 yo norte∣x _yoyyo .. Para dos puntos en el plano, esta fórmula calcula dos puntosxxx y y El valor máximo de la diferencia de coordenadas y (el lado rectángulo más largo del triángulo rectángulo en la figura siguiente).
fórmula de distancia
De lo anterior también podemos ver que KNN es un modelo非参数模型/nonparametric function, porque la decisión del modelo no depende del peso óptimo, sino de todos los datos de entrada. Por lo tanto, para mantener la autenticidad y la exhaustividad de los datos, los modelos kNN suelen ser de mayor tamaño.

El modelo 超参/Hyperparameterssolo tiene el numero de vecinos kkk , y tenemos que decidir qué regla de determinación de etiquetas y método de cálculo de distancia usar, por lo que en muchos casos podemos probar diferentes combinaciones para encontrar el modelo más adecuado.

Un último punto: no todos los datos son adecuados para la clasificación KNN. Cuando los datos no están bien separados (es decir, los datos con diferentes etiquetas se superponen mucho), el rendimiento de kNN será deficiente. En este momento, debemos considerar cambiar un modelo 数据工程/Data Engineeringo agregar información adicional a los datos para separar etiquetas.

código

Después de comprender el principio, podemos usar Python para implementar el algoritmo de clasificación kNN anterior.

Primero importamos las bibliotecas requeridas.

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

El conjunto de datos que utilizamos esta vez está sklearnincluido en el paquete y se utiliza para clasificar las flores de iris. Los datos tienen un total de 150 filas y 4 columnas. El conjunto de características incluye el largo y ancho de los pétalos y sépalos de la flor. El conjunto de etiquetas es la especie a la que pertenece el iris (Setosa/Mountain Iris, Versicolor/variegated iris , Virginica/Virginia iris). ).

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) # 看看长什么样

La siguiente imagen muestra el resultado del código anterior. Podemos ver que el conjunto de características tiene cuatro características (es decir, las primeras cuatro columnas del DataFrame) y el conjunto de etiquetas son las especies de iris representadas por los números.
Marco de datos
Podemos hacer una visualización sencilla. seabornEs una biblioteca de dibujo muy útil que puede ahorrarnos tiempo al dibujar diferentes permutaciones y combinaciones de variables. El código se muestra a continuación:

import seaborn as sb

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

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

Podemos ver que la imagen a continuación es el resultado dibujado por seaborn. En la figura podemos observar la relación entre diferentes variables. Como se mencionó anteriormente, kNN debe tener clases de etiquetas separables. En general, la clase 0 está bien separada de las otras clases, pero parece haber cierta superposición entre las clases 1 y 2. Podemos adivinar a partir de esta simple observación que el modelo tendrá una mayor precisión al clasificar la clase 0 y una menor precisión entre las clases 1 y 2.
alguien
A continuación entrenamos el modelo. Entrenar el modelo también es muy simple, de la siguiente manera:

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

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

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

Nuestro modelo ha sido entrenado, ahora pensemos en cómo evaluar su desempeño. sklearnEl método utilizado se llama 0-1损失函数/Zero-one Loss. En pocas palabras, la clasificación correcta se registra como 0 y la clasificación incorrecta es 1. Sume las puntuaciones de todas las clasificaciones y divídalas por el número total de datos. La definición es la siguiente:
E ˉ = 1 m ∑ t ∈ todos los datos 1 clf ( t ) ≠ t \bar{E} = \frac{1}{m}\sum_{t \in all\ data} {\bf 1}_{clf(t) \ne t}miˉ=metro1t todos los d un t un 1cl f ( t ) _= t
En otras palabras, la precisión es 1 − E ˉ 1-\bar{E}1miˉ . Podemos sklearn.metricsusarlo

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

Se puede ver que la precisión sigue siendo muy alta. Pero ¿cómo sabemos qué datos están mal clasificados? Podemos 混淆矩阵/Confusion Matrixsacar un juicio intuitivo:

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)

Obtenemos la siguiente matriz de confusión. Se puede observar que, al igual que nuestra suposición, el modelo produjo algunos errores al distinguir el tipo 1 (versicolor) y el tipo 2 (virginica). La precisión de nuestro modelo ya es bastante alta, pero si la precisión es baja, deberíamos considerar agregar más muestras de datos a las categorías donde el modelo es propenso a errores, o proporcionar características más útiles para los datos (como el grosor de la hoja, etc.). ).
matriz de confusión
Por supuesto, el número elegido arriba k=10es un número que elegimos arbitrariamente. ¿Hay mejor número de vecinos? Podemos probar diferentes valores de k y 交叉验证/Cross-validationevaluar el rendimiento de diferentes modelos, de la siguiente manera:

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)
'''

Como se puede ver en lo anterior, k=1parece ser el mejor entrenado, pero en este caso es obvio que el modelo está sobreajustado, porque la precisión del entrenamiento del modelo es mucho mayor que la precisión de la validación. k=50La precisión fue mucho menor porque no teníamos suficientes muestras (solo 150) y consideramos demasiados vecinos, lo que provocó que la toma de decisiones del modelo fuera más engañosa. Deberíamos hacer todo lo posible para elegir uno con alta precisión de entrenamiento y verificación y pequeña diferencia, por lo que k=9es una mejor opción.

Conclusión

K-均值聚类/K-means ClusteringEn el próximo blog, el blogger presentará cómo implementarlo utilizando algoritmos en el aprendizaje no supervisado 分类/Classification. Si tienes alguna pregunta o sugerencia, no dudes en comentar o enviar un mensaje privado. Codificar no es fácil. Si te gusta el contenido del blogger, ¡dale me gusta y apóyalo!

Supongo que te gusta

Origin blog.csdn.net/EricFrenzy/article/details/131468505
Recomendado
Clasificación