Різниця в реалізації двійкових розщеплень у деревах рішень


12

Мені цікаво практична реалізація бінарного розколу на дереві рішень - оскільки це стосується рівнів категоричного предиктора .Хj

Зокрема, я часто буду використовувати якусь схему відбору зразків (наприклад, розфасування, пересимплінг тощо), коли будую модель прогнозування за допомогою дерева рішень, щоб поліпшити її точність прогнозування та стабільність. Під час цих процедур вибірки категорична змінна може бути представлена ​​в алгоритмі встановлення дерева з меншим, ніж повний набір рівнів.

Скажімо, змінна X займає рівні {A,B,C,D,E}. У вибірці можуть бути лише рівні {A,B,C,D}. Потім, коли отримане дерево використовується для прогнозування, може бути присутній повний набір.

Продовжуючи цей приклад, скажімо, що дерево розбивається на X і направляється {A,B}ліворуч та {C,D}праворуч. Я б очікував, що логіка двійкового розколу потім скаже, стикаючись з новими даними: "Якщо X має значення A або B, надішліть ліворуч, інакше надішліть цей випадок праворуч". Що, здається, трапляється в деяких реалізаціях, це "якщо X має значення A або B, надішліть ліворуч, якщо X має значення C або D надішліть праворуч". Коли цей випадок набуває значення E, алгоритм руйнується.

Який "правильний" спосіб обробляти двійковий розкол? Здається, набагато надійніший спосіб реалізується часто, але не завжди (див. Розділ нижче).

Ось кілька прикладів:

Rpart не вдається, з іншими нормально.

#test trees and missing values

summary(solder)
table(solder$PadType)

# create train and validation
set.seed(12345)
t_rows<-sample(1:nrow(solder),size=360, replace=FALSE)
train_solder<-solder[t_rows,]
val_solder<-solder[-t_rows,]

#look at PadType
table(train_solder$PadType)
table(val_solder$PadType)
#set a bunch to missing
levels(train_solder$PadType)[train_solder$PadType %in% c('L8','L9','W4','W9')] <- 'MISSING'


#Fit several trees, may have to play with the parameters to get them to split on the variable

####RPART
mod_rpart<-rpart(Solder~PadType,data=train_solder)
predict(mod_rpart,val_solder)
#Error in model.frame.default(Terms, newdata, na.action = na.action, xlev = attr(object,  : 
#factor 'PadType' has new level(s) D6, L6, L7, L8, L9, W4

####TREE
mod_tree<-tree(Solder~PadType,data=train_solder,split="gini")
predict(mod_tree,val_solder) #works fine

####ctree
mod_ctree<-ctree(Solder~PadType,data=train_solder,control = ctree_control(mincriterion = 0.05))
predict(mod_ctree,val_solder) #works fine

Відповіді:


9

Насправді існує два типи факторів - упорядкований (як крихітний <малий <середній <великий <величезний) та не упорядкований (огірок, морква, фенхель, баклажан).
Перший клас такий же, як і безперервний - перевірити всі повороти лише простіше, також немає проблем із розширенням списку рівнів.
Для другого класу ви повинні скласти набір елементів, які будуть спрямовані в одну гілку, залишаючи решту в іншу - у цьому випадку ви можете:

  1. помилка кидка
  2. припустимо, що небачений клас переходить у вашу улюблену галузь
  3. трактуйте це як NA та виберіть гілку більш менш випадковим чином.

12#категорії-1-1ii

Я б сказав, що найрозумніша ідея - це змусити користувача визначити повний набір факторів (наприклад, R робить це органічно, зберігаючи рівні за допомогою операцій підмножини) та використовувати варіант 1. для незадекларованих рівнів та варіант 2. для оголошених . Варіант 3. може мати сенс, якщо у вас вже є якась інфраструктура обробки NA.

*) Існує також побічна стратегія зробити деяке нетривіальне перекодування рівнів у числа, як, наприклад, кодування Breiman - але це створює ще більше проблем.


1
Ви хочете сказати, що ctree або дерево в моєму прикладі насправді трактує цей не упорядкований фактор як упорядкований фактор і таким чином надсилає його у відділення "0"?
B_Miner

@mbq, чи можете ви пояснити, чому загальна кількість способів розщеплення дорівнює 2 ^ (# категорії + 1) - 2. Я не зовсім розумію, чому частина "-2".
медобандер

Гм, здається, я накрутив цю формулу; є як 2 ^ n n-бітових слів, але ми не рахуємо і слова a і ~ a, тому 2 ^ (n-1), і нам не подобаються розщеплення, які взагалі не розпливаються, так 2 ^ (n-1) -1 (іншими словами, рахуємо від 1). n = 1 - це окремий випадок.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.