Загружаем нужные пакеты:

library("randomForest")
library("ggplot2")

Индекс Джини и энтропия

Предположим, что в выборке \(A\) у нас есть объекты разных типов, скажем, черные муравьи, рыжие муравьи и киты. Доля объектов типа \(i\) в выборке \(A\) равна \(f_i\).

В выборке из ста муравьев и одного кита средняя масса муравья может оказаться больше килограмма.

Индекс Джини — это вероятность того, что типы двух случайно независимо друг от друга выбранных объектов не совпадут. Индекс Джини равен \[ I_G=\sum_i f_i(1-f_i) = 1 - \sum_i f_i^2 \] Энтропия определяется как (при соглашении \(0 \cdot \ln 0=0\)) \[ I_E= - \sum f_i \ln f_i \]

Индекс Джини и энтропия измеряют неоднородность выборки. Индекс Джини и энтропия будут максимальны, если все типы равновероятны. Если же все объекты принадлежат одному типу, то индекс Джини и энтропия равны нулю.

Классификационное дерево

Каждый мужчина должен посадить дерево!

При каждом ветвлении дерево разбивает выборку на несколько частей (обычно на две): \(A_1\), \(A_2\), … Индекс Джини или энтропия для выборки разбитой на несколько частей определяется как взвешенные по частям:

\[ I_G(Tree)=\sum_j P(A_j) \cdot I_G(A_j) \] \[ I_E(Tree)=\sum_j P(A_j) \cdot I_E(A_j) \]

где \(P(A_j)\) — размер выборки \(A_j\) деленный на общее число наблюдений.

Как посадить одно дерево для качественной переменной?

Существует куча алгоритмов как построить одно дерево. Рассмотрим один под условным названием “Джин жадный до Джини” :)

Алгоритм растит дерево так, чтобы падение индекса Джини было максимальным на каждом шаге.

Проблема с этим алгоритмом состоит в том, что на обучающей выборке он показывает очень хороший результат, но при попытке прогнозирования за пределы обучающей выборки качестве прогнозов становится плохим. Существует несколько подходов, как победить эту проблему. Один из подходов — укорачивание дерева после его построения. Другой подход — случайный лес.

Как посадить одно дерево для количественной переменной?

Дерево можно также строить для непрерывной зависимой переменной. Отличий немного:

Случайный лес

Допустим в общей выборке всего \(n\) наблюдений. Случайный лес строит ntree=500 деревьев. Для каждого дерева:

Есть много вариаций алгоритма, можно менять ntree, mtry, брать для каждого дерева случайную выборку с повторениями или без. В R по умолчанию берется ntree равное 500 и mtry равное корню из количества регрессоров.

R

Загружаем данные:

h <- read.table("~/Documents/em301/datasets/flats_moscow.txt", header = TRUE)

Сажаем случайный лес. Тут важно, что есть два алгоритма — случайный лес для качественной переменной и случайный лес для количественной переменной. R сам определит, какой использовать, если правильно указать тип записимой переменной, numeric или factor.

str(h$brick)
##  int [1:2040] 1 0 1 0 1 1 0 1 1 0 ...
h$brick <- as.factor(h$brick)
str(h$brick)
##  Factor w/ 2 levels "0","1": 2 1 2 1 2 2 1 2 2 1 ...
model <- randomForest(brick ~ price + totsp + kitsp + dist, data = h)

Строим прогнозы вероятностей

new_data <- data.frame(price = 100, totsp = 60, kitsp = 10, dist = 13)
predict(model, new_data, type = "prob")
##       0     1
## 1 0.938 0.062
## attr(,"class")
## [1] "matrix" "votes"

Меры важности

Волков бояться — в лес не ходить!

Посмотрим на первое дерево в лесу:

tree1 <- getTree(model, 1, labelVar = TRUE)
head(tree1)
##   left daughter right daughter split var split point status prediction
## 1             2              3      dist       11.75      1       <NA>
## 2             4              5     price      147.50      1       <NA>
## 3             6              7     totsp       84.50      1       <NA>
## 4             8              9     kitsp        9.50      1       <NA>
## 5            10             11     price      225.50      1       <NA>
## 6            12             13     totsp       58.50      1       <NA>

Здесь split var — это переменная по которой происходит разделение, split point — значение с которым сравнивается разделяющая переменная. Для нетерминальных (status=1) узлов указываются левый и правый узлы за данным, left daughter и right daughter. Для терминальных (status=-1) узлов указывается прогноз, prediction.

Даже на одном дереве не очень-то понятно, что происходит, а уж на 500 деревьях и подавно!

Чем дальше в лес, тем толще партизаны!

Алгоритм случайного леса хорошо прогнозирует, но не дает какой-то простой наглядной формулы модели. Чтобы как-то описать, что происходит внутри леса придумали меры важности регрессоров.

Переоценим нашу модель заново, теперь попросим R посчитать меры важности регрессоров:

model <- randomForest(brick ~ price + totsp + kitsp + dist, 
                      data = h, importance = TRUE)
importance(model)
##              0        1 MeanDecreaseAccuracy MeanDecreaseGini
## price 59.38571 23.15105             72.61310         259.2885
## totsp 58.60943 13.70479             71.39470         217.0696
## kitsp 64.53308 27.88184             78.60146         126.9355
## dist  63.79644 56.81195             83.08734         254.8525

Меры близости

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

Почиташки: