ML - док комменты и Clone - в порядке
This commit is contained in:
parent
3e88b53848
commit
e5c9344b74
|
|
@ -216,6 +216,11 @@ type
|
|||
/// epochs — число итераций обучения.
|
||||
constructor Create(lambda: real := 0.0; lr: real := 0.1; epochs: integer := 1000);
|
||||
|
||||
/// Обучает модель логистической регрессии.
|
||||
/// X — матрица признаков.
|
||||
/// y — вектор меток классов (целочисленные значения).
|
||||
/// Возвращает обученную модель.
|
||||
/// После вызова IsFitted становится true.
|
||||
function Fit(X: Matrix; y: Vector): IModel;
|
||||
|
||||
/// Возвращает матрицу вероятностей (m x k).
|
||||
|
|
@ -224,10 +229,14 @@ type
|
|||
/// Возвращает вектор предсказанных классов.
|
||||
function Predict(X: Matrix): Vector;
|
||||
|
||||
/// Показывает, была ли модель обучена.
|
||||
/// Если false — вызов Predict или PredictProba приведет к ошибке.
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
/// Возвращает строковое представление модели.
|
||||
function ToString: string; override;
|
||||
|
||||
/// Создает глубокую копию модели.
|
||||
function Clone: IModel;
|
||||
end;
|
||||
|
||||
|
|
@ -240,32 +249,56 @@ type
|
|||
Right: DecisionTreeNode;
|
||||
LeafValue: real;
|
||||
|
||||
/// Создает глубокую копию узла вместе со всеми подузлами
|
||||
function Clone: DecisionTreeNode;
|
||||
end;
|
||||
|
||||
/// Результат поиска лучшего разбиения узла дерева.
|
||||
SplitResult = record
|
||||
/// Found = true, если допустимое разбиение найдено.
|
||||
Found: boolean;
|
||||
/// Feature — индекс признака, по которому делается split.
|
||||
Feature: integer;
|
||||
/// Threshold — пороговое значение признака.
|
||||
Threshold: real;
|
||||
end;
|
||||
|
||||
/// Интерфейс критерия разбиения узла дерева.
|
||||
/// Определяет функцию нечистоты (impurity), которая используется для оценки качества разбиения.
|
||||
ISplitCriterion = interface
|
||||
/// Вычисляет нечистоту для вектора целевых значений y.
|
||||
/// Чем меньше значение — тем "чище" узел.
|
||||
function Impurity(y: Vector): real;
|
||||
end;
|
||||
|
||||
/// Критерий Джини.
|
||||
/// Используется в классификации.
|
||||
/// Минимизирует Gini-нечистоту, что приводит к более однородным по классам листьям.
|
||||
GiniCriterion = class(ISplitCriterion)
|
||||
public
|
||||
/// Вычисляет Gini impurity для текущего набора y.
|
||||
function Impurity(y: Vector): real;
|
||||
end;
|
||||
|
||||
/// Критерий дисперсии.
|
||||
/// Используется в регрессии.
|
||||
/// Минимизирует внутригрупповую дисперсию значений целевой переменной.
|
||||
VarianceCriterion = class(ISplitCriterion)
|
||||
public
|
||||
/// Вычисляет дисперсию значений y.
|
||||
/// Чем меньше дисперсия — тем лучше узел.
|
||||
function Impurity(y: Vector): real;
|
||||
end;
|
||||
|
||||
//============================
|
||||
// DecisionTreeBase
|
||||
//============================
|
||||
/// Базовый абстрактный класс дерева решений.
|
||||
/// Реализует общую логику построения структуры дерева:
|
||||
/// рекурсивное разбиение, контроль глубины,
|
||||
/// минимального числа объектов и расчет важности признаков.
|
||||
/// Конкретная логика вычисления значения листа
|
||||
/// и критерия разбиения задается в наследниках.
|
||||
DecisionTreeBase = abstract class(ITreeModel)
|
||||
protected
|
||||
fRoot: DecisionTreeNode;
|
||||
|
|
@ -296,20 +329,45 @@ type
|
|||
|
||||
procedure SetRowIndices(rows: array of integer);
|
||||
public
|
||||
/// Создает дерево решений.
|
||||
/// maxDepth — максимальная глубина дерева.
|
||||
/// minSamplesSplit — минимальное число объектов для разбиения узла.
|
||||
/// minSamplesLeaf — минимальное число объектов в листе.
|
||||
constructor Create(maxDepth: integer := 10; minSamplesSplit: integer := 2; minSamplesLeaf: integer := 1);
|
||||
|
||||
/// Возвращает вектор важности признаков.
|
||||
/// Важность вычисляется как суммарное уменьшение
|
||||
/// нечистоты (impurity reduction) по всем разбиениям.
|
||||
/// Значения нормированы так, что сумма равна 1.
|
||||
function FeatureImportances: Vector;
|
||||
|
||||
/// Обучает дерево решений.
|
||||
/// X — матрица признаков.
|
||||
/// y — целевая переменная.
|
||||
/// Реализация зависит от типа дерева (регрессия или классификация).
|
||||
function Fit(X: Matrix; y: Vector): IModel; virtual; abstract;
|
||||
|
||||
/// Выполняет предсказание для матрицы X.
|
||||
/// Возвращает вектор прогнозов.
|
||||
/// Для регрессии — вещественные значения.
|
||||
/// Для классификации — метки классов.
|
||||
function Predict(X: Matrix): Vector; virtual; abstract;
|
||||
|
||||
/// Создает глубокую копию дерева.
|
||||
/// Копируется структура узлов, параметры и обученное состояние.
|
||||
function Clone: IModel; virtual; abstract;
|
||||
|
||||
/// Возвращает true, если дерево обучено.
|
||||
/// Если false — Predict вызовет ошибку.
|
||||
function IsFitted: boolean;
|
||||
end;
|
||||
|
||||
//============================
|
||||
// DecisionTreeClassifier
|
||||
//============================
|
||||
/// Дерево решений для задачи классификации.
|
||||
/// Использует критерий нечистоты (обычно Gini) для выбора оптимальных разбиений.
|
||||
/// В листьях хранится наиболее частый класс.
|
||||
DecisionTreeClassifier = class(DecisionTreeBase, IClassifier)
|
||||
private
|
||||
fClassToIndex: Dictionary<integer, integer>;
|
||||
|
|
@ -328,16 +386,38 @@ type
|
|||
end;
|
||||
|
||||
public
|
||||
/// Создает классификационное дерево.
|
||||
/// maxDepth — максимальная глубина дерева.
|
||||
/// minSamplesSplit — минимальное число объектов для разбиения узла.
|
||||
/// minSamplesLeaf — минимальное число объектов в листе.
|
||||
constructor Create(maxDepth: integer := 10; minSamplesSplit: integer := 2; minSamplesLeaf: integer := 1);
|
||||
|
||||
/// Обучает классификационное дерево.
|
||||
/// X — матрица признаков.
|
||||
/// y — вектор целевых меток (целые значения).
|
||||
/// Строит структуру дерева путем минимизации нечистоты в узлах.
|
||||
function Fit(X: Matrix; y: Vector): IModel; override;
|
||||
|
||||
/// Выполняет предсказание меток классов для X.
|
||||
/// Для каждого объекта возвращается класс, соответствующий листу дерева.
|
||||
function Predict(X: Matrix): Vector; override;
|
||||
|
||||
/// Создает глубокую копию дерева классификации.
|
||||
/// Копируется структура узлов, параметры и обученное состояние.
|
||||
function Clone: IModel; override;
|
||||
|
||||
/// Возвращает строковое представление модели.
|
||||
function ToString: string; override;
|
||||
end;
|
||||
|
||||
//============================
|
||||
// DecisionTreeRegressor
|
||||
//============================
|
||||
/// Дерево решений для задачи регрессии.
|
||||
/// Наследуется от DecisionTreeBase.
|
||||
/// Использует критерий дисперсии для выбора разбиений.
|
||||
/// В листьях хранится среднее значение целевой переменной.
|
||||
/// Поддерживает L2-регуляризацию значения листа (leafL2).
|
||||
DecisionTreeRegressor = class(DecisionTreeBase, IRegressor)
|
||||
private
|
||||
fLeafL2: real;
|
||||
|
|
@ -345,28 +425,60 @@ type
|
|||
function PredictOne(x: Vector): real;
|
||||
|
||||
protected
|
||||
/// Вычисляет значение листа для набора индексов.
|
||||
/// В регрессии это среднее целевой переменной
|
||||
/// с учетом L2-регуляризации (если leafL2 > 0).
|
||||
function LeafValue(y: Vector; indices: array of integer): real; override;
|
||||
|
||||
/// Ищет лучшее разбиение узла по всем признакам и возможным порогам.
|
||||
/// Критерий — максимальное уменьшение дисперсии.
|
||||
function FindBestSplit(X: Matrix; y: Vector; indices: array of integer): SplitResult; override;
|
||||
/// Проверяет, является ли узел "чистым".
|
||||
/// Для регрессии это означает, что все значения y одинаковы
|
||||
/// или разбиение больше не имеет смысла.
|
||||
function IsPure(y: Vector; indices: array of integer): boolean; override;
|
||||
|
||||
public
|
||||
/// Создает регрессионное дерево.
|
||||
/// maxDepth — максимальная глубина.
|
||||
/// minSamplesSplit — минимальное число объектов для разбиения.
|
||||
/// minSamplesLeaf — минимальное число объектов в листе.
|
||||
/// leafL2 — коэффициент L2-регуляризации значения листа.
|
||||
constructor Create(maxDepth: integer := 10; minSamplesSplit: integer := 2; minSamplesLeaf: integer := 1;
|
||||
leafL2: real := 0.0);
|
||||
|
||||
/// Обучает регрессионное дерево.
|
||||
/// X — матрица признаков.
|
||||
/// y — вещественная целевая переменная.
|
||||
function Fit(X: Matrix; y: Vector): IModel; override;
|
||||
|
||||
/// Выполняет предсказание для всех объектов X.
|
||||
/// Возвращает вектор вещественных значений.
|
||||
function Predict(X: Matrix): Vector; override;
|
||||
|
||||
/// Создает глубокую копию дерева регрессии.
|
||||
/// Копируется структура узлов, параметры и обученное состояние.
|
||||
function Clone: IModel; override;
|
||||
|
||||
/// Возвращает строковое представление модели.
|
||||
function ToString: string; override;
|
||||
end;
|
||||
|
||||
|
||||
/// Режим выбора числа признаков при поиске разбиения.
|
||||
/// Определяет, сколько признаков m из общего числа p
|
||||
/// будет случайно выбрано для рассмотрения в узле.
|
||||
/// Используется в Random Forest и других ансамблях
|
||||
/// для увеличения разнообразия деревьев.
|
||||
TMaxFeaturesMode = (
|
||||
/// m = p
|
||||
/// Использовать все признаки: m = p
|
||||
AllFeatures,
|
||||
/// m = sqrt(p)
|
||||
SqrtFeatures,
|
||||
/// m = log2(p)
|
||||
/// Использовать квадратный корень от числа признаков: m = sqrt(p)
|
||||
/// Типичный выбор для классификации.
|
||||
SqrtFeatures,
|
||||
/// Использовать log2 от числа признаков: m = log2(p)
|
||||
/// Более агрессивное ограничение признаков.
|
||||
Log2Features,
|
||||
/// m = p/2
|
||||
/// Использовать половину признаков: m = p / 2
|
||||
/// Компромисс между скоростью и разнообразием.
|
||||
HalfFeatures
|
||||
);
|
||||
|
||||
|
|
@ -378,6 +490,12 @@ type
|
|||
// feature-subset = в каждом дереве - случайные признаки
|
||||
// RandomForest снижает корреляцию между деревьями, что хорошо
|
||||
|
||||
/// Базовый абстрактный класс случайного леса.
|
||||
/// Реализует ансамбль из множества независимых деревьев,
|
||||
/// обученных на случайных подвыборках данных
|
||||
/// и случайных подмножествах признаков.
|
||||
/// Конкретная логика агрегирования предсказаний
|
||||
/// определяется в наследниках (регрессия или классификация).
|
||||
RandomForestBase = abstract class(IModel)
|
||||
protected
|
||||
fNTrees: integer;
|
||||
|
|
@ -390,56 +508,125 @@ type
|
|||
function ComputeMaxFeatures(p: integer): integer;
|
||||
procedure BootstrapSample(X: Matrix; y: Vector; var Xb: Matrix; var yb: Vector);
|
||||
public
|
||||
/// Создает случайный лес.
|
||||
/// nTrees — число деревьев в ансамбле.
|
||||
/// maxDepth — максимальная глубина каждого дерева.
|
||||
/// minSamplesSplit — минимальное число объектов для разбиения узла.
|
||||
/// minSamplesLeaf — минимальное число объектов в листе.
|
||||
/// maxFeatures — режим выбора числа признаков, рассматриваемых при поиске разбиения.
|
||||
constructor Create(
|
||||
nTrees: integer;
|
||||
maxDepth: integer;
|
||||
minSamplesSplit: integer;
|
||||
minSamplesLeaf: integer;
|
||||
maxFeatures: TMaxFeaturesMode);
|
||||
|
||||
|
||||
/// Обучает ансамбль деревьев на данных X и y.
|
||||
/// Для каждого дерева используется bootstrap-подвыборка
|
||||
/// и случайное подмножество признаков.
|
||||
function Fit(X: Matrix; y: Vector): IModel; virtual; abstract;
|
||||
|
||||
/// Выполняет предсказание для матрицы X.
|
||||
/// В регрессии — усреднение предсказаний деревьев.
|
||||
/// В классификации — голосование (majority vote) или усреднение вероятностей.
|
||||
function Predict(X: Matrix): Vector; virtual; abstract;
|
||||
|
||||
/// Создает глубокую копию случайного леса.
|
||||
/// Копируются все деревья и параметры ансамбля.
|
||||
function Clone: IModel; virtual; abstract;
|
||||
|
||||
/// Возвращает вектор важности признаков.
|
||||
/// Обычно вычисляется как средняя важность по всем деревьям ансамбля.
|
||||
function FeatureImportances: Vector; virtual; abstract;
|
||||
end;
|
||||
|
||||
/// Случайный лес для задачи регрессии.
|
||||
/// Строит ансамбль регрессионных деревьев,
|
||||
/// обученных на bootstrap-подвыборках данных и случайных подмножествах признаков.
|
||||
/// Итоговое предсказание — среднее значение по всем деревьям ансамбля.
|
||||
RandomForestRegressor = class(RandomForestBase, IModel)
|
||||
private
|
||||
fTrees: array of DecisionTreeRegressor;
|
||||
public
|
||||
/// Создает регрессионный случайный лес.
|
||||
/// nTrees — число деревьев в ансамбле.
|
||||
/// maxDepth — максимальная глубина деревьев.
|
||||
/// minSamplesSplit — минимальное число объектов для разбиения узла.
|
||||
/// minSamplesLeaf — минимальное число объектов в листе.
|
||||
/// maxFeaturesMode — режим выбора числа признаков, рассматриваемых при поиске разбиения.
|
||||
constructor Create(nTrees: integer := 100;
|
||||
maxDepth: integer := integer.MaxValue;
|
||||
minSamplesSplit: integer := 2;
|
||||
minSamplesLeaf: integer := 1;
|
||||
maxFeaturesMode: TMaxFeaturesMode := TMaxFeaturesMode.HalfFeatures);
|
||||
|
||||
/// Обучает случайный лес на данных X и y.
|
||||
/// Для каждого дерева используется bootstrap-выборка.
|
||||
/// Возвращает обученную модель.
|
||||
function Fit(X: Matrix; y: Vector): IModel; override;
|
||||
|
||||
/// Выполняет предсказание для X.
|
||||
/// Итоговое значение — среднее предсказаний всех деревьев ансамбля.
|
||||
function Predict(X: Matrix): Vector; override;
|
||||
|
||||
/// Создает глубокую копию случайного леса.
|
||||
/// Копируются все деревья и параметры модели.
|
||||
function Clone: IModel; override;
|
||||
|
||||
/// Возвращает усредненную важность признаков по всем деревьям ансамбля.
|
||||
/// Значения нормированы так, что сумма равна 1.
|
||||
function FeatureImportances: Vector; override;
|
||||
|
||||
/// Возвращает строковое представление модели.
|
||||
function ToString: string; override;
|
||||
end;
|
||||
|
||||
/// Случайный лес для задачи классификации.
|
||||
/// Наследуется от RandomForestBase и реализует интерфейс IClassifier.
|
||||
/// Строит ансамбль классификационных деревьев, обученных на bootstrap-подвыборках
|
||||
/// объектов и случайных подмножествах признаков.
|
||||
/// Итоговое предсказание формируется голосованием деревьев или агрегацией вероятностей классов.
|
||||
RandomForestClassifier = class(RandomForestBase, IClassifier)
|
||||
private
|
||||
fTrees: array of DecisionTreeClassifier;
|
||||
public
|
||||
/// Создает классификационный случайный лес.
|
||||
/// nTrees — число деревьев в ансамбле.
|
||||
/// maxDepth — максимальная глубина каждого дерева.
|
||||
/// minSamplesSplit — минимальное число объектов для разбиения узла.
|
||||
/// minSamplesLeaf — минимальное число объектов в листе.
|
||||
/// maxFeaturesMode — режим выбора числа признаков при поиске разбиения, по умолчанию используется sqrt(p),
|
||||
/// что является стандартом для классификации.
|
||||
constructor Create(nTrees: integer := 100;
|
||||
maxDepth: integer := integer.MaxValue;
|
||||
minSamplesSplit: integer := 2;
|
||||
minSamplesLeaf: integer := 1;
|
||||
maxFeaturesMode: TMaxFeaturesMode := TMaxFeaturesMode.SqrtFeatures);
|
||||
|
||||
/// Обучает случайный лес на данных X и y.
|
||||
/// Для каждого дерева используется bootstrap-выборка обучающих объектов.
|
||||
/// В каждом узле рассматривается случайное подмножество признаков согласно maxFeaturesMode.
|
||||
/// Возвращает обученную модель.
|
||||
function Fit(X: Matrix; y: Vector): IModel; override;
|
||||
|
||||
/// Выполняет предсказание меток классов для матрицы X.
|
||||
/// Для каждого объекта агрегируются предсказания всех деревьев.
|
||||
/// Итоговый класс определяется большинством голосов или максимальной суммарной вероятностью.
|
||||
function Predict(X: Matrix): Vector; override;
|
||||
|
||||
/// Создает глубокую копию случайного леса классификации.
|
||||
/// Копируются все деревья, параметры ансамбля и обученное состояние модели.
|
||||
function Clone: IModel; override;
|
||||
|
||||
/// Возвращает усредненную важность признаков по всем деревьям ансамбля.
|
||||
/// Важность рассчитывается как суммарное уменьшение нечистоты, нормированное так, что сумма равна 1.
|
||||
function FeatureImportances: Vector; override;
|
||||
|
||||
/// Возвращает строковое представление модели.
|
||||
function ToString: string; override;
|
||||
end;
|
||||
|
||||
|
||||
{ Gradient Boosting v1.0 — Freeze Checklist
|
||||
|
||||
GradientBoostingRegressor
|
||||
✔ SquaredError
|
||||
✔ Huber
|
||||
|
|
@ -465,9 +652,19 @@ type
|
|||
✔ Feature importance
|
||||
✔ Clone
|
||||
}
|
||||
|
||||
|
||||
/// Тип функции потерь для GradientBoostingRegressor.
|
||||
/// SquaredError — классическая L2 (MSE).
|
||||
/// Huber — робастная loss: квадратичная около нуля и линейная на хвостах.
|
||||
/// Quantile — квантильная регрессия (асимметричная L1).
|
||||
TGBLoss = (SquaredError, Huber, Quantile);
|
||||
|
||||
/// Gradient Boosting Regressor.
|
||||
/// Реализует градиентный бустинг над деревьями решений.
|
||||
/// Каждая новая модель обучается на псевдо-остатках предыдущей.
|
||||
/// Поддерживает разные loss-функции, subsample (stochastic boosting),
|
||||
/// early stopping (validation или OOB),
|
||||
/// L2-регуляризацию в листьях и staged prediction.
|
||||
GradientBoostingRegressor = class(IRegressor)
|
||||
private
|
||||
fNEstimators: integer;
|
||||
|
|
@ -515,6 +712,20 @@ type
|
|||
function ComputeTrainLossMasked(yTrue, yPred: Vector; mask: array of boolean): real;
|
||||
|
||||
public
|
||||
/// Создает новый GradientBoostingRegressor.
|
||||
/// nEstimators — число деревьев (итераций бустинга).
|
||||
/// learningRate — коэффициент shrinkage.
|
||||
/// maxDepth — максимальная глубина дерева.
|
||||
/// minSamplesSplit — минимальное число объектов для split.
|
||||
/// minSamplesLeaf — минимальное число объектов в листе.
|
||||
/// subsample — доля выборки на каждой итерации (0..1].
|
||||
/// randomSeed — зерно генератора случайных чисел.
|
||||
/// loss — функция потерь.
|
||||
/// huberDelta — параметр Huber loss.
|
||||
/// earlyStoppingPatience — число итераций без улучшения до остановки.
|
||||
/// quantileAlpha — уровень квантили для Quantile loss.
|
||||
/// leafL2 — L2-регуляризация значения листа.
|
||||
/// useOOBEarlyStopping — использовать OOB loss для ранней остановки.
|
||||
constructor Create(
|
||||
nEstimators: integer := 100;
|
||||
learningRate: real := 0.1;
|
||||
|
|
@ -531,28 +742,65 @@ type
|
|||
useOOBEarlyStopping: boolean := false
|
||||
);
|
||||
|
||||
/// Обучает модель на всей обучающей выборке.
|
||||
/// Если включен early stopping и subsample < 1,
|
||||
/// может использоваться OOB loss.
|
||||
/// Возвращает обученную модель.
|
||||
function Fit(X: Matrix; y: Vector): IModel;
|
||||
/// Предсказывает значения целевой переменной.
|
||||
/// Используются все обученные деревья.
|
||||
function Predict(X: Matrix): Vector;
|
||||
/// Создает глубокую копию модели.
|
||||
/// Копируются все деревья и внутреннее состояние.
|
||||
function Clone: IModel;
|
||||
|
||||
/// Обучает модель с использованием отдельной validation-выборки.
|
||||
/// Early stopping (если включен) происходит по validation loss.
|
||||
function FitWithValidation(XTrain: Matrix; yTrain: Vector;
|
||||
XVal: Matrix; yVal: Vector): IModel;
|
||||
|
||||
|
||||
/// История значения функции потерь на обучающей выборке.
|
||||
/// Один элемент на итерацию бустинга.
|
||||
property TrainLossHistory: List<real> read fTrainLossHistory;
|
||||
/// История значения функции потерь на validation-выборке.
|
||||
property ValLossHistory: List<real> read fValLossHistory;
|
||||
/// Индекс итерации с лучшим значением функции потерь
|
||||
/// (validation или OOB в зависимости от режима).
|
||||
property BestIteration: integer read fBestIteration;
|
||||
/// История OOB loss (если включен OOB early stopping).
|
||||
property OOBLossHistory: List<real> read fOOBLossHistory;
|
||||
|
||||
/// Предсказание по первым m итерациям бустинга.
|
||||
/// m может быть от 0 до TreeCount.
|
||||
/// Используется для анализа обучения и переобучения.
|
||||
function PredictStage(X: Matrix; m: integer): Vector;
|
||||
/// Возвращает последовательность предсказаний
|
||||
/// после каждой итерации бустинга.
|
||||
/// Удобно для построения learning curve.
|
||||
function StagedPredict(X: Matrix): sequence of Vector;
|
||||
|
||||
/// Возвращает текущее количество деревьев в ансамбле.
|
||||
function TreeCount: integer := fEstimators.Count;
|
||||
|
||||
|
||||
/// Возвращает нормированные importance признаков.
|
||||
/// Значения суммируются по всем деревьям и нормируются к 1.
|
||||
function FeatureImportances: Vector;
|
||||
|
||||
/// Возвращает строковое представление модели.
|
||||
function ToString: string; override;
|
||||
end;
|
||||
|
||||
/// Тип функции потерь для классификатора.
|
||||
/// В текущей версии используется только LogLoss
|
||||
/// (многоклассовая кросс-энтропия).
|
||||
TGBCLoss = (LogLoss);
|
||||
|
||||
/// Gradient Boosting Classifier.
|
||||
/// Реализует многоклассовый градиентный бустинг с использованием softmax и LogLoss.
|
||||
/// На каждой итерации обучается по одному дереву
|
||||
/// для каждого класса (one-vs-all в логит-пространстве).
|
||||
/// Поддерживает subsample, validation early stopping,
|
||||
/// OOB early stopping и staged prediction.
|
||||
GradientBoostingClassifier = class(IProbabilisticClassifier)
|
||||
private
|
||||
// hyperparams
|
||||
|
|
@ -604,6 +852,15 @@ type
|
|||
mask: array of boolean): real;
|
||||
|
||||
public
|
||||
/// Создает новый GradientBoostingClassifier.
|
||||
/// nEstimators — число итераций бустинга.
|
||||
/// learningRate — коэффициент shrinkage.
|
||||
/// maxDepth — максимальная глубина деревьев.
|
||||
/// minSamplesSplit — минимальное число объектов для split.
|
||||
/// minSamplesLeaf — минимальное число объектов в листе.
|
||||
/// subsample — доля обучающей выборки на каждой итерации.
|
||||
/// randomSeed — зерно генератора случайных чисел.
|
||||
/// earlyStoppingPatience — число итераций без улучшения до ранней остановки.
|
||||
constructor Create(
|
||||
nEstimators: integer := 200;
|
||||
learningRate: real := 0.05;
|
||||
|
|
@ -614,25 +871,58 @@ type
|
|||
randomSeed: integer := 42;
|
||||
earlyStoppingPatience: integer := 20);
|
||||
|
||||
/// Обучает классификатор на всей обучающей выборке.
|
||||
/// Если включен early stopping и subsample < 1,
|
||||
/// может использоваться OOB loss.
|
||||
/// Возвращает обученную модель.
|
||||
function Fit(X: Matrix; y: Vector): IModel;
|
||||
|
||||
/// Обучает классификатор с использованием validation-набора.
|
||||
/// Если включен early stopping, он основан на validation loss.
|
||||
function FitWithValidation(XTrain: Matrix; yTrain: Vector; XVal: Matrix; yVal: Vector): IModel;
|
||||
|
||||
/// Предсказывает метки классов.
|
||||
/// Возвращает исходные значения классов, а не внутренние индексы.
|
||||
function Predict(X: Matrix): Vector;
|
||||
|
||||
/// Возвращает вероятности принадлежности к каждому классу.
|
||||
/// Размер результата: [nSamples x nClasses].
|
||||
/// Вероятности получаются через softmax.
|
||||
function PredictProba(X: Matrix): Matrix;
|
||||
|
||||
/// Создает глубокую копию классификатора.
|
||||
/// Копируются все деревья и внутреннее состояние.
|
||||
function Clone: IModel;
|
||||
|
||||
/// История значения LogLoss на обучающей выборке.
|
||||
/// Один элемент на итерацию бустинга.
|
||||
property TrainLossHistory: List<real> read fTrainLossHistory;
|
||||
/// История LogLoss на validation-наборе.
|
||||
property ValLossHistory: List<real> read fValLossHistory;
|
||||
/// Индекс итерации с лучшим значением функции потерь (validation или OOB).
|
||||
property BestIteration: integer read fBestIteration;
|
||||
/// История OOB LogLoss (если включен OOB early stopping).
|
||||
property OOBLossHistory: List<real> read fOOBLossHistory;
|
||||
|
||||
/// Возвращает вероятности после первых m итераций бустинга.
|
||||
/// m может быть от 0 до TreeCount.
|
||||
/// Используется для анализа обучения.
|
||||
function PredictStageProba(X: Matrix; m: integer): Matrix;
|
||||
|
||||
/// Предсказывает классы по первым m итерациям бустинга.
|
||||
/// Удобно для построения learning curve.
|
||||
function PredictStage(X: Matrix; m: integer): Vector;
|
||||
|
||||
/// Текущее количество деревьев в ансамбле.
|
||||
function TreeCount: integer := fEstimators.Count;
|
||||
|
||||
/// Нормированные importance признаков.
|
||||
/// Рассчитываются как суммарное уменьшение impurity
|
||||
/// по всем деревьям и нормируются к 1.
|
||||
function FeatureImportances: Vector;
|
||||
|
||||
/// Возвращает строковое представление модели.
|
||||
function ToString: string; override;
|
||||
end;
|
||||
|
||||
{$endregion Models}
|
||||
|
|
@ -905,7 +1195,11 @@ type
|
|||
/// Показывает, был ли выполнен Fit.
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
/// Возвращает строковое представление трансформера
|
||||
function ToString: string; override;
|
||||
|
||||
/// Создает глубокую копию.
|
||||
/// Копируются параметры и внутреннее состояние.
|
||||
function Clone: ITransformer;
|
||||
end;
|
||||
|
||||
|
|
@ -923,14 +1217,29 @@ type
|
|||
fNormType: NormType;
|
||||
fFitted: boolean;
|
||||
public
|
||||
/// Создает нормализатор.
|
||||
/// norm — тип нормы, используемой для масштабирования строки признаков.
|
||||
/// По умолчанию используется L2-норма.
|
||||
constructor Create(norm: NormType := NormType.L2);
|
||||
|
||||
/// Подготавливает трансформер к работе.
|
||||
/// Для Normalizer этап обучения может быть формальным, так как параметры не накапливаются.
|
||||
function Fit(X: Matrix): ITransformer;
|
||||
|
||||
/// Применяет нормализацию к матрице X.
|
||||
/// Каждая строка масштабируется так, чтобы ее норма соответствовала выбранному типу.
|
||||
/// Возвращает новую матрицу с нормализованными объектами.
|
||||
function Transform(X: Matrix): Matrix;
|
||||
|
||||
/// Показывает, был ли вызван метод Fit.
|
||||
/// Если False, вызов Transform может привести к ошибке.
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
/// Возвращает строковое представление трансформера
|
||||
function ToString: string; override;
|
||||
|
||||
/// Создает глубокую копию нормализатора.
|
||||
/// Копируются параметры и внутреннее состояние.
|
||||
function Clone: ITransformer;
|
||||
end;
|
||||
|
||||
|
|
@ -1678,6 +1987,14 @@ begin
|
|||
dest.fMinSamplesSplit := fMinSamplesSplit;
|
||||
dest.fMinSamplesLeaf := fMinSamplesLeaf;
|
||||
dest.fFitted := fFitted;
|
||||
dest.fRandomSeed := fRandomSeed;
|
||||
dest.fMaxFeatures := fMaxFeatures;
|
||||
|
||||
if fCriterion <> nil then
|
||||
dest.fCriterion := fCriterion; // можно так, если критерий stateless
|
||||
|
||||
if fFeatureImportances <> nil then
|
||||
dest.fFeatureImportances := fFeatureImportances.Clone;
|
||||
|
||||
if fRoot <> nil then
|
||||
dest.fRoot := fRoot.Clone;
|
||||
|
|
@ -2231,6 +2548,16 @@ begin
|
|||
Result := MajorityClass(y, indices);
|
||||
end;
|
||||
|
||||
function DecisionTreeClassifier.ToString: string;
|
||||
begin
|
||||
Result :=
|
||||
$'DecisionTreeClassifier(' +
|
||||
$'maxDepth={fMaxDepth}, ' +
|
||||
$'minSamplesSplit={fMinSamplesSplit}, ' +
|
||||
$'minSamplesLeaf={fMinSamplesLeaf}' +
|
||||
')';
|
||||
end;
|
||||
|
||||
// DecisionTreeRegressor
|
||||
|
||||
constructor DecisionTreeRegressor.Create(maxDepth: integer; minSamplesSplit: integer;
|
||||
|
|
@ -2340,7 +2667,8 @@ begin
|
|||
var m := new DecisionTreeRegressor(
|
||||
fMaxDepth,
|
||||
fMinSamplesSplit,
|
||||
fMinSamplesLeaf
|
||||
fMinSamplesLeaf,
|
||||
fLeafL2
|
||||
);
|
||||
|
||||
CopyBaseState(m);
|
||||
|
|
@ -2348,6 +2676,21 @@ begin
|
|||
Result := m;
|
||||
end;
|
||||
|
||||
function DecisionTreeRegressor.ToString: string;
|
||||
begin
|
||||
var s :=
|
||||
$'DecisionTreeRegressor(maxDepth={fMaxDepth}, ' +
|
||||
$'minSamplesSplit={fMinSamplesSplit}, ' +
|
||||
$'minSamplesLeaf={fMinSamplesLeaf}';
|
||||
|
||||
if fLeafL2 <> 0.0 then
|
||||
s += $', leafL2={fLeafL2}';
|
||||
|
||||
s += ')';
|
||||
|
||||
Result := s;
|
||||
end;
|
||||
|
||||
|
||||
//-----------------------------
|
||||
// RandomForestBase
|
||||
|
|
@ -2499,9 +2842,26 @@ begin
|
|||
Result := resultVec;
|
||||
end;
|
||||
|
||||
function RandomForestRegressor.ToString: string;
|
||||
begin
|
||||
var depthStr :=
|
||||
if fMaxDepth = integer.MaxValue then '∞'
|
||||
else fMaxDepth.ToString;
|
||||
|
||||
Result :=
|
||||
$'RandomForestRegressor(' +
|
||||
$'nTrees={fNTrees}, ' +
|
||||
$'maxDepth={depthStr}, ' +
|
||||
$'minSamplesSplit={fMinSamplesSplit}, ' +
|
||||
$'minSamplesLeaf={fMinSamplesLeaf}, ' +
|
||||
$'maxFeatures={fMaxFeaturesMode}' +
|
||||
')';
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
// RandomForestClassifier
|
||||
//-----------------------------
|
||||
|
||||
constructor RandomForestClassifier.Create(nTrees: integer;
|
||||
maxDepth: integer; minSamplesSplit: integer; minSamplesLeaf: integer;
|
||||
maxFeaturesMode: TMaxFeaturesMode);
|
||||
|
|
@ -2626,6 +2986,22 @@ begin
|
|||
Result := resultVec;
|
||||
end;
|
||||
|
||||
function RandomForestClassifier.ToString: string;
|
||||
begin
|
||||
var depthStr :=
|
||||
if fMaxDepth = integer.MaxValue then '∞'
|
||||
else fMaxDepth.ToString;
|
||||
|
||||
Result :=
|
||||
$'RandomForestClassifier(' +
|
||||
$'nTrees={fNTrees}, ' +
|
||||
$'maxDepth={depthStr}, ' +
|
||||
$'minSamplesSplit={fMinSamplesSplit}, ' +
|
||||
$'minSamplesLeaf={fMinSamplesLeaf}, ' +
|
||||
$'maxFeatures={fMaxFeaturesMode}' +
|
||||
')';
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
// GradientBoostingRegressor
|
||||
//-----------------------------
|
||||
|
|
@ -3185,63 +3561,57 @@ begin
|
|||
Result := fFeatureImportances;
|
||||
end;
|
||||
|
||||
function GradientBoostingRegressor.ToString: string;
|
||||
begin
|
||||
var s :=
|
||||
$'GradientBoostingRegressor(' +
|
||||
$'n={fNEstimators}, ' +
|
||||
$'lr={fLearningRate}, ' +
|
||||
$'maxDepth={fMaxDepth}, ' +
|
||||
$'loss={fLoss}';
|
||||
|
||||
if fSubsample <> 1.0 then
|
||||
s += $', subs={fSubsample}';
|
||||
|
||||
if fEarlyStoppingPatience > 0 then
|
||||
s += $', earlyStop={fEarlyStoppingPatience}';
|
||||
|
||||
if fLoss = TGBLoss.Huber then
|
||||
s += $', delta={fHuberDelta}';
|
||||
|
||||
if fLoss = TGBLoss.Quantile then
|
||||
s += $', alpha={fQuantileAlpha}';
|
||||
|
||||
if fLeafL2 <> 0.0 then
|
||||
s += $', leafL2={fLeafL2}';
|
||||
|
||||
if fUseOOBEarlyStopping then
|
||||
s += ', OOB=true';
|
||||
|
||||
s += ')';
|
||||
|
||||
Result := s;
|
||||
end;
|
||||
|
||||
function GradientBoostingRegressor.Clone: IModel;
|
||||
begin
|
||||
var c := new GradientBoostingRegressor(
|
||||
var copy := new GradientBoostingRegressor(
|
||||
fNEstimators,
|
||||
fLearningRate,
|
||||
fMaxDepth,
|
||||
fMinSamplesSplit,
|
||||
fMinSamplesLeaf,
|
||||
fSubsample,
|
||||
fRandomSeed,
|
||||
fLoss,
|
||||
fHuberDelta,
|
||||
fEarlyStoppingPatience,
|
||||
fQuantileAlpha,
|
||||
fLeafL2,
|
||||
fUseOOBEarlyStopping
|
||||
);
|
||||
fRandomSeed);
|
||||
|
||||
// --- fitted state
|
||||
c.fFitted := fFitted;
|
||||
c.fFeatureCount := fFeatureCount;
|
||||
c.fInitValue := fInitValue;
|
||||
copy.fInitValue := fInitValue;
|
||||
copy.fFeatureCount := fFeatureCount;
|
||||
copy.fFitted := fFitted;
|
||||
|
||||
// --- best/iters
|
||||
c.fBestIteration := fBestIteration;
|
||||
c.fBestTrainLoss := fBestTrainLoss;
|
||||
c.fBestValLoss := fBestValLoss;
|
||||
foreach var tree in fEstimators do
|
||||
copy.fEstimators.Add(tree.Clone as DecisionTreeRegressor);
|
||||
|
||||
// --- estimators (deep)
|
||||
c.fEstimators.Clear;
|
||||
foreach var t in fEstimators do
|
||||
c.fEstimators.Add(DecisionTreeRegressor(t.Clone));
|
||||
|
||||
// --- histories (deep copy values)
|
||||
c.fTrainLossHistory.Clear;
|
||||
foreach var v in fTrainLossHistory do
|
||||
c.fTrainLossHistory.Add(v);
|
||||
|
||||
c.fValLossHistory.Clear;
|
||||
foreach var v in fValLossHistory do
|
||||
c.fValLossHistory.Add(v);
|
||||
|
||||
c.fOOBLossHistory.Clear;
|
||||
foreach var v in fOOBLossHistory do
|
||||
c.fOOBLossHistory.Add(v);
|
||||
|
||||
// --- feature importances (deep)
|
||||
if fFeatureImportances <> nil then
|
||||
begin
|
||||
c.fFeatureImportances := new Vector(fFeatureImportances.Length);
|
||||
for var i := 0 to fFeatureImportances.Length - 1 do
|
||||
c.fFeatureImportances[i] := fFeatureImportances[i];
|
||||
end
|
||||
else
|
||||
c.fFeatureImportances := nil;
|
||||
|
||||
Result := c;
|
||||
Result := copy;
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
|
|
@ -3880,9 +4250,28 @@ begin
|
|||
Result := fFeatureImportances;
|
||||
end;
|
||||
|
||||
function GradientBoostingClassifier.ToString: string;
|
||||
begin
|
||||
var s :=
|
||||
$'GradientBoostingClassifier(' +
|
||||
$'n={fNEstimators}, ' +
|
||||
$'lr={fLearningRate}, ' +
|
||||
$'maxDepth={fMaxDepth}';
|
||||
|
||||
if fSubsample <> 1.0 then
|
||||
s += $', subs={fSubsample}';
|
||||
|
||||
if fEarlyStoppingPatience > 0 then
|
||||
s += $', earlyStop={fEarlyStoppingPatience}';
|
||||
|
||||
s += ')';
|
||||
|
||||
Result := s;
|
||||
end;
|
||||
|
||||
function GradientBoostingClassifier.Clone: IModel;
|
||||
begin
|
||||
var c := new GradientBoostingClassifier(
|
||||
var model := new GradientBoostingClassifier(
|
||||
fNEstimators,
|
||||
fLearningRate,
|
||||
fMaxDepth,
|
||||
|
|
@ -3894,77 +4283,47 @@ begin
|
|||
);
|
||||
|
||||
// --- fitted state
|
||||
c.fFitted := fFitted;
|
||||
c.fFeatureCount := fFeatureCount;
|
||||
|
||||
// --- class mapping (deep)
|
||||
c.fClassCount := fClassCount;
|
||||
model.fFitted := fFitted;
|
||||
model.fFeatureCount := fFeatureCount;
|
||||
model.fClassCount := fClassCount;
|
||||
|
||||
// --- classes
|
||||
if fClasses <> nil then
|
||||
begin
|
||||
SetLength(c.fClasses, Length(fClasses));
|
||||
SetLength(model.fClasses, Length(fClasses));
|
||||
for var i := 0 to Length(fClasses) - 1 do
|
||||
c.fClasses[i] := fClasses[i];
|
||||
end
|
||||
else
|
||||
c.fClasses := nil;
|
||||
|
||||
c.fClassIndex := new Dictionary<integer, integer>;
|
||||
if fClassIndex <> nil then
|
||||
foreach var kv in fClassIndex do
|
||||
c.fClassIndex[kv.Key] := kv.Value;
|
||||
|
||||
// --- init logits (deep)
|
||||
if fInitLogits <> nil then
|
||||
begin
|
||||
SetLength(c.fInitLogits, Length(fInitLogits));
|
||||
for var i := 0 to Length(fInitLogits) - 1 do
|
||||
c.fInitLogits[i] := fInitLogits[i];
|
||||
end
|
||||
else
|
||||
c.fInitLogits := nil;
|
||||
|
||||
// --- best/iters
|
||||
c.fBestIteration := fBestIteration;
|
||||
c.fBestValLoss := fBestValLoss;
|
||||
|
||||
// --- estimators (deep): List<array of DecisionTreeRegressor>
|
||||
c.fEstimators.Clear;
|
||||
foreach var arr in fEstimators do
|
||||
begin
|
||||
var k := Length(arr);
|
||||
var arr2 := new DecisionTreeRegressor[k];
|
||||
|
||||
for var cls := 0 to k - 1 do
|
||||
arr2[cls] := DecisionTreeRegressor(arr[cls].Clone);
|
||||
|
||||
c.fEstimators.Add(arr2);
|
||||
model.fClasses[i] := fClasses[i];
|
||||
end;
|
||||
|
||||
// --- histories
|
||||
c.fTrainLossHistory.Clear;
|
||||
foreach var v in fTrainLossHistory do
|
||||
c.fTrainLossHistory.Add(v);
|
||||
|
||||
c.fValLossHistory.Clear;
|
||||
foreach var v in fValLossHistory do
|
||||
c.fValLossHistory.Add(v);
|
||||
|
||||
c.fOOBLossHistory.Clear;
|
||||
foreach var v in fOOBLossHistory do
|
||||
c.fOOBLossHistory.Add(v);
|
||||
|
||||
// --- feature importances (deep)
|
||||
if fFeatureImportances <> nil then
|
||||
if fClassIndex <> nil then
|
||||
begin
|
||||
c.fFeatureImportances := new Vector(fFeatureImportances.Length);
|
||||
for var i := 0 to fFeatureImportances.Length - 1 do
|
||||
c.fFeatureImportances[i] := fFeatureImportances[i];
|
||||
end
|
||||
else
|
||||
c.fFeatureImportances := nil;
|
||||
model.fClassIndex := new Dictionary<integer, integer>;
|
||||
foreach var kv in fClassIndex do
|
||||
model.fClassIndex.Add(kv.Key, kv.Value);
|
||||
end;
|
||||
|
||||
Result := c;
|
||||
// --- estimators (deep copy)
|
||||
foreach var trees in fEstimators do
|
||||
begin
|
||||
var newTrees := new DecisionTreeRegressor[Length(trees)];
|
||||
|
||||
for var cls := 0 to Length(trees) - 1 do
|
||||
newTrees[cls] := trees[cls].Clone as DecisionTreeRegressor;
|
||||
|
||||
model.fEstimators.Add(newTrees);
|
||||
end;
|
||||
|
||||
// --- history
|
||||
foreach var v in fTrainLossHistory do
|
||||
model.fTrainLossHistory.Add(v);
|
||||
|
||||
foreach var v in fValLossHistory do
|
||||
model.fValLossHistory.Add(v);
|
||||
|
||||
model.fBestIteration := fBestIteration;
|
||||
model.fBestValLoss := fBestValLoss;
|
||||
|
||||
Result := model;
|
||||
end;
|
||||
|
||||
function GradientBoostingClassifier.Fit(X: Matrix; y: Vector): IModel;
|
||||
|
|
|
|||
Loading…
Reference in a new issue