Wie Debuggen “Kontraste können nur auf Faktoren mit 2 oder mehr Ebenen angewendet werden” Fehler?

Hier sind alle Variablen, mit denen ich arbeite:

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

Hier ist das Glm, das ich versuche zu passen:

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

Ich weiß, dass es viele Variablen gibt (Plan ist die Reduzierung über die Vorwärtsauswahl von Variablen). Aber selbst wenn man weiß, dass es viele Variablen sind, sind sie entweder int oder Factor; was ich verstehe, sollte einfach mit einem glm funktionieren. Jedes Mal, wenn ich versuche, dieses Modell anzupassen, bekomme ich:

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

Wie sieht es für mich aus, als ob R meine Factor-Variablen aus irgendeinem Grund nicht als Faktor-Variablen behandelt?

Sogar etwas so einfaches wie:

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

funktioniert nicht! (gleiche Fehlermeldung)

Wo als das:

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

Wird funktionieren!

Wer weiß, was hier vor sich geht? Warum kann ich diese Faktorvariablen nicht auf meine Glm anpassen?

Danke im Voraus!

-Troy

   

    Einführung

    Was ein “Kontrasterrors” ist, wurde gut erklärt: Sie haben einen Faktor, der nur eine Stufe (oder weniger) hat . Aber in der Realität kann diese einfache Tatsache leicht verdeckt werden, da die Daten, die tatsächlich für die Anpassung von Modellen verwendet werden, sich sehr von denen unterscheiden können, die Sie übergeben haben. Dies passiert, wenn Sie NA in Ihren Daten haben Faktor hat ungenutzte Ebenen, oder Sie haben Ihre Variablen transformiert und NaN irgendwo bekommen. Sie befinden sich selten in dieser idealen Situation, in der ein einstufiger Faktor direkt von str(your_data_frame) werden kann. Viele Fragen zu StackOverflow hinsichtlich dieses Fehlers sind nicht reproduzierbar, daher können Vorschläge von Leuten funktionieren oder nicht. Obwohl es zu diesem Thema mittlerweile 118 Beiträge gibt, können Nutzer dennoch keine adaptive Lösung finden, so dass diese Frage immer wieder gestellt wird. Diese Antwort ist mein Versuch, diese Angelegenheit “ein für allemal” zu lösen, oder zumindest eine vernünftige Anleitung zu geben.

    Diese Antwort hat reiche Informationen, also lass mich zuerst eine kurze Zusammenfassung machen.

    Ich habe 3 debug_contr_error für Sie definiert: debug_contr_error , debug_contr_error2 , NA_preproc .

    Ich empfehle Ihnen, sie auf folgende Weise zu verwenden.

    1. Führen Sie NA_preproc , um vollständigere Fälle zu erhalten.
    2. Führen Sie Ihr Modell aus, und wenn Sie einen “Kontrasterrors” erhalten, verwenden Sie debug_contr_error2 zum Debuggen.

    Die meisten Antworten zeigen Ihnen Schritt für Schritt, wie und warum diese functionen definiert sind. Es ist wahrscheinlich nicht schädlich, diesen Entwicklungsprozess zu überspringen, aber Abschnitte aus “Reproduzierbare Fallstudien und Diskussionen” sollten nicht übersprungen werden.


    Überarbeitete Antwort

    Die ursprüngliche Antwort funktioniert perfekt für OP und hat anderen erfolgreich geholfen . Aber es war an anderer Stelle mangels Anpassungsfähigkeit gescheitert . Sehen Sie sich die Ausgabe von str(ad.train) in der Frage an. Die Variablen von OP sind numerisch oder Faktoren; Es gibt keine Charaktere. Die ursprüngliche Antwort war für diese Situation. Wenn Sie Charaktervariablen haben, obwohl diese bei lm und glm fitting zu Faktoren gezwungen werden, werden sie nicht vom Code gemeldet, da sie nicht als Faktoren zur Verfügung gestellt wurden, so dass sie von is.factor übersehen werden. In dieser Erweiterung werde ich die ursprüngliche Antwort adaptiver machen.

    Lass dat dass dein Datensatz an lm oder glm . Wenn Sie nicht so einfach einen solchen Datenrahmen haben, dh alle Ihre Variablen in der globalen Umgebung verstreut sind, müssen Sie sie in einem Datenrahmen sammeln. Das Folgende ist vielleicht nicht der beste Weg, aber es funktioniert.

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

    Schritt 0: Explizites Subsetting

    Wenn Sie das subset von lm oder glm , beginnen Sie mit einer expliziten Teilmenge:

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

    Schritt 1: Entfernen Sie unvollständige Fälle

     dat < - na.omit(dat) 

    Sie können diesen Schritt überspringen, wenn Sie Schritt 0 durchlaufen haben, da die subset automatisch unvollständige Fälle entfernt .

    Schritt 2: Modusüberprüfung und Konvertierung

    Eine Datenrahmenspalte ist normalerweise ein atomarer Vektor mit einem Modus aus dem Folgenden: "logisch", "numerisch", "komplex", "Zeichen", "roh". Bei der Regression werden Variablen verschiedener Modi unterschiedlich behandelt.

     "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` 

    Eine logische Variable ist schwierig. Es kann entweder als Dummy-Variable behandelt werden ( 1 für TRUE ; 0 für FALSE ), also eine "Numerische", oder es kann zu einem Zwei-Ebenen-Faktor gezwungen werden. Es kommt darauf an, ob model.matrix eine "to-factor" model.matrix aus der Spezifikation Ihrer Modellformel benötigt. Der Einfachheit halber können wir es so verstehen: es wird immer zu einem Faktor gezwungen, aber das Ergebnis der Anwendung von Kontrasten kann mit der gleichen Modellmatrix enden, als wenn es direkt als Dummy gehandhabt würde.

    Manche Leute fragen sich, warum "integer" nicht enthalten ist. Weil ein ganzzahliger Vektor wie 1:4 einen "numerischen" Modus hat (try mode(1:4) ).

    Eine Datenrahmenspalte kann auch eine Matrix mit einer "AsIs" -class sein, aber eine solche Matrix muss einen "numerischen" Modus haben.

    Unsere Überprüfung soll Fehler erzeugen, wenn

    • ein "Komplex" oder "roh" wird gefunden;
    • eine "logische" oder "Zeichen" -Matrixvariable wird gefunden;

    und fortfahren, "logisch" und "Zeichen" in "numerisch" der "Faktor" -class zu konvertieren.

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

    Beachten Sie, dass, wenn eine ind1 bereits eine Faktorvariable ist, diese nicht in ind1 , da eine Faktorvariable den "numerischen" Modus hat (Try- mode(factor(letters[1:4])) ).

    Schritt 3: Nicht verwendete Faktorstufen fallen lassen

    Wir werden keine ungenutzten Faktorstufen für Faktorvariablen haben, die aus Schritt 2 konvertiert wurden, dh diejenigen, die durch ind1 indiziert ind1 . Faktorvariablen, die mit dat können jedoch ungenutzte Ebenen haben (oft als Ergebnis von Schritt 0 und Schritt 1). Wir müssen alle möglichen ungenutzten Niveaus von ihnen fallenlassen.

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

    Schritt 4: Zusammenfassen von Faktorvariablen

    Nun sind wir bereit zu sehen, was und wie viele Faktorstufen tatsächlich von lm oder glm :

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

    Um Ihnen das Leben zu erleichtern, habe ich diese Schritte in eine function debug_contr_error .

    Eingang:

    • dat ist Ihr glm über glm an lm oder glm .
    • subset_vec ist der glm über subset an lm oder glm .

    Ausgabe: eine Liste mit

    • nlevels (eine Liste) gibt die Anzahl der Faktorstufen für alle Faktorvariablen an;
    • levels (ein Vektor) gibt Ebenen für alle Faktorvariablen an.

    Die function erzeugt eine Warnung, wenn keine vollständigen Fälle oder keine Faktorvariablen zusammenzufassen sind.

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

    Hier ist ein kleines Beispiel.

     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 

    Gut, wir sehen einen Fehler. Jetzt macht mein debug_contr_error dass f2 mit einer einzigen Ebene endet.

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

    Beachten Sie, dass die ursprüngliche kurze Antwort hier hoffnungslos ist, da f2 als Zeichenvariable und nicht als Faktorvariable bereitgestellt wird.

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

    Sehen wir uns nun ein Beispiel mit einer Matrixvariablen 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 

    Beachten Sie, dass eine Faktorvariable ohne Ebenen auch einen "Kontrastierungserrors" verursachen kann. Sie fragen sich vielleicht, wie ein 0-Level-Faktor möglich ist. Nun, es ist legitim: nlevels(factor(character(0))) . Hier erhalten Sie einen 0-Level-Faktor, wenn Sie keine vollständigen Fälle haben.

     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 

    Schließlich sehen wir uns eine Situation an, in der f2 eine logische Variable ist.

     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 

    Unser Debugger wird einen "Kontrasterrors" vorhersagen, aber wird es wirklich passieren?

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

    Nein, zumindest scheitert dieses nicht ( der NA Koeffizient ist auf den Rang-Mangel des Modells zurückzuführen; mach dir keine Sorgen ):

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

    Es ist schwierig für mich, ein Beispiel zu finden, das einen Fehler gibt, aber es gibt auch keine Notwendigkeit. In der Praxis verwenden wir den Debugger nicht zur Vorhersage; wir benutzen es, wenn wir wirklich einen Fehler bekommen; und in diesem Fall kann der Debugger die verursachende Faktorvariable lokalisieren.

    Vielleicht mögen einige argumentieren, dass sich eine logische Variable nicht von einem Dummy unterscheidet. Aber versuchen Sie das einfache Beispiel unten: es hängt von Ihrer Formel ab.

     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 

    Flexiblere Implementierung mit "model.frame" Methode von lm

    Es wird auch empfohlen, R: zu durchlaufen , um den Fehler "Faktor hat neue Ebenen" für lineares Modell und Vorhersage zu debuggen , der erklärt, was lm und glm unter der Haube Ihres Datasets tun. Sie werden verstehen, dass die oben aufgeführten Schritte 0 bis 4 nur versuchen, einen solchen internen process nachzuahmen. Denken Sie daran, dass die Daten, die tatsächlich für die Modellanpassung verwendet werden, sich sehr von denen unterscheiden können, die Sie übergeben haben .

    Unsere Schritte sind mit einer solchen internen Verarbeitung nicht vollständig konsistent. Für einen Vergleich können Sie das Ergebnis der internen Verarbeitung method = "model.frame" indem Sie method = "model.frame" in lm und glm . Versuchen Sie dies auf dem zuvor konstruierten winzigen Beispiel dat wobei f2 eine Zeichenvariable ist.

     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 der Praxis führt model.frame nur Schritt 0 und Schritt 1 durch. Es model.frame auch Variablen, die in Ihrem Dataset, jedoch nicht in Ihrer Modellformel enthalten sind. Ein Modellrahmen kann also weniger Zeilen und Spalten enthalten als das, was Sie lm und glm . Typ Coercing wie in unserem Schritt 2 getan wird von der späteren model.matrix wo ein "Kontraste Fehler" produziert werden kann.

    Es gibt einige Vorteile, diesen internen Modellrahmen zuerst zu erhalten und ihn dann an debug_contr_error zu debug_contr_error (so dass er im Wesentlichen die Schritte 2 bis 4 ausführt).

    Vorteil 1: Variablen, die in Ihrer Modellformel nicht verwendet werden, werden ignoriert

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

    Vorteil 2: fähig, transformierte Variablen zu bewältigen

    Es ist zulässig, Variablen in der Modellformel zu transformieren, und model.frame zeichnet die transformierten Variablen anstelle der ursprünglichen auf. Beachten Sie, dass, selbst wenn Ihre ursprüngliche Variable keine NA , die transformierte haben kann.

     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 

    Angesichts dieser Vorteile schreibe ich eine andere function, die model.frame und debug_contr_error .

    Eingabe :

    • form ist deine Modellformel;
    • dat ist das Dataset, das über glm an lm oder glm .
    • subset_vec ist der glm über subset an lm oder glm .

    Ausgabe: eine Liste mit

    • mf (ein Datenrahmen) gibt den Modellrahmen an (wobei das Attribut "Terms" weggelassen wurde);
    • nlevels (eine Liste) gibt die Anzahl der Faktorstufen für alle Faktorvariablen an;
    • levels (ein Vektor) gibt Ebenen für alle Faktorvariablen an.
     ## 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)) } 

    Versuchen Sie das vorherige 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 

    Versuchen Sie auch 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 

    Modellanpassung pro Gruppe und NA als Faktorstufen

    Wenn Sie Modell für Gruppe anpassen, erhalten Sie eher einen "Kontrasterrors". Du brauchst

    1. ?split.data.frame Ihren ?split.data.frame durch die Gruppierungsvariable (siehe ?split.data.frame );
    2. arbeiten Sie diese Datenframes nacheinander ab, indem debug_contr_error2 lapply anwenden (die lapply function kann hilfreich sein, um diese Schleife lapply ).

    Einige haben mir auch gesagt, dass sie na.omit für ihre Daten verwenden können, weil sie zu wenig Zeilen benötigen, um etwas Vernünftiges zu tun. Dies kann entspannt werden. In der Praxis müssen NA_integer_ und NA_real_ weggelassen werden, aber NA_character_ kann beibehalten werden: NA_character_ einfach NA als Faktor ein. Um dies zu erreichen, müssen Sie Variablen in Ihrem Datenrahmen durchlaufen:

    • Wenn eine Variable x bereits ein Faktor ist und anyNA(x) TRUE , dann x < - addNA(x) . Das "und" ist wichtig. Wenn x keine NA , addNA(x) ein unbenutztes -Niveau hinzu.
    • Wenn eine Variable x ein Zeichen ist, mache x < - factor(x, exclude = NULL) , um es zu einem Faktor zu zwingen. exclude = NULL behält als Ebene bei.
    • Wenn x "logisch", "numerisch", "roh" oder "komplex" ist, sollte nichts geändert werden. NA ist nur NA .

    faktor level wird nicht von droplevels oder na.omit und ist für den Aufbau einer Modellmatrix gültig. Überprüfen Sie die folgenden Beispiele.

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

    Sobald Sie NA als Ebene in einem Faktor / Zeichen hinzugefügt haben, könnte Ihr Datensatz plötzlich vollständigere Fälle enthalten. Dann können Sie Ihr Modell ausführen. Wenn Sie immer noch einen "Kontrasterrors" erhalten, verwenden Sie debug_contr_error2 zu sehen, was passiert ist.

    Zu Ihrer Bequemlichkeit schreibe ich eine function für diese NA Vorverarbeitung.

    Eingabe :

    • dat ist Ihr vollständiger Datensatz.

    Ausgabe:

    • ein Datenrahmen, mit NA als Ebene für Faktor / Zeichen hinzugefügt.
     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 } 

    Reproduzierbare Fallstudien und Diskussionen

    Die folgenden Beispiele sind speziell für reproduzierbare Fallstudien ausgewählt, da ich sie gerade mit den drei hier erstellten Hilfsfunktionen beantwortet habe.

    • Wie funktioniert ein GLM, wenn "Kontraste nur auf Faktoren mit zwei oder mehr Ebenen angewendet werden können"?
    • R: Kontrasterrors bei der Anpassung linearer Modelle mit 'lm`

    Es gibt auch ein paar andere qualitativ hochwertige Threads, die von anderen StackOverflow-Benutzern getriggers werden:

    • Faktoren, die nicht in einem lm mit map () erkannt werden (es handelt sich um Modellanpassung nach Gruppe)
    • Wie lässt man die NA-Beobachtung von Faktoren bedingt abbrechen, wenn man eine lineare Regression in R durchführt? (Dies ist vergleichbar mit Fall 1 in der vorherigen Liste)
    • Faktor / Level-Fehler im gemischten Modell (ein weiterer Beitrag über Modellanpassung nach Gruppe)

    Diese Antwort zielt darauf ab, den "Kontrasterrors" während der Modellanpassung zu beheben. Dieser Fehler kann jedoch auch auftreten, wenn predict für Vorhersage verwendet wird. Ein solches Verhalten ist nicht mit predict.lm oder predict.glm , sondern mit Vorhersage-Methoden aus einigen Paketen. Hier sind ein paar verwandte Themen auf StackOverflow.

    • Vorhersage in R - GLMM
    • Fehler in `contrasts 'Fehler
    • SVM prognostiziert auf Datenrahmen mit verschiedenen Faktorstufen
    • Mit svyglm voraussagen
    • Muss ein Datensatz alle Faktoren in SVM in R enthalten
    • Wahrscheinlichkeitsvorhersagen mit kumulativen Link-Mixed-Modellen
    • Muss ein Datensatz alle Faktoren in SVM in R enthalten

    Beachten Sie auch, dass die Philosophie dieser Antwort auf der von lm und glm . Diese beiden functionen sind ein Codierungsstandard für viele Modellanpassungsroutinen , aber möglicherweise verhalten sich nicht alle Modellanpassungsroutinen ähnlich. Zum Beispiel sieht das Folgende für mich nicht transparent aus, ob meine Hilfsfunktionen tatsächlich hilfreich wären.

    • Fehler mit Svychisq - 'Kontrast kann auf Faktoren mit 2 oder mehr Ebenen angewendet werden'
    • R-Pakete effects & plm: "Fehler in Kontrasten" beim Versuch, marginale Effekte zu zeichnen
    • Kontraste können nur auf Faktoren angewendet werden
    • R: lawstat :: levene.test scheitert, während Fligner Killeen arbeitet, sowie car :: leveneTest
    • R - geeglm Fehler: Kontraste können nur auf Faktoren mit 2 oder mehr Ebenen angewendet werden

    Obwohl es ein wenig off-topic ist, ist es immer noch nützlich zu wissen, dass manchmal ein "Kontrastierungserrors" nur durch das Schreiben eines falschen Stücks Code entsteht. In den folgenden Beispielen hat OP den Namen ihrer Variablen und nicht ihre Werte an lm . Da ein Name ein einzelnes Wertzeichen ist, wird er später zu einem einstufigen Faktor gezwungen und verursacht den Fehler.

    • Fehler in `contrasts < -` (` * tmp * `, Wert = contr.funs [1 + isOF [nn]]): Kontraste können nur auf Faktoren mit 2 oder mehr Ebenen angewendet werden
    • Durchlaufen Sie einen Zeichenvektor, um ihn in einer function zu verwenden

    Wie behebe ich diesen Fehler nach dem Debuggen?

    In der Praxis wollen die Menschen wissen, wie sie dieses Problem entweder auf statistischer Ebene oder auf einer Programmierungsstufe lösen können.

    Wenn Sie Modelle für Ihren vollständigen Datensatz anpassen, gibt es wahrscheinlich keine statistische Lösung, es sei denn, Sie können fehlende Werte implizieren oder mehr Daten erfassen. Sie können also einfach zu einer Kodierungslösung wechseln, um die betreffende Variable zu löschen. debug_contr_error2 gibt nlevels deren Hilfe Sie sie leicht finden können. Wenn Sie sie nicht löschen möchten, ersetzen Sie sie durch einen Vektor von 1 (wie in GLM erläutert, wenn "Kontraste nur auf Faktoren mit 2 oder mehr Ebenen angewendet werden können"? ) Und lassen Sie lm oder glm umgehen der daraus resultierende Rang-Mangel.

    Wenn Sie Modelle an Teilmengen anpassen, können statistische Lösungen zur Verfügung stehen.

    Das Anpassen von Modellen nach Gruppen erfordert nicht unbedingt, dass Sie Ihren Datensatz nach Gruppen aufteilen und unabhängige Modelle anpassen. Folgendes kann Ihnen eine grobe Vorstellung geben:

    • R Regressionsanalyse: Analyse von Daten für eine bestimmte ethnische Zugehörigkeit
    • Ermitteln der Neigung für mehrere Punkte in ausgewählten Spalten
    • R: Erstellen Sie separate Modelle für jede Kategorie

    Wenn Sie Ihre Daten explizit teilen, können Sie leicht "Kontrastserrors" erhalten und müssen daher Ihre Modellformel pro Gruppe anpassen (dh Sie müssen Modellformeln dynamisch generieren). Eine einfachere Lösung besteht darin, das Erstellen eines Modells für diese Gruppe zu überspringen.

    Sie können Ihren Datensatz auch nach dem Zufallsprinzip in eine Trainingsuntergruppe und eine Testuntergruppe partitionieren, sodass Sie eine Kreuzvalidierung durchführen können. R: Wie man den Fehler "Faktor hat neue Ebenen" für das lineare Modell debuggt und die Vorhersage erwähnt dies kurz, und Sie sollten besser eine geschichtete Stichprobe machen, um den Erfolg sowohl der Modellschätzung auf dem Trainingsteil als auch der Vorhersage auf dem Testteil sicherzustellen.