ML - небольшой рефакторинг
This commit is contained in:
parent
98fe38141b
commit
c99dcd30b8
|
|
@ -29,6 +29,9 @@ type
|
|||
VarianceThreshold = MLModelsABC.VarianceThreshold;
|
||||
SelectKBest = MLModelsABC.SelectKBest;
|
||||
FeatureScore = MLModelsABC.FeatureScore;
|
||||
Normalizer = MLModelsABC.Normalizer;
|
||||
|
||||
NormType = MLModelsABC.NormType;
|
||||
|
||||
Activations = MLModelsABC.Activations;
|
||||
Pipeline = MLModelsABC.Pipeline;
|
||||
|
|
|
|||
|
|
@ -5,10 +5,16 @@ interface
|
|||
uses LinearAlgebraML;
|
||||
|
||||
type
|
||||
/// Базовый интерфейс шага конвейера машинного обучения.
|
||||
/// Используется для объединения преобразователей и моделей
|
||||
/// в единую последовательность выполнения внутри Pipeline.
|
||||
IPipeStep = interface end;
|
||||
|
||||
/// Базовый интерфейс модели машинного обучения
|
||||
IModel = interface
|
||||
IModel = interface(IPipeStep)
|
||||
function Fit(X: Matrix; y: Vector): IModel;
|
||||
function Predict(X: Matrix): Vector;
|
||||
function Clone: IModel;
|
||||
end;
|
||||
|
||||
/// Интерфейс классификатора.
|
||||
|
|
@ -34,11 +40,11 @@ type
|
|||
/// Предназначен для моделей, предсказывающих числовые значения.
|
||||
IRegressor = interface(IModel)
|
||||
end;
|
||||
|
||||
|
||||
/// Базовый интерфейс преобразования признаков.
|
||||
/// Используется для масштабирования, отбора,
|
||||
/// уменьшения размерности и других преобразований данных.
|
||||
ITransformer = interface
|
||||
ITransformer = interface(IPipeStep)
|
||||
/// Обучает преобразование на данных.
|
||||
/// Запоминает необходимые параметры,
|
||||
/// которые будут использоваться при Transform.
|
||||
|
|
@ -46,6 +52,7 @@ type
|
|||
/// Применяет обученное преобразование к данным.
|
||||
/// Возвращает новую матрицу признаков.
|
||||
function Transform(X: Matrix): Matrix;
|
||||
function Clone: ITransformer;
|
||||
end;
|
||||
|
||||
/// Интерфейс преобразования признаков с учётом целевой переменной.
|
||||
|
|
@ -56,7 +63,7 @@ type
|
|||
/// как признаков X, так и целевой переменной y.
|
||||
/// Запоминает необходимые параметры,
|
||||
/// которые будут использоваться при Transform.
|
||||
function Fit(X: Matrix; y: Vector): ISupervisedTransformer;
|
||||
function Fit(X: Matrix; y: Vector): ITransformer;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
|
|
|||
|
|
@ -47,18 +47,17 @@ type
|
|||
|
||||
IModel = MLCoreABC.IModel;
|
||||
|
||||
/// Линейная регрессионная модель
|
||||
/// Линейная регрессионная модель (метод наименьших квадратов).
|
||||
/// Предсказывает числовое значение по линейной комбинации признаков
|
||||
/// Используется в задачах регрессии при отсутствии сильной
|
||||
/// Используется в задачах регрессии при отсутствии выраженной
|
||||
/// мультиколлинеарности и когда число признаков существенно меньше числа объектов.
|
||||
LinearRegression = class(IRegressor)
|
||||
private
|
||||
fCoef: Vector;
|
||||
fIntercept: real;
|
||||
fLambda: real;
|
||||
fFitted: boolean;
|
||||
public
|
||||
constructor Create(lambda: real := 0.0);
|
||||
constructor Create();
|
||||
|
||||
/// Обучает модель на числовых данных
|
||||
/// X — матрица m × n (m объектов, n признаков)
|
||||
|
|
@ -83,6 +82,10 @@ type
|
|||
/// После вызова Fit значение становится true.
|
||||
/// Используется для проверки корректности вызова Predict.
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
function ToString: string; override;
|
||||
|
||||
function Clone: IModel;
|
||||
end;
|
||||
|
||||
/// Логистическая регрессионная модель для бинарной классификации.
|
||||
|
|
@ -137,6 +140,10 @@ type
|
|||
/// Показывает, была ли модель обучена.
|
||||
/// После вызова Fit значение становится true.
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
function ToString: string; override;
|
||||
|
||||
function Clone: IModel;
|
||||
end;
|
||||
|
||||
/// Линейная регрессионная модель с L2-регуляризацией (Ridge).
|
||||
|
|
@ -181,6 +188,10 @@ type
|
|||
/// Показывает, была ли модель обучена.
|
||||
/// После вызова Fit значение становится true.
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
function ToString: string; override;
|
||||
|
||||
function Clone: IModel;
|
||||
end;
|
||||
|
||||
/// Линейная регрессионная модель ElasticNet.
|
||||
|
|
@ -234,7 +245,11 @@ type
|
|||
/// Показывает, была ли модель обучена.
|
||||
/// После вызова Fit значение становится true.
|
||||
property IsFitted: boolean read fFitted;
|
||||
end;
|
||||
|
||||
function ToString: string; override;
|
||||
|
||||
function Clone: IModel;
|
||||
end;
|
||||
|
||||
/// Многоклассовая логистическая регрессия (Softmax).
|
||||
/// Предсказывает вероятности принадлежности к каждому классу
|
||||
|
|
@ -267,6 +282,10 @@ type
|
|||
function Predict(X: Matrix): Vector;
|
||||
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
function ToString: string; override;
|
||||
|
||||
function Clone: IModel;
|
||||
end;
|
||||
|
||||
|
||||
|
|
@ -299,12 +318,12 @@ type
|
|||
/// Модель должна быть установлена через SetModel.
|
||||
constructor Create;
|
||||
|
||||
/// Строит конвейер машинного обучения.
|
||||
/// model — модель, обучаемая после применения всех преобразователей.
|
||||
/// transformers — последовательность преобразователей признаков,
|
||||
/// применяемых к данным перед обучением модели.
|
||||
/// Строит конвейер машинного обучения из последовательности шагов.
|
||||
/// Шаги указываются в порядке выполнения:
|
||||
/// сначала преобразователи, затем модель.
|
||||
/// Последний шаг обязан быть моделью (IModel).
|
||||
/// Возвращает сконструированный конвейер.
|
||||
static function Build(model: IModel; params transformers: array of ITransformer): Pipeline;
|
||||
static function Build(params steps: array of IPipeStep): Pipeline;
|
||||
|
||||
/// Устанавливает или заменяет модель.
|
||||
function SetModel(m: IModel): Pipeline;
|
||||
|
|
@ -326,6 +345,10 @@ type
|
|||
|
||||
/// Показывает, был ли пайплайн обучен (вызван метод Fit).
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
function ToString: string; override;
|
||||
|
||||
function Clone: IModel;
|
||||
end;
|
||||
{$endregion Pipeline}
|
||||
|
||||
|
|
@ -353,6 +376,10 @@ type
|
|||
|
||||
/// Признак того, что преобразование обучено.
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
function ToString: string; override;
|
||||
|
||||
function Clone: ITransformer;
|
||||
end;
|
||||
|
||||
/// Масштабирует признаки в заданный диапазон
|
||||
|
|
@ -387,6 +414,10 @@ type
|
|||
|
||||
/// Признак того, что преобразование обучено.
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
function ToString: string; override;
|
||||
|
||||
function Clone: ITransformer;
|
||||
end;
|
||||
|
||||
/// Трансформер главных компонент (PCA).
|
||||
|
|
@ -417,6 +448,9 @@ type
|
|||
property Components: Matrix read fComponents;
|
||||
property Mean: Vector read fMean;
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
function ToString: string; override;
|
||||
function Clone: ITransformer;
|
||||
end;
|
||||
|
||||
/// Трансформер, удаляющий признаки с малой дисперсией.
|
||||
|
|
@ -444,6 +478,9 @@ type
|
|||
|
||||
/// Показывает, был ли выполнен Fit.
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
function ToString: string; override;
|
||||
function Clone: ITransformer;
|
||||
end;
|
||||
|
||||
/// Тип критерия оценки признаков для SelectKBest.
|
||||
|
|
@ -481,7 +518,7 @@ type
|
|||
/// и оставляет k признаков с наибольшим значением score.
|
||||
/// Может использовать встроенные критерии
|
||||
/// или пользовательскую функцию оценки.
|
||||
SelectKBest = class(ITransformer)
|
||||
SelectKBest = class(ISupervisedTransformer)
|
||||
private
|
||||
fK: integer;
|
||||
fScoreType: FeatureScore;
|
||||
|
|
@ -520,6 +557,9 @@ type
|
|||
|
||||
/// Показывает, был ли выполнен Fit.
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
function ToString: string; override;
|
||||
function Clone: ITransformer;
|
||||
end;
|
||||
|
||||
/// Тип нормы для нормализации строк.
|
||||
|
|
@ -542,6 +582,9 @@ type
|
|||
function Transform(X: Matrix): Matrix;
|
||||
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
function ToString: string; override;
|
||||
function Clone: ITransformer;
|
||||
end;
|
||||
|
||||
|
||||
|
|
@ -556,16 +599,14 @@ uses System;
|
|||
// LinearRegression
|
||||
//-----------------------------
|
||||
|
||||
constructor LinearRegression.Create(lambda: real);
|
||||
constructor LinearRegression.Create();
|
||||
begin
|
||||
self.flambda := lambda;
|
||||
ffitted := false;
|
||||
end;
|
||||
|
||||
function LinearRegression.Fit(X: Matrix; y: Vector): IModel;
|
||||
begin
|
||||
var n := X.RowCount;
|
||||
var p := X.ColCount;
|
||||
|
||||
if n = 0 then
|
||||
raise new Exception('Empty dataset');
|
||||
|
|
@ -585,14 +626,10 @@ begin
|
|||
XtX := XtX - n * Matrix.OuterProduct(meanX, meanX);
|
||||
XtY := XtY - n * meanX * meanY;
|
||||
|
||||
// 4. Ridge regularization
|
||||
if flambda > 0 then
|
||||
XtX := XtX + Matrix.Identity(p) * flambda;
|
||||
|
||||
// 5. Solve
|
||||
// 4. Solve
|
||||
fcoef := Solve(XtX, XtY);
|
||||
|
||||
// 6. Intercept
|
||||
// 5. Intercept
|
||||
fintercept := meanY - meanX.Dot(fcoef);
|
||||
|
||||
ffitted := true;
|
||||
|
|
@ -610,6 +647,17 @@ begin
|
|||
Result := X * fcoef + intercept;
|
||||
end;
|
||||
|
||||
function LinearRegression.ToString: string;
|
||||
begin
|
||||
Result := 'LinearRegression'
|
||||
end;
|
||||
|
||||
function LinearRegression.Clone: IModel;
|
||||
begin
|
||||
Result := new LinearRegression();
|
||||
end;
|
||||
|
||||
|
||||
//-----------------------------
|
||||
// Activations
|
||||
//-----------------------------
|
||||
|
|
@ -700,6 +748,18 @@ begin
|
|||
Result := Predict(X, 0.5);
|
||||
end;
|
||||
|
||||
function LogisticRegression.ToString: string;
|
||||
begin
|
||||
Result := 'LogisticRegression(lambda=' + fLambda +
|
||||
', lr=' + fLearningRate + ', epochs=' + fEpochs + ')';
|
||||
end;
|
||||
|
||||
function LogisticRegression.Clone: IModel;
|
||||
begin
|
||||
Result := new LogisticRegression(fLambda, fLearningRate, fEpochs);
|
||||
end;
|
||||
|
||||
|
||||
//-----------------------------
|
||||
// RidgeRegression
|
||||
//-----------------------------
|
||||
|
|
@ -755,6 +815,21 @@ begin
|
|||
Result[i] += fIntercept;
|
||||
end;
|
||||
|
||||
function RidgeRegression.ToString: string;
|
||||
begin
|
||||
Result := 'RidgeRegression(lambda=' + fLambda + ')';
|
||||
end;
|
||||
|
||||
function RidgeRegression.Clone: IModel;
|
||||
begin
|
||||
Result := new RidgeRegression(fLambda);
|
||||
end;
|
||||
|
||||
|
||||
//-----------------------------
|
||||
// ElasticNet
|
||||
//-----------------------------
|
||||
|
||||
constructor ElasticNet.Create(lambda1, lambda2: real; maxIter: integer; tol: real);
|
||||
begin
|
||||
if (lambda1 < 0) or (lambda2 < 0) then
|
||||
|
|
@ -853,6 +928,24 @@ begin
|
|||
Result[i] += fIntercept;
|
||||
end;
|
||||
|
||||
function ElasticNet.ToString: string;
|
||||
begin
|
||||
Result :=
|
||||
'ElasticNet(lambda1=' + fLambda1 +
|
||||
', lambda2=' + fLambda2 +
|
||||
', maxIter=' + fMaxIter +
|
||||
', tol=' + fTol + ')';
|
||||
end;
|
||||
|
||||
function ElasticNet.Clone: IModel;
|
||||
begin
|
||||
Result := new ElasticNet(fLambda1, fLambda2, fMaxIter, fTol);
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
// MulticlassLogisticRegression
|
||||
//-----------------------------
|
||||
|
||||
constructor MulticlassLogisticRegression.Create(lambda: real; lr: real; epochs: integer);
|
||||
begin
|
||||
fLambda := lambda;
|
||||
|
|
@ -940,7 +1033,6 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
|
||||
function MulticlassLogisticRegression.PredictProbaMatrix(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
|
|
@ -984,6 +1076,20 @@ begin
|
|||
Result[i] := P.RowArgMax(i);
|
||||
end;
|
||||
|
||||
function MulticlassLogisticRegression.ToString: string;
|
||||
begin
|
||||
Result :=
|
||||
'MulticlassLogisticRegression(lambda=' + fLambda +
|
||||
', lr=' + fLearningRate +
|
||||
', epochs=' + fEpochs + ')';
|
||||
end;
|
||||
|
||||
function MulticlassLogisticRegression.Clone: IModel;
|
||||
begin
|
||||
Result := new MulticlassLogisticRegression(fLambda, fLearningRate, fEpochs);
|
||||
end;
|
||||
|
||||
|
||||
//-----------------------------
|
||||
// Pipeline
|
||||
//-----------------------------
|
||||
|
|
@ -1004,12 +1110,31 @@ begin
|
|||
fModel := model;
|
||||
end;
|
||||
|
||||
static function Pipeline.Build(model: IModel; transformers: array of ITransformer): Pipeline;
|
||||
class function Pipeline.Build(params steps: array of IPipeStep): Pipeline;
|
||||
begin
|
||||
Result := new Pipeline(model);
|
||||
if (steps = nil) or (Length(steps) = 0) then
|
||||
raise new ArgumentException('Pipeline requires at least one step');
|
||||
|
||||
foreach var t in transformers do
|
||||
Result.Add(t);
|
||||
// последний шаг должен быть моделью
|
||||
var last := steps[High(steps)];
|
||||
|
||||
if not (last is IModel) then
|
||||
raise new ArgumentException('Last step must be a model (IModel)');
|
||||
|
||||
var pipe := new Pipeline(last as IModel);
|
||||
|
||||
// все шаги кроме последнего должны быть преобразователями
|
||||
for var i := 0 to High(steps) - 1 do
|
||||
begin
|
||||
var step := steps[i];
|
||||
|
||||
if not (step is ITransformer) then
|
||||
raise new ArgumentException('All steps except the last must be transformers');
|
||||
|
||||
pipe.Add(step as ITransformer);
|
||||
end;
|
||||
|
||||
Result := pipe;
|
||||
end;
|
||||
|
||||
function Pipeline.Add(t: ITransformer): Pipeline;
|
||||
|
|
@ -1087,6 +1212,40 @@ begin
|
|||
Result := (fModel as IProbabilisticClassifier).PredictProba(Xt);
|
||||
end;
|
||||
|
||||
function Pipeline.ToString: string;
|
||||
begin
|
||||
var sb := 'Pipeline (' +
|
||||
(if fFitted then 'trained' else 'not trained') + '):' + NewLine;
|
||||
|
||||
var idx := 1;
|
||||
|
||||
foreach var t in fTransformers do
|
||||
begin
|
||||
sb += ' [' + idx + '] ' + t.ToString + NewLine;
|
||||
idx += 1;
|
||||
end;
|
||||
|
||||
if fModel <> nil then
|
||||
sb += ' [' + idx + '] ' + fModel.ToString;
|
||||
|
||||
Result := sb;
|
||||
end;
|
||||
|
||||
function Pipeline.Clone: IModel;
|
||||
begin
|
||||
if fModel = nil then
|
||||
raise new InvalidOperationException('Pipeline has no model');
|
||||
|
||||
var p := new Pipeline;
|
||||
|
||||
foreach var t in fTransformers do
|
||||
p.Add(t.Clone);
|
||||
|
||||
p.SetModel(fModel.Clone);
|
||||
|
||||
Result := p;
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
// StandardScaler
|
||||
//-----------------------------
|
||||
|
|
@ -1124,6 +1283,17 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function StandardScaler.ToString: string;
|
||||
begin
|
||||
Result := 'StandardScaler';
|
||||
end;
|
||||
|
||||
function StandardScaler.Clone: ITransformer;
|
||||
begin
|
||||
Result := new StandardScaler();
|
||||
end;
|
||||
|
||||
|
||||
//-----------------------------
|
||||
// MinMaxScaler
|
||||
//-----------------------------
|
||||
|
|
@ -1174,6 +1344,17 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function MinMaxScaler.ToString: string;
|
||||
begin
|
||||
Result := 'MinMaxScaler(min=' + fRangeMin + ', max=' + fRangeMax + ')';
|
||||
end;
|
||||
|
||||
function MinMaxScaler.Clone: ITransformer;
|
||||
begin
|
||||
Result := new MinMaxScaler(fRangeMin, fRangeMax);
|
||||
end;
|
||||
|
||||
|
||||
//-----------------------------
|
||||
// PCATransformer
|
||||
//-----------------------------
|
||||
|
|
@ -1222,6 +1403,16 @@ begin
|
|||
Result := Xc * fComponents;
|
||||
end;
|
||||
|
||||
function PCATransformer.ToString: string;
|
||||
begin
|
||||
Result := 'PCATransformer(k=' + fK + ')';
|
||||
end;
|
||||
|
||||
function PCATransformer.Clone: ITransformer;
|
||||
begin
|
||||
Result := new PCATransformer(fK);
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
// VarianceThreshold
|
||||
//-----------------------------
|
||||
|
|
@ -1268,6 +1459,16 @@ begin
|
|||
Result := R;
|
||||
end;
|
||||
|
||||
function VarianceThreshold.ToString: string;
|
||||
begin
|
||||
Result := 'VarianceThreshold(threshold=' + fThreshold + ')';
|
||||
end;
|
||||
|
||||
function VarianceThreshold.Clone: ITransformer;
|
||||
begin
|
||||
Result := new VarianceThreshold(fThreshold);
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
// SelectKBest
|
||||
//-----------------------------
|
||||
|
|
@ -1490,6 +1691,26 @@ begin
|
|||
Result := R;
|
||||
end;
|
||||
|
||||
function SelectKBest.ToString: string;
|
||||
begin
|
||||
var scoreStr :=
|
||||
if fScoreFunc <> nil then
|
||||
'custom'
|
||||
else
|
||||
fScoreType.ToString;
|
||||
|
||||
Result := 'SelectKBest(k=' + fK + ', score=' + scoreStr + ')';
|
||||
end;
|
||||
|
||||
function SelectKBest.Clone: ITransformer;
|
||||
begin
|
||||
if fScoreFunc <> nil then
|
||||
Result := new SelectKBest(fK, fScoreFunc)
|
||||
else
|
||||
Result := new SelectKBest(fK, fScoreType);
|
||||
end;
|
||||
|
||||
|
||||
//-----------------------------
|
||||
// Normalizer
|
||||
//-----------------------------
|
||||
|
|
@ -1544,6 +1765,15 @@ begin
|
|||
Result := R;
|
||||
end;
|
||||
|
||||
function Normalizer.ToString: string;
|
||||
begin
|
||||
Result :=
|
||||
'Normalizer(norm=' + fNormType.ToString + ')';
|
||||
end;
|
||||
|
||||
|
||||
function Normalizer.Clone: ITransformer;
|
||||
begin
|
||||
Result := new Normalizer(fNormType);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
@ -49,6 +49,30 @@ type
|
|||
/// 0.5 — случайная модель,
|
||||
/// 1 — идеальная модель.
|
||||
static function AUC(yTrue, yProb: Vector): real;
|
||||
|
||||
/// Доля правильных предсказаний.
|
||||
/// Показывает, какая часть объектов классифицирована верно.
|
||||
/// Удобна, когда классы примерно сбалансированы.
|
||||
/// Пример: Accuracy = 0.9 означает 90% правильных ответов.
|
||||
static function Accuracy(yTrue, yPred: Vector): real;
|
||||
|
||||
/// Точность (Precision) для положительного класса (1).
|
||||
/// Среди всех объектов, которые модель предсказала как 1,
|
||||
/// показывает долю действительно принадлежащих этому классу.
|
||||
/// Важна, когда критичны ложные положительные результаты («ложные тревоги»).
|
||||
static function Precision(yTrue, yPred: Vector): real;
|
||||
|
||||
/// Полнота (Recall) для положительного класса (1).
|
||||
/// Среди всех объектов, которые в действительности равны 1,
|
||||
/// показывает долю правильно найденных моделью.
|
||||
/// Важна, когда нежелательны пропуски положительных случаев (например, заболеваний).
|
||||
static function Recall(yTrue, yPred: Vector): real;
|
||||
|
||||
/// F1-мера.
|
||||
/// Объединённая метрика, учитывающая и Precision, и Recall одновременно.
|
||||
/// Высока только тогда, когда и Precision, и Recall высоки.
|
||||
/// Используется, когда классы сильно различаются по количеству элементов
|
||||
static function F1(yTrue, yPred: Vector): real;
|
||||
end;
|
||||
|
||||
type
|
||||
|
|
@ -267,6 +291,27 @@ begin
|
|||
Result := area;
|
||||
end;
|
||||
|
||||
static function Metrics.Accuracy(yTrue, yPred: Vector): real;
|
||||
begin
|
||||
Result := ConfusionMatrix.Create(yTrue, yPred).Accuracy;
|
||||
end;
|
||||
|
||||
static function Metrics.Precision(yTrue, yPred: Vector): real;
|
||||
begin
|
||||
Result := ConfusionMatrix.Create(yTrue, yPred).Precision;
|
||||
end;
|
||||
|
||||
static function Metrics.Recall(yTrue, yPred: Vector): real;
|
||||
begin
|
||||
Result := ConfusionMatrix.Create(yTrue, yPred).Recall;
|
||||
end;
|
||||
|
||||
static function Metrics.F1(yTrue, yPred: Vector): real;
|
||||
begin
|
||||
Result := ConfusionMatrix.Create(yTrue, yPred).F1;
|
||||
end;
|
||||
|
||||
|
||||
//-----------------------------
|
||||
// ConfusionMatrix
|
||||
//-----------------------------
|
||||
|
|
|
|||
|
|
@ -57,18 +57,21 @@ type
|
|||
/// X, y — обучающие данные.
|
||||
/// k — число фолдов в кросс-валидации.
|
||||
/// metric — функция оценки качества (yTrue, yPred) → real.
|
||||
/// Возвращает кортеж (лучший параметр, лучшее среднее значение метрики).
|
||||
class function Search<T>(
|
||||
modelFactory: real -> IModel;
|
||||
paramValues: array of real;
|
||||
X: Matrix; y: Vector;
|
||||
k: integer;
|
||||
metric: (Vector, Vector) -> real
|
||||
): (real, real); where T: IModel;
|
||||
/// Возвращает кортеж (лучший параметр, лучшее среднее значение метрики,
|
||||
/// модель, обученная на всём датасете с лучшим параметром).
|
||||
class function Search<T>(
|
||||
modelFactory: real -> T;
|
||||
paramValues: array of real;
|
||||
X: Matrix; y: Vector;
|
||||
k: integer;
|
||||
metric: (Vector, Vector) -> real
|
||||
): (real, real, T); where T: IModel;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses System;
|
||||
|
||||
//-----------------------------
|
||||
// Validation
|
||||
//-----------------------------
|
||||
|
|
@ -235,7 +238,8 @@ begin
|
|||
yte[i] := y[r];
|
||||
end;
|
||||
|
||||
var m := model.Fit(Xtr, ytr);
|
||||
var m := model.Clone();
|
||||
m.Fit(Xtr, ytr);
|
||||
var pred := m.Predict(Xte);
|
||||
|
||||
total += metric(yte, pred);
|
||||
|
|
@ -281,7 +285,8 @@ begin
|
|||
yte[i] := y[r];
|
||||
end;
|
||||
|
||||
var m := model.Fit(Xtr, ytr);
|
||||
var m := model.Clone();
|
||||
m.Fit(Xtr, ytr);
|
||||
var pred := m.Predict(Xte);
|
||||
|
||||
total += metric(yte, pred);
|
||||
|
|
@ -296,65 +301,23 @@ end;
|
|||
//-----------------------------
|
||||
|
||||
class function GridSearch.Search<T>(
|
||||
modelFactory: real -> IModel;
|
||||
modelFactory: real -> T;
|
||||
paramValues: array of real;
|
||||
X: Matrix; y: Vector;
|
||||
k: integer;
|
||||
metric: (Vector, Vector) -> real
|
||||
): (real, real); where T: IModel;
|
||||
): (real, real, T); where T: IModel;
|
||||
begin
|
||||
var bestParam := 0.0;
|
||||
var bestScore := -1e308;
|
||||
if paramValues.Length = 0 then
|
||||
raise new ArgumentException('paramValues is empty');
|
||||
|
||||
var n := X.RowCount;
|
||||
var foldSize := n div k;
|
||||
var bestParam := paramValues[0];
|
||||
var bestScore := -1e308;
|
||||
|
||||
foreach var param in paramValues do
|
||||
begin
|
||||
var totalScore := 0.0;
|
||||
|
||||
for var fold := 0 to k - 1 do
|
||||
begin
|
||||
var startIdx := fold * foldSize;
|
||||
var endIdx := if fold = k - 1 then n - 1 else (startIdx + foldSize - 1);
|
||||
|
||||
var trainCount := n - (endIdx - startIdx + 1);
|
||||
var testCount := endIdx - startIdx + 1;
|
||||
|
||||
var Xtrain := new Matrix(trainCount, X.ColCount);
|
||||
var ytrain := new Vector(trainCount);
|
||||
var Xtest := new Matrix(testCount, X.ColCount);
|
||||
var ytest := new Vector(testCount);
|
||||
|
||||
var ti := 0;
|
||||
var si := 0;
|
||||
|
||||
for var i := 0 to n - 1 do
|
||||
begin
|
||||
if (i >= startIdx) and (i <= endIdx) then
|
||||
begin
|
||||
for var j := 0 to X.ColCount - 1 do
|
||||
Xtest[si,j] := X[i,j];
|
||||
ytest[si] := y[i];
|
||||
si += 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
for var j := 0 to X.ColCount - 1 do
|
||||
Xtrain[ti,j] := X[i,j];
|
||||
ytrain[ti] := y[i];
|
||||
ti += 1;
|
||||
end;
|
||||
end;
|
||||
|
||||
var model := modelFactory(param);
|
||||
model.Fit(Xtrain, ytrain);
|
||||
|
||||
var pred := model.Predict(Xtest);
|
||||
totalScore += metric(ytest, pred);
|
||||
end;
|
||||
|
||||
var avgScore := totalScore / k;
|
||||
var model := modelFactory(param);
|
||||
var avgScore := Validation.CrossValidate(model, X, y, k, metric);
|
||||
|
||||
if avgScore > bestScore then
|
||||
begin
|
||||
|
|
@ -363,8 +326,12 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
Result := (bestParam, bestScore);
|
||||
var bestModel := modelFactory(bestParam);
|
||||
bestModel.Fit(X, y);
|
||||
|
||||
Result := (bestParam, bestScore, bestModel);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
|
|
|||
Loading…
Reference in a new issue