Guía del algoritmo de vecinos más cercanos K en Python y Scikit-Learn

En esta guía definitiva detallada, aprenda cómo funciona K-Nearest Neighbors y cómo implementarlo para la regresión, clasificación y detección de anomalías con Python y Scikit-Learn, a través de ejemplos prácticos de código y mejores prácticas.

Introducción

El algoritmo K-vecinos más cercanos (KNN) es un tipo de algoritmo de aprendizaje automático supervisado que se utiliza para la clasificación, la regresión y la detección de valores atípicos. Es extremadamente fácil de implementar en su forma más básica, pero puede realizar tareas bastante complejas. Es un algoritmo de aprendizaje perezoso ya que no tiene una fase de entrenamiento especializada. Más bien, utiliza todos los datos para el entrenamiento mientras clasifica (o retrocede) un nuevo punto de datos o instancia.

KNN es un algoritmo de aprendizaje no paramétrico, lo que significa que no asume nada sobre los datos subyacentes. Esta es una característica extremadamente útil ya que la mayoría de los datos del mundo real en realidad no siguen ninguna suposición teórica, p. separabilidad lineal, distribución uniforme, etc.

En esta guía, veremos cómo se puede implementar KNN con la biblioteca Scikit-Learn de Python. Antes de eso, primero exploraremos cómo podemos usar KNN y explicaremos la teoría detrás de esto. Después de eso, echaremos un vistazo al conjunto de datos de vivienda de California que usaremos para ilustrar el algoritmo KNN y varias de sus variaciones. En primer lugar, veremos cómo implementar el algoritmo KNN para la regresión, seguido de implementaciones de la clasificación KNN y la detección de valores atípicos. Al final, concluiremos con algunos de los pros y los contras del algoritmo.

¿Cuándo debe usar KNN?

Suponga que desea alquilar un apartamento y recientemente descubrió que el vecino de su amigo podría alquilar su apartamento en 2 semanas. Dado que el apartamento aún no está en un sitio web de alquiler, ¿cómo podría tratar de estimar su valor de alquiler?

Digamos que tu amigo paga $1,200 de alquiler. El valor de tu alquiler puede rondar ese número, pero los apartamentos no son exactamente iguales (orientación, área, calidad de los muebles, etc.), por lo que sería bueno tener más datos sobre otros apartamentos.

Al preguntar a otros vecinos y mirar los apartamentos del mismo edificio que se enumeraron en un sitio web de alquiler, los tres alquileres de apartamentos vecinos más cercanos son $ 1200, \ $ 1210, \ $ 1210 y \ $ 1215. Esos apartamentos están en el mismo bloque y piso que el apartamento de tu amigo.

Otros departamentos, que están más alejados, en el mismo piso, pero en otro bloque tienen rentas de $1,400, $1,430, $1,500 y $1,470. Parece que son más caros debido a que tienen más luz del sol por la noche.

Teniendo en cuenta la proximidad del apartamento, parece que el alquiler estimado rondaría los $1210. ¡Esa es la idea general de lo que hace el algoritmo K-vecinos más cercanos (KNN)! Clasifica o retrocede nuevos datos en función de su proximidad a los datos ya existentes.

Traducir el ejemplo a teoría

Cuando el valor estimado es un número continuo, como el valor del alquiler, KNN se usa para la regresión. Pero también podríamos dividir los apartamentos en categorías según el alquiler mínimo y máximo, por ejemplo. Cuando el valor es discreto, lo que lo convierte en una categoría, KNN se usa para clasificación.

También existe la posibilidad de estimar qué vecinos son tan diferentes a los demás que probablemente dejarán de pagar el alquiler. Esto es lo mismo que detectar qué puntos de datos están tan lejos que no encajan en ningún valor o categoría; cuando eso sucede, KNN se usa para la detección de valores atípicos.

En nuestro ejemplo, también conocíamos los alquileres de cada apartamento, lo que significa que nuestros datos estaban etiquetados. KNN utiliza datos previamente etiquetados, lo que lo convierte en un algoritmo de aprendizaje supervisado.

KNN es extremadamente fácil de implementar en su forma más básica y, sin embargo, realiza tareas de clasificación, regresión o detección de valores atípicos bastante complejas.

Cada vez que se agrega un nuevo punto a los datos, KNN usa solo una parte de los datos para decidir el valor (regresión) o la clase (clasificación) de ese punto agregado. Dado que no tiene que volver a mirar todos los puntos, esto lo convierte en un algoritmo de aprendizaje perezoso.

KNN tampoco asume nada sobre las características subyacentes de los datos, no espera que los datos se ajusten a algún tipo de distribución, como uniforme, o que sean linealmente separables. Esto significa que es un algoritmo de aprendizaje no paramétrico. Esta es una característica extremadamente útil ya que la mayoría de los datos del mundo real no siguen ninguna suposición teórica.

Visualización de diferentes usos de la KNN {#visualización de diferentes usos de la knn}

Como se ha demostrado, la intuición detrás del algoritmo KNN es una de las más directas de todos los algoritmos de aprendizaje automático supervisado. El algoritmo primero calcula la distancia de un nuevo punto de datos a todos los demás puntos de datos de entrenamiento.

{.icon aria-hidden=“true”}

Nota: La distancia se puede medir de diferentes maneras. Puede usar una fórmula de Minkowski, euclidiana, Manhattan, Mahalanobis o Hamming, por nombrar algunas métricas. Con datos de alta dimensionalidad, la distancia euclidiana a menudo comienza a fallar (la alta dimensionalidad es ... extraña), y en su lugar se usa la distancia de Manhattan.

Después de calcular la distancia, KNN selecciona una cantidad de puntos de datos más cercanos: 2, 3, 10 o, en realidad, cualquier número entero. ¡Este número de puntos (2, 3, 10, etc.) es la K en K-vecinos más cercanos!

En el paso final, si se trata de una tarea de regresión, KNN calculará la suma ponderada promedio de los K puntos más cercanos para la predicción. Si se trata de una tarea de clasificación, el nuevo punto de datos se asignará a la clase a la que pertenecen la mayoría de los K-puntos más cercanos seleccionados.

Visualicemos el algoritmo en acción con la ayuda de un ejemplo simple. Considere un conjunto de datos con dos variables y una K de 3.

Al realizar una regresión, la tarea es encontrar el valor de un nuevo punto de datos, en función de la suma ponderada promedio de los 3 puntos más cercanos.

KNN con K = 3, cuando se usa para regresión:


El algoritmo KNN comenzará calculando la distancia del nuevo punto desde todos los puntos. Luego encuentra los 3 puntos con la menor distancia al nuevo punto. Esto se muestra en la segunda figura anterior, en la que se han rodeado los tres puntos más cercanos, 47, 58 y 79. Después de eso, calcula la suma ponderada de 47, 58 y 79 - en este caso los pesos son iguales a 1 - estamos considerando todos los puntos como iguales, pero también podríamos asignar diferentes pesos en función de la distancia. Después de calcular la suma ponderada, el nuevo valor de puntos es 61,33.

Y al realizar una clasificación, la tarea de KNN para clasificar un nuevo punto de datos, en la clase "Purple" o "Red".

KNN con K = 3, cuando se usa para la clasificación:


El algoritmo KNN comenzará de la misma manera que antes, calculando la distancia del nuevo punto desde todos los puntos, encontrando los 3 puntos más cercanos con la menor distancia al nuevo punto, y luego, en lugar de calcular un número, asigna el nuevo punto a la clase a la que pertenecen la mayoría de los tres puntos más cercanos, la clase roja. Por lo tanto, el nuevo punto de datos se clasificará como "Rojo".

El proceso de detección de valores atípicos es diferente de los dos anteriores, hablaremos más al respecto cuando lo implementemos después de las implementaciones de regresión y clasificación.

{.icon aria-hidden=“true”}

Nota: El código proporcionado en este tutorial se ha ejecutado y probado con el siguiente cuaderno de Jupyter.

El conjunto de datos de vivienda de Scikit-Learn California

Vamos a utilizar el conjunto de datos de vivienda de California para ilustrar cómo funciona el algoritmo KNN. El conjunto de datos se derivó del censo de EE. UU. de 1990. Una fila del conjunto de datos representa el censo de un grupo de bloques.

En esta sección, repasaremos los detalles del conjunto de datos de vivienda de California, para que pueda obtener una comprensión intuitiva de los datos con los que trabajaremos. Es muy importante conocer sus datos antes de comenzar a trabajar en ellos.

Un grupo de bloque es la unidad geográfica más pequeña para la cual la Oficina del Censo de EE. UU. publica datos de muestra. Además de grupo de bloques, otro término utilizado es hogar, un hogar es un grupo de personas que residen dentro de una casa.

El conjunto de datos consta de nueve atributos:

  • MedInc - ingreso medio en grupo de bloque
  • HouseAge - edad media de la casa en un grupo de bloque
  • AveRooms - el número promedio de habitaciones (proporcionadas por hogar)
  • AveBedrms - el número promedio de dormitorios (proporcionado por hogar)
  • Población - población del grupo de bloque
  • AveOccup - el número promedio de miembros del hogar
  • Latitud - latitud del grupo de bloques
  • Longitud - longitud del grupo de bloques
  • MedHouseVal - valor medio de la vivienda en los distritos de California (cientos de miles de dólares)

El conjunto de datos ya forma parte de la biblioteca Scikit-Learn, solo necesitamos importarlo y cargarlo como un marco de datos:

1
2
3
4
5
from sklearn.datasets import fetch_california_housing
# as_frame=True loads the data in a dataframe format, with other metadata besides it
california_housing = fetch_california_housing(as_frame=True)
# Select only the dataframe part and assign it to the df variable
df = california_housing.frame

Al importar los datos directamente desde Scikit-Learn, importa más que solo las columnas y los números e incluye la descripción de los datos como un objeto ‘Bunch’, por lo que solo extrajimos el ‘marco’. Más detalles del conjunto de datos están disponibles aquí.

Importemos Pandas y echemos un vistazo a las primeras filas de datos:

1
2
import pandas as pd
df.head()

Ejecutar el código mostrará las primeras cinco filas de nuestro conjunto de datos:

1
2
3
4
5
6
    MedInc  HouseAge  AveRooms  AveBedrms  Population  AveOccup   Latitude  Longitude  MedHouseVal
0   8.3252  41.0      6.984127  1.023810   322.0       2.555556   37.88     -122.23    4.526
1   8.3014  21.0      6.238137  0.971880   2401.0      2.109842   37.86     -122.22    3.585
2   7.2574  52.0      8.288136  1.073446   496.0       2.802260   37.85     -122.24    3.521
3   5.6431  52.0      5.817352  1.073059   558.0       2.547945   37.85     -122.25    3.413
4   3.8462  52.0      6.281853  1.081081   565.0       2.181467   37.85     -122.25    3.422

En esta guía, utilizaremos MedInc, HouseAge, AveRooms, AveBedrms, Population, AveOccup, Latitude, Longitude para predecir MedHouseVal. Algo similar a nuestra narrativa de motivación.

Pasemos ahora directamente a la implementación del algoritmo KNN para la regresión.

Regresión con K-vecinos más cercanos con Scikit-Learn

Hasta ahora, conocemos nuestro conjunto de datos y ahora podemos continuar con otros pasos en el algoritmo KNN.

Preprocesamiento de datos para la regresión KNN

El preprocesamiento es donde aparecen las primeras diferencias entre las tareas de regresión y clasificación. Dado que esta sección trata sobre la regresión, prepararemos nuestro conjunto de datos en consecuencia.

Para la regresión, necesitamos predecir otro valor medio de la casa. Para hacerlo, asignaremos MedHouseVal a y y todas las demás columnas a X simplemente soltando MedHouseVal:

1
2
y = df['MedHouseVal']
X = df.drop(['MedHouseVal'], axis = 1)

Al observar las descripciones de nuestras variables, podemos ver que tenemos diferencias en las medidas. Para evitar adivinar, usemos el método describe() para verificar:

1
2
# .T transposes the results, transforming rows into columns
X.describe().T

Esto resulta en:

1
2
3
4
5
6
7
8
9
            count     mean         std          min         25%         50%         75%         max
MedInc      20640.0   3.870671     1.899822     0.499900    2.563400    3.534800    4.743250    15.000100
HouseAge    20640.0   28.639486    12.585558    1.000000    18.000000   29.000000   37.000000   52.000000
AveRooms    20640.0   5.429000     2.474173     0.846154    4.440716    5.229129    6.052381    141.909091
AveBedrms   20640.0   1.096675     0.473911     0.333333    1.006079    1.048780    1.099526    34.066667
Population  20640.0   1425.476744  1132.462122  3.000000    787.000000  1166.000000 1725.000000 35682.000000
AveOccup    20640.0   3.070655     10.386050    0.692308    2.429741    2.818116    3.282261    1243.333333
Latitude    20640.0   35.631861    2.135952     32.540000   33.930000   34.260000   37.710000   41.950000
Longitude   20640.0   -119.569704  2.003532    -124.350000 -121.800000  -118.490000 -118.010000 -114.310000

Aquí, podemos ver que el valor “promedio” de “MedInc” es aproximadamente “3,87” y el valor “promedio” de “HouseAge” es aproximadamente “28,64”, lo que lo hace 7,4 veces mayor que “MedInc”. Otras características también tienen diferencias en la media y la desviación estándar; para ver eso, mire los valores media y std y observe cómo están distantes entre sí. Para MedInc, std es aproximadamente 1.9, para HouseAge, std es 12.59 y lo mismo se aplica a las otras características.

Estamos usando un algoritmo basado en la distancia y los algoritmos basados ​​en la distancia sufren mucho con los datos que no están en la misma escala, como estos datos. La escala de los puntos puede (y en la práctica casi siempre lo hace) distorsionar la distancia real entre valores.

Para realizar el Feature Scaling, usaremos la clase StandardScaler de Scikit-Learn más adelante. Si aplicamos la escala en este momento (antes de una división de prueba de tren), el cálculo incluiría datos de prueba, efectivamente filtrando información de datos de prueba en el resto de la canalización. Desafortunadamente, este tipo de fuga de datos suele pasarse por alto, lo que da como resultado hallazgos irreproducibles o ilusorios.

{.icon aria-hidden=“true”}

Advice: If you'd like to learn more about feature scaling - read our "Características de escalado de datos con Scikit-Learn para aprendizaje automático en Python"

División de datos en conjuntos de entrenamiento y prueba

Para poder escalar nuestros datos sin fugas, pero también para evaluar nuestros resultados y evitar el ajuste excesivo, dividiremos nuestro conjunto de datos en divisiones de entrenamiento y prueba.

Una forma sencilla de crear divisiones de entrenamiento y prueba es el método train_test_split de Scikit-Learn. La división no se divide linealmente en algún punto, sino que muestra X% e Y% aleatoriamente. Para hacer que este proceso sea reproducible (para que el método siempre muestree los mismos puntos de datos), estableceremos el argumento random_state en una cierta SEED:

1
2
3
4
from sklearn.model_selection import train_test_split

SEED = 42
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=SEED)

Este fragmento de código muestra el 75 % de los datos para entrenamiento y el 25 % de los datos para pruebas. Al cambiar test_size a 0.3, por ejemplo, podría entrenar con el 70% de los datos y probar con el 30%.

Al usar el 75 % de los datos para entrenamiento y el 25 % para pruebas, de 20640 registros, el conjunto de entrenamiento contiene 15480 y el conjunto de prueba contiene 5160. Podemos inspeccionar esos números rápidamente al imprimir las longitudes del conjunto de datos completo y de los datos divididos :

1
2
3
len(X)       # 20640
len(X_train) # 15480
len(X_test)  # 5160

¡Excelente! Ahora podemos ajustar el escalador de datos en el conjunto X_train y escalar tanto X_train como X_test sin filtrar ningún dato de X_test a X_train.

{.icon aria-hidden=“true”}

Consejo: Si desea obtener más información sobre el método train_test_split(), la importancia de una división de validación de prueba de entrenamiento, así como también cómo separar los conjuntos de validación, lea nuestro \ “train_test_split() de Scikit-Learn - Conjuntos de entrenamiento, prueba y validación".

Escalado de funciones para la regresión KNN

Al importar ‘StandardScaler’, instanciarlo, ajustarlo de acuerdo con nuestros datos de tren (previniendo fugas) y transformar los conjuntos de datos de prueba y tren, podemos realizar escalado de características:

1
2
3
4
5
6
7
8
9
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
# Fit only on X_train
scaler.fit(X_train)

# Scale both X_train and X_test
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

{.icon aria-hidden=“true”}

Nota: Dado que a menudo llamará a scaler.fit(X_train) seguido de scaler.transform(X_train), puede llamar a un único scaler.fit_transform(X_train) seguido de scaler. transform(X_test) para acortar la llamada.

¡Ahora nuestros datos están escalados! El escalador mantiene solo los puntos de datos, y no los nombres de las columnas, cuando se aplica en un DataFrame. Organicemos los datos en un DataFrame nuevamente con nombres de columnas y usemos describe() para observar los cambios en mean y std:

1
2
3
col_names=['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup', 'Latitude', 'Longitude']
scaled_df = pd.DataFrame(X_train, columns=col_names)
scaled_df.describe().T

Esto nos dará:

1
2
3
4
5
6
7
8
9
            count       mean            std         min         25%         50%         75%         max
MedInc      15480.0     2.074711e-16    1.000032    -1.774632   -0.688854   -0.175663   0.464450    5.842113
HouseAge    15480.0     -1.232434e-16   1.000032    -2.188261   -0.840224   0.032036    0.666407    1.855852
AveRooms    15480.0     -1.620294e-16   1.000032    -1.877586   -0.407008   -0.083940   0.257082    56.357392
AveBedrms   15480.0     7.435912e-17    1.000032    -1.740123   -0.205765   -0.108332   0.007435    55.925392
Population  15480.0     -8.996536e-17   1.000032    -1.246395   -0.558886   -0.227928   0.262056    29.971725
AveOccup    15480.0     1.055716e-17    1.000032    -0.201946   -0.056581   -0.024172   0.014501    103.737365
Latitude    15480.0     7.890329e-16    1.000032    -1.451215   -0.799820   -0.645172   0.971601    2.953905
Longitude   15480.0     2.206676e-15    1.000032    -2.380303   -1.106817   0.536231    0.785934    2.633738

Observe cómo todas las desviaciones estándar ahora son 1 y las medias se han vuelto más pequeñas. ¡Esto es lo que hace que nuestros datos sean más uniformes! Entrenemos y evalúemos un regresor basado en KNN.

Entrenamiento y predicción de la regresión KNN {#entrenamiento y predicción de la regresión knn}

La API intuitiva y estable de Scikit-Learn hace que el entrenamiento de regresores y clasificadores sea muy sencillo. Vamos a importar la clase KNeighborsRegressor desde el módulo sklearn.neighbors, crear una instancia y ajustarla a nuestros datos de tren:

1
2
3
from sklearn.neighbors import KNeighborsRegressor
regressor = KNeighborsRegressor(n_neighbors=5)
regressor.fit(X_train, y_train)

En el código anterior, n_neighbors es el valor de K, o el número de vecinos que el algoritmo tendrá en cuenta para elegir un nuevo valor medio de la casa. 5 es el valor predeterminado para KNeighborsRegressor(). No hay un valor ideal para K y se selecciona después de la prueba y la evaluación; sin embargo, para empezar, 5 es un valor de uso común para KNN y, por lo tanto, se estableció como el valor predeterminado.

El paso final es hacer predicciones sobre nuestros datos de prueba. Para hacerlo, ejecute el siguiente script:

1
y_pred = regressor.predict(X_test)

Ahora podemos evaluar qué tan bien se generaliza nuestro modelo a los nuevos datos para los que tenemos etiquetas (verdad básica): ¡el conjunto de prueba!

Evaluación del algoritmo para la regresión KNN

Las métricas de regresión más utilizadas para evaluar el algoritmo son el error absoluto medio (MAE), el error cuadrático medio (MSE), el error cuadrático medio (RMSE) y el coeficiente de determinación (R^2^):

  1. Error absoluto medio (MAE): cuando restamos los valores pronosticados de los valores reales, obtenemos los errores, sumamos los valores absolutos de esos errores y obtenemos su media. Esta métrica da una noción del error global para cada predicción del modelo, cuanto menor (más cercano a 0) mejor:

$$
mae = (\frac{1}{n})\sum_{i=1}^{n}\left | Real - Predicho \right |
$$

{.icon aria-hidden=“true”}

Nota: También puede encontrar la notación y y ŷ (léase como y-hat) en las ecuaciones. La y se refiere a los valores reales y la ŷ a los valores predichos.

  1. Mean Squared Error (MSE): Es similar a la métrica MAE, pero eleva al cuadrado los valores absolutos de los errores. Además, al igual que con MAE, cuanto más pequeño o más cercano a 0, mejor. El valor de MSE se eleva al cuadrado para que los errores grandes sean aún mayores. Una cosa a la que hay que prestar mucha atención es que suele ser una métrica difícil de interpretar debido al tamaño de sus valores y al hecho de que no están en la misma escala que los datos.

$$
mse = \sum_{i=1}^{D}(Real - Predicho)^2
$$

  1. Root Mean Squared Error (RMSE): Intenta resolver el problema de interpretación planteado con el MSE obteniendo la raíz cuadrada de su valor final, para escalarlo a las mismas unidades de los datos. Es más fácil de interpretar y bueno cuando necesitamos mostrar o mostrar el valor real de los datos con el error. Muestra cuánto pueden variar los datos, por lo que, si tenemos un RMSE de 4,35, nuestro modelo puede cometer un error porque agregó 4,35 al valor real o porque necesitó 4,35 para llegar al valor real. Cuanto más cerca de 0, mejor también.

$$
rmse = \sqrt{ \sum_{i=1}^{D}(Real - Predicho)^2}
$$

Los métodos mean_absolute_error() y mean_squared_error() de sklearn.metrics se pueden usar para calcular estas métricas, como se puede ver en el siguiente fragmento:

1
2
3
4
5
6
7
8
9
from sklearn.metrics import mean_absolute_error, mean_squared_error

mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = mean_squared_error(y_test, y_pred, squared=False)

print(f'mae: {mae}')
print(f'mse: {mse}')
print(f'rmse: {rmse}')

La salida del script anterior se ve así:

1
2
3
mae: 0.4460739527131783 
mse: 0.4316907430948294 
rmse: 0.6570317671884894

El R^2^ se puede calcular directamente con el método score():

1
regressor.score(X_test, y_test)

Qué salidas:

1
0.6737569252627673

Los resultados muestran que el error general y el error medio de nuestro algoritmo KNN están alrededor de 0.44 y 0.43. Además, el RMSE muestra que podemos ir por encima o por debajo del valor real de los datos sumando 0.65 o restando 0.65. ¿Qué tan bueno es eso?

Veamos cómo se ven los precios:

1
y.describe()
1
2
3
4
5
6
7
8
9
count    20640.000000
mean         2.068558
std          1.153956
min          0.149990
25%          1.196000
50%          1.797000
75%          2.647250
max          5.000010
Name: MedHouseVal, dtype: float64

La media es 2,06 y la desviación estándar de la media es 1,15, por lo que nuestra puntuación de ~0,44 no es realmente estelar, pero no es tan mala.

Con el R^2^, cuanto más cerca estemos de 1 (o 100), mejor. El R^2^ indica cuántos cambios en los datos, o varianza de datos, están siendo entendidos o explicados por KNN.

$$
R^2 = 1 - \frac{\sum(Real - Predicho)^2}{\sum(Real - Real \ Media)^2}
$$

Con un valor de 0.67, podemos ver que nuestro modelo explica el 67% de la varianza de los datos. Ya es más del 50%, lo cual está bien, pero no es muy bueno. ¿Hay alguna manera de que podamos hacerlo mejor?

Hemos usado una K predeterminada con un valor de 5, por lo tanto, estamos usando 5 vecinos para predecir nuestros objetivos, que no es necesariamente el mejor número. Para entender cuál sería un número ideal de Ks, podemos analizar los errores de nuestro algoritmo y elegir el K que minimice la pérdida.

Encontrar la mejor K para la regresión KNN

Idealmente, vería qué métrica se ajusta más a su contexto, pero generalmente es interesante probar todas las métricas. Siempre que puedas probarlos todos, hazlo. Aquí, le mostraremos cómo elegir la mejor K usando solo el error absoluto medio, pero puede cambiarlo a cualquier otra métrica y comparar los resultados.

Para ello, crearemos un bucle for y ejecutaremos modelos que tengan de 1 a X vecinos. En cada interacción, calcularemos el MAE y trazaremos el número de K junto con el resultado del MAE:

1
2
3
4
5
6
7
8
9
error = []

# Calculating MAE error for K values between 1 and 39
for i in range(1, 40):
    knn = KNeighborsRegressor(n_neighbors=i)
    knn.fit(X_train, y_train)
    pred_i = knn.predict(X_test)
    mae = mean_absolute_error(y_test, pred_i)
    error.append(mae)

Ahora, grafiquemos los ’errores’:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import matplotlib.pyplot as plt 

plt.figure(figsize=(12, 6))
plt.plot(range(1, 40), error, color='red', 
         linestyle='dashed', marker='o',
         markerfacecolor='blue', markersize=10)
         
plt.title('K Value MAE')
plt.xlabel('K Value')
plt.ylabel('Mean Absolute Error')

Mirando la gráfica, parece que el valor MAE más bajo es cuando K es 12. Echemos un vistazo más de cerca a la trama para asegurarnos de trazar menos datos:

1
2
3
4
5
6
7
plt.figure(figsize=(12, 6))
plt.plot(range(1, 15), error[:14], color='red', 
         linestyle='dashed', marker='o',
         markerfacecolor='blue', markersize=10)
plt.title('K Value MAE')
plt.xlabel('K Value')
plt.ylabel('Mean Absolute Error')

También puede obtener el error más bajo y el índice de ese punto utilizando la función integrada min() (funciona en listas) o convertir la lista en una matriz NumPy y obtener el argmin() (índice del elemento con el valor más bajo):

1
2
3
4
import numpy as np 

print(min(error))               # 0.43631325936692505
print(np.array(error).argmin()) # 11

Comenzamos a contar vecinos en 1, mientras que las matrices se basan en 0, por lo que el índice 11 es 12 vecinos.

Esto significa que necesitamos 12 vecinos para poder predecir un punto con el error MAE más bajo. Podemos ejecutar el modelo y las métricas nuevamente con 12 vecinos para comparar resultados:

1
2
3
4
5
6
7
8
9
knn_reg12 = KNeighborsRegressor(n_neighbors=12)
knn_reg12.fit(X_train, y_train)
y_pred12 = knn_reg12.predict(X_test)
r2 = knn_reg12.score(X_test, y_test) 

mae12 = mean_absolute_error(y_test, y_pred12)
mse12 = mean_squared_error(y_test, y_pred12)
rmse12 = mean_squared_error(y_test, y_pred12, squared=False)
print(f'r2: {r2}, \nmae: {mae12} \nmse: {mse12} \nrmse: {rmse12}')

El siguiente código genera:

1
2
3
4
r2: 0.6887495617137436, 
mae: 0.43631325936692505 
mse: 0.4118522151025172 
rmse: 0.6417571309323467

Con 12 vecinos, nuestro modelo KNN ahora explica el 69 % de la varianza de los datos y ha perdido un poco menos, pasando de 0,44 a 0,43, 0,43 a 0,41 y 0,65 a 0,64 con las respectivas métricas. No es una mejora muy grande, pero es una mejora, no obstante.

{.icon aria-hidden=“true”}

Nota: Avanzando más en este análisis, realizar un Análisis exploratorio de datos (EDA) junto con un análisis residual puede ayudar a seleccionar características y lograr mejores resultados.

Ya hemos visto cómo usar KNN para la regresión, pero ¿qué pasaría si quisiéramos clasificar un punto en lugar de predecir su valor? Ahora, podemos ver cómo usar KNN para la clasificación.

Clasificación usando K-vecinos más cercanos con Scikit-Learn

En esta tarea, en lugar de predecir un valor continuo, queremos predecir la clase a la que pertenecen estos grupos de bloques. Para hacer eso, podemos dividir el valor medio de la vivienda de los distritos en grupos con diferentes rangos de valor de la vivienda o contenedores.

Cuando desee utilizar un valor continuo para la clasificación, normalmente puede agrupar los datos. De esta forma, puede predecir grupos, en lugar de valores.

Preprocesamiento de datos para clasificación {#preprocesamiento de datos para clasificación}

Vamos a crear los contenedores de datos para transformar nuestros valores continuos en categorías:

1
2
# Creating 4 categories and assigning them to a MedHouseValCat column
df["MedHouseValCat"] = pd.qcut(df["MedHouseVal"], 4, retbins=False, labels=[1, 2, 3, 4])

Luego, podemos dividir nuestro conjunto de datos en sus atributos y etiquetas:

1
2
y = df['MedHouseValCat']
X = df.drop(['MedHouseVal', 'MedHouseValCat'], axis = 1)

Dado que hemos utilizado la columna MedHouseVal para crear contenedores, debemos eliminar la columna MedHouseVal y las columnas MedHouseValCat de X. De esta manera, el DataFrame contendrá las primeras 8 columnas del conjunto de datos (es decir, atributos, características) mientras que nuestra y contendrá solo la etiqueta asignada MedHouseValCat.

{.icon aria-hidden=“true”}

Nota: También puede seleccionar columnas usando .iloc() en lugar de soltarlas. Al soltar, solo tenga en cuenta que necesita asignar valores y antes de asignar valores X, porque no puede asignar una columna eliminada de un DataFrame a otro objeto en la memoria.

División de datos en conjuntos de entrenamiento y prueba

Como se ha hecho con la regresión, también dividiremos el conjunto de datos en divisiones de entrenamiento y prueba. Como tenemos datos diferentes, necesitamos repetir este proceso:

1
2
3
4
from sklearn.model_selection import train_test_split

SEED = 42
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=SEED)

Usaremos el valor estándar de Scikit-Learn de 75 % de datos de entrenamiento y 25 % de datos de prueba nuevamente. Esto significa que tendremos el mismo número de registros de tren y prueba que en la regresión anterior.

Escalado de características para clasificación

Dado que estamos tratando con el mismo conjunto de datos sin procesar y sus diferentes unidades de medida, volveremos a realizar el escalado de características, de la misma manera que lo hicimos con nuestros datos de regresión:

1
2
3
4
5
6
7
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaler.fit(X_train)

X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

Entrenamiento y predicción para la clasificación {#entrenamiento y predicción para la clasificación}

Después de agrupar, dividir y escalar los datos, finalmente podemos colocar un clasificador en ellos. Para la predicción, usaremos 5 vecinos nuevamente como línea de base. También puede instanciar la clase KNeighbors_ sin ningún argumento y automáticamente usará 5 vecinos. Aquí, en lugar de importar KNeighborsRegressor, importaremos la clase KNeighborsClassifier:

1
2
3
4
from sklearn.neighbors import KNeighborsClassifier

classifier = KNeighborsClassifier()
classifier.fit(X_train, y_train)

Después de ajustar KNeighborsClassifier, podemos predecir las clases de los datos de prueba:

1
y_pred = classifier.predict(X_test)

¡Es hora de evaluar las predicciones! ¿Sería la predicción de clases un mejor enfoque que la predicción de valores en este caso? Evaluemos el algoritmo para ver qué sucede.

Evaluación de KNN para la clasificación

Para evaluar el clasificador KNN, también podemos usar el método score, pero ejecuta una métrica diferente ya que estamos calificando un clasificador y no un regresor. La métrica básica para la clasificación es la “precisión”: describe cuántas predicciones acertó nuestro clasificador. El valor de precisión más bajo es 0 y el más alto es 1. Normalmente multiplicamos ese valor por 100 para obtener un porcentaje.

$$
precisión = \frac{\text{número de predicciones correctas}}{\text{número total de predicciones}}
$$

{.icon aria-hidden=“true”}

Nota: Es extremadamente difícil obtener una precisión del 100 % en cualquier dato real, si eso sucede, tenga en cuenta que podría estar ocurriendo alguna fuga o algo incorrecto; no hay consenso sobre un valor de precisión ideal y también es contexto -dependiente. Dependiendo del costo del error (qué tan malo es si confiamos en el clasificador y resulta que está equivocado), una tasa de error aceptable podría ser del 5%, 10% o incluso del 30%.

Vamos a puntuar nuestro clasificador:

1
2
acc =  classifier.score(X_test, y_test)
print(acc) # 0.6191860465116279

Al observar el puntaje resultante, podemos deducir que nuestro clasificador acertó ~62% de nuestras clases. Esto ya ayuda en el análisis, aunque con solo saber lo que acertó el clasificador es difícil mejorarlo.

Hay 4 clases en nuestro conjunto de datos: ¿qué pasa si nuestro clasificador acertó 90% de las clases 1, 2 y 3, pero solo 30% de la clase 4 correcta?

Una falla sistémica de alguna clase, a diferencia de una falla equilibrada compartida entre clases, puede generar una puntuación de precisión del 62 %. La precisión no es una métrica realmente buena para la evaluación real, pero sirve como un buen indicador. La mayoría de las veces, con conjuntos de datos equilibrados, una precisión del 62% se distribuye de manera relativamente uniforme. Además, la mayoría de las veces, los conjuntos de datos no están equilibrados, por lo que estamos de vuelta en el punto de partida y la precisión es una métrica insuficiente.

Podemos profundizar en los resultados usando otras métricas para poder determinar eso. Este paso también es diferente de la regresión, aquí usaremos:

  1. Matriz de Confusión: Para saber cuánto acertamos o fallamos en cada clase. Los valores que fueron correctos y se pronosticaron correctamente se denominan verdaderos positivos; los que se pronosticaron como positivos pero no lo fueron se denominan falsos positivos. La misma nomenclatura de verdaderos negativos y falsos negativos se utiliza para valores negativos;
  2. Precisión: Para entender qué valores de predicción correctos fueron considerados correctos por nuestro clasificador. La precisión dividirá esos valores positivos verdaderos por todo lo que se predijo como positivo;

$$
precisión = \frac{\text{verdadero positivo}}{\text{verdadero positivo} + \text{falso positivo}}
$$

  1. Recordar: para entender cuántos de los verdaderos positivos fueron identificados por nuestro clasificador. El recuerdo se calcula dividiendo los verdaderos positivos por cualquier cosa que debería haber sido pronosticada como positiva.

$$
recordar = \frac{\text{verdadero positivo}}{\text{verdadero positivo} + \text{falso negativo}}
$$

  1. Puntuación F1: Es la media equilibrada o armónica de precisión y recuperación. El valor más bajo es 0 y el más alto es 1. Cuando f1-score es igual a 1, significa que todas las clases se predijeron correctamente; esta es una puntuación muy difícil de obtener con datos reales (casi siempre existen excepciones).

$$
\text{puntuación f1} = 2* \frac{\text{precisión} * \text{recordar}}{\text{precisión} + \text{recordar}}
$$

{.icon aria-hidden=“true”}

Nota: También existe un puntaje F1 ponderado, y es solo un F1 que no aplica el mismo peso a todas las clases. El peso generalmente lo dictan las clases soporte: cuántas instancias "soportan" la puntuación F1 (la proporción de etiquetas que pertenecen a una determinada clase). Cuanto menor sea el soporte (menos instancias de una clase), menor será el F1 ponderado para esa clase, porque es menos confiable.

Los métodos confusion_matrix() y classification_report() del módulo sklearn.metrics se pueden usar para calcular y mostrar todas estas métricas. La confusion_matrix se visualiza mejor usando un mapa de calor. El informe de clasificación ya nos brinda exactitud, precisión, recordación y f1-score, pero también puede importar cada una de estas métricas desde sklearn.metrics.

Para obtener métricas, ejecute el siguiente fragmento:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from sklearn.metrics import classification_report, confusion_matrix
#importing Seaborn's to use the heatmap 
import seaborn as sns

# Adding classes names for better interpretation
classes_names = ['class 1','class 2','class 3', 'class 4']
cm = pd.DataFrame(confusion_matrix(yc_test, yc_pred), 
                  columns=classes_names, index = classes_names)
                  
# Seaborn's heatmap to better visualize the confusion matrix
sns.heatmap(cm, annot=True, fmt='d');

print(classification_report(y_test, y_pred))

La salida del script anterior se ve así:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
              precision    recall  f1-score   support

           1       0.75      0.78      0.76      1292
           2       0.49      0.56      0.53      1283
           3       0.51      0.51      0.51      1292
           4       0.76      0.62      0.69      1293

    accuracy                           0.62      5160
   macro avg       0.63      0.62      0.62      5160
weighted avg       0.63      0.62      0.62      5160

Los resultados muestran que KNN pudo clasificar todos los 5160 registros en el conjunto de prueba con un 62 % de precisión, lo que está por encima del promedio. Los soportes son bastante iguales (distribución uniforme de clases en el conjunto de datos), por lo que el F1 ponderado y el F1 no ponderado serán aproximadamente iguales.

También podemos ver el resultado de las métricas para cada una de las 4 clases. A partir de eso, podemos notar que la “clase 2” tenía la precisión más baja, la “recuperación” más baja y la “puntuación f1” más baja. La clase 3 está justo detrás de la clase 2 por tener las puntuaciones más bajas, y luego tenemos la clase 1 con las mejores puntuaciones, seguida de la clase 4.

Al observar la matriz de confusión, podemos ver que:

  • clase 1 se confundió principalmente con clase 2 en 238 casos
  • clase 2 para clase 1 en 256 entradas, y para clase 3 en 260 casos
  • clase 3 se confundió principalmente con clase 2, 374 entradas, y clase 4, en 193 casos
  • La “clase 4” se clasificó erróneamente como “clase 3” en 339 entradas y como “clase 2” en 130 casos.

Además, observe que la diagonal muestra los verdaderos valores positivos, al mirarla, es fácil ver que la “clase 2” y la “clase 3” tienen los valores predichos menos correctos.

Con esos resultados, podríamos profundizar en el análisis inspeccionándolos más para descubrir por qué sucedió eso, y también comprender si 4 clases son la mejor manera de agrupar los datos. Quizás los valores de clase 2 y clase 3 estaban demasiado cerca uno del otro, por lo que se hizo difícil diferenciarlos.

Siempre intente probar los datos con un número diferente de contenedores para ver qué sucede.

Además del número arbitrario de contenedores de datos, también hay otro número arbitrario que hemos elegido, el número de K vecinos. La misma técnica que aplicamos a la tarea de regresión se puede aplicar a la clasificación al determinar el número de K que maximizan o minimizan un valor métrico.

Búsqueda de la mejor K para la clasificación KNN

Repitamos lo que se ha hecho para la regresión y tracemos el gráfico de valores K y la métrica correspondiente para el conjunto de prueba. También puede elegir qué métrica se adapta mejor a su contexto, aquí elegiremos f1-score.

De esta forma, trazaremos el f1-score para los valores pronosticados del conjunto de prueba para todos los valores K entre 1 y 40.

Primero, importamos el f1_score de sklearn.metrics y luego calculamos su valor para todas las predicciones de un clasificador K-Nearest Neighbors, donde K varía de 1 a 40:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from sklearn.metrics import f1_score

f1s = []

# Calculating f1 score for K values between 1 and 40
for i in range(1, 40):
    knn = KNeighborsClassifier(n_neighbors=i)
    knn.fit(X_train, y_train)
    pred_i = knn.predict(X_test)
    # using average='weighted' to calculate a weighted average for the 4 classes 
    f1s.append(f1_score(y_test, pred_i, average='weighted'))

El siguiente paso es graficar los valores f1_score contra los valores K. La diferencia con la regresión es que en lugar de elegir el valor K que minimiza el error, esta vez elegiremos el valor que maximiza el f1-score.

Ejecute el siguiente script para crear la trama:

1
2
3
4
5
6
plt.figure(figsize=(12, 6))
plt.plot(range(1, 40), f1s, color='red', linestyle='dashed', marker='o',
         markerfacecolor='blue', markersize=10)
plt.title('F1 Score K Value')
plt.xlabel('K Value')
plt.ylabel('F1 Score')

El gráfico de salida se ve así:

A partir de la salida, podemos ver que el f1-score es el más alto cuando el valor de K es 15. Volvamos a entrenar nuestro clasificador con 15 vecinos y veamos qué hace con los resultados de nuestro informe de clasificación:

1
2
3
4
classifier15 = KNeighborsClassifier(n_neighbors=15)
classifier15.fit(X_train, y_train)
y_pred15 = classifier15.predict(X_test)
print(classification_report(y_test, y_pred15))

Esto da como resultado:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
              precision    recall  f1-score   support

           1       0.77      0.79      0.78      1292
           2       0.52      0.58      0.55      1283
           3       0.51      0.53      0.52      1292
           4       0.77      0.64      0.70      1293

    accuracy                           0.63      5160
   macro avg       0.64      0.63      0.64      5160
weighted avg       0.64      0.63      0.64      5160

Tenga en cuenta que nuestras métricas han mejorado con 15 vecinos, tenemos un 63 % de precisión y una precisión, recuperación y puntuaciones f1 más altas, pero aún tenemos que mirar más a fondo los contenedores para tratar de entender por qué f1 -score para las clases 2 y 3 sigue siendo bajo.

Además de usar KNN para regresión y determinar valores de bloque y clasificación, para determinar clases de bloque, también podemos usar KNN para detectar qué valores medios de bloque son diferentes de la mayoría, los que no siguen lo que hace la mayoría de los datos. En otras palabras, podemos usar KNN para detectar valores atípicos.

Implementación de KNN para la detección de valores atípicos con Scikit-Learn

La detección de valores atípicos utiliza otro método que difiere de lo que habíamos hecho anteriormente para la regresión y la clasificación.

Aquí, veremos qué tan lejos está cada uno de los vecinos de un punto de datos. Usemos los 5 vecinos predeterminados. Para un punto de datos, calcularemos la distancia a cada uno de los K-vecinos más cercanos. Para hacer eso, importaremos otro algoritmo KNN de Scikit-learn que no es específico para regresión o clasificación llamado simplemente NearestNeighbors.

Después de importar, instanciaremos una clase NearestNeighbors con 5 vecinos; también puede instanciarla con 12 vecinos para identificar valores atípicos en nuestro ejemplo de regresión o con 15, para hacer lo mismo con el ejemplo de clasificación. Luego ajustaremos los datos de nuestro tren y usaremos el método kneighbors() para encontrar nuestras distancias calculadas para cada punto de datos e índices de vecinos:

1
2
3
4
5
6
from sklearn.neighbors import NearestNeighbors

nbrs = NearestNeighbors(n_neighbors = 5)
nbrs.fit(X_train)
# Distances and indexes of the 5 neighbors 
distances, indexes = nbrs.kneighbors(X_train)

Ahora tenemos 5 distancias para cada punto de datos: la distancia entre él y sus 5 vecinos, y un índice que los identifica. Echemos un vistazo a los primeros tres resultados y la forma de la matriz para visualizar esto mejor.

Para ver la forma de las tres primeras distancias, ejecute:

1
distances[:3], distances.shape
1
2
3
4
(array([[0.        , 0.12998939, 0.15157687, 0.16543705, 0.17750354],
        [0.        , 0.25535314, 0.37100754, 0.39090243, 0.40619693],
        [0.        , 0.27149697, 0.28024623, 0.28112326, 0.30420656]]),
 (3, 5))

Observa que hay 3 filas con 5 distancias cada una. También podemos mirar y los índices de los vecinos:

1
indexes[:3], indexes[:3].shape

Esto resulta en:

1
2
3
4
(array([[    0,  8608, 12831,  8298,  2482],
        [    1,  4966,  5786,  8568,  6759],
        [    2, 13326, 13936,  3618,  9756]]),
 (3, 5))

En la salida anterior, podemos ver los índices de cada uno de los 5 vecinos. Ahora, podemos continuar calculando la media de las 5 distancias y trazar un gráfico que cuente cada fila en el eje X y muestre cada distancia media en el eje Y:

1
2
3
4
5
dist_means = distances.mean(axis=1)
plt.plot(dist_means)
plt.title('Mean of the 5 neighbors distances for each data point')
plt.xlabel('Count')
plt.ylabel('Mean Distances')

Observe que hay una parte de la gráfica en la que las distancias medias tienen valores uniformes. Ese punto del eje Y en el que las medias no son demasiado altas ni demasiado bajas es exactamente el punto que debemos identificar para eliminar los valores atípicos.

En este caso, es donde la distancia media es 3. Tracemos de nuevo la gráfica con una línea punteada horizontal para poder localizarla:

1
2
3
4
5
6
dist_means = distances.mean(axis=1)
plt.plot(dist_means)
plt.title('Mean of the 5 neighbors distances for each data point with cut-off line')
plt.xlabel('Count')
plt.ylabel('Mean Distances')
plt.axhline(y = 3, color = 'r', linestyle = '--')

Esta línea marca la distancia media en la que por encima de ella varían todos los valores. Esto significa que todos los puntos con una distancia media por encima de 3 son nuestros valores atípicos. Podemos encontrar los índices de esos puntos usando np.where(). Este método generará Verdadero o Falso para cada índice con respecto a la condición media por encima de 3:

1
2
3
4
5
import numpy as np

# Visually determine cutoff values > 3
outlier_index = np.where(dist_means > 3)
outlier_index

El código anterior genera:

1
2
(array([  564,  2167,  2415,  2902,  6607,  8047,  8243,  9029, 11892,
        12127, 12226, 12353, 13534, 13795, 14292, 14707]),)

Ahora tenemos nuestros índices de puntos atípicos. Ubiquémoslos en el marco de datos:

1
2
3
# Filter outlier values
outlier_values = df.iloc[outlier_index]
outlier_values

Esto resulta en:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
        MedInc  HouseAge AveRooms   AveBedrms   Population  AveOccup    Latitude    Longitude   MedHouseVal
564     4.8711  27.0     5.082811   0.944793    1499.0      1.880803    37.75       -122.24     2.86600
2167    2.8359  30.0     4.948357   1.001565    1660.0      2.597809    36.78       -119.83     0.80300
2415    2.8250  32.0     4.784232   0.979253    761.0       3.157676    36.59       -119.44     0.67600
2902    1.1875  48.0     5.492063   1.460317    129.0       2.047619    35.38       -119.02     0.63800
6607    3.5164  47.0     5.970639   1.074266    1700.0      2.936097    34.18       -118.14     2.26500
8047    2.7260  29.0     3.707547   1.078616    2515.0      1.977201    33.84       -118.17     2.08700
8243    2.0769  17.0     3.941667   1.211111    1300.0      3.611111    33.78       -118.18     1.00000
9029    6.8300  28.0     6.748744   1.080402    487.0       2.447236    34.05       -118.78     5.00001
11892   2.6071  45.0     4.225806   0.903226    89.0        2.870968    33.99       -117.35     1.12500
12127   4.1482  7.0      5.674957   1.106998    5595.0      3.235975    33.92       -117.25     1.24600
12226   2.8125  18.0     4.962500   1.112500    239.0       2.987500    33.63       -116.92     1.43800
12353   3.1493  24.0     7.307323   1.460984    1721.0      2.066026    33.81       -116.54     1.99400
13534   3.7949  13.0     5.832258   1.072581    2189.0      3.530645    34.17       -117.33     1.06300
13795   1.7567  8.0      4.485173   1.120264    3220.0      2.652389    34.59       -117.42     0.69500
14292   2.6250  50.0     4.742236   1.049689    728.0       2.260870    32.74       -117.13     2.03200
14707   3.7167  17.0     5.034130   1.051195    549.0       1.873720    32.80       -117.05     1.80400

Nuestra detección de valores atípicos ha terminado. Así es como detectamos cada punto de datos que se desvía de la tendencia general de datos. Podemos ver que hay 16 puntos en los datos de nuestro tren que deben analizarse, investigarse, quizás tratarse o incluso eliminarse de nuestros datos (si se ingresaron erróneamente) para mejorar los resultados. Esos puntos podrían haber sido el resultado de errores de tipeo, inconsistencias en los valores medios de los bloques, o incluso ambos.

Ventajas y desventajas de KNN

En esta sección, presentaremos algunos de los pros y los contras de usar el algoritmo KNN.

Ventajas

  • Es fácil de implementar.
  • Es un algoritmo de aprendizaje perezoso y, por lo tanto, no requiere entrenamiento en todos los puntos de datos (solo usa los vecinos K-Nearest para predecir). Esto hace que el algoritmo KNN sea mucho más rápido que otros algoritmos que requieren entrenamiento con todo el conjunto de datos, como Máquinas de vectores de soporte, regresión lineal, etc.
  • Dado que KNN no requiere capacitación antes de hacer predicciones, se pueden agregar nuevos datos sin problemas
  • Solo se requieren dos parámetros para trabajar con KNN, es decir, el valor de K y la función de distancia

Contras

  • El algoritmo KNN no funciona bien con datos dimensionales altos porque con una gran cantidad de dimensiones, la distancia entre puntos se vuelve "extraña", y las métricas de distancia que usamos no se sostienen
  • Finalmente, el algoritmo KNN no funciona bien con características categóricas ya que es difícil encontrar la distancia entre dimensiones con características categóricas.

Yendo más lejos: proyecto de extremo a extremo portátil

{.icon aria-hidden=“true”}

¿Tu naturaleza inquisitiva te hace querer ir más allá? Recomendamos consultar nuestro Proyecto guiado: ["Predicción práctica del precio de la vivienda: aprendizaje automático en Python"](https://wikihtp.com/courses/hands-on-house-price- predicción-aprendizaje-máquina-en-python/#cta){target="_blank”}.

[](https://wikihtp.com/ cursos/predicción-de-precio-de-la-casa-práctica-aprendizaje-de-máquina-en-python/#cta)

En este proyecto guiado, aprenderá cómo crear potentes modelos tradicionales de aprendizaje automático, así como modelos de aprendizaje profundo, utilizar Ensemble Learning y capacitar a los meta-aprendices para predecir los precios de la vivienda a partir de una bolsa de modelos Scikit-Learn y Keras.

Con Keras, la API de aprendizaje profundo creada sobre Tensorflow, experimentaremos con arquitecturas, crearemos un conjunto de modelos apilados y entrenaremos una red neuronal meta-aprendizaje (modelo de nivel 1) para determinar el precio de un casa.

El aprendizaje profundo es asombroso, pero antes de recurrir a él, se recomienda intentar resolver el problema con técnicas más simples, como algoritmos de aprendizaje superficial . Nuestro rendimiento de referencia se basará en un algoritmo Random Forest Regression . Además, exploraremos la creación de conjuntos de modelos a través de Scikit-Learn mediante técnicas como embalaje y votación.

Este es un proyecto integral y, como todos los proyectos de aprendizaje automático, comenzaremos con Análisis exploratorio de datos, seguido de Preprocesamiento de datos y finalmente Creación de modelos de aprendizaje superficial y Deep Learning para adaptarse los datos que hemos explorado y limpiado previamente.

Conclusión

KNN es un algoritmo simple pero poderoso. Se puede utilizar para muchas tareas, como regresión, clasificación o detección de valores atípicos.

KNN se ha utilizado ampliamente para encontrar similitudes de documentos y reconocimiento de patrones. También se ha empleado para desarrollar sistemas de recomendación y para la reducción de la dimensionalidad y los pasos de preprocesamiento para la visión por computadora, en particular las tareas de reconocimiento facial.

En esta guía, hemos pasado por la regresión, la clasificación y la detección de valores atípicos utilizando la implementación de Scikit-Learn del algoritmo K-Nearest Neighbor. eighbor.