mlpIPELINEabc - НОВЫЙ МОДУЛЬ

DataPipeline - закончен
This commit is contained in:
Mikhalkovich Stanislav 2026-02-26 22:40:34 +03:00
parent f834ed4ea9
commit 398ea2440f
13 changed files with 555 additions and 195 deletions

View file

@ -15,7 +15,7 @@ internal static class RevisionClass
public const string Major = "3";
public const string Minor = "11";
public const string Build = "1";
public const string Revision = "3764";
public const string Revision = "3765";
public const string MainVersion = Major + "." + Minor;
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;

View file

@ -1,4 +1,4 @@
%COREVERSION%=1
%REVISION%=3764
%MINOR%=11
%REVISION%=3765
%COREVERSION%=1
%MAJOR%=3

View file

@ -1 +1 @@
3.11.1.3764
3.11.1.3765

View file

@ -1 +1 @@
!define VERSION '3.11.1.3764'
!define VERSION '3.11.1.3765'

View file

@ -21,7 +21,7 @@ uses
TasksArr, TasksMatr, TasksStr, Tasks1Begin, Tasks1BoolIfCase, Tasks1Loops, Tasks1Arr,
WPF,
DataFrameABC, DataFrameABCCore, LinearAlgebraML, PreprocessorABC,
MetricsABC, MLABC, MLCoreABC, MLModelsABC, ValidationML, MLExceptions, InspectionML
MetricsABC, MLABC, MLCoreABC, MLModelsABC, ValidationML, MLExceptions, InspectionML, MLPipelineABC
;
begin

View file

@ -11,7 +11,7 @@
ABCDatabases,
School, SF, TurtleABC,
DataFrameABC, DataFrameABCCore, LinearAlgebraML, PreprocessorABC,
MetricsABC, MLABC, MLCoreABC, MLModelsABC, ValidationML, MLExceptions, InspectionML
MetricsABC, MLABC, MLCoreABC, MLModelsABC, ValidationML, MLExceptions, InspectionML, MLPipelineABC
;
begin

View file

@ -190,6 +190,7 @@
File ..\bin\Lib\ValidationML.pcu
File ..\bin\Lib\MLExceptions.pcu
File ..\bin\Lib\InspectionML.pcu
File ..\bin\Lib\MLPipelineABC.pcu
File ..\bin\Lib\PABCRtl.dll
File ..\bin\Lib\HelixToolkit.Wpf.dll
@ -294,6 +295,7 @@
${AddFile} "ValidationML.pcu"
${AddFile} "MLExceptions.pcu"
${AddFile} "InspectionML.pcu"
${AddFile} "MLPipelineABC.pcu"
${AddFile} "turtle.png"
@ -435,6 +437,7 @@
File ..\bin\Lib\ValidationML.pas
File ..\bin\Lib\MLExceptions.pas
File ..\bin\Lib\InspectionML.pas
File ..\bin\Lib\MLPipelineABC.pas
File ..\bin\Lib\__RedirectIOMode.vb
File ..\bin\Lib\VBSystem.vb
@ -526,6 +529,8 @@
${AddFile} "ValidationML.pas"
${AddFile} "MLExceptions.pas"
${AddFile} "InspectionML.pas"
${AddFile} "MLPipelineABC.pas"
${AddFile} "__RedirectIOMode.vb"
${AddFile} "VBSystem.vb"

View file

@ -119,6 +119,9 @@ copy bin\Lib\MLABC.pcu Release\PascalABCNETLinux\Lib\MLABC.pcu
copy bin\Lib\MLCoreABC.pcu Release\PascalABCNETLinux\Lib\MLCoreABC.pcu
copy bin\Lib\MLModelsABC.pcu Release\PascalABCNETLinux\Lib\MLModelsABC.pcu
copy bin\Lib\ValidationML.pcu Release\PascalABCNETLinux\Lib\ValidationML.pcu
copy bin\Lib\MLExceptions.pcu Release\PascalABCNETLinux\Lib\MLExceptions.pcu
copy bin\Lib\InspectionML.pcu Release\PascalABCNETLinux\Lib\InspectionML.pcu
copy bin\Lib\MLPipelineABC.pcu Release\PascalABCNETLinux\Lib\MLPipelineABC.pcu
copy bin\Lib\ABCDatabases.pas Release\PascalABCNETLinux\LibSource\ABCDatabases.pas
copy bin\Lib\BBCMicrobit.pas Release\PascalABCNETLinux\LibSource\BBCMicrobit.pas
@ -169,6 +172,10 @@ copy bin\Lib\MLABC.pas Release\PascalABCNETLinux\LibSource\MLABC.pas
copy bin\Lib\MLCoreABC.pas Release\PascalABCNETLinux\LibSource\MLCoreABC.pas
copy bin\Lib\MLModelsABC.pas Release\PascalABCNETLinux\LibSource\MLModelsABC.pas
copy bin\Lib\ValidationML.pas Release\PascalABCNETLinux\LibSource\ValidationML.pas
copy bin\Lib\MLExceptions.pas Release\PascalABCNETLinux\LibSource\MLExceptions.pas
copy bin\Lib\InspectionML.pas Release\PascalABCNETLinux\LibSource\InspectionML.pas
copy bin\Lib\MLPipelineABC.pas Release\PascalABCNETLinux\LibSource\MLPipelineABC.pas
copy bin\Lng\Eng\.LanguageName Release\PascalABCNETLinux\Lng\Eng\.LanguageName
copy bin\Lng\Eng\AspectsTree.dat Release\PascalABCNETLinux\Lng\Eng\AspectsTree.dat

View file

@ -6,24 +6,31 @@ interface
uses LinearAlgebraML;
uses ValidationML;
uses MLCoreABC;
uses MLModelsABC;
uses MetricsABC;
uses PreprocessorABC;
uses DataFrameABC;
uses MLExceptions;
uses InspectionML;
uses MLPipelineABC;
type
Vector = LinearAlgebraML.Vector;
Matrix = LinearAlgebraML.Matrix;
Validation = ValidationML.Validation;
ConfusionMatrix = MetricsABC.ConfusionMatrix;
Metrics = MetricsABC.Metrics;
DataPipeline = PreprocessorABC.DataPipeline;
DataStandardScaler = PreprocessorABC.DataStandardScaler;
DataPipeline = MLPipelineABC.DataPipeline;
DataFrame = DataFrameABC.DataFrame;
Statistics = DataFrameABC.Statistics;
CsvLoader = DataFrameABC.CsvLoader;
IProbabilisticClassifier = MLCoreABC.IProbabilisticClassifier;
StandardScaler = MLModelsABC.StandardScaler;
PCATransformer = MLModelsABC.PCATransformer;
@ -63,60 +70,5 @@ type
implementation
const
ER_TO_MATRIX_NO_COLUMNS =
'ToMatrix: не указаны столбцы!!ToMatrix: no columns specified';
ER_TO_VECTOR_NON_NUMERIC =
'ToVector: столбец "{0}" содержит нечисловые или NA значения!!' +
'ToVector: column "{0}" contains non-numeric or NA values';
function ToMatrix(Self: DataFrame; colNames: array of string): Matrix; extensionmethod;
begin
var df := Self;
var n := df.RowCount;
var p := colNames.Length;
if p = 0 then
ArgumentError(ER_TO_MATRIX_NO_COLUMNS);
Result := new Matrix(n, p);
for var j := 0 to p - 1 do
begin
var col := df[colNames[j]];
for var i := 0 to n - 1 do
begin
var value: real;
if not col.TryGetNumericValue(i, value) then
raise new Exception(
'ToMatrix: column "' + colNames[j] +
'" contains non-numeric or NA values');
Result[i,j] := value;
end;
end;
end;
function ToVector(Self: DataFrame; colName: string): Vector; extensionmethod;
begin
var df := Self;
var n := df.RowCount;
Result := new Vector(n);
var col := df[colName];
for var i := 0 to n - 1 do
begin
var value: real;
if not col.TryGetNumericValue(i, value) then
ArgumentError(ER_TO_VECTOR_NON_NUMERIC, colName);
Result[i] := value;
end;
end;
end.

View file

@ -5,13 +5,24 @@ interface
uses LinearAlgebraML;
type
/// Базовый интерфейс шага конвейера машинного обучения.
/// Используется для объединения преобразователей и моделей
/// в единую последовательность выполнения внутри Pipeline.
IPipeStep = interface end;
/// Базовый интерфейс шага конвейера машинного обучения.
/// Используется для объединения всех типов шагов
/// (DataFrame-преобразователей, матричных трансформеров и моделей)
/// в единую последовательность выполнения внутри различных Pipeline
IPipelineStep = interface end;
/// Интерфейс шага конвейера, работающего в числовом (матричном) пространстве.
/// Реализуется трансформерами и моделями, которые принимают на вход Matrix и Vector
/// и используются в Matrix-уровне Pipeline
IMatrixStep = interface(IPipelineStep) end;
/// Интерфейс шага конвейера, работающего на уровне DataFrame.
/// Реализуется препроцессорами, которые выполняют преобразования табличных данных
/// до перехода в числовое (Matrix) представление
IDataStep = interface(IPipelineStep) end;
/// Базовый интерфейс модели машинного обучения
IModel = interface(IPipeStep)
IModel = interface(IMatrixStep)
function Fit(X: Matrix; y: Vector): IModel;
function Predict(X: Matrix): Vector;
function Clone: IModel;
@ -36,8 +47,12 @@ type
/// Позволяет получать значения в диапазоне (0, 1)
/// вместо только итогового решения.
IProbabilisticClassifier = interface(IClassifier)
/// Возвращает вероятность принадлежности к положительному классу для каждого объекта.
/// Возвращает матрицу вероятностей размера (nSamples × nClasses).
/// Столбцы соответствуют классам в порядке внутреннего кодирования модели
function PredictProba(X: Matrix): Matrix;
/// Возвращает массив меток классов в порядке столбцов PredictProba.
function GetClasses: array of real;
end;
/// Интерфейс регрессионной модели.
@ -49,7 +64,7 @@ type
/// Базовый интерфейс преобразования признаков.
/// Используется для масштабирования, отбора,
/// уменьшения размерности и других преобразований данных.
ITransformer = interface(IPipeStep)
ITransformer = interface(IMatrixStep)
/// Обучает преобразование на данных.
/// Запоминает необходимые параметры,
/// которые будут использоваться при Transform.

View file

@ -223,6 +223,9 @@ type
/// Возвращает матрицу вероятностей (m x k).
function PredictProba(X: Matrix): Matrix;
/// Возвращает массив меток классов в порядке столбцов PredictProba.
function GetClasses: array of real;
/// Возвращает вектор предсказанных классов.
function Predict(X: Matrix): Vector;
@ -905,6 +908,8 @@ type
/// Вероятности получаются через softmax.
function PredictProba(X: Matrix): Matrix;
function GetClasses: array of real;
/// Создает глубокую копию классификатора.
/// Копируются все деревья и внутреннее состояние.
function Clone: IModel;
@ -949,8 +954,14 @@ type
idx: integer;
end;
/// Режим взвешивания в алгоритме k ближайших соседей.
/// Uniform — равномерное голосование/усреднение.
/// Distance — веса обратно пропорциональны расстоянию (1 / dist)
KNNWeighting = (Uniform, Distance);
/// Базовый абстрактный класс для алгоритма k ближайших соседей (kNN).
/// Реализует общий механизм поиска k ближайших объектов,
/// но не определяет способ агрегации (классификация или регрессия)
KNNBase = abstract class(IModel)
protected
// ==== train state ====
@ -973,14 +984,26 @@ type
function Partition(left, right: integer): integer;
public
/// Создаёт модель kNN.
/// k — число ближайших соседей (k > 0).
/// weighting — режим взвешивания соседей
constructor Create(k: integer; weighting: KNNWeighting := KNNWeighting.Uniform);
/// Обучает модель на матрице признаков X и целевом векторе y.
/// Возвращает текущий экземпляр модели
function Fit(X: Matrix; y: Vector): IModel; virtual; abstract;
/// Выполняет предсказание для матрицы признаков X.
/// Возвращает вектор предсказанных значений или меток
function Predict(X: Matrix): Vector; virtual; abstract;
/// Создаёт глубокую копию модели
function Clone: IModel; virtual; abstract;
end;
/// Классификатор на основе алгоритма k ближайших соседей (kNN).
/// Поддерживает равномерное (Uniform) и взвешенное по расстоянию (Distance) голосование.
/// Реализует вероятностные предсказания через PredictProba
KNNClassifier = class(KNNBase, IProbabilisticClassifier)
private
// ==== classification state ====
@ -997,27 +1020,57 @@ type
procedure EncodeClasses(y: Vector);
public
/// Создаёт классификатор kNN.
/// k — число ближайших соседей (k > 0).
/// weighting — режим взвешивания голосов соседей
constructor Create(k: integer; weighting: KNNWeighting := KNNWeighting.Uniform);
/// Обучает модель на матрице признаков X и векторе меток y.
/// Метки классов могут быть произвольными числами.
/// Возвращает текущий экземпляр модели
function Fit(X: Matrix; y: Vector): IModel; override;
/// Выполняет предсказание меток классов для объектов X.
/// Возвращает вектор предсказанных меток
function Predict(X: Matrix): Vector; override;
/// Возвращает матрицу вероятностей размера (nSamples × nClasses).
/// Столбцы соответствуют классам в порядке, возвращаемом GetClasses()
function PredictProba(X: Matrix): Matrix;
function GetClasses: array of double;
/// Возвращает массив меток классов в порядке столбцов PredictProba
function GetClasses: array of real;
/// Создаёт глубокую копию классификатора
function Clone: IModel; override;
end;
/// Регрессор на основе алгоритма k ближайших соседей (kNN).
/// Поддерживает равномерное (Uniform) усреднение и взвешенное по расстоянию (Distance) усреднение.
/// Предсказание вычисляется как среднее (или взвешенное среднее) значений целевой переменной
/// по k ближайшим обучающим объектам
KNNRegressor = class(KNNBase, IRegressor)
private
fYTrain: Vector;
public
/// Создаёт регрессор kNN.
/// k — число ближайших соседей (k > 0).
/// weighting — режим взвешивания вкладов соседей
constructor Create(k: integer; weighting: KNNWeighting := KNNWeighting.Uniform);
/// Обучает модель на матрице признаков X и целевом векторе y.
/// Возвращает текущий экземпляр модели
function Fit(X: Matrix; y: Vector): IModel; override;
/// Выполняет предсказание числовых значений для объектов X.
/// Возвращает вектор предсказанных значений
function Predict(X: Matrix): Vector; override;
/// Создаёт глубокую копию регрессора
function Clone: IModel; override;
end;
{$endregion Models}
{$region Pipeline}
@ -1032,7 +1085,7 @@ type
///
/// Обеспечивает единый интерфейс Fit / Predict
/// и воспроизводимость полного процесса обучения
Pipeline = class(IModel)
Pipeline = class(IModel, IProbabilisticClassifier)
private
fTransformers: List<ITransformer>;
fModel: IModel;
@ -1052,7 +1105,7 @@ type
/// сначала преобразователи, затем модель.
/// Последний шаг обязан быть моделью (IModel).
/// Возвращает сконструированный конвейер.
static function Build(params steps: array of IPipeStep): Pipeline;
static function Build(params steps: array of IPipelineStep): Pipeline;
/// Устанавливает или заменяет модель.
function SetModel(m: IModel): Pipeline;
@ -1072,6 +1125,8 @@ type
/// Возвращает матрицу вероятностей (m x k)
/// для вероятностной модели в конце пайплайна.
function PredictProba(X: Matrix): Matrix;
function GetClasses: array of real;
/// Показывает, был ли пайплайн обучен (вызван метод Fit).
property IsFitted: boolean read fFitted;
@ -1080,6 +1135,7 @@ type
function Clone: IModel;
end;
{$endregion Pipeline}
{$region Transformers}
@ -1922,6 +1978,13 @@ begin
Result := Z;
end;
function LogisticRegression.GetClasses: array of real;
begin
SetLength(Result, fClassCount);
for var i := 0 to fClassCount - 1 do
Result[i] := fIndexToClass[i];
end;
function LogisticRegression.Predict(X: Matrix): Vector;
begin
if not fFitted then
@ -4328,6 +4391,13 @@ begin
Result := probs;
end;
function GradientBoostingClassifier.GetClasses: array of real;
begin
SetLength(Result, fClassCount);
for var i := 0 to fClassCount - 1 do
Result[i] := fClasses[i];
end;
function GradientBoostingClassifier.PredictStageProba(
X: Matrix; m: integer): Matrix;
begin
@ -4724,7 +4794,7 @@ begin
exit(self);
end;
function KNNClassifier.GetClasses: array of double;
function KNNClassifier.GetClasses: array of real;
begin
Result := fClasses;
end;
@ -5117,7 +5187,7 @@ begin
fModel := model;
end;
class function Pipeline.Build(params steps: array of IPipeStep): Pipeline;
class function Pipeline.Build(params steps: array of IPipelineStep): Pipeline;
begin
if (steps = nil) or (Length(steps) = 0) then
ArgumentError(ER_PIPELINE_NO_STEPS);
@ -5220,6 +5290,14 @@ 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 (' +
@ -5250,6 +5328,8 @@ begin
p.Add(t.Clone);
p.SetModel(fModel.Clone);
p.fFitted := fFitted;
Result := p;
end;

372
bin/Lib/MLPipelineABC.pas Normal file
View file

@ -0,0 +1,372 @@
unit MLPipelineABC;
interface
uses MLCoreABC;
uses PreprocessorABC;
uses DataFrameABC;
uses LinearAlgebraML;
type
/// DataPipeline — конвейер подготовки данных и обучения модели на DataFrame.
/// Поддерживает два уровня шагов:
/// • DataFrame-уровень: IPreprocessor (Fit/Transform над DataFrame)
/// • Matrix-уровень: ITransformer + IModel (после преобразования DataFrame → Matrix/Vector)
///
/// Правила порядка шагов:
/// • Сначала идут только DataFrame-шаги (IPreprocessor).
/// • Затем — матричные шаги (ITransformer).
/// • Модель (IModel) добавляется последней и может быть только одна.
///
/// Если модель не добавлена, DataPipeline работает как чистый DF-конвейер (Fit/Transform/FitTransform)
DataPipeline = class
private
fDataSteps: List<IPreprocessor>;
fMatrixSteps: List<ITransformer>;
fModel: IModel;
fTarget: string;
fFeatures: array of string;
fFitted: boolean;
procedure ValidateSchema(df: DataFrame);
public
/// Создаёт пустой конвейер
constructor Create;
/// Добавляет шаг в конец конвейера.
/// Принимает:
/// • IPreprocessor (DataFrame-уровень)
/// • ITransformer (Matrix-уровень)
/// • IModel (модель, должна быть последней)
/// Запрещено добавлять шаги после вызова Fit/FitTransform.
function Add(step: IPipelineStep): DataPipeline;
/// Строит конвейер из последовательности шагов.
/// target и features используются только в режиме с моделью (когда в шагах присутствует IModel).
/// Шаги должны удовлетворять порядку: DataFrame* → Matrix* → Model.
class function Build(target: string; features: array of string;
params steps: array of IPipelineStep): DataPipeline;
/// Обучает конвейер на DataFrame.
/// Семантика:
/// • выполняет Fit/Transform для всех DataFrame-шагов;
/// • если присутствует модель — преобразует DataFrame в (X, y) по features/target,
/// затем обучает матричные трансформеры и модель.
function Fit(df: DataFrame): DataPipeline;
/// Применяет обученные DataFrame-шаги к DataFrame и возвращает новый DataFrame.
/// В ML-режиме Transform не выполняет матричные шаги и не вызывает модель.
function Transform(df: DataFrame): DataFrame;
/// Выполняет Fit и Transform за один проход для DataFrame-режима.
/// Недоступен, если конвейер содержит модель (IModel).
function FitTransform(df: DataFrame): DataFrame;
/// Делает предсказание модели для объектов из DataFrame.
/// Доступен только если конвейер содержит модель (IModel) и был обучен (Fit).
function Predict(df: DataFrame): Vector;
/// Возвращает матрицу вероятностей (nSamples × nClasses).
/// Доступен только если конечная модель поддерживает IProbabilisticClassifier.
function PredictProba(df: DataFrame): Matrix;
/// Возвращает список классов в порядке столбцов PredictProba.
/// Доступен только если конечная модель поддерживает IProbabilisticClassifier.
function GetClasses: array of real;
/// Признак того, что был вызван Fit или FitTransform.
property IsFitted: boolean read fFitted;
end;
implementation
uses MLExceptions;
const
ER_PIPELINE_MODIFY_AFTER_FIT =
'Нельзя добавлять шаг после вызова Fit()!!Cannot add step after Fit';
ER_PIPELINE_STEP_NULL =
'Шаг конвейера не может быть nil!!Pipeline step cannot be nil';
ER_DATAPIPE_DF_AFTER_MATRIX =
'Шаг DataFrame не может идти после матричных шагов!!DataFrame step cannot appear after matrix steps';
ER_PIPELINE_MULTIPLE_MODELS =
'В конвейере разрешена только одна модель!!Only one model is allowed in the pipeline';
ER_DATAPIPE_MATRIX_AFTER_MODEL =
'Матричный шаг не может идти после модели!!Matrix step cannot appear after the model';
ER_DATAPIPE_UNKNOWN_STEP =
'Неизвестный тип шага конвейера!!Unknown pipeline step type';
ER_TO_MATRIX_NO_COLUMNS =
'ToMatrix: не указаны столбцы!!ToMatrix: no columns specified';
ER_TO_VECTOR_NON_NUMERIC =
'ToVector: столбец "{0}" содержит нечисловые или NA значения!!' +
'ToVector: column "{0}" contains non-numeric or NA values';
ER_FITTRANSFORM_WITH_MODEL =
'FitTransform недоступен, если конвейер содержит модель!!FitTransform is not available when the pipeline contains a model';
ER_PROBA_NOT_SUPPORTED =
'Модель не поддерживает предсказание вероятностей!!Model does not support probability prediction';
ER_TARGET_EMPTY =
'Имя целевой переменной не задано!!Target column name is not specified';
ER_FEATURES_EMPTY =
'Список признаков пуст!!Feature list must not be empty';
ER_DATAPIPE_TARGET_IN_FEATURES =
'Целевая переменная не должна входить в список признаков!!Target column must not be included in feature list';
ER_TO_MATRIX_NON_NUMERIC =
'Столбец "{0}" содержит нечисловые или NA значения!!Column "{0}" contains non-numeric or NA values';
ER_DATAPIPE_TARGET_NOT_FOUND =
'Целевой столбец "{0}" не найден!!Target column "{0}" not found';
ER_DATAPIPE_FEATURE_NOT_FOUND =
'Столбец признака "{0}" не найден!!Feature column "{0}" not found';
function ToMatrix(Self: DataFrame; colNames: array of string): Matrix; extensionmethod;
begin
var df := Self;
var n := df.RowCount;
var p := colNames.Length;
if p = 0 then
ArgumentError(ER_TO_MATRIX_NO_COLUMNS);
Result := new Matrix(n, p);
for var j := 0 to p - 1 do
begin
var col := df[colNames[j]];
for var i := 0 to n - 1 do
begin
var value: real;
if not col.TryGetNumericValue(i, value) then
ArgumentError(ER_TO_MATRIX_NON_NUMERIC, colNames[j]);
Result[i,j] := value;
end;
end;
end;
function ToVector(Self: DataFrame; colName: string): Vector; extensionmethod;
begin
var df := Self;
var n := df.RowCount;
Result := new Vector(n);
var col := df[colName];
for var i := 0 to n - 1 do
begin
var value: real;
if not col.TryGetNumericValue(i, value) then
ArgumentError(ER_TO_VECTOR_NON_NUMERIC, colName);
Result[i] := value;
end;
end;
//-----------------------------
// DataPipeline
//-----------------------------
constructor DataPipeline.Create;
begin
fDataSteps := new List<IPreprocessor>;
fMatrixSteps := new List<ITransformer>;
fModel := nil;
fTarget := '';
fFeatures := nil;
fFitted := false;
end;
function DataPipeline.Add(step: IPipelineStep): DataPipeline;
begin
if step = nil then
ArgumentError(ER_PIPELINE_STEP_NULL);
if fFitted then
Error(ER_PIPELINE_MODIFY_AFTER_FIT);
if step is IDataStep then
begin
if (fMatrixSteps.Count > 0) or (fModel <> nil) then
ArgumentError(ER_DATAPIPE_DF_AFTER_MATRIX);
fDataSteps.Add(step as IPreprocessor);
exit(Self);
end;
if step is IMatrixStep then
begin
if step is IModel then
begin
if fModel <> nil then
ArgumentError(ER_PIPELINE_MULTIPLE_MODELS);
fModel := step as IModel;
exit(Self);
end;
if fModel <> nil then
ArgumentError(ER_DATAPIPE_MATRIX_AFTER_MODEL);
fMatrixSteps.Add(step as ITransformer);
exit(Self);
end;
ArgumentError(ER_DATAPIPE_UNKNOWN_STEP);
Result := Self;
end;
class function DataPipeline.Build(target: string;
features: array of string; params steps: array of IPipelineStep): DataPipeline;
begin
var p := new DataPipeline;
p.fTarget := target;
p.fFeatures := features;
for var i := 0 to High(steps) do
p.Add(steps[i]);
Result := p;
end;
function DataPipeline.Fit(df: DataFrame): DataPipeline;
begin
var current := df;
// 1) DataFrame слой (с сохранением fitted-объектов)
for var i := 0 to fDataSteps.Count - 1 do
begin
fDataSteps[i] := fDataSteps[i].Fit(current);
current := fDataSteps[i].Transform(current);
end;
// DF-only режим
if fModel = nil then
begin
fFitted := true;
exit(Self);
end;
// 2) Проверка схемы
ValidateSchema(current);
// 3) Split
var X := current.ToMatrix(fFeatures);
var y := current.ToVector(fTarget);
// 4) Matrix слой (с сохранением fitted-объектов)
for var i := 0 to fMatrixSteps.Count - 1 do
begin
var t := fMatrixSteps[i];
if t is ISupervisedTransformer (var sup) then
fMatrixSteps[i] := sup.Fit(X, y)
else
fMatrixSteps[i] := t.Fit(X);
X := fMatrixSteps[i].Transform(X);
end;
// 5) Модель
fModel.Fit(X, y);
fFitted := true;
Result := Self;
end;
function DataPipeline.Transform(df: DataFrame): DataFrame;
begin
if not fFitted then
NotFittedError(ER_FIT_NOT_CALLED);
var current := df;
foreach var s in fDataSteps do
current := s.Transform(current);
Result := current;
end;
function DataPipeline.FitTransform(df: DataFrame): DataFrame;
begin
if fModel <> nil then
ArgumentError(ER_FITTRANSFORM_WITH_MODEL);
var current := df;
for var i := 0 to fDataSteps.Count - 1 do
begin
fDataSteps[i] := fDataSteps[i].Fit(current);
current := fDataSteps[i].Transform(current);
end;
fFitted := true;
Result := current;
end;
function DataPipeline.Predict(df: DataFrame): Vector;
begin
if not fFitted then
NotFittedError(ER_FIT_NOT_CALLED);
if fModel = nil then
ArgumentError(ER_MODEL_NULL);
var current := Transform(df);
var X := current.ToMatrix(fFeatures);
foreach var t in fMatrixSteps do
X := t.Transform(X);
Result := fModel.Predict(X);
end;
function DataPipeline.PredictProba(df: DataFrame): Matrix;
begin
if not fFitted then
NotFittedError(ER_FIT_NOT_CALLED);
if not (fModel is IProbabilisticClassifier) then
Error(ER_PROBA_NOT_SUPPORTED);
var current := Transform(df);
var X := current.ToMatrix(fFeatures);
foreach var t in fMatrixSteps do
X := t.Transform(X);
Result := (fModel as IProbabilisticClassifier).PredictProba(X);
end;
function DataPipeline.GetClasses: array of real;
begin
if not (fModel is IProbabilisticClassifier) then
ArgumentError(ER_PROBA_NOT_SUPPORTED);
Result := (fModel as IProbabilisticClassifier).GetClasses;
end;
procedure DataPipeline.ValidateSchema(df: DataFrame);
begin
if fTarget = '' then
ArgumentError(ER_TARGET_EMPTY);
if (fFeatures = nil) or (Length(fFeatures) = 0) then
ArgumentError(ER_FEATURES_EMPTY);
for var i := 0 to High(fFeatures) do
if fFeatures[i] = fTarget then
ArgumentError(ER_DATAPIPE_TARGET_IN_FEATURES);
if not df.Schema.HasColumn(fTarget) then
ArgumentError(ER_DATAPIPE_TARGET_NOT_FOUND, fTarget);
for var i := 0 to High(fFeatures) do
if not df.Schema.HasColumn(fFeatures[i]) then
ArgumentError(ER_DATAPIPE_FEATURE_NOT_FOUND, fFeatures[i]);
end;
end.

View file

@ -22,11 +22,12 @@ interface
uses DataFrameABC;
uses System;
uses MLCoreABC;
type
/// Базовый интерфейс шагов подготовки данных.
/// Определяет семантику операций Fit и Transform
IPreprocessor = interface
IPreprocessor = interface(IDataStep)
/// Анализирует DataFrame и и сохраняет параметры шага
function Fit(df: DataFrame): IPreprocessor;
/// Применяет сохранённые параметры к DataFrame.
@ -36,50 +37,6 @@ type
function FitTransform(df: DataFrame): DataFrame;
end;
/// Приводит числовые столбцы к нулевому среднему и единичному стандартному отклонению.
/// При Fit вычисляет среднее значение и стандартное отклонение столбцов.
/// Применяет преобразование: x' = (x - mean) / std.
/// Пропущенные значения (NA) сохраняются.
DataStandardScaler = class(IPreprocessor)
private
cols: array of string;
means: array of real;
stds: array of real;
fitted: boolean;
public
/// Создаёт StandardScaler для указанных числовых столбцов.
constructor Create(params columns: array of string);
/// Вычисляет среднее значение и стандартное отклонение для каждого столбца.
function Fit(df: DataFrame): IPreprocessor;
/// Возвращает DataFrame со стандартизованными числовыми столбцами.
function Transform(df: DataFrame): DataFrame;
/// Последовательно выполняет Fit и Transform.
function FitTransform(df: DataFrame): DataFrame;
end;
/// Приводит числовые столбцы к заданному диапазону значений
/// При Fit вычисляет минимальное и максимальное значения столбцов
/// Применяет преобразование: x' = (x - min) / (max - min)
/// Пропущенные значения (NA) сохраняются
DataMinMaxScaler = class(IPreprocessor)
private
cols: array of string;
mins: array of real;
maxs: array of real;
fitted: boolean;
public
/// Создаёт MinMaxScaler для указанных столбцов
constructor Create(params columns: array of string);
/// Вычисляет минимальные и максимальные значения столбцов
function Fit(df: DataFrame): IPreprocessor;
/// Применяет масштабирование к DataFrame
/// Возвращает новый DataFrame
function Transform(df: DataFrame): DataFrame;
/// Последовательно выполняет Fit и Transform.
function FitTransform(df: DataFrame): DataFrame;
end;
/// Кодирует строковый категориальный столбец в числовые значения
/// Категории фиксируются при Fit
/// Работает только со строковыми столбцами
@ -150,26 +107,51 @@ type
/// Выполняет Fit и Transform последовательно
function FitTransform(df: DataFrame): DataFrame;
end;
type
/// DataPipeline (конвейер) шагов подготовки данных.
/// Выполняет шаги последовательно с семантикой Fit / Transform.
DataPipeline = class
{/// Приводит числовые столбцы к нулевому среднему и единичному стандартному отклонению.
/// При Fit вычисляет среднее значение и стандартное отклонение столбцов.
/// Применяет преобразование: x' = (x - mean) / std.
/// Пропущенные значения (NA) сохраняются.
DataStandardScaler = class(IPreprocessor)
private
steps: List<IPreprocessor>;
cols: array of string;
means: array of real;
stds: array of real;
fitted: boolean;
public
constructor;
/// Добавляет шаг в конец pipeline
function Add(p: IPreprocessor): DataPipeline;
/// Обучает все шаги pipeline на DataFrame
function Fit(df: DataFrame): DataPipeline;
/// Применяет обученный pipeline к DataFrame
/// Создаёт StandardScaler для указанных числовых столбцов.
constructor Create(params columns: array of string);
/// Вычисляет среднее значение и стандартное отклонение для каждого столбца.
function Fit(df: DataFrame): IPreprocessor;
/// Возвращает DataFrame со стандартизованными числовыми столбцами.
function Transform(df: DataFrame): DataFrame;
/// Выполняет Fit и Transform последовательно
/// Последовательно выполняет Fit и Transform.
function FitTransform(df: DataFrame): DataFrame;
end;
/// Приводит числовые столбцы к заданному диапазону значений
/// При Fit вычисляет минимальное и максимальное значения столбцов
/// Применяет преобразование: x' = (x - min) / (max - min)
/// Пропущенные значения (NA) сохраняются
DataMinMaxScaler = class(IPreprocessor)
private
cols: array of string;
mins: array of real;
maxs: array of real;
fitted: boolean;
public
/// Создаёт MinMaxScaler для указанных столбцов
constructor Create(params columns: array of string);
/// Вычисляет минимальные и максимальные значения столбцов
function Fit(df: DataFrame): IPreprocessor;
/// Применяет масштабирование к DataFrame
/// Возвращает новый DataFrame
function Transform(df: DataFrame): DataFrame;
/// Последовательно выполняет Fit и Transform.
function FitTransform(df: DataFrame): DataFrame;
end;}
implementation
@ -233,14 +215,12 @@ const
ER_IMPUTER_CONSTANT_TYPE_MISMATCH =
'Imputer(constant): несоответствие типа значения для столбца "{0}"!!' +
'Imputer(constant): value type mismatch for column "{0}"';
ER_PIPELINE_MODIFY_AFTER_FIT =
'Нельзя добавлять шаг после вызова Fit()!!Cannot add step after Fit';
//-----------------------------
// StandardScaler
//-----------------------------
constructor DataStandardScaler.Create(params columns: array of string);
{constructor DataStandardScaler.Create(params columns: array of string);
begin
if (columns = nil) or (columns.Length = 0) then
ArgumentError(ER_SCALER_NO_COLUMNS);
@ -420,7 +400,7 @@ function DataMinMaxScaler.FitTransform(df: DataFrame): DataFrame;
begin
Fit(df);
Result := Transform(df);
end;
end;}
//-----------------------------
// LabelEncoder
@ -733,56 +713,5 @@ begin
Result := Transform(df);
end;
//-----------------------------
// Pipeline
//-----------------------------
constructor DataPipeline.Create;
begin
steps := new List<IPreprocessor>;
fitted := false;
end;
function DataPipeline.Add(p: IPreprocessor): DataPipeline;
begin
if fitted then
Error(ER_PIPELINE_MODIFY_AFTER_FIT);
steps.Add(p);
Result := Self;
end;
function DataPipeline.Fit(df: DataFrame): DataPipeline;
begin
var current := df;
for var i := 0 to steps.Count - 1 do
begin
steps[i] := steps[i].Fit(current);
current := steps[i].Transform(current);
end;
fitted := true;
Result := Self;
end;
function DataPipeline.Transform(df: DataFrame): DataFrame;
begin
if not fitted then
NotFittedError(ER_FIT_NOT_CALLED);
var current := df;
foreach var step in steps do
current := step.Transform(current);
Result := current;
end;
function DataPipeline.FitTransform(df: DataFrame): DataFrame;
begin
Fit(df);
Result := Transform(df);
end;
end.