Правки ML

This commit is contained in:
Mikhalkovich Stanislav 2026-04-27 09:34:44 +03:00
parent be48d378be
commit a5a96bc68c
17 changed files with 380 additions and 952 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 = "3810";
public const string Revision = "3812";
public const string MainVersion = Major + "." + Minor;
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;

View file

@ -1,4 +1,4 @@
%COREVERSION%=1
%REVISION%=3810
%REVISION%=3812
%MINOR%=11
%MAJOR%=3

View file

@ -1 +1 @@
3.11.1.3810
3.11.1.3812

View file

@ -1 +1 @@
!define VERSION '3.11.1.3810'
!define VERSION '3.11.1.3812'

View file

@ -292,7 +292,7 @@ namespace PascalABCCompiler.TreeConverter
ccc.parameters.AddRange(exprs);
return ccc;
}
//Метод только для внутнреннего использования.
//Метод только для внутреннего использования.
//НЕ ПРЕОБРАЗУЕТ ТИПЫ. Только создает узел вызова метода.
//Этот метод и используется для создания узлов преобразования типов.
//TODO: Переименовать.

View file

@ -105,15 +105,24 @@ namespace VisualPascalABC
return;
}
mes = Form1StringResources.Get("FILE_CHANGED_MESSAGE");
if (MessageBox.Show(fileName + "\n\n" + mes, Form1StringResources.Get("CHANGED_FILE"), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
WorkbenchServiceFactory.FileService.ReloadFile(fileName);
}
else
{
WorkbenchServiceFactory.FileService.SetFileAsChanged(fileName);
}
//mes = Form1StringResources.Get("FILE_CHANGED_MESSAGE");
var tab = VisualPABCSingleton.MainForm.FindTab(fileName);
if (tab != null)
if (tab.DocumentChanged)
{
if (MessageBox.Show(fileName + "\n\n" + mes, Form1StringResources.Get("CHANGED_FILE"), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
WorkbenchServiceFactory.FileService.ReloadFile(fileName);
}
else
{
WorkbenchServiceFactory.FileService.SetFileAsChanged(fileName);
}
}
else
{
WorkbenchServiceFactory.FileService.ReloadFile(fileName);
}
}
void MainForm_Activated(object sender, EventArgs e)

View file

@ -316,11 +316,16 @@ namespace VisualPascalABC
public void ReloadFile(string FileName)
{
CodeFileDocumentControl tab = FindTab(FileName);
CodeFileDocumentControl tab = FindTab(FileName);
if (tab != null)
{
var CaretLine = tab.TextEditor.CaretLine;
tab.LoadFromFile(FileName);
tab.DocumentChanged = false;
tab.TextEditor.ActiveTextAreaControl.Update();
tab.TextEditor.ActiveTextAreaControl.CenterViewOn(CaretLine + 2, 0);
tab.TextEditor.CaretLine = CaretLine;
SetTabPageText(tab);
}
}

View file

@ -14,9 +14,6 @@ uses LinearAlgebraML;
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';
ER_TO_MATRIX_NON_NUMERIC =
'Столбец "{0}" содержит нечисловые или NA значения!!Column "{0}" contains non-numeric or NA values';
ER_ENCODELABELS_COLUMN_NOT_STRING =
@ -281,4 +278,4 @@ end;
end.
end.

View file

@ -108,7 +108,7 @@ type
/// Столбец целых чисел
IntColumn = class(Column)
// Data и IsValid считаются immutable после создания
Data: array of integer; // Данные столбца
Data: array of integer;
public
constructor Create; begin end;
constructor Create(name: string);
@ -120,7 +120,7 @@ type
/// Столбец вещественных чисел
FloatColumn = class(Column)
Data: array of real; // Данные столбца
Data: array of real;
public
constructor Create; begin end;
constructor Create(name: string);
@ -133,7 +133,7 @@ type
/// Столбец строк
StrColumn = class(Column)
Data: array of string; // Данные столбца
Data: array of string;
public
constructor Create; begin end;
constructor Create(name: string);
@ -142,15 +142,11 @@ type
function TryGetNumericValue(i: integer; var value: real): boolean; override;
/// Возвращает количество строк в столбце
function RowCount: integer; override := Data.Length;
/// Добавляет невалидное (NA) значение в конец столбца
//procedure AppendInvalid; override;
/// Добавляет значение из курсора в указанной позиции
//procedure AppendFromCursor(cur: DataFrameCursor; colIndex: integer); override;
end;
/// Столбец булевых значений
BoolColumn = class(Column)
Data: array of boolean; // Данные столбца
Data: array of boolean;
public
constructor Create; begin end;
constructor Create(name: string);
@ -780,16 +776,21 @@ begin
var n := cols.Length;
colCnt := cols.Length;
SetLength(intAcc, n);
SetLength(floatAcc, n);
SetLength(strAcc, n);
SetLength(boolAcc, n);
SetLength(validAcc, n);
intAcc := new IntAccessor[n];
floatAcc := new FloatAccessor[n];
strAcc := new StrAccessor[n];
boolAcc := new BoolAccessor[n];
validAcc := new ValidAccessor[n];
for var i := 0 to n - 1 do
begin
var col := cols[i];
intAcc[i] := NotInt;
floatAcc[i] := NotFloat;
strAcc[i] := NotStr;
boolAcc[i] := NotBool;
case fSchema.ColumnTypeAt(i) of
ctInt:
begin
@ -806,7 +807,6 @@ begin
validAcc[i] := pos -> c.IsValid[pos];
floatAcc[i] := pos -> c.Data[pos];
intAcc[i] := NotInt;
end;
ctStr:
@ -886,4 +886,4 @@ begin
pos := p;
end;
end.
end.

View file

@ -94,6 +94,7 @@ type
LinearRegression = MLModelsABC.LinearRegression;
LogisticRegression = MLModelsABC.LogisticRegression;
RidgeRegression = MLModelsABC.RidgeRegression;
LassoRegression = MLModelsABC.LassoRegression;
ElasticNet = MLModelsABC.ElasticNet;
DecisionTreeClassifier = MLModelsABC.DecisionTreeClassifier;
DecisionTreeRegressor = MLModelsABC.DecisionTreeRegressor;
@ -148,7 +149,16 @@ const
jkRight = JoinKind.jkRight;
jkFull = JoinKind.jkFull;
/// Преобразует вектор меток классов в массив целых чисел.
/// Значения округляются функцией Round, чтобы устранить
/// возможные небольшие численные ошибки
function LabelsToInts(y: Vector): array of integer;
/// Кодирует строковые метки классов в целочисленные индексы.
/// Каждому уникальному значению присваивается номер 0,1,2,...
/// Порядок кодирования соответствует порядку первого появления меток.
/// Используется при обучении моделей и визуализации.
/// Предполагается, что входные данные уже очищены от пропущенных значений.
function EncodeLabels(labels: array of string): array of integer;
@ -161,4 +171,4 @@ end;
function EncodeLabels(labels: array of string): array of integer := MLUtilsABC.EncodeLabels(labels);
end.
end.

View file

@ -5,6 +5,9 @@ interface
const
ER_DIM_MISMATCH =
'Размерности не совпадают: {0} и {1}!!Dimension mismatch: {0} and {1}';
ER_TO_VECTOR_NON_NUMERIC =
'ToVector: столбец "{0}" содержит нечисловые или NA значения!!' +
'ToVector: column "{0}" contains non-numeric or NA values';
ER_PARAM_VALUES_EMPTY =
'Список paramValues пуст!!paramValues is empty';
ER_EMPTY_DATASET =

View file

@ -10,7 +10,7 @@
///
/// Все алгоритмы работают с числовыми данными:
/// X Matrix (объекты × признаки), y Vector (целевая переменная).
unit MLModelsABC;
unit MLModelsABC;
// =============================================================
// СТАТИСТИЧЕСКОЕ СОГЛАШЕНИЕ (MLModelsABC)
@ -110,20 +110,8 @@ type
function ToString: string; override;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel;
function Name: string := Self.GetType.Name;
@ -135,7 +123,7 @@ type
/// Устойчива к мультиколлинеарности и плохо обусловленным данным.
/// Используется при коррелированных признаках
/// и в задачах, где важна численная стабильность решения
RidgeRegression = class(IRegressor)
RidgeRegression = class(IRegressor)
private
fLambda: real;
fCoef: Vector;
@ -175,22 +163,10 @@ type
/// После вызова Fit значение становится true.
property IsFitted: boolean read fFitted;
function ToString: string; override;
function ToString: string; override;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel;
function Name: string := Self.GetType.Name;
@ -255,20 +231,8 @@ type
function ToString: string; override;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel;
function Name: string := Self.GetType.Name;
@ -310,20 +274,8 @@ type
/// Возвращает вектор предсказаний длины nSamples.
function Predict(X: Matrix): Vector;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel;
/// Показывает, была ли модель обучена.
@ -421,20 +373,8 @@ type
function GetClassLabels: array of string;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel;
end;
@ -573,13 +513,6 @@ type
function FindBestSplit(X: Matrix; y: Vector; indices: array of integer;
var bestF: integer; var bestT: real): boolean;
procedure Split(
X: Matrix; y: Vector;
f: integer; t: real;
var Xl: Matrix; var yl: Vector;
var Xr: Matrix; var yr: Vector
);
function MajorityClass(y: Vector; indices: array of integer): integer;
public
property FeatureImportances: Vector read GetFeatureImportances;
@ -656,20 +589,8 @@ type
/// Для классификации метки классов.
function Predict(X: Matrix): Vector; virtual; abstract;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel; virtual; abstract;
/// Возвращает true, если дерево обучено.
@ -748,20 +669,8 @@ type
/// Если false Predict вызовет ошибку.
property IsFitted: boolean read fFitted;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel;
end;
@ -816,20 +725,8 @@ type
/// Возвращает вектор вещественных значений.
function Predict(X: Matrix): Vector; override;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel; override;
/// Возвращает строковое представление модели.
@ -925,20 +822,8 @@ type
/// В классификации голосование (majority vote) или усреднение вероятностей.
function Predict(X: Matrix): Vector; virtual; abstract;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel; virtual; abstract;
/// Возвращает вектор важности признаков.
@ -994,20 +879,8 @@ type
/// Итоговое значение среднее предсказаний всех деревьев ансамбля.
function Predict(X: Matrix): Vector; override;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel; override;
/// Возвращает усредненную важность признаков по всем деревьям ансамбля.
@ -1075,20 +948,8 @@ type
/// Требует предварительного вызова Fit.
function PredictProba(X: Matrix): Matrix;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel; override;
/// Возвращает усредненную важность признаков по всем деревьям ансамбля.
@ -1245,20 +1106,8 @@ type
/// Используются все обученные деревья.
function Predict(X: Matrix): Vector;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel;
/// Обучает модель градиентного бустинга с использованием валидационной выборки.
@ -1423,20 +1272,8 @@ type
function GetClasses: array of real;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel;
/// История значения LogLoss на обучающей выборке.
@ -1534,20 +1371,8 @@ type
/// Возвращает вектор предсказанных значений или меток
function Predict(X: Matrix): Vector; virtual; abstract;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel; virtual; abstract;
function Name: string := Self.GetType.Name;
@ -1610,20 +1435,8 @@ type
/// Возвращает массив меток классов в порядке столбцов PredictProba
function GetClasses: array of real;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel; override;
function Name: string := Self.GetType.Name;
@ -1661,20 +1474,8 @@ type
/// Возвращает вектор предсказанных значений
function Predict(X: Matrix): Vector; override;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel; override;
function Name: string := Self.GetType.Name;
@ -1738,20 +1539,8 @@ type
/// Выполняет обучение и сразу возвращает метки кластеров.
function FitPredict(X: Matrix): array of integer;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel;
/// Количество кластеров
@ -1819,20 +1608,8 @@ type
/// Возвращает метки после обучения.
function FitPredict(X: Matrix): array of integer;
/// Создаёт копию модели с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и Pipeline
/// гарантирует независимое переобучение моделей
///
/// Примечание:
/// для копирования обученной модели следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию модели (без обученного состояния).
/// Используется для создания независимых экземпляров модели.
function Clone: IModel;
property Labels: array of integer read fLabels;
@ -1976,16 +1753,8 @@ type
/// Возвращает строковое представление пайплайна.
function ToString: string; override;
/// Создаёт копию пайплайна с теми же шагами и моделью.
///
/// ВАЖНО:
/// Clone копирует только конфигурацию (transformers и модель)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Все шаги и модель клонируются через их Clone (config-only)
///
/// Назначение:
/// использование в CrossValidate и Pipeline
/// обеспечивает независимое переобучение пайплайна
/// Копирует только конфигурацию пайплайна (без обученного состояния).
/// Используется для создания независимых экземпляров пайплайна.
function Clone: IModel;
function Name: string := Self.GetType.Name;
@ -2068,16 +1837,8 @@ type
/// Возвращает строковое представление пайплайна.
function ToString: string; override;
/// Создаёт копию пайплайна с теми же шагами и моделью.
///
/// ВАЖНО:
/// Clone копирует только конфигурацию (transformers и модель)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Все шаги и модель клонируются через их Clone (config-only)
///
/// Назначение:
/// использование в CrossValidate и MatrixPipeline
/// обеспечивает независимое переобучение пайплайна
/// Копирует только конфигурацию пайплайна (без обученного состояния).
/// Используется для создания независимых экземпляров пайплайна.
function Clone: IModel;
function Name: string := Self.GetType.Name;
end;
@ -2130,20 +1891,8 @@ type
function ToString: string; override;
/// Создаёт копию трансформера с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и MatrixPipeline
/// гарантирует независимое переобучение трансформеров
///
/// Примечание:
/// для копирования обученного трансформера следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию трансформера (без обученного состояния).
/// Используется для создания независимых экземпляров трансформера.
function Clone: ITransformer;
end;
@ -2188,20 +1937,8 @@ type
function ToString: string; override;
/// Создаёт копию трансформера с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и MatrixPipeline
/// гарантирует независимое переобучение трансформеров
///
/// Примечание:
/// для копирования обученного трансформера следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию трансформера (без обученного состояния).
/// Используется для создания независимых экземпляров трансформера.
function Clone: ITransformer;
end;
@ -2242,20 +1979,8 @@ type
function ToString: string; override;
/// Создаёт копию трансформера с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и MatrixPipeline
/// гарантирует независимое переобучение трансформеров
///
/// Примечание:
/// для копирования обученного трансформера следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию трансформера (без обученного состояния).
/// Используется для создания независимых экземпляров трансформера.
function Clone: ITransformer;
end;
@ -2295,20 +2020,8 @@ type
function ToString: string; override;
/// Создаёт копию трансформера с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и MatrixPipeline
/// гарантирует независимое переобучение трансформеров
///
/// Примечание:
/// для копирования обученного трансформера следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию трансформера (без обученного состояния).
/// Используется для создания независимых экземпляров трансформера.
function Clone: ITransformer;
end;
@ -2392,20 +2105,8 @@ type
/// Возвращает строковое представление трансформера
function ToString: string; override;
/// Создаёт копию трансформера с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и MatrixPipeline
/// гарантирует независимое переобучение трансформеров
///
/// Примечание:
/// для копирования обученного трансформера следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию трансформера (без обученного состояния).
/// Используется для создания независимых экземпляров трансформера.
function Clone: ITransformer;
end;
@ -2450,20 +2151,8 @@ type
/// Возвращает строковое представление трансформера
function ToString: string; override;
/// Создаёт копию трансформера с теми же гиперпараметрами.
///
/// ВАЖНО:
/// Clone копирует ТОЛЬКО конфигурацию (hyperparameters)
/// Clone НЕ копирует обученное состояние (fitted state)
/// Возвращаемый объект эквивалентен новому экземпляру после Create(...)
///
/// Назначение:
/// использование в CrossValidate, GridSearch и MatrixPipeline
/// гарантирует независимое переобучение трансформеров
///
/// Примечание:
/// для копирования обученного трансформера следует использовать отдельные механизмы
/// (сериализация, ModelIO и т.п.)
/// Копирует только конфигурацию трансформера (без обученного состояния).
/// Используется для создания независимых экземпляров трансформера.
function Clone: ITransformer;
end;
@ -3226,18 +2915,7 @@ begin
var p := X.ColCount;
// --- convert to integer labels
var yInt := new integer[m];
for var i := 0 to m - 1 do
begin
var r := y[i];
var ir := Round(r);
if Abs(r - ir) > 1e-12 then
ArgumentError(ER_LABELS_NOT_INTEGER);
yInt[i] := ir;
end;
var yInt := LabelsToInts(y);
// --- encode (порядок первого появления)
var unique: array of integer;
@ -4053,140 +3731,6 @@ begin
Result.Right := right;
end;
procedure DecisionTreeCore.Split(X: Matrix; y: Vector; f: integer; t: real;
var Xl: Matrix; var yl: Vector;
var Xr: Matrix; var yr: Vector
);
begin
var leftIdx := new List<integer>;
var rightIdx := new List<integer>;
// 1. Разделяем индексы
for var i := 0 to X.RowCount - 1 do
if X[i, f] <= t then
leftIdx.Add(i)
else
rightIdx.Add(i);
// 2. Формируем подматрицы и подвекторы
var leftArr := leftIdx.ToArray;
var rightArr := rightIdx.ToArray;
Xl := X.TakeRows(leftArr);
yl := y.SubvectorBy(leftArr);
Xr := X.TakeRows(rightArr);
yr := y.SubvectorBy(rightArr);
end;
{function DecisionTreeCore.FindBestSplit(
X: Matrix;
y: Vector;
indices: array of integer;
var bestF: integer;
var bestT: real
): boolean;
begin
Result := false;
var n := indices.Length;
if n = 0 then exit;
var parentImp := fCriterion.Impurity(y, indices);
var bestScore := parentImp;
// --- выбор признаков (с учётом maxFeatures)
var featureCount := X.ColCount;
var features: array of integer;
if (fMaxFeatures > 0) and (fMaxFeatures < featureCount) then
begin
var perm := new integer[featureCount];
for var i := 0 to featureCount - 1 do
perm[i] := i;
for var i := 0 to fMaxFeatures - 1 do
begin
var j := i + fRng.Next(featureCount - i);
var tmp := perm[i];
perm[i] := perm[j];
perm[j] := tmp;
end;
SetLength(features, fMaxFeatures);
for var i := 0 to fMaxFeatures - 1 do
features[i] := perm[i];
end
else
begin
SetLength(features, featureCount);
for var i := 0 to featureCount - 1 do
features[i] := i;
end;
// --- перебор
for var fi := 0 to features.Length - 1 do
begin
var f := features[fi];
var leftBuf := new integer[n];
var rightBuf := new integer[n];
for var ii := 0 to n - 1 do
begin
var i := indices[ii];
var t := X[i, f];
var lcnt := 0;
var rcnt := 0;
for var jj := 0 to n - 1 do
begin
var j := indices[jj];
if X[j, f] <= t then
begin
leftBuf[lcnt] := j;
lcnt += 1;
end
else
begin
rightBuf[rcnt] := j;
rcnt += 1;
end;
end;
if (lcnt < fMinSamplesLeaf) or (rcnt < fMinSamplesLeaf) then
continue;
// создаём массивы нужного размера
var leftIdx := new integer[lcnt];
var rightIdx := new integer[rcnt];
for var i1 := 0 to lcnt - 1 do
leftIdx[i1] := leftBuf[i1];
for var i1 := 0 to rcnt - 1 do
rightIdx[i1] := rightBuf[i1];
var leftImp := fCriterion.Impurity(y, leftIdx);
var rightImp := fCriterion.Impurity(y, rightIdx);
var score :=
(leftIdx.Length * leftImp + rightIdx.Length * rightImp) / n;
if score < bestScore then
begin
bestScore := score;
bestF := f;
bestT := t;
Result := true;
end;
end;
end;
end;}
// Новая реализация (O(n log n · p))
function DecisionTreeCore.FindBestSplit(
X: Matrix;
@ -4737,19 +4281,7 @@ begin
fFeatureImportances := new Vector(X.ColCount);
// --- convert to integer labels
var m := y.Length;
var yInt := new integer[m];
for var i := 0 to m - 1 do
begin
var r := y[i];
var ir := Round(r);
if Abs(r - ir) > 1e-12 then
ArgumentError(ER_LABELS_NOT_INTEGER);
yInt[i] := ir;
end;
var yInt := LabelsToInts(y);
// --- encode
var classes: array of integer;
@ -4947,17 +4479,9 @@ begin
fFeatureImportances := new Vector(X.ColCount);
var indices: array of integer;
// 🔹 Ключевое изменение
if fRowIndices = nil then
begin
SetLength(indices, X.RowCount);
for var i := 0 to X.RowCount - 1 do
indices[i] := i;
end
else
indices := fRowIndices;
var indices: array of integer := fRowIndices;
if indices = nil then
indices := Arr(0..X.RowCount - 1);
fRoot := BuildTree(X, y, indices, 0);
@ -4978,12 +4502,10 @@ begin
var node := fRoot;
while not node.IsLeaf do
begin
if X[rowIndex, node.FeatureIndex] <= node.Threshold then
node := node.Left
else
node := node.Right;
end;
Result := node.LeafValue; // для регрессии это уже real
end;
@ -5035,7 +4557,6 @@ begin
Result := s;
end;
//-----------------------------
// RandomForestBase
//-----------------------------
@ -5364,18 +4885,7 @@ begin
// ЕДИНЫЙ ENCODING (forest-level)
// =========================================================
var yInt := new integer[n];
for var i := 0 to n - 1 do
begin
var r := y[i];
var ir := Round(r);
if Abs(r - ir) > 1e-12 then
ArgumentError(ER_LABELS_NOT_INTEGER);
yInt[i] := ir;
end;
var yInt := LabelsToInts(y);
var yEncArr := EncodeLabelsInt(yInt, fIndexToClass);
fClassCount := fIndexToClass.Length;
@ -5383,9 +4893,7 @@ begin
if fClassCount < 2 then
ArgumentError(ER_NEED_AT_LEAST_TWO_CLASSES);
var yEnc := new Vector(n);
for var i := 0 to n - 1 do
yEnc[i] := yEncArr[i];
var yEnc := new Vector(yEncArr);
// =========================================================
@ -6508,21 +6016,10 @@ begin
var nTrain := XTrain.RowCount;
// =========================================================
// НОВЫЙ ЕДИНЫЙ ENCODING
// Новый Encoding
// =========================================================
var yTrainInt := new integer[nTrain];
for var i := 0 to nTrain - 1 do
begin
var r := yTrain[i];
var ir := Round(r);
if Abs(r - ir) > 1e-12 then
ArgumentError(ER_LABELS_NOT_INTEGER);
yTrainInt[i] := ir;
end;
var yTrainInt := LabelsToInts(yTrain);
var yEncoded := EncodeLabelsInt(yTrainInt, fClasses);
@ -6588,19 +6085,15 @@ begin
if useValidation then
begin
var nVal := yVal.Length;
var yValInt := LabelsToInts(yVal);
yValEncoded := new integer[nVal];
yValEncoded := new integer[yValInt.Length];
for var i := 0 to nVal - 1 do
for var i := 0 to yValInt.Length - 1 do
begin
var r := yVal[i];
var ir := Round(r);
var ir := yValInt[i];
if Abs(r - ir) > 1e-12 then
ArgumentError(ER_LABELS_NOT_INTEGER);
if not fClassIndex.ContainsKey(ir) then
if ir not in fClassIndex then
ArgumentError(ER_UNKNOWN_CLASS_LABEL, ir);
yValEncoded[i] := fClassIndex[ir];
@ -7350,7 +6843,7 @@ end;
function KNNBase.SquaredL2(trainRow: integer; XTest: Matrix; testRow: integer): double;
begin
var sum := 0.0;
var sum := 0.0;
var d := fXTrain.ColCount;
var train := fXTrain; // локальная ссылка
@ -7556,18 +7049,7 @@ begin
// ЕДИНЫЙ ENCODING
// =========================================================
var yInt := new integer[n];
for var i := 0 to n - 1 do
begin
var r := y[i];
var ir := Round(r);
if Abs(r - ir) > 1e-12 then
ArgumentError(ER_LABELS_NOT_INTEGER);
yInt[i] := ir;
end;
var yInt := LabelsToInts(y);
var classesInt: array of integer;
var yEncArr := EncodeLabelsInt(yInt, classesInt);
@ -9364,16 +8846,13 @@ begin
var classToIndex := new Dictionary<integer, integer>;
var uniqueClasses := new List<integer>;
var yEncoded := new integer[n];
var yInt := LabelsToInts(y);
for var i := 0 to n - 1 do
begin
var r := y[i];
var ir := Round(r);
var ir := yInt[i];
if Abs(r - ir) > 1e-12 then
ArgumentError(ER_LABELS_NOT_INTEGER);
if not classToIndex.ContainsKey(ir) then
if ir not in classToIndex then
begin
classToIndex[ir] := uniqueClasses.Count;
uniqueClasses.Add(ir);
@ -9454,16 +8933,13 @@ begin
var classToIndex := new Dictionary<integer, integer>;
var uniqueClasses := new List<integer>;
var yEncoded := new integer[n];
var yInt := LabelsToInts(y);
for var i := 0 to n - 1 do
begin
var r := y[i];
var ir := Round(r);
var ir := yInt[i];
if Abs(r - ir) > 1e-12 then
ArgumentError(ER_LABELS_NOT_INTEGER);
if not classToIndex.ContainsKey(ir) then
if ir not in classToIndex then
begin
classToIndex[ir] := uniqueClasses.Count;
uniqueClasses.Add(ir);
@ -9710,4 +9186,4 @@ begin
Result := new Normalizer(fNormType);
end;
end.
end.

View file

@ -20,8 +20,23 @@ type
fFitted: boolean;
procedure ValidateSchema(df: DataFrame); virtual; abstract;
class procedure ValidateFeatureList(features: array of string);
/// Вычисляет итоговый список признаков после всех DataFrame-преобразований.
///
/// Для каждого исходного признака из fFeatures:
/// пытается получить расширенные столбцы через IColumnExpander;
/// если расширения нет, использует сам исходный столбец.
///
/// Возвращает только те столбцы, которые реально присутствуют в current,
/// без повторов и в итоговом порядке для построения матрицы признаков.
///
/// Если после preprocessing не осталось ни одного признака,
/// выбрасывается исключение
function ResolveFinalFeatures(current: DataFrame): array of string;
function PrepareMatrix(df: DataFrame; var current: DataFrame): Matrix;
function TransformDataFrame(df: DataFrame): DataFrame;
function FitTransformMatrix(var X: Matrix; y: Vector := nil): Matrix;
@ -29,7 +44,7 @@ type
public
constructor Create;
/// Признак того, что был вызван Fit или FitTransform.
/// Признак того, что был вызван Fit.
property IsFitted: boolean read fFitted;
end;
@ -45,11 +60,10 @@ type
/// Затем матричные шаги (ITransformer / ISupervisedTransformer).
/// Модель (IModel) добавляется последней и может быть только одна.
///
/// В режиме с моделью используются:
/// В конвейере используются:
/// features признаки;
/// target целевая переменная.
///
/// Если модель не добавлена, DataPipeline работает как чистый DF-конвейер (Fit/Transform/FitTransform)
DataPipeline = class(PipelineBase, IModel)
private
fModel: ISupervisedModel;
@ -67,7 +81,7 @@ type
/// IPreprocessor (DataFrame-уровень)
/// ITransformer (Matrix-уровень)
/// ISupervisedModel (модель, должна быть последней)
/// Запрещено добавлять шаги после вызова Fit/FitTransform.
/// Запрещено добавлять шаги после вызова Fit.
function Add(step: IPipelineStep): DataPipeline;
/// Строит конвейер из шагов обработки данных и модели.
@ -90,16 +104,18 @@ type
/// затем обучает матричные трансформеры и модель.
function Fit(df: DataFrame): DataPipeline;
/// Применяет обученные DataFrame-шаги к DataFrame и возвращает новый DataFrame.
/// В ML-режиме Transform не выполняет матричные шаги и не вызывает модель.
/// Применяет только обученные DataFrame-шаги pipeline и возвращает новый DataFrame.
///
/// Матричные шаги и модель при этом не используются.
/// Метод предназначен в основном для просмотра и анализа промежуточного
/// результата preprocessing.
///
/// Полученный DataFrame обычно не следует повторно подавать в тот же pipeline,
/// так как DataFrame-преобразования будут выполнены ещё раз.
function Transform(df: DataFrame): DataFrame;
/// Выполняет Fit и Transform за один проход для DataFrame-режима.
/// Недоступен, если конвейер содержит модель (IModel).
function FitTransform(df: DataFrame): DataFrame;
/// Делает предсказание модели для объектов из DataFrame.
/// Доступен только если конвейер содержит модель (IModel) и был обучен (Fit).
/// Доступен после обучения конвейера (Fit).
function Predict(df: DataFrame): Vector;
/// Возвращает матрицу вероятностей (nSamples × nClasses).
@ -133,8 +149,6 @@ type
/// В конвейере используются:
/// features признаки (целевая переменная отсутствует).
///
/// Если модель не добавлена, UDataPipeline работает как чистый DF-конвейер
/// (Fit/Transform/FitTransform)
UDataPipeline = class(PipelineBase, IModel)
private
fModel: IUnsupervisedModel;
@ -161,13 +175,16 @@ type
/// Обучает конвейер на DataFrame.
function Fit(df: DataFrame): UDataPipeline;
/// Применяет обученные DataFrame-шаги к DataFrame и возвращает новый DataFrame.
/// Применяет только обученные DataFrame-шаги pipeline и возвращает новый DataFrame.
///
/// Матричные шаги и модель при этом не используются.
/// Метод предназначен в основном для просмотра и анализа промежуточного
/// результата preprocessing.
///
/// Полученный DataFrame обычно не следует повторно подавать в тот же pipeline,
/// так как DataFrame-преобразования будут выполнены ещё раз.
function Transform(df: DataFrame): DataFrame;
/// Выполняет Fit и Transform за один проход для DataFrame-режима.
/// Недоступен, если конвейер содержит модель (IModel).
function FitTransform(df: DataFrame): DataFrame;
/// Обучает конвейер и сразу возвращает метки кластеров.
///
/// Выполняет полный pipeline:
@ -177,7 +194,7 @@ type
/// Используется для задач кластеризации, где нет разделения на train/test.
///
/// Доступен только если:
/// конвейер содержит модель кластеризации (IClusterer).
/// конечная модель поддерживает кластеризацию (IClusterer).
function FitPredict(df: DataFrame): array of integer;
/// Делает предсказание модели для объектов из DataFrame.
@ -189,8 +206,7 @@ type
/// затем применяет обученную модель кластеризации.
///
/// Доступен только если:
/// конвейер содержит модель (IModel);
/// модель поддерживает кластеризацию (IClusterer);
/// конечная модель поддерживает кластеризацию (IClusterer);
/// конвейер был обучен (Fit).
function PredictLabels(df: DataFrame): array of integer;
@ -219,11 +235,6 @@ const
'Матричный шаг не может идти после модели!!Matrix step cannot appear after the model';
ER_DATAPIPE_UNKNOWN_STEP_TYPE =
'Неизвестный тип шага конвейера: {0}!!Unknown pipeline step type: {0}';
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 =
@ -275,6 +286,8 @@ const
'LabelEncoder нельзя применять к целевой переменной — кодирование выполняется внутри модели!!LabelEncoder cannot be applied to target — encoding is handled internally by the model';
ER_ENCODELABELS_NOT_CATEGORICAL =
'Целевой столбец должен быть категориальным для задач классификации!!Target column must be categorical for classification tasks';
ER_REGRESSION_TARGET_MUST_BE_NUMERIC =
'Целевой столбец "{0}" должен быть числовым для задач регрессии!!Target column "{0}" must be numeric for regression tasks';
ER_PIPELINE_TARGET_TRANSFORM_NOT_ALLOWED =
'Преобразование целевой переменной "{0}" запрещено в DataPipeline!!' +
'Transformation of target variable "{0}" is not allowed in DataPipeline';
@ -312,24 +325,30 @@ begin
fFitted := false;
end;
function PipelineBase.PrepareMatrix(df: DataFrame; var current: DataFrame): Matrix;
class procedure PipelineBase.ValidateFeatureList(features: array of string);
begin
if df = nil then
ArgumentNullError(ER_ARG_NULL, 'df');
if (features = nil) or (features.Length = 0) then
ArgumentError(ER_FEATURES_EMPTY);
current := df;
var seen := new HashSet<string>;
// --- schema
ValidateSchema(current);
// --- DataFrame steps
for var i := 0 to fDataSteps.Count - 1 do
foreach var f in features do
begin
fDataSteps[i] := fDataSteps[i].Fit(current);
current := fDataSteps[i].Transform(current);
end;
if (f = nil) or (f = '') then
ArgumentError(ER_FEATURE_EMPTY);
if f in seen then
ArgumentError(ER_DATAPIPE_DUPLICATE_FEATURE, f);
seen.Add(f);
end;
end;
function PipelineBase.ResolveFinalFeatures(current: DataFrame): array of string;
begin
if current = nil then
ArgumentNullError(ER_ARG_NULL, 'current');
// --- features
var feats := new List<string>;
foreach var f in fFeatures do
@ -348,7 +367,7 @@ begin
begin
foreach var c in cols do
if current.HasColumn(c) then
if not feats.Contains(c) then
if c not in feats then
feats.Add(c);
expanded := true;
@ -361,18 +380,52 @@ begin
// fallback: обычный столбец
if current.HasColumn(f) then
if not feats.Contains(f) then
if f not in feats then
feats.Add(f);
end;
if feats.Count = 0 then
ArgumentError(ER_PIPELINE_NO_FEATURES);
fFinalFeatures := feats.ToArray;
Result := feats.ToArray;
end;
function PipelineBase.PrepareMatrix(df: DataFrame; var current: DataFrame): Matrix;
begin
if df = nil then
ArgumentNullError(ER_ARG_NULL, 'df');
current := df;
// --- schema
ValidateSchema(current);
// --- DataFrame steps
for var i := 0 to fDataSteps.Count - 1 do
begin
fDataSteps[i] := fDataSteps[i].Fit(current);
current := fDataSteps[i].Transform(current);
end;
fFinalFeatures := ResolveFinalFeatures(current);
Result := current.ToMatrix(fFinalFeatures);
end;
function PipelineBase.TransformDataFrame(df: DataFrame): DataFrame;
begin
if df = nil then
ArgumentNullError(ER_ARG_NULL, 'df');
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 PipelineBase.FitTransformMatrix(var X: Matrix; y: Vector): Matrix;
begin
for var i := 0 to fMatrixSteps.Count - 1 do
@ -416,12 +469,9 @@ end;
constructor DataPipeline.Create;
begin
fDataSteps := new List<IPreprocessor>;
fMatrixSteps := new List<ITransformer>;
inherited Create;
fModel := nil;
fTarget := '';
fFeatures := nil;
fFitted := false;
end;
function DataPipeline.Add(step: IPipelineStep): DataPipeline;
@ -493,25 +543,12 @@ begin
if (target = nil) or (target = '') then
ArgumentError(ER_TARGET_EMPTY);
if (features = nil) or (features.Length = 0) then
ArgumentError(ER_FEATURES_EMPTY);
var seen := new HashSet<string>;
ValidateFeatureList(features);
foreach var f in features do
begin
if (f = nil) or (f = '') then
ArgumentError(ER_FEATURE_EMPTY);
if f = target then
ArgumentError(ER_DATAPIPE_TARGET_IN_FEATURES, target);
if seen.Contains(f) then
ArgumentError(ER_DATAPIPE_DUPLICATE_FEATURE, f);
seen.Add(f);
end;
if (steps = nil) or (Length(steps) = 0) then
ArgumentError(ER_PIPELINE_NO_STEPS);
@ -604,38 +641,7 @@ begin
Result := Self;
end;
function DataPipeline.Transform(df: DataFrame): DataFrame;
begin
if df = nil then
ArgumentNullError(ER_ARG_NULL, 'df');
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 df = nil then
ArgumentNullError(ER_ARG_NULL, 'df');
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.Transform(df: DataFrame): DataFrame := TransformDataFrame(df);
function DataPipeline.Predict(df: DataFrame): Vector;
begin
@ -699,8 +705,7 @@ begin
if fTarget = '' then
ArgumentError(ER_TARGET_EMPTY);
if (fFeatures = nil) or (Length(fFeatures) = 0) then
ArgumentError(ER_FEATURES_EMPTY);
ValidateFeatureList(fFeatures);
// target не должен входить в features
for var i := 0 to High(fFeatures) do
@ -714,29 +719,28 @@ begin
ArgumentError(ER_DATAPIPE_TARGET_NOT_FOUND, fTarget, cols);
end;
if fTask = tkClassification then
if not df.IsCategorical(fTarget) then
ArgumentError(ER_ENCODELABELS_NOT_CATEGORICAL, fTarget);
var seen := new HashSet<string>;
case fTask of
tkClassification:
if not df.IsCategorical(fTarget) then
ArgumentError(ER_ENCODELABELS_NOT_CATEGORICAL, fTarget);
tkRegression:
begin
var ct := df.GetColumnType(fTarget);
if not (ct in [ColumnType.ctInt, ColumnType.ctFloat]) then
ArgumentError(ER_REGRESSION_TARGET_MUST_BE_NUMERIC, fTarget);
end;
end;
for var i := 0 to High(fFeatures) do
begin
var f := fFeatures[i];
if f = '' then
ArgumentError(ER_FEATURE_EMPTY);
if not df.Schema.HasColumn(f) then
begin
var cols := df.Schema.ColumnNames.JoinToString(', ');
ArgumentError(ER_DATAPIPE_FEATURE_NOT_FOUND, f, cols);
end;
if seen.Contains(f) then
ArgumentError(ER_DATAPIPE_DUPLICATE_FEATURE, f);
seen.Add(f);
end;
end;
@ -804,11 +808,8 @@ end;
constructor UDataPipeline.Create;
begin
fDataSteps := new List<IPreprocessor>;
fMatrixSteps := new List<ITransformer>;
inherited Create;
fModel := nil;
fFeatures := nil;
fFitted := false;
end;
function UDataPipeline.Add(step: IPipelineStep): UDataPipeline;
@ -856,21 +857,7 @@ end;
class function UDataPipeline.Build(features: array of string;
params steps: array of IPipelineStep): UDataPipeline;
begin
if (features = nil) or (features.Length = 0) then
ArgumentError(ER_FEATURES_EMPTY);
var seen := new HashSet<string>;
foreach var f in features do
begin
if (f = nil) or (f = '') then
ArgumentError(ER_FEATURE_EMPTY);
if seen.Contains(f) then
ArgumentError(ER_DATAPIPE_DUPLICATE_FEATURE, f);
seen.Add(f);
end;
ValidateFeatureList(features);
if (steps = nil) or (Length(steps) = 0) then
ArgumentError(ER_PIPELINE_NO_STEPS);
@ -921,38 +908,7 @@ begin
Result := Self;
end;
function UDataPipeline.Transform(df: DataFrame): DataFrame;
begin
if df = nil then
ArgumentNullError(ER_ARG_NULL, 'df');
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 UDataPipeline.FitTransform(df: DataFrame): DataFrame;
begin
if df = nil then
ArgumentNullError(ER_ARG_NULL, 'df');
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 UDataPipeline.Transform(df: DataFrame): DataFrame := TransformDataFrame(df);
function UDataPipeline.FitPredict(df: DataFrame): array of integer;
begin
@ -978,27 +934,7 @@ begin
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;
fFinalFeatures := ResolveFinalFeatures(current);
var X := current.ToMatrix(fFinalFeatures);
@ -1100,28 +1036,17 @@ end;
procedure UDataPipeline.ValidateSchema(df: DataFrame);
begin
if (fFeatures = nil) or (Length(fFeatures) = 0) then
ArgumentError(ER_FEATURES_EMPTY);
var seen := new HashSet<string>;
ValidateFeatureList(fFeatures);
for var i := 0 to High(fFeatures) do
begin
var f := fFeatures[i];
if f = '' then
ArgumentError(ER_FEATURE_EMPTY);
if not df.Schema.HasColumn(f) then
begin
var cols := df.Schema.ColumnNames.JoinToString(', ');
ArgumentError(ER_DATAPIPE_FEATURE_NOT_FOUND, f, cols);
end;
if seen.Contains(f) then
ArgumentError(ER_DATAPIPE_DUPLICATE_FEATURE, f);
seen.Add(f);
end;
end;
@ -1179,4 +1104,4 @@ begin
Result := p;
end;
end.
end.

View file

@ -97,9 +97,11 @@ uses MLExceptions;
const
ER_LABELS_NULL =
'y не может быть nil!!y cannot be nil';
'{0} не может быть nil!!{0} cannot be nil';
ER_LABELS_ARRAY_NULL =
'labels не может быть nil!!labels cannot be nil';
ER_LABELS_NOT_INTEGER =
'Метки классов должны быть целыми числами!!Class labels must be integers';
ER_UNKNOWN_CLASS_IN_TRANSFORM =
'Неизвестное значение класса "{0}" при преобразовании меток!!Unknown class value "{0}" in TransformLabels';
ER_LABEL_INDEX_OUT_OF_RANGE =
@ -128,7 +130,15 @@ begin
Result := new integer[y.Length];
for var i := 0 to y.Length - 1 do
Result[i] := Round(y[i]);
begin
var r := y[i];
var ir := Round(r);
if Abs(r - ir) > 1e-12 then
ArgumentError(ER_LABELS_NOT_INTEGER);
Result[i] := ir;
end;
end;
function IntsToLabels(a: array of integer): Vector;
@ -151,7 +161,7 @@ begin
for var i := 0 to labels.Length - 1 do
begin
var lbl := labels[i];
if not map.ContainsKey(lbl) then
if lbl not in map then
begin
map[lbl] := classList.Count;
classList.Add(lbl);
@ -182,7 +192,7 @@ begin
begin
var lbl := labels[i];
if not map.ContainsKey(lbl) then
if lbl not in map then
Error(ER_UNKNOWN_CLASS_IN_TRANSFORM, lbl);
res[i] := map[lbl];
@ -210,7 +220,7 @@ begin
begin
var v := labels[i];
if not map.ContainsKey(v) then
if v not in map then
Error(ER_UNKNOWN_CLASS_IN_TRANSFORM, v);
res[i] := map[v];
@ -237,7 +247,7 @@ begin
for var i := 0 to labels.Length - 1 do
begin
var lbl := labels[i];
if not map.ContainsKey(lbl) then
if lbl not in map then
begin
map[lbl] := classList.Count;
classList.Add(lbl);
@ -276,7 +286,7 @@ begin
var res := new List<string>;
for var i := 0 to labels.Length - 1 do
if not seen.Contains(labels[i]) then
if labels[i] not in seen then
begin
seen.Add(labels[i]);
res.Add(labels[i]);
@ -298,4 +308,4 @@ begin
DimensionError(ER_DIM_MISMATCH, a.Length, b.Length);
end;
end.
end.

View file

@ -53,6 +53,9 @@ type
/// R2 = 1 идеальная модель,
/// R2 = 0 не лучше среднего,
/// R2 < 0 хуже константной модели.
///
/// Если дисперсия целевой переменной равна нулю (все значения одинаковы),
/// метрика не определена. В этом случае возвращается 0.0 по соглашению.
static function R2(yTrue, yPred: Vector): real;
// ---- Вероятностные метрики классификации ----
@ -104,14 +107,14 @@ type
/// Важна, когда критичны ложные положительные результаты («ложные тревоги»).
static function Precision(yTrue, yPred: Vector): real;
/// Точность (Precision) для многоклассовой классификации.
/// Точность (Precision) с усреднением по классам.
/// Вычисляется для каждого класса отдельно как:
/// Precision(c) = TP(c) / (TP(c) + FP(c)),
/// после чего агрегируется согласно параметру avg:
/// а затем результаты объединяются способом, заданным параметром avg:
/// avMacro среднее по всем классам (каждый класс равновесен);
/// avMicro глобальная метрика по суммарным TP и FP;
/// avWeighted среднее с весами, пропорциональными размеру классов.
/// Используется для задач с числом классов больше двух.
/// Особенно полезна для многоклассовой классификации.
static function Precision(yTrue, yPred: Vector; avg: Averaging): real;
/// Полнота (Recall) для положительного класса (1).
@ -122,14 +125,14 @@ type
/// Важна, когда нежелательны пропуски положительных случаев (например, заболеваний).
static function Recall(yTrue, yPred: Vector): real;
/// Полнота (Recall) для многоклассовой классификации.
/// Полнота (Recall) с усреднением по классам.
/// Вычисляется для каждого класса отдельно как:
/// Recall(c) = TP(c) / (TP(c) + FN(c)),
/// после чего агрегируется согласно параметру avg:
/// а затем результаты объединяются способом, заданным параметром avg:
/// avMacro среднее по всем классам (каждый класс равновесен);
/// avMicro глобальная метрика по суммарным TP и FN;
/// avWeighted среднее с весами, пропорциональными размеру классов.
/// Используется для задач с числом классов больше двух.
/// Особенно полезна для многоклассовой классификации.
static function Recall(yTrue, yPred: Vector; avg: Averaging): real;
/// F1-мера для бинарной классификации.
@ -140,14 +143,14 @@ type
/// Особенно полезна при несбалансированных классах.
static function F1(yTrue, yPred: Vector): real;
/// F1-мера для многоклассовой классификации.
/// F1-мера с усреднением по классам.
/// Вычисляется для каждого класса отдельно как:
/// F1(c) = 2 * Precision(c) * Recall(c) / (Precision(c) + Recall(c)),
/// после чего агрегируется согласно параметру avg:
/// а затем результаты объединяются способом, заданным параметром avg:
/// avMacro среднее по всем классам (каждый класс равновесен);
/// avMicro вычисляется по суммарным TP, FP и FN;
/// avWeighted среднее с весами, пропорциональными размеру классов.
/// Используется для задач с числом классов больше двух.
/// Особенно полезна для многоклассовой классификации.
static function F1(yTrue, yPred: Vector; avg: Averaging): real;
/// Специфичность (Specificity, True Negative Rate) для бинарной классификации.
@ -212,24 +215,25 @@ type
end;
type
/// Матрица ошибок (Confusion Matrix).
/// Представляет собой квадратную матрицу размера K × K,
/// где K число классов.
/// Элемент [i, j] содержит количество объектов,
/// истинный класс которых равен i,
/// а предсказанный j.
/// Используется для анализа качества классификатора
/// и вычисления метрик (Accuracy, Precision, Recall, F1 и др.).
/// Поддерживает как бинарную, так и многоклассовую классификацию.
/// Для бинарной классификации дополнительно доступны
/// агрегированные показатели: TP, TN, FP, FN.
///
/// Ожидается, что yTrue и yPred содержат закодированные метки классов
/// (целые значения 0..K-1, допускается хранение в Vector типа real).
/// Для строковых меток необходимо предварительно применить EncodeLabels
///
/// Метки классов упорядочиваются по возрастанию для обеспечения
/// стабильного и предсказуемого представления результатов
/// Матрица ошибок (Confusion Matrix) для бинарной и многоклассовой классификации.
///
/// Показывает, сколько объектов каждого класса
/// модель распознала правильно и сколько перепутала.
///
/// На вход можно передавать любые целочисленные метки классов
/// (например, 0, 1, 2 или 2, 5, 8).
///
/// При построении матрицы все метки автоматически нумеруются
/// числами от 0 до K-1, где K число различных классов.
///
/// Элемент матрицы [i, j] показывает, сколько объектов
/// класса i модель предсказала как класс j.
///
/// Свойства Labels, GetLabel и GetIndex позволяют узнать,
/// как новые внутренние номера классов связаны с исходными метками.
///
/// Для бинарной классификации дополнительно доступны
/// показатели TP, TN, FP, FN, Precision, Recall, F1, Specificity и BalancedAccuracy
ConfusionMatrix = class
private
fMatrix: array[,] of integer;
@ -248,76 +252,87 @@ type
procedure EnsureClassIndex(c: integer);
public
/// Создаёт матрицу ошибок по истинным меткам yTrue и предсказаниям модели yPred.
/// Векторы должны иметь одинаковую длину и содержать метки классов,
/// представленные целыми числами (0, 1, 2, ...).
/// Автоматически определяет множество классов и строит
/// матрицу размера K × K, где K число различных классов.
/// Элемент [i, j] содержит количество объектов,
/// истинный класс которых равен i,
/// а предсказанный j.
/// Для бинарной классификации дополнительно доступны агрегированные
/// значения TP, TN, FP и FN
///
/// Векторы должны иметь одинаковую длину и содержать целочисленные метки классов.
///
/// Можно использовать любые целые метки классов. При построении матрицы они
/// автоматически перенумеровываются числами от 0 до K-1, где K число
/// различных классов.
///
/// Элемент [i, j] показывает, сколько объектов класса i модель предсказала
/// как класс j.
///
/// Для бинарной классификации дополнительно доступны значения TP, TN, FP и FN
constructor Create(yTrue, yPred: Vector);
/// Возвращает исходную метку класса по внутреннему индексу c.
/// c индекс класса в диапазоне [0, ClassCount).
/// Результат метка класса (например, 2, 5, 8), соответствующая этому индексу.
/// Используется для интерпретации результатов, так как внутренние индексы
/// могут не совпадать с исходными значениями меток.
/// Возвращает исходную метку класса по его внутреннему номеру.
///
/// Внутренние номера классов используются внутри матрицы ошибок
/// и находятся в диапазоне от 0 до ClassCount-1.
///
/// Метод позволяет узнать, какой исходной метке соответствует
/// данный внутренний номер.
function GetLabel(c: integer): integer;
/// Возвращает внутренний индекс класса по его метке label.
/// label исходная метка класса (например, 2, 5, 8).
/// Результат индекс класса в диапазоне [0, ClassCount).
/// Используется для преобразования внешних меток в внутренние индексы,
/// применяемые внутри матрицы ошибок.
/// Возвращает внутренний номер класса по его исходной метке.
///
/// Результат находится в диапазоне от 0 до ClassCount-1
/// и используется для обращения к элементам матрицы ошибок.
///
/// Если такой метки нет, выбрасывается исключение.
function GetIndex(labl: integer): integer;
/// Массив меток классов в порядке внутренних индексов.
/// Labels[c] исходная метка класса для индекса c.
/// Исходные метки классов в порядке внутренних номеров.
///
/// Labels[c] это исходная метка класса,
/// соответствующая внутреннему номеру c.
property Labels: array of integer read fLabels;
/// Число различных классов в данных.
/// Определяется автоматически по объединению меток из yTrue и yPred.
/// Используется для построения матрицы размера K × K.
/// Число различных классов, встретившихся в yTrue или yPred.
///
/// Используется для построения матрицы ошибок размера K × K, где K = ClassCount.
property ClassCount: integer read fClassCount;
/// Число истинно положительных предсказаний для класса c.
/// TP(c) количество объектов, для которых истинный и предсказанный класс равны c.
/// Здесь c номер класса в матрице ошибок.
/// Соответствует элементу матрицы [c, c].
function TPForClass(c: integer): integer;
/// Число ложно положительных предсказаний для класса c.
/// Здесь c номер класса в матрице ошибок.
/// FP(c) количество объектов, предсказанных как класс c,
/// но в действительности принадлежащих другим классам.
/// Вычисляется как сумма по столбцу c минус TP(c).
function FPForClass(c: integer): integer;
/// Число ложно отрицательных предсказаний для класса c.
/// Здесь c номер класса в матрице ошибок.
/// FN(c) количество объектов, принадлежащих классу c,
/// но предсказанных как другие классы.
/// Вычисляется как сумма по строке c минус TP(c).
function FNForClass(c: integer): integer;
/// Число истинно положительных предсказаний (TP) для бинарной классификации.
/// Количество объектов, для которых истинный и предсказанный класс равны 1.
/// Показывает, сколько объектов положительного класса
/// модель правильно распознала как положительные.
/// Доступно только при числе классов, равном 2.
property TP: integer read GetTPBinary;
/// Число ложно положительных предсказаний (FP) для бинарной классификации.
/// Количество объектов, предсказанных как класс 1,
/// но в действительности принадлежащих классу 0.
/// Показывает, сколько объектов отрицательного класса
/// модель ошибочно отнесла к положительному классу.
/// Доступно только при числе классов, равном 2.
property FP: integer read GetFPBinary;
/// Число ложно отрицательных предсказаний (FN) для бинарной классификации.
/// Количество объектов, принадлежащих классу 1,
/// но предсказанных как класс 0.
/// Показывает, сколько объектов положительного класса
/// модель ошибочно отнесла к отрицательному классу.
/// Доступно только при числе классов, равном 2.
property FN: integer read GetFNBinary;
/// Число истинно отрицательных предсказаний (TN) для бинарной классификации.
/// Количество объектов, для которых истинный и предсказанный класс равны 0.
/// Показывает, сколько объектов отрицательного класса
/// модель правильно распознала как отрицательные.
/// Доступно только при числе классов, равном 2.
property TN: integer read GetTNBinary;
@ -483,6 +498,9 @@ type
/// Используется только для бинарной классификации.
static function AUC(yTrue, yPred: Vector): real := Metrics.AUC(yTrue, yPred);
/// Формирует текстовый отчёт по качеству классификации.
/// Для каждого класса выводит Precision, Recall, F1 и число объектов этого класса.
/// Также выводит усреднённые показатели по всем классам.
static function ClassificationReport(yTrue, yPred: Vector): string := Metrics.ClassificationReport(yTrue, yPred);
end;
@ -527,7 +545,10 @@ type
/// 1.0 идеальная модель
/// 0.0 модель не лучше среднего
/// <0 модель хуже простого среднего
static function R2(yTrue, yPred: Vector): real := Metrics.R2(yTrue, yPred);
///
/// Если дисперсия целевой переменной равна нулю (все значения одинаковы),
/// метрика не определена. В этом случае возвращается 0.0 по соглашению.
static function R2(yTrue, yPred: Vector): real := Metrics.R2(yTrue, yPred);
end;
/// Метрики для оценки качества кластеризации
@ -601,6 +622,8 @@ const
'Для вычисления Silhouette требуется минимум 2 кластера!!Silhouette requires at least 2 clusters';
ER_INVALID_VALUE_AT =
'Некорректное значение в {0} на позиции {1}!!Invalid value in {0} at index {1}';
ER_ARG_NAN_INF =
'Аргумент {0} содержит NaN или Infinity!!Argument {0} contains NaN or Infinity';
ER_CH_NEEDS_2_CLUSTERS =
'Для CalinskiHarabasz требуется минимум 2 кластера!!CalinskiHarabasz requires at least 2 clusters';
ER_CH_NEEDS_N_GT_K =
@ -715,6 +738,12 @@ begin
var y := yTrue[i];
var yp := yPred[i];
if double.IsNaN(y) or double.IsInfinity(y) then
ArgumentError(ER_ARG_NAN_INF, 'yTrue');
if double.IsNaN(yp) or double.IsInfinity(yp) then
ArgumentError(ER_ARG_NAN_INF, 'yPred');
if y = 0.0 then continue;
sum += Abs((y - yp) / y);
@ -932,9 +961,6 @@ begin
fprList.Add(fpr);
end;
fprList.Add(1.0);
tprList.Add(1.0);
Result := (new Vector(fprList.ToArray),
new Vector(tprList.ToArray));
end;
@ -1675,9 +1701,9 @@ end;
/// 1 идеальное совпадение кластеризации и истинных меток
/// 0 случайное разбиение
/// <0 хуже случайного
/// Сложность: O(). При больших n может быть медленным.
/// Для больших выборок рекомендуется использовать альтернативную реализацию
/// через таблицу сопряжённости (contingency table) с асимптотикой O(n · k)
/// Использует таблицу сопряжённости (contingency table).
/// Сложность: O(n + kT * kP),
/// где kT и kP числа различных классов в yTrue и yPred.
static function Metrics.AdjustedRandIndex(yTrue, yPred: Vector): real;
begin
if yTrue = nil then
@ -1697,14 +1723,8 @@ begin
end;
// --- Vector -> int[]
var yTInt := new integer[n];
var yPInt := new integer[n];
for var i := 0 to n - 1 do
begin
yTInt[i] := Round(yTrue[i]);
yPInt[i] := Round(yPred[i]);
end;
var yTInt := LabelsToInts(yTrue);
var yPInt := LabelsToInts(yPred);
// --- encoding
var classesTrue: array of integer;
@ -1977,7 +1997,7 @@ end;
function ConfusionMatrix.GetIndex(labl: integer): integer;
begin
if not fLabelToIndex.ContainsKey(labl) then
if labl not in fLabelToIndex then
ArgumentError(ER_INVALID_CLASS_LABEL, labl);
Result := fLabelToIndex[labl];

View file

@ -36,6 +36,8 @@ type
/// Выполняет Fit и Transform последовательно
function FitTransform(df: DataFrame): DataFrame;
/// Копирует только конфигурацию препроцессора (без обученного состояния).
/// Используется для создания независимых экземпляров препроцессора.
function Clone: IPreprocessor;
end;
@ -72,15 +74,8 @@ type
property ColumnName: string read col;
/// Создаёт копию препроцессора с той же конфигурацией.
///
/// ВАЖНО:
/// Clone копирует только конфигурацию (например, имя столбца)
/// Clone НЕ копирует обученное состояние (mapping, статистики и т.п.)
///
/// Назначение:
/// использование в Pipeline и CrossValidate
/// обеспечивает независимое переобучение препроцессоров
/// Копирует только конфигурацию препроцессора (без обученного состояния).
/// Используется для создания независимых экземпляров препроцессора.
function Clone: IPreprocessor;
end;
@ -118,15 +113,8 @@ type
function GetExpandedColumns(sourceColumn: string): array of string;
/// Создаёт копию препроцессора с той же конфигурацией.
///
/// ВАЖНО:
/// Clone копирует только конфигурацию (например, имя столбца)
/// Clone НЕ копирует обученное состояние (mapping, статистики и т.п.)
///
/// Назначение:
/// использование в Pipeline и CrossValidate
/// обеспечивает независимое переобучение препроцессоров
/// Копирует только конфигурацию препроцессора (без обученного состояния).
/// Используется для создания независимых экземпляров препроцессора.
function Clone: IPreprocessor;
end;
@ -171,15 +159,8 @@ type
property Columns: array of string read cols;
/// Создаёт копию препроцессора с той же конфигурацией.
///
/// ВАЖНО:
/// Clone копирует только конфигурацию (например, имя столбца)
/// Clone НЕ копирует обученное состояние (mapping, статистики и т.п.)
///
/// Назначение:
/// использование в Pipeline и CrossValidate
/// обеспечивает независимое переобучение препроцессоров
/// Копирует только конфигурацию препроцессора (без обученного состояния).
/// Используется для создания независимых экземпляров препроцессора.
function Clone: IPreprocessor;
end;
@ -698,7 +679,7 @@ begin
res := res.ReplaceColumnInt(
name,
c -> (if c.IsValid(idx) then c.Int(idx) else k)
c -> (if c.IsValid(capturedIdx) then c.Int(capturedIdx) else k)
);
end
else // ctFloat
@ -789,4 +770,4 @@ begin
end;
end;
end.
end.

View file

@ -96,6 +96,9 @@ type
/// лучший параметр,
/// лучшее среднее значение метрики,
/// модель, обученная на всём датасете с лучшим параметром
///
/// Все параметры оцениваются на одном и том же разбиении данных
/// (используется фиксированный seed), что обеспечивает корректное и сопоставимое сравнение моделей
class function Search<T, P>(
modelFactory: P -> T;
paramValues: array of P;
@ -460,17 +463,6 @@ begin
if (k < 2) or (k > X.RowCount) then
ArgumentError(ER_K_INVALID_STRATIFIED, k, X.RowCount);
var labels := y.ToIntArray;
var classCounts := labels.EachCount;
var minCount := integer.MaxValue;
foreach var pair in classCounts do
if pair.Value < minCount then
minCount := pair.Value;
if k > minCount then
ArgumentError(ER_STRATIFIED_K_TOO_LARGE, k, minCount);
var baseSeed :=
if seed >= 0 then seed
else System.Environment.TickCount and integer.MaxValue;