Распространение 2-классовых моделей на мультиклассовые задачи

11

В этой статье об Adaboost приведены некоторые предложения и код (стр. 17) для расширения моделей с 2 ​​классами до задач класса K. Я хотел бы обобщить этот код так, чтобы я мог легко подключить различные 2-классовые модели и сравнить результаты. Поскольку большинство моделей классификации имеют интерфейс формулы и predictметод, некоторые из них должны быть относительно простыми. К сожалению, я не нашел стандартного способа извлечения вероятностей классов из двухклассовых моделей, поэтому для каждой модели потребуется некоторый пользовательский код.

Вот функция, которую я написал, чтобы разбить задачу K-класса на задачи 2-класса и вернуть K-модели:

oneVsAll <- function(X,Y,FUN,...) {
    models <- lapply(unique(Y), function(x) {
        name <- as.character(x)
        .Target <- factor(ifelse(Y==name,name,'other'), levels=c(name, 'other'))
        dat <- data.frame(.Target, X)
        model <- FUN(.Target~., data=dat, ...)
        return(model)
    })
    names(models) <- unique(Y)
    info <- list(X=X, Y=Y, classes=unique(Y))
    out <- list(models=models, info=info)
    class(out) <- 'oneVsAll'
    return(out)
}

Вот метод прогнозирования, который я написал, чтобы перебрать каждую модель и сделать прогноз:

predict.oneVsAll <- function(object, newX=object$info$X, ...) {
    stopifnot(class(object)=='oneVsAll')
    lapply(object$models, function(x) {
        predict(x, newX, ...)
    })
}

И наконец, вот функция, позволяющая включить нормализацию data.frameпредсказанных вероятностей и классифицировать случаи. Обратите внимание, что вы должны построить K-столбец data.frameвероятностей из каждой модели, так как нет единого способа извлечения вероятностей классов из модели 2 классов:

classify <- function(dat) {
    out <- dat/rowSums(dat)
    out$Class <- apply(dat, 1, function(x) names(dat)[which.max(x)])
    out
}

Вот пример использования adaboost:

library(ada)
library(caret) 
X <- iris[,-5]
Y <- iris[,5]
myModels <- oneVsAll(X, Y, ada)
preds <- predict(myModels, X, type='probs')
preds <- data.frame(lapply(preds, function(x) x[,2])) #Make a data.frame of probs
preds <- classify(preds)
>confusionMatrix(preds$Class, Y)
Confusion Matrix and Statistics

            Reference
Prediction   setosa versicolor virginica
  setosa         50          0         0
  versicolor      0         47         2
  virginica       0          3        48

Вот пример использования lda(я знаю, что lda может обрабатывать несколько классов, но это всего лишь пример):

library(MASS)
myModels <- oneVsAll(X, Y, lda)
preds <- predict(myModels, X)
preds <- data.frame(lapply(preds, function(x) x[[2]][,1])) #Make a data.frame of probs
preds <- classify(preds)
>confusionMatrix(preds$Class, Y)
Confusion Matrix and Statistics

            Reference
Prediction   setosa versicolor virginica
  setosa         50          0         0
  versicolor      0         39         5
  virginica       0         11        45

Эти функции должны работать для любой 2-классовой модели с интерфейсом формулы и predictметодом. Обратите внимание, что вы должны вручную разделить компоненты X и Y, что немного уродливо, но на данный момент написание интерфейса формул мне не по силам.

Этот подход имеет смысл для всех? Есть ли способ, которым я могу улучшить это, или есть существующий пакет для решения этой проблемы?

Zach
источник
2
Ничего себе, пока вы не спросили, и я не посмотрел, я был бы уверен, что какой-то пакет (например car, или один из *labпакетов) предоставит такую ​​же функцию, как ваша. Извините, я не могу помочь. Я немного читал о том, как работает k-way SVM, и кажется, что это было сложнее, чем я думал.
Уэйн
1
@Wayne: Я тоже! Я был уверен, что будет какая-то общая функция, которая будет делать это, если у модели есть predictметод.
Зак

Ответы:

1

Одним из способов улучшения является использование подхода «взвешенных всех пар», который, предположительно, лучше, чем «один против всех», и в то же время масштабируемый.

Что касается существующих пакетов, glmnetподдерживает (регуляризованный) многочленный логит, который может использоваться в качестве классификатора мультикласса.

Евгений
источник
Мне известно о многих пакетах в R, которые поддерживают мультиклассовую классификацию (например, glmnet, случайные леса, kernlab, rpart, nnet и т. Д.). Меня больше интересует расширение пакетов бинарной классификации (например, gbm) для задач мультикласса. Я посмотрю на «взвешенные все пары».
Зак
Также интересно, что glmnetвключает функцию multinomialпотерь. Интересно, можно ли использовать эту функцию потерь в других алгоритмах в R, например, adaили gbm?
Зак
Да, некоторые методы могут быть расширены для поддержки функции полиномиальных потерь. Например, логистическая регрессия в ядре расширяется таким образом: books.nips.cc/papers/files/nips14/AA13.pdf Насколько известно ada, «зарезервировано» для определенной (экспоненциальной) функции потерь, но можно расширить еще одно повышение метод поддержки многочленной потери - например, см. стр. 360 «Элементы статистического обучения» для получения подробной информации о мультиклассовом GBM - бинарные деревья K построены для каждой ускоряющей итерации, где K - количество классов (только одно дерево на итерацию нужен в двоичном случае).
Евгений