Capítulo 27 Introducción a machine learning

Quizás las metodologías de ciencia de datos más populares provienen del campo de machine learning. Las historias de éxito de machine learning incluyen lectores de códigos postales escritos a mano implementados por el servicio postal, tecnología de reconocimiento de voz como Siri de Apple, sistemas de recomendación de películas, detectores de spam y malware, automóviles sin conductor y predictores de precios de viviendas. Aunque hoy en día los términos Inteligencia Artificial y machine learning se usan indistintamente, hacemos la siguiente distinción: mientras que los primeros algoritmos de inteligencia artificial, como esos utilizados por las máquinas de ajedrez, implementaron la toma de decisiones según reglas programables derivadas de la teoría o de los primeros principios, en machine learning las decisiones de aprendizaje se basan en algoritmos que se construyen con datos.

27.1 Notación

En machine learning, los datos se presentan en forma de:

  1. el resultado (outcome en inglés) que queremos predecir y
  2. los atributos (features en inglés) que usaremos para predecir el resultado.

Queremos construir un algoritmo que tome los valores de los atributos como entrada y devuelva una predicción para el resultado cuando no sabemos el resultado. El enfoque de machine learning consiste en entrenar un algoritmo utilizando un set de datos para el cual conocemos el resultado y luego usar este algoritmo en el futuro para hacer una predicción cuando no sabemos el resultado.

Aquí usaremos \(Y\) para denotar el resultado y \(X_1, \dots, X_p\) para denotar atributos. Tengan en cuenta que los atributos a veces se denominan predictores o covariables. Consideramos estos sinónimos.

Los problemas de predicción se pueden dividir en resultados categóricos y continuos. Para resultados categóricos, \(Y\) puede ser cualquiera de \(K\) clases. El número de clases puede variar mucho entre distintas aplicaciones. Por ejemplo, en los datos del lector de dígitos, \(K=10\) con las clases representando los dígitos 0, 1, 2, 3, 4, 5, 6, 7, 8 y 9. En el reconocimiento de voz, los resultados son todas las palabras o frases posibles que estamos tratando de detectar. La detección de spam tiene dos resultados: spam o no spam. En este libro, denotamos las categorías \(K\) con índices \(k=1,\dots,K\). Sin embargo, para datos binarios usaremos \(k=0,1\) para conveniencias matemáticas que demostraremos más adelante.

La configuración general es la siguiente. Tenemos una serie de características y un resultado desconocido que queremos predecir:

outcome feature 1 feature 2 feature 3 feature 4 feature 5
? \(X_1\) \(X_2\) \(X_3\) \(X_4\) \(X_5\)

Para construir un modelo que provee una predicción para cualquier conjunto de valores observados \(X_1=x_1,X_2=x_2,\dots X_5=x_5\), recolectamos datos para los cuales conocemos el resultado:

outcome feature 1 feature 2 feature 3 feature 4 feature 5
\(y_{1}\) \(x_{1,1}\) \(x_{1,2}\) \(x_{1,3}\) \(x_{1,4}\) \(x_{1,5}\)
\(y_{2}\) \(x_{2,1}\) \(x_{2,2}\) \(x_{2,3}\) \(x_{2,4}\) \(x_{2,5}\)
\(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\)
\(y_n\) \(x_{n,1}\) \(x_{n,2}\) \(x_{n,3}\) \(x_{n,4}\) \(x_{n,5}\)

Cuando el resultado es continuo, nos referimos a la tarea de machine learning como predicción. El resultado principal del modelo es una función \(f\) que produce automáticamente una predicción, denotada con \(\hat{y}\), para cualquier conjunto de predictores: \(\hat{y} = f(x_1, x_2, \dots, x_p)\). Usamos el término resultado real (actual outcome en inglés) para denotar lo que acabamos observando. Entonces queremos que la predicción \(\hat{y}\) coincida con resultado real \(y\) lo mejor posible. Debido a que nuestro resultado es continuo, nuestras predicciones \(\hat{y}\) no serán exactamente correctas o incorrectas, sino que determinaremos un error definido como la diferencia entre la predicción y el resultado real \(y - \hat{y}\).

Cuando el resultado es categórico, nos referimos a la tarea de machine learning como clasificación. El resultado principal de este modelo será una regla de decisión (decision rule en inglés) que determina cuál de las \(K\) clases debemos predecir. En esta situación, la mayoría de los modelos provee funciones de los predictores para cada clase \(k\), \(f_k(x_1, x_2, \dots, x_p)\), que se utilizan para tomar esta decisión. Cuando los datos son binarios, una regla de decisión típica sería algo como: si \(f_1(x_1, x_2, \dots, x_p) > C\), pronostique la categoría 1, si no, pronostique la otra categoría, con \(C\) un umbral predeterminado. Debido a que los resultados son categóricos, nuestras predicciones serán correctas o incorrectas.

Tengan en cuenta que estos términos varían entre cursos, libros de texto y otras publicaciones. A menudo, el término predicción se usa tanto para resultados categóricos como continuos y el término regresión puede usarse para el caso continuo. Aquí no usamos el término regresión para evitar confusión con nuestro uso previo del término regresión lineal. En la mayoría de los casos, estará claro si nuestros resultados son categóricos o continuos, por lo que evitaremos usar estos términos cuando sea posible.

27.2 Un ejemplo

Consideremos el ejemplo del lector de código postal. El primer paso para manejar el correo en la oficina de correos es organizar las cartas por código postal:

Originalmente, los humanos tenían que clasificarlos a mano. Para hacer esto, tuvieron que leer los códigos postales de cada sobre. Hoy, gracias a los algoritmos de machine learning, una computadora puede leer códigos postales y luego un robot clasifica las cartas. En esta parte del libro, aprenderemos cómo construir algoritmos que puedan leer un dígito.

El primer paso para construir un algoritmo es entender cuáles son los resultados y los atributos. A continuación hay tres imágenes de dígitos escritos. Estos ya han sido leídos por un humano y se les ha asignado un resultado \(Y\). Por lo tanto, se consideran conocidos y sirven como set de entrenamiento.

Las imágenes se convierten en \(28 \times 28 = 784\) píxeles y, para cada píxel, obtenemos una intensidad de escala de grises entre 0 (blanco) y 255 (negro), que consideramos continua por ahora. El siguiente gráfico muestra los atributos individuales de cada imagen:

Para cada imagen digitalizada \(i\), tenemos un resultado categórico \(Y_i\) que puede ser uno de los 10 valores (\(0,1,2,3,4,5,6,7,8,9\)) y atributos \(X_{i,1}, \dots, X_{i,784}\). Usamos negrilla \(\mathbf{X}_i = (X_{i,1}, \dots, X_{i,784})\) para distinguir el vector de predictores de los predictores individuales. Cuando nos referimos a un conjunto arbitrario de atributos en lugar de una imagen específica en nuestro set de datos, descartamos el índice \(i\) y usamos \(Y\) y \(\mathbf{X} = (X_{1}, \dots, X_{784})\). Utilizamos variables en mayúsculas porque, en general, pensamos en los predictores como variables aleatorias. Usamos minúsculas, por ejemplo \(\mathbf{X} = \mathbf{x}\), para denotar valores observados. Cuando codificamos usamos minúsculas.

La tarea de machine learning es construir un algoritmo que devuelva una predicción para cualquiera de los posibles valores de los atributos. Aquí, aprenderemos varios enfoques para construir estos algoritmos. Aunque en este momento puede parecer imposible lograr esto, comenzaremos con ejemplos sencillos y desarrollaremos nuestro conocimiento hasta que podamos atacar algunos más complejos. De hecho, comenzamos con un ejemplo artificialmente sencillo con un solo predictor y luego pasamos a un ejemplo un poco más realista con dos predictores. Una vez que comprendamos estos, atacaremos algunos retos de machine learning del mundo real que involucran muchos predictores.

27.3 Ejercicios

1. Para cada uno de los siguientes ejemplos, determine si el resultado es continuo o categórico:

  1. Lector de dígitos
  2. Recomendaciones de películas
  3. Filtro de spam
  4. Hospitalizaciones
  5. Siri (reconocimiento de voz)

2. ¿Cuántas funciones tenemos disponibles para la predicción en el set de datos de dígitos?

3. En el ejemplo del lector de dígitos, los resultados se almacenan aquí:

library(dslabs)
mnist <- read_mnist()
y <- mnist$train$labels

¿Las siguientes operaciones tienen un significado práctico?

y[5] + y[6]
y[5] > y[6]

Eliga la mejor respuesta:

  1. Sí, porque \(9 + 2 = 11\) y \(9 > 2\).
  2. No, porque y no es un vector numérico.
  3. No, porque 11 no es un dígito. Son dos dígitos.
  4. No, porque estas son etiquetas que representan una categoría, no un número. Un 9 representa una clase, no el número 9.

27.4 Métricas de evaluación

Antes de comenzar a describir enfoques para optimizar la forma en que construimos algoritmos, primero debemos definir a qué nos referimos cuando decimos que un enfoque es mejor que otro. En esta sección, nos centramos en describir las formas en que se evalúan los algoritmos de machine learning. Específicamente, necesitamos cuantificar lo que queremos decir con “mejor”.

Para nuestra primera introducción a los conceptos de machine learning, comenzaremos con un ejemplo aburrido y sencillo: cómo predecir sexo basado en altura. A medida que explicamos machine learning paso a paso, este ejemplo nos permitirá establecer el primer componente básico. Muy pronto, estaremos atacando desafíos más interesantes. Utilizamos el paquete caret, que tiene varias funciones útiles para construir y evaluar métodos de machine learning. Presentamos los detalles de este paquete en el Capítulo 30.

library(tidyverse)
library(caret)

Como primer ejemplo, usamos los datos de altura en dslabs:

library(dslabs)
data(heights)

Comenzamos definiendo el resultado y los predictores.

y <- heights$sex
x <- heights$height

En este caso, solo tenemos un predictor, altura, mientras que y es claramente un resultado categórico ya que los valores observados son Male o Female. Sabemos que no podremos predecir \(Y\) de forma precisa basado en \(X\) porque las alturas promedio masculinas y femeninas no son tan diferentes en relación con la variabilidad dentro del grupo. ¿Pero podemos hacerlo mejor que con simplemente adivinar? Para responder a esta pregunta, necesitamos una definición cuantitativa de “mejor”.

27.4.1 Sets de entrenamiento y de evaluación

En última instancia, un algoritmo de machine learning se evalúa basado en cómo funciona en el mundo real con sets de datos completamente nuevos. Sin embargo, cuando desarrollamos un algoritmo, generalmente tenemos un set de datos para el cual conocemos los resultados, como lo hacemos con las alturas: sabemos el sexo de cada estudiante en nuestro set de datos. Por lo tanto, para imitar el proceso de evaluación final, generalmente dividimos los datos en dos partes y actuamos como si no supiéramos el resultado de una de estas. Dejamos de fingir que no conocemos el resultado para evaluar el algoritmo, pero solo después de haber terminado de construirlo. Nos referimos al grupo para el que conocemos el resultado y que usamos para desarrollar el algoritmo como el set de entrenamiento (training set en inglés). Nos referimos al grupo para el que aparentamos no conocer el resultado como el set de evaluación (test set en inglés).

Una forma estándar de generar los sets de entrenamiento y de evaluación es dividiendo aleatoriamente los datos. El paquete caret incluye la función createDataPartition que nos ayuda a generar índices para dividir aleatoriamente los datos en sets de entrenamiento y de evaluación:

set.seed(2007)
test_index <- createDataPartition(y, times = 1, p = 0.5, list = FALSE)

El argumento times se usa para definir cuántas muestras aleatorias de índices devolver, el argumento p se utiliza para definir qué proporción de los datos está representada por el índice y el argumento list se usa para decidir si queremos que los índices se devuelvan como una lista o no. Podemos usar el resultado de la llamada a la función createDataPartition para definir los sets de entrenamiento y de evaluación de esta manera:

test_set <- heights[test_index, ]
train_set <- heights[-test_index, ]

Ahora desarrollaremos un algoritmo usando solo el set de entrenamiento. Una vez que hayamos terminado de desarrollar el algoritmo, lo congelaremos y lo evaluaremos utilizando el set de evaluación. La forma más sencilla de evaluar el algoritmo cuando los resultados son categóricos es simplemente informar la proporción de casos que se predijeron correctamente en el set de evaluación. Esta métrica generalmente se conoce como exactitud general (overall accuracy en inglés).

27.4.2 Exactitud general

Para demostrar el uso de la exactidud general, crearemos dos algoritmos diferentes y los compararemos.

Comencemos desarrollando el algoritmo más sencillo posible: adivinar el resultado.

y_hat <- sample(c("Male", "Female"), length(test_index), replace = TRUE)

Tengan en cuenta que estamos ignorando completamente el predictor y simplemente adivinando el sexo.

En las aplicaciones de machine learning, es útil usar factores para representar los resultados categóricos porque las funciones de R desarrolladas para machine learning, como las del paquete caret, requieren o recomiendan que los resultados categóricos se codifiquen como factores. Para convertir y_hat en factores podemos usar la función factor:

y_hat <- sample(c("Male", "Female"), length(test_index), replace = TRUE) |>
  factor(levels = levels(test_set$sex))

La exactidud general se define simplemente como la proporción general que se predice correctamente:

mean(y_hat == test_set$sex)
#> [1] 0.51

No es sorprendente que nuestra exactidud sea 50%. ¡Estamos adivinando!

¿Podemos mejorarla? El análisis de datos exploratorios sugiere que sí porque, en promedio, los hombres son un poco más altos que las mujeres:

heights |> group_by(sex) |> summarize(mean(height), sd(height))
#> # A tibble: 2 × 3
#>   sex    `mean(height)` `sd(height)`
#>   <fct>           <dbl>        <dbl>
#> 1 Female           64.9         3.76
#> 2 Male             69.3         3.61

Pero, ¿cómo usamos esta información? Probemos con otro enfoque sencillo: predecir Male si la altura está dentro de dos desviaciones estándar del hombre promedio.

y_hat <- ifelse(x > 62, "Male", "Female") |>
  factor(levels = levels(test_set$sex))

La exactidud aumenta de 0.50 a aproximadamente 0.80:

mean(y == y_hat)
#> [1] 0.793

¿Pero podemos mejorarla aún más? En el ejemplo anterior, utilizamos un umbral de 62, pero podemos examinar la exactidud obtenida para otros umbrales y luego elegir el valor que provee los mejores resultados. Sin embargo, recuerden que es importante que optimicemos el umbral utilizando solo el set de entrenamiento: el set de evaluación es solo para evaluación. Aunque para este ejemplo sencillo no es un problema, más adelante aprenderemos que evaluar un algoritmo en el set de entrenamiento puede resultar en un sobreajuste (overfitting en inglés), que a menudo resulta en evaluaciones peligrosamente sobre optimistas.

Aquí examinamos la exactidud de 10 umbrales diferentes y elegimos el que produce el mejor resultado:

cutoff <- seq(61, 70)
accuracy <- map_dbl(cutoff, function(x){
  y_hat <- ifelse(train_set$height > x, "Male", "Female") |>
    factor(levels = levels(test_set$sex))
  mean(y_hat == train_set$sex)
})

Podemos hacer un gráfico que muestra la exactitud obtenida en el set de entrenamiento para hombres y mujeres:

Vemos que el valor máximo es:

max(accuracy)
#> [1] 0.85

que es mucho más grande que 0.5. El umbral que resulta en esta exactitud es:

best_cutoff <- cutoff[which.max(accuracy)]
best_cutoff
#> [1] 64

Ahora podemos evaluar el uso de este umbral en nuestro set de evaluaciones para asegurarnos de que nuestra exactitud no sea demasiado optimista:

y_hat <- ifelse(test_set$height > best_cutoff, "Male", "Female") |>
  factor(levels = levels(test_set$sex))
y_hat <- factor(y_hat)
mean(y_hat == test_set$sex)
#> [1] 0.804

Vemos que es un poco más baja que la exactitud observada para el set de entrenamiento, pero aún es mejor que adivinar. Y al probar en un set de datos en el que no entrenamos, sabemos que nuestro resultado no se debe a que se haya elegido para dar un buen resultado en el set de evaluación.

27.4.3 Matriz de confusión

La regla de predicción que desarrollamos en la sección anterior predice Male si el alumno es más alto que 64 pulgadas. Dado que la mujer promedio es aproximadamente 64 pulgadas, esta regla de predicción parece incorrecta. ¿Que pasó? Si la altura de un estudiante es la de la mujer promedio, ¿no deberíamos predecir Female?

En términos generales, la exactitud general puede ser una medida engañosa. Para ver esto, comenzaremos construyendo lo que se conoce como matriz de confusión (confusion matrix en inglés), que básicamente tabula cada combinación de predicción y valor real. Podemos hacer esto en R usando la función table:

table(predicted = y_hat, actual = test_set$sex)
#>          actual
#> predicted Female Male
#>    Female     48   32
#>    Male       71  374

Si estudiamos esta tabla detenidamente, revela un problema. Si calculamos la exactitud por separado para cada sexo, obtenemos:

test_set |>
  mutate(y_hat = y_hat) |>
  group_by(sex) |>
  summarize(accuracy = mean(y_hat == sex))
#> # A tibble: 2 × 2
#>   sex    accuracy
#>   <fct>     <dbl>
#> 1 Female    0.403
#> 2 Male      0.921

Hay un desequilibrio en la exactitud para hombres y mujeres: se predice que demasiadas mujeres son hombres. ¡Estamos prediciendo que casi la mitad de las mujeres son hombres! ¿Cómo es que nuestra exactitud general sea tan alta? Esto se debe a que la prevalencia de los hombres en este set de datos es alta. Estas alturas se obtuvieron de tres cursos de ciencias de datos, dos de los cuales tenían más hombres matriculados:

prev <- mean(y == "Male")
prev
#> [1] 0.773

Entonces, al calcular la exactitud general, el alto porcentaje de errores cometidos prediciendo cuales son mujeres se ve superado por las ganancias en las predicciones acertadas para los hombres. Esto puede ser un gran problema en machine learning. Si sus datos de entrenamiento están sesgados de alguna manera, es probable que también desarrolle algoritmos sesgados. El hecho de que hayamos utilizado un set de evaluación no importa porque también se deriva del set de datos sesgado original. Esta es una de las razones por las que observamos métricas distintas de la exactitud general al evaluar un algoritmo de machine learning.

Hay varias métricas que podemos usar para evaluar un algoritmo de manera que la prevalencia no afecte nuestra evaluación y todas estas pueden derivarse de la matriz de confusión. Una forma general de mejorar el uso de la exactitud general es estudiar la sensibilidad y la especificidad por separado.

27.4.4 Sensibilidad y especificidad

Para definir la sensibilidad y la especificidad, necesitamos un resultado binario. Cuando los resultados son categóricos, podemos definir estos términos para una categoría específica. En el ejemplo de dígitos, podemos pedir la especificidad en el caso de predecir correctamente 2 en lugar de algún otro dígito. Una vez que especifiquemos una categoría de interés, podemos hablar sobre resultados positivos, \(Y=1\), y resultados negativos, \(Y=0\).

En general, la sensibilidad se define como la capacidad de un algoritmo para predecir un resultado positivo cuando el resultado real es positivo: \(\hat{Y}=1\) cuando \(Y=1\). Un algoritmo que predice que todo es positivo (\(\hat{Y}=1\) pase lo que pase) tiene una sensibilidad perfecta, pero esta métrica por sí sola no es suficiente para evaluar un algoritmo. Por esta razón, también examinamos la especificidad, que generalmente se define como la capacidad de un algoritmo para no predecir un resultado positivo \(\hat{Y}=0\) cuando el resultado real no es positivo \(Y=0\). Podemos resumir de la siguiente manera:

  • Alta sensibilidad: \(Y=1 \implies \hat{Y}=1\)
  • Alta especificidad: \(Y=0 \implies \hat{Y} = 0\)

Aunque lo anterior a menudo se considera la definición de especificidad, otra forma de pensar en la especificidad es por la proporción de predicciones positivas que realmente son positivas:

  • Alta especificidad: \(\hat{Y}=1 \implies Y=1\).

Para ofrecer definiciones precisas, nombramos las cuatro entradas de la matriz de confusión:

Actually Positive Actually Negative
Predicted positive True positives (TP) False positives (FP)
Predicted negative False negatives (FN) True negatives (TN)

Típicamente, la sensibilidad se cuantifica con \(TP/(TP+FN)\), la proporción de positivos verdaderos (la primera columna = \(TP+FN\)) que se predicen ser positivos (\(TP\)). Esta cantidad se conoce como la tasa de positivos verdaderos (true positive rate o TPR por sus siglas en inglés) o recall.

La especificidad se define como \(TN/(TN+FP)\) o la proporción de negativos (la segunda columna = \(FP+TN\)) que se predicen ser negativos (\(TN\)). Esta cantidad también se denomina la tasa de falsos positivos (true negative rate o TNR por sus siglas en inglés). Hay otra forma de cuantificar la especificidad que es \(TP/(TP+FP)\) o la proporción de resultados que se predicen ser positivos (la primera fila o \(TP+FP\)) que realmente son positivos (\(TP\)). Esta cantidad se conoce como valor predictivo positivo (positive predictive value o PPV por sus siglas en inglés) y también como precisión. Tengan en cuenta que, a diferencia de TPR y TNR, la precisión depende de la prevalencia. Por ejemplo, una mayor prevalencia implica que se puede obtener una precisión alta aun cuando están adivinando.

Los diferentes nombres pueden ser confusos, por lo que incluimos una tabla para ayudarnos a recordar los términos. La tabla incluye una columna que muestra la definición si pensamos en las proporciones como probabilidades.

Medida de Nombre 1 Nombre 2 Definición Representación de probabilidad
sensibilidad TPR Recall \(\frac{\mbox{TP}}{\mbox{TP} + \mbox{FN}}\) \(\mbox{Pr}(\hat{Y}=1 \mid Y=1)\)
especificidad TNR 1-FPR \(\frac{\mbox{TN}}{\mbox{TN}+\mbox{FP}}\) \(\mbox{Pr}(\hat{Y}=0 \mid Y=0)\)
especificidad PPV Precisión \(\frac{\mbox{TP}}{\mbox{TP}+\mbox{FP}}\) \(\mbox{Pr}(Y=1 \mid \hat{Y}=1)\)

Aquí, TPR es la tasa de positivos verdaderos, FPR es la tasa de falsos positivos y PPV es el valor predictivo positivo. La función confusionMatrix del paquete caret calcula todas estas métricas para nosotros una vez que definamos qué categoría es “positiva”. La función espera factores como entrada y el primer nivel se considera el resultado positivo o \(Y=1\). En nuestro ejemplo, Female es el primer nivel porque viene antes de Male alfabéticamente. Si escriben esto en R, verán varias métricas que incluyen exactitud, sensibilidad, especificidad y PPV.

cm <- confusionMatrix(data = y_hat, reference = test_set$sex)

Pueden acceder a estos directamente, por ejemplo, así:

cm$overall["Accuracy"]
#> Accuracy 
#>    0.804
cm$byClass[c("Sensitivity","Specificity", "Prevalence")]
#> Sensitivity Specificity  Prevalence 
#>       0.403       0.921       0.227

Podemos ver que la alta exactitud general es posible a pesar de la sensibilidad relativamente baja. Como sugerimos anteriormente, la razón por la que esto sucede es debido a la baja prevalencia (0.23): la proporción de mujeres es baja. Como la prevalencia es baja, no predecir mujeres reales como mujeres (baja sensibilidad) no disminuye la exactitud tanto como no predecir hombres reales como hombres (baja especificidad). Este es un ejemplo de por qué es importante examinar la sensibilidad y la especificidad y no solo la exactitud. Antes de aplicar este algoritmo a sets de datos generales, debemos preguntarnos si la prevalencia será la misma.

27.4.5 Exactitud equilibrada y medida \(F_1\)

Aunque generalmente recomendamos estudiar tanto la especificidad como la sensibilidad, a menudo es útil tener un resumen de un número, por ejemplo, para fines de optimización. Una medida que se prefiere sobre la exactitud general es el promedio de especificidad y de sensibilidad, conocida como exactitud equilibrada (balanced accuracy en inglés). Debido a que la especificidad y la sensibilidad son tasas, es más apropiado calcular la media armónica (harmonic average en inglés). De hecho, la medida \(F_1\) (\(F_1\)-score en inglés), un resumen de un número ampliamente utilizado, es la media armónica de precisión y recall:

\[ \frac{1}{\frac{1}{2}\left(\frac{1}{\mbox{recall}} + \frac{1}{\mbox{precision}}\right) } \]

Dado que es más fácil de escribir, a menudo se ve esta media armónica reescrita como:

\[ 2 \times \frac{\mbox{precision} \cdot \mbox{recall}} {\mbox{precision} + \mbox{recall}} \]

cuando se define \(F_1\).

Recuerden que, según el contexto, algunos tipos de errores son más costosos que otros. Por ejemplo, en el caso de la seguridad de los aviones, es mucho más importante maximizar la sensibilidad sobre la especificidad: no predecir el mal funcionamiento de un avión antes de que se estrelle es un error mucho más costoso que impedir que vuela un avión cuando el avión está en perfectas condiciones. En un caso criminal de asesinato, lo contrario es cierto ya que un falso positivo puede resultar en la ejecución de una persona inocente. La medida \(F_1\) se puede adaptar para pesar la especificidad y la sensibilidad de manera diferente. Para hacer esto, definimos \(\beta\) para representar cuánto más importante es la sensibilidad en comparación con la especificidad y consideramos una media armónica ponderada:

\[ \frac{1}{\frac{\beta^2}{1+\beta^2}\frac{1}{\mbox{recall}} + \frac{1}{1+\beta^2}\frac{1}{\mbox{precision}} } \]

La función F_meas en el paquete caret calcula este resumen con un valor de beta igual a 1 por defecto.

Reconstruyamos nuestro algoritmo de predicción, pero esta vez maximizando la medida F en lugar de la exactitud general:

cutoff <- seq(61, 70)
F_1 <- map_dbl(cutoff, function(x){
  y_hat <- ifelse(train_set$height > x, "Male", "Female") |>
    factor(levels = levels(test_set$sex))
  F_meas(data = y_hat, reference = factor(train_set$sex))
})

Como antes, podemos trazar estas medidas \(F_1\) versus los umbrales:

Vemos que el maximo de la medida \(F_1\) es:

max(F_1)
#> [1] 0.647

Este máximo se logra cuando usamos el siguiente umbral:

best_cutoff <- cutoff[which.max(F_1)]
best_cutoff
#> [1] 66

Un umbral de 66 tiene más sentido que de 64. Además, equilibra la especificidad y la sensibilidad de nuestra matriz de confusión:

y_hat <- ifelse(test_set$height > best_cutoff, "Male", "Female") |>
  factor(levels = levels(test_set$sex))
sensitivity(data = y_hat, reference = test_set$sex)
#> [1] 0.63
specificity(data = y_hat, reference = test_set$sex)
#> [1] 0.833

Ahora vemos que obtenemos mejores resultados que adivinando, que tanto la sensibilidad como la especificidad son relativamente altas y que hemos construido nuestro primer algoritmo de machine learning. Este toma altura como predictor y predice mujeres si la persona mide 65 pulgadas o menos.

27.4.6 La prevalencia importa en la práctica

Un algoritmo de machine learning con sensibilidad y especificidad muy altas puede ser inútil en la práctica cuando la prevalencia se acerca a 0 o 1. Para ver esto, consideren el caso de una doctora que se especializa en una enfermedad rara y que está interesada en desarrollar un algoritmo para predecir quién tiene la enfermedad. La doctora comparte los datos con ustedes, que entonces desarrollan un algoritmo con una sensibilidad muy alta. Explican que esto significa que si un paciente tiene la enfermedad, es muy probable que el algoritmo prediga correctamente. También le dicen a la doctora que están preocupados porque, según el set de datos que analizaron, la mitad de los pacientes tienen la enfermedad: \(\mbox{Pr}(\hat{Y}=1)\). La doctora no está preocupada ni impresionada y explica que lo importante es la precisión de la evaluación: \(\mbox{Pr}(Y=1 | \hat{Y}=1)\). Usando el teorema de Bayes, podemos conectar las dos medidas:

\[ \mbox{Pr}(Y = 1\mid \hat{Y}=1) = \mbox{Pr}(\hat{Y}=1 \mid Y=1) \frac{\mbox{Pr}(Y=1)}{\mbox{Pr}(\hat{Y}=1)}\]

La doctora sabe que la prevalencia de la enfermedad es de 5 en 1,000, lo que implica que \(\mbox{Pr}(Y=1) \,/ \,\mbox{Pr}(\hat{Y}=1) = 1/100\) y, por lo tanto, la precisión de su algoritmo es inferior a 0.01. La doctora no tiene mucho uso para su algoritmo.

27.4.7 Curvas ROC y precision-recall

Al comparar los dos métodos (adivinar versus usar un umbral de altura), comparamos la exactitud y \(F_1\). El segundo método claramente superó al primero. Sin embargo, si bien consideramos varios umbrales para el segundo método, para el primero solo consideramos un enfoque: adivinar con igual probabilidad. Noten que adivinar Male con mayor probabilidad nos daría una mayor exactitud debido al sesgo en la muestra:

p <- 0.9
n <- length(test_index)
y_hat <- sample(c("Male", "Female"), n, replace = TRUE, prob=c(p, 1-p)) |>
  factor(levels = levels(test_set$sex))
mean(y_hat == test_set$sex)
#> [1] 0.739

Pero, como se describió anteriormente, esto tendría el costo de una menor sensibilidad. Las curvas que describimos en esta sección nos ayudarán a ver esto.

Recuerden que para cada uno de estos parámetros, podemos obtener una sensibilidad y especificidad diferente. Por esta razón, un enfoque muy común para evaluar métodos es compararlos gráficamente trazando ambos.

Un gráfico ampliamente utilizado que hace esto es la curva característica operativa del receptor (Receiver Operating Characteristic o ROC por sus siglas en inglés). Para aprender más sobre el origen del nombre, pueden consultar la página de Wikipedia Curva ROC106.

La curva ROC representa la sensibilidad (TPR) frente a la especificidad 1 o la tasa de falsos positivos (FPR). Aquí calculamos el TPR y el FPR necesarios para diferentes probabilidades de adivinar Male:

probs <- seq(0, 1, length.out = 10)
guessing <- map_df(probs, function(p){
  y_hat <-
    sample(c("Male", "Female"), n, replace = TRUE, prob=c(p, 1-p)) |>
    factor(levels = c("Female", "Male"))
  list(method = "Guessing",
       FPR = 1 - specificity(y_hat, test_set$sex),
       TPR = sensitivity(y_hat, test_set$sex))
})

Podemos usar un código similar para calcular estos valores para nuestro segundo enfoque. Al graficar ambas curvas juntas, podemos comparar la sensibilidad para diferentes valores de especificidad:

Vemos que obtenemos una mayor sensibilidad con este enfoque para todos los valores de especificidad, lo que implica que es un método mejor. Tengan en cuenta que si simplemente adivinamos, las curvas ROC caen en la línea de identidad. También noten que cuando hacemos curvas ROC, a veces ayuda agregar el umbral asociado con cada punto al gráfico.

Los paquetes pROC y plotROC son útiles para generar estos gráficos.

Las curvas ROC tienen una debilidad y es que ninguna de las medidas graficadas depende de la prevalencia. En los casos en que la prevalencia es importante, en su lugar podemos hacer un gráfico precision-recall. La idea es similar, pero en cambio graficamos la precisión versus el recall:

En este gráfico inmediatamente vemos que la precisión de adivinar no es alta. Esto se debe a que la prevalencia es baja. También vemos que si cambiamos los positivos para que representen “Male” en lugar de “Female”, la curva ROC permanece igual, pero el gráfico precision-recall cambia.

27.4.8 Función de pérdida

Hasta ahora hemos descrito métricas de evaluación que se aplican exclusivamente a datos categóricos. Específicamente, para los resultados binarios, hemos descrito cómo la sensibilidad, especificidad, exactitud y \(F_1\) se pueden utilizar como cuantificación. Sin embargo, estas métricas no son útiles para resultados continuos. En esta sección, describimos cómo el enfoque general para definir “mejor” en machine learning es definir una función de pérdida (loss function en inglés), que puede aplicarse tanto a datos categóricos como continuos.

La función de pérdida más utilizada es la función de pérdida al cuadrado. Si \(\hat{y}\) es nuestro predictor e \(y\) es el resultado observado, la función de pérdida al cuadrado es simplemente:

\[ (\hat{y} - y)^2 \]

Debido a que frecuentemente tenemos un set de evaluaciones con muchas observaciones, digamos \(N\), usamos el error cuadrático medio (mean squared error o MSE por sus siglas en inglés):

\[ \mbox{MSE} = \frac{1}{N} \mbox{RSS} = \frac{1}{N}\sum_{i=1}^N (\hat{y}_i - y_i)^2 \]

En la práctica, a menudo indicamos la raiz de la desviación cuadrática media (root mean squared error o RMSE por sus siglas en inglés), que es \(\sqrt{\mbox{MSE}}\), porque está en las mismas unidades que los resultados. Pero hacer las matemáticas muchas veces es más fácil con el MSE y, por lo tanto, se usa más en los libros de texto, ya que estos generalmente describen las propiedades teóricas de los algoritmos.

Si los resultados son binarios, tanto RMSE como MSE son equivalentes a la exactitud menos uno, ya que \((\hat{y} - y)^2\) es 0 si la predicción fue correcta y 1 en caso contrario. En general, nuestro objetivo es construir un algoritmo que minimice la pérdida para que esté lo más cerca posible a 0.

Debido a que nuestros datos son generalmente una muestra aleatoria, podemos pensar en el MSE como una variable aleatoria y el MSE observado puede considerarse como una estimación del MSE esperado, que en notación matemática escribimos así:

\[ \mbox{E}\left\{ \frac{1}{N}\sum_{i=1}^N (\hat{Y}_i - Y_i)^2 \right\} \]

Este es un concepto teórico porque en la práctica solo tenemos un set de datos con el cual trabajar. Una forma de pensar en lo que es esta expectativa teórica es la siguiente: tomamos un gran número (llámelo \(B\)) de muestras aleatorias, aplicamos nuestro algoritmo a cada muestra aleatoria, calculamos el MSE observado y tomamos el promedio. Podemos escribir la siguiente fórmula para esta cantidad:

\[ \frac{1}{B} \sum_{b=1}^B \frac{1}{N}\sum_{i=1}^N \left(\hat{y}_i^b - y_i^b\right)^2 \]

con \(y_{i}^b\) denotando la observación \(i\) en la muestra aleatoria \(b\) e \(\hat{y}_i^b\) denotando la predicción resultante obtenida de aplicar exactamente el mismo algoritmo a la muestra aleatoria \(b\). De nuevo, en la práctica solo observamos una muestra aleatoria, por lo que el MSE esperado es solo teórico. Sin embargo, en el Capítulo 29, describimos un enfoque para estimar el MSE que trata de imitar esta cantidad teórica.

Tengan en cuenta que hay funciones de pérdida distintas de la función de pérdida cuadrática. Por ejemplo, el error medio absoluto (mean absolute error en inglés) utiliza valores absolutos, \(|\hat{Y}_i - Y_i|\) en lugar de cuadrar los errores \((\hat{Y}_i - Y_i)^2\). Sin embargo, en este libro nos enfocamos en minimizar la función de pérdida cuadrática ya que es la más utilizada.

27.5 Ejercicios

Los sets de datos reported_height y height se recopilaron de tres clases impartidas en los Departamentos de Ciencias Computacionales y Bioestadística, así como de forma remota a través de la Escuela de Extensión. La clase de bioestadística se impartió en 2016 junto con una versión en línea ofrecida por la Escuela de Extensión. El 25 de enero de 2016 a las 8:15 a.m., durante una de las clases, los instructores le pidieron a los estudiantes que completaran el cuestionario de sexo y altura que poblaba el set de datos reported_height. Los estudiantes en línea completaron la encuesta durante los próximos días, después de que la conferencia se publicara en línea. Podemos usar esta información para definir una variable, llamarla type, para denotar el tipo de estudiante: inclass (presenciales) o online (en línea):

library(lubridate)
data("reported_heights")
dat <- mutate(reported_heights, date_time = ymd_hms(time_stamp)) |>
  filter(date_time >= make_date(2016, 01, 25) &
           date_time < make_date(2016, 02, 1)) |>
  mutate(type = ifelse(day(date_time) == 25 & hour(date_time) == 8 &
                         between(minute(date_time), 15, 30),
                       "inclass", "online")) |> select(sex, type)
x <- dat$type
y <- factor(dat$sex, c("Female", "Male"))

1. Muestre estadísticas de resumen que indican que el type es predictivo del sexo.

2. En lugar de usar la altura para predecir el sexo, use la variable type.

3. Muestre la matriz de confusión.

4. Utilice la función confusionMatrix en el paquete caret para indicar la exactitud.

5. Ahora use las funciones sensitivity y specificity para indicar especificidad y sensibilidad.

6. ¿Cuál es la prevalencia (% de mujeres) en el set de datos dat definido anteriormente?

27.6 Probabilidades y expectativas condicionales

En las aplicaciones de machine learning, rara vez podemos predecir los resultados perfectamente. Por ejemplo, los detectores de spam a menudo no detectan correos electrónicos que son claramente spam, Siri no siempre entiende las palabras que estamos diciendo y su banco a veces piensa que su tarjeta fue robada cuando no fue así. La razón más común para no poder construir algoritmos perfectos es que es imposible. Para entender esto, noten que la mayoría de los sets de datos incluirán grupos de observaciones con los mismos valores exactos observados para todos los predictores, pero con diferentes resultados. Debido a que nuestras reglas de predicción son funciones, entradas iguales (los predictores) implican que los resultados (los atributos/las predicciones) tienen que ser iguales. Por lo tanto, para un set de datos en el que los mismos predictores se asocian con diferentes resultados en diferentes observaciones individuales, es imposible predecir correctamente para todos estos casos. Vimos un ejemplo sencillo de esto en la sección anterior: para cualquier altura dada \(x\), tendrán hombres y mujeres que son \(x\) pulgadas de alto.

Sin embargo, nada de esto significa que no podamos construir algoritmos útiles que sean mucho mejores que adivinar y que en algunos casos sean mejores que las opiniones de expertos. Para lograr esto de manera óptima, hacemos uso de representaciones probabilísticas del problema basadas en las ideas presentadas en la Sección 17.3. Las observaciones con los mismos valores observados para los predictores pueden ser desiguales, pero podemos suponer que todas tienen la misma probabilidad de esta clase o de esa clase. Escribiremos esta idea matemáticamente para el caso de datos categóricos.

27.6.1 Probabilidades condicionales

Usamos la notación \((X_1 = x_1,\dots,X_p=x_p)\) para representar el hecho de que hemos observado valores \(x_1, \dots ,x_p\) para covariables \(X_1, \dots, X_p\). Esto no implica que el resultado \(Y\) tomará un valor específico. En cambio, implica una probabilidad específica. En particular, denotamos las probabilidades condicionales para cada clase \(k\):

\[ \mbox{Pr}(Y=k \mid X_1 = x_1,\dots,X_p=x_p), \, \mbox{for}\,k=1,\dots,K \]

Para evitar escribir todos los predictores, utilizamos letras en negrilla así: \(\mathbf{X} \equiv (X_1,\dots,X_p)\) y \(\mathbf{x} \equiv (x_1,\dots,x_p)\). También usaremos la siguiente notación para la probabilidad condicional de ser clase \(k\):

\[ p_k(\mathbf{x}) = \mbox{Pr}(Y=k \mid \mathbf{X}=\mathbf{x}), \, \mbox{for}\, k=1,\dots,K \]

Ojo: Utilizaremos la notación \(p(x)\) para representar probabilidades condicionales como funciones de los predictores. No lo confundan con el \(p\) que representa el número de predictores.

Estas probabilidades guían la construcción de un algoritmo que mejora la predicción: para cualquier \(\mathbf{x}\), vamos a predecir la clase \(k\) con la mayor probabilidad entre \(p_1(x),p_2(x),\dots p_K(x)\). En notación matemática, lo escribimos así: \(\hat{Y}=\max_k p_k(\mathbf{x})\).

En machine learning, nos referimos a esto como la Regla de Bayes. Pero recuerden que esta es una regla teórica ya que en la práctica no sabemos \(p_k(\mathbf{x}),k=1,\dots,K\). De hecho, estimar estas probabilidades condicionales puede considerarse como el principal desafío de machine learning. Cuanto mejores sean nuestros estimadores de la probabilidad \(\hat{p}_k(\mathbf{x})\), mejor será nuestro predictor:

\[\hat{Y} = \max_k \hat{p}_k(\mathbf{x})\]

Entonces, lo que predeciremos depende de dos cosas: 1) cuán cerca están las \(\max_k p_k(\mathbf{x})\) a 1 o 0 (certeza perfecta) y 2) cuán cerca están nuestros estimadores de \(\hat{p}_k(\mathbf{x})\) a \(p_k(\mathbf{x})\). No podemos hacer nada con respecto a la primera restricción, ya que está determinada por la naturaleza del problema y, por lo tanto, nos dedicaremos a encontrar buenas formas de estimar las probabilidades condicionales. La primera restricción implica que tenemos límites en cuanto a cuán bien puede funcionar hasta el mejor algoritmo posible. Deberían acostumbrarse a la idea de que, si bien en algunos retos podremos lograr una exactitud casi perfecta, por ejemplo con lectores de dígitos, en otros nuestro éxito está restringido por la aleatoriedad del proceso, como con recomendaciones de películas.

Antes de continuar, es importante recordar que definir nuestra predicción maximizando la probabilidad no siempre es óptimo en la práctica y depende del contexto. Como se discutió anteriormente, la sensibilidad y la especificidad pueden diferir en importancia. Pero incluso en estos casos, tener un buen estimador de la \(p_k(x), k=1,\dots,K\) nos bastará para construir modelos de predicción óptimos, ya que podemos controlar el equilibrio entre especificidad y sensibilidad como queramos. Por ejemplo, simplemente podemos cambiar los umbrales utilizados para predecir un resultado u otro. En el ejemplo del avión, podemos evitar que vuela un avión en cualquier momento en que la probabilidad de mal funcionamiento sea superior a 1 en un millón, en lugar del 1/2 predeterminado que se usa cuando los tipos de error son igualmente indeseados.

27.6.2 Expectativas condicionales

Para datos binarios, pueden pensar en la probabilidad \(\mbox{Pr}(Y=1 \mid \mathbf{X}=\mathbf{x})\) como la proporción de 1s en el estrato de la población para la cual \(\mathbf{X}=\mathbf{x}\). Muchos de los algoritmos que aprenderemos se pueden aplicar tanto a datos categóricos como continuos debido a la conexión entre las probabilidades condicionales y las expectativas condicionales.

Porque la expectativa es el promedio de los valores \(y_1,\dots,y_n\) en la población, en el caso en que las \(y\)s son 0 o 1, la expectativa es equivalente a la probabilidad de elegir aleatoriamente un 1 ya que el promedio es simplemente la proporción de 1s:

\[ \mbox{E}(Y \mid \mathbf{X}=\mathbf{x})=\mbox{Pr}(Y=1 \mid \mathbf{X}=\mathbf{x}). \]

Como resultado, a menudo solo usamos la expectativa para denotar tanto la probabilidad condicional como la expectativa condicional.

Al igual que con los resultados categóricos, en la mayoría de las aplicaciones, los mismos predictores observados no garantizan los mismos resultados continuos. En cambio, suponemos que el resultado sigue la misma distribución condicional. Ahora explicaremos por qué usamos la expectativa condicional para definir nuestros predictores.

27.6.3 La expectativa condicional minimiza la función de pérdida cuadrática

¿Por qué nos importa la expectativa condicional en machine learning? Se debe a que el valor esperado tiene una propiedad matemática atractiva: minimiza el MSE. Específicamente, de todas las posibles predicciones \(\hat{Y}\),

\[ \hat{Y} = \mbox{E}(Y \mid \mathbf{X}=\mathbf{x}) \, \mbox{ minimizes } \, \mbox{E}\{ (\hat{Y} - Y)^2 \mid \mathbf{X}=\mathbf{x} \} \]

Debido a esta propiedad, una descripción sucinta de la tarea principal de machine learning es que utilizamos datos para estimar:

\[ f(\mathbf{x}) \equiv \mbox{E}( Y \mid \mathbf{X}=\mathbf{x} ) \]

para cualquier conjunto de características \(\mathbf{x} = (x_1, \dots, x_p)\). Por supuesto, esto es más fácil decirlo que hacerlo, ya que esta función puede tomar cualquier forma y \(p\) puede ser muy grande. Consideren un caso en el que solo tenemos un predictor \(x\). La expectativa \(\mbox{E}\{ Y \mid X=x \}\) puede ser cualquier función de \(x\): una línea, una parábola, una onda sinusoidal, una función escalón, etc. Se vuelve aún más complicado cuando consideramos instancias con grandes \(p\), en cual caso \(f(\mathbf{x})\) es una función de un vector multidimensional \(\mathbf{x}\). ¡Por ejemplo, en nuestro ejemplo de lector de dígitos \(p = 784\)! La principal forma en que los algoritmos competitivos de machine learning difieren es en su enfoque para estimar esta expectativa.

27.7 Ejercicios

1. Calcule las probabilidades condicionales de ser hombre para el set the datos heights. Redondee las alturas a la pulgada más cercana. Grafique la probabilidad condicional estimada \(P(x) = \mbox{Pr}(\mbox{Male} | \mbox{height}=x)\) para cada \(x\).

2. En el gráfico que acabamos de hacer, vemos una gran variabilidad para valores bajos de altura. Esto se debe a que tenemos pocos puntos de datos en estos estratos. Use la función quantile para cuantiles \(0.1,0.2,\dots,0.9\) y la función cut para asegurar que cada grupo tenga el mismo número de puntos. Sugerencia: para cualquier vector numérico x, puede crear grupos basados en cuantiles como este:

cut(x, quantile(x, seq(0, 1, 0.1)), include.lowest = TRUE)

3. Genere datos a partir de una distribución normal de dos variables utilizando el paquete MASS como este:

Sigma <- 9*matrix(c(1,0.5,0.5,1), 2, 2)
dat <- MASS::mvrnorm(n = 10000, c(69, 69), Sigma) |>
  data.frame() |> setNames(c("x", "y"))

Pueden hacer un gráfico rápido de los datos usando plot(dat). Use un enfoque similar al ejercicio anterior para estimar las expectativas condicionales y haga un gráfico.

27.8 Estudio de caso: ¿es un 2 o un 7?

En los dos ejemplos anteriores, solo teníamos un predictor. Realmente no consideramos estos retos de machine learning, que se caracterizan por casos con muchos predictores. Volvamos al ejemplo de dígitos en el que teníamos 784 predictores. Para fines ilustrativos, comenzaremos simplificando este problema a uno con dos predictores y dos clases. Específicamente, definimos el desafío como construir un algoritmo que pueda determinar si un dígito es un 2 o 7 de los predictores. No estamos del todo listos para construir algoritmos con 784 predictores, por lo que extraeremos dos predictores sencillos de los 784: la proporción de píxeles oscuros que están en el cuadrante superior izquierdo (\(X_1\)) y el cuadrante inferior derecho (\(X_2\)).

Entonces seleccionamos una muestra aleatoria de 1,000 dígitos, 500 en el set de entrenamiento y 500 en el set de evaluación. Proveemos este set de datos en el paquete dslabs:

library(tidyverse)
library(dslabs)
data("mnist_27")

Podemos explorar los datos graficando los dos predictores y usando colores para denotar las etiquetas:

mnist_27$train |> ggplot(aes(x_1, x_2, color = y)) + geom_point()

Inmediatamente vemos algunos patrones. Por ejemplo, si \(X_1\) (el panel superior izquierdo) es muy grande, entonces el dígito es probablemente un 7. Además, para valores más pequeños de \(X_1\), los 2s parecen estar en los valores de rango medio de \(X_2\).

Para ilustrar como interpretar \(X_1\) y \(X_2\), incluimos cuatro imágenes como ejemplo. A la izquierda están las imágenes originales de los dos dígitos con los valores más grandes y más pequeños para \(X_1\) y a la derecha tenemos las imágenes correspondientes a los valores más grandes y más pequeños de \(X_2\):

Comenzamos a tener una idea de por qué estos predictores son útiles, pero también por qué el problema será algo desafiante.

Realmente no hemos aprendido ningún algoritmo todavía, así que intentemos construir un algoritmo usando regresión. El modelo es simplemente:

\[ p(x_1, x_2) = \mbox{Pr}(Y=1 \mid X_1=x_1 , X_2 = x_2) = \beta_0 + \beta_1 x_1 + \beta_2 x_2 \]

Lo ajustamos así:

fit <- mnist_27$train |>
  mutate(y = ifelse(y==7, 1, 0)) |>
  lm(y ~ x_1 + x_2, data = _)

Ahora podemos construir una regla de decisión basada en el estimador \(\hat{p}(x_1, x_2)\):

library(caret)
p_hat <- predict(fit, newdata = mnist_27$test)
y_hat <- factor(ifelse(p_hat > 0.5, 7, 2))
confusionMatrix(y_hat, mnist_27$test$y)$overall[["Accuracy"]]
#> [1] 0.75

Obtenemos una exactidud muy superior al 50%. No está mal para nuestro primer intento. ¿Pero podemos mejorar?

Como construimos el ejemplo mnist_27 y tuvimos a nuestra disposición 60,000 dígitos solo en el set de datos MNIST, lo usamos para construir la distribución condicional verdadera \(p(x_1, x_2)\). Recuerden que esto es algo a lo que no tenemos acceso en la práctica, pero lo incluimos en este ejemplo porque permite comparar \(\hat{p}(x_1, x_2)\) con la verdadera \(p(x_1, x_2)\). Esta comparación nos enseña las limitaciones de diferentes algoritmos. Hagamos eso aquí. Hemos almacenado el verdadero \(p(x_1,x_2)\) en el objeto mnist_27 y podemos graficar la imagen usando la función geom_raster() de ggplot2 . Elegimos mejores colores y usamos la función stat_contour para dibujar una curva que separa pares \((x_1,x_2)\) para cual \(p(x_1,x_2) > 0.5\) y pares para cual \(p(x_1,x_2) < 0.5\):

mnist_27$true_p |> ggplot(aes(x_1, x_2, z = p, fill = p)) +
  geom_raster() +
  scale_fill_gradientn(colors=c("#F8766D", "white", "#00BFC4")) +
  stat_contour(breaks=c(0.5), color="black")

Arriba vemos un gráfico del verdadero \(p(x,y)\). Para comenzar a entender las limitaciones de la regresión logística aquí, primero tengan en cuenta que con la regresión logística \(\hat{p}(x,y)\) tiene que ser un plano y, como resultado, el umbral definido por la regla de decisión lo da: \(\hat{p}(x,y) = 0.5\), lo que implica que el umbral no puede ser otra cosa que una línea recta:

\[ \hat{\beta}_0 + \hat{\beta}_1 x_1 + \hat{\beta}_2 x_2 = 0.5 \implies \hat{\beta}_0 + \hat{\beta}_1 x_1 + \hat{\beta}_2 x_2 = 0.5 \implies x_2 = (0.5-\hat{\beta}_0)/\hat{\beta}_2 -\hat{\beta}_1/\hat{\beta}_2 x_1 \]

Noten que, para este umbral, \(x_2\) es una función lineal de \(x_1\). Esto implica que nuestro enfoque de regresión logística no tiene posibilidades de capturar la naturaleza no lineal de la verdadera \(p(x_1,x_2)\). A continuación se muestra una representación visual de \(\hat{p}(x_1, x_2)\). Utilizamos la función squish del paquete scales para restringir los estimados entre 0 y 1. Podemos ver dónde se cometieron los errores al mostrar también los datos y el umbral. Principalmente provienen de valores bajos \(x_1\) que tienen un valor alto o bajo de \(x_2\). La regresión no puede detectar esto.

Necesitamos algo más flexible: un método que permita estimadores con formas distintas a un plano.

Vamos a aprender algunos algoritmos nuevos basados en diferentes ideas y conceptos. Pero lo que todos tienen en común es que permiten enfoques más flexibles. Comenzaremos describiendo alogoritmos basados en nearest neighbor o kernels. Para introducir los conceptos detrás de estos enfoques, comenzaremos nuevamente con un ejemplo unidimensional sencillo y describiremos el concepto de suavización (smoothing en inglés).