Статьи

Выбор модели классификации

Чтобы проиллюстрировать проблему выбора модели классификации, рассмотрим некоторые моделируемые данные,

> n = 500
> set.seed(1)
> X = rnorm(n)
> ma = 10-(X+1.5)^2*2
> mb = -10+(X-1.5)^2*2
> M = cbind(ma,mb)
> set.seed(1)
> Z = sample(1:2,size=n,replace=TRUE)
> Y = ma*(Z==1)+mb*(Z==2)+rnorm(n)*5
> df = data.frame(Z=as.factor(Z),X,Y)

Первая стратегия состоит в том, чтобы разбить набор данных на две части: набор обучающих данных и набор тестируемых данных.

> df1 = training = df[1:300,]
> df2 = testing  = df[301:500,]

Метод удержания: наборы данных для обучения и тестирования

Два набора данных могут быть отображены ниже, с обучающим набором данных сверху и тестовым набором данных ниже

> plot(df1$X,df1$Y,pch=19,col=c(rgb(1,0,0,.4),
+ rgb(0,0,1,.4))[df1$Z])

Мы можем рассмотреть простое дерево классификации.

> library(rpart)
> fit = rpart(Z~X+Y,data=df1)
> pred = function(x,y) predict(fit,newdata=data.frame(X=x,Y=y))[,1]

Чтобы визуализировать это, используйте

> vx=seq(-3,3,length=101)
> vy=seq(-25,25,length=101)
> z=matrix(NA,length(vx),length(vy))
> for(i in 1:length(vx)){
+   for(j in 1:length(vy))
+  {z[i,j]=pred(vx[i],vy[j])}}

и

> image(vx,vy,z,axes=FALSE,xlab="",ylab="")
> points(df1$X,df1$Y,pch=19,col=c(rgb(1,0,0,.4),
+ rgb(0,0,1,.4))[df1$Z])

Мы имеем сверху прогноз на наборе обучающих данных, затем ниже прогноз на наборе тестовых данных. И, наконец, внизу кривая ROC для тестового набора данных (черная кривая), а также тренировочный набор данных (серая кривая)

> Y1=as.numeric(df1$Z)-1
> Y2=as.numeric(df2$Z)-1
> library(ROCR)
> S1 = predict(fit,newdata=df1)[,1]
> S2 = predict(fit,newdata=df2)[,1]
> pred <- prediction( S2, Y2 ) 
> perf <- performance( pred, "tpr", "fpr" ) 
> plot( perf ) 
> pred <- prediction( S1, Y1 ) 
> perf <- performance( pred, "tpr", "fpr" ) 
> plot( perf ,add=TRUE,col="grey")

Исходя из этого дерева, естественно получить прогноз, используя случайный лес

> library(randomForest)
> fit=randomForest(Z~X+Y,data=df1)

Чтобы получить прогноз, используйте

> pred=function(x,y) 
+ predict(fit,newdata=data.frame(X=x,Y=y),
+ type="prob")[,2]

Не то, чтобы подгонка идеально подходила к тренировочному образцу. Другой популярной моделью может быть логистическая регрессия.

> fit=glm(Z~X+Y,data=df1,family=binomial)
> pred=function(x,y) 
+ predict(fit,newdata=data.frame(X=x,Y=y),
+ type="response")

Последнее очень близко к линейному дискриминантному анализу

> library(MASS)
> fit=lda(Z~X+Y,data=df1,family=binomial)
> pred=function(x,y) 
+ predict(fit,newdata=
+ data.frame(X=x,Y=y))$posterior[,2]

или квадратичный дискриминантный анализ

> fit=qda(Z~X+Y,data=df1,family=binomial)
> pred=function(x,y) 
+ predict(fit,newdata=
+ data.frame(X=x,Y=y))$posterior[,2]

Чтобы попробовать самые разные модели, рассмотрим  k- ближайшего соседа
(здесь с 9 соседями)

> library(caret)
> fit=knn3(Z~X+Y,data=df1,k=9)
> pred=function(x,y)  
+ predict(fit,newdata=data.frame(X=x,Y=y))[,2]

некоторая логистическая регрессия с двумерными сплайнами

> library(mgcv)
> fit=gam(Z~s(X,Y),data=df1,family=binomial)
> pred=function(x,y) 
+ predict(fit,newdata=data.frame(X=x,Y=y),
+ type="response")

или какой-то алгоритм повышения градиента

> library(dismo)
> df1$Z01 = 1*(df1$Z=="2")
> fit=gbm.step(data=df1, gbm.x = 2:3, gbm.y = 4,
+     family = "bernoulli", tree.complexity = 5,
+     learning.rate = 0.01, bag.fraction = 0.5)
> pred = function(x,y) 
+ predict(fit,newdata=data.frame(X=x,Y=y),
+ type="response",n.trees=400)

Тем не менее, использование этого метода для создания некоторых обучающих и тестовых наборов данных может быть затруднено. Это можно сделать только тогда, когда у нас много наблюдений. И даже в этом случае мы все еще можем быть неудачниками при создании тестового образца (просто из-за неудачи). Альтернативой является использование перекрестной проверки.

Использование перекрестной проверки

Здесь мы рассматриваем перекрестную проверку с одним пропуском (но можно также рассмотреть перекрестную проверку с v- кратным увеличением, чтобы получить результаты быстрее).

Рассмотрим здесь дерево классификации . Например, для получения кривой ROC перекрестной проверки используйте

> FIT=list()
> for(i in 1:n) 
+ FIT[[i]] = rpart(Z~X+Y,data=df[-i,])
> predict_i = function(i) 
+ predict(FIT[[i]],newdata=df[i,])[,2] 
> S = Vectorize(predict_i)(1:n)

Здесь я храню n моделей, где каждый раз удаляется одно наблюдение, а затем я получаю прогноз для удаленного наблюдения. И мы можем сгенерировать ROC-кривую

> Y = as.numeric(df$Z)-1
> library(ROCR)
> pred = prediction( S, Y )
> perf = performance( pred, "tpr", "fpr" )
> plot( perf )

Конечно, можно легко получить код, который работает быстрее, но он работает с этим небольшим набором данных.

Если мы рассмотрим случайный лес , мы получим

> FIT=list()
> for(i in 1:n) 
+ FIT[[i]] = randomForest(Z~X+Y,data=df[-i,])
> predict_i = function(i) 
+ predict(FIT[[i]],newdata=df[i,],
+ type="prob")[,2] 
> S = Vectorize(predict_i)(1:n)

Можно рассмотреть логистическую регрессию

> FIT=list()
> for(i in 1:n) 
+ FIT[[i]] = glm(Z~X+Y,data=df[-i,],
+ family=binomial)
> predict_i = function(i) 
+ predict(FIT[[i]],newdata=df[i,],
+ type="response") 
> S = Vectorize(predict_i)(1:n)

или линейный дискриминантный анализ

> FIT=list()
> for(i in 1:n) 
+ FIT[[i]] = lda(Z~X+Y,data=df[-i,],
+ family=binomial)
> predict_i = function(i) 
+ predict(FIT[[i]],newdata=df[i,])$posterior[,2] 
> S = Vectorize(predict_i)(1:n)

в то время как квадратичный дискриминантный анализ дает

> FIT=list()
> for(i in 1:n) 
+ FIT[[i]] =  qda(Z~X+Y,data=df[-i,],
+ family=binomial)
> predict_i = function(i) 
+ predict(FIT[[i]],newdata=df[i,])$posterior[,2] 
> S = Vectorize(predict_i)(1:n)

Опять же, если мы рассмотрим другой тип модели, такой как  k- ближайший сосед (с  k = 5), мы получим

> FIT=list()
> for(i in 1:n) 
+ FIT[[i]] = knn3(Z~X+Y,data=df[-i,],k=5)
> predict_i = function(i) 
+ predict(FIT[[i]],newdata=df[i,])[,2] 
> S = Vectorize(predict_i)(1:n)

или k ближайшего соседа с k = 9

или  к = 21

Можно также рассмотреть логистическую регрессию с двумерными сплайнами

или, что не менее важно, некоторая модель повышения градиента . На этом у нас могут возникнуть проблемы с сохранением 500 выходных данных от функции повышения градиента (выходной сигнал большой). Более быстрый код может быть

> VS = rep(NA,n)
> for(i in 1:n){
+  FIT = gbm.step(data=df[-i,], 
+  gbm.x = 2:3, gbm.y = 4, family = "bernoulli", 
+  tree.complexity = 5, learning.rate = 0.01,
+  bag.fraction = 0.5)
+  VS[i] = predict(FIT,newdata=df[i,],
+  n.trees=400) 
+ }

Фактически, теперь можно сравнить все эти модели со всеми кривыми ROC на одном графике: