Почистил примеры
This commit is contained in:
parent
ce84830349
commit
de75f00031
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -7,7 +7,7 @@ begin
|
||||||
var features := ['rooms','area','kitchen_area','floor','floors_total','metro_minutes'];
|
var features := ['rooms','area','kitchen_area','floor','floors_total','metro_minutes'];
|
||||||
var target := 'price';
|
var target := 'price';
|
||||||
|
|
||||||
var (trainDf, testDf) := df.TrainTestSplit(0.2, 42);
|
var (trainDf, testDf) := df.TrainTestSplit(0.2, seed := 42);
|
||||||
|
|
||||||
var Xtrain := trainDf.ToMatrix(features);
|
var Xtrain := trainDf.ToMatrix(features);
|
||||||
var ytrain := trainDf.ToVector(target);
|
var ytrain := trainDf.ToVector(target);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ begin
|
||||||
var features := ['rooms','area','kitchen_area','floor','floors_total','metro_minutes'];
|
var features := ['rooms','area','kitchen_area','floor','floors_total','metro_minutes'];
|
||||||
var target := 'price';
|
var target := 'price';
|
||||||
|
|
||||||
var (trainDf, testDf) := df.TrainTestSplit(0.2, 42);
|
var (trainDf, testDf) := df.TrainTestSplit(0.2, seed := 42);
|
||||||
|
|
||||||
var Xtrain := trainDf.ToMatrix(features);
|
var Xtrain := trainDf.ToMatrix(features);
|
||||||
var ytrain := trainDf.ToVector(target);
|
var ytrain := trainDf.ToVector(target);
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,10 @@ begin
|
||||||
|
|
||||||
var pipe :=
|
var pipe :=
|
||||||
DataPipeline.Build(
|
DataPipeline.Build(
|
||||||
|
TaskKind.tkRegression,
|
||||||
target,
|
target,
|
||||||
features,
|
features,
|
||||||
new LabelEncoder('renovation'),
|
new OrdinalEncoder('renovation'),
|
||||||
model
|
model
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@ begin
|
||||||
df := portImputer.FitTransform(df);
|
df := portImputer.FitTransform(df);
|
||||||
|
|
||||||
// Кодируем категориальные признаки числами.
|
// Кодируем категориальные признаки числами.
|
||||||
var sexEncoder := new LabelEncoder('Пол');
|
var sexEncoder := new OrdinalEncoder('Пол');
|
||||||
df := sexEncoder.FitTransform(df);
|
df := sexEncoder.FitTransform(df);
|
||||||
|
|
||||||
var portEncoder := new LabelEncoder('ПортПосадки');
|
var portEncoder := new OrdinalEncoder('ПортПосадки');
|
||||||
df := portEncoder.FitTransform(df);
|
df := portEncoder.FitTransform(df);
|
||||||
|
|
||||||
var features := ['Класс', 'Пол', 'Возраст', 'БратьяИСупруги', 'РодителиИДети', 'ЦенаБилета', 'ПортПосадки'];
|
var features := ['Класс', 'Пол', 'Возраст', 'БратьяИСупруги', 'РодителиИДети', 'ЦенаБилета', 'ПортПосадки'];
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ begin
|
||||||
var portImputer := new Imputer('Саутгемптон', ['ПортПосадки']);
|
var portImputer := new Imputer('Саутгемптон', ['ПортПосадки']);
|
||||||
df := portImputer.FitTransform(df);
|
df := portImputer.FitTransform(df);
|
||||||
|
|
||||||
var sexEncoder := new LabelEncoder('Пол');
|
var sexEncoder := new OrdinalEncoder('Пол');
|
||||||
df := sexEncoder.FitTransform(df);
|
df := sexEncoder.FitTransform(df);
|
||||||
|
|
||||||
var portEncoder := new LabelEncoder('ПортПосадки');
|
var portEncoder := new OrdinalEncoder('ПортПосадки');
|
||||||
df := portEncoder.FitTransform(df);
|
df := portEncoder.FitTransform(df);
|
||||||
|
|
||||||
var features := ['Класс', 'Пол', 'Возраст', 'БратьяИСупруги', 'РодителиИДети', 'ЦенаБилета', 'ПортПосадки'];
|
var features := ['Класс', 'Пол', 'Возраст', 'БратьяИСупруги', 'РодителиИДети', 'ЦенаБилета', 'ПортПосадки'];
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -11,10 +11,10 @@ begin
|
||||||
df := imputer.FitTransform(df);
|
df := imputer.FitTransform(df);
|
||||||
|
|
||||||
// Кодируем категориальные признаки
|
// Кодируем категориальные признаки
|
||||||
var encoder := new LabelEncoder('region_name');
|
var encoder := new OrdinalEncoder('region_name');
|
||||||
df := encoder.FitTransform(df);
|
df := encoder.FitTransform(df);
|
||||||
|
|
||||||
var encoder2 := new LabelEncoder('federal_district');
|
var encoder2 := new OrdinalEncoder('federal_district');
|
||||||
df := encoder2.FitTransform(df);
|
df := encoder2.FitTransform(df);
|
||||||
|
|
||||||
df.Print;
|
df.Print;
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ begin
|
||||||
var imputer := new Imputer(['population', 'lat', 'lon']);
|
var imputer := new Imputer(['population', 'lat', 'lon']);
|
||||||
df := imputer.FitTransform(df);
|
df := imputer.FitTransform(df);
|
||||||
|
|
||||||
var le1 := new LabelEncoder('region_name');
|
var le1 := new OrdinalEncoder('region_name');
|
||||||
df := le1.FitTransform(df);
|
df := le1.FitTransform(df);
|
||||||
|
|
||||||
var le2 := new LabelEncoder('federal_district');
|
var le2 := new OrdinalEncoder('federal_district');
|
||||||
df := le2.FitTransform(df);
|
df := le2.FitTransform(df);
|
||||||
|
|
||||||
// Явно задаём признаки
|
// Явно задаём признаки
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ begin
|
||||||
var imputer := new Imputer(['population', 'lat', 'lon']);
|
var imputer := new Imputer(['population', 'lat', 'lon']);
|
||||||
df := imputer.FitTransform(df);
|
df := imputer.FitTransform(df);
|
||||||
|
|
||||||
var le1 := new LabelEncoder('region_name');
|
var le1 := new OrdinalEncoder('region_name');
|
||||||
df := le1.FitTransform(df);
|
df := le1.FitTransform(df);
|
||||||
|
|
||||||
var le2 := new LabelEncoder('federal_district');
|
var le2 := new OrdinalEncoder('federal_district');
|
||||||
df := le2.FitTransform(df);
|
df := le2.FitTransform(df);
|
||||||
|
|
||||||
var features := ['lat', 'lon', 'region_name', 'federal_district'];
|
var features := ['lat', 'lon', 'region_name', 'federal_district'];
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
3.11.1.3815
|
3.11.1.3821
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
!define VERSION '3.11.1.3815'
|
!define VERSION '3.11.1.3821'
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ begin
|
||||||
df.AddStrColumn('Region', Arr('South', 'North', 'South', 'East'));
|
df.AddStrColumn('Region', Arr('South', 'North', 'South', 'East'));
|
||||||
df := df.SetCategorical(['Region']);
|
df := df.SetCategorical(['Region']);
|
||||||
|
|
||||||
var enc := new LabelEncoder('Region');
|
var enc := new OrdinalEncoder('Region');
|
||||||
enc.Fit(df);
|
enc.Fit(df);
|
||||||
|
|
||||||
var res := enc.Transform(df);
|
var res := enc.Transform(df);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ begin
|
||||||
testDf.AddIntColumn('City', Arr(1, 2, 3));
|
testDf.AddIntColumn('City', Arr(1, 2, 3));
|
||||||
testDf := testDf.SetCategorical(['City']);
|
testDf := testDf.SetCategorical(['City']);
|
||||||
|
|
||||||
var enc := new LabelEncoder('City');
|
var enc := new OrdinalEncoder('City');
|
||||||
enc.Fit(trainDf);
|
enc.Fit(trainDf);
|
||||||
|
|
||||||
CheckRaises(procedure -> begin
|
CheckRaises(procedure -> begin
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ type
|
||||||
Inspection = InspectionML.Inspection;
|
Inspection = InspectionML.Inspection;
|
||||||
|
|
||||||
IPreprocessor = PreprocessorABC.IPreprocessor;
|
IPreprocessor = PreprocessorABC.IPreprocessor;
|
||||||
LabelEncoder = PreprocessorABC.LabelEncoder;
|
OrdinalEncoder = PreprocessorABC.OrdinalEncoder;
|
||||||
OneHotEncoder = PreprocessorABC.OneHotEncoder;
|
OneHotEncoder = PreprocessorABC.OneHotEncoder;
|
||||||
ImputeStrategy = PreprocessorABC.ImputeStrategy;
|
ImputeStrategy = PreprocessorABC.ImputeStrategy;
|
||||||
Imputer = PreprocessorABC.Imputer;
|
Imputer = PreprocessorABC.Imputer;
|
||||||
|
|
|
||||||
|
|
@ -1157,6 +1157,7 @@ begin
|
||||||
ArgumentNullError(ER_ARG_NULL, 'name');
|
ArgumentNullError(ER_ARG_NULL, 'name');
|
||||||
|
|
||||||
var baseDir := PascalABCDirectory + 'Files\Datasets\';
|
var baseDir := PascalABCDirectory + 'Files\Datasets\';
|
||||||
|
//var baseDir := 'C:\Program Files (x86)\PascalABC.NET\Files\Datasets\';
|
||||||
|
|
||||||
var metaPath := baseDir + name + '.meta';
|
var metaPath := baseDir + name + '.meta';
|
||||||
var csvPath := baseDir + name + '.csv';
|
var csvPath := baseDir + name + '.csv';
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,14 @@ unit MLModelsABC;
|
||||||
// См. статистическую политику в модуле MLABC.
|
// См. статистическую политику в модуле MLABC.
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
||||||
|
{
|
||||||
|
Производительность
|
||||||
|
|
||||||
|
DecisionTreeRegressor.Fit - 340 мс против 156 мс в Питоне при той же точности
|
||||||
|
GradientBoostingRegressor.Fit - 5500 мс против 5500 мс в Питоне
|
||||||
|
RandomForestRegressor.Fit - 1280 мс против 480 мс в Питоне
|
||||||
|
}
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses MLCoreABC;
|
uses MLCoreABC;
|
||||||
|
|
@ -432,6 +440,8 @@ type
|
||||||
Found: boolean;
|
Found: boolean;
|
||||||
Feature: integer;
|
Feature: integer;
|
||||||
Threshold: real;
|
Threshold: real;
|
||||||
|
LeftCount: integer;
|
||||||
|
LeftOrderSize: integer;
|
||||||
WeightedScore: real;
|
WeightedScore: real;
|
||||||
|
|
||||||
static function Invalid: RegSplitResult;
|
static function Invalid: RegSplitResult;
|
||||||
|
|
@ -439,6 +449,8 @@ type
|
||||||
Result.Found := false;
|
Result.Found := false;
|
||||||
Result.Feature := -1;
|
Result.Feature := -1;
|
||||||
Result.Threshold := 0.0;
|
Result.Threshold := 0.0;
|
||||||
|
Result.LeftCount := 0;
|
||||||
|
Result.LeftOrderSize := 0;
|
||||||
Result.WeightedScore := real.PositiveInfinity;
|
Result.WeightedScore := real.PositiveInfinity;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
@ -708,8 +720,9 @@ type
|
||||||
private
|
private
|
||||||
fLeafL2: real;
|
fLeafL2: real;
|
||||||
fSortedOrders: array of array of integer;
|
fSortedOrders: array of array of integer;
|
||||||
fSortedValues: array of array of real;
|
fUseSortedOrdersAsRoot: boolean;
|
||||||
|
fRowWeights: array of integer;
|
||||||
|
|
||||||
fVisitMarks: array of integer;
|
fVisitMarks: array of integer;
|
||||||
fVisitId: integer;
|
fVisitId: integer;
|
||||||
|
|
||||||
|
|
@ -726,12 +739,14 @@ type
|
||||||
function FindBestSplitReg(X: Matrix; y: Vector; nodeOrders: array of array of integer): RegSplitResult;
|
function FindBestSplitReg(X: Matrix; y: Vector; nodeOrders: array of array of integer): RegSplitResult;
|
||||||
procedure BuildSortedOrders(X: Matrix; indices: array of integer);
|
procedure BuildSortedOrders(X: Matrix; indices: array of integer);
|
||||||
function BuildInitialNodeOrders(indices: array of integer): array of array of integer;
|
function BuildInitialNodeOrders(indices: array of integer): array of array of integer;
|
||||||
procedure SplitNodeOrders(X: Matrix; nodeOrders: array of array of integer; feature: integer; threshold: real;
|
procedure SplitNodeOrders(nodeOrders: array of array of integer; feature: integer; leftCount, leftOrderSize: integer;
|
||||||
var leftOrders, rightOrders: array of array of integer);
|
var leftOrders, rightOrders: array of array of integer);
|
||||||
function BuildMembershipMask(rowCount: integer; indices: array of integer): array of boolean;
|
function BuildMembershipMask(rowCount: integer; indices: array of integer): array of boolean;
|
||||||
procedure ComputeNodeStats(yData: array of real; indices: array of integer; var sumAll, sumSqAll: real);
|
procedure ComputeNodeStats(yData: array of real; indices: array of integer; var sumAll, sumSqAll: real);
|
||||||
function WeightedVariance(n, leftCount: integer; leftSum, leftSumSq, sumAll, sumSqAll: real): real;
|
function WeightedVariance(n, leftCount: integer; leftSum, leftSumSq, sumAll, sumSqAll: real): real;
|
||||||
function GetFeatureSubset(p: integer): array of integer;
|
function GetFeatureSubset(p: integer): array of integer;
|
||||||
|
function SampleWeight(rowIndex: integer): integer;
|
||||||
|
function TotalWeight(indices: array of integer): integer;
|
||||||
|
|
||||||
/// Проверяет, является ли узел "чистым".
|
/// Проверяет, является ли узел "чистым".
|
||||||
/// Для регрессии это означает, что все значения y одинаковы
|
/// Для регрессии это означает, что все значения y одинаковы
|
||||||
|
|
@ -758,6 +773,16 @@ type
|
||||||
/// Выполняет предсказание для всех объектов X.
|
/// Выполняет предсказание для всех объектов X.
|
||||||
/// Возвращает вектор вещественных значений.
|
/// Возвращает вектор вещественных значений.
|
||||||
function Predict(X: Matrix): Vector; override;
|
function Predict(X: Matrix): Vector; override;
|
||||||
|
|
||||||
|
/// Внутренний hook для ансамблей: позволяет переиспользовать
|
||||||
|
/// уже отсортированные порядки строк по признакам.
|
||||||
|
/// Обычному пользовательскому коду не нужен.
|
||||||
|
procedure SetPreSortedOrders(sortedOrders: array of array of integer);
|
||||||
|
|
||||||
|
/// Внутренний hook для bootstrap-подвыборок с повторами.
|
||||||
|
/// Передаются уже готовые сортированные порядки именно для корневого узла.
|
||||||
|
procedure SetPreSortedRootOrders(sortedOrders: array of array of integer);
|
||||||
|
procedure SetBootstrapRootOrders(sortedOrders: array of array of integer; rowWeights: array of integer);
|
||||||
|
|
||||||
/// Копирует только конфигурацию модели (без обученного состояния).
|
/// Копирует только конфигурацию модели (без обученного состояния).
|
||||||
/// Используется для создания независимых экземпляров модели.
|
/// Используется для создания независимых экземпляров модели.
|
||||||
|
|
@ -4022,7 +4047,7 @@ function DecisionTreeRegressor.BuildTreeNode(X: Matrix; y: Vector;
|
||||||
nodeOrders: array of array of integer; depth: integer): DecisionTreeNode;
|
nodeOrders: array of array of integer; depth: integer): DecisionTreeNode;
|
||||||
begin
|
begin
|
||||||
var indices := nodeOrders[0];
|
var indices := nodeOrders[0];
|
||||||
var n := indices.Length;
|
var n := TotalWeight(indices);
|
||||||
|
|
||||||
if (fMaxDepth >= 0) and (depth >= fMaxDepth) then
|
if (fMaxDepth >= 0) and (depth >= fMaxDepth) then
|
||||||
exit(LeafNode(LeafValue(y, indices)));
|
exit(LeafNode(LeafValue(y, indices)));
|
||||||
|
|
@ -4048,12 +4073,13 @@ begin
|
||||||
exit(LeafNode(LeafValue(y, indices)));
|
exit(LeafNode(LeafValue(y, indices)));
|
||||||
|
|
||||||
var leftOrders, rightOrders: array of array of integer;
|
var leftOrders, rightOrders: array of array of integer;
|
||||||
SplitNodeOrders(X, nodeOrders, split.Feature, split.Threshold, leftOrders, rightOrders);
|
SplitNodeOrders(nodeOrders, split.Feature, split.LeftCount, split.LeftOrderSize, leftOrders, rightOrders);
|
||||||
var leftArr := leftOrders[0];
|
var leftArr := leftOrders[0];
|
||||||
var rightArr := rightOrders[0];
|
var rightArr := rightOrders[0];
|
||||||
|
var rightCount := n - split.LeftCount;
|
||||||
|
|
||||||
if (leftArr.Length < fMinSamplesLeaf) or
|
if (split.LeftCount < fMinSamplesLeaf) or
|
||||||
(rightArr.Length < fMinSamplesLeaf) then
|
(rightCount < fMinSamplesLeaf) then
|
||||||
exit(LeafNode(LeafValue(y, indices)));
|
exit(LeafNode(LeafValue(y, indices)));
|
||||||
|
|
||||||
var delta := parentVar - split.WeightedScore;
|
var delta := parentVar - split.WeightedScore;
|
||||||
|
|
@ -4095,7 +4121,7 @@ begin
|
||||||
Result := RegSplitResult.Invalid;
|
Result := RegSplitResult.Invalid;
|
||||||
|
|
||||||
var indices := nodeOrders[0];
|
var indices := nodeOrders[0];
|
||||||
var n := indices.Length;
|
var n := TotalWeight(indices);
|
||||||
if n < 2 then
|
if n < 2 then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
|
|
@ -4108,6 +4134,11 @@ begin
|
||||||
var bestScore := real.PositiveInfinity;
|
var bestScore := real.PositiveInfinity;
|
||||||
var bestFeature := -1;
|
var bestFeature := -1;
|
||||||
var bestThreshold := 0.0;
|
var bestThreshold := 0.0;
|
||||||
|
var bestLeftCount := 0;
|
||||||
|
var bestLeftOrderSize := 0;
|
||||||
|
var invN := 1.0 / n;
|
||||||
|
var minLeaf := fMinSamplesLeaf;
|
||||||
|
var maxLeftCount := n - minLeaf;
|
||||||
|
|
||||||
var features := GetFeatureSubset(X.ColCount);
|
var features := GetFeatureSubset(X.ColCount);
|
||||||
|
|
||||||
|
|
@ -4116,64 +4147,62 @@ begin
|
||||||
var j := features[fj];
|
var j := features[fj];
|
||||||
var order := nodeOrders[j];
|
var order := nodeOrders[j];
|
||||||
var orderLen := order.Length;
|
var orderLen := order.Length;
|
||||||
|
|
||||||
|
if orderLen < 2 then
|
||||||
|
continue;
|
||||||
|
|
||||||
var leftCount := 0;
|
var firstIdx := order[0];
|
||||||
var leftSum := 0.0;
|
var firstWeight := SampleWeight(firstIdx);
|
||||||
var leftSumSq := 0.0;
|
var leftCount := firstWeight;
|
||||||
|
var leftSum := firstWeight * yData[firstIdx];
|
||||||
|
var leftSumSq := firstWeight * yData[firstIdx] * yData[firstIdx];
|
||||||
|
var prevValue := xData[firstIdx, j];
|
||||||
|
|
||||||
var prevValue := 0.0;
|
for var i := 1 to orderLen - 1 do
|
||||||
var firstIncluded := true;
|
|
||||||
|
|
||||||
for var i := 0 to orderLen - 1 do
|
|
||||||
begin
|
begin
|
||||||
|
if leftCount > maxLeftCount then
|
||||||
|
break;
|
||||||
|
|
||||||
var idx := order[i];
|
var idx := order[i];
|
||||||
var xCur := xData[idx, j];
|
var xCur := xData[idx, j];
|
||||||
var yCur := yData[idx];
|
|
||||||
|
if (leftCount >= minLeaf) and (prevValue <> xCur) then
|
||||||
if not firstIncluded then
|
|
||||||
begin
|
begin
|
||||||
var rightCount := n - leftCount;
|
var rightCount := n - leftCount;
|
||||||
|
var rightSum := sumAll - leftSum;
|
||||||
|
var rightSumSq := sumSqAll - leftSumSq;
|
||||||
|
|
||||||
|
var leftScore := leftSumSq - (leftSum * leftSum) / leftCount;
|
||||||
|
var rightScore := rightSumSq - (rightSum * rightSum) / rightCount;
|
||||||
|
var weighted := (leftScore + rightScore) * invN;
|
||||||
|
|
||||||
|
if weighted < 0 then
|
||||||
|
weighted := 0.0;
|
||||||
|
|
||||||
if (leftCount >= fMinSamplesLeaf) and
|
if weighted < bestScore then
|
||||||
(rightCount >= fMinSamplesLeaf) and
|
|
||||||
(prevValue <> xCur) then
|
|
||||||
begin
|
begin
|
||||||
var rightCountReal := rightCount;
|
bestScore := weighted;
|
||||||
var leftMean := leftSum / leftCount;
|
bestFeature := j;
|
||||||
var leftVar := leftSumSq / leftCount - leftMean * leftMean;
|
bestThreshold := (prevValue + xCur) * 0.5;
|
||||||
|
bestLeftCount := leftCount;
|
||||||
var rightSum := sumAll - leftSum;
|
bestLeftOrderSize := i;
|
||||||
var rightSumSq := sumSqAll - leftSumSq;
|
|
||||||
var rightMean := rightSum / rightCount;
|
|
||||||
var rightVar := rightSumSq / rightCount - rightMean * rightMean;
|
|
||||||
|
|
||||||
if leftVar < 0 then
|
|
||||||
leftVar := 0.0;
|
|
||||||
if rightVar < 0 then
|
|
||||||
rightVar := 0.0;
|
|
||||||
|
|
||||||
var weighted := (leftCount * leftVar + rightCountReal * rightVar) / n;
|
|
||||||
|
|
||||||
if weighted < bestScore then
|
|
||||||
begin
|
|
||||||
bestScore := weighted;
|
|
||||||
bestFeature := j;
|
|
||||||
bestThreshold := (prevValue + xCur) * 0.5;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
leftCount += 1;
|
var wCur := SampleWeight(idx);
|
||||||
leftSum += yCur;
|
var yCur := yData[idx];
|
||||||
leftSumSq += yCur * yCur;
|
leftCount += wCur;
|
||||||
|
leftSum += wCur * yCur;
|
||||||
|
leftSumSq += wCur * yCur * yCur;
|
||||||
prevValue := xCur;
|
prevValue := xCur;
|
||||||
firstIncluded := false;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Result.Found := bestFeature <> -1;
|
Result.Found := bestFeature <> -1;
|
||||||
Result.Feature := bestFeature;
|
Result.Feature := bestFeature;
|
||||||
Result.Threshold := bestThreshold;
|
Result.Threshold := bestThreshold;
|
||||||
|
Result.LeftCount := bestLeftCount;
|
||||||
|
Result.LeftOrderSize := bestLeftOrderSize;
|
||||||
Result.WeightedScore := bestScore;
|
Result.WeightedScore := bestScore;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -4190,14 +4219,103 @@ type
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function BuildPreSortedOrders(X: Matrix): array of array of integer;
|
||||||
|
begin
|
||||||
|
var p := X.ColCount;
|
||||||
|
var n := X.RowCount;
|
||||||
|
var xData := X.Data;
|
||||||
|
|
||||||
|
SetLength(Result, p);
|
||||||
|
|
||||||
|
for var j := 0 to p - 1 do
|
||||||
|
begin
|
||||||
|
var pairs: array of SortPair;
|
||||||
|
SetLength(pairs, n);
|
||||||
|
|
||||||
|
for var i := 0 to n - 1 do
|
||||||
|
begin
|
||||||
|
pairs[i].Value := xData[i, j];
|
||||||
|
pairs[i].Index := i;
|
||||||
|
end;
|
||||||
|
|
||||||
|
System.Array.Sort(pairs, new SortPairComparer);
|
||||||
|
|
||||||
|
Result[j] := new integer[n];
|
||||||
|
for var i := 0 to n - 1 do
|
||||||
|
Result[j][i] := pairs[i].Index;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function BuildRowCounts(rows: array of integer; rowCount: integer): array of integer;
|
||||||
|
begin
|
||||||
|
Result := new integer[rowCount];
|
||||||
|
|
||||||
|
for var i := 0 to rows.Length - 1 do
|
||||||
|
Result[rows[i]] += 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function BuildSortedOrdersFromCounts(
|
||||||
|
fullSortedOrders: array of array of integer;
|
||||||
|
rowCounts: array of integer
|
||||||
|
): array of array of integer;
|
||||||
|
begin
|
||||||
|
var p := Length(fullSortedOrders);
|
||||||
|
SetLength(Result, p);
|
||||||
|
|
||||||
|
var total := 0;
|
||||||
|
for var i := 0 to rowCounts.Length - 1 do
|
||||||
|
total += rowCounts[i];
|
||||||
|
|
||||||
|
for var j := 0 to p - 1 do
|
||||||
|
begin
|
||||||
|
Result[j] := new integer[total];
|
||||||
|
var k := 0;
|
||||||
|
|
||||||
|
foreach var idx in fullSortedOrders[j] do
|
||||||
|
for var rep := 1 to rowCounts[idx] do
|
||||||
|
begin
|
||||||
|
Result[j][k] := idx;
|
||||||
|
k += 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function BuildUniqueOrdersFromCounts(
|
||||||
|
fullSortedOrders: array of array of integer;
|
||||||
|
rowCounts: array of integer
|
||||||
|
): array of array of integer;
|
||||||
|
begin
|
||||||
|
var p := Length(fullSortedOrders);
|
||||||
|
SetLength(Result, p);
|
||||||
|
|
||||||
|
var total := 0;
|
||||||
|
for var i := 0 to rowCounts.Length - 1 do
|
||||||
|
if rowCounts[i] > 0 then
|
||||||
|
total += 1;
|
||||||
|
|
||||||
|
for var j := 0 to p - 1 do
|
||||||
|
begin
|
||||||
|
Result[j] := new integer[total];
|
||||||
|
var k := 0;
|
||||||
|
|
||||||
|
foreach var idx in fullSortedOrders[j] do
|
||||||
|
if rowCounts[idx] > 0 then
|
||||||
|
begin
|
||||||
|
Result[j][k] := idx;
|
||||||
|
k += 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure DecisionTreeRegressor.BuildSortedOrders(X: Matrix; indices: array of integer);
|
procedure DecisionTreeRegressor.BuildSortedOrders(X: Matrix; indices: array of integer);
|
||||||
begin
|
begin
|
||||||
|
// Обычный путь для отдельного дерева:
|
||||||
|
// построить сортировку только по реально используемым строкам.
|
||||||
var p := X.ColCount;
|
var p := X.ColCount;
|
||||||
var n := indices.Length;
|
var n := indices.Length;
|
||||||
var xData := X.Data;
|
var xData := X.Data;
|
||||||
|
|
||||||
SetLength(fSortedOrders, p);
|
SetLength(fSortedOrders, p);
|
||||||
SetLength(fSortedValues, p);
|
|
||||||
|
|
||||||
for var j := 0 to p - 1 do
|
for var j := 0 to p - 1 do
|
||||||
begin
|
begin
|
||||||
|
|
@ -4214,13 +4332,9 @@ begin
|
||||||
System.Array.Sort(pairs,new SortPairComparer);
|
System.Array.Sort(pairs,new SortPairComparer);
|
||||||
|
|
||||||
fSortedOrders[j] := new integer[n];
|
fSortedOrders[j] := new integer[n];
|
||||||
fSortedValues[j] := new real[n];
|
|
||||||
|
|
||||||
for var i := 0 to n - 1 do
|
for var i := 0 to n - 1 do
|
||||||
begin
|
|
||||||
fSortedValues[j][i] := pairs[i].Value;
|
|
||||||
fSortedOrders[j][i] := pairs[i].Index;
|
fSortedOrders[j][i] := pairs[i].Index;
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -4252,13 +4366,13 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure DecisionTreeRegressor.SplitNodeOrders(X: Matrix;
|
procedure DecisionTreeRegressor.SplitNodeOrders(
|
||||||
nodeOrders: array of array of integer;
|
nodeOrders: array of array of integer;
|
||||||
feature: integer;
|
feature: integer;
|
||||||
threshold: real;
|
leftCount: integer;
|
||||||
|
leftOrderSize: integer;
|
||||||
var leftOrders, rightOrders: array of array of integer);
|
var leftOrders, rightOrders: array of array of integer);
|
||||||
begin
|
begin
|
||||||
var xData := X.Data;
|
|
||||||
var p := Length(nodeOrders);
|
var p := Length(nodeOrders);
|
||||||
|
|
||||||
fVisitId += 1;
|
fVisitId += 1;
|
||||||
|
|
@ -4266,31 +4380,33 @@ begin
|
||||||
|
|
||||||
var splitArr := nodeOrders[feature];
|
var splitArr := nodeOrders[feature];
|
||||||
var splitLen := splitArr.Length;
|
var splitLen := splitArr.Length;
|
||||||
|
var rightCount := splitLen - leftOrderSize;
|
||||||
|
var markLeft := leftOrderSize <= rightCount;
|
||||||
|
|
||||||
var leftCount := 0;
|
if markLeft then
|
||||||
|
for var i := 0 to leftOrderSize - 1 do
|
||||||
for var i := 0 to splitLen - 1 do
|
fVisitMarks[splitArr[i]] := mark
|
||||||
begin
|
else
|
||||||
var idx := splitArr[i];
|
for var i := leftOrderSize to splitLen - 1 do
|
||||||
|
fVisitMarks[splitArr[i]] := mark;
|
||||||
if xData[idx, feature] <= threshold then
|
|
||||||
begin
|
|
||||||
fVisitMarks[idx] := mark;
|
|
||||||
leftCount += 1;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
var rightCount := splitLen - leftCount;
|
|
||||||
|
|
||||||
SetLength(leftOrders, p);
|
SetLength(leftOrders, p);
|
||||||
SetLength(rightOrders, p);
|
SetLength(rightOrders, p);
|
||||||
|
|
||||||
|
leftOrders[feature] := new integer[leftOrderSize];
|
||||||
|
rightOrders[feature] := new integer[rightCount];
|
||||||
|
System.Array.Copy(splitArr, 0, leftOrders[feature], 0, leftOrderSize);
|
||||||
|
System.Array.Copy(splitArr, leftOrderSize, rightOrders[feature], 0, rightCount);
|
||||||
|
|
||||||
for var j := 0 to p - 1 do
|
for var j := 0 to p - 1 do
|
||||||
begin
|
begin
|
||||||
|
if j = feature then
|
||||||
|
continue;
|
||||||
|
|
||||||
var src := nodeOrders[j];
|
var src := nodeOrders[j];
|
||||||
var n := src.Length;
|
var n := src.Length;
|
||||||
|
|
||||||
var left := new integer[leftCount];
|
var left := new integer[leftOrderSize];
|
||||||
var right := new integer[rightCount];
|
var right := new integer[rightCount];
|
||||||
|
|
||||||
var li := 0;
|
var li := 0;
|
||||||
|
|
@ -4300,15 +4416,31 @@ begin
|
||||||
begin
|
begin
|
||||||
var idx := src[k];
|
var idx := src[k];
|
||||||
|
|
||||||
if fVisitMarks[idx] = mark then
|
if markLeft then
|
||||||
begin
|
begin
|
||||||
left[li] := idx;
|
if fVisitMarks[idx] = mark then
|
||||||
li += 1;
|
begin
|
||||||
|
left[li] := idx;
|
||||||
|
li += 1;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
right[ri] := idx;
|
||||||
|
ri += 1;
|
||||||
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
right[ri] := idx;
|
if fVisitMarks[idx] = mark then
|
||||||
ri += 1;
|
begin
|
||||||
|
right[ri] := idx;
|
||||||
|
ri += 1;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
left[li] := idx;
|
||||||
|
li += 1;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -4331,9 +4463,11 @@ begin
|
||||||
|
|
||||||
for var i := 0 to indices.Length - 1 do
|
for var i := 0 to indices.Length - 1 do
|
||||||
begin
|
begin
|
||||||
var v := yData[indices[i]];
|
var idx := indices[i];
|
||||||
sumAll += v;
|
var w := SampleWeight(idx);
|
||||||
sumSqAll += v * v;
|
var v := yData[idx];
|
||||||
|
sumAll += w * v;
|
||||||
|
sumSqAll += w * v * v;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -4380,6 +4514,48 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure DecisionTreeRegressor.SetPreSortedOrders(sortedOrders: array of array of integer);
|
||||||
|
begin
|
||||||
|
// Внутренний fast-path для ансамблей:
|
||||||
|
// используем готовую полную сортировку X и затем фильтруем её по fRowIndices.
|
||||||
|
fSortedOrders := sortedOrders;
|
||||||
|
fRowWeights := nil;
|
||||||
|
fUseSortedOrdersAsRoot := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DecisionTreeRegressor.SetPreSortedRootOrders(sortedOrders: array of array of integer);
|
||||||
|
begin
|
||||||
|
// Внутренний fast-path для bootstrap-выборок с повторами:
|
||||||
|
// сортировка уже соответствует корневому узлу текущего дерева.
|
||||||
|
fSortedOrders := sortedOrders;
|
||||||
|
fRowWeights := nil;
|
||||||
|
fUseSortedOrdersAsRoot := true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DecisionTreeRegressor.SetBootstrapRootOrders(
|
||||||
|
sortedOrders: array of array of integer;
|
||||||
|
rowWeights: array of integer);
|
||||||
|
begin
|
||||||
|
fSortedOrders := sortedOrders;
|
||||||
|
fRowWeights := rowWeights;
|
||||||
|
fUseSortedOrdersAsRoot := true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function DecisionTreeRegressor.SampleWeight(rowIndex: integer): integer;
|
||||||
|
begin
|
||||||
|
if fRowWeights = nil then
|
||||||
|
Result := 1
|
||||||
|
else
|
||||||
|
Result := fRowWeights[rowIndex];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function DecisionTreeRegressor.TotalWeight(indices: array of integer): integer;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
for var i := 0 to indices.Length - 1 do
|
||||||
|
Result += SampleWeight(indices[i]);
|
||||||
|
end;
|
||||||
|
|
||||||
//==============================
|
//==============================
|
||||||
// DecisionTreeClassifier
|
// DecisionTreeClassifier
|
||||||
//==============================
|
//==============================
|
||||||
|
|
@ -4571,7 +4747,7 @@ end;
|
||||||
|
|
||||||
function DecisionTreeRegressor.LeafValue(y: Vector; indices: array of integer): real;
|
function DecisionTreeRegressor.LeafValue(y: Vector; indices: array of integer): real;
|
||||||
begin
|
begin
|
||||||
var n := indices.Length;
|
var n := TotalWeight(indices);
|
||||||
|
|
||||||
if n = 0 then
|
if n = 0 then
|
||||||
exit(0.0); // безопасный fallback, не должен происходить
|
exit(0.0); // безопасный fallback, не должен происходить
|
||||||
|
|
@ -4582,7 +4758,7 @@ begin
|
||||||
var sum := 0.0;
|
var sum := 0.0;
|
||||||
|
|
||||||
foreach var idx in indices do
|
foreach var idx in indices do
|
||||||
sum += y[idx];
|
sum += SampleWeight(idx) * y[idx];
|
||||||
|
|
||||||
var denom: real;
|
var denom: real;
|
||||||
|
|
||||||
|
|
@ -4637,12 +4813,16 @@ begin
|
||||||
if indices = nil then
|
if indices = nil then
|
||||||
indices := Arr(0..X.RowCount - 1);
|
indices := Arr(0..X.RowCount - 1);
|
||||||
|
|
||||||
BuildSortedOrders(X, indices);
|
if (fSortedOrders = nil) or (Length(fSortedOrders) = 0) then
|
||||||
|
BuildSortedOrders(X, indices);
|
||||||
|
|
||||||
SetLength(fVisitMarks, X.RowCount);
|
SetLength(fVisitMarks, X.RowCount);
|
||||||
fVisitId := 0;
|
fVisitId := 0;
|
||||||
|
|
||||||
fRoot := BuildTreeNew(X, y, indices, 0);
|
if fUseSortedOrdersAsRoot then
|
||||||
|
fRoot := BuildTreeNode(X, y, fSortedOrders, 0)
|
||||||
|
else
|
||||||
|
fRoot := BuildTreeNew(X, y, indices, 0);
|
||||||
|
|
||||||
var s := fFeatureImportances.Sum;
|
var s := fFeatureImportances.Sum;
|
||||||
if s > 0 then
|
if s > 0 then
|
||||||
|
|
@ -4653,7 +4833,8 @@ begin
|
||||||
|
|
||||||
fRowIndices := nil;
|
fRowIndices := nil;
|
||||||
fSortedOrders := nil;
|
fSortedOrders := nil;
|
||||||
fSortedValues := nil;
|
fUseSortedOrdersAsRoot := false;
|
||||||
|
fRowWeights := nil;
|
||||||
|
|
||||||
fVisitMarks := nil;
|
fVisitMarks := nil;
|
||||||
|
|
||||||
|
|
@ -4830,6 +5011,7 @@ begin
|
||||||
fFeatureCount := p;
|
fFeatureCount := p;
|
||||||
|
|
||||||
SetLength(fTrees, fNTrees);
|
SetLength(fTrees, fNTrees);
|
||||||
|
var fullSortedOrders := BuildPreSortedOrders(X);
|
||||||
|
|
||||||
// --- OOB buffers (regression) ---
|
// --- OOB buffers (regression) ---
|
||||||
var oobSum: Vector := nil;
|
var oobSum: Vector := nil;
|
||||||
|
|
@ -4858,8 +5040,11 @@ begin
|
||||||
|
|
||||||
var rows: array of integer;
|
var rows: array of integer;
|
||||||
BootstrapRowIndices(n, rows);
|
BootstrapRowIndices(n, rows);
|
||||||
|
|
||||||
tree.SetRowIndices(rows);
|
var rowCounts := BuildRowCounts(rows, n);
|
||||||
|
var bootSortedOrders := BuildUniqueOrdersFromCounts(fullSortedOrders, rowCounts);
|
||||||
|
tree.SetBootstrapRootOrders(bootSortedOrders, rowCounts);
|
||||||
|
|
||||||
tree.Fit(X, y);
|
tree.Fit(X, y);
|
||||||
|
|
||||||
// --- OOB accumulate ---
|
// --- OOB accumulate ---
|
||||||
|
|
@ -5729,6 +5914,9 @@ begin
|
||||||
var yPredTrain := new Vector(nTrain);
|
var yPredTrain := new Vector(nTrain);
|
||||||
for var i := 0 to nTrain - 1 do
|
for var i := 0 to nTrain - 1 do
|
||||||
yPredTrain[i] := fInitValue;
|
yPredTrain[i] := fInitValue;
|
||||||
|
|
||||||
|
var residuals := new Vector(nTrain);
|
||||||
|
var preSortedOrders := BuildPreSortedOrders(XTrain);
|
||||||
|
|
||||||
// --- OOB logic ---
|
// --- OOB logic ---
|
||||||
var useSubsample := fSubsample < 1.0;
|
var useSubsample := fSubsample < 1.0;
|
||||||
|
|
@ -5754,8 +5942,7 @@ begin
|
||||||
for var m := 0 to fNEstimators - 1 do
|
for var m := 0 to fNEstimators - 1 do
|
||||||
begin
|
begin
|
||||||
// 1. residuals
|
// 1. residuals
|
||||||
var r := new Vector(nTrain);
|
ComputePseudoResiduals(yTrain, yPredTrain, residuals);
|
||||||
ComputePseudoResiduals(yTrain, yPredTrain, r);
|
|
||||||
|
|
||||||
var stageSeed := fRng.Next(integer.MaxValue);
|
var stageSeed := fRng.Next(integer.MaxValue);
|
||||||
|
|
||||||
|
|
@ -5766,6 +5953,7 @@ begin
|
||||||
fLeafL2,
|
fLeafL2,
|
||||||
stageSeed
|
stageSeed
|
||||||
);
|
);
|
||||||
|
tree.SetPreSortedOrders(preSortedOrders);
|
||||||
|
|
||||||
// --- subsample ---
|
// --- subsample ---
|
||||||
var rows: array of integer := nil;
|
var rows: array of integer := nil;
|
||||||
|
|
@ -5784,7 +5972,7 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
tree.Fit(XTrain, r);
|
tree.Fit(XTrain, residuals);
|
||||||
fEstimators.Add(tree);
|
fEstimators.Add(tree);
|
||||||
|
|
||||||
var deltaTrain := tree.Predict(XTrain);
|
var deltaTrain := tree.Predict(XTrain);
|
||||||
|
|
|
||||||
|
|
@ -48,14 +48,14 @@ type
|
||||||
/// Пропущенные значения (NA) игнорируются при обучении
|
/// Пропущенные значения (NA) игнорируются при обучении
|
||||||
/// и сохраняются как пропуски при преобразовании.
|
/// и сохраняются как пропуски при преобразовании.
|
||||||
/// Работает только со строковыми столбцами и предназначен для признаков.
|
/// Работает только со строковыми столбцами и предназначен для признаков.
|
||||||
/// Не должен применяться к целевому столбцу (target).
|
/// Не должен применяться к целевому столбцу (target)
|
||||||
LabelEncoder = class(IPreprocessor, IColumnBoundStep)
|
OrdinalEncoder = class(IPreprocessor, IColumnBoundStep)
|
||||||
private
|
private
|
||||||
col: string;
|
col: string;
|
||||||
mapping: Dictionary<string, integer>;
|
mapping: Dictionary<string, integer>;
|
||||||
fitted: boolean;
|
fitted: boolean;
|
||||||
public
|
public
|
||||||
/// Создаёт LabelEncoder для указанного столбца
|
/// Создаёт OrdinalEncoder для указанного столбца
|
||||||
constructor Create(column: string);
|
constructor Create(column: string);
|
||||||
|
|
||||||
/// Определяет множество категорий столбца и сохраняет их числовое кодирование.
|
/// Определяет множество категорий столбца и сохраняет их числовое кодирование.
|
||||||
|
|
@ -66,8 +66,10 @@ type
|
||||||
/// • отображение категорий НЕ копируется методом Clone
|
/// • отображение категорий НЕ копируется методом Clone
|
||||||
function Fit(df: DataFrame): IPreprocessor;
|
function Fit(df: DataFrame): IPreprocessor;
|
||||||
|
|
||||||
/// Заменяет категории их числовыми кодами
|
/// Заменяет категории их числовыми кодами.
|
||||||
/// Возвращает новый DataFrame
|
/// Неизвестные категории кодируются значением -1.
|
||||||
|
/// Пропущенные значения сохраняются как пропуски.
|
||||||
|
/// Возвращает новый DataFrame.
|
||||||
function Transform(df: DataFrame): DataFrame;
|
function Transform(df: DataFrame): DataFrame;
|
||||||
|
|
||||||
/// Выполняет Fit и Transform последовательно
|
/// Выполняет Fit и Transform последовательно
|
||||||
|
|
@ -174,14 +176,14 @@ implementation
|
||||||
uses MLExceptions;
|
uses MLExceptions;
|
||||||
|
|
||||||
const
|
const
|
||||||
ER_LABELENCODER_NO_COLUMN =
|
ER_ORDINALENCODER_NO_COLUMN =
|
||||||
'LabelEncoder: столбец не указан!!LabelEncoder: column not specified';
|
'OrdinalEncoder: столбец не указан!!OrdinalEncoder: column not specified';
|
||||||
ER_LABELENCODER_NOT_STRING =
|
ER_ORDINALENCODER_NOT_STRING =
|
||||||
'LabelEncoder: столбец "{0}" не является строковым!!' +
|
'OrdinalEncoder: столбец "{0}" не является строковым!!' +
|
||||||
'LabelEncoder: column "{0}" is not string';
|
'OrdinalEncoder: column "{0}" is not string';
|
||||||
ER_LABELENCODER_UNSEEN_CATEGORY =
|
ER_ORDINALENCODER_UNSEEN_CATEGORY =
|
||||||
'LabelEncoder: неизвестная категория "{0}"!!' +
|
'OrdinalEncoder: неизвестная категория "{0}"!!' +
|
||||||
'LabelEncoder: unseen category "{0}"';
|
'OrdinalEncoder: unseen category "{0}"';
|
||||||
ER_ONEHOT_NO_COLUMN =
|
ER_ONEHOT_NO_COLUMN =
|
||||||
'OneHotEncoder: столбец не указан!!OneHotEncoder: column not specified';
|
'OneHotEncoder: столбец не указан!!OneHotEncoder: column not specified';
|
||||||
ER_ONEHOT_NOT_STRING =
|
ER_ONEHOT_NOT_STRING =
|
||||||
|
|
@ -229,19 +231,19 @@ const
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------
|
//-----------------------------
|
||||||
// LabelEncoder
|
// OrdinalEncoder
|
||||||
//-----------------------------
|
//-----------------------------
|
||||||
|
|
||||||
constructor LabelEncoder.Create(column: string);
|
constructor OrdinalEncoder.Create(column: string);
|
||||||
begin
|
begin
|
||||||
if column = '' then
|
if column = '' then
|
||||||
ArgumentError(ER_LABELENCODER_NO_COLUMN);
|
ArgumentError(ER_ORDINALENCODER_NO_COLUMN);
|
||||||
|
|
||||||
col := column;
|
col := column;
|
||||||
fitted := false;
|
fitted := false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function LabelEncoder.Fit(df: DataFrame): IPreprocessor;
|
function OrdinalEncoder.Fit(df: DataFrame): IPreprocessor;
|
||||||
begin
|
begin
|
||||||
if df = nil then
|
if df = nil then
|
||||||
ArgumentNullError(ER_ARG_NULL, 'df');
|
ArgumentNullError(ER_ARG_NULL, 'df');
|
||||||
|
|
@ -252,7 +254,7 @@ begin
|
||||||
var idx := df.Schema.IndexOf(col);
|
var idx := df.Schema.IndexOf(col);
|
||||||
|
|
||||||
if df.Schema.ColumnTypeAt(idx) <> ColumnType.ctStr then
|
if df.Schema.ColumnTypeAt(idx) <> ColumnType.ctStr then
|
||||||
Error(ER_LABELENCODER_NOT_STRING, col);
|
Error(ER_ORDINALENCODER_NOT_STRING, col);
|
||||||
|
|
||||||
mapping := new Dictionary<string, integer>;
|
mapping := new Dictionary<string, integer>;
|
||||||
|
|
||||||
|
|
@ -275,7 +277,7 @@ begin
|
||||||
Result := Self;
|
Result := Self;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function LabelEncoder.Transform(df: DataFrame): DataFrame;
|
function OrdinalEncoder.Transform(df: DataFrame): DataFrame;
|
||||||
begin
|
begin
|
||||||
if not fitted then
|
if not fitted then
|
||||||
NotFittedError(ER_FIT_NOT_CALLED);
|
NotFittedError(ER_FIT_NOT_CALLED);
|
||||||
|
|
@ -299,10 +301,11 @@ begin
|
||||||
begin
|
begin
|
||||||
var s := cur.Str(idx);
|
var s := cur.Str(idx);
|
||||||
|
|
||||||
if not mapping.ContainsKey(s) then
|
if s not in mapping then
|
||||||
Error(ER_LABELENCODER_UNSEEN_CATEGORY, s);
|
data[row] := -1
|
||||||
|
else
|
||||||
data[row] := mapping[s];
|
data[row] := mapping[s];
|
||||||
|
|
||||||
valid[row] := True;
|
valid[row] := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -328,20 +331,20 @@ begin
|
||||||
Result := res.SetCategorical(catCols.ToArray);
|
Result := res.SetCategorical(catCols.ToArray);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function LabelEncoder.FitTransform(df: DataFrame): DataFrame;
|
function OrdinalEncoder.FitTransform(df: DataFrame): DataFrame;
|
||||||
begin
|
begin
|
||||||
Fit(df);
|
Fit(df);
|
||||||
Result := Transform(df);
|
Result := Transform(df);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function LabelEncoder.ToString: string;
|
function OrdinalEncoder.ToString: string;
|
||||||
begin
|
begin
|
||||||
Result := 'LabelEncoder(' + col + ')';
|
Result := 'OrdinalEncoder(' + col + ')';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function LabelEncoder.Clone: IPreprocessor;
|
function OrdinalEncoder.Clone: IPreprocessor;
|
||||||
begin
|
begin
|
||||||
Result := new LabelEncoder(col);
|
Result := new OrdinalEncoder(col);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure AppendAllColumnsExcept(
|
procedure AppendAllColumnsExcept(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue