R: Kreuzvalidierung eines Datensatzes mit Faktoren

Häufig möchte ich eine Kreuzvalidierung für einen Datensatz ausführen, der einige Faktorvariablen enthält, und nach einer Weile schlägt die Kreuzvalidierungsroutine mit dem Fehler fehl:factor x has new levels Y.

Zum Beispiel mit packageStiefel:

library(boot)
d <- data.frame(x=c('A', 'A', 'B', 'B', 'C', 'C'), y=c(1, 2, 3, 4, 5, 6))
m <- glm(y ~ x, data=d)
m.cv <- cv.glm(d, m, K=2) # Sometimes succeeds
m.cv <- cv.glm(d, m, K=2)
# Error in model.frame.default(Terms, newdata, na.action = na.action, xlev = object$xlevels) : 
#   factor x has new levels B

Aktualisieren: Dies ist ein Spielzeugbeispiel. Dasselbe Problem tritt auch bei größeren Datasets auf, bei denen Ebenen mehrfach vorkommenC aber keiner von ihnen ist in derAusbildung Trennwand.

Die FunktioncreateDataPartition Funktion aus dem Paketcaret tutgeschichtet Probenahme für dieErgebnisvariablen und warnt richtig:

Bei ‘createDataPartition’ werden sehr kleine Klassengrößen (<= 3) möglicherweise nicht in den Trainings- und Testdaten angezeigt.

Es gibt zwei Lösungen, die in den Sinn kommen:

Erstellen Sie zunächst eine Teilmenge der Daten, indem Sie jeweils eine Zufallsstichprobe auswählenfactor level Zuerst ausgehend von der seltensten Klasse (nach Häufigkeit) und dann gierig die nächste seltene Klasse befriedigend und so weiter. Dann mitcreateDataPartition auf den Rest des Datensatzes und Zusammenführen der Ergebnisse, um eine neue zu erstellenZug Datensatz, der alle enthältlevels.VerwendencreateDataPartitions und und Ablehnungsabtastung durchführen.

Bisher Option2 hat bei mir wegen der datengröße geklappt, aber ich kann nicht anders, als zu denken, dass es eine bessere lösung geben muss als eine von hand ausgerollte.

Idealerweise möchte ich eine Lösung welchefunktioniert einfach zum Erstellen von Partitionen und schlägt fehlfrüh wenn es keine Möglichkeit gibt, solche Partitionen zu erstellen.

Gibt es einen fundamentalen theoretischen Grund, warum Pakete dies nicht anbieten? Bieten sie es an und ich konnte sie nur wegen eines blinden Flecks nicht erkennen? Gibt es eine bessere Möglichkeit, diese geschichtete Stichprobe zu erstellen?

Bitte hinterlassen Sie einen Kommentar, wenn ich diese Frage stellen sollstats.stackoverflow.com.

Aktualisieren:

So sieht meine von Hand ausgerollte Lösung (2) aus:

get.cv.idx <- function(train.data, folds, factor.cols = NA) {

    if (is.na(factor.cols)) {
        all.cols        <- colnames(train.data)
        factor.cols     <- all.cols[laply(llply(train.data[1, ], class), function (x) 'factor' %in% x)]
    }

    n                   <- nrow(train.data)
    test.n              <- floor(1 / folds * n)

    cond.met            <- FALSE
    n.tries             <- 0

    while (!cond.met) {
        n.tries         <- n.tries + 1
        test.idx        <- sample(nrow(train.data), test.n)
        train.idx       <- setdiff(1:nrow(train.data), test.idx)

        cond.met        <- TRUE

        for(factor.col in factor.cols) {
            train.levels <- train.data[ train.idx, factor.col ]
            test.levels  <- train.data[ test.idx , factor.col ]
            if (length(unique(train.levels)) < length(unique(test.levels))) {
                cat('Factor level: ', factor.col, ' violated constraint, retrying.\n')
                cond.met <- FALSE
            }
        }
    }

    cat('Done in ', n.tries, ' trie(s).\n')

    list( train.idx = train.idx
        , test.idx  = test.idx
        )
}

Antworten auf die Frage(2)

Ihre Antwort auf die Frage