Como depurar o erro “os contrastes podem ser aplicados apenas a fatores com 2 ou mais níveis”?

Aqui estão todas as variables ​​com as quais estou trabalhando:

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 ... 

Aqui está o glm que estou tentando encheckboxr:

 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)) 

Eu sei que é um monte de variables ​​(o plano é reduzir através da seleção de variables ​​para frente). Mas mesmo sabendo que são muitas variables, elas são int ou Factor; que, pelo que entendi, as coisas deveriam funcionar apenas com um glm. No entanto, toda vez que eu tento encheckboxr esse modelo eu fico:

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

Que tipo de olhar para mim como se R não está tratando minhas variables ​​de fator como variables ​​fator por algum motivo?

Mesmo algo tão simples como:

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

não está funcionando! (mesma mensagem de erro)

Onde como isto:

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

Vai funcionar!

Alguém sabe o que está acontecendo aqui? Por que não posso ajustar essas variables ​​de fator ao meu glm ??

Desde já, obrigado!

-Troy

    Introdução

    O que é um “erro de contraste” foi bem explicado: você tem um fator que tem apenas um nível (ou menos) . Mas, na realidade, esse simples fato pode ser facilmente obscurecido porque os dados que são realmente usados ​​para adaptação do modelo podem ser muito diferentes do que você passou. Isso acontece quando você tem NA em seus dados, você subconjunto seus dados, um o fator tem níveis não utilizados, ou você transformou suas variables ​​e obtém o NaN algum lugar. Você raramente está nessa situação ideal em que um fator de nível único pode ser localizado diretamente de str(your_data_frame) . Muitas questões sobre StackOverflow relativas a este erro não são reproduzíveis, portanto sugestões de pessoas podem ou não funcionar. Portanto, embora existam atualmente 118 postagens sobre esse problema, os usuários ainda não conseguem encontrar uma solução adaptável para que essa questão seja levantada repetidas vezes. Esta resposta é a minha tentativa de resolver este assunto “de uma vez por todas”, ou pelo menos fornecer um guia razoável.

    Esta resposta tem informações ricas, então deixe-me primeiro fazer um resumo rápido.

    Eu defini 3 funções auxiliares para você: debug_contr_error , debug_contr_error2 , NA_preproc .

    Eu recomendo que você os use da seguinte maneira.

    1. executar NA_preproc para obter casos mais completos;
    2. execute seu modelo e, se você receber um “erro de contraste”, use debug_contr_error2 para debugging.

    A maior parte da resposta mostra passo a passo como e por que essas funções são definidas. Provavelmente, não há mal algum em pular esse processo de desenvolvimento, mas não pule seções de “Estudos de casos e discussões reprodutíveis”.


    Resposta revisada

    A resposta original funciona perfeitamente para o OP e ajudou alguns outros com sucesso . Mas havia falhado em outro lugar por falta de adaptabilidade. Veja a saída de str(ad.train) na questão. As variables ​​do OP são numéricas ou fatores; não há personagens. A resposta original foi para esta situação. Se você tiver variables ​​de caractere, embora elas sejam coagidas a fatores durante o ajuste de lm e glm , elas não serão relatadas pelo código, uma vez que elas não foram fornecidas como fatores que o is.factor não is.factor . Nesta expansão, tornarei a resposta original mais adaptativa.

    Deixe dat ser seu dataset passado para lm ou glm . Se você não tiver prontamente esse quadro de dados, ou seja, todas as suas variables ​​estão espalhadas no ambiente global, você precisa reuni-las em um quadro de dados. O seguinte pode não ser o melhor caminho, mas 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)) 

    Etapa 0: subconjunto explícito

    Se você usou o argumento de subset de lm ou glm , comece por um subset 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) 

    Etapa 1: remover casos incompletos

     dat < - na.omit(dat) 

    Você pode pular esta etapa se tiver passado pela etapa 0, pois o subset remove automaticamente os casos incompletos .

    Etapa 2: verificação e conversão de modo

    Uma coluna do quadro de dados é geralmente um vetor atômico, com um modo do seguinte: "lógico", "numérico", "complexo", "caractere", "bruto". Para regressão, variables ​​de diferentes modos são tratadas de maneira 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` 

    Uma variável lógica é complicada. Ele pode ser tratado como uma variável dummy ( 1 para TRUE ; 0 para FALSE ), portanto, um "numérico", ou pode ser coagido a um fator de dois níveis. Tudo depende se model.matrix acha que uma coerção "to-factor" é necessária a partir da especificação de sua fórmula modelo. Por simplicidade, podemos entendê-lo como tal: ele é sempre coagido a um fator, mas o resultado da aplicação de contrastes pode acabar com a mesma matriz de modelo, como se fosse manipulado como um manequim diretamente.

    Algumas pessoas podem se perguntar por que "inteiro" não está incluído. Porque um vetor inteiro, como 1:4 , tem um modo "numérico" ( mode(1:4) ).

    Uma coluna do quadro de dados também pode ser uma matriz com a class "AsIs", mas essa matriz deve ter o modo "numérico".

    Nossa verificação é produzir erro quando

    • um "complexo" ou "bruto" é encontrado;
    • uma variável de matriz "lógica" ou "caractere" é encontrada;

    e prossiga para converter "lógico" e "caractere" para "numérico" da class "fator".

     ## 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) 

    Note que se uma coluna de frame de dados já for uma variável de fator, ela não será incluída em ind1 , já que uma variável de fator possui o modo "numérico" ( mode(factor(letters[1:4])) try mode(factor(letters[1:4])) ).

    Etapa 3: descarte os níveis dos fatores não utilizados

    Não teremos níveis de fator não utilizados para variables ​​de fator convertidas da etapa 2, isto é, aquelas indexadas por ind1 . No entanto, as variables ​​de fator que vêm com o dat podem ter níveis não utilizados (geralmente como resultado da etapa 0 e da etapa 1). Precisamos eliminar todos os níveis possíveis não utilizados deles.

     ## 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) 

    etapa 4: resumir as variables ​​do fator

    Agora estamos prontos para ver o que e quantos níveis de fator são realmente usados ​​por lm ou glm :

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

    Para tornar sua vida mais fácil, eu debug_contr_error esses passos em uma function debug_contr_error .

    Entrada:

    • dat é o seu quadro de dados passado para lm ou glm via argumento de data ;
    • subset_vec é o vetor de índice passado para lm ou glm via argumento de subset .

    Saída: uma lista com

    • nlevels (uma lista) fornece o número de níveis de fatores para todas as variables ​​de fatores;
    • levels (um vetor) fornece níveis para todas as variables ​​do fator.

    A function produz um aviso, se não houver casos completos ou nenhuma variável de fator 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) } 

    Aqui está um pequeno exemplo construído.

     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 

    Bom, nós vemos um erro. Agora meu debug_contr_error expõe que f2 acaba com um único nível.

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

    Observe que a resposta curta original é inútil aqui, pois f2 é fornecido como uma variável de caractere e não como uma variável de fator.

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

    Agora vamos ver um exemplo com uma variável 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 

    Observe que uma variável de fator sem níveis pode causar um "erro de contraste" também. Você pode se perguntar como um fator de nível 0 é possível. Bem, é legítimo: nlevels(factor(character(0))) . Aqui você terminará com um fator de nível 0 se não tiver 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, vamos ver algumas situações em que if f2 é uma variável 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 

    Nosso debugger irá prever um "erro de contraste", mas será que isso realmente acontecerá?

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

    Não, pelo menos este não falha ( o coeficiente de NA é devido à baixa pontuação do modelo; não se preocupe ):

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

    É difícil para mim dar um exemplo, mas também não há necessidade. Na prática, não usamos o depurador para previsão; nós usamos quando realmente recebemos um erro; e nesse caso, o depurador pode localizar a variável do fator ofensivo.

    Talvez alguns possam argumentar que uma variável lógica não é diferente de um manequim. Mas tente o exemplo simples abaixo: depende da sua 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 

    Implementação mais flexível usando o método "model.frame" de lm

    Você também é aconselhado a passar por R: como depurar o erro "fator tem novos níveis" para o modelo linear e a previsão , o que explica o que o lm e o glm fazem sob o capô do seu dataset. Você entenderá que as etapas de 0 a 4 listadas acima estão apenas tentando imitar esse processo interno. Lembre-se, os dados que são realmente usados ​​para o ajuste do modelo podem ser muito diferentes do que você passou .

    Nossas etapas não são completamente consistentes com esse processamento interno. Para uma comparação, você pode recuperar o resultado do processamento interno usando method = "model.frame" em lm e glm . Tente isso no pequeno exemplo dat construído anteriormente, onde f2 é uma variável de caractere.

     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..] 

    Na prática, model.frame executará apenas a etapa 0 e a etapa 1. Também descarta as variables ​​fornecidas em seu dataset, mas não na fórmula do modelo. Assim, um quadro de modelo pode ter menos linhas e colunas do que você alimenta lm e glm . Tipo coercing como feito em nossa etapa 2 é feito pelo model.matrix posterior, onde um "erro de contraste" pode ser produzido.

    Há algumas vantagens em primeiro obter esse quadro de modelo interno, em seguida, passá-lo para debug_contr_error (para que ele essencialmente executa as etapas 2 a 4).

    Vantagem 1: variables ​​não usadas em sua fórmula modelo são ignoradas

     ## 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 

    Vantagem 2: capaz de lidar com variables ​​transformadas

    É válido transformar variables ​​na fórmula do modelo e model.frame registrará as transformadas em vez das originais. Note que, mesmo que sua variável original não tenha NA , a transformada pode ter.

     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 esses benefícios, eu escrevo outra function encerrando model.frame e debug_contr_error .

    Entrada :

    • form é sua fórmula modelo;
    • dat é o dataset passado para lm ou glm via argumento de data ;
    • subset_vec é o vetor de índice passado para lm ou glm via argumento de subset .

    Saída: uma lista com

    • mf (um quadro de dados) fornece o quadro do modelo (com o atributo "termos" eliminado);
    • nlevels (uma lista) fornece o número de níveis de fatores para todas as variables ​​de fatores;
    • levels (um vetor) fornece níveis para todas as variables ​​do fator.
     ## 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)) } 

    Experimente o exemplo anterior de transformação 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 

    Tente também o subset_vec .

     ## 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 assembly por grupo e NA como níveis de fator

    Se você estiver ajustando o modelo por grupo, é mais provável que você receba um "erro de contraste". Você precisa

    1. divida seu quadro de dados pela variável de agrupamento (consulte ?split.data.frame );
    2. trabalhe através desses frameworks de dados um por um, aplicando debug_contr_error2 (a function lapply pode ser útil para fazer este loop).

    Alguns também me disseram que eles não podem usar na.omit em seus dados, porque ele vai acabar com poucas linhas para fazer qualquer coisa sensata. Isso pode ser relaxado. Na prática, é o NA_integer_ e o NA_real_ que devem ser omitidos, mas o NA_character_ pode ser retido: basta adicionar NA como um nível de fator. Para conseguir isso, você precisa percorrer as variables ​​em seu quadro de dados:

    • se uma variável x já é um fator e anyNA(x) é TRUE , faça x < - addNA(x) . O "e" é importante. Se x não tiver NA , addNA(x) adicionará um nível não utilizado.
    • se uma variável x for um caractere, faça x < - factor(x, exclude = NULL) para coagi-lo a um fator. exclude = NULL reterá como um nível.
    • se x for "lógico", "numérico", "bruto" ou "complexo", nada deverá ser alterado. NA é apenas NA .

    nível do fator não será eliminado por droplevels de droplevels ou na.omit , e é válido para construir uma matriz modelo. Verifique os exemplos a seguir.

     ## 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 

    Depois que você adicionar NA como um nível em um fator / caractere, seu dataset poderá ter casos mais completos. Então você pode executar o seu modelo. Se você ainda receber um "erro de contraste", use debug_contr_error2 para ver o que aconteceu.

    Para sua conveniência, escrevo uma function para esse pré-processamento de NA .

    Entrada :

    • dat é seu dataset completo .

    Saída:

    • um quadro de dados, com NA adicionado como um nível de fator / caractere.
     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 } 

    Estudos de casos reprodutíveis e discussões

    Os itens a seguir são especialmente selecionados para estudos de caso reproduzíveis, pois acabei de respondê-los com as três funções auxiliares criadas aqui.

    • Como fazer um GLM quando "contrastes podem ser aplicados apenas a fatores com 2 ou mais níveis"?
    • R: Erro nos contrastes ao ajustar modelos lineares com `lm`

    Há também alguns outros tópicos de boa qualidade resolvidos por outros usuários do StackOverflow:

    • Fatores não sendo reconhecidos em um lm usando map () (isso é sobre o ajuste do modelo por grupo)
    • Como diminuir a observação de fatores de NA condicionalmente ao fazer a regressão linear em R? (isso é semelhante ao caso 1 na lista anterior)
    • Erro de fator / nível em modelo misto (outro post sobre ajuste de modelo por grupo)

    Esta resposta tem como objective depurar o "erro de contraste" durante o ajuste do modelo. No entanto, esse erro também pode aparecer ao usar predict para previsão. Esse comportamento não é com predict.lm ou predict.glm , mas com methods de previsão de alguns pacotes. Aqui estão alguns tópicos relacionados no StackOverflow.

    • Previsão em R - GLMM
    • Erro no erro "contrasts"
    • O SVM prevê o dataframe com diferentes níveis de fatores
    • Usando prever com svyglm
    • um dataset deve conter todos os fatores no SVM em R
    • Previsões de Probabilidade com Modelos Mistos de Link Cumulativo
    • um dataset deve conter todos os fatores no SVM em R

    Observe também que a filosofia desta resposta é baseada na de lm e glm . Essas duas funções são um padrão de codificação para muitas rotinas de ajuste de modelo , mas talvez nem todas as rotinas de ajuste de modelo se comportem de maneira semelhante. Por exemplo, o seguinte não parece transparente para mim se minhas funções auxiliares realmente seriam úteis.

    • Erro com svychisq - 'contraste pode ser aplicado a fatores com 2 ou mais níveis'
    • R packages effects & plm: "erro nos contrastes" ao tentar plotar efeitos marginais
    • Contrastes podem ser aplicados apenas ao fator
    • R: lawstat :: levene.test falha enquanto Fligner Killeen trabalha, assim como car :: leveneTest
    • R - geeglm Error: os contrastes podem ser aplicados apenas a fatores com 2 ou mais níveis

    Embora um pouco fora do tópico, ainda é útil saber que às vezes um "erro de contraste" vem simplesmente da gravação de um código incorreto. Nos exemplos a seguir, OP passou o nome de suas variables ​​em vez de seus valores para lm . Como um nome é um caractere de valor único, ele é posteriormente coagido a um fator de nível único e causa o erro.

    • Erro em `contrasts < -` (` * tmp * `, valor = contr.funs [1 + isOF [nn]]): os contrastes podem ser aplicados apenas a fatores com 2 ou mais níveis
    • Fazer um loop por um vetor de caracteres para usar em uma function

    Como resolver esse erro após a debugging?

    Na prática, as pessoas querem saber como resolver esse problema, seja em nível estatístico ou em nível de programação.

    Se você estiver ajustando modelos em seu dataset completo, provavelmente não há solução estatística, a menos que você possa imputar valores ausentes ou coletar mais dados. Assim, você pode simplesmente recorrer a uma solução de codificação para eliminar a variável incorreta. debug_contr_error2 retorna nlevels que ajuda você a localizá-los facilmente. Se você não quiser soltá-los, substitua-os por um vetor de 1 (como explicado em Como fazer um GLM quando "contrastes podem ser aplicados apenas a fatores com 2 ou mais níveis"? ) E deixe lm ou glm lidar com a deficiência de sorting resultante.

    Se você estiver ajustando modelos em subconjunto, pode haver soluções statistics.

    Ajustar modelos por grupo não requer necessariamente que você divida seu dataset por grupo e ajuste modelos independentes. A seguir, você pode ter uma ideia aproximada:

    • R análise de regressão: análise de dados para uma determinada etnia
    • Encontrar a inclinação para vários pontos nas colunas selecionadas
    • R: construa modelos separados para cada categoria

    Se você dividir seus dados explicitamente, poderá obter facilmente "erros de contraste", portanto, terá que ajustar sua fórmula de modelo por grupo (ou seja, será necessário gerar dinamicamente fórmulas de modelo). Uma solução mais simples é ignorar a construção de um modelo para esse grupo.

    Você também pode particionar aleatoriamente seu dataset em um subconjunto de treinamento e um subconjunto de teste para que você possa fazer a validação cruzada. R: como depurar o erro "fator tem novos níveis" para o modelo linear e a previsão menciona isso rapidamente, e é melhor fazer uma amostragem estratificada para garantir o sucesso da estimativa do modelo na parte de treinamento e a previsão na parte de teste.