R: Walidacja krzyżowa zestawu danych z czynnikami

Często chcę przeprowadzić walidację krzyżową zestawu danych, który zawiera pewne zmienne czynnikowe i po uruchomieniu przez pewien czas procedura sprawdzania poprawności krzyżowej kończy się niepowodzeniem z błędem:factor x has new levels Y.

Na przykład za pomocą pakietubagażnik:

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

Aktualizacja: To jest zabawkowy przykład. Ten sam problem występuje również w przypadku większych zbiorów danych, w których występuje kilka poziomówC ale żaden z nich nie jest obecny wtrening przegroda.

FunkcjacreateDataPartition funkcja z pakietucaret robiwarstwowy próbkowanie dlazmienne wynikowe i poprawnie ostrzega:

Ponadto w przypadku „createDataPartition” bardzo małych rozmiarów klas (<= 3) klasy mogą nie pojawiać się zarówno w danych treningowych, jak i testowych.

Są dwa rozwiązania, które przychodzą na myśl:

Najpierw utwórz podzbiór danych, wybierając jedną losową próbkę każdej z nichfactor level najpierw, zaczynając od najrzadszej klasy (według częstotliwości), a następnie zachłannie spełniając kolejną rzadką klasę i tak dalej. Następnie za pomocącreateDataPartition w pozostałej części zestawu danych i połączenie wyników w celu utworzenia nowegopociąg zbiór danych, który zawiera wszystkolevels.Za pomocącreateDataPartitions i oraz próbkowanie odrzucenia.

Do tej pory opcja2 pracował dla mnie ze względu na rozmiary danych, ale nie mogę pomóc, ale myślę, że musi istnieć lepsze rozwiązanie, niż rozwiązanie ręczne.

Idealnie chciałbym rozwiązanie, którepo prostu działa do tworzenia partycji i kończy się niepowodzeniemwcześnie jeśli nie ma możliwości utworzenia takich partycji.

Czy istnieje podstawowy teoretyczny powód, dla którego pakiety nie oferują tego? Czy oferują to, a ja po prostu nie byłem w stanie ich zauważyć z powodu martwego punktu? Czy jest lepszy sposób na zrobienie tego warstwowego próbkowania?

Proszę zostawić komentarz, jeśli powinienem zadać to pytaniestats.stackoverflow.com.

Aktualizacja:

Oto jak wygląda moje rozwijane rozwiązanie (2):

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

questionAnswers(2)

yourAnswerToTheQuestion