Загружаем нужные пакеты:
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 деревьев. Для каждого дерева:
mtry=
3 регрессора из множества всех регрессоров, а уже затем из них выбирается переменная, использование которой даёт наибольшее падение индекса Джини.Есть много вариаций алгоритма, можно менять ntree
, mtry
, брать для каждого дерева случайную выборку с повторениями или без. В R по умолчанию берется ntree
равное 500 и mtry
равное корню из количества регрессоров.
Загружаем данные:
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
Для небольших наборов данных можно посчитать меры близости, т.е. насколько каждые два наблюдения близки между собой.
Почиташки: