Ряд исправлений в ML библиотеках
This commit is contained in:
parent
9e36ff2abc
commit
728852276d
|
|
@ -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 = "3821";
|
||||
public const string Revision = "3823";
|
||||
|
||||
public const string MainVersion = Major + "." + Minor;
|
||||
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
%MINOR%=11
|
||||
%REVISION%=3821
|
||||
%REVISION%=3823
|
||||
%COREVERSION%=1
|
||||
%MAJOR%=3
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
3.11.1.3821
|
||||
3.11.1.3823
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
name = TitanicRu
|
||||
name = TitanicRu
|
||||
|
||||
task = classification
|
||||
|
||||
|
|
@ -56,9 +56,14 @@ value.Класс.1.en = first class
|
|||
value.Класс.2.en = second class
|
||||
value.Класс.3.en = third class
|
||||
|
||||
value.Пол.муж.ru = муж
|
||||
value.Пол.жен.ru = жен
|
||||
value.Пол.муж.en = male
|
||||
value.Пол.жен.en = female
|
||||
|
||||
value.ПортПосадки.Саутгемптон.ru = Саутгемптон
|
||||
value.ПортПосадки.Шербур.ru = Шербур
|
||||
value.ПортПосадки.Квинстаун.ru = Квинстаун
|
||||
value.ПортПосадки.Саутгемптон.en = Southampton
|
||||
value.ПортПосадки.Шербур.en = Cherbourg
|
||||
value.ПортПосадки.Квинстаун.en = Queenstown
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
!define VERSION '3.11.1.3821'
|
||||
!define VERSION '3.11.1.3823'
|
||||
|
|
|
|||
|
|
@ -39,15 +39,39 @@ begin
|
|||
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
|
||||
case col.Info.ColType of
|
||||
ColumnType.ctInt:
|
||||
begin
|
||||
var c := IntColumn(col);
|
||||
for var i := 0 to n - 1 do
|
||||
begin
|
||||
if not c.IsValid[i] then
|
||||
ArgumentError(ER_TO_MATRIX_NON_NUMERIC, colNames[j]);
|
||||
Result[i,j] := c.Data[i];
|
||||
end;
|
||||
end;
|
||||
ColumnType.ctFloat:
|
||||
begin
|
||||
var c := FloatColumn(col);
|
||||
for var i := 0 to n - 1 do
|
||||
begin
|
||||
if not c.IsValid[i] then
|
||||
ArgumentError(ER_TO_MATRIX_NON_NUMERIC, colNames[j]);
|
||||
Result[i,j] := c.Data[i];
|
||||
end;
|
||||
end;
|
||||
ColumnType.ctBool:
|
||||
begin
|
||||
var c := BoolColumn(col);
|
||||
for var i := 0 to n - 1 do
|
||||
begin
|
||||
if not c.IsValid[i] then
|
||||
ArgumentError(ER_TO_MATRIX_NON_NUMERIC, colNames[j]);
|
||||
Result[i,j] := if c.Data[i] then 1.0 else 0.0;
|
||||
end;
|
||||
end;
|
||||
else
|
||||
ArgumentError(ER_TO_MATRIX_NON_NUMERIC, colNames[j]);
|
||||
|
||||
Result[i,j] := value;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
|
@ -59,15 +83,39 @@ begin
|
|||
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
|
||||
case col.Info.ColType of
|
||||
ColumnType.ctInt:
|
||||
begin
|
||||
var c := IntColumn(col);
|
||||
for var i := 0 to n - 1 do
|
||||
begin
|
||||
if not c.IsValid[i] then
|
||||
ArgumentError(ER_TO_VECTOR_NON_NUMERIC, colName);
|
||||
Result[i] := c.Data[i];
|
||||
end;
|
||||
end;
|
||||
ColumnType.ctFloat:
|
||||
begin
|
||||
var c := FloatColumn(col);
|
||||
for var i := 0 to n - 1 do
|
||||
begin
|
||||
if not c.IsValid[i] then
|
||||
ArgumentError(ER_TO_VECTOR_NON_NUMERIC, colName);
|
||||
Result[i] := c.Data[i];
|
||||
end;
|
||||
end;
|
||||
ColumnType.ctBool:
|
||||
begin
|
||||
var c := BoolColumn(col);
|
||||
for var i := 0 to n - 1 do
|
||||
begin
|
||||
if not c.IsValid[i] then
|
||||
ArgumentError(ER_TO_VECTOR_NON_NUMERIC, colName);
|
||||
Result[i] := if c.Data[i] then 1.0 else 0.0;
|
||||
end;
|
||||
end;
|
||||
else
|
||||
ArgumentError(ER_TO_VECTOR_NON_NUMERIC, colName);
|
||||
|
||||
Result[i] := value;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ type
|
|||
columns: List<Column>;
|
||||
fschema: DataFrameSchema;
|
||||
|
||||
procedure RebuildSchema;
|
||||
procedure CommitAddedColumn(c: Column);
|
||||
procedure ValidateColumnsAgainstSchema;
|
||||
procedure ValidateColumnsAgainstSchema(candidate: DataFrameSchema);
|
||||
|
|
@ -194,19 +193,24 @@ type
|
|||
/// Не изменяйте их после передачи в DataFrame.
|
||||
procedure AddBoolColumn(name: string; data: array of boolean; valid: array of boolean := nil);
|
||||
|
||||
/// Возвращает внутренний буфер целочисленного столбца без копирования.
|
||||
/// Не изменяйте его, иначе DataFrame будет повреждён.
|
||||
/// Возвращает целочисленный массив значений столбца с данным именем.
|
||||
function GetIntColumn(name: string): array of integer;
|
||||
/// Возвращает внутренний буфер вещественного столбца без копирования.
|
||||
/// Не изменяйте его, иначе DataFrame будет повреждён.
|
||||
/// Возвращает вещественный массив значений столбца с данным именем.
|
||||
function GetFloatColumn(name: string): array of real;
|
||||
/// Возвращает внутренний буфер строкового столбца без копирования.
|
||||
/// Не изменяйте его, иначе DataFrame будет повреждён.
|
||||
/// Возвращает строковый массив значений столбца с данным именем.
|
||||
function GetStrColumn(name: string): array of string;
|
||||
/// Возвращает внутренний буфер логического столбца без копирования.
|
||||
/// Не изменяйте его, иначе DataFrame будет повреждён.
|
||||
/// Возвращает логический массив значений столбца с данным именем.
|
||||
function GetBoolColumn(name: string): array of boolean;
|
||||
|
||||
/// Возвращает целочисленный массив значений столбца с данным именем.
|
||||
function Int(name: string): array of integer;
|
||||
/// Возвращает вещественный массив значений столбца с данным именем.
|
||||
function Float(name: string): array of real;
|
||||
/// Возвращает строковый массив значений столбца с данным именем.
|
||||
function Str(name: string): array of string;
|
||||
/// Возвращает логический массив значений столбца с данным именем.
|
||||
function Bool(name: string): array of boolean;
|
||||
|
||||
/// Вычисляет сумму значений столбца по индексу
|
||||
function Sum(colIndex: integer): real;
|
||||
/// Вычисляет сумму значений столбца по имени
|
||||
|
|
@ -2170,29 +2174,6 @@ begin
|
|||
Result.AssertSchemaConsistent;
|
||||
end;
|
||||
|
||||
procedure DataFrame.RebuildSchema;
|
||||
begin
|
||||
var n := columns.Count;
|
||||
var names := new string[n];
|
||||
var types := new ColumnType[n];
|
||||
var cats := new boolean[n];
|
||||
|
||||
for var i := 0 to n - 1 do
|
||||
begin
|
||||
var info := columns[i].Info;
|
||||
names[i] := info.Name;
|
||||
types[i] := info.ColType;
|
||||
|
||||
// берем из старой schema
|
||||
if (fSchema <> nil) and (i < fSchema.ColumnCount) then
|
||||
cats[i] := fSchema.CategoricalFlags[i]
|
||||
else
|
||||
cats[i] := false;
|
||||
end;
|
||||
|
||||
fSchema := new DataFrameSchema(names, types, cats);
|
||||
end;
|
||||
|
||||
procedure DataFrame.CommitAddedColumn(c: Column);
|
||||
begin
|
||||
var n := columns.Count;
|
||||
|
|
@ -2206,7 +2187,7 @@ begin
|
|||
names[i] := info.Name;
|
||||
types[i] := info.ColType;
|
||||
if fSchema <> nil then
|
||||
cats[i] := fSchema.CategoricalFlags[i]
|
||||
cats[i] := fSchema.IsCategoricalAt(i)
|
||||
else
|
||||
cats[i] := false;
|
||||
end;
|
||||
|
|
@ -2322,6 +2303,26 @@ begin
|
|||
Result := c.Data;
|
||||
end;
|
||||
|
||||
function DataFrame.Int(name: string): array of integer;
|
||||
begin
|
||||
Result := GetIntColumn(name);
|
||||
end;
|
||||
|
||||
function DataFrame.Float(name: string): array of real;
|
||||
begin
|
||||
Result := GetFloatColumn(name);
|
||||
end;
|
||||
|
||||
function DataFrame.Str(name: string): array of string;
|
||||
begin
|
||||
Result := GetStrColumn(name);
|
||||
end;
|
||||
|
||||
function DataFrame.Bool(name: string): array of boolean;
|
||||
begin
|
||||
Result := GetBoolColumn(name);
|
||||
end;
|
||||
|
||||
function DataFrame.TrainTestSplit(testRatio: real; shuffle: boolean; seed: integer): (DataFrame, DataFrame);
|
||||
begin
|
||||
if Self = nil then
|
||||
|
|
@ -2595,7 +2596,7 @@ function DataFrame.Mean(colName: string): real
|
|||
function DataFrame.Median(colIndex: integer): real;
|
||||
begin
|
||||
CheckColumnIndex(colIndex);
|
||||
Result := Statistics.Median(Self, fSchema.ColumnNames[colIndex]);
|
||||
Result := Statistics.Median(Self, fSchema.NameAt(colIndex));
|
||||
end;
|
||||
|
||||
function DataFrame.Median(colName: string): real;
|
||||
|
|
@ -3086,7 +3087,7 @@ begin
|
|||
|
||||
// копируем старые значения
|
||||
for var i := 0 to n - 1 do
|
||||
cats[i] := fSchema.CategoricalFlags[i];
|
||||
cats[i] := fSchema.IsCategoricalAt(i);
|
||||
|
||||
// применяем новые
|
||||
foreach var name in names do
|
||||
|
|
@ -3207,7 +3208,7 @@ begin
|
|||
// КЛЮЧЕВОЕ: перенос schema
|
||||
var cats := new boolean[ColumnCount];
|
||||
for var i := 0 to ColumnCount - 1 do
|
||||
cats[i] := fSchema.CategoricalFlags[i];
|
||||
cats[i] := fSchema.IsCategoricalAt(i);
|
||||
|
||||
res.SetSchema(new DataFrameSchema(
|
||||
fSchema.ColumnNames,
|
||||
|
|
@ -3311,12 +3312,12 @@ begin
|
|||
|
||||
for var i := 0 to n - 1 do
|
||||
begin
|
||||
var oldName := fSchema.ColumnNames[i];
|
||||
var oldName := fSchema.NameAt(i);
|
||||
var newName := if map.ContainsKey(oldName) then map[oldName] else oldName;
|
||||
|
||||
names[i] := newName;
|
||||
types[i] := fSchema.Types[i];
|
||||
cats[i] := fSchema.CategoricalFlags[i];
|
||||
types[i] := fSchema.ColumnTypeAt(i);
|
||||
cats[i] := fSchema.IsCategoricalAt(i);
|
||||
end;
|
||||
|
||||
res.SetSchema(new DataFrameSchema(names, types, cats));
|
||||
|
|
@ -3565,9 +3566,9 @@ begin
|
|||
|
||||
for var j := 0 to oldN - 1 do
|
||||
begin
|
||||
names[j] := fSchema.ColumnNames[j];
|
||||
types[j] := fSchema.Types[j];
|
||||
cats[j] := fSchema.CategoricalFlags[j];
|
||||
names[j] := fSchema.NameAt(j);
|
||||
types[j] := fSchema.ColumnTypeAt(j);
|
||||
cats[j] := fSchema.IsCategoricalAt(j);
|
||||
end;
|
||||
|
||||
names[oldN] := name;
|
||||
|
|
@ -4260,7 +4261,7 @@ begin
|
|||
|
||||
for var i := 0 to ColumnCount - 1 do
|
||||
begin
|
||||
var name := fSchema.ColumnNames[i].PadRight(nameWidth);
|
||||
var name := fSchema.NameAt(i).PadRight(nameWidth);
|
||||
var typ := GetColumnType(i).ToString.Replace('ct','').PadRight(typeWidth);
|
||||
PABCSystem.Println($'{name} : {typ}');
|
||||
end;
|
||||
|
|
@ -4290,7 +4291,7 @@ begin
|
|||
for var i := 0 to ColumnCount - 1 do
|
||||
begin
|
||||
var t := ColumnTypeToString(GetColumnType(i));
|
||||
if fSchema.CategoricalFlags[i] then
|
||||
if fSchema.IsCategoricalAt(i) then
|
||||
t += ' (categorical)';
|
||||
|
||||
types[i] := t;
|
||||
|
|
@ -4305,7 +4306,7 @@ begin
|
|||
|
||||
for var i := 0 to ColumnCount - 1 do
|
||||
begin
|
||||
var name := fSchema.ColumnNames[i].PadRight(nameWidth);
|
||||
var name := fSchema.NameAt(i).PadRight(nameWidth);
|
||||
var typ := types[i].PadRight(maxTypeWidth);
|
||||
var cnt := Count(i);
|
||||
|
||||
|
|
@ -4428,15 +4429,15 @@ begin
|
|||
|
||||
for var i := 0 to n - 1 do
|
||||
begin
|
||||
var name := fSchema.ColumnNames[i];
|
||||
var name := fSchema.NameAt(i);
|
||||
|
||||
namesArr[i] := name;
|
||||
cats[i] := fSchema.CategoricalFlags[i];
|
||||
cats[i] := fSchema.IsCategoricalAt(i);
|
||||
|
||||
if toCast.Contains(name) then
|
||||
types[i] := ctInt
|
||||
else
|
||||
types[i] := fSchema.Types[i];
|
||||
types[i] := fSchema.ColumnTypeAt(i);
|
||||
end;
|
||||
|
||||
res.SetSchema(new DataFrameSchema(namesArr, types, cats));
|
||||
|
|
@ -5538,7 +5539,7 @@ begin
|
|||
// числовые столбцы
|
||||
for var i := 0 to df.ColumnCount - 1 do
|
||||
if df.GetColumnType(i) in [ColumnType.ctInt, ColumnType.ctFloat] then
|
||||
names.Add(df.fSchema.ColumnNames[i]);
|
||||
names.Add(df.fSchema.NameAt(i));
|
||||
|
||||
var n := names.Count;
|
||||
if n = 0 then
|
||||
|
|
@ -5626,7 +5627,7 @@ begin
|
|||
means[i] := mean;
|
||||
stds[i] := Sqrt(variance);
|
||||
if stds[i] = 0 then
|
||||
Error(ER_ZERO_STD_COLUMN, df.fSchema.ColumnNames[i]);
|
||||
Error(ER_ZERO_STD_COLUMN, df.fSchema.NameAt(i));
|
||||
isNumeric[i] := true;
|
||||
end;
|
||||
end;
|
||||
|
|
@ -5635,7 +5636,7 @@ begin
|
|||
for var i := 0 to df.ColumnCount - 1 do
|
||||
begin
|
||||
if isNumeric[i] then
|
||||
res.AddFloatColumn(df.fSchema.ColumnNames[i], new real[df.RowCount], nil)
|
||||
res.AddFloatColumn(df.fSchema.NameAt(i), new real[df.RowCount], nil)
|
||||
else
|
||||
res.AddColumnAlias(df.GetColumn(i));
|
||||
end;
|
||||
|
|
@ -5708,7 +5709,7 @@ begin
|
|||
begin
|
||||
var (mn, mx) := df.MinMax(i);
|
||||
if mn = mx then
|
||||
Error(ER_ZERO_RANGE_COLUMN, df.fSchema.ColumnNames[i]);
|
||||
Error(ER_ZERO_RANGE_COLUMN, df.fSchema.NameAt(i));
|
||||
mins[i] := mn;
|
||||
maxs[i] := mx;
|
||||
isNumeric[i] := true;
|
||||
|
|
@ -5719,7 +5720,7 @@ begin
|
|||
for var i := 0 to df.ColumnCount - 1 do
|
||||
begin
|
||||
if isNumeric[i] then
|
||||
res.AddFloatColumn(df.fSchema.ColumnNames[i], new real[df.RowCount], nil)
|
||||
res.AddFloatColumn(df.fSchema.NameAt(i), new real[df.RowCount], nil)
|
||||
else
|
||||
res.AddColumnAlias(df.GetColumn(i));
|
||||
end;
|
||||
|
|
|
|||
|
|
@ -39,36 +39,55 @@ type
|
|||
function GetTypes: array of ColumnType;
|
||||
function GetCategoricalFlags: array of boolean;
|
||||
public
|
||||
/// Возвращает количество столбцов в схеме
|
||||
property ColumnCount: integer read fNames.Length;
|
||||
/// Возвращает копию массива имён столбцов
|
||||
property ColumnNames: array of string read GetColumnNames;
|
||||
/// Возвращает копию массива типов столбцов
|
||||
property Types: array of ColumnType read GetTypes;
|
||||
/// Возвращает копию массива categorical-флагов
|
||||
property CategoricalFlags: array of boolean read GetCategoricalFlags;
|
||||
|
||||
/// Возвращает индекс столбца по имени
|
||||
function IndexOf(name: string): integer;
|
||||
/// Проверяет наличие столбца с указанным именем
|
||||
function HasColumn(name: string): boolean;
|
||||
|
||||
/// Возвращает тип столбца по индексу
|
||||
function ColumnTypeAt(i: integer): ColumnType;
|
||||
/// Проверяет categorical-флаг столбца по индексу
|
||||
function IsCategoricalAt(i: integer): boolean;
|
||||
|
||||
/// Возвращает тип столбца по имени
|
||||
function GetColumnType(name: string): ColumnType;
|
||||
/// Проверяет categorical-флаг столбца по имени
|
||||
function IsCategorical(name: string): boolean;
|
||||
|
||||
/// Возвращает имя столбца по индексу
|
||||
function NameAt(i: integer): string;
|
||||
|
||||
/// Создаёт схему по именам, типам и categorical-флагам
|
||||
constructor Create(names: array of string; types: array of ColumnType;
|
||||
isCategorical: array of boolean := nil);
|
||||
|
||||
/// Печатает схему без перевода строки в конце
|
||||
procedure Print;
|
||||
|
||||
/// Печатает схему и переводит строку
|
||||
procedure Println;
|
||||
|
||||
{ --- schema operations (immutable) --- }
|
||||
/// Возвращает схему, содержащую только указанные столбцы
|
||||
function Select(indices: array of integer): DataFrameSchema;
|
||||
/// Возвращает схему без указанных столбцов
|
||||
function Drop(indices: array of integer): DataFrameSchema;
|
||||
/// Возвращает схему с переименованным столбцом
|
||||
function Rename(oldName, newName: string): DataFrameSchema;
|
||||
/// Возвращает схему с изменённым categorical-флагом столбца
|
||||
function WithCategorical(name: string; value: boolean := True): DataFrameSchema;
|
||||
|
||||
{ --- join helpers --- }
|
||||
/// Объединяет две схемы по правилам Join
|
||||
class function Merge(
|
||||
left, right: DataFrameSchema;
|
||||
leftKeys, rightKeys: array of integer;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ type
|
|||
DataFrame = DataFrameABC.DataFrame;
|
||||
DataFrameCursor = DataFrameABCCore.DataFrameCursor;
|
||||
ColumnType = DataFrameABCCore.ColumnType;
|
||||
Column = DataFrameABCCore.Column;
|
||||
|
||||
Statistics = DataFrameABC.Statistics;
|
||||
CsvLoader = DataFrameABC.CsvLoader;
|
||||
|
|
@ -127,6 +128,7 @@ type
|
|||
|
||||
Datasets = MLDatasets.Datasets;
|
||||
Dataset = MLDatasets.Dataset;
|
||||
LabelEncoder = MLDatasets.LabelEncoder;
|
||||
|
||||
IModel = MLCoreABC.IModel;
|
||||
ISupervisedModel = MLCoreABC.ISupervisedModel;
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ type
|
|||
/// как признаков X, так и целевой переменной y.
|
||||
/// Запоминает необходимые параметры, которые будут использоваться при Transform.
|
||||
function Fit(X: Matrix; y: Vector): ISupervisedTransformer;
|
||||
function FitTransform(X: Matrix; y: Vector): Matrix;
|
||||
end;
|
||||
|
||||
/// Интерфейс преобразования признаков без учёта целевой переменной.
|
||||
|
|
@ -167,6 +168,7 @@ type
|
|||
/// Обучает преобразование на данных с использованием признаков X
|
||||
/// Запоминает необходимые параметры, которые будут использоваться при Transform.
|
||||
function Fit(X: Matrix): IUnsupervisedTransformer;
|
||||
function FitTransform(X: Matrix): Matrix;
|
||||
end;
|
||||
|
||||
IColumnExpander = interface
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ type
|
|||
private
|
||||
function ValueLabel(feature, value: string): string;
|
||||
function CloneMeta(df: DataFrame): Dataset;
|
||||
function GetCategoricalFeatures: array of string;
|
||||
public
|
||||
FeatureLabels: Dictionary<string,string>;
|
||||
ValueLabels: Dictionary<string,Dictionary<string,string>>;
|
||||
|
|
@ -65,10 +66,34 @@ type
|
|||
function RowCount: integer := Data.RowCount;
|
||||
|
||||
function GetFeatureColumns: array of string;
|
||||
property CategoricalFeatures: array of string read GetCategoricalFeatures;
|
||||
|
||||
function HasTarget: boolean;
|
||||
end;
|
||||
|
||||
/// Кодирует target-колонку классификационного Dataset в числовой Vector.
|
||||
/// Используется только для целевой переменной, не для признаков.
|
||||
LabelEncoder = class
|
||||
private
|
||||
fClasses: array of string;
|
||||
fClassToIndex: Dictionary<string, integer>;
|
||||
|
||||
function GetClasses: array of string;
|
||||
procedure EnsureFitted;
|
||||
procedure CheckDataset(ds: Dataset);
|
||||
function TargetLabels(ds: Dataset): array of string;
|
||||
public
|
||||
function Fit(ds: Dataset): LabelEncoder;
|
||||
function Transform(ds: Dataset): Vector;
|
||||
function FitTransform(ds: Dataset): Vector;
|
||||
|
||||
property Classes: array of string read GetClasses;
|
||||
|
||||
function ClassName(index: integer): string;
|
||||
function ClassIndex(name: string): integer;
|
||||
function Decode(y: Vector): array of string;
|
||||
end;
|
||||
|
||||
/// Набор генераторов и загрузчиков датасетов для задач машинного обучения.
|
||||
/// Содержит синтетические генераторы (MakeBlobs, MakeMoons, MakeRegression)
|
||||
/// и реальные учебные датасеты (например, RussianHousing, StudentExam).
|
||||
|
|
@ -263,6 +288,10 @@ type
|
|||
|
||||
/// Датасет пассажиров Титаника (задача классификации)
|
||||
static function TitanicRu: Dataset;
|
||||
|
||||
/// Датасет цен на автомобили с пробегом (задача регрессии)
|
||||
static function UsedCarsPrice: Dataset;
|
||||
|
||||
|
||||
{/// Датасет результатов экзамена студентов (классификация)
|
||||
static function StudentExam: Dataset;
|
||||
|
|
@ -340,6 +369,13 @@ const
|
|||
ER_ENCODELABELS_UNSUPPORTED_TYPE =
|
||||
'Неподдерживаемый тип столбца для кодирования меток: {0}!!' +
|
||||
'Unsupported column type for label encoding: {0}';
|
||||
ER_LABEL_ENCODER_NOT_FITTED =
|
||||
'LabelEncoder не обучен. Сначала вызовите Fit или FitTransform.!!' +
|
||||
'LabelEncoder is not fitted. Call Fit or FitTransform first.';
|
||||
ER_LABEL_ENCODER_UNKNOWN_CLASS =
|
||||
'Неизвестная метка класса: {0}!!Unknown class label: {0}';
|
||||
ER_LABEL_ENCODER_INDEX_OUT_OF_RANGE =
|
||||
'Индекс класса вне диапазона: {0}!!Class index out of range: {0}';
|
||||
|
||||
C_DATASET = 'Датасет: {0}!!Dataset: {0}';
|
||||
C_DESCRIPTION = 'Описание:!!Description:';
|
||||
|
|
@ -352,6 +388,7 @@ const
|
|||
C_URL = 'Ссылка: {0}!!URL: {0}';
|
||||
C_CLASSES = 'Классов: {0}!!Classes: {0}';
|
||||
C_FEATURE_LIST = 'Признаки:!!Features:';
|
||||
C_CATEGORICAL = 'Категориальные признаки: {0}!!Categorical features: {0}';
|
||||
|
||||
function Normal(rnd: System.Random): real;
|
||||
begin
|
||||
|
|
@ -509,6 +546,9 @@ begin
|
|||
if (Target <> nil) and (Target <> '') then
|
||||
PrintlnTr(C_TARGET, Target);
|
||||
|
||||
if CategoricalFeatures.Length > 0 then
|
||||
PrintlnTr(C_CATEGORICAL, CategoricalFeatures.JoinToString(', '));
|
||||
|
||||
Println;
|
||||
|
||||
var maxLen := Features.Max(f -> f.Length);
|
||||
|
|
@ -604,12 +644,153 @@ begin
|
|||
Result := Data.Schema.ColumnNames;
|
||||
end;
|
||||
|
||||
function Dataset.GetCategoricalFeatures: array of string;
|
||||
begin
|
||||
Result := Features
|
||||
.Where(f -> Data.IsCategorical(f))
|
||||
.ToArray;
|
||||
end;
|
||||
|
||||
function Dataset.HasTarget: boolean;
|
||||
begin
|
||||
Result := (Target <> nil) and (Target <> '');
|
||||
end;
|
||||
|
||||
|
||||
//-----------------------------
|
||||
// LabelEncoder
|
||||
//-----------------------------
|
||||
|
||||
function LabelEncoder.GetClasses: array of string;
|
||||
begin
|
||||
EnsureFitted;
|
||||
Result := Copy(fClasses);
|
||||
end;
|
||||
|
||||
procedure LabelEncoder.EnsureFitted;
|
||||
begin
|
||||
if (fClasses = nil) or (fClassToIndex = nil) then
|
||||
Error(ER_LABEL_ENCODER_NOT_FITTED);
|
||||
end;
|
||||
|
||||
procedure LabelEncoder.CheckDataset(ds: Dataset);
|
||||
begin
|
||||
if ds = nil then
|
||||
ArgumentNullError(ER_ARG_NULL, 'ds');
|
||||
|
||||
if ds.Data = nil then
|
||||
ArgumentNullError(ER_ARG_NULL, 'Data');
|
||||
|
||||
if ds.Task <> TaskType.Classification then
|
||||
ArgumentError(ER_CLASSES_ONLY_CLASSIFICATION);
|
||||
|
||||
if not ds.HasTarget then
|
||||
ArgumentError(ER_DATASET_TARGET_MISSING);
|
||||
|
||||
if not ds.Data.HasColumn(ds.Target) then
|
||||
ArgumentError(ER_DATASET_TARGET_NOT_FOUND, ds.Target);
|
||||
end;
|
||||
|
||||
function LabelEncoder.TargetLabels(ds: Dataset): array of string;
|
||||
begin
|
||||
CheckDataset(ds);
|
||||
|
||||
case ds.Data.GetColumnType(ds.Target) of
|
||||
ColumnType.ctStr:
|
||||
Result := ds.Data.GetStrColumn(ds.Target);
|
||||
ColumnType.ctInt:
|
||||
Result := ds.Data.GetIntColumn(ds.Target).Select(x -> x.ToString).ToArray;
|
||||
else
|
||||
ArgumentError(ER_ENCODELABELS_UNSUPPORTED_TYPE, ds.Target);
|
||||
end;
|
||||
end;
|
||||
|
||||
function LabelEncoder.Fit(ds: Dataset): LabelEncoder;
|
||||
begin
|
||||
var labels := TargetLabels(ds);
|
||||
|
||||
var classes := new List<string>;
|
||||
fClassToIndex := new Dictionary<string, integer>;
|
||||
|
||||
foreach var labelName in labels do
|
||||
if not fClassToIndex.ContainsKey(labelName) then
|
||||
begin
|
||||
fClassToIndex[labelName] := classes.Count;
|
||||
classes.Add(labelName);
|
||||
end;
|
||||
|
||||
fClasses := classes.ToArray;
|
||||
Result := self;
|
||||
end;
|
||||
|
||||
function LabelEncoder.Transform(ds: Dataset): Vector;
|
||||
begin
|
||||
EnsureFitted;
|
||||
|
||||
var labels := TargetLabels(ds);
|
||||
var y := new integer[labels.Length];
|
||||
|
||||
for var i := 0 to labels.Length - 1 do
|
||||
begin
|
||||
var labelName := labels[i];
|
||||
|
||||
if not fClassToIndex.ContainsKey(labelName) then
|
||||
ArgumentError(ER_LABEL_ENCODER_UNKNOWN_CLASS, labelName);
|
||||
|
||||
y[i] := fClassToIndex[labelName];
|
||||
end;
|
||||
|
||||
Result := new Vector(y);
|
||||
end;
|
||||
|
||||
function LabelEncoder.FitTransform(ds: Dataset): Vector;
|
||||
begin
|
||||
Fit(ds);
|
||||
Result := Transform(ds);
|
||||
end;
|
||||
|
||||
function LabelEncoder.ClassName(index: integer): string;
|
||||
begin
|
||||
EnsureFitted;
|
||||
|
||||
if (index < 0) or (index >= fClasses.Length) then
|
||||
ArgumentError(ER_LABEL_ENCODER_INDEX_OUT_OF_RANGE, index);
|
||||
|
||||
Result := fClasses[index];
|
||||
end;
|
||||
|
||||
function LabelEncoder.ClassIndex(name: string): integer;
|
||||
begin
|
||||
EnsureFitted;
|
||||
|
||||
if not fClassToIndex.ContainsKey(name) then
|
||||
ArgumentError(ER_LABEL_ENCODER_UNKNOWN_CLASS, name);
|
||||
|
||||
Result := fClassToIndex[name];
|
||||
end;
|
||||
|
||||
function LabelEncoder.Decode(y: Vector): array of string;
|
||||
begin
|
||||
EnsureFitted;
|
||||
|
||||
if y = nil then
|
||||
ArgumentNullError(ER_ARG_NULL, 'y');
|
||||
|
||||
Result := new string[y.Length];
|
||||
|
||||
for var i := 0 to y.Length - 1 do
|
||||
begin
|
||||
var value := y.Data[i];
|
||||
var index := Round(value);
|
||||
|
||||
if (Abs(value - index) > 1e-12) or (index < 0) or (index >= fClasses.Length) then
|
||||
ArgumentError(ER_LABEL_ENCODER_INDEX_OUT_OF_RANGE, index);
|
||||
|
||||
Result[i] := fClasses[index];
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
//-----------------------------
|
||||
// Datasets
|
||||
//-----------------------------
|
||||
|
|
@ -1174,6 +1355,18 @@ begin
|
|||
ArgumentError(ER_DATASET_TASK_MISSING, name);
|
||||
|
||||
var df := DataFrame.FromCsv(csvPath);
|
||||
var categoricalCols := new List<string>;
|
||||
|
||||
foreach var k in meta.Keys do
|
||||
if k.StartsWith('feature.') and not k.EndsWith('.ru') and not k.EndsWith('.en') then
|
||||
begin
|
||||
var colName := k.Substring('feature.'.Length);
|
||||
if (meta[k] = 'categorical') and df.HasColumn(colName) then
|
||||
categoricalCols.Add(colName);
|
||||
end;
|
||||
|
||||
if categoricalCols.Count > 0 then
|
||||
df := df.SetCategorical(categoricalCols.ToArray);
|
||||
|
||||
var ds := new Dataset;
|
||||
|
||||
|
|
@ -1255,50 +1448,27 @@ end;
|
|||
|
||||
static function Datasets.Iris: Dataset;
|
||||
begin
|
||||
var ds := Load('Iris');
|
||||
|
||||
ds.Data := ds.Data.SetCategorical([
|
||||
'species'
|
||||
]);
|
||||
|
||||
Result := ds;
|
||||
Result := Load('Iris');
|
||||
end;
|
||||
|
||||
static function Datasets.MoscowHousing: Dataset;
|
||||
begin
|
||||
var ds := Load('moscow_housing');
|
||||
|
||||
ds.Data := ds.Data.SetCategorical([
|
||||
'renovation'
|
||||
]);
|
||||
|
||||
Result := ds;
|
||||
Result := Load('moscow_housing');
|
||||
end;
|
||||
|
||||
static function Datasets.RussianCities: Dataset;
|
||||
begin
|
||||
var ds := Load('russian_cities');
|
||||
|
||||
ds.Data := ds.Data.SetCategorical([
|
||||
'region_name',
|
||||
'federal_district'
|
||||
]);
|
||||
|
||||
Result := ds;
|
||||
Result := Load('russian_cities');
|
||||
end;
|
||||
|
||||
static function Datasets.TitanicRu: Dataset;
|
||||
begin
|
||||
var ds := Load('titanic_ru');
|
||||
Result := Load('titanic_ru');
|
||||
end;
|
||||
|
||||
ds.Data := ds.Data.SetCategorical([
|
||||
'Выжил',
|
||||
'Класс',
|
||||
'Пол',
|
||||
'ПортПосадки'
|
||||
]);
|
||||
|
||||
Result := ds;
|
||||
static function Datasets.UsedCarsPrice: Dataset;
|
||||
begin
|
||||
Result := Load('used_cars_price');
|
||||
end;
|
||||
|
||||
{static function Datasets.StudentExam: Dataset;
|
||||
|
|
|
|||
|
|
@ -1735,7 +1735,7 @@ type
|
|||
// В отличие от этого, DataPipeline.Build используется,
|
||||
// когда исходные данные представлены в виде DataFrame
|
||||
// и требуется выполнить препроцессинг таблицы
|
||||
// (Imputer, OneHotEncoder, LabelEncoder и др.)
|
||||
// (Imputer, OneHotEncoder, OrdinalEncoder и др.)
|
||||
// перед преобразованием данных в Matrix/Vector.
|
||||
|
||||
var pipe1 :=
|
||||
|
|
@ -1932,6 +1932,9 @@ type
|
|||
/// Примечание:
|
||||
/// • вычисленные параметры НЕ копируются методом Clone
|
||||
function Fit(X: Matrix): IUnsupervisedTransformer;
|
||||
|
||||
/// Последовательно выполняет Fit и Transform на одних и тех же данных.
|
||||
function FitTransform(X: Matrix): Matrix;
|
||||
|
||||
/// Применяет стандартизацию к данным.
|
||||
function Transform(X: Matrix): Matrix;
|
||||
|
|
@ -1978,6 +1981,9 @@ type
|
|||
/// Примечание:
|
||||
/// • вычисленные параметры НЕ копируются методом Clone
|
||||
function Fit(X: Matrix): IUnsupervisedTransformer;
|
||||
|
||||
/// Последовательно выполняет Fit и Transform на одних и тех же данных.
|
||||
function FitTransform(X: Matrix): Matrix;
|
||||
|
||||
/// Применяет линейное масштабирование признаков к диапазону [0, 1].
|
||||
function Transform(X: Matrix): Matrix;
|
||||
|
|
@ -2027,6 +2033,9 @@ type
|
|||
/// Примечание:
|
||||
/// • вычисленные параметры НЕ копируются методом Clone
|
||||
function Fit(X: Matrix): IUnsupervisedTransformer;
|
||||
|
||||
/// Последовательно выполняет Fit и Transform на одних и тех же данных.
|
||||
function FitTransform(X: Matrix): Matrix;
|
||||
|
||||
/// Преобразует матрицу X в пространство главных компонент.
|
||||
/// Возвращает матрицу m × k.
|
||||
|
|
@ -2067,6 +2076,9 @@ type
|
|||
/// Примечание:
|
||||
/// • выбранные признаки НЕ копируются методом Clone
|
||||
function Fit(X: Matrix): IUnsupervisedTransformer;
|
||||
|
||||
/// Последовательно выполняет Fit и Transform на одних и тех же данных.
|
||||
function FitTransform(X: Matrix): Matrix;
|
||||
|
||||
/// Возвращает матрицу, содержащую только отобранные признаки.
|
||||
function Transform(X: Matrix): Matrix;
|
||||
|
|
@ -2151,6 +2163,9 @@ type
|
|||
/// Примечание:
|
||||
/// • выбранные признаки НЕ копируются методом Clone
|
||||
function Fit(X: Matrix; y: Vector): ISupervisedTransformer;
|
||||
|
||||
/// Последовательно выполняет Fit и Transform на одних и тех же данных.
|
||||
function FitTransform(X: Matrix; y: Vector): Matrix;
|
||||
|
||||
/// Возвращает матрицу, содержащую только выбранные признаки.
|
||||
function Transform(X: Matrix): Matrix;
|
||||
|
|
@ -2198,6 +2213,9 @@ type
|
|||
/// • у трансформера отсутствует обученное состояние
|
||||
function Fit(X: Matrix): IUnsupervisedTransformer;
|
||||
|
||||
/// Последовательно выполняет Fit и Transform на одних и тех же данных.
|
||||
function FitTransform(X: Matrix): Matrix;
|
||||
|
||||
/// Применяет нормализацию к матрице X.
|
||||
/// Каждая строка масштабируется так, чтобы ее норма соответствовала выбранному типу.
|
||||
/// Возвращает новую матрицу с нормализованными объектами.
|
||||
|
|
@ -3416,12 +3434,40 @@ end;
|
|||
|
||||
function LogisticRegression.PredictLabels(X: Matrix): array of integer;
|
||||
begin
|
||||
var P := PredictProba(X);
|
||||
|
||||
SetLength(Result, P.RowCount);
|
||||
|
||||
for var i := 0 to P.RowCount - 1 do
|
||||
Result[i] := P.RowArgMax(i);
|
||||
if not fFitted then
|
||||
NotFittedError(ER_FIT_NOT_CALLED);
|
||||
|
||||
if X = nil then
|
||||
ArgumentNullError(ER_X_NULL);
|
||||
|
||||
if MLConfig.ValidateFiniteInputs then
|
||||
CheckXForPredict(X);
|
||||
|
||||
if X.ColCount <> fW.RowCount then
|
||||
DimensionError(ER_FEATURE_COUNT_MISMATCH, X.ColCount, fW.RowCount);
|
||||
|
||||
var m := X.RowCount;
|
||||
var Z := X * fW;
|
||||
|
||||
SetLength(Result, m);
|
||||
|
||||
for var i := 0 to m - 1 do
|
||||
begin
|
||||
var best := 0;
|
||||
var bestVal := Z[i,0] + fIntercept[0];
|
||||
|
||||
for var k := 1 to fClassCount - 1 do
|
||||
begin
|
||||
var score := Z[i,k] + fIntercept[k];
|
||||
if score > bestVal then
|
||||
begin
|
||||
bestVal := score;
|
||||
best := k;
|
||||
end;
|
||||
end;
|
||||
|
||||
Result[i] := best;
|
||||
end;
|
||||
end;
|
||||
|
||||
function LogisticRegression.ToString: string;
|
||||
|
|
@ -4074,8 +4120,8 @@ begin
|
|||
|
||||
var leftOrders, rightOrders: array of array of integer;
|
||||
SplitNodeOrders(nodeOrders, split.Feature, split.LeftCount, split.LeftOrderSize, leftOrders, rightOrders);
|
||||
var leftArr := leftOrders[0];
|
||||
var rightArr := rightOrders[0];
|
||||
//var leftArr := leftOrders[0];
|
||||
//var rightArr := rightOrders[0];
|
||||
var rightCount := n - split.LeftCount;
|
||||
|
||||
if (split.LeftCount < fMinSamplesLeaf) or
|
||||
|
|
@ -6105,11 +6151,8 @@ begin
|
|||
yPred[i] := fInitValue;
|
||||
|
||||
foreach var tree in fEstimators do
|
||||
begin
|
||||
var delta := tree.Predict(X);
|
||||
for var i := 0 to n - 1 do
|
||||
yPred[i] += fLearningRate * delta[i];
|
||||
end;
|
||||
yPred[i] += fLearningRate * tree.PredictOne(X, i);
|
||||
|
||||
Result := yPred;
|
||||
end;
|
||||
|
|
@ -6912,12 +6955,8 @@ begin
|
|||
// --- накопление логитов
|
||||
foreach var trees in fEstimators do
|
||||
for var cls := 0 to classCount - 1 do
|
||||
begin
|
||||
var delta := trees[cls].Predict(X);
|
||||
|
||||
for var i := 0 to nSamples - 1 do
|
||||
logits[i, cls] += fLearningRate * delta[i];
|
||||
end;
|
||||
logits[i, cls] += fLearningRate * trees[cls].PredictOne(X, i);
|
||||
|
||||
var probs := new Matrix(nSamples, classCount);
|
||||
|
||||
|
|
@ -8786,6 +8825,12 @@ begin
|
|||
Result := Self;
|
||||
end;
|
||||
|
||||
function StandardScaler.FitTransform(X: Matrix): Matrix;
|
||||
begin
|
||||
Fit(X);
|
||||
Result := Transform(X);
|
||||
end;
|
||||
|
||||
function StandardScaler.Transform(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
|
|
@ -8880,6 +8925,12 @@ begin
|
|||
Result := Self;
|
||||
end;
|
||||
|
||||
function MinMaxScaler.FitTransform(X: Matrix): Matrix;
|
||||
begin
|
||||
Fit(X);
|
||||
Result := Transform(X);
|
||||
end;
|
||||
|
||||
function MinMaxScaler.Transform(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
|
|
@ -8998,6 +9049,12 @@ begin
|
|||
Result := Self;
|
||||
end;
|
||||
|
||||
function PCATransformer.FitTransform(X: Matrix): Matrix;
|
||||
begin
|
||||
Fit(X);
|
||||
Result := Transform(X);
|
||||
end;
|
||||
|
||||
function PCATransformer.Transform(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
|
|
@ -9075,6 +9132,12 @@ begin
|
|||
Result := Self;
|
||||
end;
|
||||
|
||||
function VarianceThreshold.FitTransform(X: Matrix): Matrix;
|
||||
begin
|
||||
Fit(X);
|
||||
Result := Transform(X);
|
||||
end;
|
||||
|
||||
function VarianceThreshold.Transform(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
|
|
@ -9396,6 +9459,12 @@ begin
|
|||
Result := Self;
|
||||
end;
|
||||
|
||||
function SelectKBest.FitTransform(X: Matrix; y: Vector): Matrix;
|
||||
begin
|
||||
Fit(X, y);
|
||||
Result := Transform(X);
|
||||
end;
|
||||
|
||||
function SelectKBest.Transform(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
|
|
@ -9465,6 +9534,12 @@ begin
|
|||
Result := Self;
|
||||
end;
|
||||
|
||||
function Normalizer.FitTransform(X: Matrix): Matrix;
|
||||
begin
|
||||
Fit(X);
|
||||
Result := Transform(X);
|
||||
end;
|
||||
|
||||
function Normalizer.Transform(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
|
|
|
|||
|
|
@ -96,6 +96,18 @@ type
|
|||
features: array of string;
|
||||
params steps: array of IPipelineStep
|
||||
): DataPipeline;
|
||||
|
||||
/// Строит только preprocessing-часть supervised-конвейера без модели.
|
||||
/// Модель затем можно присоединить методом WithModel
|
||||
static function BuildPreprocessing(
|
||||
task: TaskKind;
|
||||
target: string;
|
||||
features: array of string;
|
||||
params steps: array of IPipelineStep
|
||||
): DataPipeline;
|
||||
|
||||
/// Возвращает копию текущего preprocessing-конвейера с добавленной моделью.
|
||||
function WithModel(model: ISupervisedModel): DataPipeline;
|
||||
|
||||
/// Обучает конвейер на DataFrame.
|
||||
/// Семантика:
|
||||
|
|
@ -185,6 +197,13 @@ type
|
|||
/// Строит unsupervised-конвейер из шагов обработки данных и модели.
|
||||
static function Build(features: array of string;
|
||||
params steps: array of IPipelineStep): UDataPipeline;
|
||||
|
||||
/// Строит только preprocessing-часть unsupervised-конвейера без модели.
|
||||
static function BuildPreprocessing(features: array of string;
|
||||
params steps: array of IPipelineStep): UDataPipeline;
|
||||
|
||||
/// Возвращает копию текущего preprocessing-конвейера с добавленной моделью.
|
||||
function WithModel(model: IUnsupervisedModel): UDataPipeline;
|
||||
|
||||
/// Обучает конвейер на DataFrame.
|
||||
function Fit(df: DataFrame): UDataPipeline;
|
||||
|
|
@ -299,10 +318,13 @@ const
|
|||
'Метки классов недоступны. Убедитесь, что конвейер обучен и задача — классификация!!Class labels are not available. Ensure the pipeline is fitted and the task is classification';
|
||||
ER_LABEL_INDEX_OUT_OF_RANGE =
|
||||
'Индекс метки {0} вне диапазона [0, {1})!!Label index {0} is out of range [0, {1})';
|
||||
ER_LABELENCODER_TARGET_NOT_ALLOWED =
|
||||
'LabelEncoder нельзя применять к целевой переменной — кодирование выполняется внутри модели!!LabelEncoder cannot be applied to target — encoding is handled internally by the model';
|
||||
ER_ORDINALENCODER_TARGET_NOT_ALLOWED =
|
||||
'OrdinalEncoder нельзя применять к целевой переменной — кодирование выполняется внутри модели!!OrdinalEncoder 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_CLASSIFICATION_TARGET_MUST_BE_CATEGORICAL_STR_OR_INT =
|
||||
'Целевой столбец "{0}" должен быть категориальным строковым или целочисленным для задач классификации!!' +
|
||||
'Target column "{0}" must be a categorical string or integer column for classification tasks';
|
||||
ER_REGRESSION_TARGET_MUST_BE_NUMERIC =
|
||||
'Целевой столбец "{0}" должен быть числовым для задач регрессии!!Target column "{0}" must be numeric for regression tasks';
|
||||
ER_PREPROCESSOR_ROWCOUNT_CHANGED =
|
||||
|
|
@ -557,10 +579,10 @@ begin
|
|||
Result := Self;
|
||||
end;
|
||||
|
||||
class function DataPipeline.Build(
|
||||
class function DataPipeline.BuildPreprocessing(
|
||||
task: TaskKind;
|
||||
target: string;
|
||||
features: array of string;
|
||||
features: array of string;
|
||||
params steps: array of IPipelineStep
|
||||
): DataPipeline;
|
||||
begin
|
||||
|
|
@ -579,6 +601,38 @@ begin
|
|||
if (steps = nil) or (Length(steps) = 0) then
|
||||
ArgumentError(ER_PIPELINE_NO_STEPS);
|
||||
|
||||
for var i := 0 to High(steps) do
|
||||
begin
|
||||
var step := steps[i];
|
||||
|
||||
if step = nil then
|
||||
ArgumentError(ER_PIPELINE_STEP_NULL, i);
|
||||
|
||||
if step is ISupervisedModel then
|
||||
ArgumentError(ER_PIPELINE_INVALID_STEP_ORDER);
|
||||
end;
|
||||
|
||||
var p := new DataPipeline;
|
||||
p.fTarget := target;
|
||||
p.fFeatures := Copy(features);
|
||||
p.fTask := task;
|
||||
|
||||
for var i := 0 to High(steps) do
|
||||
p.Add(steps[i]);
|
||||
|
||||
Result := p;
|
||||
end;
|
||||
|
||||
class function DataPipeline.Build(
|
||||
task: TaskKind;
|
||||
target: string;
|
||||
features: array of string;
|
||||
params steps: array of IPipelineStep
|
||||
): DataPipeline;
|
||||
begin
|
||||
if (steps = nil) or (Length(steps) = 0) then
|
||||
ArgumentError(ER_PIPELINE_NO_STEPS);
|
||||
|
||||
var last := steps[High(steps)];
|
||||
|
||||
if last = nil then
|
||||
|
|
@ -611,14 +665,32 @@ begin
|
|||
ArgumentError(ER_PIPELINE_INVALID_STEP_ORDER);
|
||||
end;
|
||||
|
||||
var p := new DataPipeline;
|
||||
p.fTarget := target;
|
||||
p.fFeatures := Copy(features);
|
||||
p.fTask := task;
|
||||
var prepSteps := new IPipelineStep[steps.Length - 1];
|
||||
for var i := 0 to High(prepSteps) do
|
||||
prepSteps[i] := steps[i];
|
||||
|
||||
for var i := 0 to High(steps) do
|
||||
p.Add(steps[i]);
|
||||
Result :=
|
||||
BuildPreprocessing(task, target, features, prepSteps)
|
||||
.WithModel(last as ISupervisedModel);
|
||||
end;
|
||||
|
||||
function DataPipeline.WithModel(model: ISupervisedModel): DataPipeline;
|
||||
begin
|
||||
if model = nil then
|
||||
ArgumentError(ER_MODEL_NULL);
|
||||
|
||||
var p := Clone as DataPipeline;
|
||||
|
||||
if p = nil then
|
||||
Error(ER_MODEL_CLONE_TYPE);
|
||||
|
||||
if p.fFitted then
|
||||
Error(ER_PIPELINE_MODIFY_AFTER_FIT);
|
||||
|
||||
if p.fModel <> nil then
|
||||
ArgumentError(ER_PIPELINE_MULTIPLE_MODELS);
|
||||
|
||||
p.Add(model as IPipelineStep);
|
||||
Result := p;
|
||||
end;
|
||||
|
||||
|
|
@ -790,8 +862,13 @@ begin
|
|||
|
||||
case fTask of
|
||||
tkClassification:
|
||||
if not df.IsCategorical(fTarget) then
|
||||
ArgumentError(ER_ENCODELABELS_NOT_CATEGORICAL, fTarget);
|
||||
begin
|
||||
if not df.IsCategorical(fTarget) then
|
||||
ArgumentError(ER_ENCODELABELS_NOT_CATEGORICAL, fTarget);
|
||||
var ct := df.GetColumnType(fTarget);
|
||||
if not (ct in [ColumnType.ctStr, ColumnType.ctInt]) then
|
||||
ArgumentError(ER_CLASSIFICATION_TARGET_MUST_BE_CATEGORICAL_STR_OR_INT, fTarget);
|
||||
end;
|
||||
|
||||
tkRegression:
|
||||
begin
|
||||
|
|
@ -923,11 +1000,37 @@ begin
|
|||
Result := Self;
|
||||
end;
|
||||
|
||||
class function UDataPipeline.Build(features: array of string;
|
||||
class function UDataPipeline.BuildPreprocessing(features: array of string;
|
||||
params steps: array of IPipelineStep): UDataPipeline;
|
||||
begin
|
||||
ValidateFeatureList(features);
|
||||
|
||||
if (steps = nil) or (Length(steps) = 0) then
|
||||
ArgumentError(ER_PIPELINE_NO_STEPS);
|
||||
|
||||
for var i := 0 to High(steps) do
|
||||
begin
|
||||
var step := steps[i];
|
||||
|
||||
if step = nil then
|
||||
ArgumentError(ER_PIPELINE_STEP_NULL, i);
|
||||
|
||||
if step is IUnsupervisedModel then
|
||||
ArgumentError(ER_PIPELINE_INVALID_STEP_ORDER);
|
||||
end;
|
||||
|
||||
var p := new UDataPipeline;
|
||||
p.fFeatures := Copy(features);
|
||||
|
||||
for var i := 0 to High(steps) do
|
||||
p.Add(steps[i]);
|
||||
|
||||
Result := p;
|
||||
end;
|
||||
|
||||
class function UDataPipeline.Build(features: array of string;
|
||||
params steps: array of IPipelineStep): UDataPipeline;
|
||||
begin
|
||||
if (steps = nil) or (Length(steps) = 0) then
|
||||
ArgumentError(ER_PIPELINE_NO_STEPS);
|
||||
|
||||
|
|
@ -950,12 +1053,32 @@ begin
|
|||
ArgumentError(ER_PIPELINE_INVALID_STEP_ORDER);
|
||||
end;
|
||||
|
||||
var p := new UDataPipeline;
|
||||
p.fFeatures := Copy(features);
|
||||
var prepSteps := new IPipelineStep[steps.Length - 1];
|
||||
for var i := 0 to High(prepSteps) do
|
||||
prepSteps[i] := steps[i];
|
||||
|
||||
for var i := 0 to High(steps) do
|
||||
p.Add(steps[i]);
|
||||
Result :=
|
||||
BuildPreprocessing(features, prepSteps)
|
||||
.WithModel(last as IUnsupervisedModel);
|
||||
end;
|
||||
|
||||
function UDataPipeline.WithModel(model: IUnsupervisedModel): UDataPipeline;
|
||||
begin
|
||||
if model = nil then
|
||||
ArgumentError(ER_MODEL_NULL);
|
||||
|
||||
var p := Clone as UDataPipeline;
|
||||
|
||||
if p = nil then
|
||||
Error(ER_INVALID_MODEL_TYPE, 'UDataPipeline');
|
||||
|
||||
if p.fFitted then
|
||||
Error(ER_PIPELINE_MODIFY_AFTER_FIT);
|
||||
|
||||
if p.fModel <> nil then
|
||||
ArgumentError(ER_PIPELINE_MULTIPLE_MODELS);
|
||||
|
||||
p.Add(model as IPipelineStep);
|
||||
Result := p;
|
||||
end;
|
||||
|
||||
|
|
|
|||
|
|
@ -244,6 +244,8 @@ type
|
|||
|
||||
procedure EnsureBinary;
|
||||
|
||||
function GetMatrix: array[,] of integer;
|
||||
|
||||
function GetTPBinary: integer;
|
||||
function GetFPBinary: integer;
|
||||
function GetFNBinary: integer;
|
||||
|
|
@ -292,6 +294,11 @@ type
|
|||
///
|
||||
/// Используется для построения матрицы ошибок размера K × K, где K = ClassCount.
|
||||
property ClassCount: integer read fClassCount;
|
||||
|
||||
/// Матрица ошибок.
|
||||
///
|
||||
/// Matrix[i, j] — количество объектов класса i, которые модель предсказала как класс j.
|
||||
property Matrix: array[,] of integer read GetMatrix;
|
||||
|
||||
/// Число истинно положительных предсказаний для класса c.
|
||||
/// Здесь c — номер класса в матрице ошибок.
|
||||
|
|
@ -2001,6 +2008,15 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function ConfusionMatrix.GetMatrix: array[,] of integer;
|
||||
begin
|
||||
Result := new integer[fClassCount, fClassCount];
|
||||
|
||||
for var i := 0 to fClassCount - 1 do
|
||||
for var j := 0 to fClassCount - 1 do
|
||||
Result[i, j] := fMatrix[i, j];
|
||||
end;
|
||||
|
||||
function ConfusionMatrix.GetLabel(c: integer): integer;
|
||||
begin
|
||||
if (c < 0) or (c >= fClassCount) then
|
||||
|
|
|
|||
1277
bin/Lib/PlotML.pas
1277
bin/Lib/PlotML.pas
File diff suppressed because it is too large
Load diff
|
|
@ -445,6 +445,8 @@ begin
|
|||
var srcIdx := df.Schema.IndexOf(col);
|
||||
if srcIdx < 0 then
|
||||
ArgumentError(ER_COLUMN_NOT_FOUND, col);
|
||||
if df.Schema.ColumnTypeAt(srcIdx) <> ColumnType.ctStr then
|
||||
Error(ER_ONEHOT_NOT_STRING, col);
|
||||
|
||||
var rowCount := df.RowCount;
|
||||
var catCount := categories.Length;
|
||||
|
|
|
|||
Loading…
Reference in a new issue