¿Cuándo debemos discretizar / bin variables / características continuas independientes y cuándo no?

21

¿Cuándo debemos discretizar / bin variables / características independientes y cuándo no?

Mis intentos de responder la pregunta:

  • En general, no debemos bin, porque binning perderá información.
  • El binning en realidad aumenta el grado de libertad del modelo, por lo que es posible causar un ajuste excesivo después del binning. Si tenemos un modelo de "alto sesgo", el binning puede no ser malo, pero si tenemos un modelo de "alta varianza", debemos evitar el binning.
  • Depende de qué modelo estamos usando. Si es un modo lineal, y los datos tienen muchos "valores atípicos", la probabilidad de agrupamiento es mejor. Si tenemos un modelo de árbol, entonces, valores atípicos y binning harán demasiada diferencia.

Estoy en lo cierto? ¿y qué más?


Pensé que esta pregunta debería hacerse muchas veces, pero no puedo encontrarla en el CV solo en estas publicaciones

¿Deberíamos bin variables continuas?

¿Cuál es el beneficio de romper una variable predictiva continua?

Haitao Du
fuente
No creo que esa pregunta sea un duplicado porque la respuesta no aborda este problema ("deberíamos hacerlo").
Firebug
8
Los enfoques de CART / bosque aleatorio son más o menos binning de variables continuas (que se ajustan a funciones constantes por partes), pero lo están haciendo de una manera mucho mejor. Si pre-bin, está negando a su algoritmo de construcción de árboles la flexibilidad para poner los descansos en un lugar óptimo ...
Ben Bolker

Respuestas:

16

Parece que también está buscando una respuesta desde un punto de vista predictivo, por lo que preparé una breve demostración de dos enfoques en R

  • Binning una variable en factores de igual tamaño.
  • Splines cúbicos naturales.

A continuación, he dado el código para una función que comparará los dos métodos automáticamente para cualquier función de señal verdadera

test_cuts_vs_splines <- function(signal, N, noise,
                                 range=c(0, 1), 
                                 max_parameters=50,
                                 seed=154)

Esta función creará conjuntos de datos de entrenamiento y prueba ruidosos a partir de una señal dada, y luego ajustará una serie de regresiones lineales a los datos de entrenamiento de dos tipos

  • El cutsmodelo incluye predictores agrupados, formados segmentando el rango de datos en intervalos semiabiertos de igual tamaño, y luego creando predictores binarios que indican a qué intervalo pertenece cada punto de entrenamiento.
  • El splinesmodelo incluye una expansión de base de spline cúbica natural, con nudos igualmente espaciados en todo el rango del predictor.

Los argumentos son

  • signal: Una función de una variable que representa la verdad a estimar.
  • N: El número de muestras a incluir tanto en los datos de entrenamiento como de prueba.
  • noise: La cantidad de ruido gaussiano aleatorio para agregar a la señal de entrenamiento y prueba.
  • range: El rango de los xdatos de entrenamiento y prueba , datos que se generan de manera uniforme dentro de este rango.
  • max_paramters: El número máximo de parámetros para estimar en un modelo. Este es el número máximo de segmentos en el cutsmodelo y el número máximo de nudos en el splinesmodelo.

Tenga en cuenta que el número de parámetros estimados en el splinesmodelo es el mismo que el número de nudos, por lo que los dos modelos se comparan bastante.

El objeto de retorno de la función tiene algunos componentes.

  • signal_plot: Un gráfico de la función de señal.
  • data_plot: Un diagrama de dispersión de los datos de entrenamiento y prueba.
  • errors_comparison_plot: Un gráfico que muestra la evolución de la suma de la tasa de error al cuadrado para ambos modelos en un rango del número de parámetros estimados.

Lo demostraré con dos funciones de señal. La primera es una ola de pecado con una tendencia lineal creciente superpuesta

true_signal_sin <- function(x) {
  x + 1.5*sin(3*2*pi*x)
}

obj <- test_cuts_vs_splines(true_signal_sin, 250, 1)

Así es como evolucionan las tasas de error

Agrupar vs splines entrenar y probar el rendimiento con diversos grados de libertad para aumentar la onda de pecado

El segundo ejemplo es una función de nuez que mantengo solo para este tipo de cosas, trazarla y ver

true_signal_weird <- function(x) {
  x*x*x*(x-1) + 2*(1/(1+exp(-.5*(x-.5)))) - 3.5*(x > .2)*(x < .5)*(x - .2)*(x - .5)
}

obj <- test_cuts_vs_splines(true_signal_weird, 250, .05)

Agrupar vs splines entrenar y probar el rendimiento con un grado variable de libertad para aumentar la función extraña

Y por diversión, aquí hay una aburrida función lineal

obj <- test_cuts_vs_splines(function(x) {x}, 250, .2)

Agrupar vs splines entrenar y probar el rendimiento con un grado variable de libertad para la función lineal

Puedes ver eso:

  • Las splines brindan un mejor rendimiento general de la prueba cuando la complejidad del modelo se ajusta adecuadamente para ambos.
  • Las splines ofrecen un rendimiento de prueba óptimo con muchos menos parámetros estimados .
  • En general, el rendimiento de las splines es mucho más estable ya que el número de parámetros estimados varía.

Por lo tanto, las splines siempre se deben preferir desde un punto de vista predictivo.

Código

Aquí está el código que usé para producir estas comparaciones. Lo he incluido todo en una función para que pueda probarlo con sus propias funciones de señal. Deberá importar las bibliotecas ggplot2y splinesR.

test_cuts_vs_splines <- function(signal, N, noise,
                                 range=c(0, 1), 
                                 max_parameters=50,
                                 seed=154) {

  if(max_parameters < 8) {
    stop("Please pass max_parameters >= 8, otherwise the plots look kinda bad.")
  }

  out_obj <- list()

  set.seed(seed)

  x_train <- runif(N, range[1], range[2])
  x_test <- runif(N, range[1], range[2])

  y_train <- signal(x_train) + rnorm(N, 0, noise)
  y_test <- signal(x_test) + rnorm(N, 0, noise)

  # A plot of the true signals
  df <- data.frame(
    x = seq(range[1], range[2], length.out = 100)
  )
  df$y <- signal(df$x)
  out_obj$signal_plot <- ggplot(data = df) +
    geom_line(aes(x = x, y = y)) +
    labs(title = "True Signal")

  # A plot of the training and testing data
  df <- data.frame(
    x = c(x_train, x_test),
    y = c(y_train, y_test),
    id = c(rep("train", N), rep("test", N))
  )
  out_obj$data_plot <- ggplot(data = df) + 
    geom_point(aes(x=x, y=y)) + 
    facet_wrap(~ id) +
    labs(title = "Training and Testing Data")

  #----- lm with various groupings -------------   
  models_with_groupings <- list()
  train_errors_cuts <- rep(NULL, length(models_with_groupings))
  test_errors_cuts <- rep(NULL, length(models_with_groupings))

  for (n_groups in 3:max_parameters) {
    cut_points <- seq(range[1], range[2], length.out = n_groups + 1)
    x_train_factor <- cut(x_train, cut_points)
    factor_train_data <- data.frame(x = x_train_factor, y = y_train)
    models_with_groupings[[n_groups]] <- lm(y ~ x, data = factor_train_data)

    # Training error rate
    train_preds <- predict(models_with_groupings[[n_groups]], factor_train_data)
    soses <- (1/N) * sum( (y_train - train_preds)**2)
    train_errors_cuts[n_groups - 2] <- soses

    # Testing error rate
    x_test_factor <- cut(x_test, cut_points)
    factor_test_data <- data.frame(x = x_test_factor, y = y_test)
    test_preds <- predict(models_with_groupings[[n_groups]], factor_test_data)
    soses <- (1/N) * sum( (y_test - test_preds)**2)
    test_errors_cuts[n_groups - 2] <- soses
  }

  # We are overfitting
  error_df_cuts <- data.frame(
    x = rep(3:max_parameters, 2),
    e = c(train_errors_cuts, test_errors_cuts),
    id = c(rep("train", length(train_errors_cuts)),
           rep("test", length(test_errors_cuts))),
    type = "cuts"
  )
  out_obj$errors_cuts_plot <- ggplot(data = error_df_cuts) +
    geom_line(aes(x = x, y = e)) +
    facet_wrap(~ id) +
    labs(title = "Error Rates with Grouping Transformations",
         x = ("Number of Estimated Parameters"),
         y = ("Average Squared Error"))

  #----- lm with natural splines -------------  
  models_with_splines <- list()
  train_errors_splines <- rep(NULL, length(models_with_groupings))
  test_errors_splines <- rep(NULL, length(models_with_groupings))

  for (deg_freedom in 3:max_parameters) {
    knots <- seq(range[1], range[2], length.out = deg_freedom + 1)[2:deg_freedom]

    train_data <- data.frame(x = x_train, y = y_train)
    models_with_splines[[deg_freedom]] <- lm(y ~ ns(x, knots=knots), data = train_data)

    # Training error rate
    train_preds <- predict(models_with_splines[[deg_freedom]], train_data)
    soses <- (1/N) * sum( (y_train - train_preds)**2)
    train_errors_splines[deg_freedom - 2] <- soses

    # Testing error rate
    test_data <- data.frame(x = x_test, y = y_test)  
    test_preds <- predict(models_with_splines[[deg_freedom]], test_data)
    soses <- (1/N) * sum( (y_test - test_preds)**2)
    test_errors_splines[deg_freedom - 2] <- soses
  }

  error_df_splines <- data.frame(
    x = rep(3:max_parameters, 2),
    e = c(train_errors_splines, test_errors_splines),
    id = c(rep("train", length(train_errors_splines)),
           rep("test", length(test_errors_splines))),
    type = "splines"
  )
  out_obj$errors_splines_plot <- ggplot(data = error_df_splines) +
    geom_line(aes(x = x, y = e)) +
    facet_wrap(~ id) +
    labs(title = "Error Rates with Natural Cubic Spline Transformations",
         x = ("Number of Estimated Parameters"),
         y = ("Average Squared Error"))


  error_df <- rbind(error_df_cuts, error_df_splines)
  out_obj$error_df <- error_df

  # The training error for the first cut model is always an outlier, and
  # messes up the y range of the plots.
  y_lower_bound <- min(c(train_errors_cuts, train_errors_splines))
  y_upper_bound = train_errors_cuts[2]
  out_obj$errors_comparison_plot <- ggplot(data = error_df) +
    geom_line(aes(x = x, y = e)) +
    facet_wrap(~ id*type) +
    scale_y_continuous(limits = c(y_lower_bound, y_upper_bound)) +
    labs(
      title = ("Binning vs. Natural Splines"),
      x = ("Number of Estimated Parameters"),
      y = ("Average Squared Error"))

  out_obj
}
Matthew Drury
fuente
19

La agregación tiene un significado sustancial (ya sea que el investigador lo sepa o no).

Uno debe agrupar los datos, incluidas las variables independientes, en función de los datos en sí cuando se quiera:

  • A la hemorragia el poder estadístico.

  • Para sesgar las medidas de asociación.

Una literatura que comienza, creo, con Ghelke y Biehl (1934, definitivamente vale la pena leer, y sugiere algunas simulaciones por computadora lo suficientemente fáciles que uno puede ejecutar por sí mismo), y continúa especialmente en la literatura de 'problema de unidad de área modificable' (Openshaw , 1983; Dudley, 1991; Lee y Kemp, 2000) aclara ambos puntos.

A menos que uno tenga una teoría a priori de la escala de agregación (a cuántas unidades agregar) y la función de categorización de la agregación (qué observaciones individuales terminarán en qué unidades agregadas), uno no debe agregar. Por ejemplo, en epidemiología, nos preocupamos por la salud de las personas y la salud de las poblaciones . Los últimos no son simplemente colecciones aleatorias de los primeros, sino que se definen, por ejemplo, por límites geopolíticos, circunstancias sociales como la categorización racial-étnica, el estado carcelario y las categorías de historia, etc. (Ver, por ejemplo, Krieger, 2012)

Referencias
Dudley, G. (1991). Escala, agregación y el problema de la unidad de área modificable . [paredes de pago] The Operational Geographer, 9 (3): 28–33.

Gehlke, CE y Biehl, K. (1934). Ciertos efectos de la agrupación sobre el tamaño del coeficiente de correlación en el material del tramo censal . [con paredes de pago] Revista de la Asociación Americana de Estadística , 29 (185): 169-170.

Krieger, N. (2012). ¿Quién y qué es una "población"? Debates históricos, controversias actuales e implicaciones para comprender la “salud de la población” y rectificar las inequidades en salud. . The Milbank Quarterly , 90 (4): 634–681.

Lee, HTK y Kemp, Z. (2000). Razonamiento jerárquico y procesamiento analítico en línea de datos espaciales y temporales. . En Actas del 9º Simposio Internacional sobre Manejo de Datos Espaciales , Beijing, PR China. Unión Geográfica Internacional.

Openshaw, S. (1983). El problema de la unidad de área modificable. Conceptos y técnicas en geografía moderna . Geo Books, Norwich, Reino Unido.

Alexis
fuente
10
Me entristeció votar esta respuesta porque su representante ahora es mayor que 8888, lo que me resultó estéticamente agradable.
Sycorax dice Reinstate Monica
@ hxd1011 y GeneralAbrial:: D: D: D: D
Alexis
ME ENCANTA esta respuesta, pero la respuesta de @ MatthewDrury es que realmente quiero ver.
Haitao Du
¡Gracias por una respuesta convincente con un montón de referencias interesantes!
y.selivonchyk