Come eseguire il debug dei “contrasti può essere applicato solo ai fattori con 2 o più livelli” di errore?

Ecco tutte le variabili con cui sto lavorando:

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

Ecco il glm che sto cercando di adattare:

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

So che ci sono molte variabili (il piano è di ridurre attraverso la selezione delle variabili in avanti). Ma anche sapere che molte variabili sono int o Factor; che a quanto capisco le cose dovrebbero funzionare solo con glm. Tuttavia, ogni volta che cerco di adattare questo modello, ottengo:

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

Che tipo di sguardi come se R non stesse trattando le variabili Fattore come variabili Fattore per qualche ragione?

Anche qualcosa di semplice come:

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

    non sta funzionando! (stesso messaggio di errore)

    Dove in questo modo:

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

    Funzionerà!

    Qualcuno sa cosa sta succedendo qui? Perché non riesco ad adattare queste variabili Fattore al mio glm ??

    Grazie in anticipo!

    -Troy

    introduzione

    Che “errore di contrasto” è stato ben spiegato: hai un fattore che ha solo un livello (o meno) . Ma in realtà questo semplice fatto può essere facilmente oscurato perché i dati effettivamente utilizzati per l’adattamento del modello possono essere molto diversi da quello che hai passato. Ciò accade quando hai NA nei tuoi dati, hai sottotetto i tuoi dati, un il fattore ha livelli non utilizzati o hai trasformato le tue variabili e ottenuto NaN da qualche parte. Raramente ci si trova in questa situazione ideale in cui un fattore a livello singolo può essere individuato direttamente da str(your_data_frame) . Molte domande su StackOverflow relative a questo errore non sono riproducibili, quindi i suggerimenti delle persone potrebbero non funzionare. Pertanto, anche se ci sono attualmente 118 post relativi a questo problema, gli utenti non riescono ancora a trovare una soluzione adtriggers in modo che questa domanda venga ripetuta più e più volte. Questa risposta è il mio tentativo, di risolvere questo problema “una volta per tutte”, o almeno di fornire una guida ragionevole.

    Questa risposta ha una ricca informazione, quindi permettimi prima di fare un rapido riassunto.

    Ho definito per voi 3 funzioni di supporto: debug_contr_error , debug_contr_error2 , NA_preproc .

    Vi consiglio di usarli nel modo seguente.

    1. eseguire NA_preproc per ottenere casi più completi;
    2. eseguire il modello, e se si ottiene un “errore di contrasto”, utilizzare debug_contr_error2 per il debug.

    La maggior parte della risposta ti mostra passo dopo passo come e perché queste funzioni sono definite. Probabilmente non c’è nulla di male saltare questi processi di sviluppo, ma non saltare le sezioni da “Case studies e discussioni riproducibili”.


    Risposta modificata

    La risposta originale funziona perfettamente per OP e ha aiutato con successo alcuni altri . Ma aveva fallito altrove per mancanza di capacità di adattamento. Guarda l’output di str(ad.train) nella domanda. Le variabili dell’OP sono numeriche o fattori; non ci sono personaggi La risposta originale era per questa situazione. Se si dispone di variabili di carattere, anche se saranno costretti a fattori durante lm e glm fitting, non verranno segnalati dal codice poiché non sono stati forniti come fattori, quindi is.factor non mancheranno. In questa espansione renderò la risposta originale sia più adattabile.

    Lascia dat sia il tuo set di dati passato a lm o glm . Se non si dispone facilmente di un tale frame di dati, cioè tutte le variabili sono sparse nell’ambiente globale, è necessario raggrupparle in un frame di dati. Il seguente potrebbe non essere il modo migliore ma funziona.

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

    Passaggio 0: subsetting esplicito

    Se hai utilizzato l'argomento subset di lm o glm , inizia con un sottoinsieme esplicito:

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

    Passaggio 1: rimuovere i casi incompleti

     dat <- na.omit(dat) 

    È ansible saltare questo passaggio se si è passati al punto 0, poiché il subset rimuove automaticamente i casi incompleti .

    Passaggio 2: controllo e conversione della modalità

    Una colonna di frame di dati è in genere un vettore atomico, con una modalità che segue: "logico", "numerico", "complesso", "carattere", "grezzo". Per la regressione, le variabili delle diverse modalità vengono gestite in modo diverso.

     "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 variabile logica è difficile. Può essere trattato come una variabile dummy ( 1 per TRUE ; 0 per FALSE ) quindi un "numerico", oppure può essere forzato a un fattore a due livelli. Tutto dipende dal fatto che model.matrix pensi che sia model.matrix una coercizione "to-factor" dalle specifiche della formula del modello. Per semplicità possiamo comprenderlo come tale: è sempre forzato ad un fattore, ma il risultato dell'applicazione di contrasti può finire con la stessa matrice del modello come se fosse gestita direttamente come un manichino.

    Alcune persone potrebbero chiedersi perché "intero" non è incluso. Perché un vettore intero, come 1:4 , ha una modalità "numerica" ​​( mode(1:4) prova mode(1:4) ).

    Una colonna di frame di dati può anche essere una matrice con class "AsIs", ma tale matrice deve avere la modalità "numerica".

    Il nostro controllo è di generare un errore quando

    • si trova un "complesso" o "grezzo";
    • si trova una variabile di matrice "logica" o "carattere";

    e procedere a convertire "logico" e "carattere" in "numerico" di class "fattore".

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

    Si noti che se una colonna del frame di dati è già una variabile fattore, non sarà inclusa in ind1 , poiché una variabile fattore ha la modalità "numerica" ​​( mode(factor(letters[1:4])) prova mode(factor(letters[1:4])) ).

    fase 3: eliminare i livelli di fattore inutilizzati

    Non avremo livelli di fattore inutilizzati per le variabili fattoriali convertite dal passaggio 2, cioè quelle indicizzate da ind1 . Tuttavia, le variabili fattoriali fornite con dat potrebbero avere livelli non utilizzati (spesso come risultato del passaggio 0 e del passaggio 1). Dobbiamo eliminare tutti i possibili livelli inutilizzati da loro.

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

    fase 4: riepilogare le variabili dei fattori

    Ora siamo pronti a vedere quali e quanti livelli di fattore vengono effettivamente utilizzati da lm o glm :

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

    Per semplificarti la vita, ho inserito questi passaggi in una funzione debug_contr_error .

    Ingresso:

    • dat è il tuo frame di dati passato a lm o glm tramite data argomento dei data ;
    • subset_vec è il vettore dell'indice passato a lm o glm tramite l'argomento subset .

    Uscita: una lista con

    • nlevels (una lista) indica il numero di livelli di fattore per tutte le variabili fattoriali;
    • levels (un vettore) fornisce i livelli per tutte le variabili dei fattori.

    La funzione genera un avviso, se non ci sono casi completi o variabili di fattori da riepilogare.

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

    Ecco un piccolo esempio costruito.

     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 

    Bene, vediamo un errore. Ora il mio debug_contr_error espone che f2 finisce con un singolo livello.

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

    Nota che la risposta breve originale è senza speranza qui, dato che f2 è fornito come variabile di carattere e non come variabile di fattore.

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

    Ora vediamo un esempio con una variabile matrix 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 

    Si noti che una variabile fattore senza livelli può causare anche un "errore di contrasto". Potresti chiederti come sia ansible un fattore di livello 0. Beh, è ​​legittimo: nlevels(factor(character(0))) . Qui finirai con un fattore di livello 0 se non hai casi completi.

     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 vediamo una situazione in cui se f2 è una variabile logica.

     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 

    Il nostro debugger pronosticherà un "errore di contrasto", ma succederà davvero?

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

    No, almeno questo non fallisce ( il coefficiente NA è dovuto al grado di carenza del modello, non preoccuparti ):

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

    Per me è difficile trovare un esempio che dia un errore, ma non è necessario. In pratica, non usiamo il debugger per la previsione; lo usiamo quando otteniamo veramente un errore; e in tal caso, il debugger può individuare la variabile del fattore offendente.

    Forse alcuni potrebbero obiettare che una variabile logica non è diversa da un manichino. Ma prova il semplice esempio qui sotto: dipende dalla tua formula.

     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 

    Implementazione più flessibile con il metodo "model.frame" di lm

    Si consiglia inoltre di consultare R: come eseguire il debug dell'errore "il fattore ha nuovi livelli" per il modello lineare e la previsione , il che spiega che cosa lm e glm fanno sotto il cofano del set di dati. Capirai che i passaggi da 0 a 4 sopra elencati stanno solo cercando di imitare tale processo interno. Ricorda, i dati effettivamente utilizzati per l'adattamento del modello possono essere molto diversi da quelli in cui sei passato .

    I nostri passaggi non sono completamente coerenti con tale elaborazione interna. Per un confronto, è ansible recuperare il risultato dell'elaborazione interna utilizzando method = "model.frame" in lm e glm . Prova questo sul piccolo esempio di dat precedentemente costruito dove f2 è una variabile di carattere.

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

    In pratica, model.frame eseguirà solo il passaggio 0 e il passaggio 1. Inoltre, elimina le variabili fornite nel set di dati ma non nella formula del modello. Quindi un frame del modello può avere meno righe e colonne rispetto a quello che alimenta lm e glm . Digitare coercing come fatto nel nostro passo 2 è fatto dalla successiva model.matrix dove può essere prodotto un "errore di contrasto".

    Ci sono alcuni vantaggi di ottenere prima questo frame del modello interno, quindi passarlo a debug_contr_error (in modo che esegua essenzialmente solo i passaggi da 2 a 4).

    vantaggio 1: le variabili non utilizzate nella formula del modello vengono ignorate

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

    vantaggio 2: in grado di far fronte a variabili trasformate

    È valido per trasformare le variabili nella formula del modello e model.frame registrerà quelle trasformate invece di quelle originali. Nota che, anche se la tua variabile originale non ha NA , la trasformazione può avere.

     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 

    Dati questi vantaggi, scrivo un'altra funzione che racchiude model.frame e debug_contr_error .

    Input :

    • form è la formula del tuo modello;
    • dat è il dataset passato a lm o glm tramite data argomento data ;
    • subset_vec è il vettore dell'indice passato a lm o glm tramite l'argomento subset .

    Uscita: una lista con

    • mf (un frame di dati) fornisce il frame del modello (con l'attributo "terms" abbandonato);
    • nlevels (una lista) indica il numero di livelli di fattore per tutte le variabili fattoriali;
    • levels (un vettore) fornisce i livelli per tutte le variabili dei fattori.
     ## 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)) } 

    Prova il precedente esempio di trasformazione del 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 

    Prova anche 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 

    Modello di raccordo per gruppo e NA come livelli di fattore

    Se si sta adattando il modello per gruppo, è più probabile che si verifichi un "errore di contrasto". Devi

    1. dividere il tuo data frame dalla variabile di raggruppamento (vedi ?split.data.frame );
    2. lavorare su quei frame di dati uno per uno, applicando debug_contr_error2 (la funzione lapply può essere utile per fare questo ciclo).

    Alcuni mi hanno anche detto che non possono usare na.omit sui loro dati, perché finiranno con poche righe per fare qualcosa di sensato. Questo può essere rilassato. In pratica è NA_integer_ NA_real_ NA_integer_ e NA_real_ , ma NA_character_ può essere mantenuto: basta aggiungere NA come livello di fattore. Per ottenere ciò, è necessario scorrere le variabili nel frame di dati:

    • se una variabile x è già un fattore e anyNA(x) è TRUE , fai x <- addNA(x) . Il "e" è importante. Se x non ha NA , addNA(x) aggiungerà un livello inutilizzato.
    • se una variabile x è un carattere, fai x <- factor(x, exclude = NULL) per costringerlo a un fattore. exclude = NULL manterrà come livello.
    • se x è "logico", "numerico", "grezzo" o "complesso", nulla deve essere cambiato. NA è solo NA .

    livello di fattore non verrà eliminato da droplevels o na.omit ed è valido per la costruzione di una matrice del modello. Controlla i seguenti esempi.

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

    Dopo aver aggiunto NA come livello in un fattore / carattere, il set di dati potrebbe improvvisamente avere casi più completi. Quindi puoi eseguire il tuo modello. Se ottieni ancora un "errore di contrasto", utilizza debug_contr_error2 per vedere cosa è successo.

    Per comodità, scrivo una funzione per questa preelaborazione di NA .

    Input :

    • dat è il tuo set di dati completo .

    Produzione:

    • un frame di dati, con NA aggiunto come livello per fattore / carattere.
     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 } 

    Studi di casi e discussioni riproducibili

    I seguenti sono appositamente selezionati per casi di studio riproducibili, in quanto li ho appena risposto con le tre funzioni di supporto create qui.

    • Come fare un GLM quando "i contrasti possono essere applicati solo a fattori con 2 o più livelli"?
    • R: Errore nei contrasti quando si adattano i modelli lineari con `lm`

    Esistono anche altri thread di buona qualità risolti da altri utenti di StackOverflow:

    • Fattori non riconosciuti in un lm usando map () (questo riguarda il fitting del modello per gruppo)
    • Come far cadere l'osservazione NA dei fattori condizionalmente quando si esegue la regressione lineare in R? (questo è simile al caso 1 nell'elenco precedente)
    • Fattore / errore di livello nel modello misto (un altro post sul assembly del modello per gruppo)

    Questa risposta mira a eseguire il debug del "errore di contrasto" durante l'adattamento del modello. Tuttavia, questo errore può anche verificarsi quando si utilizza la predict per la previsione. Tale comportamento non è con predict.lm o predict.glm , ma con metodi di previsione da alcuni pacchetti. Ecco alcuni thread correlati su StackOverflow.

    • Predizione in R - GLMM
    • Errore nell'errore `contrasti '
    • SVM prevede su dataframe con diversi livelli di fattore
    • Usando predire con svyglm
    • un set di dati deve contenere tutti i fattori in SVM in R
    • Previsioni di probabilità con modelli misti di collegamenti cumulativi
    • un set di dati deve contenere tutti i fattori in SVM in R

    Si noti inoltre che la filosofia di questa risposta è basata su quella di lm e glm . Queste due funzioni sono uno standard di codifica per molte routine di adattamento del modello , ma forse non tutte le routine di adattamento del modello si comportano in modo simile. Ad esempio, il seguente non mi sembra trasparente se le mie funzioni di aiuto siano effettivamente utili.

    • Errore con svychisq - 'il contrasto può essere applicato a fattori con 2 o più livelli'
    • R pacchetti effetti & plm: "errore nei contrasti" quando si tenta di tracciare effetti marginali
    • I contrasti possono essere applicati solo al fattore
    • R: lawstat :: levene.test fallisce mentre Fligner Killeen funziona, così come car :: leveneTest
    • R - Errore geeglm: i contrasti possono essere applicati solo a fattori con 2 o più livelli

    Sebbene sia un po 'fuori tema, è comunque utile sapere che a volte un "errore di contrasto" deriva semplicemente dalla scrittura di un pezzo di codice sbagliato. Nei seguenti esempi, OP ha passato il nome delle loro variabili piuttosto che i loro valori a lm . Poiché un nome è un carattere a valore singolo, viene successivamente convertito in un fattore a livello singolo e causa l'errore.

    • Errore in `contrasti <-` (` * tmp * `, valore = contr.funs [1 + isOF [nn]]): i contrasti possono essere applicati solo a fattori con 2 o più livelli
    • Passa attraverso un vettore di caratteri da utilizzare in una funzione

    Come risolvere questo errore dopo il debug?

    In pratica le persone vogliono sapere come risolvere questo problema, sia a livello statistico che a livello di programmazione.

    Se si stanno adattando modelli al set di dati completo, probabilmente non esiste alcuna soluzione statistica, a meno che non sia ansible imputare valori mancanti o raccogliere più dati. Quindi puoi semplicemente passare a una soluzione di codifica per eliminare la variabile offendente. debug_contr_error2 restituisce nlevels che ti aiuta a localizzarli facilmente. Se non vuoi lasciarli cadere, sostituiscili con un vettore di 1 (come spiegato in Come fare un GLM quando "i contrasti possono essere applicati solo a fattori con 2 o più livelli"? ) E lascia che lm o glm occupino di la conseguente carenza di rango.

    Se si stanno adattando modelli su sottoinsiemi, ci possono essere soluzioni statistiche.

    Adattare i modelli per gruppo non richiede necessariamente la suddivisione del set di dati per gruppo e il assembly di modelli indipendenti. Quanto segue potrebbe darti un'idea approssimativa:

    • Analisi di regressione R: analisi dei dati per una certa etnia
    • Trovare la pendenza per più punti nelle colonne selezionate
    • R: costruisci modelli separati per ogni categoria

    Se si suddividono i dati in modo esplicito, è ansible ottenere facilmente l'errore "contrasti", quindi regolare la formula del modello per gruppo (ovvero, è necessario generare dynamicmente le formule del modello). Una soluzione più semplice è saltare la costruzione di un modello per questo gruppo.

    È anche ansible partizionare in modo casuale il set di dati in un sottoinsieme di training e un sottoinsieme di test in modo da poter eseguire la convalida incrociata. R: come eseguire il debug dell'errore "il fattore ha nuovi livelli" per il modello lineare e la previsione lo menziona brevemente, e faresti meglio a fare un campionamento stratificato per assicurare il successo sia della stima del modello sulla parte di allenamento che della previsione sulla parte di test.