Este documento no Adaboost fornece algumas sugestões e códigos (página 17) para estender os modelos de 2 classes para problemas da classe K. Gostaria de generalizar esse código, para que eu possa conectar facilmente diferentes modelos de 2 classes e comparar os resultados. Como a maioria dos modelos de classificação possui uma interface de fórmula e um predict
método, parte disso deve ser relativamente fácil. Infelizmente, não encontrei uma maneira padrão de extrair probabilidades de classe de modelos de 2 classes, portanto cada modelo exigirá algum código personalizado.
Aqui está uma função que escrevi para dividir um problema da classe K em problemas de 2 classes e retornar os modelos 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)
}
Aqui está um método de previsão que escrevi para iterar sobre cada modelo e fazer previsões:
predict.oneVsAll <- function(object, newX=object$info$X, ...) {
stopifnot(class(object)=='oneVsAll')
lapply(object$models, function(x) {
predict(x, newX, ...)
})
}
E finalmente, aqui está uma função para normalizar uma data.frame
das probabilidades previstas e classificar os casos. Observe que cabe a você construir a coluna K data.frame
de probabilidades de cada modelo, pois não há uma maneira unificada de extrair probabilidades de classe de um modelo de 2 classes:
classify <- function(dat) {
out <- dat/rowSums(dat)
out$Class <- apply(dat, 1, function(x) names(dat)[which.max(x)])
out
}
Aqui está um exemplo usando 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
Aqui está um exemplo usando lda
(eu sei que o lda pode lidar com várias classes, mas este é apenas um exemplo):
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
Essas funções devem funcionar para qualquer modelo de 2 classes com uma interface de fórmula e um predict
método. Observe que você precisa dividir manualmente os componentes X e Y, o que é um pouco feio, mas escrever uma interface de fórmula está além de mim no momento.
Essa abordagem faz sentido para todos? Existe alguma maneira de melhorá-lo ou existe um pacote existente para resolver esse problema?
predict
método.
car
ou um dos*lab
pacotes) teria fornecido uma função como a sua. Desculpe, não posso ajudar. Eu li um pouco sobre como o k-way SVM funciona e parece que foi mais complicado do que eu pensava.