pascalabcnet/bin/Lib/InspectionML.pas

222 lines
7.5 KiB
ObjectPascal
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/// InspectionML — инструменты анализа поведения обученных моделей.
///
/// Модуль предназначен для исследования и интерпретации уже обученных
/// моделей машинного обучения.
///
/// Содержит алгоритмы:
/// • оценки важности признаков
/// • анализа чувствительности модели
/// • построения частичных зависимостей
/// • диагностических процедур
///
/// Область ответственности:
/// • работает только с обученными моделями (IModel)
/// • не участвует в обучении
/// • не вычисляет метрики напрямую
/// • не изменяет состояние модели
///
/// Архитектурный принцип:
/// • модуль зависит от абстракции IModel
/// • модели не зависят от данного модуля
unit InspectionML;
interface
uses MLCoreABC, LinearAlgebraML;
type
Inspection = static class
public
/// PermutationImportance — оценка важности признаков методом перестановок.
///
/// Для каждого признака случайно перемешивает соответствующий столбец
/// и измеряет снижение качества модели по заданной функции scoreFunc.
///
/// Текущая версия предназначена для регрессионных моделей.
///
/// Параметры:
/// • model — обученная регрессионная модель;
/// • X — матрица признаков (nSamples × nFeatures);
/// • y — вектор истинных значений;
/// • scoreFunc — функция оценки качества (например, MSE, Accuracy);
/// • seed — начальное значение генератора случайных чисел.
///
/// Возвращает:
/// Вектор важностей признаков длины nFeatures.
/// Чем больше значение, тем сильнее признак влияет на качество модели
static function PermutationImportance(model: IRegressor; X: Matrix; y: Vector;
scoreFunc: (Vector, Vector) -> real;
nRepeats: integer := 5;
higherIsBetter: boolean := True;
seed: integer := -1): Vector;
/// 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;
end;
implementation
uses MLExceptions;
uses MLUtilsABC;
const
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(
model: IRegressor;
X: Matrix; y: Vector;
scoreFunc: (Vector, Vector) -> 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;
// --- детерминированный seed для (j, r)
var runSeed := baseSeed + j * 100000 + r;
var rnd := new System.Random(runSeed);
// --- shuffle столбца j (FisherYates)
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;
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.