Дерево рішень у R: Дерево класифікації з прикладом
⚡ Розумний підсумок
Дерева рішень в R розділяють дані на гілки, використовуючи прості правила «так» або «ні», доки кожен лист не містить одного домінантного класу. У цьому покроковому посібнику побудовано, побудовано, оцінено та налаштовано дерево класифікації rpart на наборі даних про виживання «Титаніка».
Що таке дерева рішень?
Дерева рішень – це універсальний алгоритм машинного навчання, який може виконувати як завдання класифікації, так і регресії. Це дуже потужні алгоритми, здатні підбирати складні набори даних. Крім того, дерева рішень є фундаментальними компонентами випадкових лісів, які є одними з найпотужніших алгоритмів машинного навчання, доступних сьогодні.
Перш ніж створювати його в коді, корисно знати, як дерево вирішує, де розділитися.
Як працює дерево рішень?
Дерево рішень перетворює набір даних на блок-схему питань типу «так» чи «ні», побудовану з трьох типів вузлів: корінь проводить кожне навчальне спостереження, внутрішній вузол ставить питання про один предиктор і розділяє дані на дві частини, а лист зупиняє розщеплення та повертає клас більшості.
Зростання відбувається за жадібною процедурою, яка називається рекурсивне бінарне розбиття:
- Оцініть кожен поділ кандидатів. Для кожного предиктора та точки відсікання виміряйте, наскільки нечистими будуть дві отримані групи.
- Залиште собі найкращий. Розщеплення, яке найбільше зменшує домішки, стає питанням, яке задається в цьому вузлі.
- Повторити з кожною дитиною доки його не зупинить правило керування: minsplit, minbucket, maxdepth або cp.
- Чорнослив. Потім cp обрізає гілки, які не окупаються, що зупиняє запам'ятовування навчального набору деревом.
Оскільки кожне запитання порівнює одну змінну з пороговим значенням, алгоритм ніколи не потребує масштабування або фіктивного кодування.
Індекс Джині проти ентропії в деревах рішень
Цю домішку можна виміряти двома способами, і rpart дозволяє вам вибрати.
| Критерії | Індекс Джині | Ентропія (інформаційний приріст) |
|---|---|---|
| Formula | 1 – сума квадратів пропорцій класу | -сума p, помножена на log²(p) |
| Асортимент (два класи) | 0 до 0.5, | 0 до 1, |
| Обчислення | Швидше, без логарифмування | Повільніше, використовує логарифми |
| налаштування rpart | дефолт | parms = список(split = “інформація”) |
fit_entropy <- rpart(survived~., data = data_train, method = 'class', parms = list(split = "information"))
На практиці обидва критерії більшу частину часу вибирають один і той самий розподіл, тому індекс Джині за замовчуванням є безпечним вибором.
Переваги та недоліки дерев рішень
Компроміси підказують, коли одного дерева достатньо, а коли переходити до ансамблю.
Переваги
- Повністю інтерпретується: Підібрана модель — це діаграма, яку може прочитати будь-який зацікавлений сторон.
- Мінімальна попередня обробка: не потрібне масштабування чи нормалізація, а фактори працюють автоматично.
- Вирішує обидва завдання: method = 'class' відповідає класифікатору, а method = 'anova' відповідає дереву регресії.
- Швидко тренується: Великі набори даних вміщуються за лічені секунди, тому дерева є корисною першою базовою лінією.
Недоліки
- Висока дисперсія: невелика зміна в навчальних даних може призвести до зовсім іншого дерева.
- Схильні до перенавантаження: Необмежене дерево росте доти, доки кожен листок не стане чистим, якщо cp та maxdepth не обмежують його.
- Тільки паралельні по осях розбиття: діагональні межі потребують багатьох розрізів у формі сходів.
Засіб від перших двох слабких місць полягає в усередненні великої кількості дерев, що і є випадковий ліс робить.
Як навчити та візуалізувати дерево рішень в R
Щоб побудувати своє перше дерево рішень у R, вам потрібно буде виконати сім кроків:
- Крок 1. Імпортуйте дані
- Крок 2. Очистіть набір даних
- Крок 3: Створіть тренувальний/тестовий набір
- Крок 4: Побудуйте модель
- Крок 5: Зробіть прогноз
- Крок 6. Виміряйте продуктивність
- Крок 7: Налаштуйте гіперпараметри
Крок 1) Імпортуйте дані
Якщо вам цікава доля титаніка, ви можете переглянути це відео на Youtube. Мета цього набору даних — передбачити, які люди мають більше шансів вижити після зіткнення з айсбергом. Набір даних містить 13 змінних і 1309 спостережень. Набір даних упорядковано за змінною X.
set.seed(678) path <- 'https://raw.githubusercontent.com/guru99-edu/R-Programming/master/titanic_data.csv' titanic <-read.csv(path) head(titanic)
вихід:
## X pclass survived name sex ## 1 1 1 1 Allen, Miss. Elisabeth Walton female ## 2 2 1 1 Allison, Master. Hudson Trevor male ## 3 3 1 0 Allison, Miss. Helen Loraine female ## 4 4 1 0 Allison, Mr. Hudson Joshua Creighton male ## 5 5 1 0 Allison, Mrs. Hudson J C (Bessie Waldo Daniels) female ## 6 6 1 1 Anderson, Mr. Harry male ## age sibsp parch ticket fare cabin embarked ## 1 29.0000 0 0 24160 211.3375 B5 S ## 2 0.9167 1 2 113781 151.5500 C22 C26 S ## 3 2.0000 1 2 113781 151.5500 C22 C26 S ## 4 30.0000 1 2 113781 151.5500 C22 C26 S ## 5 25.0000 1 2 113781 151.5500 C22 C26 S ## 6 48.0000 0 0 19952 26.5500 E12 S ## home.dest ## 1 St Louis, MO ## 2 Montreal, PQ / Chesterville, ON ## 3 Montreal, PQ / Chesterville, ON ## 4 Montreal, PQ / Chesterville, ON ## 5 Montreal, PQ / Chesterville, ON ## 6 New York, NY
tail(titanic)
вихід:
## X pclass survived name sex age sibsp ## 1304 1304 3 0 Yousseff, Mr. Gerious male NA 0 ## 1305 1305 3 0 Zabour, Miss. Hileni female 14.5 1 ## 1306 1306 3 0 Zabour, Miss. Thamine female NA 1 ## 1307 1307 3 0 Zakarian, Mr. Mapriededer male 26.5 0 ## 1308 1308 3 0 Zakarian, Mr. Ortin male 27.0 0 ## 1309 1309 3 0 Zimmerman, Mr. Leo male 29.0 0 ## parch ticket fare cabin embarked home.dest ## 1304 0 2627 14.4583 C ## 1305 0 2665 14.4542 C ## 1306 0 2665 14.4542 C ## 1307 0 2656 7.2250 C ## 1308 0 2670 7.2250 C ## 1309 0 315082 7.8750 S
З вихідних даних голови та хвоста ви можете помітити, що дані не перетасовані. Це велика проблема! Ви вибираєте, коли ви розділяєте свої дані між набором поїздів і тестовим набором тільки пасажир з класу 1 і 2 (жодного пасажира з класу 3 не входить до 80 відсотків спостережень), що означає, що алгоритм ніколи не побачить характеристики пасажира класу 3. Ця помилка призведе до поганого прогнозу.
Щоб подолати цю проблему, ви можете використовувати функцію sample().
shuffle_index <- sample(1:nrow(titanic)) head(shuffle_index)
Дерево рішень R код Пояснення
- sample(1:nrow(titanic)): генерує випадковий список індексів від 1 до 1309 (тобто максимальну кількість рядків).
вихід:
## [1] 288 874 1078 633 887 992
Ви будете використовувати цей індекс, щоб перетасувати титанічний набір даних.
titanic <- titanic[shuffle_index, ]
head(titanic)
вихід:
## X pclass survived ## 288 288 1 0 ## 874 874 3 0 ## 1078 1078 3 1 ## 633 633 3 0 ## 887 887 3 1 ## 992 992 3 1 ## name sex age ## 288 Sutton, Mr. Frederick male 61 ## 874 Humblen, Mr. Adolf Mathias Nicolai Olsen male 42 ## 1078 O'Driscoll, Miss. Bridget female NA ## 633 Andersson, Mrs. Anders Johan (Alfrida Konstantia Brogren) female 39 ## 887 Jermyn, Miss. Annie female NA ## 992 Mamee, Mr. Hanna male NA ## sibsp parch ticket fare cabin embarked home.dest## 288 0 0 36963 32.3208 D50 S Haddenfield, NJ ## 874 0 0 348121 7.6500 F G63 S ## 1078 0 0 14311 7.7500 Q ## 633 1 5 347082 31.2750 S Sweden Winnipeg, MN ## 887 0 0 14313 7.7500 Q ## 992 0 0 2677 7.2292 C
Крок 2) Очистіть набір даних
Кілька змінних містять значення NA. Очищення виконується у три етапи:
- Видаліть змінні home.dest, cabin, name, X та ticket
- Створіть факторні змінні для pclass і survived
- Відпустіть НС
library(dplyr) # Drop variables clean_titanic <- titanic %>% select(-c(home.dest, cabin, name, X, ticket)) %>% #Convert to factor level mutate(pclass = factor(pclass, levels = c(1, 2, 3), labels = c('Upper', 'Middle', 'Lower')), survived = factor(survived, levels = c(0, 1), labels = c('No', 'Yes'))) %>% na.omit() glimpse(clean_titanic)
Code Пояснення
- select(-c(home.dest, cabin, name, X, ticket)): видалити непотрібні змінні
- pclass = factor(pclass, levels = c(1,2,3), labels= c('Верхній', 'Середній', 'Нижній')): Додати мітку до змінної pclass. 1 стає Верхнім, 2 стає Середнім, а 3 стає Нижнім
- factor(survived, levels = c(0,1), labels = c('Ні', 'Так')): Додати мітки до змінної survived. 0 стає Ні, а 1 стає Так
- na.omit(): Видалити спостереження NA
вихід:
## Observations: 1,045 ## Variables: 8 ## $ pclass <fctr> Upper, Lower, Lower, Upper, Middle, Upper, Middle, U... ## $ survived <fctr> No, No, No, Yes, No, Yes, Yes, No, No, No, No, No, Y... ## $ sex <fctr> male, male, female, female, male, male, female, male... ## $ age <dbl> 61.0, 42.0, 39.0, 49.0, 29.0, 37.0, 20.0, 54.0, 2.0, ... ## $ sibsp <int> 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, 0, 1, 1, 0, 0, 0, 1, 1,... ## $ parch <int> 0, 0, 5, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 4, 0,... ## $ fare <dbl> 32.3208, 7.6500, 31.2750, 25.9292, 10.5000, 52.5542, ... ## $ embarked <fctr> S, S, S, S, S, S, S, S, S, C, S, S, S, Q, C, S, S, C...
Крок 3) Створіть навчальний/тестовий набір
Перш ніж навчити свою модель, вам потрібно виконати два кроки:
- Створення тренування та тестового набору: Ви навчаєте модель на тренуванні та перевіряєте прогноз на тестовому наборі (тобто невидимі дані).
- Встановіть rpart.plot з консолі
Загальноприйнятою практикою є розділення даних 80/20, 80 відсотків даних служать для навчання моделі, а 20 відсотків — для прогнозування. Вам потрібно створити два окремих кадри даних. Ви не хочете торкатися тестового набору, доки не завершите створення своєї моделі. Ви можете створити назву функції create_train_test(), яка приймає три аргументи.
create_train_test(df, size = 0.8, train = TRUE) arguments: -df: Dataset used to train the model. -size: Size of the split. By default, 0.8. Numerical value -train: If set to `TRUE`, the function creates the train set, otherwise the test set. Default value sets to `TRUE`. Boolean value.You need to add a Boolean parameter because R does not allow to return two data frames simultaneously.
create_train_test <- function(data, size = 0.8, train = TRUE) { n_row = nrow(data) total_row = size * n_row train_sample <- 1: total_row if (train == TRUE) { return (data[train_sample, ]) } else { return (data[-train_sample, ]) } }
Code Пояснення
- function(data, size=0.8, train = TRUE): додайте аргументи у функцію
- n_row = nrow(data): підрахувати кількість рядків у наборі даних
- total_row = size*n_row: повертає n-й рядок, щоб побудувати набір поїздів
- train_sample <- 1:total_row: Виберіть перший рядок до n-го рядків
- if (train ==TRUE){ } else { }: якщо умова має значення true, повертає набір поїздів, інакше тестовий набір.
Ви можете перевірити свою функцію та перевірити розмір.
data_train <- create_train_test(clean_titanic, 0.8, train = TRUE) data_test <- create_train_test(clean_titanic, 0.8, train = FALSE) dim(data_train)
вихід:
## [1] 836 8
dim(data_test)
вихід:
## [1] 209 8
Набір даних про поїзди має 836 рядків і 8 стовпців, тоді як тестовий набір даних має 209 рядків і ті ж 8 стовпців.
Ви використовуєте функцію prop.table() у поєднанні з table(), щоб перевірити правильність процесу рандомізації.
prop.table(table(data_train$survived))
вихід:
## ## No Yes ## 0.5944976 0.4055024
prop.table(table(data_test$survived))
вихід:
## ## No Yes ## 0.5789474 0.4210526
В обох наборах даних кількість вижили однакова, близько 40 відсотків.
Встановіть rpart.plot
rpart.plot недоступний з бібліотек conda. Ви можете встановити його з консолі:
install.packages("rpart.plot")
Крок 4) Побудуйте модель
Ви готові до побудови моделі. Синтаксис функції дерева рішень rpart() такий:
rpart(formula, data=, method='') arguments: - formula: The function to predict - data: Specifies the data frame - method: - "class" for a classification tree - "anova" for a regression tree
Ви використовуєте метод класу, оскільки ви прогнозуєте клас.
library(rpart) library(rpart.plot) fit <- rpart(survived~., data = data_train, method = 'class') rpart.plot(fit, extra = 106)
Code Пояснення
- rpart(): функція для підгонки моделі. Аргументи:
- пережив ~.: Формула дерев рішень
- data = data_train: Набір даних
- method = 'class': підібрати бінарну модель
- rpart.plot(fit, extra= 106): Побудувати дерево. Аргумент extra встановлено на 106, що відображає ймовірність другого класу плюс відсоток спостережень у кожному вузлі. Ви можете звернутися до віньєтка для отримання додаткової інформації про інші варіанти.
вихід:
Ви починаєте з кореневого вузла, у верхній частині графіка та на глибині 0 з 3:
- На вершині це загальна ймовірність виживання. Він показує частку пасажирів, які вижили в аварії. 41 відсоток пасажирів вижив.
- Цей вузол запитує, чи стать пасажира чоловіча. Якщо так, то ви переходите до лівого дочірнього елемента кореня (глибина 1). 63 відсотки — чоловіки з ймовірністю виживання 21 відсоток.
- У другому вузлі ви запитуєте, чи пасажиру чоловічої статі більше 3.5 років. Якщо так, то шанс вижити становить 19 відсотків.
- Ви продовжуєте так, щоб зрозуміти, які особливості впливають на ймовірність виживання.
Зауважте, що однією з багатьох властивостей дерев рішень є те, що вони вимагають дуже мало підготовки даних. Зокрема, вони не вимагають масштабування або центрування функцій.
За замовчуванням функція rpart() використовує Джині міра домішки для вибору кожного розколу. Чим вище значення Джині, тим більше змішані класи всередині цього вузла, тому алгоритм завжди вибирає розкол, який найбільше його знижує.
Крок 5) Зробіть прогноз
Ви можете передбачити свій тестовий набір даних. Щоб зробити прогноз, ви можете скористатися функцією predict(). Основний синтаксис прогнозу для дерева рішень R:
predict(fitted_model, df, type = 'class') arguments: - fitted_model: This is the object stored after model estimation. - df: Data frame used to make the prediction - type: Type of prediction - 'class': for classification - 'prob': to compute the probability of each class - 'vector': Predict the mean response at the node level
Тепер ви прогнозуєте для кожного з 209 пасажирів у тестовому наборі, чи очікує модель, що вони виживуть після зіткнення.
predict_unseen <-predict(fit, data_test, type = 'class')
Code Пояснення
- predict(fit, data_test, type = 'class'): передбачити клас (0/1) тестового набору
Тепер порівняйте прогнозовані класи з реальними результатами.
table_mat <- table(data_test$survived, predict_unseen)
table_mat
Code Пояснення
- table(data_test$survived, predict_unseen): Побудувати таблицю зв'язків передбачуваних класів відносно справжнього результату
вихід:
## predict_unseen ## No Yes ## No 106 15 ## Yes 30 58
Рядки – це фактичні значення, стовпці – прогнози. Модель правильно визначила 106 осіб, які не вижили, та 58 осіб, які вижили, але позначила 15 осіб, які не вижили, як тих, хто вижив, та 30 осіб, які вижили, як тих, хто помер.
Крок 6) Виміряйте продуктивність
Ви можете обчислити міру точності для завдання класифікації за допомогою матриця плутанини:
Команда матриця плутанини є кращим вибором для оцінки ефективності класифікації. Загальна ідея полягає в тому, щоб підрахувати кількість разів, коли випадки True класифікуються як False.
Кожен рядок матриці плутанини представляє фактичну ціль, тоді як кожен стовпець представляє передбачувану ціль. Перший рядок цієї матриці враховує пасажирів, які загинули (негативний клас): 106 було правильно класифіковано як загиблих (Справжній негатив), тоді як 15 були помилково класифіковані як ті, хто вижив (Хибно позитивний). У другому рядку враховано тих, хто вижив: 58 було правильно ідентифіковано (Справжній позитив), тоді як 30 було пропущено (Хибнонегативний).
Ви можете обчислити тест на точність з матриці плутанини:
Це частка істинно позитивного та істинно негативного значення в сумі матриці. За допомогою R ви можете кодувати наступним чином:
accuracy_Test <- sum(diag(table_mat)) / sum(table_mat)
Code Пояснення
- sum(diag(table_mat)): сума діагоналі
- sum(table_mat): сума матриці.
Ви можете роздрукувати точність тестового набору:
print(paste('Accuracy for test', accuracy_Test))
вихід:
## [1] "Accuracy for test 0.784688995215311"
Точність на тестовому наборі становить 0.7847, що становить 78.47 відсотка. Повторіть вправу на навчальному наборі, щоб побачити, наскільки модель переналаштовується.
Крок 7) Налаштуйте гіперпараметри
Дерево рішень у R має різні параметри, які контролюють аспекти відповідності. У бібліотеці дерева рішень rpart ви можете керувати параметрами за допомогою функції rpart.control(). У наступному коді ви вводите параметри, які ви будете налаштовувати. Ви можете звернутися до віньєтка для інших параметрів.
rpart.control(minsplit = 20, minbucket = round(minsplit/3), maxdepth = 30) Arguments: -minsplit: Set the minimum number of observations in the node before the algorithm perform a split -minbucket: Set the minimum number of observations in a terminal node, i.e. the leaf -maxdepth: Set the maximum depth of any node of the final tree. The root node is treated as depth 0
Ми будемо діяти наступним чином:
- Побудова функції для повернення точності
- Налаштувати максимальну глибину
- Налаштуйте мінімальну кількість зразків, які повинен мати вузол, перш ніж його можна буде розділити
- Налаштуйте мінімальну кількість зразків, які повинен мати листовий вузол
Ви можете написати функцію для відображення точності. Ви просто обертаєте код, який використовували раніше:
- predict: predict_unseen <- predict(fit, data_test, type = 'class')
- Створення таблиці: table_mat <- table(data_test$survived, predict_unseen)
- Точність обчислення: accuracy_Test <- sum(diag(table_mat))/sum(table_mat)
accuracy_tune <- function(fit) { predict_unseen <- predict(fit, data_test, type = 'class') table_mat <- table(data_test$survived, predict_unseen) accuracy_Test <- sum(diag(table_mat)) / sum(table_mat) accuracy_Test }
Тепер налаштуйте параметри та подивіться, чи можна покращити модель за замовчуванням. Нагадуємо, що вам потрібно перевершити точність 0.7847.
control <- rpart.control(minsplit = 4,
minbucket = round(5 / 3),
maxdepth = 3,
cp = 0)
tune_fit <- rpart(survived~., data = data_train, method = 'class', control = control)
accuracy_tune(tune_fit)
вихід:
## [1] 0.7990431
З таким параметром:
minsplit = 4
minbucket = round(5/3)
maxdepth = 3
cp = 0
Точність зростає з 0.7847 до 0.7990, тому налаштоване дерево перевершує конфігурацію за замовчуванням приблизно на 1.4 відсоткових пункти.
Дерева рішень у R: Короткий довідник з функцій
У таблиці нижче перелічено всі функції, що використовуються у семи кроках вище, разом із пакетом, який їх надає, та параметрами, які вона очікує. R.
| Library | Мета | функція | Клас | Параметри | Деталі |
|---|---|---|---|---|---|
| rpart | Дерево класифікації поїздів у R | rpart() | клас | формула, df, метод | |
| rpart | Дерево тренування регресії | rpart() | anova | формула, df, метод | |
| rpart | Накресліть дерева | rpart.plot() | приталена модель | ||
| база | передбачати | передбачити() | клас | приталена модель, тип | |
| база | передбачати | передбачити() | проб | приталена модель, тип | |
| база | передбачати | передбачити() | вектор | приталена модель, тип | |
| rpart | Параметри управління | rpart.control() | minsplit | Встановіть мінімальну кількість спостережень у вузлі, перш ніж алгоритм виконає розбиття | |
| minbucket | Встановити мінімальну кількість спостережень у термінальному вузлі, тобто листку | ||||
| максимальна глибина | Встановлює максимальну глибину будь-якого вузла кінцевого дерева. Кореневий вузол вважається глибиною 0. | ||||
| rpart | Модель поїзда з контрольним параметром | rpart() | формула, df, метод, контроль |
Примітка. Навчіть модель на навчальних даних і перевірте продуктивність на невидимому наборі даних, тобто тестовому наборі.




