2026-02-21 13:34:18 +03:00
|
|
|
|
/// InspectionML — инструменты анализа поведения обученных моделей.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Модуль предназначен для исследования и интерпретации уже обученных
|
|
|
|
|
|
/// моделей машинного обучения.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Содержит алгоритмы:
|
|
|
|
|
|
/// • оценки важности признаков
|
|
|
|
|
|
/// • анализа чувствительности модели
|
|
|
|
|
|
/// • построения частичных зависимостей
|
|
|
|
|
|
/// • диагностических процедур
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Область ответственности:
|
|
|
|
|
|
/// • работает только с обученными моделями (IModel)
|
|
|
|
|
|
/// • не участвует в обучении
|
|
|
|
|
|
/// • не вычисляет метрики напрямую
|
|
|
|
|
|
/// • не изменяет состояние модели
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Архитектурный принцип:
|
|
|
|
|
|
/// • модуль зависит от абстракции IModel
|
|
|
|
|
|
/// • модели не зависят от данного модуля
|
|
|
|
|
|
unit InspectionML;
|
|
|
|
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
|
|
|
|
uses MLCoreABC, LinearAlgebraML;
|
|
|
|
|
|
|
|
|
|
|
|
type
|
|
|
|
|
|
Inspection = static class
|
|
|
|
|
|
public
|
2026-04-04 14:33:26 +03:00
|
|
|
|
/// PermutationImportance — оценка важности признаков методом перестановок.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Для каждого признака случайно перемешивает соответствующий столбец
|
|
|
|
|
|
/// и измеряет снижение качества модели по заданной функции scoreFunc.
|
|
|
|
|
|
///
|
2026-05-28 10:23:22 +03:00
|
|
|
|
/// Текущая версия предназначена для регрессионных моделей.
|
2026-04-04 14:33:26 +03:00
|
|
|
|
///
|
|
|
|
|
|
/// Параметры:
|
2026-05-28 10:23:22 +03:00
|
|
|
|
/// • model — обученная регрессионная модель;
|
2026-04-04 14:33:26 +03:00
|
|
|
|
/// • X — матрица признаков (nSamples × nFeatures);
|
|
|
|
|
|
/// • y — вектор истинных значений;
|
|
|
|
|
|
/// • scoreFunc — функция оценки качества (например, MSE, Accuracy);
|
|
|
|
|
|
/// • seed — начальное значение генератора случайных чисел.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Возвращает:
|
|
|
|
|
|
/// Вектор важностей признаков длины nFeatures.
|
|
|
|
|
|
/// Чем больше значение, тем сильнее признак влияет на качество модели
|
2026-05-28 10:23:22 +03:00
|
|
|
|
static function PermutationImportance(model: IRegressor; X: Matrix; y: Vector;
|
2026-04-15 20:11:49 +03:00
|
|
|
|
scoreFunc: (Vector, Vector) -> real;
|
|
|
|
|
|
nRepeats: integer := 5;
|
|
|
|
|
|
higherIsBetter: boolean := True;
|
|
|
|
|
|
seed: integer := -1): Vector;
|
2026-05-28 10:23:22 +03:00
|
|
|
|
|
|
|
|
|
|
/// PermutationImportance — оценка важности признаков методом перестановок.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Текущая версия предназначена для классификационных моделей.
|
|
|
|
|
|
/// Для каждого признака случайно перемешивает соответствующий столбец
|
|
|
|
|
|
/// и измеряет снижение качества модели по заданной функции scoreFunc.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Параметры:
|
|
|
|
|
|
/// • model — обученная классификационная модель;
|
|
|
|
|
|
/// • X — матрица признаков (nSamples × nFeatures);
|
|
|
|
|
|
/// • y — массив истинных меток классов;
|
|
|
|
|
|
/// • scoreFunc — функция оценки качества (например, Accuracy);
|
|
|
|
|
|
/// • seed — начальное значение генератора случайных чисел.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Возвращает:
|
|
|
|
|
|
/// Вектор важностей признаков длины nFeatures.
|
|
|
|
|
|
/// Чем больше значение, тем сильнее признак влияет на качество модели
|
|
|
|
|
|
static function PermutationImportance(model: IClassifier; X: Matrix; y: array of integer;
|
|
|
|
|
|
scoreFunc: (array of integer, array of integer) -> real;
|
|
|
|
|
|
nRepeats: integer := 5;
|
|
|
|
|
|
higherIsBetter: boolean := True;
|
|
|
|
|
|
seed: integer := -1): Vector;
|
2026-02-21 13:34:18 +03:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
2026-02-25 15:15:47 +03:00
|
|
|
|
uses MLExceptions;
|
2026-04-23 16:30:27 +03:00
|
|
|
|
uses MLUtilsABC;
|
2026-02-25 15:15:47 +03:00
|
|
|
|
|
|
|
|
|
|
const
|
2026-04-05 00:00:36 +03:00
|
|
|
|
ER_SCORE_FUNC_NULL =
|
|
|
|
|
|
'scoreFunc не может быть nil!!scoreFunc cannot be nil';
|
|
|
|
|
|
ER_ARG_OUT_OF_RANGE =
|
|
|
|
|
|
'Аргумент {0} имеет недопустимое значение {1}!!Argument {0} has invalid value {1}';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static function Inspection.PermutationImportance(
|
2026-05-28 10:23:22 +03:00
|
|
|
|
model: IRegressor;
|
2026-04-15 20:11:49 +03:00
|
|
|
|
X: Matrix; y: Vector;
|
2026-04-05 00:00:36 +03:00
|
|
|
|
scoreFunc: (Vector, Vector) -> real;
|
|
|
|
|
|
nRepeats: integer;
|
2026-04-15 20:11:49 +03:00
|
|
|
|
higherIsBetter: boolean;
|
|
|
|
|
|
seed: integer): Vector;
|
2026-02-21 13:34:18 +03:00
|
|
|
|
begin
|
2026-02-25 15:15:47 +03:00
|
|
|
|
if model = nil then
|
|
|
|
|
|
ArgumentNullError(ER_MODEL_NULL);
|
|
|
|
|
|
|
|
|
|
|
|
if scoreFunc = nil then
|
|
|
|
|
|
ArgumentNullError(ER_SCORE_FUNC_NULL);
|
|
|
|
|
|
|
2026-03-02 00:22:35 +03:00
|
|
|
|
if X.RowCount <> y.Length then
|
|
|
|
|
|
DimensionError(ER_DIM_MISMATCH, X.RowCount, y.Length);
|
2026-02-21 13:34:18 +03:00
|
|
|
|
|
2026-04-05 00:00:36 +03:00
|
|
|
|
if nRepeats < 1 then
|
|
|
|
|
|
ArgumentOutOfRangeError(ER_ARG_OUT_OF_RANGE, 'nRepeats', nRepeats);
|
|
|
|
|
|
|
2026-02-21 13:34:18 +03:00
|
|
|
|
var baselinePred := model.Predict(X);
|
|
|
|
|
|
var baselineScore := scoreFunc(y, baselinePred);
|
|
|
|
|
|
|
2026-03-02 00:22:35 +03:00
|
|
|
|
var n := X.RowCount;
|
|
|
|
|
|
var p := X.ColCount;
|
2026-02-21 13:34:18 +03:00
|
|
|
|
|
|
|
|
|
|
var resultVec := new Vector(p);
|
|
|
|
|
|
|
2026-04-23 16:30:27 +03:00
|
|
|
|
var userProvidedSeed: boolean;
|
|
|
|
|
|
var baseSeed := ResolveRandomSeed(seed, userProvidedSeed);
|
2026-04-06 23:04:46 +03:00
|
|
|
|
|
2026-04-05 00:00:36 +03:00
|
|
|
|
for var j := 0 to p - 1 do
|
2026-02-21 13:34:18 +03:00
|
|
|
|
begin
|
2026-04-05 00:00:36 +03:00
|
|
|
|
var acc := 0.0;
|
2026-02-21 13:34:18 +03:00
|
|
|
|
|
2026-04-05 00:00:36 +03:00
|
|
|
|
for var r := 0 to nRepeats - 1 do
|
2026-02-21 13:34:18 +03:00
|
|
|
|
begin
|
2026-04-05 00:00:36 +03:00
|
|
|
|
var Xperm := X.Clone;
|
|
|
|
|
|
|
2026-04-06 23:04:46 +03:00
|
|
|
|
// --- детерминированный seed для (j, r)
|
|
|
|
|
|
var runSeed := baseSeed + j * 100000 + r;
|
2026-02-21 13:34:18 +03:00
|
|
|
|
|
2026-04-05 00:00:36 +03:00
|
|
|
|
var rnd := new System.Random(runSeed);
|
|
|
|
|
|
|
2026-04-06 23:04:46 +03:00
|
|
|
|
// --- shuffle столбца j (Fisher–Yates)
|
2026-04-05 00:00:36 +03:00
|
|
|
|
for var i := n - 1 downto 1 do
|
|
|
|
|
|
begin
|
|
|
|
|
|
var k := rnd.Next(i + 1);
|
|
|
|
|
|
var tmp := Xperm[i,j];
|
|
|
|
|
|
Xperm[i,j] := Xperm[k,j];
|
|
|
|
|
|
Xperm[k,j] := tmp;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
var permPred := model.Predict(Xperm);
|
|
|
|
|
|
var permScore := scoreFunc(y, permPred);
|
|
|
|
|
|
|
2026-04-15 20:11:49 +03:00
|
|
|
|
if higherIsBetter then
|
|
|
|
|
|
acc += (baselineScore - permScore)
|
|
|
|
|
|
else
|
|
|
|
|
|
acc += (permScore - baselineScore);
|
2026-04-05 00:00:36 +03:00
|
|
|
|
end;
|
2026-02-21 13:34:18 +03:00
|
|
|
|
|
2026-04-05 00:00:36 +03:00
|
|
|
|
resultVec[j] := acc / nRepeats;
|
2026-02-21 13:34:18 +03:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
Result := resultVec;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
2026-05-28 10:23:22 +03:00
|
|
|
|
static function Inspection.PermutationImportance(
|
|
|
|
|
|
model: IClassifier;
|
|
|
|
|
|
X: Matrix; y: array of integer;
|
|
|
|
|
|
scoreFunc: (array of integer, array of integer) -> real;
|
|
|
|
|
|
nRepeats: integer;
|
|
|
|
|
|
higherIsBetter: boolean;
|
|
|
|
|
|
seed: integer): Vector;
|
|
|
|
|
|
begin
|
|
|
|
|
|
if model = nil then
|
|
|
|
|
|
ArgumentNullError(ER_MODEL_NULL);
|
|
|
|
|
|
|
|
|
|
|
|
if scoreFunc = nil then
|
|
|
|
|
|
ArgumentNullError(ER_SCORE_FUNC_NULL);
|
|
|
|
|
|
|
|
|
|
|
|
if X.RowCount <> y.Length then
|
|
|
|
|
|
DimensionError(ER_DIM_MISMATCH, X.RowCount, y.Length);
|
|
|
|
|
|
|
|
|
|
|
|
if nRepeats < 1 then
|
|
|
|
|
|
ArgumentOutOfRangeError(ER_ARG_OUT_OF_RANGE, 'nRepeats', nRepeats);
|
|
|
|
|
|
|
|
|
|
|
|
var baselinePred := model.Predict(X);
|
|
|
|
|
|
var baselineScore := scoreFunc(y, baselinePred);
|
|
|
|
|
|
|
|
|
|
|
|
var n := X.RowCount;
|
|
|
|
|
|
var p := X.ColCount;
|
|
|
|
|
|
|
|
|
|
|
|
var resultVec := new Vector(p);
|
|
|
|
|
|
|
|
|
|
|
|
var userProvidedSeed: boolean;
|
|
|
|
|
|
var baseSeed := ResolveRandomSeed(seed, userProvidedSeed);
|
|
|
|
|
|
|
|
|
|
|
|
for var j := 0 to p - 1 do
|
|
|
|
|
|
begin
|
|
|
|
|
|
var acc := 0.0;
|
|
|
|
|
|
|
|
|
|
|
|
for var r := 0 to nRepeats - 1 do
|
|
|
|
|
|
begin
|
|
|
|
|
|
var Xperm := X.Clone;
|
|
|
|
|
|
|
|
|
|
|
|
var runSeed := baseSeed + j * 100000 + r;
|
|
|
|
|
|
var rnd := new System.Random(runSeed);
|
|
|
|
|
|
|
|
|
|
|
|
for var i := n - 1 downto 1 do
|
|
|
|
|
|
begin
|
|
|
|
|
|
var k := rnd.Next(i + 1);
|
|
|
|
|
|
var tmp := Xperm[i,j];
|
|
|
|
|
|
Xperm[i,j] := Xperm[k,j];
|
|
|
|
|
|
Xperm[k,j] := tmp;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
var permPred := model.Predict(Xperm);
|
|
|
|
|
|
var permScore := scoreFunc(y, permPred);
|
|
|
|
|
|
|
|
|
|
|
|
if higherIsBetter then
|
|
|
|
|
|
acc += (baselineScore - permScore)
|
|
|
|
|
|
else
|
|
|
|
|
|
acc += (permScore - baselineScore);
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
resultVec[j] := acc / nRepeats;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
Result := resultVec;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
end.
|