used_cars
Мелкие дополнения ML
This commit is contained in:
parent
7c31caa0b7
commit
911142c83e
|
|
@ -22,7 +22,7 @@ begin
|
||||||
var y := df.EncodeLabels(ds.Target);
|
var y := df.EncodeLabels(ds.Target);
|
||||||
|
|
||||||
// Делим данные на обучающую и тестовую выборки
|
// Делим данные на обучающую и тестовую выборки
|
||||||
var (Xtrain, Xtest, ytrain, ytest) := Validation.TrainTestSplit(X, y, 0.2, 3);
|
var (Xtrain, Xtest, ytrain, ytest) := Validation.TrainTestSplit(X, y, 0.2, seed := 3);
|
||||||
|
|
||||||
// Создаём модель логистической регрессии
|
// Создаём модель логистической регрессии
|
||||||
var model := new LogisticRegression(0.001);
|
var model := new LogisticRegression(0.001);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
uses MLABC,PlotML;
|
||||||
|
|
||||||
|
begin
|
||||||
|
var df := DataFrame.FromCsvText('''
|
||||||
|
Вес,ВысотаВХолке,Порода
|
||||||
|
20,33,бульдог
|
||||||
|
22,34,бульдог
|
||||||
|
24,35,бульдог
|
||||||
|
25,36,бульдог
|
||||||
|
19,35,бульдог
|
||||||
|
21,35,бульдог
|
||||||
|
26,34,бульдог
|
||||||
|
20,36,бульдог
|
||||||
|
14,39,спаниель
|
||||||
|
15,40,спаниель
|
||||||
|
16,41,спаниель
|
||||||
|
18,42,спаниель
|
||||||
|
17,43,спаниель
|
||||||
|
15,38,спаниель
|
||||||
|
19,40,спаниель
|
||||||
|
16,40,спаниель
|
||||||
|
''');
|
||||||
|
|
||||||
|
var X := df.ToMatrix(['Вес', 'ВысотаВХолке']);
|
||||||
|
var target := df.EncodeTarget('Порода');
|
||||||
|
var y := target.Labels;
|
||||||
|
var classNames := target.ClassNames;
|
||||||
|
|
||||||
|
var model := new LogisticRegression;
|
||||||
|
model.Fit(X, y);
|
||||||
|
|
||||||
|
var example := [20.0, 38.0];
|
||||||
|
var pred := model.PredictOne(example);
|
||||||
|
var prob := model.PredictProbaOne(example);
|
||||||
|
|
||||||
|
Println('Предсказанная порода:', classNames[pred]);
|
||||||
|
Println('Предсказанные вероятности:');
|
||||||
|
Println(classnames[0]:10,'-',prob[0]:0:2);
|
||||||
|
Println(classnames[1]:10,'-',prob[1]:0:2);
|
||||||
|
|
||||||
|
Plot.XLabel := df.ColumnNames[0];
|
||||||
|
Plot.YLabel := df.ColumnNames[1];
|
||||||
|
Plot.Title := 'Бульдоги и спаниели';
|
||||||
|
|
||||||
|
Plot.Points(X.Col(0),X.Col(1),y);
|
||||||
|
Plot.Points([example[0]],[example[1]],Colors.Black,size := 8);
|
||||||
|
|
||||||
|
var (A,B,C) := model.DecisionBoundary.Coefficients;
|
||||||
|
Plot.Line(A,B,C);
|
||||||
|
end.
|
||||||
|
|
@ -496,7 +496,7 @@ namespace PascalABCCompiler.ParserTools
|
||||||
ss[0] = ss[0].Trim();
|
ss[0] = ss[0].Trim();
|
||||||
if (ss[0].Length > 0)
|
if (ss[0].Length > 0)
|
||||||
// мы сюда точно не должны попасть. Это должна быть обычная строка!
|
// мы сюда точно не должны попасть. Это должна быть обычная строка!
|
||||||
this.AddErrorFromResource("IMPOSSIBLE_MULTILINE_ERROR", sc);
|
this.AddErrorFromResource("IMPOSSIBLE_MULTILINE_ERROR"+" " + ss[0].Length.ToString(), sc);
|
||||||
|
|
||||||
if (ss[ss.Length - 1].Trim().Length > 0)
|
if (ss[ss.Length - 1].Trim().Length > 0)
|
||||||
// There should be no non-whitespace characters before the closing quotes of the multiline string
|
// There should be no non-whitespace characters before the closing quotes of the multiline string
|
||||||
|
|
|
||||||
10001
ReleaseGenerators/Files/Datasets/used_cars_price.csv
Normal file
10001
ReleaseGenerators/Files/Datasets/used_cars_price.csv
Normal file
File diff suppressed because it is too large
Load diff
45
ReleaseGenerators/Files/Datasets/used_cars_price.meta
Normal file
45
ReleaseGenerators/Files/Datasets/used_cars_price.meta
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
name = UsedCarsPrice
|
||||||
|
|
||||||
|
task = regression
|
||||||
|
|
||||||
|
features = model,year,transmission,mileage_km,fuelType,l_100km,engineSize,Make
|
||||||
|
target = price_k_rub
|
||||||
|
|
||||||
|
description.en = Used car prices with model, year, mileage, engine, fuel and transmission features. The target variable is price in thousand rubles.
|
||||||
|
description.ru = Цены на автомобили с пробегом по модели, году выпуска, пробегу, двигателю, топливу и типу коробки передач. Целевая переменная — цена в тыс. руб.
|
||||||
|
modified.en = Modified version with mileage, fuel consumption and price converted to units familiar to Russian users.
|
||||||
|
modified.ru = Модифицированная версия датасета с переводом пробега, расхода топлива и цены в привычные для российской аудитории величины.
|
||||||
|
|
||||||
|
source = Kaggle: Used Car Price Prediction Dataset
|
||||||
|
url = https://www.kaggle.com/datasets/taeefnajib/used-car-price-prediction-dataset
|
||||||
|
|
||||||
|
feature.model = categorical
|
||||||
|
feature.year = int
|
||||||
|
feature.price_k_rub = float
|
||||||
|
feature.transmission = categorical
|
||||||
|
feature.mileage_km = int
|
||||||
|
feature.fuelType = categorical
|
||||||
|
feature.l_100km = float
|
||||||
|
feature.engineSize = float
|
||||||
|
feature.Make = categorical
|
||||||
|
|
||||||
|
feature.model.ru = модель
|
||||||
|
feature.year.ru = год выпуска
|
||||||
|
feature.price_k_rub.ru = цена в тыс. руб.
|
||||||
|
feature.transmission.ru = коробка передач
|
||||||
|
feature.mileage_km.ru = пробег в километрах
|
||||||
|
feature.fuelType.ru = тип топлива
|
||||||
|
feature.l_100km.ru = расход в литрах на 100 км
|
||||||
|
feature.engineSize.ru = объём двигателя в литрах
|
||||||
|
feature.Make.ru = марка
|
||||||
|
|
||||||
|
feature.model.en = model
|
||||||
|
feature.year.en = year
|
||||||
|
feature.price_k_rub.en = price in thousand rubles
|
||||||
|
feature.transmission.en = transmission
|
||||||
|
feature.mileage_km.en = mileage in kilometres
|
||||||
|
feature.fuelType.en = fuel type
|
||||||
|
feature.l_100km.en = fuel consumption in litres per 100 km
|
||||||
|
feature.engineSize.en = engine size in litres
|
||||||
|
feature.Make.en = make
|
||||||
|
|
||||||
|
|
@ -2,7 +2,19 @@
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
// Здесь пока только методы расширения поэтому секция interface - пуста
|
type
|
||||||
|
/// Результат кодирования целевого столбца:
|
||||||
|
/// целочисленные метки и соответствующие имена классов.
|
||||||
|
EncodedTarget = record
|
||||||
|
Labels: array of integer;
|
||||||
|
ClassNames: array of string;
|
||||||
|
|
||||||
|
/// Возвращает код класса для строки с индексом rowIndex.
|
||||||
|
function ClassIndex(rowIndex: integer): integer;
|
||||||
|
|
||||||
|
/// Возвращает имя класса для строки с индексом rowIndex.
|
||||||
|
function ClassName(rowIndex: integer): string;
|
||||||
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
|
@ -23,7 +35,29 @@ const
|
||||||
ER_ENCODELABELS_UNSUPPORTED_TYPE =
|
ER_ENCODELABELS_UNSUPPORTED_TYPE =
|
||||||
'Неподдерживаемый тип столбца "{0}" для EncodeLabels!!Unsupported column type "{0}" for EncodeLabels';
|
'Неподдерживаемый тип столбца "{0}" для EncodeLabels!!Unsupported column type "{0}" for EncodeLabels';
|
||||||
ER_TARGET_HAS_NA =
|
ER_TARGET_HAS_NA =
|
||||||
'Целевой столбец "{0}" содержит NA!!Target column "{0}" contains NA values';
|
'Целевой столбец "{0}" содержит NA!!Target column "{0}" contains NA values';
|
||||||
|
ER_ENCODED_TARGET_ROW_INDEX_OUT_OF_RANGE =
|
||||||
|
'Индекс строки {0} вне диапазона [0, {1})!!Row index {0} is out of range [0, {1})';
|
||||||
|
ER_ENCODED_TARGET_CLASS_INDEX_OUT_OF_RANGE =
|
||||||
|
'Индекс класса {0} вне диапазона [0, {1})!!Class index {0} is out of range [0, {1})';
|
||||||
|
|
||||||
|
function EncodedTarget.ClassIndex(rowIndex: integer): integer;
|
||||||
|
begin
|
||||||
|
if (rowIndex < 0) or (rowIndex >= Labels.Length) then
|
||||||
|
ArgumentOutOfRangeError(ER_ENCODED_TARGET_ROW_INDEX_OUT_OF_RANGE, rowIndex, Labels.Length);
|
||||||
|
|
||||||
|
Result := Labels[rowIndex];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function EncodedTarget.ClassName(rowIndex: integer): string;
|
||||||
|
begin
|
||||||
|
var cls := ClassIndex(rowIndex);
|
||||||
|
|
||||||
|
if (cls < 0) or (cls >= ClassNames.Length) then
|
||||||
|
ArgumentOutOfRangeError(ER_ENCODED_TARGET_CLASS_INDEX_OUT_OF_RANGE, cls, ClassNames.Length);
|
||||||
|
|
||||||
|
Result := ClassNames[cls];
|
||||||
|
end;
|
||||||
|
|
||||||
function ToMatrix(Self: DataFrame; colNames: array of string): Matrix; extensionmethod;
|
function ToMatrix(Self: DataFrame; colNames: array of string): Matrix; extensionmethod;
|
||||||
begin
|
begin
|
||||||
|
|
@ -215,6 +249,16 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
/// Кодирует целевой столбец DataFrame и возвращает
|
||||||
|
/// целочисленные метки вместе с массивом имён классов.
|
||||||
|
/// Порядок кодирования соответствует порядку первого появления значений.
|
||||||
|
function EncodeTarget(Self: DataFrame; target: string): EncodedTarget; extensionmethod;
|
||||||
|
begin
|
||||||
|
var classes: array of string;
|
||||||
|
Result.Labels := Self.EncodeLabels(target, classes);
|
||||||
|
Result.ClassNames := classes;
|
||||||
|
end;
|
||||||
|
|
||||||
/// Преобразует строковые метки целевого столбца в целочисленные индексы (0,1,2,...)
|
/// Преобразует строковые метки целевого столбца в целочисленные индексы (0,1,2,...)
|
||||||
/// с использованием заданного массива classes (mapping индекс → метка).
|
/// с использованием заданного массива classes (mapping индекс → метка).
|
||||||
/// classes должен быть получен ранее с помощью EncodeLabels.
|
/// classes должен быть получен ранее с помощью EncodeLabels.
|
||||||
|
|
|
||||||
|
|
@ -99,11 +99,14 @@ type
|
||||||
|
|
||||||
function GetColumn(name: string): Column;
|
function GetColumn(name: string): Column;
|
||||||
function GetSchema: DataFrameSchema;
|
function GetSchema: DataFrameSchema;
|
||||||
|
procedure CheckRowIndex(rowIndex: integer);
|
||||||
|
|
||||||
function CloneWithSharedColumns: DataFrame;
|
function CloneWithSharedColumns: DataFrame;
|
||||||
public
|
public
|
||||||
/// Создает пустой DataFrame
|
/// Создает пустой DataFrame
|
||||||
constructor Create;
|
constructor Create;
|
||||||
|
/// Возвращает имена столбцов
|
||||||
|
property ColumnNames: array of string read Schema.ColumnNames;
|
||||||
|
|
||||||
/// Возвращает копию схемы DataFrame
|
/// Возвращает копию схемы DataFrame
|
||||||
property Schema: DataFrameSchema read GetSchema;
|
property Schema: DataFrameSchema read GetSchema;
|
||||||
|
|
@ -220,14 +223,34 @@ type
|
||||||
|
|
||||||
/// Возвращает целочисленный массив значений столбца с данным именем.
|
/// Возвращает целочисленный массив значений столбца с данным именем.
|
||||||
function Int(name: string): array of integer;
|
function Int(name: string): array of integer;
|
||||||
|
/// Возвращает целочисленное значение ячейки по индексам строки и столбца.
|
||||||
|
function Int(rowIndex, colIndex: integer): integer;
|
||||||
|
/// Возвращает целочисленное значение ячейки по индексу строки и имени столбца.
|
||||||
|
function Int(rowIndex: integer; colName: string): integer;
|
||||||
/// Возвращает вещественный массив значений столбца с данным именем.
|
/// Возвращает вещественный массив значений столбца с данным именем.
|
||||||
function Float(name: string): array of real;
|
function Float(name: string): array of real;
|
||||||
|
/// Возвращает вещественное значение ячейки по индексам строки и столбца.
|
||||||
|
function Float(rowIndex, colIndex: integer): real;
|
||||||
|
/// Возвращает вещественное значение ячейки по индексу строки и имени столбца.
|
||||||
|
function Float(rowIndex: integer; colName: string): real;
|
||||||
/// Возвращает строковый массив значений столбца с данным именем.
|
/// Возвращает строковый массив значений столбца с данным именем.
|
||||||
function Str(name: string): array of string;
|
function Str(name: string): array of string;
|
||||||
|
/// Возвращает строковое значение ячейки по индексам строки и столбца.
|
||||||
|
function Str(rowIndex, colIndex: integer): string;
|
||||||
|
/// Возвращает строковое значение ячейки по индексу строки и имени столбца.
|
||||||
|
function Str(rowIndex: integer; colName: string): string;
|
||||||
/// Возвращает логический массив значений столбца с данным именем.
|
/// Возвращает логический массив значений столбца с данным именем.
|
||||||
function Bool(name: string): array of boolean;
|
function Bool(name: string): array of boolean;
|
||||||
|
/// Возвращает логическое значение ячейки по индексам строки и столбца.
|
||||||
|
function Bool(rowIndex, colIndex: integer): boolean;
|
||||||
|
/// Возвращает логическое значение ячейки по индексу строки и имени столбца.
|
||||||
|
function Bool(rowIndex: integer; colName: string): boolean;
|
||||||
/// Возвращает массив DateTime-значений столбца с данным именем.
|
/// Возвращает массив DateTime-значений столбца с данным именем.
|
||||||
function DateTime(name: string): array of System.DateTime;
|
function DateTime(name: string): array of System.DateTime;
|
||||||
|
/// Возвращает DateTime-значение ячейки по индексам строки и столбца.
|
||||||
|
function DateTime(rowIndex, colIndex: integer): System.DateTime;
|
||||||
|
/// Возвращает DateTime-значение ячейки по индексу строки и имени столбца.
|
||||||
|
function DateTime(rowIndex: integer; colName: string): System.DateTime;
|
||||||
|
|
||||||
/// Вычисляет сумму значений столбца по индексу
|
/// Вычисляет сумму значений столбца по индексу
|
||||||
function Sum(colIndex: integer): real;
|
function Sum(colIndex: integer): real;
|
||||||
|
|
@ -770,6 +793,8 @@ const
|
||||||
'Дублирующееся имя агрегированной колонки!!Duplicate aggregated column name';
|
'Дублирующееся имя агрегированной колонки!!Duplicate aggregated column name';
|
||||||
ER_ROW_INDEX_OUT_OF_RANGE =
|
ER_ROW_INDEX_OUT_OF_RANGE =
|
||||||
'Индекс строки вне диапазона!!Row index is out of range';
|
'Индекс строки вне диапазона!!Row index is out of range';
|
||||||
|
ER_VALUE_IS_NA =
|
||||||
|
'Значение в столбце "{0}" равно NA!!Value in column "{0}" is NA';
|
||||||
ER_UNSUPPORTED_COLUMN_TYPE =
|
ER_UNSUPPORTED_COLUMN_TYPE =
|
||||||
'Неподдерживаемый тип столбца!!Unsupported column type';
|
'Неподдерживаемый тип столбца!!Unsupported column type';
|
||||||
ER_JOIN_FLOAT_KEY_NOT_SUPPORTED =
|
ER_JOIN_FLOAT_KEY_NOT_SUPPORTED =
|
||||||
|
|
@ -2473,6 +2498,12 @@ begin
|
||||||
);
|
);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure DataFrame.CheckRowIndex(rowIndex: integer);
|
||||||
|
begin
|
||||||
|
if (rowIndex < 0) or (rowIndex >= RowCount) then
|
||||||
|
ArgumentOutOfRangeError(ER_ROW_INDEX_OUT_OF_RANGE);
|
||||||
|
end;
|
||||||
|
|
||||||
function DataFrame.GetCursor: DataFrameCursor :=
|
function DataFrame.GetCursor: DataFrameCursor :=
|
||||||
new DataFrameCursor(columns.ToArray,fSchema);
|
new DataFrameCursor(columns.ToArray,fSchema);
|
||||||
|
|
||||||
|
|
@ -2516,26 +2547,106 @@ begin
|
||||||
Result := GetIntColumn(name);
|
Result := GetIntColumn(name);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function DataFrame.Int(rowIndex, colIndex: integer): integer;
|
||||||
|
begin
|
||||||
|
CheckRowIndex(rowIndex);
|
||||||
|
CheckColumnIndex(colIndex);
|
||||||
|
|
||||||
|
var c := IntColumn(columns[colIndex]);
|
||||||
|
if not c.IsValid[rowIndex] then
|
||||||
|
Error(ER_VALUE_IS_NA, fSchema.NameAt(colIndex));
|
||||||
|
Result := c.Data[rowIndex];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function DataFrame.Int(rowIndex: integer; colName: string): integer;
|
||||||
|
begin
|
||||||
|
Result := Int(rowIndex, ColumnIndex(colName));
|
||||||
|
end;
|
||||||
|
|
||||||
function DataFrame.Float(name: string): array of real;
|
function DataFrame.Float(name: string): array of real;
|
||||||
begin
|
begin
|
||||||
Result := GetFloatColumn(name);
|
Result := GetFloatColumn(name);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function DataFrame.Float(rowIndex, colIndex: integer): real;
|
||||||
|
begin
|
||||||
|
CheckRowIndex(rowIndex);
|
||||||
|
CheckColumnIndex(colIndex);
|
||||||
|
|
||||||
|
var c := FloatColumn(columns[colIndex]);
|
||||||
|
if not c.IsValid[rowIndex] then
|
||||||
|
Error(ER_VALUE_IS_NA, fSchema.NameAt(colIndex));
|
||||||
|
Result := c.Data[rowIndex];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function DataFrame.Float(rowIndex: integer; colName: string): real;
|
||||||
|
begin
|
||||||
|
Result := Float(rowIndex, ColumnIndex(colName));
|
||||||
|
end;
|
||||||
|
|
||||||
function DataFrame.Str(name: string): array of string;
|
function DataFrame.Str(name: string): array of string;
|
||||||
begin
|
begin
|
||||||
Result := GetStrColumn(name);
|
Result := GetStrColumn(name);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function DataFrame.Str(rowIndex, colIndex: integer): string;
|
||||||
|
begin
|
||||||
|
CheckRowIndex(rowIndex);
|
||||||
|
CheckColumnIndex(colIndex);
|
||||||
|
|
||||||
|
var c := StrColumn(columns[colIndex]);
|
||||||
|
if not c.IsValid[rowIndex] then
|
||||||
|
Error(ER_VALUE_IS_NA, fSchema.NameAt(colIndex));
|
||||||
|
Result := c.Data[rowIndex];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function DataFrame.Str(rowIndex: integer; colName: string): string;
|
||||||
|
begin
|
||||||
|
Result := Str(rowIndex, ColumnIndex(colName));
|
||||||
|
end;
|
||||||
|
|
||||||
function DataFrame.Bool(name: string): array of boolean;
|
function DataFrame.Bool(name: string): array of boolean;
|
||||||
begin
|
begin
|
||||||
Result := GetBoolColumn(name);
|
Result := GetBoolColumn(name);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function DataFrame.Bool(rowIndex, colIndex: integer): boolean;
|
||||||
|
begin
|
||||||
|
CheckRowIndex(rowIndex);
|
||||||
|
CheckColumnIndex(colIndex);
|
||||||
|
|
||||||
|
var c := BoolColumn(columns[colIndex]);
|
||||||
|
if not c.IsValid[rowIndex] then
|
||||||
|
Error(ER_VALUE_IS_NA, fSchema.NameAt(colIndex));
|
||||||
|
Result := c.Data[rowIndex];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function DataFrame.Bool(rowIndex: integer; colName: string): boolean;
|
||||||
|
begin
|
||||||
|
Result := Bool(rowIndex, ColumnIndex(colName));
|
||||||
|
end;
|
||||||
|
|
||||||
function DataFrame.DateTime(name: string): array of System.DateTime;
|
function DataFrame.DateTime(name: string): array of System.DateTime;
|
||||||
begin
|
begin
|
||||||
Result := GetDateTimeColumn(name);
|
Result := GetDateTimeColumn(name);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function DataFrame.DateTime(rowIndex, colIndex: integer): System.DateTime;
|
||||||
|
begin
|
||||||
|
CheckRowIndex(rowIndex);
|
||||||
|
CheckColumnIndex(colIndex);
|
||||||
|
|
||||||
|
var c := DateTimeColumn(columns[colIndex]);
|
||||||
|
if not c.IsValid[rowIndex] then
|
||||||
|
Error(ER_VALUE_IS_NA, fSchema.NameAt(colIndex));
|
||||||
|
Result := c.Data[rowIndex];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function DataFrame.DateTime(rowIndex: integer; colName: string): System.DateTime;
|
||||||
|
begin
|
||||||
|
Result := DateTime(rowIndex, ColumnIndex(colName));
|
||||||
|
end;
|
||||||
|
|
||||||
function DataFrame.TrainTestSplit(testRatio: real; shuffle: boolean; seed: integer): (DataFrame, DataFrame);
|
function DataFrame.TrainTestSplit(testRatio: real; shuffle: boolean; seed: integer): (DataFrame, DataFrame);
|
||||||
begin
|
begin
|
||||||
if Self = nil then
|
if Self = nil then
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ type
|
||||||
public
|
public
|
||||||
/// Возвращает количество столбцов в схеме
|
/// Возвращает количество столбцов в схеме
|
||||||
property ColumnCount: integer read fNames.Length;
|
property ColumnCount: integer read fNames.Length;
|
||||||
/// Возвращает копию массива имён столбцов
|
/// Возвращает имена столбцов
|
||||||
property ColumnNames: array of string read GetColumnNames;
|
property ColumnNames: array of string read GetColumnNames;
|
||||||
/// Возвращает копию массива типов столбцов
|
/// Возвращает копию массива типов столбцов
|
||||||
property Types: array of ColumnType read GetTypes;
|
property Types: array of ColumnType read GetTypes;
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,8 @@ type
|
||||||
/// Создаёт матрицу из двумерного массива вещественных значений.
|
/// Создаёт матрицу из двумерного массива вещественных значений.
|
||||||
constructor Create(values: array[,] of real);
|
constructor Create(values: array[,] of real);
|
||||||
|
|
||||||
|
constructor Create(values: array of Vector);
|
||||||
|
|
||||||
/// Возвращает копию данных в виде двумерного массива.
|
/// Возвращает копию данных в виде двумерного массива.
|
||||||
function ToArray2D: array[,] of real;
|
function ToArray2D: array[,] of real;
|
||||||
/// Возвращает строку матрицы в виде массива.
|
/// Возвращает строку матрицы в виде массива.
|
||||||
|
|
@ -225,6 +227,7 @@ type
|
||||||
|
|
||||||
|
|
||||||
static function operator implicit(a: array [,] of real): Matrix := new Matrix(a);
|
static function operator implicit(a: array [,] of real): Matrix := new Matrix(a);
|
||||||
|
static function operator implicit(a: array of Vector): Matrix := new Matrix(a);
|
||||||
static function operator implicit(a: array of array of real): Matrix := new Matrix(Matr(a));
|
static function operator implicit(a: array of array of real): Matrix := new Matrix(Matr(a));
|
||||||
static function operator implicit(a: array of array of integer): Matrix := new Matrix(Matr(a.ConvertAll(x -> x.ConvertAll(y -> real(y)))));
|
static function operator implicit(a: array of array of integer): Matrix := new Matrix(Matr(a.ConvertAll(x -> x.ConvertAll(y -> real(y)))));
|
||||||
|
|
||||||
|
|
@ -369,8 +372,14 @@ const
|
||||||
'Длина вектора должна быть неотрицательной!!Vector length must be non-negative';
|
'Длина вектора должна быть неотрицательной!!Vector length must be non-negative';
|
||||||
ER_VALUES_NULL =
|
ER_VALUES_NULL =
|
||||||
'values не может быть nil!!values cannot be nil';
|
'values не может быть nil!!values cannot be nil';
|
||||||
|
ER_VALUES_EMPTY =
|
||||||
|
'values не может быть пустым!!values cannot be empty';
|
||||||
ER_VECTOR_LENGTH_MISMATCH =
|
ER_VECTOR_LENGTH_MISMATCH =
|
||||||
'Несоответствие длины векторов: {0} и {1}!!Vector length mismatch: {0} vs {1}';
|
'Несоответствие длины векторов: {0} и {1}!!Vector length mismatch: {0} vs {1}';
|
||||||
|
ER_VECTOR_NULL =
|
||||||
|
'Вектор не может быть nil!!vector cannot be nil';
|
||||||
|
ER_MATRIX_ROWS_HAVE_DIFFERENT_LENGTHS =
|
||||||
|
'Строки матрицы имеют разную длину!!matrix rows have different lengths';
|
||||||
ER_VECTOR_EMPTY =
|
ER_VECTOR_EMPTY =
|
||||||
'Вектор пуст!!Vector is empty';
|
'Вектор пуст!!Vector is empty';
|
||||||
ER_VECTOR_DIVIDE_BY_ZERO =
|
ER_VECTOR_DIVIDE_BY_ZERO =
|
||||||
|
|
@ -659,6 +668,38 @@ begin
|
||||||
fdata := Copy(values);
|
fdata := Copy(values);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
constructor Matrix.Create(values: array of Vector);
|
||||||
|
begin
|
||||||
|
if values = nil then
|
||||||
|
ArgumentNullError(ER_VALUES_NULL);
|
||||||
|
|
||||||
|
var r := values.Length;
|
||||||
|
if r = 0 then
|
||||||
|
ArgumentError(ER_VALUES_EMPTY);
|
||||||
|
|
||||||
|
if values[0] = nil then
|
||||||
|
ArgumentNullError(ER_VECTOR_NULL);
|
||||||
|
|
||||||
|
var c := values[0].Length;
|
||||||
|
if c = 0 then
|
||||||
|
ArgumentError(ER_VECTOR_EMPTY);
|
||||||
|
|
||||||
|
for var i := 1 to r - 1 do
|
||||||
|
begin
|
||||||
|
if values[i] = nil then
|
||||||
|
ArgumentNullError(ER_VECTOR_NULL);
|
||||||
|
|
||||||
|
if values[i].Length <> c then
|
||||||
|
ArgumentError(ER_MATRIX_ROWS_HAVE_DIFFERENT_LENGTHS);
|
||||||
|
end;
|
||||||
|
|
||||||
|
fdata := new real[r, c];
|
||||||
|
|
||||||
|
for var i := 0 to r - 1 do
|
||||||
|
for var j := 0 to c - 1 do
|
||||||
|
fdata[i, j] := values[i][j];
|
||||||
|
end;
|
||||||
|
|
||||||
function Matrix.ToArray2D: array[,] of real;
|
function Matrix.ToArray2D: array[,] of real;
|
||||||
begin
|
begin
|
||||||
Result := Copy(fdata);
|
Result := Copy(fdata);
|
||||||
|
|
@ -1094,7 +1135,6 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static function Matrix.operator +(A, B: Matrix): Matrix;
|
static function Matrix.operator +(A, B: Matrix): Matrix;
|
||||||
begin
|
begin
|
||||||
CheckSameSize(A, B);
|
CheckSameSize(A, B);
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ type
|
||||||
CsvLoader = DataFrameABC.CsvLoader;
|
CsvLoader = DataFrameABC.CsvLoader;
|
||||||
JoinKind = DataFrameABC.JoinKind;
|
JoinKind = DataFrameABC.JoinKind;
|
||||||
GroupView = DataFrameABC.GroupView;
|
GroupView = DataFrameABC.GroupView;
|
||||||
|
EncodedTarget = DataAdapters.EncodedTarget;
|
||||||
|
|
||||||
IProbabilisticClassifier = MLCoreABC.IProbabilisticClassifier;
|
IProbabilisticClassifier = MLCoreABC.IProbabilisticClassifier;
|
||||||
IClassifier = MLCoreABC.IClassifier;
|
IClassifier = MLCoreABC.IClassifier;
|
||||||
|
|
@ -135,6 +136,8 @@ type
|
||||||
ClassificationMatrixPipeline = MLModelsABC.ClassificationMatrixPipeline;
|
ClassificationMatrixPipeline = MLModelsABC.ClassificationMatrixPipeline;
|
||||||
RegressionMatrixPipeline = MLModelsABC.RegressionMatrixPipeline;
|
RegressionMatrixPipeline = MLModelsABC.RegressionMatrixPipeline;
|
||||||
ClusteringMatrixPipeline = MLModelsABC.ClusteringMatrixPipeline;
|
ClusteringMatrixPipeline = MLModelsABC.ClusteringMatrixPipeline;
|
||||||
|
LinearDecisionBoundary = MLModelsABC.LinearDecisionBoundary;
|
||||||
|
LinearRegressionLine = MLModelsABC.LinearRegressionLine;
|
||||||
|
|
||||||
LinearRegression = MLModelsABC.LinearRegression;
|
LinearRegression = MLModelsABC.LinearRegression;
|
||||||
LogisticRegression = MLModelsABC.LogisticRegression;
|
LogisticRegression = MLModelsABC.LogisticRegression;
|
||||||
|
|
@ -143,12 +146,14 @@ type
|
||||||
ElasticNet = MLModelsABC.ElasticNet;
|
ElasticNet = MLModelsABC.ElasticNet;
|
||||||
DecisionTreeClassifier = MLModelsABC.DecisionTreeClassifier;
|
DecisionTreeClassifier = MLModelsABC.DecisionTreeClassifier;
|
||||||
DecisionTreeRegressor = MLModelsABC.DecisionTreeRegressor;
|
DecisionTreeRegressor = MLModelsABC.DecisionTreeRegressor;
|
||||||
|
DecisionTreeView = MLModelsABC.DecisionTreeView;
|
||||||
RandomForestRegressor = MLModelsABC.RandomForestRegressor;
|
RandomForestRegressor = MLModelsABC.RandomForestRegressor;
|
||||||
RandomForestClassifier = MLModelsABC.RandomForestClassifier;
|
RandomForestClassifier = MLModelsABC.RandomForestClassifier;
|
||||||
GradientBoostingRegressor = MLModelsABC.GradientBoostingRegressor;
|
GradientBoostingRegressor = MLModelsABC.GradientBoostingRegressor;
|
||||||
GradientBoostingClassifier = MLModelsABC.GradientBoostingClassifier;
|
GradientBoostingClassifier = MLModelsABC.GradientBoostingClassifier;
|
||||||
KNNClassifier = MLModelsABC.KNNClassifier;
|
KNNClassifier = MLModelsABC.KNNClassifier;
|
||||||
KNNRegressor = MLModelsABC.KNNRegressor;
|
KNNRegressor = MLModelsABC.KNNRegressor;
|
||||||
|
NeighborInfo = MLModelsABC.NeighborInfo;
|
||||||
KMeans = MLModelsABC.KMeans;
|
KMeans = MLModelsABC.KMeans;
|
||||||
DBSCAN = MLModelsABC.DBSCAN;
|
DBSCAN = MLModelsABC.DBSCAN;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,10 @@ type
|
||||||
/// и целевых метках классов y.
|
/// и целевых метках классов y.
|
||||||
function Fit(X: Matrix; y: array of integer): IClassifier;
|
function Fit(X: Matrix; y: array of integer): IClassifier;
|
||||||
|
|
||||||
|
/// Возвращает метку класса для одного объекта X
|
||||||
|
/// в том же виде, в каком метки были поданы модели при обучении.
|
||||||
|
function PredictOne(X: Vector): integer;
|
||||||
|
|
||||||
/// Возвращает метки классов в том же виде, в каком они были поданы модели при обучении.
|
/// Возвращает метки классов в том же виде, в каком они были поданы модели при обучении.
|
||||||
function Predict(X: Matrix): array of integer;
|
function Predict(X: Matrix): array of integer;
|
||||||
|
|
||||||
|
|
@ -131,6 +135,10 @@ type
|
||||||
/// Позволяет получать значения в диапазоне (0, 1)
|
/// Позволяет получать значения в диапазоне (0, 1)
|
||||||
/// вместо только итогового решения.
|
/// вместо только итогового решения.
|
||||||
IProbabilisticClassifier = interface(IClassifier)
|
IProbabilisticClassifier = interface(IClassifier)
|
||||||
|
/// Возвращает вектор вероятностей классов для одного объекта X.
|
||||||
|
/// Порядок элементов соответствует GetClassLabels.
|
||||||
|
function PredictProbaOne(X: Vector): Vector;
|
||||||
|
|
||||||
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
||||||
/// Размер результата: nSamples × nClasses, где:
|
/// Размер результата: nSamples × nClasses, где:
|
||||||
/// - nSamples — число объектов в X;
|
/// - nSamples — число объектов в X;
|
||||||
|
|
@ -148,6 +156,9 @@ type
|
||||||
/// и векторе целевых значений y.
|
/// и векторе целевых значений y.
|
||||||
function Fit(X: Matrix; y: Vector): IRegressor;
|
function Fit(X: Matrix; y: Vector): IRegressor;
|
||||||
|
|
||||||
|
/// Возвращает числовое предсказание для одного объекта X.
|
||||||
|
function PredictOne(X: Vector): real;
|
||||||
|
|
||||||
function Predict(X: Matrix): Vector;
|
function Predict(X: Matrix): Vector;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,24 @@ type
|
||||||
function GetClassLabels: array of string;
|
function GetClassLabels: array of string;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
LinearDecisionBoundary = record
|
||||||
|
A, B, C: real;
|
||||||
|
function Evaluate(x, y: real): real;
|
||||||
|
function Y(x: real): real;
|
||||||
|
function Side(x, y: real): integer;
|
||||||
|
function Distance(x, y: real): real;
|
||||||
|
function ToString: string; override;
|
||||||
|
function Coefficients: (real,real,real) := (A,B,C);
|
||||||
|
end;
|
||||||
|
|
||||||
|
LinearRegressionLine = record
|
||||||
|
K, B: real;
|
||||||
|
function Evaluate(x: real): real;
|
||||||
|
function Y(x: real): real;
|
||||||
|
function ToString: string; override;
|
||||||
|
function Coefficients: (real,real) := (K,B);
|
||||||
|
end;
|
||||||
|
|
||||||
/// Линейная регрессионная модель (метод наименьших квадратов).
|
/// Линейная регрессионная модель (метод наименьших квадратов).
|
||||||
/// Предсказывает числовое значение по линейной комбинации признаков
|
/// Предсказывает числовое значение по линейной комбинации признаков
|
||||||
/// Используется в задачах регрессии при отсутствии выраженной
|
/// Используется в задачах регрессии при отсутствии выраженной
|
||||||
|
|
@ -125,6 +143,9 @@ type
|
||||||
/// • обученное состояние модели НЕ копируется методом Clone
|
/// • обученное состояние модели НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: Vector): IRegressor;
|
function Fit(X: Matrix; y: Vector): IRegressor;
|
||||||
|
|
||||||
|
/// Возвращает числовое предсказание для одного объекта X.
|
||||||
|
function PredictOne(X: Vector): real;
|
||||||
|
|
||||||
/// Предсказывает значения для матрицы признаков
|
/// Предсказывает значения для матрицы признаков
|
||||||
/// Возвращает вектор длины m
|
/// Возвращает вектор длины m
|
||||||
function Predict(X: Matrix): Vector;
|
function Predict(X: Matrix): Vector;
|
||||||
|
|
@ -143,6 +164,10 @@ type
|
||||||
/// После вызова Fit значение становится True.
|
/// После вызова Fit значение становится True.
|
||||||
/// Используется для проверки корректности вызова Predict.
|
/// Используется для проверки корректности вызова Predict.
|
||||||
property IsFitted: boolean read fFitted;
|
property IsFitted: boolean read fFitted;
|
||||||
|
|
||||||
|
/// Возвращает уравнение регрессионной прямой y = k*x + b
|
||||||
|
/// для модели с одним признаком.
|
||||||
|
function RegressionLine: LinearRegressionLine;
|
||||||
|
|
||||||
function ToString: string; override;
|
function ToString: string; override;
|
||||||
|
|
||||||
|
|
@ -179,6 +204,9 @@ type
|
||||||
/// • обученное состояние модели НЕ копируется методом Clone
|
/// • обученное состояние модели НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: Vector): IRegressor;
|
function Fit(X: Matrix; y: Vector): IRegressor;
|
||||||
|
|
||||||
|
/// Возвращает числовое предсказание для одного объекта X.
|
||||||
|
function PredictOne(X: Vector): real;
|
||||||
|
|
||||||
/// Предсказывает непрерывные значения для объектов X.
|
/// Предсказывает непрерывные значения для объектов X.
|
||||||
/// Результат — вектор длины m.
|
/// Результат — вектор длины m.
|
||||||
function Predict(X: Matrix): Vector;
|
function Predict(X: Matrix): Vector;
|
||||||
|
|
@ -248,6 +276,9 @@ type
|
||||||
/// • обученное состояние модели НЕ копируется методом Clone
|
/// • обученное состояние модели НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: Vector): IRegressor;
|
function Fit(X: Matrix; y: Vector): IRegressor;
|
||||||
|
|
||||||
|
/// Возвращает числовое предсказание для одного объекта X.
|
||||||
|
function PredictOne(X: Vector): real;
|
||||||
|
|
||||||
/// Предсказывает непрерывные значения для объектов X.
|
/// Предсказывает непрерывные значения для объектов X.
|
||||||
/// Результат — вектор длины m.
|
/// Результат — вектор длины m.
|
||||||
function Predict(X: Matrix): Vector;
|
function Predict(X: Matrix): Vector;
|
||||||
|
|
@ -307,6 +338,9 @@ type
|
||||||
/// • обученное состояние модели НЕ копируется методом Clone
|
/// • обученное состояние модели НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: Vector): IRegressor;
|
function Fit(X: Matrix; y: Vector): IRegressor;
|
||||||
|
|
||||||
|
/// Возвращает числовое предсказание для одного объекта X.
|
||||||
|
function PredictOne(X: Vector): real;
|
||||||
|
|
||||||
/// Предсказывает значения целевой переменной для входных данных.
|
/// Предсказывает значения целевой переменной для входных данных.
|
||||||
/// X — матрица признаков размера [nSamples x nFeatures].
|
/// X — матрица признаков размера [nSamples x nFeatures].
|
||||||
/// Возвращает вектор предсказаний длины nSamples.
|
/// Возвращает вектор предсказаний длины nSamples.
|
||||||
|
|
@ -383,7 +417,19 @@ type
|
||||||
/// Примечание:
|
/// Примечание:
|
||||||
/// • обученное состояние модели НЕ копируется методом Clone
|
/// • обученное состояние модели НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: array of integer): IClassifier;
|
function Fit(X: Matrix; y: array of integer): IClassifier;
|
||||||
|
|
||||||
|
/// Возвращает метку класса для одного объекта X
|
||||||
|
/// в том же виде, в каком метки были поданы модели при обучении.
|
||||||
|
function PredictOne(X: Vector): integer;
|
||||||
|
|
||||||
|
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
||||||
|
/// Размер результата: nSamples × nClasses, где:
|
||||||
|
/// - nSamples — число объектов в X;
|
||||||
|
/// - nClasses — число классов модели.
|
||||||
|
/// Элемент [i, k] содержит вероятность того, что объект i принадлежит классу k.
|
||||||
|
/// Сумма вероятностей в каждой строке равна 1.
|
||||||
|
function PredictProbaOne(X: Vector): Vector;
|
||||||
|
|
||||||
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
||||||
/// Размер результата: nSamples × nClasses, где:
|
/// Размер результата: nSamples × nClasses, где:
|
||||||
/// - nSamples — число объектов в X;
|
/// - nSamples — число объектов в X;
|
||||||
|
|
@ -416,6 +462,10 @@ type
|
||||||
|
|
||||||
function Name: string := Self.GetType.Name;
|
function Name: string := Self.GetType.Name;
|
||||||
|
|
||||||
|
/// Возвращает коэффициенты разделяющей прямой A*x + B*y + C = 0
|
||||||
|
/// для бинарной задачи с двумя признаками.
|
||||||
|
function DecisionBoundary: LinearDecisionBoundary;
|
||||||
|
|
||||||
procedure SetClassLabels(classes: array of string);
|
procedure SetClassLabels(classes: array of string);
|
||||||
|
|
||||||
function GetClassLabels: array of string;
|
function GetClassLabels: array of string;
|
||||||
|
|
@ -437,6 +487,25 @@ type
|
||||||
/// Создает глубокую копию узла вместе со всеми подузлами
|
/// Создает глубокую копию узла вместе со всеми подузлами
|
||||||
function Clone: DecisionTreeNode;
|
function Clone: DecisionTreeNode;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
/// Представление решающего дерева с именами признаков и классов.
|
||||||
|
/// Используется для печати и последующей визуализации.
|
||||||
|
DecisionTreeView = class
|
||||||
|
private
|
||||||
|
fRoot: DecisionTreeNode;
|
||||||
|
fFeatureNames: array of string;
|
||||||
|
fClassNames: array of string;
|
||||||
|
|
||||||
|
public
|
||||||
|
constructor Create(
|
||||||
|
root: DecisionTreeNode;
|
||||||
|
featureNames: array of string;
|
||||||
|
classNames: array of string
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Возвращает текстовое представление дерева.
|
||||||
|
function ToString: string; override;
|
||||||
|
end;
|
||||||
|
|
||||||
/// Результат поиска лучшего разбиения узла дерева
|
/// Результат поиска лучшего разбиения узла дерева
|
||||||
SplitResult = record
|
SplitResult = record
|
||||||
|
|
@ -584,6 +653,7 @@ type
|
||||||
property FeatureImportances: Vector read GetFeatureImportances;
|
property FeatureImportances: Vector read GetFeatureImportances;
|
||||||
|
|
||||||
function PredictOne(x: Vector; node: DecisionTreeNode): integer;
|
function PredictOne(x: Vector; node: DecisionTreeNode): integer;
|
||||||
|
function RootNode: DecisionTreeNode;
|
||||||
function Clone: DecisionTreeCore;
|
function Clone: DecisionTreeCore;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -629,6 +699,10 @@ type
|
||||||
/// Примечание:
|
/// Примечание:
|
||||||
/// • обученное состояние дерева НЕ копируется методом Clone
|
/// • обученное состояние дерева НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: array of integer): IClassifier;
|
function Fit(X: Matrix; y: array of integer): IClassifier;
|
||||||
|
|
||||||
|
/// Возвращает метку класса для одного объекта X
|
||||||
|
/// в том же виде, в каком метки были поданы модели при обучении.
|
||||||
|
function PredictOne(X: Vector): integer;
|
||||||
|
|
||||||
/// Возвращает метки классов для объектов из X
|
/// Возвращает метки классов для объектов из X
|
||||||
/// в том же виде, в каком они были поданы модели при обучении.
|
/// в том же виде, в каком они были поданы модели при обучении.
|
||||||
|
|
@ -651,6 +725,11 @@ type
|
||||||
procedure SetClassLabels(classes: array of string);
|
procedure SetClassLabels(classes: array of string);
|
||||||
|
|
||||||
function GetClassLabels: array of string;
|
function GetClassLabels: array of string;
|
||||||
|
|
||||||
|
function Tree(
|
||||||
|
featureNames: array of string;
|
||||||
|
classNames: array of string
|
||||||
|
): DecisionTreeView;
|
||||||
|
|
||||||
/// Возвращает true, если дерево обучено.
|
/// Возвращает true, если дерево обучено.
|
||||||
/// Если false — Predict вызовет ошибку.
|
/// Если false — Predict вызовет ошибку.
|
||||||
|
|
@ -795,6 +874,9 @@ type
|
||||||
/// • обученное состояние дерева НЕ копируется методом Clone
|
/// • обученное состояние дерева НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: Vector): IRegressor; override;
|
function Fit(X: Matrix; y: Vector): IRegressor; override;
|
||||||
|
|
||||||
|
/// Возвращает числовое предсказание для одного объекта X.
|
||||||
|
function PredictOne(X: Vector): real;
|
||||||
|
|
||||||
/// Выполняет предсказание для всех объектов X.
|
/// Выполняет предсказание для всех объектов X.
|
||||||
/// Возвращает вектор вещественных значений.
|
/// Возвращает вектор вещественных значений.
|
||||||
function Predict(X: Matrix): Vector; override;
|
function Predict(X: Matrix): Vector; override;
|
||||||
|
|
@ -952,6 +1034,9 @@ type
|
||||||
/// • обученное состояние ансамбля НЕ копируется методом Clone
|
/// • обученное состояние ансамбля НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: Vector): IRegressor;
|
function Fit(X: Matrix; y: Vector): IRegressor;
|
||||||
|
|
||||||
|
/// Возвращает числовое предсказание для одного объекта X.
|
||||||
|
function PredictOne(X: Vector): real;
|
||||||
|
|
||||||
/// Выполняет предсказание для X.
|
/// Выполняет предсказание для X.
|
||||||
/// Итоговое значение — среднее предсказаний всех деревьев ансамбля.
|
/// Итоговое значение — среднее предсказаний всех деревьев ансамбля.
|
||||||
function Predict(X: Matrix): Vector;
|
function Predict(X: Matrix): Vector;
|
||||||
|
|
@ -1005,6 +1090,10 @@ type
|
||||||
/// • обученное состояние ансамбля НЕ копируется методом Clone
|
/// • обученное состояние ансамбля НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: array of integer): IClassifier;
|
function Fit(X: Matrix; y: array of integer): IClassifier;
|
||||||
|
|
||||||
|
/// Возвращает метку класса для одного объекта X
|
||||||
|
/// в том же виде, в каком метки были поданы модели при обучении.
|
||||||
|
function PredictOne(X: Vector): integer;
|
||||||
|
|
||||||
/// Возвращает метки классов для объектов из X
|
/// Возвращает метки классов для объектов из X
|
||||||
/// в том же виде, в каком они были поданы модели при обучении.
|
/// в том же виде, в каком они были поданы модели при обучении.
|
||||||
/// Для каждого объекта агрегируются предсказания всех деревьев.
|
/// Для каждого объекта агрегируются предсказания всех деревьев.
|
||||||
|
|
@ -1016,6 +1105,14 @@ type
|
||||||
/// Требует предварительного вызова Fit.
|
/// Требует предварительного вызова Fit.
|
||||||
function PredictLabels(X: Matrix): array of string;
|
function PredictLabels(X: Matrix): array of string;
|
||||||
|
|
||||||
|
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
||||||
|
/// Размер результата: nSamples × nClasses, где:
|
||||||
|
/// - nSamples — число объектов в X;
|
||||||
|
/// - nClasses — число классов модели.
|
||||||
|
/// Элемент [i, k] содержит вероятность того, что объект i принадлежит классу k.
|
||||||
|
/// Сумма вероятностей в каждой строке равна 1.
|
||||||
|
function PredictProbaOne(X: Vector): Vector;
|
||||||
|
|
||||||
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
||||||
/// Размер результата: nSamples × nClasses, где:
|
/// Размер результата: nSamples × nClasses, где:
|
||||||
/// - nSamples — число объектов в X;
|
/// - nSamples — число объектов в X;
|
||||||
|
|
@ -1175,6 +1272,9 @@ type
|
||||||
/// Примечание:
|
/// Примечание:
|
||||||
/// • обученное состояние модели НЕ копируется методом Clone
|
/// • обученное состояние модели НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: Vector): IRegressor;
|
function Fit(X: Matrix; y: Vector): IRegressor;
|
||||||
|
|
||||||
|
/// Возвращает числовое предсказание для одного объекта X.
|
||||||
|
function PredictOne(X: Vector): real;
|
||||||
|
|
||||||
/// Предсказывает значения целевой переменной.
|
/// Предсказывает значения целевой переменной.
|
||||||
/// Используются все обученные деревья.
|
/// Используются все обученные деревья.
|
||||||
|
|
@ -1325,6 +1425,10 @@ type
|
||||||
/// Примечание:
|
/// Примечание:
|
||||||
/// • обученное состояние модели НЕ копируется методом Clone
|
/// • обученное состояние модели НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: array of integer): IClassifier;
|
function Fit(X: Matrix; y: array of integer): IClassifier;
|
||||||
|
|
||||||
|
/// Возвращает метку класса для одного объекта X
|
||||||
|
/// в том же виде, в каком метки были поданы модели при обучении.
|
||||||
|
function PredictOne(X: Vector): integer;
|
||||||
|
|
||||||
/// Обучает модель градиентного бустинга с использованием валидационной выборки.
|
/// Обучает модель градиентного бустинга с использованием валидационной выборки.
|
||||||
/// Поддерживает early stopping:
|
/// Поддерживает early stopping:
|
||||||
|
|
@ -1339,6 +1443,14 @@ type
|
||||||
/// Возвращает исходные строковые метки классов для объектов из X.
|
/// Возвращает исходные строковые метки классов для объектов из X.
|
||||||
function PredictLabels(X: Matrix): array of string;
|
function PredictLabels(X: Matrix): array of string;
|
||||||
|
|
||||||
|
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
||||||
|
/// Размер результата: nSamples × nClasses, где:
|
||||||
|
/// - nSamples — число объектов в X;
|
||||||
|
/// - nClasses — число классов модели.
|
||||||
|
/// Элемент [i, k] содержит вероятность того, что объект i принадлежит классу k.
|
||||||
|
/// Сумма вероятностей в каждой строке равна 1.
|
||||||
|
function PredictProbaOne(X: Vector): Vector;
|
||||||
|
|
||||||
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
||||||
/// Размер результата: nSamples × nClasses, где:
|
/// Размер результата: nSamples × nClasses, где:
|
||||||
/// - nSamples — число объектов в X;
|
/// - nSamples — число объектов в X;
|
||||||
|
|
@ -1399,6 +1511,11 @@ type
|
||||||
dist: double;
|
dist: double;
|
||||||
idx: integer;
|
idx: integer;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
NeighborInfo = record
|
||||||
|
Index: integer;
|
||||||
|
Distance: real;
|
||||||
|
end;
|
||||||
|
|
||||||
/// Режим взвешивания в алгоритме k ближайших соседей.
|
/// Режим взвешивания в алгоритме k ближайших соседей.
|
||||||
/// Uniform — равномерное голосование/усреднение.
|
/// Uniform — равномерное голосование/усреднение.
|
||||||
|
|
@ -1422,6 +1539,7 @@ type
|
||||||
|
|
||||||
// ==== common methods ====
|
// ==== common methods ====
|
||||||
procedure ValidatePredictInput(X: Matrix);
|
procedure ValidatePredictInput(X: Matrix);
|
||||||
|
procedure FillNeighborDistances(x: Vector);
|
||||||
|
|
||||||
function SquaredL2(trainRow: integer; XTest: Matrix; testRow: integer): double;
|
function SquaredL2(trainRow: integer; XTest: Matrix; testRow: integer): double;
|
||||||
|
|
||||||
|
|
@ -1433,6 +1551,11 @@ type
|
||||||
/// k — число ближайших соседей (k > 0).
|
/// k — число ближайших соседей (k > 0).
|
||||||
/// weighting — режим взвешивания соседей
|
/// weighting — режим взвешивания соседей
|
||||||
constructor Create(k: integer; weighting: KNNWeighting := KNNWeighting.Uniform);
|
constructor Create(k: integer; weighting: KNNWeighting := KNNWeighting.Uniform);
|
||||||
|
|
||||||
|
/// Возвращает k ближайших обучающих объектов
|
||||||
|
/// для одного объекта X.
|
||||||
|
/// Индекс относится к обучающей выборке, переданной в Fit.
|
||||||
|
function GetNearestNeighbors(X: Vector): array of NeighborInfo;
|
||||||
|
|
||||||
/// Обучает модель k ближайших соседей.
|
/// Обучает модель k ближайших соседей.
|
||||||
/// X — матрица m × n (m объектов, n признаков).
|
/// X — матрица m × n (m объектов, n признаков).
|
||||||
|
|
@ -1482,6 +1605,10 @@ type
|
||||||
/// Примечание:
|
/// Примечание:
|
||||||
/// • обученное состояние модели (обучающая выборка) НЕ копируется методом Clone
|
/// • обученное состояние модели (обучающая выборка) НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: array of integer): IClassifier;
|
function Fit(X: Matrix; y: array of integer): IClassifier;
|
||||||
|
|
||||||
|
/// Возвращает метку класса для одного объекта X
|
||||||
|
/// в том же виде, в каком метки были поданы модели при обучении.
|
||||||
|
function PredictOne(X: Vector): integer;
|
||||||
|
|
||||||
/// Возвращает метки классов для объектов из X
|
/// Возвращает метки классов для объектов из X
|
||||||
/// в том же виде, в каком они были поданы модели при обучении.
|
/// в том же виде, в каком они были поданы модели при обучении.
|
||||||
|
|
@ -1494,6 +1621,14 @@ type
|
||||||
/// для одного экземпляра модели.
|
/// для одного экземпляра модели.
|
||||||
function PredictLabels(X: Matrix): array of string;
|
function PredictLabels(X: Matrix): array of string;
|
||||||
|
|
||||||
|
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
||||||
|
/// Размер результата: nSamples × nClasses, где:
|
||||||
|
/// - nSamples — число объектов в X;
|
||||||
|
/// - nClasses — число классов модели.
|
||||||
|
/// Элемент [i, k] содержит вероятность того, что объект i принадлежит классу k.
|
||||||
|
/// Сумма вероятностей в каждой строке равна 1.
|
||||||
|
function PredictProbaOne(X: Vector): Vector;
|
||||||
|
|
||||||
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
/// Возвращает матрицу вероятностей классов для всех объектов из X.
|
||||||
/// Размер результата: nSamples × nClasses, где:
|
/// Размер результата: nSamples × nClasses, где:
|
||||||
/// - nSamples — число объектов в X;
|
/// - nSamples — число объектов в X;
|
||||||
|
|
@ -1536,6 +1671,9 @@ type
|
||||||
/// Примечание:
|
/// Примечание:
|
||||||
/// • обученное состояние модели (обучающая выборка) НЕ копируется методом Clone
|
/// • обученное состояние модели (обучающая выборка) НЕ копируется методом Clone
|
||||||
function Fit(X: Matrix; y: Vector): IRegressor;
|
function Fit(X: Matrix; y: Vector): IRegressor;
|
||||||
|
|
||||||
|
/// Возвращает числовое предсказание для одного объекта X.
|
||||||
|
function PredictOne(X: Vector): real;
|
||||||
|
|
||||||
/// Выполняет предсказание числовых значений для объектов X.
|
/// Выполняет предсказание числовых значений для объектов X.
|
||||||
/// Возвращает вектор предсказанных значений
|
/// Возвращает вектор предсказанных значений
|
||||||
|
|
@ -1840,11 +1978,15 @@ type
|
||||||
ClassificationMatrixPipeline = class(MatrixPipeline, IProbabilisticClassifier, IClassifierInternal)
|
ClassificationMatrixPipeline = class(MatrixPipeline, IProbabilisticClassifier, IClassifierInternal)
|
||||||
public
|
public
|
||||||
function Fit(X: Matrix; y: array of integer): IClassifier;
|
function Fit(X: Matrix; y: array of integer): IClassifier;
|
||||||
|
/// Возвращает метку класса для одного объекта X
|
||||||
|
/// в том же виде, в каком метки были поданы модели при обучении.
|
||||||
|
function PredictOne(X: Vector): integer;
|
||||||
/// Возвращает метки классов для объектов из X
|
/// Возвращает метки классов для объектов из X
|
||||||
/// в том же виде, в каком они были поданы модели при обучении.
|
/// в том же виде, в каком они были поданы модели при обучении.
|
||||||
function Predict(X: Matrix): array of integer; reintroduce;
|
function Predict(X: Matrix): array of integer; reintroduce;
|
||||||
/// Возвращает строковые метки классов для объектов из X.
|
/// Возвращает строковые метки классов для объектов из X.
|
||||||
function PredictLabels(X: Matrix): array of string;
|
function PredictLabels(X: Matrix): array of string;
|
||||||
|
function PredictProbaOne(X: Vector): Vector;
|
||||||
function PredictProba(X: Matrix): Matrix; reintroduce;
|
function PredictProba(X: Matrix): Matrix; reintroduce;
|
||||||
procedure SetClassLabels(classes: array of string);
|
procedure SetClassLabels(classes: array of string);
|
||||||
function GetClassLabels: array of string;
|
function GetClassLabels: array of string;
|
||||||
|
|
@ -1853,6 +1995,8 @@ type
|
||||||
RegressionMatrixPipeline = class(MatrixPipeline, IRegressor)
|
RegressionMatrixPipeline = class(MatrixPipeline, IRegressor)
|
||||||
public
|
public
|
||||||
function Fit(X: Matrix; y: Vector): IRegressor; reintroduce;
|
function Fit(X: Matrix; y: Vector): IRegressor; reintroduce;
|
||||||
|
/// Возвращает числовое предсказание для одного объекта X.
|
||||||
|
function PredictOne(X: Vector): real;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
/// Общая база для матричных конвейеров без учителя.
|
/// Общая база для матричных конвейеров без учителя.
|
||||||
|
|
@ -2413,6 +2557,18 @@ const
|
||||||
ER_LOGISTIC_NEED_AT_LEAST_TWO_CLASSES =
|
ER_LOGISTIC_NEED_AT_LEAST_TWO_CLASSES =
|
||||||
'Для LogisticRegression нужно минимум 2 класса.!!' +
|
'Для LogisticRegression нужно минимум 2 класса.!!' +
|
||||||
'LogisticRegression requires at least 2 classes.';
|
'LogisticRegression requires at least 2 classes.';
|
||||||
|
ER_LOGISTIC_BOUNDARY_NEEDS_BINARY =
|
||||||
|
'DecisionBoundary доступен только для бинарной LogisticRegression.!!' +
|
||||||
|
'DecisionBoundary is available only for binary LogisticRegression.';
|
||||||
|
ER_LOGISTIC_BOUNDARY_NEEDS_2D =
|
||||||
|
'DecisionBoundary требует ровно 2 признака.!!' +
|
||||||
|
'DecisionBoundary requires exactly 2 features.';
|
||||||
|
ER_LINEAR_REGRESSION_LINE_NEEDS_1D =
|
||||||
|
'RegressionLine требует ровно 1 признак.!!' +
|
||||||
|
'RegressionLine requires exactly 1 feature.';
|
||||||
|
ER_DECISION_BOUNDARY_DEGENERATE =
|
||||||
|
'Разделяющая прямая вырождена: A и B равны нулю.!!' +
|
||||||
|
'Decision boundary is degenerate: A and B are zero.';
|
||||||
ER_MIN_SAMPLES_SPLIT_INVALID =
|
ER_MIN_SAMPLES_SPLIT_INVALID =
|
||||||
'minSamplesSplit должно быть >= 2 ({0}).!!' +
|
'minSamplesSplit должно быть >= 2 ({0}).!!' +
|
||||||
'minSamplesSplit must be >= 2 ({0}).';
|
'minSamplesSplit must be >= 2 ({0}).';
|
||||||
|
|
@ -2481,6 +2637,17 @@ const
|
||||||
// Проверка на NuN/Inf
|
// Проверка на NuN/Inf
|
||||||
//-----------------------------
|
//-----------------------------
|
||||||
|
|
||||||
|
function SingleRowMatrix(X: Vector): Matrix;
|
||||||
|
begin
|
||||||
|
if X = nil then
|
||||||
|
ArgumentNullError(ER_X_NULL);
|
||||||
|
|
||||||
|
Result := new Matrix(1, X.Length);
|
||||||
|
|
||||||
|
for var j := 0 to X.Length - 1 do
|
||||||
|
Result[0, j] := X[j];
|
||||||
|
end;
|
||||||
|
|
||||||
procedure ClassifierLabelHelper.SetClassValues(values: array of integer);
|
procedure ClassifierLabelHelper.SetClassValues(values: array of integer);
|
||||||
begin
|
begin
|
||||||
fClassValues := Copy(values);
|
fClassValues := Copy(values);
|
||||||
|
|
@ -2685,6 +2852,11 @@ begin
|
||||||
Result := X * fcoef + fIntercept;
|
Result := X * fcoef + fIntercept;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function LinearRegression.PredictOne(X: Vector): real;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function LinearRegression.ToString: string;
|
function LinearRegression.ToString: string;
|
||||||
begin
|
begin
|
||||||
Result := 'LinearRegression'
|
Result := 'LinearRegression'
|
||||||
|
|
@ -2811,6 +2983,11 @@ begin
|
||||||
Result[i] += fIntercept;
|
Result[i] += fIntercept;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function RidgeRegression.PredictOne(X: Vector): real;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function RidgeRegression.ToString: string;
|
function RidgeRegression.ToString: string;
|
||||||
begin
|
begin
|
||||||
Result := 'RidgeRegression(lambda=' + fLambda + ')';
|
Result := 'RidgeRegression(lambda=' + fLambda + ')';
|
||||||
|
|
@ -2994,6 +3171,11 @@ begin
|
||||||
Result[i] += fIntercept;
|
Result[i] += fIntercept;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function ElasticNet.PredictOne(X: Vector): real;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function ElasticNet.ToString: string;
|
function ElasticNet.ToString: string;
|
||||||
begin
|
begin
|
||||||
Result :=
|
Result :=
|
||||||
|
|
@ -3033,6 +3215,11 @@ begin
|
||||||
Result := fModel.Predict(X);
|
Result := fModel.Predict(X);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function LassoRegression.PredictOne(X: Vector): real;
|
||||||
|
begin
|
||||||
|
Result := fModel.PredictOne(X);
|
||||||
|
end;
|
||||||
|
|
||||||
function LassoRegression.Clone: IModel;
|
function LassoRegression.Clone: IModel;
|
||||||
begin
|
begin
|
||||||
Result := new LassoRegression(fAlpha, fMaxIter, fTol);
|
Result := new LassoRegression(fAlpha, fMaxIter, fTol);
|
||||||
|
|
@ -3520,6 +3707,11 @@ begin
|
||||||
Result := Z;
|
Result := Z;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function LogisticRegression.PredictProbaOne(X: Vector): Vector;
|
||||||
|
begin
|
||||||
|
Result := PredictProba(SingleRowMatrix(X)).GetRow(0);
|
||||||
|
end;
|
||||||
|
|
||||||
function LogisticRegression.Predict(X: Matrix): array of integer;
|
function LogisticRegression.Predict(X: Matrix): array of integer;
|
||||||
begin
|
begin
|
||||||
if not fFitted then
|
if not fFitted then
|
||||||
|
|
@ -3558,6 +3750,11 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function LogisticRegression.PredictOne(X: Vector): integer;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function LogisticRegression.PredictLabels(X: Matrix): array of string;
|
function LogisticRegression.PredictLabels(X: Matrix): array of string;
|
||||||
begin
|
begin
|
||||||
var pred := Predict(X);
|
var pred := Predict(X);
|
||||||
|
|
@ -3621,6 +3818,138 @@ begin
|
||||||
Result := fIntercept;
|
Result := fIntercept;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function LinearDecisionBoundary.Evaluate(x, y: real): real;
|
||||||
|
begin
|
||||||
|
Result := A * x + B * y + C;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LinearDecisionBoundary.Y(x: real): real;
|
||||||
|
begin
|
||||||
|
if Abs(B) < 1e-12 then
|
||||||
|
Result := real.PositiveInfinity
|
||||||
|
else
|
||||||
|
Result := -(A * x + C) / B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LinearDecisionBoundary.Side(x, y: real): integer;
|
||||||
|
begin
|
||||||
|
var v := Evaluate(x, y);
|
||||||
|
if Abs(v) < 1e-12 then
|
||||||
|
Result := 0
|
||||||
|
else if v < 0 then
|
||||||
|
Result := -1
|
||||||
|
else
|
||||||
|
Result := 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LinearDecisionBoundary.Distance(x, y: real): real;
|
||||||
|
begin
|
||||||
|
var denom := Sqrt(A * A + B * B);
|
||||||
|
if denom < 1e-12 then
|
||||||
|
Error(ER_DECISION_BOUNDARY_DEGENERATE);
|
||||||
|
Result := Abs(Evaluate(x, y)) / denom;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LinearDecisionBoundary.ToString: string;
|
||||||
|
function FormatCoeff(v: real): string;
|
||||||
|
begin
|
||||||
|
if Abs(v - Round(v)) < 1e-12 then
|
||||||
|
Result := Round(v).ToString
|
||||||
|
else
|
||||||
|
Result := v.ToString('0.##');
|
||||||
|
end;
|
||||||
|
function FmtSigned(v: real; suffix: string): string;
|
||||||
|
begin
|
||||||
|
if Abs(v) < 1e-12 then
|
||||||
|
exit('');
|
||||||
|
|
||||||
|
var mag := FormatCoeff(Abs(v));
|
||||||
|
if suffix <> '' then
|
||||||
|
mag += '*' + suffix;
|
||||||
|
|
||||||
|
if v < 0 then
|
||||||
|
Result := ' - ' + mag
|
||||||
|
else
|
||||||
|
Result := ' + ' + mag;
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
|
||||||
|
if Abs(A) >= 1e-12 then
|
||||||
|
Result := FormatCoeff(A) + '*x';
|
||||||
|
|
||||||
|
Result += FmtSigned(B, 'y');
|
||||||
|
Result += FmtSigned(C, '');
|
||||||
|
|
||||||
|
if Result = '' then
|
||||||
|
Result := '0';
|
||||||
|
|
||||||
|
if Result.StartsWith(' + ') then
|
||||||
|
Result := Result.Substring(3);
|
||||||
|
if Result.StartsWith(' - ') then
|
||||||
|
Result := '-' + Result.Substring(3);
|
||||||
|
|
||||||
|
Result += ' = 0';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LinearRegressionLine.Evaluate(x: real): real;
|
||||||
|
begin
|
||||||
|
Result := K * x + B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LinearRegressionLine.Y(x: real): real;
|
||||||
|
begin
|
||||||
|
Result := Evaluate(x);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LinearRegressionLine.ToString: string;
|
||||||
|
function FormatCoeff(v: real): string;
|
||||||
|
begin
|
||||||
|
if Abs(v - Round(v)) < 1e-12 then
|
||||||
|
Result := Round(v).ToString
|
||||||
|
else
|
||||||
|
Result := v.ToString('0.##');
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
Result := FormatCoeff(K) + '*x';
|
||||||
|
|
||||||
|
if B > 1e-12 then
|
||||||
|
Result += ' + ' + FormatCoeff(B)
|
||||||
|
else if B < -1e-12 then
|
||||||
|
Result += ' - ' + FormatCoeff(Abs(B));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LinearRegression.RegressionLine: LinearRegressionLine;
|
||||||
|
begin
|
||||||
|
if not fFitted then
|
||||||
|
NotFittedError(ER_FIT_NOT_CALLED);
|
||||||
|
|
||||||
|
if (fCoef = nil) or (fCoef.Length <> 1) then
|
||||||
|
ArgumentError(ER_LINEAR_REGRESSION_LINE_NEEDS_1D);
|
||||||
|
|
||||||
|
Result.K := fCoef[0];
|
||||||
|
Result.B := fIntercept;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LogisticRegression.DecisionBoundary: LinearDecisionBoundary;
|
||||||
|
begin
|
||||||
|
if not fFitted then
|
||||||
|
NotFittedError(ER_FIT_NOT_CALLED);
|
||||||
|
|
||||||
|
if fClassCount <> 2 then
|
||||||
|
ArgumentError(ER_LOGISTIC_BOUNDARY_NEEDS_BINARY);
|
||||||
|
|
||||||
|
if fW.RowCount <> 2 then
|
||||||
|
ArgumentError(ER_LOGISTIC_BOUNDARY_NEEDS_2D);
|
||||||
|
|
||||||
|
Result.A := fW[0,0] - fW[0,1];
|
||||||
|
Result.B := fW[1,0] - fW[1,1];
|
||||||
|
Result.C := fIntercept[0] - fIntercept[1];
|
||||||
|
|
||||||
|
if (Abs(Result.A) < 1e-12) and (Abs(Result.B) < 1e-12) then
|
||||||
|
Error(ER_DECISION_BOUNDARY_DEGENERATE);
|
||||||
|
end;
|
||||||
|
|
||||||
function GiniCriterion.Impurity(y: Vector; indices: array of integer): real;
|
function GiniCriterion.Impurity(y: Vector; indices: array of integer): real;
|
||||||
begin
|
begin
|
||||||
var n := indices.Length;
|
var n := indices.Length;
|
||||||
|
|
@ -3756,6 +4085,116 @@ begin
|
||||||
Result := n;
|
Result := n;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
constructor DecisionTreeView.Create(
|
||||||
|
root: DecisionTreeNode;
|
||||||
|
featureNames: array of string;
|
||||||
|
classNames: array of string
|
||||||
|
);
|
||||||
|
begin
|
||||||
|
if root <> nil then
|
||||||
|
fRoot := root.Clone;
|
||||||
|
fFeatureNames := Copy(featureNames);
|
||||||
|
fClassNames := Copy(classNames);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function DecisionTreeView.ToString: string;
|
||||||
|
function FormatReal(v: real): string;
|
||||||
|
begin
|
||||||
|
if Abs(v - Round(v)) < 1e-12 then
|
||||||
|
Result := Round(v).ToString
|
||||||
|
else
|
||||||
|
Result := v.ToString('0.##');
|
||||||
|
end;
|
||||||
|
|
||||||
|
function FeatureNameOf(idx: integer): string;
|
||||||
|
begin
|
||||||
|
if (idx >= 0) and (idx < fFeatureNames.Length) and (fFeatureNames[idx] <> nil) and (fFeatureNames[idx] <> '') then
|
||||||
|
Result := fFeatureNames[idx]
|
||||||
|
else
|
||||||
|
Result := 'x' + idx;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ClassNameOf(idx: integer): string;
|
||||||
|
begin
|
||||||
|
if (idx >= 0) and (idx < fClassNames.Length) then
|
||||||
|
Result := fClassNames[idx]
|
||||||
|
else
|
||||||
|
Result := idx.ToString;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LeafText(node: DecisionTreeNode): string;
|
||||||
|
begin
|
||||||
|
if node = nil then
|
||||||
|
exit('nil');
|
||||||
|
|
||||||
|
if fClassNames <> nil then
|
||||||
|
Result := ClassNameOf(Round(node.LeafValue))
|
||||||
|
else
|
||||||
|
Result := FormatReal(node.LeafValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure AppendBranch(sb: System.Text.StringBuilder; node: DecisionTreeNode;
|
||||||
|
prefix: string; isLast: boolean; branchMark: string);
|
||||||
|
begin
|
||||||
|
sb.Append(prefix);
|
||||||
|
|
||||||
|
if isLast then
|
||||||
|
sb.Append('└── ')
|
||||||
|
else
|
||||||
|
sb.Append('├── ');
|
||||||
|
|
||||||
|
if node = nil then
|
||||||
|
begin
|
||||||
|
sb.Append(branchMark + ' → nil');
|
||||||
|
sb.AppendLine;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if node.IsLeaf then
|
||||||
|
begin
|
||||||
|
sb.Append(branchMark + ' → ' + LeafText(node));
|
||||||
|
sb.AppendLine;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
sb.Append(branchMark + ' ');
|
||||||
|
sb.AppendLine;
|
||||||
|
|
||||||
|
var childPrefix := prefix;
|
||||||
|
if isLast then
|
||||||
|
childPrefix += ' '
|
||||||
|
else
|
||||||
|
childPrefix += '│ ';
|
||||||
|
|
||||||
|
sb.Append(childPrefix);
|
||||||
|
sb.Append(FeatureNameOf(node.FeatureIndex));
|
||||||
|
sb.Append(' ≤ ');
|
||||||
|
sb.Append(FormatReal(node.Threshold));
|
||||||
|
sb.Append('?');
|
||||||
|
sb.AppendLine;
|
||||||
|
|
||||||
|
AppendBranch(sb, node.Left, childPrefix, false, '✓');
|
||||||
|
AppendBranch(sb, node.Right, childPrefix, true, '✗');
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
if fRoot = nil then
|
||||||
|
exit('DecisionTreeView(empty)');
|
||||||
|
|
||||||
|
if fRoot.IsLeaf then
|
||||||
|
exit('→ ' + LeafText(fRoot));
|
||||||
|
|
||||||
|
var sb := new System.Text.StringBuilder;
|
||||||
|
sb.Append(FeatureNameOf(fRoot.FeatureIndex));
|
||||||
|
sb.Append(' ≤ ');
|
||||||
|
sb.Append(FormatReal(fRoot.Threshold));
|
||||||
|
sb.Append('?');
|
||||||
|
sb.AppendLine;
|
||||||
|
|
||||||
|
AppendBranch(sb, fRoot.Left, '', false, '✓');
|
||||||
|
AppendBranch(sb, fRoot.Right, '', true, '✗');
|
||||||
|
Result := sb.ToString.TrimEnd;
|
||||||
|
end;
|
||||||
|
|
||||||
const MAX_ALLOWED_TREE_DEPTH = 1000;
|
const MAX_ALLOWED_TREE_DEPTH = 1000;
|
||||||
|
|
||||||
// DecisionTreeCore
|
// DecisionTreeCore
|
||||||
|
|
@ -3852,6 +4291,13 @@ begin
|
||||||
Result := PredictOne(x, node.Right);
|
Result := PredictOne(x, node.Right);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function DecisionTreeCore.RootNode: DecisionTreeNode;
|
||||||
|
begin
|
||||||
|
if fRoot = nil then
|
||||||
|
NotFittedError(ER_FIT_NOT_CALLED);
|
||||||
|
Result := fRoot.Clone;
|
||||||
|
end;
|
||||||
|
|
||||||
function DecisionTreeCore.MajorityClass(y: Vector; indices: array of integer): integer;
|
function DecisionTreeCore.MajorityClass(y: Vector; indices: array of integer): integer;
|
||||||
begin
|
begin
|
||||||
var counts := new integer[fClassCount];
|
var counts := new integer[fClassCount];
|
||||||
|
|
@ -4816,6 +5262,11 @@ begin
|
||||||
Result := fLabels.DecodePredictions(fCore.Predict(X));
|
Result := fLabels.DecodePredictions(fCore.Predict(X));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function DecisionTreeClassifier.PredictOne(X: Vector): integer;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function DecisionTreeClassifier.PredictLabels(X: Matrix): array of string;
|
function DecisionTreeClassifier.PredictLabels(X: Matrix): array of string;
|
||||||
begin
|
begin
|
||||||
if fLabels = nil then
|
if fLabels = nil then
|
||||||
|
|
@ -4841,6 +5292,21 @@ begin
|
||||||
Result := fLabels.GetClassLabels;
|
Result := fLabels.GetClassLabels;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function DecisionTreeClassifier.Tree(
|
||||||
|
featureNames: array of string;
|
||||||
|
classNames: array of string
|
||||||
|
): DecisionTreeView;
|
||||||
|
begin
|
||||||
|
if not fFitted then
|
||||||
|
NotFittedError(ER_FIT_NOT_CALLED);
|
||||||
|
|
||||||
|
Result := new DecisionTreeView(
|
||||||
|
fCore.RootNode,
|
||||||
|
featureNames,
|
||||||
|
classNames
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
function DecisionTreeClassifier.Clone: IModel;
|
function DecisionTreeClassifier.Clone: IModel;
|
||||||
begin
|
begin
|
||||||
Result := new DecisionTreeClassifier(
|
Result := new DecisionTreeClassifier(
|
||||||
|
|
@ -5017,6 +5483,11 @@ begin
|
||||||
Result[i] := PredictOne(X, i);
|
Result[i] := PredictOne(X, i);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function DecisionTreeRegressor.PredictOne(X: Vector): real;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function DecisionTreeRegressor.Clone: IModel;
|
function DecisionTreeRegressor.Clone: IModel;
|
||||||
begin
|
begin
|
||||||
Result := new DecisionTreeRegressor(
|
Result := new DecisionTreeRegressor(
|
||||||
|
|
@ -5278,6 +5749,11 @@ begin
|
||||||
Result := resultVec;
|
Result := resultVec;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function RandomForestRegressor.PredictOne(X: Vector): real;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function RandomForestRegressor.Clone: IModel;
|
function RandomForestRegressor.Clone: IModel;
|
||||||
begin
|
begin
|
||||||
Result := new RandomForestRegressor(
|
Result := new RandomForestRegressor(
|
||||||
|
|
@ -5593,6 +6069,11 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function RandomForestClassifier.PredictProbaOne(X: Vector): Vector;
|
||||||
|
begin
|
||||||
|
Result := PredictProba(SingleRowMatrix(X)).GetRow(0);
|
||||||
|
end;
|
||||||
|
|
||||||
function RandomForestClassifier.Clone: IModel;
|
function RandomForestClassifier.Clone: IModel;
|
||||||
begin
|
begin
|
||||||
Result := new RandomForestClassifier(
|
Result := new RandomForestClassifier(
|
||||||
|
|
@ -6239,6 +6720,11 @@ begin
|
||||||
Result := yPred;
|
Result := yPred;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function GradientBoostingRegressor.PredictOne(X: Vector): real;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function GradientBoostingRegressor.PredictStage(X: Matrix; m: integer): Vector;
|
function GradientBoostingRegressor.PredictStage(X: Matrix; m: integer): Vector;
|
||||||
begin
|
begin
|
||||||
if not fFitted then
|
if not fFitted then
|
||||||
|
|
@ -7062,6 +7548,11 @@ begin
|
||||||
Result := probs;
|
Result := probs;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function GradientBoostingClassifier.PredictProbaOne(X: Vector): Vector;
|
||||||
|
begin
|
||||||
|
Result := PredictProba(SingleRowMatrix(X)).GetRow(0);
|
||||||
|
end;
|
||||||
|
|
||||||
function GradientBoostingClassifier.PredictStageProba(
|
function GradientBoostingClassifier.PredictStageProba(
|
||||||
X: Matrix; m: integer): Matrix;
|
X: Matrix; m: integer): Matrix;
|
||||||
begin
|
begin
|
||||||
|
|
@ -7231,6 +7722,11 @@ begin
|
||||||
Result[i] := fLabels.ClassValueAt(probs.RowArgMax(i));
|
Result[i] := fLabels.ClassValueAt(probs.RowArgMax(i));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function GradientBoostingClassifier.PredictOne(X: Vector): integer;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function GradientBoostingClassifier.PredictLabels(X: Matrix): array of string;
|
function GradientBoostingClassifier.PredictLabels(X: Matrix): array of string;
|
||||||
begin
|
begin
|
||||||
var pred := Predict(X);
|
var pred := Predict(X);
|
||||||
|
|
@ -7271,6 +7767,25 @@ begin
|
||||||
fFitted := False;
|
fFitted := False;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function KNNBase.GetNearestNeighbors(X: Vector): array of NeighborInfo;
|
||||||
|
begin
|
||||||
|
FillNeighborDistances(X);
|
||||||
|
QuickSelect(fK - 1);
|
||||||
|
|
||||||
|
var resList := new List<NeighborInfo>;
|
||||||
|
|
||||||
|
for var i := 0 to fK - 1 do
|
||||||
|
begin
|
||||||
|
var item: NeighborInfo;
|
||||||
|
item.Index := fNeighbors[i].idx;
|
||||||
|
item.Distance := Sqrt(fNeighbors[i].dist);
|
||||||
|
resList.Add(item);
|
||||||
|
end;
|
||||||
|
|
||||||
|
resList.Sort((a, b) -> a.Distance.CompareTo(b.Distance));
|
||||||
|
Result := resList.ToArray;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure KNNBase.ValidatePredictInput(X: Matrix);
|
procedure KNNBase.ValidatePredictInput(X: Matrix);
|
||||||
begin
|
begin
|
||||||
if X = nil then
|
if X = nil then
|
||||||
|
|
@ -7283,6 +7798,37 @@ begin
|
||||||
DimensionError(ER_FEATURE_COUNT_MISMATCH,X.ColCount,fXTrain.ColCount);
|
DimensionError(ER_FEATURE_COUNT_MISMATCH,X.ColCount,fXTrain.ColCount);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure KNNBase.FillNeighborDistances(x: Vector);
|
||||||
|
begin
|
||||||
|
if x = nil then
|
||||||
|
ArgumentNullError(ER_X_NULL);
|
||||||
|
|
||||||
|
if not fFitted then
|
||||||
|
NotFittedError(ER_FIT_NOT_CALLED);
|
||||||
|
|
||||||
|
if x.Length <> fXTrain.ColCount then
|
||||||
|
DimensionError(ER_FEATURE_COUNT_MISMATCH, x.Length, fXTrain.ColCount);
|
||||||
|
|
||||||
|
var n := fXTrain.RowCount;
|
||||||
|
var p := fXTrain.ColCount;
|
||||||
|
var trainRows := fXTrain.Data.Rows;
|
||||||
|
|
||||||
|
for var t := 0 to n - 1 do
|
||||||
|
begin
|
||||||
|
var rowTrain := trainRows[t];
|
||||||
|
var sum := 0.0;
|
||||||
|
|
||||||
|
for var j := 0 to p - 1 do
|
||||||
|
begin
|
||||||
|
var diff := rowTrain[j] - x[j];
|
||||||
|
sum += diff * diff;
|
||||||
|
end;
|
||||||
|
|
||||||
|
fNeighbors[t].dist := sum;
|
||||||
|
fNeighbors[t].idx := t;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function KNNBase.SquaredL2(trainRow: integer; XTest: Matrix; testRow: integer): double;
|
function KNNBase.SquaredL2(trainRow: integer; XTest: Matrix; testRow: integer): double;
|
||||||
begin
|
begin
|
||||||
var sum := 0.0;
|
var sum := 0.0;
|
||||||
|
|
@ -7307,16 +7853,14 @@ begin
|
||||||
var left := 0;
|
var left := 0;
|
||||||
var right := fNeighbors.Length - 1;
|
var right := fNeighbors.Length - 1;
|
||||||
|
|
||||||
while true do
|
while left < right do
|
||||||
begin
|
begin
|
||||||
var pivotIndex := Partition(left, right);
|
var p := Partition(left, right);
|
||||||
|
|
||||||
if pivotIndex = k then
|
if k <= p then
|
||||||
exit
|
right := p
|
||||||
else if pivotIndex > k then
|
|
||||||
right := pivotIndex - 1
|
|
||||||
else
|
else
|
||||||
left := pivotIndex + 1;
|
left := p + 1;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -7656,6 +8200,16 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function KNNClassifier.PredictOne(X: Vector): integer;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function RandomForestClassifier.PredictOne(X: Vector): integer;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function KNNClassifier.PredictLabels(X: Matrix): array of string;
|
function KNNClassifier.PredictLabels(X: Matrix): array of string;
|
||||||
begin
|
begin
|
||||||
var pred := Predict(X);
|
var pred := Predict(X);
|
||||||
|
|
@ -7808,6 +8362,11 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function KNNClassifier.PredictProbaOne(X: Vector): Vector;
|
||||||
|
begin
|
||||||
|
Result := PredictProba(SingleRowMatrix(X)).GetRow(0);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure KNNClassifier.SetClassLabels(classes: array of string);
|
procedure KNNClassifier.SetClassLabels(classes: array of string);
|
||||||
begin
|
begin
|
||||||
if fLabels = nil then
|
if fLabels = nil then
|
||||||
|
|
@ -7959,6 +8518,11 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function KNNRegressor.PredictOne(X: Vector): real;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function KNNRegressor.Clone: IModel;
|
function KNNRegressor.Clone: IModel;
|
||||||
begin
|
begin
|
||||||
Result := new KNNRegressor(fK, fWeighting);
|
Result := new KNNRegressor(fK, fWeighting);
|
||||||
|
|
@ -8722,6 +9286,11 @@ begin
|
||||||
Result := Self;
|
Result := Self;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function RegressionMatrixPipeline.PredictOne(X: Vector): real;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function ClassificationMatrixPipeline.Predict(X: Matrix): array of integer;
|
function ClassificationMatrixPipeline.Predict(X: Matrix): array of integer;
|
||||||
begin
|
begin
|
||||||
if not fFitted then
|
if not fFitted then
|
||||||
|
|
@ -8737,6 +9306,11 @@ begin
|
||||||
Result := (fModel as IClassifier).Predict(Xt);
|
Result := (fModel as IClassifier).Predict(Xt);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function ClassificationMatrixPipeline.PredictOne(X: Vector): integer;
|
||||||
|
begin
|
||||||
|
Result := Predict(SingleRowMatrix(X))[0];
|
||||||
|
end;
|
||||||
|
|
||||||
function ClassificationMatrixPipeline.PredictLabels(X: Matrix): array of string;
|
function ClassificationMatrixPipeline.PredictLabels(X: Matrix): array of string;
|
||||||
begin
|
begin
|
||||||
if not fFitted then
|
if not fFitted then
|
||||||
|
|
@ -8767,6 +9341,11 @@ begin
|
||||||
Result := (fModel as IProbabilisticClassifier).PredictProba(Xt);
|
Result := (fModel as IProbabilisticClassifier).PredictProba(Xt);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function ClassificationMatrixPipeline.PredictProbaOne(X: Vector): Vector;
|
||||||
|
begin
|
||||||
|
Result := PredictProba(SingleRowMatrix(X)).GetRow(0);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure ClassificationMatrixPipeline.SetClassLabels(classes: array of string);
|
procedure ClassificationMatrixPipeline.SetClassLabels(classes: array of string);
|
||||||
begin
|
begin
|
||||||
if (fModel = nil) or not (fModel is IClassifierInternal) then
|
if (fModel = nil) or not (fModel is IClassifierInternal) then
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ type
|
||||||
/// Доля правильных предсказаний.
|
/// Доля правильных предсказаний.
|
||||||
/// Показывает, какая часть объектов классифицирована верно.
|
/// Показывает, какая часть объектов классифицирована верно.
|
||||||
/// Удобна, когда классы примерно сбалансированы.
|
/// Удобна, когда классы примерно сбалансированы.
|
||||||
/// Пример: Accuracy = 0.9 означает 90% правильных ответов.
|
/// Пример: Accuracy = 0.9 означает 90% правильных ответов
|
||||||
static function Accuracy(yTrue, yPred: array of integer): real;
|
static function Accuracy(yTrue, yPred: array of integer): real;
|
||||||
|
|
||||||
/// Точность (Precision) для положительного класса (1).
|
/// Точность (Precision) для положительного класса (1).
|
||||||
|
|
@ -228,6 +228,7 @@ type
|
||||||
fClassCount: integer;
|
fClassCount: integer;
|
||||||
|
|
||||||
fLabels: array of integer;
|
fLabels: array of integer;
|
||||||
|
fClassNames: array of string;
|
||||||
fLabelToIndex: Dictionary<integer, integer>;
|
fLabelToIndex: Dictionary<integer, integer>;
|
||||||
|
|
||||||
procedure EnsureBinary;
|
procedure EnsureBinary;
|
||||||
|
|
@ -254,6 +255,10 @@ type
|
||||||
///
|
///
|
||||||
/// Для бинарной классификации дополнительно доступны значения TP, TN, FP и FN
|
/// Для бинарной классификации дополнительно доступны значения TP, TN, FP и FN
|
||||||
constructor Create(yTrue, yPred: array of integer);
|
constructor Create(yTrue, yPred: array of integer);
|
||||||
|
|
||||||
|
/// Создаёт матрицу ошибок и сохраняет отображаемые имена классов.
|
||||||
|
/// classNames[i] соответствует классу fLabels[i].
|
||||||
|
constructor Create(yTrue, yPred: array of integer; classNames: array of string);
|
||||||
|
|
||||||
/// Возвращает исходную метку класса по его внутреннему номеру.
|
/// Возвращает исходную метку класса по его внутреннему номеру.
|
||||||
///
|
///
|
||||||
|
|
@ -263,6 +268,10 @@ type
|
||||||
/// Метод позволяет узнать, какой исходной метке соответствует
|
/// Метод позволяет узнать, какой исходной метке соответствует
|
||||||
/// данный внутренний номер.
|
/// данный внутренний номер.
|
||||||
function GetLabel(c: integer): integer;
|
function GetLabel(c: integer): integer;
|
||||||
|
|
||||||
|
/// Возвращает отображаемое имя класса по его внутреннему номеру.
|
||||||
|
/// Если строковые имена не заданы, возвращает исходную числовую метку как строку.
|
||||||
|
function GetClassDisplayName(i: integer): string;
|
||||||
|
|
||||||
/// Возвращает внутренний номер класса по его исходной метке.
|
/// Возвращает внутренний номер класса по его исходной метке.
|
||||||
///
|
///
|
||||||
|
|
@ -400,6 +409,12 @@ type
|
||||||
/// Применима для многоклассовой классификации.
|
/// Применима для многоклассовой классификации.
|
||||||
function F1ForClass(c: integer): real;
|
function F1ForClass(c: integer): real;
|
||||||
|
|
||||||
|
/// Возвращает текстовое представление матрицы ошибок.
|
||||||
|
function ToString: string; override;
|
||||||
|
|
||||||
|
/// Печатает матрицу ошибок.
|
||||||
|
procedure Println;
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
/// Метрики для оценки качества классификационных моделей.
|
/// Метрики для оценки качества классификационных моделей.
|
||||||
|
|
@ -616,7 +631,9 @@ const
|
||||||
ER_INVALID_PROBABILITY =
|
ER_INVALID_PROBABILITY =
|
||||||
'Вероятность вне диапазона [0,1]: {0}!!Probability out of range [0,1]: {0}';
|
'Вероятность вне диапазона [0,1]: {0}!!Probability out of range [0,1]: {0}';
|
||||||
ER_ARG_OUT_OF_RANGE =
|
ER_ARG_OUT_OF_RANGE =
|
||||||
'Аргумент {0} имеет недопустимое значение: {1}!!Argument {0} is out of range: {1}';
|
'Аргумент {0} имеет недопустимое значение: {1}!!Argument {0} is out of range: {1}';
|
||||||
|
ER_CLASS_NAMES_LENGTH_MISMATCH =
|
||||||
|
'Число имён классов ({0}) не совпадает с числом классов ({1})!!Class names count ({0}) does not match class count ({1})';
|
||||||
|
|
||||||
//-----------------------------
|
//-----------------------------
|
||||||
// Metrics
|
// Metrics
|
||||||
|
|
@ -1718,7 +1735,7 @@ begin
|
||||||
// --- собираем строки классов
|
// --- собираем строки классов
|
||||||
for var c := 0 to cm.ClassCount - 1 do
|
for var c := 0 to cm.ClassCount - 1 do
|
||||||
begin
|
begin
|
||||||
var cls := cm.GetLabel(c).ToString;
|
var cls := cm.GetClassDisplayName(c);
|
||||||
|
|
||||||
var p := cm.PrecisionForClass(c);
|
var p := cm.PrecisionForClass(c);
|
||||||
var r := cm.RecallForClass(c);
|
var r := cm.RecallForClass(c);
|
||||||
|
|
@ -1875,6 +1892,19 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
constructor ConfusionMatrix.Create(yTrue, yPred: array of integer; classNames: array of string);
|
||||||
|
begin
|
||||||
|
Create(yTrue, yPred);
|
||||||
|
|
||||||
|
if classNames = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
if classNames.Length <> fClassCount then
|
||||||
|
ArgumentError(ER_CLASS_NAMES_LENGTH_MISMATCH, classNames.Length, fClassCount);
|
||||||
|
|
||||||
|
fClassNames := Copy(classNames);
|
||||||
|
end;
|
||||||
|
|
||||||
function ConfusionMatrix.GetMatrix: array[,] of integer;
|
function ConfusionMatrix.GetMatrix: array[,] of integer;
|
||||||
begin
|
begin
|
||||||
Result := new integer[fClassCount, fClassCount];
|
Result := new integer[fClassCount, fClassCount];
|
||||||
|
|
@ -1892,6 +1922,16 @@ begin
|
||||||
Result := fLabels[c];
|
Result := fLabels[c];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function ConfusionMatrix.GetClassDisplayName(i: integer): string;
|
||||||
|
begin
|
||||||
|
EnsureClassIndex(i);
|
||||||
|
|
||||||
|
if (fClassNames <> nil) and (i < fClassNames.Length) then
|
||||||
|
Result := fClassNames[i]
|
||||||
|
else
|
||||||
|
Result := fLabels[i].ToString;
|
||||||
|
end;
|
||||||
|
|
||||||
function ConfusionMatrix.GetIndex(labl: integer): integer;
|
function ConfusionMatrix.GetIndex(labl: integer): integer;
|
||||||
begin
|
begin
|
||||||
if labl not in fLabelToIndex then
|
if labl not in fLabelToIndex then
|
||||||
|
|
@ -2074,4 +2114,78 @@ begin
|
||||||
Result := 2 * p * r / (p + r);
|
Result := 2 * p * r / (p + r);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function ConfusionMatrix.ToString: string;
|
||||||
|
function Center(s: string; w: integer): string;
|
||||||
|
begin
|
||||||
|
if s.Length >= w then
|
||||||
|
exit(s);
|
||||||
|
|
||||||
|
var left := (w - s.Length) div 2;
|
||||||
|
var right := w - s.Length - left;
|
||||||
|
Result := new string(' ', left) + s + new string(' ', right);
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
var names := new string[fClassCount];
|
||||||
|
var rowHeader := 'Реально ↓';
|
||||||
|
var topHeader := 'Предсказано →';
|
||||||
|
var nameWidth := rowHeader.Length;
|
||||||
|
|
||||||
|
for var i := 0 to fClassCount - 1 do
|
||||||
|
begin
|
||||||
|
names[i] := GetClassDisplayName(i);
|
||||||
|
if names[i].Length > nameWidth then
|
||||||
|
nameWidth := names[i].Length;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var cellWidth := 1;
|
||||||
|
for var i := 0 to fClassCount - 1 do
|
||||||
|
for var j := 0 to fClassCount - 1 do
|
||||||
|
if fMatrix[i, j].ToString.Length > cellWidth then
|
||||||
|
cellWidth := fMatrix[i, j].ToString.Length;
|
||||||
|
|
||||||
|
for var i := 0 to fClassCount - 1 do
|
||||||
|
if names[i].Length > cellWidth then
|
||||||
|
cellWidth := names[i].Length;
|
||||||
|
|
||||||
|
var leftPad := nameWidth + 3;
|
||||||
|
var firstColStart := leftPad;
|
||||||
|
|
||||||
|
var sb := new System.Text.StringBuilder;
|
||||||
|
|
||||||
|
sb.Append(new string(' ', firstColStart));
|
||||||
|
sb.AppendLine(topHeader);
|
||||||
|
|
||||||
|
sb.Append(rowHeader.PadRight(nameWidth));
|
||||||
|
sb.Append(' ');
|
||||||
|
for var j := 0 to fClassCount - 1 do
|
||||||
|
begin
|
||||||
|
if j > 0 then
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(Center(names[j], cellWidth));
|
||||||
|
end;
|
||||||
|
sb.AppendLine;
|
||||||
|
|
||||||
|
for var i := 0 to fClassCount - 1 do
|
||||||
|
begin
|
||||||
|
sb.Append(names[i].PadRight(nameWidth));
|
||||||
|
sb.Append(' ');
|
||||||
|
|
||||||
|
for var j := 0 to fClassCount - 1 do
|
||||||
|
begin
|
||||||
|
if j > 0 then
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(Center(fMatrix[i, j].ToString, cellWidth));
|
||||||
|
end;
|
||||||
|
|
||||||
|
sb.AppendLine;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := sb.ToString.TrimEnd;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ConfusionMatrix.Println;
|
||||||
|
begin
|
||||||
|
System.Console.WriteLine(ToString);
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,16 @@ type
|
||||||
public
|
public
|
||||||
constructor Create(g: GridWPF; r,c: integer);
|
constructor Create(g: GridWPF; r,c: integer);
|
||||||
|
|
||||||
|
function PaletteColor(i: integer): ColorWPF;
|
||||||
|
|
||||||
procedure LineGraph(x, y: array of real; color: ColorWPF := DefaultColor;
|
procedure LineGraph(x, y: array of real; color: ColorWPF := DefaultColor;
|
||||||
thickness: real := 2; legend: string := nil);
|
thickness: real := 2; legend: string := nil);
|
||||||
|
procedure Line(k, b: real; color: ColorWPF := DefaultColor;
|
||||||
|
thickness: real := 2; legend: string := nil);
|
||||||
|
procedure Line(A, B, C: real; color: ColorWPF := DefaultColor;
|
||||||
|
thickness: real := 2; legend: string := nil);
|
||||||
|
procedure Point(x, y: real; color: ColorWPF := DefaultColor;
|
||||||
|
size: real := 8; marker: MarkerType := MarkerType.Circle; legend: string := nil);
|
||||||
procedure Points(x, y: array of real; color: ColorWPF := DefaultColor;
|
procedure Points(x, y: array of real; color: ColorWPF := DefaultColor;
|
||||||
size: real := 6; marker: MarkerType := MarkerType.Circle; legend: string := nil);
|
size: real := 6; marker: MarkerType := MarkerType.Circle; legend: string := nil);
|
||||||
procedure Points(x, y: array of real; labels: array of integer;
|
procedure Points(x, y: array of real; labels: array of integer;
|
||||||
|
|
@ -173,6 +181,8 @@ type
|
||||||
|
|
||||||
static procedure DrawLine(chart: ChartWPF; x, y: array of real;
|
static procedure DrawLine(chart: ChartWPF; x, y: array of real;
|
||||||
color: ColorWPF; thickness: real; legend: string);
|
color: ColorWPF; thickness: real; legend: string);
|
||||||
|
static procedure DrawImplicitLine(chart: ChartWPF; A, B, C: real;
|
||||||
|
color: ColorWPF; thickness: real; legend: string);
|
||||||
|
|
||||||
static procedure DrawText(chart: ChartWPF; s: string; x, y: real);
|
static procedure DrawText(chart: ChartWPF; s: string; x, y: real);
|
||||||
|
|
||||||
|
|
@ -207,8 +217,16 @@ type
|
||||||
public
|
public
|
||||||
static procedure AddSeries(chart: ChartWPF; series: UIElement);
|
static procedure AddSeries(chart: ChartWPF; series: UIElement);
|
||||||
|
|
||||||
|
static function PaletteColor(i: integer): ColorWPF;
|
||||||
|
|
||||||
static procedure LineGraph(x, y: array of real;
|
static procedure LineGraph(x, y: array of real;
|
||||||
color: ColorWPF := DefaultColor; thickness: real := 2; legend: string := nil);
|
color: ColorWPF := DefaultColor; thickness: real := 2; legend: string := nil);
|
||||||
|
static procedure Line(k, b: real;
|
||||||
|
color: ColorWPF := DefaultColor; thickness: real := 2; legend: string := nil);
|
||||||
|
static procedure Line(A, B, C: real;
|
||||||
|
color: ColorWPF := DefaultColor; thickness: real := 2; legend: string := nil);
|
||||||
|
static procedure Point(x, y: real;
|
||||||
|
color: ColorWPF := DefaultColor; size: real := 8; marker: MarkerType := MarkerType.Circle; legend: string := nil);
|
||||||
|
|
||||||
static procedure Points(x, y: array of real;
|
static procedure Points(x, y: array of real;
|
||||||
color: ColorWPF := DefaultColor; size: real := 6; marker: MarkerType := MarkerType.Circle; legend: string := nil);
|
color: ColorWPF := DefaultColor; size: real := 6; marker: MarkerType := MarkerType.Circle; legend: string := nil);
|
||||||
|
|
@ -335,6 +353,24 @@ type
|
||||||
property MaxCount: integer read fMaxCount;
|
property MaxCount: integer read fMaxCount;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
ImplicitLinePlot = class(PlotWPF)
|
||||||
|
private
|
||||||
|
fA, fB, fC: real;
|
||||||
|
fStroke: BrushWPF;
|
||||||
|
fStrokeThickness: real;
|
||||||
|
fDescription: string;
|
||||||
|
|
||||||
|
function IsFinite(x: real): boolean;
|
||||||
|
procedure OnPlotTransformChanged(sender: object; e: EventArgs);
|
||||||
|
protected
|
||||||
|
function ComputeBounds: InteractiveDataDisplay.WPF.DataRect; override;
|
||||||
|
procedure OnRender(dc: DrawingContext); override;
|
||||||
|
public
|
||||||
|
constructor Create(A, B, C: real; color: ColorWPF; thickness: real);
|
||||||
|
|
||||||
|
property Description: string read fDescription write fDescription;
|
||||||
|
end;
|
||||||
|
|
||||||
HorizontalBarPlot = class(PlotWPF)
|
HorizontalBarPlot = class(PlotWPF)
|
||||||
private
|
private
|
||||||
fElements: List<UIElement> := new List<UIElement>;
|
fElements: List<UIElement> := new List<UIElement>;
|
||||||
|
|
@ -493,6 +529,19 @@ begin
|
||||||
Result := c;
|
Result := c;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function ColorFromPalette(p: PaletteWPF; i: integer): ColorWPF;
|
||||||
|
begin
|
||||||
|
if (p = nil) or (p.Colors = nil) or (p.Colors.Length = 0) then
|
||||||
|
exit(Colors.Black);
|
||||||
|
|
||||||
|
var n := p.Colors.Length;
|
||||||
|
var k := i mod n;
|
||||||
|
if k < 0 then
|
||||||
|
k += n;
|
||||||
|
|
||||||
|
Result := p.Colors[k];
|
||||||
|
end;
|
||||||
|
|
||||||
function Clamp01(x: real): real;
|
function Clamp01(x: real): real;
|
||||||
begin
|
begin
|
||||||
if x < 0 then
|
if x < 0 then
|
||||||
|
|
@ -950,6 +999,11 @@ begin
|
||||||
Result := c;
|
Result := c;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function Cell.PaletteColor(i: integer): ColorWPF;
|
||||||
|
begin
|
||||||
|
Result := ColorFromPalette(palette, i);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure Cell.SetPalette(p: PaletteWPF);
|
procedure Cell.SetPalette(p: PaletteWPF);
|
||||||
begin
|
begin
|
||||||
if p = nil then exit;
|
if p = nil then exit;
|
||||||
|
|
@ -1108,6 +1162,29 @@ begin
|
||||||
end);
|
end);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure Cell.Line(k, b: real; color: ColorWPF; thickness: real; legend: string);
|
||||||
|
begin
|
||||||
|
Line(k, -1, b, color, thickness, legend);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Cell.Line(A, B, C: real; color: ColorWPF; thickness: real; legend: string);
|
||||||
|
begin
|
||||||
|
Plot.RunUI(() ->
|
||||||
|
begin
|
||||||
|
EnsureChart;
|
||||||
|
|
||||||
|
var clr := if color<>DefaultColor then color else Colors.Red;
|
||||||
|
|
||||||
|
Plot.DrawImplicitLine(chart, A, B, C, clr, thickness, legend);
|
||||||
|
end);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Cell.Point(x, y: real; color: ColorWPF; size: real; marker: MarkerType; legend: string);
|
||||||
|
begin
|
||||||
|
var clr := if color<>DefaultColor then color else Colors.Black;
|
||||||
|
Points(Arr(x), Arr(y), clr, size, marker, legend);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure Cell.Points(x, y: array of real; color: ColorWPF;
|
procedure Cell.Points(x, y: array of real; color: ColorWPF;
|
||||||
size: real; marker: MarkerType; legend: string);
|
size: real; marker: MarkerType; legend: string);
|
||||||
begin
|
begin
|
||||||
|
|
@ -1631,6 +1708,20 @@ begin
|
||||||
AddSeries(chart, g);
|
AddSeries(chart, g);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
static procedure Plot.DrawImplicitLine(chart: ChartWPF; A, B, C: real;
|
||||||
|
color: ColorWPF; thickness: real; legend: string);
|
||||||
|
begin
|
||||||
|
var g := new ImplicitLinePlot(A, B, C, color, thickness);
|
||||||
|
|
||||||
|
if legend <> nil then
|
||||||
|
begin
|
||||||
|
g.Description := legend;
|
||||||
|
chart.LegendVisibility := Visibility.Visible;
|
||||||
|
end;
|
||||||
|
|
||||||
|
AddSeries(chart, g);
|
||||||
|
end;
|
||||||
|
|
||||||
static procedure Plot.DrawText(chart: ChartWPF; s: string; x, y: real);
|
static procedure Plot.DrawText(chart: ChartWPF; s: string; x, y: real);
|
||||||
begin
|
begin
|
||||||
var tb := new System.Windows.Controls.TextBlock;
|
var tb := new System.Windows.Controls.TextBlock;
|
||||||
|
|
@ -1987,6 +2078,11 @@ begin
|
||||||
container.Children.Add(series);
|
container.Children.Add(series);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function Plot.PaletteColor(i: integer): ColorWPF;
|
||||||
|
begin
|
||||||
|
Result := ColorFromPalette(currentPalette, i);
|
||||||
|
end;
|
||||||
|
|
||||||
class procedure Plot.LineGraph(x, y: array of real;
|
class procedure Plot.LineGraph(x, y: array of real;
|
||||||
color: ColorWPF; thickness: real; legend: string);
|
color: ColorWPF; thickness: real; legend: string);
|
||||||
begin
|
begin
|
||||||
|
|
@ -1998,6 +2094,27 @@ begin
|
||||||
end);
|
end);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class procedure Plot.Line(k, b: real; color: ColorWPF; thickness: real; legend: string);
|
||||||
|
begin
|
||||||
|
Line(k, -1, b, color, thickness, legend);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class procedure Plot.Line(A, B, C: real; color: ColorWPF; thickness: real; legend: string);
|
||||||
|
begin
|
||||||
|
RunUI(() ->
|
||||||
|
begin
|
||||||
|
var clr := if color<>DefaultColor then color else Colors.Red;
|
||||||
|
|
||||||
|
DrawImplicitLine(rootChart, A, B, C, clr, thickness, legend);
|
||||||
|
end);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class procedure Plot.Point(x, y: real; color: ColorWPF; size: real; marker: MarkerType; legend: string);
|
||||||
|
begin
|
||||||
|
var clr := if color<>DefaultColor then color else Colors.Black;
|
||||||
|
Points(Arr(x), Arr(y), clr, size, marker, legend);
|
||||||
|
end;
|
||||||
|
|
||||||
static procedure Plot.Points(x, y: array of real;
|
static procedure Plot.Points(x, y: array of real;
|
||||||
color: ColorWPF; size: real; marker: MarkerType; legend: string);
|
color: ColorWPF; size: real; marker: MarkerType; legend: string);
|
||||||
begin
|
begin
|
||||||
|
|
@ -2722,6 +2839,94 @@ begin
|
||||||
fMaxCount := counts.Max;
|
fMaxCount := counts.Max;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
constructor ImplicitLinePlot.Create(A, B, C: real; color: ColorWPF; thickness: real);
|
||||||
|
begin
|
||||||
|
fA := A;
|
||||||
|
fB := B;
|
||||||
|
fC := C;
|
||||||
|
fStroke := new SolidColorBrush(color);
|
||||||
|
fStrokeThickness := thickness;
|
||||||
|
IsAutoFitEnabled := false;
|
||||||
|
PlotTransformChanged += OnPlotTransformChanged;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ImplicitLinePlot.IsFinite(x: real): boolean;
|
||||||
|
begin
|
||||||
|
Result := not real.IsNaN(x) and not real.IsInfinity(x);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ImplicitLinePlot.OnPlotTransformChanged(sender: object; e: EventArgs);
|
||||||
|
begin
|
||||||
|
InvalidateVisual;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ImplicitLinePlot.ComputeBounds: InteractiveDataDisplay.WPF.DataRect;
|
||||||
|
begin
|
||||||
|
Result := InteractiveDataDisplay.WPF.DataRect.Empty;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ImplicitLinePlot.OnRender(dc: DrawingContext);
|
||||||
|
begin
|
||||||
|
inherited OnRender(dc);
|
||||||
|
|
||||||
|
if (Abs(fA) < 1e-12) and (Abs(fB) < 1e-12) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
var r := ActualPlotRect;
|
||||||
|
if r.IsEmpty then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
var xmin := r.XMin;
|
||||||
|
var xmax := r.XMax;
|
||||||
|
var ymin := r.YMin;
|
||||||
|
var ymax := r.YMax;
|
||||||
|
|
||||||
|
var pts := new List<Point>;
|
||||||
|
|
||||||
|
if Abs(fB) > 1e-12 then
|
||||||
|
begin
|
||||||
|
var y := (-fA * xmin - fC) / fB;
|
||||||
|
if IsFinite(y) and (y >= ymin - 1e-9) and (y <= ymax + 1e-9) then
|
||||||
|
pts.Add(new Point(xmin, y));
|
||||||
|
|
||||||
|
y := (-fA * xmax - fC) / fB;
|
||||||
|
if IsFinite(y) and (y >= ymin - 1e-9) and (y <= ymax + 1e-9) then
|
||||||
|
pts.Add(new Point(xmax, y));
|
||||||
|
end;
|
||||||
|
|
||||||
|
if Abs(fA) > 1e-12 then
|
||||||
|
begin
|
||||||
|
var x := (-fB * ymin - fC) / fA;
|
||||||
|
if IsFinite(x) and (x >= xmin - 1e-9) and (x <= xmax + 1e-9) then
|
||||||
|
pts.Add(new Point(x, ymin));
|
||||||
|
|
||||||
|
x := (-fB * ymax - fC) / fA;
|
||||||
|
if IsFinite(x) and (x >= xmin - 1e-9) and (x <= xmax + 1e-9) then
|
||||||
|
pts.Add(new Point(x, ymax));
|
||||||
|
end;
|
||||||
|
|
||||||
|
if pts.Count < 2 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
var p1 := pts[0];
|
||||||
|
var p2 := pts[1];
|
||||||
|
|
||||||
|
for var i := 1 to pts.Count - 1 do
|
||||||
|
if Abs(pts[i].X - p1.X) + Abs(pts[i].Y - p1.Y) > 1e-9 then
|
||||||
|
begin
|
||||||
|
p2 := pts[i];
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if Abs(p2.X - p1.X) + Abs(p2.Y - p1.Y) <= 1e-9 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
var s1 := new Point(LeftFromX(p1.X), TopFromY(p1.Y));
|
||||||
|
var s2 := new Point(LeftFromX(p2.X), TopFromY(p2.Y));
|
||||||
|
|
||||||
|
dc.DrawLine(new Pen(fStroke, fStrokeThickness), s1, s2);
|
||||||
|
end;
|
||||||
|
|
||||||
constructor HorizontalBarPlot.Create;
|
constructor HorizontalBarPlot.Create;
|
||||||
begin
|
begin
|
||||||
IsAutoFitEnabled := false;
|
IsAutoFitEnabled := false;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue