Перейти к содержимому

DecisionTreeRegressor

DecisionTreeRegressor — модель дерева решений для задач регрессии.

Принцип работы похож на DecisionTreeClassifier: модель строит дерево условий. Но классификатор предсказывает класс, а регрессор предсказывает числовое значение.

Дерево решений задаёт последовательность проверок. На каждом шаге модель проверяет один признак: например, площадь квартиры или расстояние до метро.

Условия могут выглядеть так:

area <= 57.5
metro_minutes <= 10
rooms <= 2.5

Если условие выполняется, мы переходим по одной ветке дерева, иначе по другой. Далее мы либо проверяем новое условие, либо доходим до листа дерева, в котором записан ответ. Этот ответ и есть числовой прогноз модели. Обычно это среднее значение целевой переменной среди обучающих примеров, которые попали в тот же конечный лист дерева.

МодельЧто предсказываетЧто хранится в листе
DecisionTreeClassifierклассметка класса
DecisionTreeRegressorчислочисловой прогноз

Например, классификатор может ответить бульдог или спаниель, а регрессор может предсказать цену квартиры 14.7.

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

Например, цена квартиры может зависеть от площади, числа комнат, этажа и расстояния до метро не по одной прямой формуле, а по набору условий.

В примере модель предсказывает цену квартиры по нескольким числовым признакам из датасета MoscowHousing.

uses MLABC;
begin
var df := Datasets.MoscowHousing.Data;
var features := [
'rooms',
'area',
'kitchen_area',
'floor',
'floors_total',
'metro_minutes'
];
var X := df.ToMatrix(features);
var y := df.ToVector('price');
var (Xtrain, Xtest, ytrain, ytest) :=
Validation.TrainTestSplit(X, y, testRatio := 0.2, seed := 42);
var model := new DecisionTreeRegressor(
maxDepth := 4,
minSamplesSplit := 10,
minSamplesLeaf := 5,
seed := 42
);
model.Fit(Xtrain, ytrain);
var pred := model.Predict(Xtest);
Println('R2:', Metrics.R2(ytest, pred):0:3);
end.

Вывод:

R2: 0.690

R2 — безразмерная метрика качества регрессии. Она показывает, насколько хорошо модель объясняет разброс целевого значения.

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

Это означает, что модель объясняет примерно 69% разброса цен на тестовой выборке. Значит, дерево явно нашло полезные зависимости: площадь, число комнат, этаж, расстояние до метро и другие признаки. Но примерно 31% вариативности остаётся необъяснённой выбранными признаками и самой простой структурой дерева.

Сначала дерево обучается на обучающей выборке:

model.Fit(Xtrain, ytrain);

В процессе обучения модель строит дерево, используя признаки Xtrain и известные ответы ytrain.

После обучения дерево можно применить к тестовой выборке:

var pred := model.Predict(Xtest);

В переменной pred находятся прогнозы модели для всех объектов из Xtest.

Для одного объекта используется PredictOne:

var price := model.PredictOne(Vector([2.0, 45.0, 8.0, 5.0, 12.0, 10.0]));

Здесь числа идут в том же порядке, что и признаки в массиве features: rooms, area, kitchen_area, floor, floors_total, metro_minutes. Это означает, что мы предсказываем стоимость квартиры с двумя комнатами, с площадью 45 квадратных метров, площадью кухни 8 квадратных метров и т.д.

Выведем дерево регрессии с помощью команды:

Println(model.Tree(features));

Получим:

area ≤ 110.8?
├── да: area ≤ 51.15?
│ ├── да: area ≤ 40.23?
│ │ ├── да: 11153677.42
│ │ └── нет: 19990225.82
│ └── нет: area ≤ 88.9?
│ ├── да: 32870095.1
│ └── нет: 47883661.03
└── нет: area ≤ 166.4?
├── да: rooms ≤ 4.5?
│ ├── да: 88784846.53
│ └── нет: 54035762.92
└── нет: floor ≤ 7.5?
├── да: 146355239.93
└── нет: 92208129.97

Чтение начинается с корня дерева — с самого первого вопроса:

area ≤ 110.8?

Если площадь квартиры меньше или равна 110.8, идём по ветке да. Если больше — по ветке нет.

Дальше дерево задаёт следующий вопрос. Например, для квартиры с площадью 45:

area ≤ 110.8? да
area ≤ 51.15? да
area ≤ 40.23? нет

После этого мы попадаем в лист:

19990225.82

Это и есть прогноз дерева: примерно 19.99 млн рублей.

var model := new DecisionTreeRegressor(
maxDepth := 4,
minSamplesSplit := 2,
minSamplesLeaf := 1,
maxFeatures := -1,
seed := 42
);

maxDepth — максимальная глубина дерева.

Если глубина слишком большая, дерево может переобучиться. Если слишком маленькая — модель может оказаться слишком простой.

minSamplesSplit — минимальное число объектов, при котором узел можно разделять.

minSamplesLeaf — минимальное число объектов в листе.

maxFeatures — сколько признаков рассматривать при разбиении.

seed — начальное значение генератора случайных чисел.

Для первых экспериментов обычно достаточно настроить maxDepth и minSamplesLeaf.

  • модель легко объяснить;
  • не требует масштабирования признаков;
  • умеет описывать нелинейные зависимости.
  • легко переобучается при большой глубине;
  • прогноз получается кусочно-постоянным;
  • одно дерево может быть нестабильным.
  • начинайте с небольшой глубины дерева;
  • не делайте minSamplesLeaf слишком маленьким;
  • сравнивайте качество с RandomForestRegressor и GradientBoostingRegressor.