¿Cómo se puede depurar el error “los contrastes solo se pueden aplicar a factores con 2 o más niveles”?

Aquí están todas las variables con las que estoy trabajando:

str(ad.train) $ Date : Factor w/ 427 levels "2012-03-24","2012-03-29",..: 4 7 12 14 19 21 24 29 31 34 ... $ Team : Factor w/ 18 levels "Adelaide","Brisbane Lions",..: 1 1 1 1 1 1 1 1 1 1 ... $ Season : int 2012 2012 2012 2012 2012 2012 2012 2012 2012 2012 ... $ Round : Factor w/ 28 levels "EF","GF","PF",..: 5 16 21 22 23 24 25 26 27 6 ... $ Score : int 137 82 84 96 110 99 122 124 49 111 ... $ Margin : int 69 18 -56 46 19 5 50 69 -26 29 ... $ WinLoss : Factor w/ 2 levels "0","1": 2 2 1 2 2 2 2 2 1 2 ... $ Opposition : Factor w/ 18 levels "Adelaide","Brisbane Lions",..: 8 18 10 9 13 16 7 3 4 6 ... $ Venue : Factor w/ 19 levels "Adelaide Oval",..: 4 7 10 7 7 13 7 6 7 15 ... $ Disposals : int 406 360 304 370 359 362 365 345 324 351 ... $ Kicks : int 252 215 170 225 221 218 224 230 205 215 ... $ Marks : int 109 102 52 41 95 78 93 110 69 85 ... $ Handballs : int 154 145 134 145 138 144 141 115 119 136 ... $ Goals : int 19 11 12 13 16 15 19 19 6 17 ... $ Behinds : int 19 14 9 16 11 6 7 9 12 6 ... $ Hitouts : int 42 41 34 47 45 70 48 54 46 34 ... $ Tackles : int 73 53 51 76 65 63 65 67 77 58 ... $ Rebound50s : int 28 34 23 24 32 48 39 31 34 29 ... $ Inside50s : int 73 49 49 56 61 45 47 50 49 48 ... $ Clearances : int 39 33 38 52 37 43 43 48 37 52 ... $ Clangers : int 47 38 44 62 49 46 32 24 31 41 ... $ FreesFor : int 15 14 15 18 17 15 19 14 18 20 ... $ ContendedPossessions: int 152 141 149 192 138 164 148 151 160 155 ... $ ContestedMarks : int 10 16 11 3 12 12 17 14 15 11 ... $ MarksInside50 : int 16 13 10 8 12 9 14 13 6 12 ... $ OnePercenters : int 42 54 30 58 24 56 32 53 50 57 ... $ Bounces : int 1 6 4 4 1 7 11 14 0 4 ... $ GoalAssists : int 15 6 9 10 9 12 13 14 5 14 ... 

Aquí está el glm que bash encajar:

 ad.glm.all <- glm(WinLoss ~ factor(Team) + Season + Round + Score + Margin + Opposition + Venue + Disposals + Kicks + Marks + Handballs + Goals + Behinds + Hitouts + Tackles + Rebound50s + Inside50s+ Clearances+ Clangers+ FreesFor + ContendedPossessions + ContestedMarks + MarksInside50 + OnePercenters + Bounces+GoalAssists, data = ad.train, family = binomial(logit)) 

Sé que hay muchas variables (el plan es reducir mediante la selección de variables hacia adelante). Pero aun sabiendo que hay muchas variables, son int o Factor; que como yo entiendo las cosas solo deberían funcionar con un glm. Sin embargo, cada vez que bash adaptarme a este modelo, obtengo:

 Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : contrasts can be applied only to factors with 2 or more levels 

¿Qué tipo de cosas me parecen como si R no tratara mis variables Factor como variables Factor por alguna razón?

Incluso algo tan simple como:

 ad.glm.test <- glm(WinLoss ~ factor(Team), data = ad.train, family = binomial(logit)) 

no está funcionando! (el mismo mensaje de error)

Donde como esto:

 ad.glm.test <- glm(WinLoss ~ Clearances, data = ad.train, family = binomial(logit)) 

¡Trabajará!

Alguien sabe lo que está pasando aquí? ¿Por qué no puedo ajustar estas variables de Factor a mi glm?

¡Gracias por adelantado!

-Troy

Introducción

Lo que un “error de contrastes” ha sido bien explicado: usted tiene un factor que solo tiene un nivel (o menos) . Pero, en realidad, este simple hecho se puede ocultar fácilmente porque los datos que se usan realmente para la adaptación del modelo pueden ser muy diferentes de los que ha pasado. Esto sucede cuando tiene NA en sus datos, ha subconjunto sus datos, un factor tiene niveles no utilizados, o ha transformado sus variables y obtiene NaN algún lugar. Rara vez se encuentra en esta situación ideal en la que se puede detectar un factor de un solo nivel desde str(your_data_frame) directamente. Muchas preguntas sobre StackOverflow con respecto a este error no son reproducibles, por lo que las sugerencias de las personas pueden funcionar o no. Por lo tanto, aunque ahora hay 118 publicaciones relacionadas con este tema, los usuarios aún no pueden encontrar una solución adaptable, por lo que esta pregunta se plantea una y otra vez. Esta es mi respuesta, para resolver este asunto “de una vez por todas”, o al menos para proporcionar una guía razonable.

Esta respuesta tiene mucha información, así que permítanme primero hacer un resumen rápido.

debug_contr_error 3 funciones de ayuda para usted: debug_contr_error , debug_contr_error2 , NA_preproc .

Te recomiendo que los uses de la siguiente manera.

  1. ejecutar NA_preproc para obtener casos más completos;
  2. ejecuta tu modelo, y si obtienes un “error de contrastes”, utiliza debug_contr_error2 para la depuración.

La mayoría de las respuestas muestran paso a paso cómo y por qué se definen estas funciones. Probablemente no sea perjudicial omitir ese proceso de desarrollo, pero no omita las secciones de “Estudios de casos y debates reproducibles”.


Respuesta revisada

La respuesta original funciona perfectamente para OP , y ha ayudado con éxito a otros . Pero había fallado en otro lado por falta de adaptabilidad. Mire la salida de str(ad.train) en la pregunta. Las variables de OP son numéricas o factores; no hay personajes La respuesta original fue para esta situación. Si tiene variables de caracteres, aunque serán forzadas a factores durante el ajuste de lm y glm , el código no informará estos datos, ya que no se proporcionaron como factores, por lo que el is.factor se perderá. En esta expansión, haré que la respuesta original sea más adaptativa.

Deje dat sea ​​su conjunto de datos pasado a lm o glm . Si no tiene ese dataframe fácilmente, es decir, todas sus variables están dispersas en el entorno global, debe reunirlas en un dataframe. Lo siguiente puede no ser la mejor manera, pero funciona.

 ## `form` is your model formula, here is an example y <- x1 <- x2 <- x3 <- 1:4 x4 <- matrix(1:8, 4) form <- y ~ bs(x1) + poly(x2) + I(1 / x3) + x4 ## to gather variables `model.frame.default(form)` is the easiest way ## but it does too much: it drops `NA` and transforms variables ## we want something more primitive ## first get variable names vn <- all.vars(form) #[1] "y" "x1" "x2" "x3" "x4" ## `get_all_vars(form)` gets you a data frame ## but it is buggy for matrix variables so don't use it ## instead, first use `mget` to gather variables into a list lst <- mget(vn) ## don't do `data.frame(lst)`; it is buggy with matrix variables ## need to first protect matrix variables by `I()` then do `data.frame` lst_protect <- lapply(lst, function (x) if (is.matrix(x)) I(x) else x) dat <- data.frame(lst_protect) str(dat) #'data.frame': 4 obs. of 5 variables: # $ y : int 1 2 3 4 # $ x1: int 1 2 3 4 # $ x2: int 1 2 3 4 # $ x3: int 1 2 3 4 # $ x4: 'AsIs' int [1:4, 1:2] 1 2 3 4 5 6 7 8 ## note the 'AsIs' for matrix variable `x4` ## in comparison, try the following buggy ones yourself str(get_all_vars(form)) str(data.frame(lst)) 

Paso 0: subconjunto explícito

Si ha utilizado el argumento del subset de lm o glm , comience por un subconjunto explícito:

 ## `subset_vec` is what you pass to `lm` via `subset` argument ## it can either be a logical vector of length `nrow(dat)` ## or a shorter positive integer vector giving position index ## note however, `base::subset` expects logical vector for `subset` argument ## so a rigorous check is necessary here if (mode(subset_vec) == "logical") { if (length(subset_vec) != nrow(dat)) { stop("'logical' `subset_vec` provided but length does not match `nrow(dat)`") } subset_log_vec <- subset_vec } else if (mode(subset_vec) == "numeric") { ## check range ran <- range(subset_vec) if (ran[1] < 1 || ran[2] > nrow(dat)) { stop("'numeric' `subset_vec` provided but values are out of bound") } else { subset_log_vec <- logical(nrow(dat)) subset_log_vec[as.integer(subset_vec)] <- TRUE } } else { stop("`subset_vec` must be either 'logical' or 'numeric'") } dat <- base::subset(dat, subset = subset_log_vec) 

Paso 1: eliminar casos incompletos

 dat <- na.omit(dat) 

Puede omitir este paso si ha pasado por el paso 0, ya que el subset elimina automáticamente casos incompletos .

Paso 2: comprobación de modo y conversión

Una columna de dataframe suele ser un vector atómico, con un modo de los siguientes: "lógico", "numérico", "complejo", "personaje", "sin formato". Para la regresión, las variables de diferentes modos se manejan de manera diferente.

 "logical", it depends "numeric", nothing to do "complex", not allowed by `model.matrix`, though allowed by `model.frame` "character", converted to "numeric" with "factor" class by `model.matrix` "raw", not allowed by `model.matrix`, though allowed by `model.frame` 

Una variable lógica es engañosa. Puede tratarse como una variable ficticia ( 1 para TRUE , 0 para FALSE ) por lo tanto, un "numérico", o puede ser forzado a un factor de dos niveles. Todo depende de si model.matrix considera que es necesaria una coerción "factorial" a partir de la especificación de la fórmula de su modelo. Para simplificar, podemos entenderlo como tal: siempre se lo coacciona a un factor, pero el resultado de aplicar contrastes puede terminar con la misma matriz de modelo como si se manejara como un maniquí directamente.

Algunas personas pueden preguntarse por qué "entero" no está incluido. Porque un vector entero, como 1:4 , tiene un modo "numérico" ( mode(1:4) prueba mode(1:4) ).

Una columna de dataframe también puede ser una matriz con clase "AsIs", pero dicha matriz debe tener un modo "numérico".

Nuestra comprobación es para producir un error cuando

  • un "complejo" o "crudo" se encuentra;
  • se encuentra una variable de matriz "lógica" o "de carácter";

y proceda a convertir "lógico" y "personaje" a "numérico" de la clase "factor".

 ## get mode of all vars var_mode <- sapply(dat, mode) ## produce error if complex or raw is found if (any(var_mode %in% c("complex", "raw"))) stop("complex or raw not allowed!") ## get class of all vars var_class <- sapply(dat, class) ## produce error if an "AsIs" object has "logical" or "character" mode if (any(var_mode[var_class == "AsIs"] %in% c("logical", "character"))) { stop("matrix variables with 'AsIs' class must be 'numeric'") } ## identify columns that needs be coerced to factors ind1 <- which(var_mode %in% c("logical", "character")) ## coerce logical / character to factor with `as.factor` dat[ind1] <- lapply(dat[ind1], as.factor) 

Tenga en cuenta que si una columna de dataframe ya es una variable de factor, no se incluirá en ind1 , ya que una variable de factor tiene modo "numérico" ( mode(factor(letters[1:4])) prueba mode(factor(letters[1:4])) ).

paso 3: colocar niveles de factor no utilizados

No tendremos niveles de factores no utilizados para las variables de factor convertidas a partir del paso 2, es decir, aquellas indexadas por ind1 . Sin embargo, las variables de factor que vienen con dat pueden tener niveles no utilizados (a menudo como resultado del paso 0 y el paso 1). Tenemos que eliminar los posibles niveles no utilizados de ellos.

 ## index of factor columns fctr <- which(sapply(dat, is.factor)) ## factor variables that have skipped explicit conversion in step 2 ## don't simply do `ind2 <- fctr[-ind1]`; buggy if `ind1` is `integer(0)` ind2 <- if (length(ind1) > 0L) fctr[-ind1] else fctr ## drop unused levels dat[ind2] <- lapply(dat[ind2], droplevels) 

paso 4: resume las variables de los factores

Ahora estamos listos para ver qué y cuántos niveles de factor realmente utilizan los lm o glm :

 ## export factor levels actually used by `lm` and `glm` lev <- lapply(dat[fctr], levels) ## count number of levels nl <- lengths(lev) 

Para hacerte la vida más fácil, he completado esos pasos en una función debug_contr_error .

Entrada:

  • dat es su dataframe pasado a lm o glm través data argumento de data ;
  • subset_vec es el vector de índice pasado a lm o glm través del argumento subset .

Salida: una lista con

  • nlevels (una lista) da la cantidad de niveles de factores para todas las variables de factores;
  • levels (un vector) da niveles para todas las variables de los factores.

La función produce una advertencia, si no hay casos completos o variables de factores para resumir.

 debug_contr_error <- function (dat, subset_vec = NULL) { if (!is.null(subset_vec)) { ## step 0 if (mode(subset_vec) == "logical") { if (length(subset_vec) != nrow(dat)) { stop("'logical' `subset_vec` provided but length does not match `nrow(dat)`") } subset_log_vec <- subset_vec } else if (mode(subset_vec) == "numeric") { ## check range ran <- range(subset_vec) if (ran[1] < 1 || ran[2] > nrow(dat)) { stop("'numeric' `subset_vec` provided but values are out of bound") } else { subset_log_vec <- logical(nrow(dat)) subset_log_vec[as.integer(subset_vec)] <- TRUE } } else { stop("`subset_vec` must be either 'logical' or 'numeric'") } dat <- base::subset(dat, subset = subset_log_vec) } else { ## step 1 dat <- stats::na.omit(dat) } if (nrow(dat) == 0L) warning("no complete cases") ## step 2 var_mode <- sapply(dat, mode) if (any(var_mode %in% c("complex", "raw"))) stop("complex or raw not allowed!") var_class <- sapply(dat, class) if (any(var_mode[var_class == "AsIs"] %in% c("logical", "character"))) { stop("matrix variables with 'AsIs' class must be 'numeric'") } ind1 <- which(var_mode %in% c("logical", "character")) dat[ind1] <- lapply(dat[ind1], as.factor) ## step 3 fctr <- which(sapply(dat, is.factor)) if (length(fctr) == 0L) warning("no factor variables to summary") ind2 <- if (length(ind1) > 0L) fctr[-ind1] else fctr dat[ind2] <- lapply(dat[ind2], base::droplevels.factor) ## step 4 lev <- lapply(dat[fctr], base::levels.default) nl <- lengths(lev) ## return list(nlevels = nl, levels = lev) } 

Aquí hay un pequeño ejemplo construido.

 dat <- data.frame(y = 1:4, x = c(1:3, NA), f1 = gl(2, 2, labels = letters[1:2]), f2 = c("A", "A", "A", "B"), stringsAsFactors = FALSE) # yx f1 f2 #1 1 1 a A #2 2 2 a A #3 3 3 b A #4 4 NA b B str(dat) #'data.frame': 4 obs. of 4 variables: # $ y : int 1 2 3 4 # $ x : int 1 2 3 NA # $ f1: Factor w/ 2 levels "a","b": 1 1 2 2 # $ f2: chr "A" "A" "A" "B" lm(y ~ x + f1 + f2, dat) #Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : # contrasts can be applied only to factors with 2 or more levels 

Bien, vemos un error. Ahora mi debug_contr_error expone que f2 termina con un solo nivel.

 debug_contr_error(dat) #$nlevels #f1 f2 # 2 1 # #$levels #$levels$f1 #[1] "a" "b" # #$levels$f2 #[1] "A" 

Tenga en cuenta que la respuesta corta original es inútil aquí, ya que f2 se proporciona como una variable de carácter no una variable de factor.

 ## old answer tmp <- na.omit(dat) fctr <- lapply(tmp[sapply(tmp, is.factor)], droplevels) sapply(fctr, nlevels) #f1 # 2 rm(tmp, fctr) 

Ahora veamos un ejemplo con una variable de matriz x .

 dat <- data.frame(X = I(rbind(matrix(1:6, 3), NA)), f = c("a", "a", "a", "b"), y = 1:4) dat # X.1 X.2 fy #1 1 4 a 1 #2 2 5 a 2 #3 3 6 a 3 #4 NA NA b 4 str(dat) #'data.frame': 4 obs. of 3 variables: # $ X: 'AsIs' int [1:4, 1:2] 1 2 3 NA 4 5 6 NA # $ f: Factor w/ 2 levels "a","b": 1 1 1 2 # $ y: int 1 2 3 4 lm(y ~ X + f, data = dat) #Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : # contrasts can be applied only to factors with 2 or more levels debug_contr_error(dat)$nlevels #f #1 

Tenga en cuenta que una variable de factor sin niveles también puede causar un "error de contrastes". Puede preguntarse cómo es posible un factor de nivel 0. Bueno, es legítimo: nlevels(factor(character(0))) . Aquí terminará con factores de nivel 0 si no tiene casos completos.

 dat <- data.frame(y = 1:4, x = rep(NA_real_, 4), f1 = gl(2, 2, labels = letters[1:2]), f2 = c("A", "A", "A", "B"), stringsAsFactors = FALSE) lm(y ~ x + f1 + f2, dat) #Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : # contrasts can be applied only to factors with 2 or more levels debug_contr_error(dat)$nlevels #f1 f2 # 0 0 ## all values are 0 #Warning message: #In debug_contr_error(dat) : no complete cases 

Finalmente, veamos una situación en la que si f2 es una variable lógica.

 dat <- data.frame(y = 1:4, x = c(1:3, NA), f1 = gl(2, 2, labels = letters[1:2]), f2 = c(TRUE, TRUE, TRUE, FALSE)) dat # yx f1 f2 #1 1 1 a TRUE #2 2 2 a TRUE #3 3 3 b TRUE #4 4 NA b FALSE str(dat) #'data.frame': 4 obs. of 4 variables: # $ y : int 1 2 3 4 # $ x : int 1 2 3 NA # $ f1: Factor w/ 2 levels "a","b": 1 1 2 2 # $ f2: logi TRUE TRUE TRUE FALSE 

Nuestro depurador predecirá un "error de contrastes", pero ¿realmente sucederá?

 debug_contr_error(dat)$nlevels #f1 f2 # 2 1 

No, al menos, esto no falla ( el coeficiente de NA se debe a la deficiencia de rango del modelo, no se preocupe ):

 lm(y ~ x + f1 + f2, data = dat) #Coefficients: #(Intercept) x f1b f2TRUE # 0 1 0 NA 

Es difícil para mí dar con un ejemplo que da un error, pero tampoco es necesario. En la práctica, no usamos el depurador para la predicción; lo usamos cuando realmente obtenemos un error; y en ese caso, el depurador puede ubicar la variable de factor ofensivo.

Tal vez algunos puedan argumentar que una variable lógica no es diferente de un maniquí. Pero pruebe el ejemplo simple a continuación: depende de su fórmula.

 u <- c(TRUE, TRUE, FALSE, FALSE) v <- c(1, 1, 0, 0) ## "numeric" dummy of `u` model.matrix(~ u) # (Intercept) uTRUE #1 1 1 #2 1 1 #3 1 0 #4 1 0 model.matrix(~ v) # (Intercept) v #1 1 1 #2 1 1 #3 1 0 #4 1 0 model.matrix(~ u - 1) # uFALSE uTRUE #1 0 1 #2 0 1 #3 1 0 #4 1 0 model.matrix(~ v - 1) # v #1 1 #2 1 #3 0 #4 0 

Implementación más flexible usando el método "model.frame" de lm

También se recomienda pasar por R: cómo depurar el error de "factor tiene nuevos niveles" para el modelo lineal y la predicción , lo que explica qué hacen lm y glm bajo el capó de su conjunto de datos. Comprenderá que los pasos 0 a 4 enumerados anteriormente solo intentan imitar dicho proceso interno. Recuerde, los datos que se usan realmente para la adaptación del modelo pueden ser muy diferentes de los que ha pasado .

Nuestros pasos no son completamente consistentes con dicho procesamiento interno. Para una comparación, puede recuperar el resultado del procesamiento interno utilizando method = "model.frame" en lm y glm . Pruebe esto en el ejemplo minúsculo previamente construido dat donde f2 es una variable de caracteres.

 dat_internal <- lm(y ~ x + f1 + f2, dat, method = "model.frame") dat_internal # yx f1 f2 #1 1 1 a A #2 2 2 a A #3 3 3 b A str(dat_internal) #'data.frame': 3 obs. of 4 variables: # $ y : int 1 2 3 # $ x : int 1 2 3 # $ f1: Factor w/ 2 levels "a","b": 1 1 2 # $ f2: chr "A" "A" "A" ## [.."terms" attribute is truncated..] 

En la práctica, model.frame solo realizará los pasos 0 y 1. También descarta las variables provistas en su conjunto de datos pero no en su fórmula de modelo. Por lo tanto, un marco de modelo puede tener tanto menos filas y columnas que lo que usted alimenta lm y glm . La coerción de tipo como se hace en nuestro paso 2 es realizada por el model.matrix posterior donde se puede producir un "error de contrastes".

Hay algunas ventajas para obtener primero este marco de modelo interno, luego pasarlo a debug_contr_error (para que solo realice esencialmente los pasos 2 a 4).

ventaja 1: se ignoran las variables que no se usan en su fórmula de modelo

 ## no variable `f1` in formula dat_internal <- lm(y ~ x + f2, dat, method = "model.frame") ## compare the following debug_contr_error(dat)$nlevels #f1 f2 # 2 1 debug_contr_error(dat_internal)$nlevels #f2 # 1 

ventaja 2: capaz de hacer frente a las variables transformadas

Es válido para transformar variables en la fórmula del modelo, y model.frame registrará las transformadas en lugar de las originales. Tenga en cuenta que, incluso si su variable original no tiene NA , la transformada puede tener.

 dat <- data.frame(y = 1:4, x = c(1:3, -1), f = rep(letters[1:2], c(3, 1))) # yxf #1 1 1 a #2 2 2 a #3 3 3 a #4 4 -1 b lm(y ~ log(x) + f, data = dat) #Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : # contrasts can be applied only to factors with 2 or more levels #In addition: Warning message: #In log(x) : NaNs produced # directly using `debug_contr_error` is hopeless here debug_contr_error(dat)$nlevels #f #2 ## this works dat_internal <- lm(y ~ log(x) + f, data = dat, method = "model.frame") # y log(x) f #1 1 0.0000000 a #2 2 0.6931472 a #3 3 1.0986123 a debug_contr_error(dat_internal)$nlevels #f #1 

Dados estos beneficios, escribo otra función que completa model.frame y debug_contr_error .

Entrada :

  • form es su fórmula modelo;
  • dat es el conjunto de datos pasado a lm o glm través data argumento de data ;
  • subset_vec es el vector de índice pasado a lm o glm través del argumento subset .

Salida: una lista con

  • mf (un dataframe) da el marco del modelo (con el atributo "términos" caído);
  • nlevels (una lista) da la cantidad de niveles de factores para todas las variables de factores;
  • levels (un vector) da niveles para todas las variables de los factores.
 ## note: this function relies on `debug_contr_error` debug_contr_error2 <- function (form, dat, subset_vec = NULL) { ## step 0 if (!is.null(subset_vec)) { if (mode(subset_vec) == "logical") { if (length(subset_vec) != nrow(dat)) { stop("'logical' `subset_vec` provided but length does not match `nrow(dat)`") } subset_log_vec <- subset_vec } else if (mode(subset_vec) == "numeric") { ## check range ran <- range(subset_vec) if (ran[1] < 1 || ran[2] > nrow(dat)) { stop("'numeric' `subset_vec` provided but values are out of bound") } else { subset_log_vec <- logical(nrow(dat)) subset_log_vec[as.integer(subset_vec)] <- TRUE } } else { stop("`subset_vec` must be either 'logical' or 'numeric'") } dat <- base::subset(dat, subset = subset_log_vec) } ## step 0 and 1 dat_internal <- stats::lm(form, data = dat, method = "model.frame") attr(dat_internal, "terms") <- NULL ## rely on `debug_contr_error` for steps 2 to 4 c(list(mf = dat_internal), debug_contr_error(dat_internal, NULL)) } 

Pruebe el ejemplo anterior de transformación de log .

 debug_contr_error2(y ~ log(x) + f, dat) #$mf # y log(x) f #1 1 0.0000000 a #2 2 0.6931472 a #3 3 1.0986123 a # #$nlevels #f #1 # #$levels #$levels$f #[1] "a" # # #Warning message: #In log(x) : NaNs produced 

Pruebe subset_vec también.

 ## or: debug_contr_error2(y ~ log(x) + f, dat, c(T, F, T, T)) debug_contr_error2(y ~ log(x) + f, dat, c(1,3,4)) #$mf # y log(x) f #1 1 0.000000 a #3 3 1.098612 a # #$nlevels #f #1 # #$levels #$levels$f #[1] "a" # # #Warning message: #In log(x) : NaNs produced 

Modelo de ajuste por grupo y NA como niveles de factor

Si se ajusta modelo por grupo, es más probable que obtenga un "error de contrastes". Necesitas

  1. divida su dataframe por la variable de agrupamiento (vea ?split.data.frame );
  2. trabaje a través de esos marcos de datos uno por uno, aplicando debug_contr_error2 (la función lapply puede ser útil para hacer este ciclo).

Algunos también me dijeron que no pueden usar na.omit en sus datos, porque terminará muy pocas filas para hacer algo sensato. Esto puede ser relajado. En la práctica, es NA_integer_ y NA_real_ que deben omitirse, pero NA_character_ puede conservarse: simplemente agregue NA como un nivel de factor. Para lograr esto, debe recorrer las variables en su dataframe:

  • si una variable x ya es un factor y anyNA(x) es TRUE , haga x <- addNA(x) . El "y" es importante. Si x no tiene NA , addNA(x) agregará un nivel no utilizado.
  • si una variable x es un caracter, haga x <- factor(x, exclude = NULL) para forzarlo a un factor. exclude = NULL retendrá como un nivel.
  • si x es "lógico", "numérico", "crudo" o "complejo", no se debe cambiar nada. NA es solo NA .

nivel de factor no será eliminado por droplevels o na.omit , y es válido para construir una matriz modelo. Verifique los siguientes ejemplos.

 ## x is a factor with NA x <- factor(c(letters[1:4], NA)) ## default: `exclude = NA` #[1] abcd  ## there is an NA value #Levels: abcd ## but NA is not a level na.omit(x) ## NA is gone #[1] abcd #[.. attributes truncated..] #Levels: abcd x <- addNA(x) ## now add NA into a valid level #[1] abcd  #Levels: abcd  ## it appears here droplevels(x) ## it can not be dropped #[1] abcd  #Levels: abcd  na.omit(x) ## it is not omitted #[1] abcd  #Levels: abcd  model.matrix(~ x) ## and it is valid to be in a design matrix # (Intercept) xb xc xd xNA #1 1 0 0 0 0 #2 1 1 0 0 0 #3 1 0 1 0 0 #4 1 0 0 1 0 #5 1 0 0 0 1 

 ## x is a character with NA x <- c(letters[1:4], NA) #[1] "a" "b" "c" "d" NA as.factor(x) ## this calls `factor(x)` with default `exclude = NA` #[1] abcd  ## there is an NA value #Levels: abcd ## but NA is not a level factor(x, exclude = NULL) ## we want `exclude = NULL` #[1] abcd  #Levels: abcd  ## now NA is a level 

Una vez que agregue NA como un nivel en un factor / carácter, su conjunto de datos de repente podría tener casos más completos. Entonces puedes ejecutar tu modelo. Si aún obtiene un "error de contrastes", use debug_contr_error2 para ver qué sucedió.

Para su comodidad, escribo una función para este preprocesamiento de NA .

Entrada :

  • dat es tu conjunto de datos completo .

Salida:

  • un dataframe, con NA agregado como un nivel para factor / personaje.
 NA_preproc <- function (dat) { for (j in 1:ncol(dat)) { x <- dat[[j]] if (is.factor(x) && anyNA(x)) dat[[j]] <- base::addNA(x) if (is.character(x)) dat[[j]] <- factor(x, exclude = NULL) } dat } 

Estudios de casos y discusiones reproducibles

Los siguientes son especialmente seleccionados para estudios de casos reproducibles, ya que acabo de responderlos con las tres funciones de ayuda creadas aquí.

  • ¿Cómo hacer un GLM cuando "los contrastes se pueden aplicar solo a factores con 2 o más niveles"?
  • R: Error en contrastes cuando se ajustan modelos lineales con `lm`

También hay otros pocos hilos de buena calidad resueltos por otros usuarios de StackOverflow:

  • Factores que no se reconocen en un mapa de uso de lm () (esto se trata de la adaptación del modelo por grupo)
  • ¿Cómo se puede descartar la observación de factores de NA condicionalmente cuando se hace regresión lineal en R? (Esto es similar al caso 1 en la lista anterior)
  • Error de factor / nivel en el modelo mixto (otra publicación sobre la adaptación del modelo por grupo)

Esta respuesta tiene como objective depurar el "error de contrastes" durante la adaptación del modelo. Sin embargo, este error también puede aparecer al usar predict de predicción. Tal comportamiento no es con predict.lm o predict.glm , sino con métodos de predicción de algunos paquetes. Aquí hay algunos hilos relacionados en StackOverflow.

  • Predicción en R - GLMM
  • Error en el error de 'contrastes'
  • SVM predict en dataframe con diferentes niveles de factor
  • Usar predecir con svyglm
  • debe un conjunto de datos contiene todos los factores en SVM en R
  • Predicciones de probabilidad con modelos mixtos de enlaces acumulativos
  • debe un conjunto de datos contiene todos los factores en SVM en R

También tenga en cuenta que la filosofía de esta respuesta se basa en la de lm y glm . Estas dos funciones son un estándar de encoding para muchas rutinas de ajuste de modelos , pero quizás no todas las rutinas de ajuste de modelos se comporten de manera similar. Por ejemplo, lo siguiente no me parece transparente si mis funciones auxiliares realmente serían útiles.

  • Error con svychisq - 'el contraste se puede aplicar a factores con 2 o más niveles'
  • R packages effects & plm: "error en contrastes" cuando se intenta trazar efectos marginales
  • Los contrastes se pueden aplicar solo al factor
  • R: lawstat :: levene.test falla mientras Fligner Killeen funciona, así como auto :: leveneTest
  • R - error de geeglm: los contrastes se pueden aplicar solo a factores con 2 o más niveles

Aunque un poco fuera de tema, todavía es útil saber que a veces un "error de contrastes" simplemente proviene de escribir un código incorrecto. En los siguientes ejemplos, OP pasó el nombre de sus variables en lugar de sus valores a lm . Como un nombre es un carácter de valor único, posteriormente se fuerza a un factor de un solo nivel y causa el error.

  • Error en `contrastes <-` (` * tmp * `, value = contr.funs [1 + isOF [nn]]): los contrastes se pueden aplicar solo a factores con 2 o más niveles
  • Bucle a través de un vector de caracteres para usar en una función

¿Cómo resolver este error después de la depuración?

En la práctica, la gente quiere saber cómo resolver este problema, ya sea a nivel estadístico o a nivel de progtwigción.

Si está ajustando modelos en su conjunto de datos completo, probablemente no haya una solución estadística, a menos que pueda imputar valores perdidos o recostackr más datos. Por lo tanto, puede recurrir a una solución de encoding para descartar la variable ofensiva. debug_contr_error2 devuelve nlevels que te ayuda a localizarlos fácilmente. Si no quiere soltarlos, reemplácelos por un vector de 1 (como se explica en Cómo hacer un GLM cuando "los contrastes se pueden aplicar solo a factores con 2 o más niveles"? ) Y deje que lm o glm con la deficiencia de rango resultante.

Si está ajustando modelos en un subconjunto, puede haber soluciones estadísticas.

Ajustar los modelos por grupo no requiere necesariamente dividir su conjunto de datos por grupo y ajustar modelos independientes. Lo siguiente puede darle una idea aproximada:

  • R análisis de regresión: análisis de datos para una determinada etnia
  • Encontrar la pendiente para puntos múltiples en columnas seleccionadas
  • R: construya modelos separados para cada categoría

Si divide sus datos explícitamente, puede obtener fácilmente "contrastes de error", por lo tanto, tendrá que ajustar la fórmula de su modelo por grupo (es decir, debe generar dinámicamente las fórmulas del modelo). Una solución más simple es omitir la construcción de un modelo para este grupo.

También puede dividir aleatoriamente su conjunto de datos en un subconjunto de capacitación y un subconjunto de prueba para que pueda realizar la validación cruzada. R: cómo depurar el error "factor tiene nuevos niveles" para el modelo lineal y la predicción lo menciona brevemente, y será mejor que realice un muestreo estratificado para garantizar el éxito tanto de la estimación del modelo en la parte de entrenamiento como de la predicción en la parte de prueba.

    Intereting Posts