Много добавок в ML
This commit is contained in:
parent
d4e56ead6c
commit
95a1e58952
|
|
@ -5,7 +5,6 @@ interface
|
|||
type
|
||||
Vector = class
|
||||
private
|
||||
|
||||
static procedure CheckSameLength(const a, b: Vector);
|
||||
static procedure CheckNonEmpty(const v: Vector);
|
||||
procedure SetData(i: integer; value: real) := data[i] := value;
|
||||
|
|
@ -93,7 +92,25 @@ type
|
|||
function ColumnMins: Vector;
|
||||
function ColumnMaxs: Vector;
|
||||
function RowMins: Vector;
|
||||
function RowMaxs: Vector;
|
||||
function RowMaxs: Vector;
|
||||
|
||||
function RowSum(i: integer): real;
|
||||
function RowMean(i: integer): real;
|
||||
function RowVariance(i: integer): real;
|
||||
function RowStd(i: integer): real;
|
||||
function RowMin(i: integer): real;
|
||||
function RowMax(i: integer): real;
|
||||
function RowArgMin(i: integer): integer;
|
||||
function RowArgMax(i: integer): integer;
|
||||
|
||||
function ColumnSum(j: integer): real;
|
||||
function ColumnMean(j: integer): real;
|
||||
function ColumnVariance(j: integer): real;
|
||||
function ColumnStd(j: integer): real;
|
||||
function ColumnMin(j: integer): real;
|
||||
function ColumnMax(j: integer): real;
|
||||
function ColumnArgMin(j: integer): integer;
|
||||
function ColumnArgMax(j: integer): integer;
|
||||
|
||||
function FrobeniusNorm: real;
|
||||
procedure AddScaledIdentity(lambda: real);
|
||||
|
|
@ -561,6 +578,154 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function Matrix.RowArgMin(i: integer): integer;
|
||||
begin
|
||||
var minVal := data[i,0];
|
||||
var arg := 0;
|
||||
|
||||
for var j := 1 to ColCount - 1 do
|
||||
if data[i,j] < minVal then
|
||||
begin
|
||||
minVal := data[i,j];
|
||||
arg := j;
|
||||
end;
|
||||
|
||||
Result := arg;
|
||||
end;
|
||||
|
||||
function Matrix.RowMin(i: integer): real;
|
||||
begin
|
||||
Result := data[i, RowArgMin(i)];
|
||||
end;
|
||||
|
||||
function Matrix.RowArgMax(i: integer): integer;
|
||||
begin
|
||||
var maxVal := data[i,0];
|
||||
var arg := 0;
|
||||
|
||||
for var j := 1 to ColCount - 1 do
|
||||
if data[i,j] > maxVal then
|
||||
begin
|
||||
maxVal := data[i,j];
|
||||
arg := j;
|
||||
end;
|
||||
|
||||
Result := arg;
|
||||
end;
|
||||
|
||||
function Matrix.RowMax(i: integer): real;
|
||||
begin
|
||||
Result := data[i, RowArgMax(i)];
|
||||
end;
|
||||
|
||||
function Matrix.RowSum(i: integer): real;
|
||||
begin
|
||||
var sum := 0.0;
|
||||
|
||||
for var j := 0 to ColCount - 1 do
|
||||
sum += data[i,j];
|
||||
|
||||
Result := sum;
|
||||
end;
|
||||
|
||||
function Matrix.RowMean(i: integer): real;
|
||||
begin
|
||||
Result := RowSum(i) / ColCount;
|
||||
end;
|
||||
|
||||
function Matrix.RowVariance(i: integer): real;
|
||||
begin
|
||||
var mean := RowMean(i);
|
||||
var sum := 0.0;
|
||||
|
||||
for var j := 0 to ColCount - 1 do
|
||||
begin
|
||||
var d := data[i,j] - mean;
|
||||
sum += d * d;
|
||||
end;
|
||||
|
||||
Result := sum / ColCount;
|
||||
end;
|
||||
|
||||
function Matrix.RowStd(i: integer): real;
|
||||
begin
|
||||
Result := Sqrt(RowVariance(i));
|
||||
end;
|
||||
|
||||
function Matrix.ColumnArgMin(j: integer): integer;
|
||||
begin
|
||||
var minVal := data[0,j];
|
||||
var arg := 0;
|
||||
|
||||
for var i := 1 to RowCount - 1 do
|
||||
if data[i,j] < minVal then
|
||||
begin
|
||||
minVal := data[i,j];
|
||||
arg := i;
|
||||
end;
|
||||
|
||||
Result := arg;
|
||||
end;
|
||||
|
||||
function Matrix.ColumnMin(j: integer): real;
|
||||
begin
|
||||
Result := data[ColumnArgMin(j), j];
|
||||
end;
|
||||
|
||||
function Matrix.ColumnArgMax(j: integer): integer;
|
||||
begin
|
||||
var maxVal := data[0,j];
|
||||
var arg := 0;
|
||||
|
||||
for var i := 1 to RowCount - 1 do
|
||||
if data[i,j] > maxVal then
|
||||
begin
|
||||
maxVal := data[i,j];
|
||||
arg := i;
|
||||
end;
|
||||
|
||||
Result := arg;
|
||||
end;
|
||||
|
||||
function Matrix.ColumnMax(j: integer): real;
|
||||
begin
|
||||
Result := data[ColumnArgMax(j), j];
|
||||
end;
|
||||
|
||||
function Matrix.ColumnSum(j: integer): real;
|
||||
begin
|
||||
var sum := 0.0;
|
||||
|
||||
for var i := 0 to RowCount - 1 do
|
||||
sum += data[i,j];
|
||||
|
||||
Result := sum;
|
||||
end;
|
||||
|
||||
function Matrix.ColumnMean(j: integer): real;
|
||||
begin
|
||||
Result := ColumnSum(j) / RowCount;
|
||||
end;
|
||||
|
||||
function Matrix.ColumnVariance(j: integer): real;
|
||||
begin
|
||||
var mean := ColumnMean(j);
|
||||
var sum := 0.0;
|
||||
|
||||
for var i := 0 to RowCount - 1 do
|
||||
begin
|
||||
var d := data[i,j] - mean;
|
||||
sum += d * d;
|
||||
end;
|
||||
|
||||
Result := sum / RowCount;
|
||||
end;
|
||||
|
||||
function Matrix.ColumnStd(j: integer): real;
|
||||
begin
|
||||
Result := Sqrt(ColumnVariance(j));
|
||||
end;
|
||||
|
||||
|
||||
function Matrix.FrobeniusNorm: real;
|
||||
begin
|
||||
|
|
|
|||
|
|
@ -24,13 +24,20 @@ type
|
|||
CsvLoader = DataFrameABC.CsvLoader;
|
||||
|
||||
StandardScaler = MLModelsABC.StandardScaler;
|
||||
PCATransformer = MLModelsABC.PCATransformer;
|
||||
MinMaxScaler = MLModelsABC.MinMaxScaler;
|
||||
VarianceThreshold = MLModelsABC.VarianceThreshold;
|
||||
SelectKBest = MLModelsABC.SelectKBest;
|
||||
FeatureScore = MLModelsABC.FeatureScore;
|
||||
|
||||
Activations = MLModelsABC.Activations;
|
||||
Pipeline = MLModelsABC.Pipeline;
|
||||
|
||||
LinearRegression = MLModelsABC.LinearRegression;
|
||||
LogisticRegression = MLModelsABC.LogisticRegression;
|
||||
RidgeRegression = MLModelsABC.RidgeRegression;
|
||||
ElasticNet = ElasticNet;
|
||||
ElasticNet = MLModelsABC.ElasticNet;
|
||||
MulticlassLogisticRegression = MLModelsABC.MulticlassLogisticRegression;
|
||||
|
||||
implementation
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,17 @@ type
|
|||
function Transform(X: Matrix): Matrix;
|
||||
end;
|
||||
|
||||
/// Интерфейс преобразования признаков с учётом целевой переменной.
|
||||
/// Используется для методов отбора признаков и других процедур,
|
||||
/// в которых при обучении требуется вектор целевых значений.
|
||||
ISupervisedTransformer = interface(ITransformer)
|
||||
/// Обучает преобразование на данных с использованием
|
||||
/// как признаков X, так и целевой переменной y.
|
||||
/// Запоминает необходимые параметры,
|
||||
/// которые будут использоваться при Transform.
|
||||
function Fit(X: Matrix; y: Vector): ISupervisedTransformer;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
||||
|
|
@ -234,34 +234,80 @@ type
|
|||
/// Показывает, была ли модель обучена.
|
||||
/// После вызова Fit значение становится true.
|
||||
property IsFitted: boolean read fFitted;
|
||||
end;
|
||||
|
||||
/// Многоклассовая логистическая регрессия (Softmax).
|
||||
/// Предсказывает вероятности принадлежности к каждому классу
|
||||
/// на основе линейной комбинации признаков и softmax-функции.
|
||||
/// Использует кросс-энтропийную функцию потерь.
|
||||
/// Поддерживает L2-регуляризацию.
|
||||
MulticlassLogisticRegression = class(IProbabilisticClassifier)
|
||||
private
|
||||
fW: Matrix; // p x k
|
||||
fIntercept: Vector; // k
|
||||
fLambda: real;
|
||||
fLearningRate: real;
|
||||
fEpochs: integer;
|
||||
fFitted: boolean;
|
||||
fClassCount: integer;
|
||||
public
|
||||
/// lambda — коэффициент L2-регуляризации.
|
||||
/// lr — шаг градиентного спуска.
|
||||
/// epochs — число итераций обучения.
|
||||
constructor Create(lambda: real := 0.0; lr: real := 0.1; epochs: integer := 1000);
|
||||
|
||||
function Fit(X: Matrix; y: Vector): IModel;
|
||||
|
||||
function PredictProba(X: Matrix): Vector;
|
||||
|
||||
/// Возвращает матрицу вероятностей (m x k).
|
||||
function PredictProbaMatrix(X: Matrix): Matrix;
|
||||
|
||||
/// Возвращает вектор предсказанных классов.
|
||||
function Predict(X: Matrix): Vector;
|
||||
|
||||
property IsFitted: boolean read fFitted;
|
||||
end;
|
||||
|
||||
|
||||
{$endregion Models}
|
||||
|
||||
{$region Pipeline}
|
||||
/// Конвейер машинного обучения (Pipeline).
|
||||
/// Объединяет несколько шагов подготовки данных и модель
|
||||
/// в единую последовательность обработки.
|
||||
/// Сначала данные проходят через все преобразования,
|
||||
/// затем итоговые признаки передаются в модель.
|
||||
/// Обеспечивает единый интерфейс Fit / Predict.
|
||||
/// Последовательный конвейер машинного обучения.
|
||||
/// Гарантирует строгий порядок выполнения шагов:
|
||||
/// [преобразователи] → [модель].
|
||||
///
|
||||
/// Поддерживает:
|
||||
/// - преобразователи без учёта целевой переменной;
|
||||
/// - преобразователи с учётом целевой переменной;
|
||||
/// - одну финальную модель.
|
||||
///
|
||||
/// Обеспечивает единый интерфейс Fit / Predict
|
||||
/// и воспроизводимость полного процесса обучения.
|
||||
Pipeline = class(IModel)
|
||||
private
|
||||
fTransformers: List<ITransformer>;
|
||||
fModel: IModel;
|
||||
fFitted: boolean;
|
||||
public
|
||||
/// Создаёт пайплайн (конвейер машинного обучения) для заданной модели.
|
||||
/// model — финальная модель (регрессор или классификатор),
|
||||
/// которая будет обучаться после всех преобразований.
|
||||
/// Создаёт конвейер машинного обучения для заданной модели.
|
||||
/// model — модель, которая будет обучена
|
||||
/// после последовательного применения всех преобразователей.
|
||||
constructor Create(model: IModel);
|
||||
|
||||
/// Создаёт пустой пайплайн (конвейер машинного обучения).
|
||||
/// Модель должна быть установлена через SetModel.
|
||||
constructor Create;
|
||||
|
||||
/// Строит пайплайн (конвейер машинного обучения).
|
||||
/// model — финальная модель, которая будет обучаться.
|
||||
/// transformers — последовательность преобразований признаков,
|
||||
/// применяемых к данным перед обучением модели.
|
||||
/// Возвращает настроенный конвейер.
|
||||
/// Строит конвейер машинного обучения.
|
||||
/// model — модель, обучаемая после применения всех преобразователей.
|
||||
/// transformers — последовательность преобразователей признаков,
|
||||
/// применяемых к данным перед обучением модели.
|
||||
/// Возвращает сконструированный конвейер.
|
||||
static function Build(model: IModel; params transformers: array of ITransformer): Pipeline;
|
||||
|
||||
/// Устанавливает или заменяет модель.
|
||||
function SetModel(m: IModel): Pipeline;
|
||||
|
||||
/// Добавляет преобразование в конец пайплайна
|
||||
function Add(t: ITransformer): Pipeline;
|
||||
|
|
@ -342,6 +388,163 @@ type
|
|||
/// Признак того, что преобразование обучено.
|
||||
property IsFitted: boolean read fFitted;
|
||||
end;
|
||||
|
||||
/// Трансформер главных компонент (PCA).
|
||||
/// Выполняет уменьшение размерности путём проекции данных
|
||||
/// на первые k главных компонент.
|
||||
/// На этапе Fit вычисляет главные компоненты ковариационной матрицы.
|
||||
/// На этапе Transform проецирует данные:
|
||||
/// Z = (X - μ) · W
|
||||
PCATransformer = class(ITransformer)
|
||||
private
|
||||
fK: integer;
|
||||
fComponents: Matrix; // W
|
||||
fMean: Vector; // μ
|
||||
fFitted: boolean;
|
||||
public
|
||||
/// Создаёт PCA-трансформер.
|
||||
/// k — число главных компонент (k > 0).
|
||||
constructor Create(k: integer);
|
||||
|
||||
/// Обучает трансформер на матрице признаков X.
|
||||
/// X — матрица m × n.
|
||||
function Fit(X: Matrix): ITransformer;
|
||||
|
||||
/// Преобразует матрицу X в пространство главных компонент.
|
||||
/// Возвращает матрицу m × k.
|
||||
function Transform(X: Matrix): Matrix;
|
||||
|
||||
property Components: Matrix read fComponents;
|
||||
property Mean: Vector read fMean;
|
||||
property IsFitted: boolean read fFitted;
|
||||
end;
|
||||
|
||||
/// Трансформер, удаляющий признаки с малой дисперсией.
|
||||
/// Удаляет столбцы X_j, для которых Var(X_j) < threshold.
|
||||
/// Не использует целевую переменную (unsupervised).
|
||||
VarianceThreshold = class(ITransformer)
|
||||
private
|
||||
fThreshold: real;
|
||||
fSelected: array of integer;
|
||||
fFitted: boolean;
|
||||
|
||||
public
|
||||
/// threshold — минимальная допустимая дисперсия (>= 0).
|
||||
constructor Create(threshold: real := 0.0);
|
||||
|
||||
/// Вычисляет дисперсии признаков и запоминает индексы
|
||||
/// признаков, удовлетворяющих порогу.
|
||||
function Fit(X: Matrix): ITransformer;
|
||||
|
||||
/// Возвращает матрицу, содержащую только отобранные признаки.
|
||||
function Transform(X: Matrix): Matrix;
|
||||
|
||||
/// Индексы выбранных признаков.
|
||||
property SelectedFeatures: array of integer read fSelected;
|
||||
|
||||
/// Показывает, был ли выполнен Fit.
|
||||
property IsFitted: boolean read fFitted;
|
||||
end;
|
||||
|
||||
/// Тип критерия оценки признаков для SelectKBest.
|
||||
/// Определяет способ вычисления значимости признака
|
||||
/// относительно целевой переменной.
|
||||
FeatureScore = (
|
||||
/// Абсолютное значение коэффициента корреляции Пирсона
|
||||
/// между признаком и целевой переменной.
|
||||
/// Подходит для задач регрессии и бинарной классификации при линейной зависимости.
|
||||
Correlation,
|
||||
|
||||
/// F-статистика линейной регрессии (FRegression).
|
||||
/// Оценивает статистическую значимость линейной связи
|
||||
/// между признаком и целевой переменной.
|
||||
/// Основан на коэффициенте детерминации (R²) и F-статистике.
|
||||
/// Более строгий критерий, чем простая корреляция.
|
||||
FRegression,
|
||||
|
||||
/// ANOVA F-критерий.
|
||||
/// Используется в задачах классификации.
|
||||
/// Оценивает различие средних значений признака между различными классами.
|
||||
AnovaF,
|
||||
|
||||
/// Хи-квадрат (Chi-Square) критерий независимости.
|
||||
/// Используется в задачах классификации.
|
||||
/// Оценивает зависимость между признаком и классом
|
||||
/// на основе различия наблюдаемых и ожидаемых частот.
|
||||
/// Предполагает, что значения признака неотрицательны.
|
||||
/// Часто применяется для текстовых данных и частотных представлений (bag-of-words).
|
||||
ChiSquare
|
||||
);
|
||||
|
||||
/// Преобразователь с учётом целевой переменной
|
||||
/// Для каждого признака вычисляет score(X_j, y)
|
||||
/// и оставляет k признаков с наибольшим значением score.
|
||||
/// Может использовать встроенные критерии
|
||||
/// или пользовательскую функцию оценки.
|
||||
SelectKBest = class(ITransformer)
|
||||
private
|
||||
fK: integer;
|
||||
fScoreType: FeatureScore;
|
||||
fScoreFunc: (Vector, Vector) -> real;
|
||||
fSelected: array of integer;
|
||||
fFitted: boolean;
|
||||
|
||||
function ComputeScore(feature: Vector; y: Vector): real;
|
||||
function ComputeCorrelation(x: Vector; y: Vector): real;
|
||||
function ComputeFRegression(feature: Vector; y: Vector): real;
|
||||
function ComputeAnovaF(feature: Vector; y: Vector): real;
|
||||
function ComputeChiSquare(feature: Vector; y: Vector): real;
|
||||
public
|
||||
/// Создаёт трансформер с использованием встроенного критерия.
|
||||
/// k — число отбираемых признаков.
|
||||
/// score — тип критерия (например, Correlation).
|
||||
constructor Create(k: integer; score: FeatureScore := FeatureScore.Correlation);
|
||||
|
||||
/// Создаёт трансформер с пользовательской функцией оценки.
|
||||
/// scoreFunc — функция (feature, y) → real.
|
||||
constructor Create(k: integer; scoreFunc: (Vector, Vector) -> real);
|
||||
|
||||
/// Выбрасывает исключение
|
||||
/// Данный преобразователь требует целевую переменную.
|
||||
/// Используйте перегруженный метод Fit(X, y).
|
||||
function Fit(X: Matrix): ITransformer;
|
||||
|
||||
/// Вычисляет оценки признаков и выбирает k лучших.
|
||||
function Fit(X: Matrix; y: Vector): ITransformer;
|
||||
|
||||
/// Возвращает матрицу, содержащую только выбранные признаки.
|
||||
function Transform(X: Matrix): Matrix;
|
||||
|
||||
/// Индексы выбранных признаков.
|
||||
property SelectedFeatures: array of integer read fSelected;
|
||||
|
||||
/// Показывает, был ли выполнен Fit.
|
||||
property IsFitted: boolean read fFitted;
|
||||
end;
|
||||
|
||||
/// Тип нормы для нормализации строк.
|
||||
NormType = (L1, L2);
|
||||
|
||||
/// Преобразователь нормализации по строкам.
|
||||
/// Для каждой строки X_i выполняет нормализацию:
|
||||
/// L1: x := x / ||x||₁
|
||||
/// L2: x := x / ||x||₂
|
||||
/// Используется перед моделями, чувствительными к масштабу
|
||||
/// (LogisticRegression, SVM, L1-регуляризация).
|
||||
Normalizer = class(ITransformer)
|
||||
private
|
||||
fNormType: NormType;
|
||||
fFitted: boolean;
|
||||
public
|
||||
constructor Create(norm: NormType := NormType.L2);
|
||||
|
||||
function Fit(X: Matrix): ITransformer;
|
||||
function Transform(X: Matrix): Matrix;
|
||||
|
||||
property IsFitted: boolean read fFitted;
|
||||
end;
|
||||
|
||||
|
||||
{$endregion Transformers}
|
||||
|
||||
|
||||
|
|
@ -650,54 +853,209 @@ begin
|
|||
Result[i] += fIntercept;
|
||||
end;
|
||||
|
||||
constructor MulticlassLogisticRegression.Create(lambda: real; lr: real; epochs: integer);
|
||||
begin
|
||||
fLambda := lambda;
|
||||
fLearningRate := lr;
|
||||
fEpochs := epochs;
|
||||
fFitted := false;
|
||||
end;
|
||||
|
||||
function MulticlassLogisticRegression.Fit(X: Matrix; y: Vector): IModel;
|
||||
begin
|
||||
var m := X.RowCount;
|
||||
var p := X.ColCount;
|
||||
|
||||
// число классов
|
||||
fClassCount := Round(y.Max) + 1;
|
||||
|
||||
// инициализация параметров
|
||||
fW := new Matrix(p, fClassCount);
|
||||
fIntercept := new Vector(fClassCount);
|
||||
|
||||
// one-hot матрица
|
||||
var YoneHot := new Matrix(m, fClassCount);
|
||||
for var i := 0 to m - 1 do
|
||||
YoneHot[i, Round(y[i])] := 1.0;
|
||||
|
||||
for var epoch := 1 to fEpochs do
|
||||
begin
|
||||
// Z = XW + b
|
||||
var Z := X * fW;
|
||||
|
||||
for var i := 0 to m - 1 do
|
||||
for var k := 0 to fClassCount - 1 do
|
||||
Z[i,k] += fIntercept[k];
|
||||
|
||||
// softmax
|
||||
for var i := 0 to m - 1 do
|
||||
begin
|
||||
var maxVal := Z.RowMax(i);
|
||||
|
||||
var sumExp := 0.0;
|
||||
|
||||
for var k := 0 to fClassCount - 1 do
|
||||
begin
|
||||
Z[i,k] := Exp(Z[i,k] - maxVal);
|
||||
sumExp += Z[i,k];
|
||||
end;
|
||||
|
||||
for var k := 0 to fClassCount - 1 do
|
||||
Z[i,k] /= sumExp;
|
||||
end;
|
||||
|
||||
var PP := Z;
|
||||
|
||||
// градиенты
|
||||
var diff := PP - YoneHot; // m x k
|
||||
var gradW := X.Transpose * diff; // p x k
|
||||
|
||||
// L2 регуляризация (только веса)
|
||||
if fLambda <> 0 then
|
||||
gradW += fLambda * fW;
|
||||
|
||||
// обновление
|
||||
fW -= fLearningRate * gradW;
|
||||
|
||||
// градиент по intercept
|
||||
var gradB := diff.ColumnSums;
|
||||
fIntercept -= fLearningRate * gradB;
|
||||
end;
|
||||
|
||||
fFitted := true;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function MulticlassLogisticRegression.PredictProba(X: Matrix): Vector;
|
||||
begin
|
||||
var P := PredictProbaMatrix(X);
|
||||
|
||||
var m := P.RowCount;
|
||||
Result := new Vector(m);
|
||||
|
||||
for var i := 0 to m - 1 do
|
||||
begin
|
||||
var k := P.RowArgMax(i);
|
||||
Result[i] := P[i, k];
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function MulticlassLogisticRegression.PredictProbaMatrix(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
raise new Exception('Model not fitted');
|
||||
|
||||
var m := X.RowCount;
|
||||
|
||||
var Z := X * fW;
|
||||
|
||||
for var i := 0 to m - 1 do
|
||||
for var k := 0 to fClassCount - 1 do
|
||||
Z[i,k] += fIntercept[k];
|
||||
|
||||
for var i := 0 to m - 1 do
|
||||
begin
|
||||
var maxVal := Z.RowMax(i);
|
||||
|
||||
var sumExp := 0.0;
|
||||
|
||||
for var k := 0 to fClassCount - 1 do
|
||||
begin
|
||||
Z[i,k] := Exp(Z[i,k] - maxVal);
|
||||
sumExp += Z[i,k];
|
||||
end;
|
||||
|
||||
for var k := 0 to fClassCount - 1 do
|
||||
Z[i,k] /= sumExp;
|
||||
end;
|
||||
|
||||
Result := Z;
|
||||
end;
|
||||
|
||||
function MulticlassLogisticRegression.Predict(X: Matrix): Vector;
|
||||
begin
|
||||
var P := PredictProbaMatrix(X);
|
||||
|
||||
var m := P.RowCount;
|
||||
Result := new Vector(m);
|
||||
|
||||
for var i := 0 to m - 1 do
|
||||
Result[i] := P.RowArgMax(i);
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
// Pipeline
|
||||
//-----------------------------
|
||||
|
||||
|
||||
constructor Pipeline.Create;
|
||||
begin
|
||||
fTransformers := new List<ITransformer>;
|
||||
fModel := nil;
|
||||
fFitted := false;
|
||||
end;
|
||||
|
||||
constructor Pipeline.Create(model: IModel);
|
||||
begin
|
||||
Create;
|
||||
if model = nil then
|
||||
raise new ArgumentException('Model cannot be nil');
|
||||
fModel := model;
|
||||
fTransformers := new List<ITransformer>;
|
||||
fFitted := false;
|
||||
end;
|
||||
|
||||
static function Pipeline.Build(model: IModel; transformers: array of ITransformer): Pipeline;
|
||||
begin
|
||||
var pipe := new Pipeline(model);
|
||||
Result := new Pipeline(model);
|
||||
|
||||
foreach var t in transformers do
|
||||
pipe.Add(t);
|
||||
|
||||
Result := pipe;
|
||||
Result.Add(t);
|
||||
end;
|
||||
|
||||
function Pipeline.Add(t: ITransformer): Pipeline;
|
||||
begin
|
||||
if t = nil then
|
||||
raise new ArgumentException('Transformer cannot be nil');
|
||||
|
||||
fTransformers.Add(t);
|
||||
Result := self;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function Pipeline.SetModel(m: IModel): Pipeline;
|
||||
begin
|
||||
if m = nil then
|
||||
raise new ArgumentException('Model cannot be nil');
|
||||
|
||||
fModel := m;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function Pipeline.Fit(X: Matrix; y: Vector): IModel;
|
||||
begin
|
||||
var Xcur := X;
|
||||
if fModel = nil then
|
||||
raise new Exception('Model is not set');
|
||||
|
||||
var Xt := X;
|
||||
|
||||
foreach var t in fTransformers do
|
||||
begin
|
||||
t.Fit(Xcur);
|
||||
Xcur := t.Transform(Xcur);
|
||||
if t is ISupervisedTransformer (var sup) then
|
||||
sup.Fit(Xt, y)
|
||||
else t.Fit(Xt);
|
||||
|
||||
Xt := t.Transform(Xt);
|
||||
end;
|
||||
|
||||
fModel.Fit(Xcur, y);
|
||||
fFitted := true;
|
||||
fModel.Fit(Xt, y);
|
||||
|
||||
Result := self;
|
||||
fFitted := true;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function Pipeline.Transform(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
raise new Exception('Pipeline is not fitted');
|
||||
raise new Exception('Pipeline not fitted');
|
||||
|
||||
var Xt := X;
|
||||
|
||||
|
|
@ -712,28 +1070,21 @@ begin
|
|||
if not fFitted then
|
||||
raise new Exception('Pipeline not fitted');
|
||||
|
||||
var Xcur := X;
|
||||
|
||||
foreach var t in fTransformers do
|
||||
Xcur := t.Transform(Xcur);
|
||||
|
||||
Result := fModel.Predict(Xcur);
|
||||
var Xt := Transform(X);
|
||||
Result := fModel.Predict(Xt);
|
||||
end;
|
||||
|
||||
function Pipeline.PredictProba(X: Matrix): Vector;
|
||||
begin
|
||||
if not fFitted then
|
||||
raise new Exception('Pipeline is not fitted');
|
||||
raise new Exception('Pipeline not fitted');
|
||||
|
||||
var Xt := X;
|
||||
if not (fModel is IProbabilisticClassifier) then
|
||||
raise new Exception('Model does not support probability prediction');
|
||||
|
||||
foreach var t in fTransformers do
|
||||
Xt := t.Transform(Xt);
|
||||
var Xt := Transform(X);
|
||||
|
||||
if fModel is IProbabilisticClassifier then
|
||||
exit(IProbabilisticClassifier(fModel).PredictProba(Xt));
|
||||
|
||||
raise new Exception('Model does not support probability prediction');
|
||||
Result := (fModel as IProbabilisticClassifier).PredictProba(Xt);
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
|
|
@ -823,6 +1174,376 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
// PCATransformer
|
||||
//-----------------------------
|
||||
|
||||
constructor PCATransformer.Create(k: integer);
|
||||
begin
|
||||
if k <= 0 then
|
||||
raise new ArgumentException('k must be > 0');
|
||||
|
||||
fK := k;
|
||||
fFitted := false;
|
||||
end;
|
||||
|
||||
function PCATransformer.Fit(X: Matrix): ITransformer;
|
||||
begin
|
||||
if fK > X.ColCount then
|
||||
raise new ArgumentException('k exceeds feature count');
|
||||
|
||||
fMean := X.ColumnMeans;
|
||||
|
||||
var Xc := X.Clone;
|
||||
|
||||
for var j := 0 to X.ColCount - 1 do
|
||||
for var i := 0 to X.RowCount - 1 do
|
||||
Xc[i,j] -= fMean[j];
|
||||
|
||||
var (W, xxx) := Xc.PCA(fK);
|
||||
|
||||
fComponents := W;
|
||||
fFitted := true;
|
||||
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function PCATransformer.Transform(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
raise new InvalidOperationException('PCA not fitted');
|
||||
|
||||
var Xc := X.Clone;
|
||||
|
||||
for var j := 0 to X.ColCount - 1 do
|
||||
for var i := 0 to X.RowCount - 1 do
|
||||
Xc[i,j] -= fMean[j];
|
||||
|
||||
Result := Xc * fComponents;
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
// VarianceThreshold
|
||||
//-----------------------------
|
||||
|
||||
constructor VarianceThreshold.Create(threshold: real);
|
||||
begin
|
||||
if threshold < 0 then
|
||||
raise new ArgumentException('threshold must be >= 0');
|
||||
|
||||
fThreshold := threshold;
|
||||
fFitted := false;
|
||||
end;
|
||||
|
||||
function VarianceThreshold.Fit(X: Matrix): ITransformer;
|
||||
begin
|
||||
var vars := X.ColumnVariances;
|
||||
|
||||
var tmp := new List<integer>;
|
||||
|
||||
for var j := 0 to X.ColCount - 1 do
|
||||
if vars[j] >= fThreshold then
|
||||
tmp.Add(j);
|
||||
|
||||
fSelected := tmp.ToArray;
|
||||
fFitted := true;
|
||||
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function VarianceThreshold.Transform(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
raise new InvalidOperationException('VarianceThreshold not fitted');
|
||||
|
||||
var n := X.RowCount;
|
||||
var k := fSelected.Length;
|
||||
|
||||
var R := new Matrix(n, k);
|
||||
|
||||
for var i := 0 to n - 1 do
|
||||
for var c := 0 to k - 1 do
|
||||
R[i,c] := X[i, fSelected[c]];
|
||||
|
||||
Result := R;
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
// SelectKBest
|
||||
//-----------------------------
|
||||
|
||||
constructor SelectKBest.Create(k: integer; score: FeatureScore);
|
||||
begin
|
||||
if k <= 0 then
|
||||
raise new ArgumentException('k must be > 0');
|
||||
|
||||
fK := k;
|
||||
fScoreType := score;
|
||||
fScoreFunc := nil;
|
||||
fFitted := false;
|
||||
end;
|
||||
|
||||
constructor SelectKBest.Create(k: integer; scoreFunc: (Vector, Vector) -> real);
|
||||
begin
|
||||
if k <= 0 then
|
||||
raise new ArgumentException('k must be > 0');
|
||||
|
||||
fK := k;
|
||||
fScoreFunc := scoreFunc;
|
||||
fFitted := false;
|
||||
end;
|
||||
|
||||
function SelectKBest.ComputeCorrelation(x: Vector; y: Vector): real;
|
||||
begin
|
||||
var mx := x.Mean;
|
||||
var my := y.Mean;
|
||||
|
||||
var num := 0.0;
|
||||
var dx := 0.0;
|
||||
var dy := 0.0;
|
||||
|
||||
for var i := 0 to x.Length - 1 do
|
||||
begin
|
||||
var vx := x[i] - mx;
|
||||
var vy := y[i] - my;
|
||||
|
||||
num += vx * vy;
|
||||
dx += vx * vx;
|
||||
dy += vy * vy;
|
||||
end;
|
||||
|
||||
if (dx = 0) or (dy = 0) then
|
||||
exit(0.0);
|
||||
|
||||
Result := Abs(num / Sqrt(dx * dy));
|
||||
end;
|
||||
|
||||
function SelectKBest.ComputeFRegression(feature: Vector; y: Vector): real;
|
||||
begin
|
||||
var r := ComputeCorrelation(feature, y);
|
||||
var n := feature.Length;
|
||||
|
||||
if Abs(r) >= 1 then
|
||||
exit(1e308);
|
||||
|
||||
Result := (r*r / (1 - r*r)) * (n - 2);
|
||||
end;
|
||||
|
||||
function SelectKBest.ComputeAnovaF(feature: Vector; y: Vector): real;
|
||||
begin
|
||||
var mean0 := 0.0;
|
||||
var mean1 := 0.0;
|
||||
var n0 := 0;
|
||||
var n1 := 0;
|
||||
|
||||
for var i := 0 to y.Length - 1 do
|
||||
if y[i] = 0 then
|
||||
begin
|
||||
mean0 += feature[i];
|
||||
n0 += 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
mean1 += feature[i];
|
||||
n1 += 1;
|
||||
end;
|
||||
|
||||
if (n0 = 0) or (n1 = 0) then
|
||||
exit(0.0);
|
||||
|
||||
mean0 /= n0;
|
||||
mean1 /= n1;
|
||||
|
||||
var grandMean := feature.Mean;
|
||||
|
||||
var ssBetween :=
|
||||
n0 * Sqr(mean0 - grandMean) +
|
||||
n1 * Sqr(mean1 - grandMean);
|
||||
|
||||
var ssWithin := 0.0;
|
||||
|
||||
for var i := 0 to y.Length - 1 do
|
||||
if y[i] = 0 then
|
||||
ssWithin += Sqr(feature[i] - mean0)
|
||||
else
|
||||
ssWithin += Sqr(feature[i] - mean1);
|
||||
|
||||
if ssWithin = 0 then
|
||||
exit(1e308);
|
||||
|
||||
Result := (ssBetween) / (ssWithin / (y.Length - 2));
|
||||
end;
|
||||
|
||||
function SelectKBest.ComputeChiSquare(feature: Vector; y: Vector): real;
|
||||
begin
|
||||
var n := y.Length;
|
||||
|
||||
var sum0 := 0.0;
|
||||
var sum1 := 0.0;
|
||||
var total := 0.0;
|
||||
var n0 := 0;
|
||||
var n1 := 0;
|
||||
|
||||
for var i := 0 to n - 1 do
|
||||
begin
|
||||
var v := feature[i];
|
||||
if v < 0 then
|
||||
raise new ArgumentException('ChiSquare requires non-negative features');
|
||||
|
||||
total += v;
|
||||
|
||||
if y[i] = 0 then
|
||||
begin
|
||||
sum0 += v;
|
||||
n0 += 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
sum1 += v;
|
||||
n1 += 1;
|
||||
end;
|
||||
end;
|
||||
|
||||
if (n0 = 0) or (n1 = 0) or (total = 0) then
|
||||
exit(0.0);
|
||||
|
||||
var expected0 := total * n0 / n;
|
||||
var expected1 := total * n1 / n;
|
||||
|
||||
var chi := 0.0;
|
||||
|
||||
if expected0 > 0 then
|
||||
chi += Sqr(sum0 - expected0) / expected0;
|
||||
|
||||
if expected1 > 0 then
|
||||
chi += Sqr(sum1 - expected1) / expected1;
|
||||
|
||||
Result := chi;
|
||||
end;
|
||||
|
||||
function SelectKBest.ComputeScore(feature: Vector; y: Vector): real;
|
||||
begin
|
||||
case fScoreType of
|
||||
FeatureScore.Correlation: Result := ComputeCorrelation(feature, y);
|
||||
FeatureScore.FRegression: Result := ComputeFRegression(feature, y);
|
||||
FeatureScore.AnovaF: Result := ComputeAnovaF(feature, y);
|
||||
FeatureScore.ChiSquare: Result := ComputeChiSquare(feature, y);
|
||||
else
|
||||
raise new InvalidOperationException('Unknown FeatureScore type');
|
||||
end;
|
||||
end;
|
||||
|
||||
function SelectKBest.Fit(X: Matrix; y: Vector): ITransformer;
|
||||
begin
|
||||
var p := X.ColCount;
|
||||
|
||||
var scores: array of (real, integer);
|
||||
SetLength(scores, p);
|
||||
|
||||
for var j := 0 to p - 1 do
|
||||
begin
|
||||
var col := new Vector(X.RowCount);
|
||||
for var i := 0 to X.RowCount - 1 do
|
||||
col[i] := X[i,j];
|
||||
|
||||
var s :=
|
||||
if fScoreFunc <> nil then
|
||||
fScoreFunc(col, y)
|
||||
else
|
||||
ComputeCorrelation(col, y);
|
||||
|
||||
scores[j] := (s, j);
|
||||
end;
|
||||
|
||||
scores := scores.OrderByDescending(t -> t.Item1).ToArray;
|
||||
|
||||
var k := Min(fK, p);
|
||||
SetLength(fSelected, k);
|
||||
|
||||
for var i := 0 to k - 1 do
|
||||
fSelected[i] := scores[i].Item2;
|
||||
|
||||
fFitted := true;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function SelectKBest.Fit(X: Matrix): ITransformer;
|
||||
begin
|
||||
Result := nil;
|
||||
raise new InvalidOperationException('Target variable is required');
|
||||
end;
|
||||
|
||||
function SelectKBest.Transform(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
raise new InvalidOperationException('SelectKBest not fitted');
|
||||
|
||||
var n := X.RowCount;
|
||||
var k := fSelected.Length;
|
||||
|
||||
var R := new Matrix(n, k);
|
||||
|
||||
for var i := 0 to n - 1 do
|
||||
for var c := 0 to k - 1 do
|
||||
R[i,c] := X[i, fSelected[c]];
|
||||
|
||||
Result := R;
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
// Normalizer
|
||||
//-----------------------------
|
||||
|
||||
constructor Normalizer.Create(norm: NormType);
|
||||
begin
|
||||
fNormType := norm;
|
||||
fFitted := false;
|
||||
end;
|
||||
|
||||
function Normalizer.Fit(X: Matrix): ITransformer;
|
||||
begin
|
||||
// Нормализация не требует обучения
|
||||
fFitted := true;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function Normalizer.Transform(X: Matrix): Matrix;
|
||||
begin
|
||||
if not fFitted then
|
||||
raise new InvalidOperationException('Normalizer not fitted');
|
||||
|
||||
var n := X.RowCount;
|
||||
var p := X.ColCount;
|
||||
|
||||
var R := new Matrix(n, p);
|
||||
|
||||
for var i := 0 to n - 1 do
|
||||
begin
|
||||
var norm := 0.0;
|
||||
|
||||
case fNormType of
|
||||
NormType.L1:
|
||||
for var j := 0 to p - 1 do
|
||||
norm += Abs(X[i,j]);
|
||||
|
||||
NormType.L2:
|
||||
for var j := 0 to p - 1 do
|
||||
norm += Sqr(X[i,j]);
|
||||
end;
|
||||
|
||||
if fNormType = NormType.L2 then
|
||||
norm := Sqrt(norm);
|
||||
|
||||
if norm = 0 then
|
||||
continue;
|
||||
|
||||
for var j := 0 to p - 1 do
|
||||
R[i,j] := X[i,j] / norm;
|
||||
end;
|
||||
|
||||
Result := R;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
Loading…
Reference in a new issue