ML Pipeline - исправления архитектуры
This commit is contained in:
parent
b9b55b513b
commit
69f90b3666
|
|
@ -49,17 +49,23 @@ type
|
|||
|
||||
/// Базовый интерфейс модели машинного обучения
|
||||
IModel = interface(IMatrixStep)
|
||||
function Predict(X: Matrix): Vector;
|
||||
// function Predict(X: Matrix): Vector; // вынес в IPredictiveModel
|
||||
function Clone: IModel;
|
||||
function Name: string;
|
||||
property IsFitted: boolean read;
|
||||
end;
|
||||
|
||||
/// Модель, реализующая отображение X → y (или аналогичный результат).
|
||||
/// Поддерживает предсказание для новых данных
|
||||
IPredictiveModel = interface(IModel)
|
||||
function Predict(X: Matrix): Vector;
|
||||
end;
|
||||
|
||||
/// Интерфейс модели с учителем (Supervised Model).
|
||||
/// Наследуется от базового интерфейса IModel.
|
||||
/// Предназначен для алгоритмов, обучающихся по признакам X
|
||||
/// с использованием целевых значений (y)
|
||||
ISupervisedModel = interface(IModel)
|
||||
ISupervisedModel = interface(IPredictiveModel)
|
||||
function Fit(X: Matrix; y: Vector): ISupervisedModel;
|
||||
end;
|
||||
|
||||
|
|
@ -71,14 +77,30 @@ type
|
|||
function Fit(X: Matrix): IUnsupervisedModel;
|
||||
end;
|
||||
|
||||
/// Интерфейс алгоритма кластеризации.
|
||||
/// Наследуется от IUnsupervisedModel.
|
||||
/// Интерфейс алгоритма кластеризации (unsupervised learning).
|
||||
/// Предназначен для моделей, разбивающих объекты на кластеры
|
||||
/// и возвращающих индекс кластера для каждого объекта
|
||||
/// без использования целевой переменной.
|
||||
/// Основной сценарий использования — FitPredict, возвращающий
|
||||
/// индекс кластера для каждого объекта обучающей выборки
|
||||
IClusterer = interface(IUnsupervisedModel)
|
||||
function PredictLabels(X: Matrix): array of integer;
|
||||
// function PredictLabels(X: Matrix): array of integer;
|
||||
|
||||
/// Выполняет кластеризацию данных и возвращает массив индексов кластеров
|
||||
/// (0,1,2,...) для каждого объекта. Значение -1 может использоваться
|
||||
/// для обозначения шума (например, в DBSCAN).
|
||||
function FitPredict(X: Matrix): array of integer;
|
||||
end;
|
||||
|
||||
/// Интерфейс кластеризатора, поддерживающего предсказание для новых данных.
|
||||
/// Используется для алгоритмов, задающих явное отображение X → cluster
|
||||
/// (например, KMeans через ближайший центр кластера)
|
||||
IPredictiveClusterer = interface(IClusterer, IPredictiveModel)
|
||||
/// Возвращает индекс кластера для каждого объекта из X
|
||||
/// без повторного обучения модели.
|
||||
/// Требует предварительного вызова Fit или FitPredict.
|
||||
function PredictLabels(X: Matrix): array of integer;
|
||||
end;
|
||||
|
||||
/// Интерфейс древовидной модели машинного обучения
|
||||
ITreeModel = interface(ISupervisedModel)
|
||||
function FeatureImportances: Vector;
|
||||
|
|
@ -107,9 +129,6 @@ type
|
|||
/// Возвращает матрицу вероятностей размера (nSamples × nClasses).
|
||||
/// Столбцы соответствуют классам в порядке внутреннего кодирования модели
|
||||
function PredictProba(X: Matrix): Matrix;
|
||||
|
||||
/// Возвращает массив меток классов в порядке столбцов PredictProba.
|
||||
function GetClasses: array of real;
|
||||
end;
|
||||
|
||||
/// Интерфейс регрессионной модели.
|
||||
|
|
|
|||
|
|
@ -719,7 +719,7 @@ type
|
|||
/// Строит ансамбль классификационных деревьев, обученных на
|
||||
/// bootstrap-подвыборках объектов и случайных подмножествах признаков.
|
||||
/// Итоговое предсказание формируется голосованием деревьев или агрегацией вероятностей классов
|
||||
RandomForestClassifier = class(RandomForestBase, IClassifier, IProbabilisticClassifier)
|
||||
RandomForestClassifier = class(RandomForestBase, IProbabilisticClassifier)
|
||||
private
|
||||
fTrees: array of DecisionTreeClassifier;
|
||||
fIndexToClass: array of integer;
|
||||
|
|
@ -1125,7 +1125,7 @@ type
|
|||
/// Базовый абстрактный класс для алгоритма k ближайших соседей (kNN).
|
||||
/// Реализует общий механизм поиска k ближайших объектов,
|
||||
/// но не определяет способ агрегации (классификация или регрессия)
|
||||
KNNBase = abstract class(IModel)
|
||||
KNNBase = abstract class(IPredictiveModel)
|
||||
protected
|
||||
// ==== train state ====
|
||||
fXTrain: Matrix;
|
||||
|
|
@ -1255,7 +1255,7 @@ type
|
|||
/// Модель кластеризации методом k-средних (KMeans).
|
||||
/// Разбивает объекты на k кластеров на основе евклидова расстояния.
|
||||
/// Реализует алгоритм без учителя
|
||||
KMeans = class(IClusterer)
|
||||
KMeans = class(IPredictiveClusterer)
|
||||
private
|
||||
fNClusters: integer;
|
||||
fMaxIter: integer;
|
||||
|
|
@ -1300,7 +1300,7 @@ type
|
|||
function PredictLabels(X: Matrix): array of integer;
|
||||
|
||||
/// Выполняет обучение и сразу возвращает метки кластеров.
|
||||
function FitPredict(X: Matrix): Vector;
|
||||
function FitPredict(X: Matrix): array of integer;
|
||||
|
||||
/// Создаёт глубокую копию модели.
|
||||
function Clone: IModel;
|
||||
|
|
@ -1405,13 +1405,13 @@ type
|
|||
Pipeline = class(ISupervisedModel)
|
||||
private
|
||||
fTransformers: List<ITransformer>;
|
||||
fModel: IModel;
|
||||
fModel: ISupervisedModel;
|
||||
fFitted: boolean;
|
||||
public
|
||||
/// Создаёт конвейер машинного обучения для заданной модели:
|
||||
/// • model — модель, которая будет обучена
|
||||
/// после последовательного применения всех преобразователей.
|
||||
constructor Create(model: IModel);
|
||||
constructor Create(model: ISupervisedModel);
|
||||
|
||||
/// Создаёт пустой пайплайн (конвейер машинного обучения).
|
||||
/// Модель должна быть установлена через SetModel.
|
||||
|
|
@ -1482,7 +1482,7 @@ type
|
|||
static function Build(params steps: array of IPipelineStep): Pipeline;
|
||||
|
||||
/// Устанавливает или заменяет модель.
|
||||
function SetModel(m: IModel): Pipeline;
|
||||
function SetModel(m: ISupervisedModel): Pipeline;
|
||||
|
||||
/// Добавляет преобразование в конец пайплайна
|
||||
function Add(t: ITransformer): Pipeline;
|
||||
|
|
@ -1501,8 +1501,6 @@ type
|
|||
/// для вероятностной модели в конце пайплайна.
|
||||
function PredictProba(X: Matrix): Matrix;
|
||||
|
||||
function GetClasses: array of real;
|
||||
|
||||
/// Показывает, был ли пайплайн обучен (вызван метод Fit).
|
||||
property IsFitted: boolean read fFitted;
|
||||
|
||||
|
|
@ -2011,6 +2009,16 @@ const
|
|||
'DBSCAN не поддерживает предсказание для новых данных!!DBSCAN does not support prediction for new data';
|
||||
ER_CLASSES_NOT_AVAILABLE =
|
||||
'Метки классов недоступны. Убедитесь, что модель обучена и метки установлены!!Class labels are not available. Ensure the model is fitted and class labels are set';
|
||||
ER_PIPELINE_LAST_NOT_SUPERVISED_MODEL =
|
||||
'Последний шаг Pipeline должен быть supervised-моделью!!' +
|
||||
'Last Pipeline step must be a supervised model';
|
||||
ER_INTERNAL_INVALID_MODEL_CLONE =
|
||||
'Внутренняя ошибка: Clone модели вернул несовместимый тип!!' +
|
||||
'Internal error: model Clone returned incompatible type';
|
||||
ER_PREDICT_NOT_SUPPORTED =
|
||||
'Модель не поддерживает Predict для данного типа алгоритма!!' +
|
||||
'Model does not support Predict for this type of algorithm';
|
||||
|
||||
|
||||
{$endregion ErrConstants}
|
||||
|
||||
|
|
@ -7239,10 +7247,10 @@ begin
|
|||
Result[i] := labels[i];
|
||||
end;
|
||||
|
||||
function KMeans.FitPredict(X: Matrix): Vector;
|
||||
function KMeans.FitPredict(X: Matrix): array of integer;
|
||||
begin
|
||||
Fit(X);
|
||||
Result := Predict(X);
|
||||
Result := PredictLabels(X);
|
||||
end;
|
||||
|
||||
function KMeans.Clone: IModel;
|
||||
|
|
@ -7477,7 +7485,7 @@ begin
|
|||
fFitted := false;
|
||||
end;
|
||||
|
||||
constructor Pipeline.Create(model: IModel);
|
||||
constructor Pipeline.Create(model: ISupervisedModel);
|
||||
begin
|
||||
Create;
|
||||
if model = nil then
|
||||
|
|
@ -7496,10 +7504,10 @@ begin
|
|||
if last = nil then
|
||||
ArgumentError(ER_PIPELINE_STEP_NULL, High(steps));
|
||||
|
||||
if not (last is IModel) then
|
||||
ArgumentError(ER_PIPELINE_LAST_NOT_MODEL);
|
||||
if not (last is ISupervisedModel) then
|
||||
ArgumentError(ER_PIPELINE_LAST_NOT_SUPERVISED_MODEL);
|
||||
|
||||
var pipe := new Pipeline(last as IModel);
|
||||
var pipe := new Pipeline(last as ISupervisedModel);
|
||||
|
||||
// все шаги кроме последнего — трансформеры
|
||||
for var i := 0 to High(steps) - 1 do
|
||||
|
|
@ -7527,7 +7535,7 @@ begin
|
|||
Result := Self;
|
||||
end;
|
||||
|
||||
function Pipeline.SetModel(m: IModel): Pipeline;
|
||||
function Pipeline.SetModel(m: ISupervisedModel): Pipeline;
|
||||
begin
|
||||
if m = nil then
|
||||
ArgumentError(ER_MODEL_NULL);
|
||||
|
|
@ -7637,14 +7645,6 @@ begin
|
|||
.PredictProba(Xt);
|
||||
end;
|
||||
|
||||
function Pipeline.GetClasses: array of real;
|
||||
begin
|
||||
if not (fModel is IProbabilisticClassifier) then
|
||||
ArgumentError(ER_PROBA_NOT_SUPPORTED);
|
||||
|
||||
Result := (fModel as IProbabilisticClassifier).GetClasses;
|
||||
end;
|
||||
|
||||
function Pipeline.ToString: string;
|
||||
begin
|
||||
var sb := 'Pipeline (' +
|
||||
|
|
@ -7674,7 +7674,12 @@ begin
|
|||
foreach var t in fTransformers do
|
||||
p.Add(t.Clone);
|
||||
|
||||
p.SetModel(fModel.Clone);
|
||||
var m := fModel.Clone;
|
||||
|
||||
if not (m is ISupervisedModel) then
|
||||
Error(ER_INTERNAL_INVALID_MODEL_CLONE);
|
||||
|
||||
p.SetModel(m as ISupervisedModel);
|
||||
|
||||
p.fFitted := fFitted;
|
||||
|
||||
|
|
@ -7822,7 +7827,10 @@ begin
|
|||
|
||||
var Xt := Transform(X);
|
||||
|
||||
Result := (fModel as IUnsupervisedModel).Predict(Xt);
|
||||
if not (fModel is IPredictiveModel) then
|
||||
Error(ER_PREDICT_NOT_SUPPORTED);
|
||||
|
||||
Result := (fModel as IPredictiveModel).Predict(Xt);
|
||||
end;
|
||||
|
||||
function UPipeline.ToString: string;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ type
|
|||
private
|
||||
fDataSteps: List<IPreprocessor>;
|
||||
fMatrixSteps: List<ITransformer>;
|
||||
fModel: IModel;
|
||||
fModel: ISupervisedModel;
|
||||
fTask: TaskKind;
|
||||
|
||||
fTarget: string;
|
||||
|
|
@ -50,7 +50,7 @@ type
|
|||
/// Принимает:
|
||||
/// • IPreprocessor (DataFrame-уровень)
|
||||
/// • ITransformer (Matrix-уровень)
|
||||
/// • IModel (модель, должна быть последней)
|
||||
/// • ISupervisedModel (модель, должна быть последней)
|
||||
/// Запрещено добавлять шаги после вызова Fit/FitTransform.
|
||||
function Add(step: IPipelineStep): DataPipeline;
|
||||
|
||||
|
|
@ -204,7 +204,7 @@ type
|
|||
private
|
||||
fDataSteps: List<IPreprocessor>;
|
||||
fMatrixSteps: List<ITransformer>;
|
||||
fModel: IModel;
|
||||
fModel: IUnsupervisedModel;
|
||||
|
||||
fFeatures: array of string;
|
||||
fFinalFeatures: array of string;
|
||||
|
|
@ -222,7 +222,7 @@ type
|
|||
/// Принимает:
|
||||
/// • IPreprocessor (DataFrame-уровень)
|
||||
/// • ITransformer (Matrix-уровень)
|
||||
/// • IModel (модель, должна быть последней)
|
||||
/// • IUnsupervisedModel (модель, должна быть последней)
|
||||
function Add(step: IPipelineStep): UDataPipeline;
|
||||
|
||||
/// Строит unsupervised-конвейер из шагов обработки данных и модели.
|
||||
|
|
@ -353,8 +353,27 @@ const
|
|||
ER_PIPELINE_TARGET_TRANSFORM_NOT_ALLOWED =
|
||||
'Преобразование целевой переменной "{0}" запрещено в DataPipeline!!' +
|
||||
'Transformation of target variable "{0}" is not allowed in DataPipeline';
|
||||
|
||||
|
||||
ER_DATAPIPE_INVALID_TASK =
|
||||
'DataPipeline поддерживает только классификацию и регрессию!!' +
|
||||
'DataPipeline supports classification and regression only';
|
||||
ER_PREDICT_NOT_SUPPORTED =
|
||||
'Модель не поддерживает операцию Predict!!' +
|
||||
'Model does not support Predict operation';
|
||||
ER_PIPELINE_NO_STEPS =
|
||||
'Pipeline не содержит шагов!!' +
|
||||
'Pipeline must contain at least one step';
|
||||
ER_PIPELINE_LAST_NOT_UNSUPERVISED_MODEL =
|
||||
'Последний шаг Pipeline должен быть unsupervised-моделью!!' +
|
||||
'Last Pipeline step must be an unsupervised model';
|
||||
ER_PIPELINE_INVALID_STEP_ORDER =
|
||||
'Неверный порядок шагов в Pipeline: модель должна быть последней!!' +
|
||||
'Invalid pipeline step order: model must be the last step';
|
||||
ER_PIPELINE_LAST_NOT_SUPERVISED_MODEL =
|
||||
'Последний шаг Pipeline должен быть supervised-моделью!!' +
|
||||
'Last Pipeline step must be a supervised model';
|
||||
ER_MODEL_NOT_CLASSIFIER =
|
||||
'Модель не является классификатором!!' +
|
||||
'Model is not a classifier';
|
||||
//-----------------------------
|
||||
// DataPipeline
|
||||
//-----------------------------
|
||||
|
|
@ -412,12 +431,12 @@ begin
|
|||
end;
|
||||
|
||||
// --- Model (обязательно последний шаг)
|
||||
if step is IModel then
|
||||
if step is ISupervisedModel then
|
||||
begin
|
||||
if fModel <> nil then
|
||||
ArgumentError(ER_PIPELINE_MULTIPLE_MODELS);
|
||||
|
||||
fModel := step as IModel;
|
||||
fModel := step as ISupervisedModel;
|
||||
exit(Self);
|
||||
end;
|
||||
|
||||
|
|
@ -432,6 +451,9 @@ class function DataPipeline.Build(
|
|||
params steps: array of IPipelineStep
|
||||
): DataPipeline;
|
||||
begin
|
||||
if not (task in [TaskKind.tkClassification, TaskKind.tkRegression]) then
|
||||
ArgumentError(ER_DATAPIPE_INVALID_TASK);
|
||||
|
||||
if (target = nil) or (target = '') then
|
||||
ArgumentError(ER_TARGET_EMPTY);
|
||||
|
||||
|
|
@ -454,14 +476,48 @@ begin
|
|||
seen.Add(f);
|
||||
end;
|
||||
|
||||
if (steps = nil) or (Length(steps) = 0) then
|
||||
ArgumentError(ER_PIPELINE_NO_STEPS);
|
||||
|
||||
var last := steps[High(steps)];
|
||||
|
||||
if last = nil then
|
||||
ArgumentError(ER_PIPELINE_STEP_NULL, High(steps));
|
||||
|
||||
if not (last is ISupervisedModel) then
|
||||
ArgumentError(ER_PIPELINE_LAST_NOT_SUPERVISED_MODEL);
|
||||
|
||||
var modelFound := false;
|
||||
|
||||
for var i := 0 to High(steps) do
|
||||
begin
|
||||
if steps[i] is ISupervisedModel then
|
||||
begin
|
||||
if modelFound then
|
||||
ArgumentError(ER_PIPELINE_MULTIPLE_MODELS);
|
||||
|
||||
modelFound := true;
|
||||
end;
|
||||
end;
|
||||
|
||||
for var i := 0 to High(steps) - 1 do
|
||||
begin
|
||||
var step := steps[i];
|
||||
|
||||
if step = nil then
|
||||
ArgumentError(ER_PIPELINE_STEP_NULL, i);
|
||||
|
||||
if step is ISupervisedModel then
|
||||
ArgumentError(ER_PIPELINE_INVALID_STEP_ORDER);
|
||||
end;
|
||||
|
||||
var p := new DataPipeline;
|
||||
p.fTarget := target;
|
||||
p.fFeatures := Copy(features);
|
||||
p.fTask := task;
|
||||
|
||||
if steps <> nil then
|
||||
for var i := 0 to High(steps) do
|
||||
p.Add(steps[i]);
|
||||
for var i := 0 to High(steps) do
|
||||
p.Add(steps[i]);
|
||||
|
||||
Result := p;
|
||||
end;
|
||||
|
|
@ -546,13 +602,15 @@ begin
|
|||
end;
|
||||
|
||||
// --- 4) модель
|
||||
if fModel is ISupervisedModel(var supModel) then
|
||||
fModel := supModel.Fit(X, y)
|
||||
else ArgumentError(ER_MODEL_NOT_SUPERVISED, fModel.GetType.Name);
|
||||
fModel := fModel.Fit(X, y);
|
||||
|
||||
if fTask = tkClassification then
|
||||
begin
|
||||
if fModel is IClassifier(var cls) then
|
||||
cls.SetClassLabels(classes);
|
||||
cls.SetClassLabels(classes)
|
||||
else
|
||||
Error(ER_MODEL_NOT_CLASSIFIER);
|
||||
end;
|
||||
|
||||
fFitted := true;
|
||||
Result := Self;
|
||||
|
|
@ -614,8 +672,11 @@ begin
|
|||
|
||||
foreach var t in fMatrixSteps do
|
||||
X := t.Transform(X);
|
||||
|
||||
if not (fModel is IPredictiveModel) then
|
||||
Error(ER_PREDICT_NOT_SUPPORTED);
|
||||
|
||||
Result := fModel.Predict(X);
|
||||
Result := (fModel as IPredictiveModel).Predict(X);
|
||||
end;
|
||||
|
||||
function DataPipeline.PredictProba(df: DataFrame): Matrix;
|
||||
|
|
@ -625,6 +686,9 @@ begin
|
|||
if not fFitted then
|
||||
NotFittedError(ER_FIT_NOT_CALLED);
|
||||
|
||||
if fTask <> tkClassification then
|
||||
ArgumentError(ER_NOT_CLASSIFICATION);
|
||||
|
||||
if not (fModel is IProbabilisticClassifier) then
|
||||
ArgumentError(ER_PROBA_NOT_SUPPORTED);
|
||||
|
||||
|
|
@ -633,9 +697,6 @@ begin
|
|||
if fFinalFeatures = nil then
|
||||
Error(ER_PIPELINE_FINALFEATURES);
|
||||
|
||||
if fTask <> tkClassification then
|
||||
ArgumentError(ER_NOT_CLASSIFICATION);
|
||||
|
||||
for var i := 0 to High(fFinalFeatures) do
|
||||
if not current.HasColumn(fFinalFeatures[i]) then
|
||||
ArgumentError(ER_PIPELINE_FEATURE_NOT_FOUND, fFinalFeatures[i]);
|
||||
|
|
@ -779,12 +840,12 @@ begin
|
|||
end;
|
||||
|
||||
// --- Model (обязательно последний шаг)
|
||||
if step is IModel then
|
||||
if step is IUnsupervisedModel then
|
||||
begin
|
||||
if fModel <> nil then
|
||||
ArgumentError(ER_PIPELINE_MULTIPLE_MODELS);
|
||||
|
||||
fModel := step as IModel;
|
||||
fModel := step as IUnsupervisedModel;
|
||||
exit(Self);
|
||||
end;
|
||||
|
||||
|
|
@ -811,8 +872,30 @@ begin
|
|||
seen.Add(f);
|
||||
end;
|
||||
|
||||
if (steps = nil) or (Length(steps) = 0) then
|
||||
ArgumentError(ER_PIPELINE_NO_STEPS);
|
||||
|
||||
var last := steps[High(steps)];
|
||||
|
||||
if last = nil then
|
||||
ArgumentError(ER_PIPELINE_STEP_NULL, High(steps));
|
||||
|
||||
if not (last is IUnsupervisedModel) then
|
||||
ArgumentError(ER_PIPELINE_LAST_NOT_UNSUPERVISED_MODEL);
|
||||
|
||||
for var i := 0 to High(steps) - 1 do
|
||||
begin
|
||||
var step := steps[i];
|
||||
|
||||
if step = nil then
|
||||
ArgumentError(ER_PIPELINE_STEP_NULL, i);
|
||||
|
||||
if step is IUnsupervisedModel then
|
||||
ArgumentError(ER_PIPELINE_INVALID_STEP_ORDER);
|
||||
end;
|
||||
|
||||
var p := new UDataPipeline;
|
||||
p.fFeatures := features;
|
||||
p.fFeatures := Copy(features);
|
||||
|
||||
for var i := 0 to High(steps) do
|
||||
p.Add(steps[i]);
|
||||
|
|
@ -878,10 +961,7 @@ begin
|
|||
end;
|
||||
|
||||
// --- 4) модель
|
||||
if fModel is IUnsupervisedModel(var unsupModel) then
|
||||
fModel := unsupModel.Fit(X)
|
||||
else
|
||||
ArgumentError(ER_MODEL_NOT_UNSUPERVISED, fModel.GetType.Name);
|
||||
fModel := fModel.Fit(X);
|
||||
|
||||
fFitted := true;
|
||||
Result := Self;
|
||||
|
|
@ -931,8 +1011,62 @@ begin
|
|||
if not (fModel is IClusterer) then
|
||||
ArgumentError(ER_MODEL_NOT_CLUSTERER, fModel.GetType.Name);
|
||||
|
||||
Fit(df);
|
||||
Result := PredictLabels(df);
|
||||
var current := df;
|
||||
|
||||
// --- 0) Проверка входной схемы
|
||||
ValidateSchema(current);
|
||||
|
||||
// --- 1) DataFrame шаги
|
||||
for var i := 0 to fDataSteps.Count - 1 do
|
||||
begin
|
||||
fDataSteps[i] := fDataSteps[i].Fit(current);
|
||||
current := fDataSteps[i].Transform(current);
|
||||
end;
|
||||
|
||||
// --- 2) вычислить финальные признаки
|
||||
var feats := new List<string>;
|
||||
|
||||
foreach var f in fFeatures do
|
||||
begin
|
||||
if current.HasColumn(f) then
|
||||
begin
|
||||
feats.Add(f);
|
||||
continue;
|
||||
end;
|
||||
|
||||
// искать производные признаки (например, OneHotEncoder)
|
||||
foreach var c in current.Schema.ColumnNames do
|
||||
if c.StartsWith(f + '_') then
|
||||
if not feats.Contains(c) then
|
||||
feats.Add(c);
|
||||
end;
|
||||
|
||||
if feats.Count = 0 then
|
||||
ArgumentError(ER_PIPELINE_NO_FEATURES);
|
||||
|
||||
fFinalFeatures := feats.ToArray;
|
||||
|
||||
var X := current.ToMatrix(fFinalFeatures);
|
||||
|
||||
// --- 3) Matrix transformers
|
||||
for var i := 0 to fMatrixSteps.Count - 1 do
|
||||
begin
|
||||
var t := fMatrixSteps[i];
|
||||
|
||||
if not (t is IUnsupervisedTransformer) then
|
||||
ArgumentError(ER_MATRIXSTEP_NO_FIT, i, t.GetType.Name);
|
||||
|
||||
var unsup := t as IUnsupervisedTransformer;
|
||||
fMatrixSteps[i] := unsup.Fit(X);
|
||||
|
||||
X := fMatrixSteps[i].Transform(X);
|
||||
end;
|
||||
|
||||
// --- 4) модель
|
||||
var cl := fModel as IClusterer;
|
||||
Result := cl.FitPredict(X);
|
||||
|
||||
fFitted := true;
|
||||
end;
|
||||
|
||||
procedure UDataPipeline.ValidateNumericFeatures(df: DataFrame);
|
||||
|
|
@ -967,6 +1101,13 @@ begin
|
|||
|
||||
ValidateNumericFeatures(current);
|
||||
|
||||
if fFinalFeatures = nil then
|
||||
Error(ER_PIPELINE_FINALFEATURES);
|
||||
|
||||
for var i := 0 to High(fFinalFeatures) do
|
||||
if not current.HasColumn(fFinalFeatures[i]) then
|
||||
ArgumentError(ER_PIPELINE_FEATURE_NOT_FOUND, fFinalFeatures[i]);
|
||||
|
||||
var X := current.ToMatrix(fFinalFeatures);
|
||||
|
||||
foreach var t in fMatrixSteps do
|
||||
|
|
@ -976,56 +1117,44 @@ begin
|
|||
end;
|
||||
|
||||
function UDataPipeline.Predict(df: DataFrame): Vector;
|
||||
begin
|
||||
if fModel = nil then
|
||||
ArgumentError(ER_MODEL_NULL);
|
||||
|
||||
var X := TransformToMatrix(df);
|
||||
|
||||
Result := fModel.Predict(X);
|
||||
end;
|
||||
|
||||
function UDataPipeline.PredictLabels(df: DataFrame): array of integer;
|
||||
begin
|
||||
if fModel = nil then
|
||||
ArgumentError(ER_MODEL_NULL);
|
||||
|
||||
if not (fModel is IClusterer) then
|
||||
ArgumentError(ER_MODEL_NOT_CLUSTERER, fModel.GetType.Name);
|
||||
|
||||
var cl := fModel as IClusterer;
|
||||
|
||||
var X := TransformToMatrix(df);
|
||||
|
||||
Result := cl.PredictLabels(X);
|
||||
end;
|
||||
|
||||
{function UDataPipeline.Predict(df: DataFrame): Vector;
|
||||
begin
|
||||
if df = nil then
|
||||
ArgumentNullError(ER_ARG_NULL, 'df');
|
||||
|
||||
if not fFitted then
|
||||
NotFittedError(ER_FIT_NOT_CALLED);
|
||||
|
||||
if fModel = nil then
|
||||
ArgumentError(ER_MODEL_NULL);
|
||||
|
||||
var current := Transform(df);
|
||||
var X := TransformToMatrix(df);
|
||||
|
||||
if fFinalFeatures = nil then
|
||||
Error(ER_PIPELINE_FINALFEATURES);
|
||||
if not (fModel is IPredictiveModel) then
|
||||
Error(ER_PREDICT_NOT_SUPPORTED);
|
||||
|
||||
for var i := 0 to High(fFinalFeatures) do
|
||||
if not current.HasColumn(fFinalFeatures[i]) then
|
||||
ArgumentError(ER_PIPELINE_FEATURE_NOT_FOUND, fFinalFeatures[i]);
|
||||
Result := (fModel as IPredictiveModel).Predict(X);
|
||||
end;
|
||||
|
||||
var X := current.ToMatrix(fFinalFeatures);
|
||||
function UDataPipeline.PredictLabels(df: DataFrame): array of integer;
|
||||
begin
|
||||
if df = nil then
|
||||
ArgumentNullError(ER_ARG_NULL, 'df');
|
||||
|
||||
foreach var t in fMatrixSteps do
|
||||
X := t.Transform(X);
|
||||
if not fFitted then
|
||||
NotFittedError(ER_FIT_NOT_CALLED);
|
||||
|
||||
Result := fModel.Predict(X);
|
||||
end;}
|
||||
if fModel = nil then
|
||||
ArgumentError(ER_MODEL_NULL);
|
||||
|
||||
if not (fModel is IPredictiveClusterer) then
|
||||
Error(ER_PREDICT_NOT_SUPPORTED);
|
||||
|
||||
var cl := fModel as IPredictiveClusterer;
|
||||
|
||||
var X := TransformToMatrix(df);
|
||||
|
||||
Result := cl.PredictLabels(X);
|
||||
end;
|
||||
|
||||
procedure UDataPipeline.ValidateSchema(df: DataFrame);
|
||||
begin
|
||||
|
|
|
|||
Loading…
Reference in a new issue