estadística
pensamientos
obviedades
2025
Published

February 24, 2025

Listening

A pesar de todo el hype de la IA y del Machín Lenin hay una cosa muy obvia que se le olvida a la mayoría de la gente, y es el error irreducible.

Imaginad, que como pasa en la vida real, se quiere modelar por ejemplo la propensión de comprar un producto por parte de clientes. Y se tienen recogidas digamos unas 4 variables, pues lo más normal es que a igual valor en las 4 variables unos clientes compren y otros no, y por lo tanto es imposible tener un acierto total. Ni con IA, ni con Machín Lenin ni que el mismo Odín te ayude con el tema.

Y eso hace por tanto que haya un límite a métricas a AUC-ROC y similares.

Ejemplo tonto.

Digamos que tenemos 2 variables

Show the code
library(tidyverse)

x1 <- c("A", "B", "C")
x2 <- c("D", "E", "F")

n <- c (100, 200,400, 150, 200, 300, 400, 25, 90 ) 
exitos  <-  round(n * c(0.4, 0.6, 0.2, 0.5, 0.9, 0.15, 0.3, 0.7, 0.1)) 

df  <-  expand.grid(x1, x2)

df$n  <-  n
df$exitos  <-  exitos
names(df)[1:2]  <-  c("x1", "x2")

df
#>   x1 x2   n exitos
#> 1  A  D 100     40
#> 2  B  D 200    120
#> 3  C  D 400     80
#> 4  A  E 150     75
#> 5  B  E 200    180
#> 6  C  E 300     45
#> 7  A  F 400    120
#> 8  B  F  25     18
#> 9  C  F  90      9

# Expandir los datos, añado la prop_real
df_exp <- df   |> 
  rowwise()  |> 
  mutate(data = list(tibble(x1 = x1, x2 = x2, prop_real = exitos /n,  y = c(rep(1, exitos), rep(0, n - exitos)))))  |> 
  select(-x1, -x2, -n, -exitos)  |> 
  unnest(data)  |> 
  mutate(y = as.factor(y))  |> 
  select(x1, x2, y, prop_real)


skimr::skim(df_exp)
Data summary
Name df_exp
Number of rows 1865
Number of columns 4
_______________________
Column type frequency:
factor 3
numeric 1
________________________
Group variables None

Variable type: factor

skim_variable n_missing complete_rate ordered n_unique top_counts
x1 0 1 FALSE 3 C: 790, A: 650, B: 425
x2 0 1 FALSE 3 D: 700, E: 650, F: 515
y 0 1 FALSE 2 0: 1178, 1: 687

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
prop_real 0 1 0.37 0.24 0.1 0.2 0.3 0.5 0.9 ▇▅▂▂▂
Show the code


DT::datatable(head(df_exp, 100))
Show the code

df_exp  |> 
  group_by(x1, x2)  |> 
  summarise(
            n = n(), 
            exitos = sum(as.numeric(y)-1),
            prop_real = mean(prop_real)
  )
#> # A tibble: 9 × 5
#> # Groups:   x1 [3]
#>   x1    x2        n exitos prop_real
#>   <fct> <fct> <int>  <dbl>     <dbl>
#> 1 A     D       100     40      0.4 
#> 2 A     E       150     75      0.5 
#> 3 A     F       400    120      0.3 
#> 4 B     D       200    120      0.6 
#> 5 B     E       200    180      0.9 
#> 6 B     F        25     18      0.72
#> 7 C     D       400     80      0.2 
#> 8 C     E       300     45      0.15
#> 9 C     F        90      9      0.1

Con esas 2 variables, x1 y x2 un modelo perfecto como mucho daría un 0.4 de probabilidad a todas las filas que tengan x1 = "A" y x2= "D"

Pues aquí el modelo perfecto tendría como mucho el siguiente auc_roc

Show the code

yardstick::roc_auc_vec( df_exp$y, df_exp$prop_real, event_level = "second")
#> [1] 0.77283

Pues como decía, hay un error irreducible. Esto es importante a la hora de gestionar expectativas en nuestros análisis. Incluso un modelo perfecto (al predecir nuevos datos) puede no llegar a tener unas métricas maravillosas.