Quand devrions-nous discrétiser / classer les variables / caractéristiques indépendantes continues et quand ne le devrions-nous pas?

22

Quand devrions-nous discrétiser / classer les variables / fonctionnalités indépendantes et quand ne le devrions-nous pas?

Mes tentatives pour répondre à la question:

  • En général, nous ne devons pas bin, car le binning perdra des informations.
  • Le binning augmente en fait le degré de liberté du modèle, il est donc possible de provoquer un sur-ajustement après le binning. Si nous avons un modèle à «biais élevé», le binning n'est peut-être pas mauvais, mais si nous avons un modèle à «forte variance», nous devons éviter le binning.
  • Cela dépend du modèle que nous utilisons. S'il s'agit d'un mode linéaire et que les données ont beaucoup de probabilités de binning "aberrantes", c'est mieux. Si nous avons un modèle d'arbre, les valeurs aberrantes et le regroupement feront trop de différence.

Ai-je raison? et quoi d'autre?


Je pensais que cette question devrait être posée plusieurs fois mais je ne la trouve pas dans le CV uniquement ces messages

Faut-il regrouper des variables continues?

Quel est l'avantage de briser une variable prédictive continue?

Haitao Du
la source
Je ne pense pas que cette question soit un double car la réponse ne s'attaque pas réellement à ce problème ("devrions-nous le faire").
Firebug
8
Les approches CART / forêt aléatoire sont des variables continues plus ou moins binning (ajustant des fonctions constantes par morceaux), mais elles le font de bien meilleure façon. Si vous pré-binez, vous refusez à votre algorithme de construction d'arbres la flexibilité de placer les pauses à un endroit optimal ...
Ben Bolker

Réponses:

16

On dirait que vous cherchez également une réponse d'un point de vue prédictif, j'ai donc préparé une courte démonstration de deux approches dans R

  • Regroupement d'une variable en facteurs de taille égale.
  • Splines cubiques naturelles.

Ci-dessous, j'ai donné le code d'une fonction qui comparera automatiquement les deux méthodes pour une fonction de signal vraie donnée

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

Cette fonction créera des ensembles de données d'apprentissage et de test bruyants à partir d'un signal donné, puis adaptera une série de régressions linéaires aux données d'entraînement de deux types

  • Le cutsmodèle comprend des prédicteurs regroupés, formés en segmentant la plage des données en intervalles à moitié ouverts de taille égale, puis en créant des prédicteurs binaires indiquant à quel intervalle chaque point d'apprentissage appartient.
  • Le splinesmodèle comprend une expansion de base de spline cubique naturelle, avec des nœuds également espacés dans toute la plage du prédicteur.

Les arguments sont

  • signal: Une fonction à une variable représentant la vérité à estimer.
  • N: Le nombre d'échantillons à inclure dans les données de formation et de test.
  • noise: La quantité de bruit gaussien aléatoire à ajouter au signal d'entraînement et de test.
  • range: La plage des xdonnées de formation et de test , données générées uniformément dans cette plage.
  • max_paramters: Le nombre maximum de paramètres à estimer dans un modèle. Il s'agit à la fois du nombre maximal de segments dans le cutsmodèle et du nombre maximal de nœuds dans le splinesmodèle.

Notez que le nombre de paramètres estimés dans le splinesmodèle est le même que le nombre de nœuds, donc les deux modèles sont assez comparés.

L'objet de retour de la fonction a quelques composants

  • signal_plot: Un tracé de la fonction du signal.
  • data_plot: Un nuage de points des données de formation et de test.
  • errors_comparison_plot: Un graphique montrant l'évolution de la somme des taux d'erreur au carré pour les deux modèles sur une plage du nombre de paramètres estimés.

Je vais démontrer avec deux fonctions de signal. Le premier est une onde sinueuse avec une tendance linéaire croissante superposée

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

obj <- test_cuts_vs_splines(true_signal_sin, 250, 1)

Voici comment évoluent les taux d'erreur

regroupement vs splines entraînent et testent les performances avec un degré de liberté variable pour augmenter l'onde de péché

Le deuxième exemple est une fonction de noix que je garde juste pour ce genre de chose, tracez-la et voyez

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)

regroupement vs splines entraînent et testent les performances avec différents degrés de liberté pour augmenter la fonction bizarro

Et pour le plaisir, voici une fonction linéaire ennuyeuse

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

groupement vs splines entraînent et testent les performances avec différents degrés de liberté pour la fonction linéaire

Tu peux voir ça:

  • Les splines donnent globalement de meilleures performances de test lorsque la complexité du modèle est correctement réglée pour les deux.
  • Les splines offrent des performances de test optimales avec beaucoup moins de paramètres estimés .
  • Globalement, les performances des splines sont beaucoup plus stables car le nombre de paramètres estimés varie.

Les splines sont donc toujours à privilégier d'un point de vue prédictif.

Code

Voici le code que j'ai utilisé pour produire ces comparaisons. J'ai tout enveloppé dans une fonction pour que vous puissiez l'essayer avec vos propres fonctions de signal. Vous devrez importer les bibliothèques ggplot2and 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
la source
19

L'agrégation est substantiellement significative (que le chercheur en soit conscient ou non).

Il faut regrouper les données, y compris les variables indépendantes, sur la base des données elles-mêmes lorsque l'on veut:

  • À la puissance statistique de l'hémorragie.

  • Pour biaiser les mesures d'association.

Une littérature commençant, je crois, par Ghelke et Biehl (1934 - vaut vraiment la peine d'être lu, et suggérant quelques simulations informatiques assez faciles que l'on peut exécuter pour soi-même), et se poursuivant en particulier dans la littérature sur le `` problème d'unité de surface modifiable '' (Openshaw , 1983; Dudley, 1991; Lee et Kemp, 2000) clarifie ces deux points.

À moins d'avoir une théorie a priori de l' échelle d'agrégation (combien d'unités à agréger) et de la fonction de catégorisation d'agrégation (quelles observations individuelles finiront dans quelles unités d'agrégation), il ne faut pas agréger. Par exemple, en épidémiologie, nous nous soucions de la santé des individus et de la santé des populations . Ces dernières ne sont pas simplement des collections aléatoires des premières, mais définies par exemple par des frontières géopolitiques, des circonstances sociales comme la catégorisation ethnique-raciale, le statut carcéral et les catégories historiques, etc. (voir, par exemple, Krieger, 2012)

Références
Dudley, G. (1991). Échelle, agrégation et problème d'unité de surface modifiable . [muraille payante] The Operational Geographer, 9 (3): 28–33.

Gehlke, CE et Biehl, K. (1934). Certains effets du regroupement sur la taille du coefficient de corrélation dans le matériel des secteurs de recensement . [muraille payante] Journal de l'American Statistical Association , 29 (185): 169-170.

Krieger, N. (2012). Qui et qu'est-ce qu'une «population»? débats historiques, controverses actuelles et implications pour comprendre la «santé de la population» et corriger les inégalités en matière de santé . The Milbank Quarterly , 90 (4): 634–681.

Lee, HTK et Kemp, Z. (2000). Raisonnement hiérarchique et traitement analytique en ligne des données spatiales et temporelles . Dans les actes du 9e Symposium international sur le traitement des données spatiales , Beijing, RP Chine. Union géographique internationale.

Openshaw, S. (1983). Le problème de l'unité de surface modifiable. Concepts et techniques en géographie moderne . Geo Books, Norwich, Royaume-Uni.

Alexis
la source
10
J'étais triste de voter pour cette réponse parce que votre représentant est maintenant plus grand que 8888, ce qui me plaisait esthétiquement.
Sycorax dit Réintégrer Monica
@ hxd1011 et GeneralAbrial:: D: D: D: D
Alexis
J'AIME cette réponse, mais la réponse de @ MatthewDrury est vraiment que je veux voir.
Haitao Du
Merci pour une réponse convaincante avec un tas de références intéressantes!
y.selivonchyk