R randomForest голосования перерыв - PullRequest
4 голосов
/ 08 декабря 2011

Кто-нибудь знает, какой механизм использует пакет R randomForest для разрешения классификационных связей, т. Е. Когда деревья в конечном итоге получают равные голоса в двух или более классах?

В документации сказано, что галстук разорван случайно. Однако, когда вы обучаете модель на наборе данных, а затем многократно оцениваете эту модель с помощью одного набора проверочных данных, решения связанного класса не равны 50/50.

cnum = vector("integer",1000)
for (i in 1:length(cnum)){
  cnum[i] = (as.integer(predict(model,val_x[bad_ind[[1]],])))
}
cls = unique(cnum)
for (i in 1:length(cls)){
  print(length(which(cnum == cls[i])))
}

, где model - это объект randomForest, а bad_ind - это просто список индексов для векторов объектов, которые связали классовые голоса. В моих тестовых случаях, используя приведенный выше код, распределение между двумя связанными классами ближе к 90/10.

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

Разве эти случаи с радиочастотными деревьями, связанными при голосовании, не должны заканчиваться 50/50?

Обновление: Трудно привести пример из-за случайного характера обучения леса, но следующий код (извините за уклон) должен привести к тому, что в лесах не будет ясного победителя. Мои тестовые прогоны показывают распределение 66% / 33%, когда связи разорваны - я ожидал, что это будет 50% / 50%.

library(randomForest)
x1 = runif(200,-4,4)
x2 = runif(200,-4,4)
x3 = runif(1000,-4,4)
x4 = runif(1000,-4,4)
y1 = dnorm(x1,mean=0,sd=1)
y2 = dnorm(x2,mean=0,sd=1)
y3 = dnorm(x3,mean=0,sd=1)
y4 = dnorm(x4,mean=0,sd=1)
train = data.frame("v1"=y1,"v2"=y2)
val = data.frame("v1"=y3,"v2"=y4)
tlab = vector("integer",length(y1))
tlab_ind = sample(1:length(y1),length(y1)/2)
tlab[tlab_ind]= 1
tlab[-tlab_ind] = 2
tlabf = factor(tlab)
vlab = vector("integer",length(y3))
vlab_ind = sample(1:length(y3),length(y3)/2)
vlab[vlab_ind]= 1
vlab[-vlab_ind] = 2
vlabf = factor(vlab)
mm <- randomForest(x=train,y=tlabf,ntree=100)
out1 <- predict(mm,val)
out2 <- predict(mm,val)
out3 <- predict(mm,val)
outv1 <- predict(mm,val,norm.votes=FALSE,type="vote")
outv2 <- predict(mm,val,norm.votes=FALSE,type="vote")
outv3 <- predict(mm,val,norm.votes=FALSE,type="vote")

(max(as.integer(out1)-as.integer(out2)));(min(as.integer(out1)-as.integer(out2)))
(max(as.integer(out2)-as.integer(out3)));(min(as.integer(out2)-as.integer(out3)))
(max(as.integer(out1)-as.integer(out3)));(min(as.integer(out1)-as.integer(out3)))

bad_ind = vector("list",0)
for (i in 1:length(out1)) {
#for (i in 1:100) {
  if (out1[[i]] != out2[[i]]){
    print(paste(i,out1[[i]],out2[[i]],sep = ";    "))
    bad_ind = append(bad_ind,i)
  }
}

for (j in 1:length(bad_ind)) {
  cnum = vector("integer",1000)
  for (i in 1:length(cnum)) {
    cnum[[i]] = as.integer(predict(mm,val[bad_ind[[j]],]))
  }
  cls = unique(cnum)
  perc_vals = vector("integer",length(cls))
  for (i in 1:length(cls)){
    perc_vals[[i]] = length(which(cnum == cls[i]))
  }
  cat("for feature vector ",bad_ind[[j]]," the class distrbution is: ",perc_vals[[1]]/sum(perc_vals),"/",perc_vals[[2]]/sum(perc_vals),"\n")
}

Обновление: Это должно быть исправлено в версии 4.6-3 для randomForest.

Ответы [ 3 ]

1 голос
/ 08 декабря 2011

Я думаю, что это происходит, потому что у вас такое небольшое количество связей.Та же проблема, что и при подбрасывании монеты 10 раз, вы не гарантированно закутываетесь в 5 голов 5 хвостов.

В случае 1, приведенном ниже, связи нарушаются равномерно, 1: 1 для каждого класса.В случае 2, 3: 6.

> out1[out1 != out2]
 52 109 144 197 314 609 939 950 
  2   2   1   2   2   1   1   1 

> out1[out1 != out3]
 52 144 146 253 314 479 609 841 939 
  2   1   2   2   2   2   1   2   1 

Переход к большему набору данных:

x1 = runif(2000,-4,4)
x2 = runif(2000,-4,4)
x3 = runif(10000,-4,4)
x4 = runif(10000,-4,4)

Я получаю:

> sum(out1[out1 != out2] == 1)
[1] 39
> sum(out1[out1 != out2] == 2)
[1] 41

и

> sum(out1[out1 != out3] == 1)
[1] 30
> sum(out1[out1 != out3] == 2)
[1] 31

, как и ожидалось, если я не пойму ваш код.


РЕДАКТИРОВАТЬ

О, понятно.Вы повторно запускаете дела, у которых были связи, и ожидаете, что они будут разорваны 50/50, то есть: sum(cnum == 1) приблизительно равно sum(cnum == 2).Используя этот подход, вы можете тестировать намного быстрее:

> for (j in 1:length(bad_ind)) {
+   mydata= data.frame("v1"=0, "v2"=0)
+   mydata[rep(1:1000000),] = val[bad_ind[[j]],]
+   outpred = predict(mm,mydata)
+   print(sum(outpred==1) / sum(outpred==2))
+ }
[1] 0.5007849
[1] 0.5003278
[1] 0.4998868
[1] 0.4995651

Кажется, вы правы, разрывая связи в пользу класса 2 вдвое чаще, чем класса 1.

1 голос
/ 31 декабря 2011

Это должно быть исправлено в версии 4.6-3 для randomForest.

1 голос
/ 08 декабря 2011

Без полного примера трудно сказать, является ли это единственной ошибкой, но одна очевидная проблема с кодом, который вы включили выше, заключается в том, что вы не копируете шаг подбора модели - только шаг прогнозирования. Выбор произвольного разрыва связи делается, когда вы подходите к модели, поэтому, если вы не переделаете эту часть, ваши predict() вызовы будут давать тому же классу более высокую вероятность / голосов.

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

library(randomForest)
df = data.frame(class=factor(rep(1:2, each=5)), X1=rep(c(1,3), each=5), X2=rep(c(2,3), each=5))
fitTie <- function(df) {
  df.rf <- randomForest(class ~ ., data=df)
  predict(df.rf, newdata=data.frame(X1=1, X2=3), type='vote')[1]
}
> df
   class X1 X2
1      1  1  2
2      1  1  2
3      1  1  2
4      1  1  2
5      1  1  2
6      2  3  3
7      2  3  3
8      2  3  3
9      2  3  3
10     2  3  3

> mean(replicate(10000, fitTie(df)))
[1] 0.49989
...