ML - примеры
This commit is contained in:
parent
c89bba640f
commit
a8d8ce82bf
|
|
@ -15,7 +15,7 @@ internal static class RevisionClass
|
|||
public const string Major = "3";
|
||||
public const string Minor = "11";
|
||||
public const string Build = "1";
|
||||
public const string Revision = "3783";
|
||||
public const string Revision = "3784";
|
||||
|
||||
public const string MainVersion = Major + "." + Minor;
|
||||
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
%MINOR%=11
|
||||
%REVISION%=3783
|
||||
%COREVERSION%=1
|
||||
%REVISION%=3784
|
||||
%MINOR%=11
|
||||
%MAJOR%=3
|
||||
|
|
|
|||
|
|
@ -1,91 +0,0 @@
|
|||
// Пример влияния регуляризации (RidgeRegression) на линейную модель
|
||||
// в задаче с большим числом признаков и относительно малым числом объектов.
|
||||
//
|
||||
// Датасет:
|
||||
// • 20 признаков, из которых информативны только 3, остальные — шум
|
||||
// • добавлен существенный гауссов шум (noise = 2.0)
|
||||
// • зависимость остаётся линейной, но сигнал частично скрыт шумом
|
||||
//
|
||||
// Такая постановка приводит к переобучению:
|
||||
// модель может подстраиваться под шум и случайные колебания признаков.
|
||||
//
|
||||
// Наблюдения:
|
||||
//
|
||||
// • LinearRegression:
|
||||
// – достигает меньшей ошибки на обучающей выборке (лучше подгонка)
|
||||
// – но заметно хуже работает на тесте (переобучение)
|
||||
//
|
||||
// • RidgeRegression:
|
||||
// – даёт большую ошибку на обучении (штраф за коэффициенты)
|
||||
// – но существенно лучше обобщает и снижает ошибку на тесте
|
||||
//
|
||||
// Интерпретация:
|
||||
//
|
||||
// • обычная линейная регрессия переобучается на шуме и лишних признаках
|
||||
// • Ridge вводит L2-регуляризацию и "сжимает" коэффициенты модели
|
||||
// • регуляризация подавляет влияние неинформативных признаков
|
||||
// • в результате модель становится более устойчивой к новым данным
|
||||
//
|
||||
// Этот пример демонстрирует:
|
||||
// • разницу между train и test ошибками как признак переобучения
|
||||
// • влияние лишних признаков на качество модели
|
||||
// • практическую пользу регуляризации в задачах с шумом и мультиколлинеарностью
|
||||
uses MLABC;
|
||||
|
||||
function Normal(rnd: System.Random): real;
|
||||
begin
|
||||
var u1 := rnd.NextDouble;
|
||||
var u2 := rnd.NextDouble;
|
||||
if u1 < 1e-12 then
|
||||
u1 := 1e-12;
|
||||
Result := Sqrt(-2 * Ln(u1)) * Cos(2 * Pi * u2);
|
||||
end;
|
||||
|
||||
begin
|
||||
var (X, y) := Datasets.MakeRegression(
|
||||
n := 100,
|
||||
nFeatures := 20,
|
||||
nInformative := 3,
|
||||
noise := 2.0,
|
||||
coefScale := 1.0,
|
||||
bias := 0.0,
|
||||
nonlinearStrength := 0.0,
|
||||
shuffle := True,
|
||||
seed := 42
|
||||
);
|
||||
|
||||
// --- добавляем корреляцию
|
||||
var rnd := new System.Random(1);
|
||||
for var i := 0 to X.RowCount - 1 do
|
||||
begin
|
||||
X[i, 1] := X[i, 0] + 0.01 * Normal(rnd);
|
||||
X[i, 2] := X[i, 0] - 0.01 * Normal(rnd);
|
||||
end;
|
||||
|
||||
var (XTrain, XTest, yTrain, yTest) := Validation.TrainTestSplit(
|
||||
X, y,
|
||||
testRatio := 0.3,
|
||||
seed := 42
|
||||
);
|
||||
|
||||
var lr := new LinearRegression;
|
||||
lr.Fit(XTrain, yTrain);
|
||||
|
||||
var ridge := new RidgeRegression(50.0);
|
||||
ridge.Fit(XTrain, yTrain);
|
||||
|
||||
var yTrainLR := lr.Predict(XTrain);
|
||||
var yTestLR := lr.Predict(XTest);
|
||||
|
||||
var yTrainRidge := ridge.Predict(XTrain);
|
||||
var yTestRidge := ridge.Predict(XTest);
|
||||
|
||||
Println('--- Train ---');
|
||||
Println($'Linear MSE: {Metrics.MSE(yTrain, yTrainLR),0:F4}');
|
||||
Println($'Ridge MSE: {Metrics.MSE(yTrain, yTrainRidge),0:F4}');
|
||||
|
||||
Println;
|
||||
Println('--- Test ---');
|
||||
Println($'Linear MSE: {Metrics.MSE(yTest, yTestLR),0:F4}');
|
||||
Println($'Ridge MSE: {Metrics.MSE(yTest, yTestRidge),0:F4}');
|
||||
end.
|
||||
|
|
@ -1,28 +1,19 @@
|
|||
// Сравнение KMeans и DBSCAN на данных с шумом и разной плотностью кластеров.
|
||||
// Сравнение KMeans и DBSCAN на данных с шумом и разной плотностью.
|
||||
//
|
||||
// Датасет содержит:
|
||||
// • несколько кластеров
|
||||
// • различную плотность
|
||||
// • дополнительные шумовые точки
|
||||
// Оба алгоритма находят одинаковое число кластеров (k = 5),
|
||||
// поэтому сравнение по ARI является корректным.
|
||||
//
|
||||
// KMeans:
|
||||
// • предполагает компактные и примерно одинаковые по размеру кластеры
|
||||
// • плохо работает при наличии шума и различной плотности
|
||||
// • стремится "размазать" шум по кластерам
|
||||
// KMeans предполагает компактные и одинаковые по форме кластеры,
|
||||
// а также чувствителен к шуму, что снижает качество разбиения.
|
||||
//
|
||||
// DBSCAN:
|
||||
// • выделяет кластеры как области высокой плотности
|
||||
// • естественно отделяет шум (метка -1)
|
||||
// • лучше справляется с неоднородной структурой данных
|
||||
// DBSCAN выделяет кластеры как области высокой плотности
|
||||
// и автоматически игнорирует шумовые точки (label = -1),
|
||||
// благодаря чему лучше восстанавливает структуру данных.
|
||||
//
|
||||
// По метрике ARI DBSCAN показывает лучший результат,
|
||||
// так как точнее восстанавливает истинную структуру кластеров.
|
||||
//
|
||||
// Этот пример демонстрирует различие двух подходов:
|
||||
// • центроидный (KMeans)
|
||||
// • плотностный (DBSCAN)
|
||||
// В результате DBSCAN показывает более высокий ARI,
|
||||
// так как точнее отражает реальную геометрию кластеров.
|
||||
|
||||
// KMeans ARI: 0.9073
|
||||
// KMeans ARI: 0.8973
|
||||
// DBSCAN ARI: 0.9496
|
||||
|
||||
uses MLABC, PlotML;
|
||||
|
|
@ -43,13 +34,15 @@ begin
|
|||
);
|
||||
|
||||
// --- модели
|
||||
var kmeans := new KMeans(3);
|
||||
var kmeans := new KMeans(5);
|
||||
kmeans.Fit(X);
|
||||
var yKM := kmeans.PredictLabels(X);
|
||||
kmeans.ClustersCount.Println;
|
||||
|
||||
var db := new DBSCAN(0.7, 5);
|
||||
db.Fit(X);
|
||||
var yDB := db.PredictLabels(X);
|
||||
db.ClustersCount.Println;
|
||||
|
||||
// --- метрики
|
||||
var ariKM := Metrics.AdjustedRandIndex(yTrue, yKM);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
// Подбор параметра eps для DBSCAN методом перебора с оценкой качества кластеризации.
|
||||
//
|
||||
// Для каждого eps вычисляются: число кластеров, доля крупнейшего кластера,
|
||||
// доля шума и silhouette, после чего считается итоговый score.
|
||||
//
|
||||
// Score балансирует качество разделения (silhouette) и структуру кластеров,
|
||||
// штрафуя решения с одним большим кластером или слишком большим шумом.
|
||||
//
|
||||
// Это позволяет избежать вырожденных случаев и выбрать eps,
|
||||
// дающий наиболее устойчивое и интерпретируемое разбиение.
|
||||
//
|
||||
// Важно: перед применением DBSCAN данные масштабируются,
|
||||
// так как значение eps зависит от масштаба признаков.
|
||||
|
||||
uses MLABC;
|
||||
|
||||
begin
|
||||
// --- данные (сложный случай: разная плотность + шум)
|
||||
var (X, yTrue) := Datasets.MakeBlobs(
|
||||
n := 400,
|
||||
centers := 3,
|
||||
nFeatures := 2,
|
||||
clusterStd := 0.9,
|
||||
clusterStdVar := 1.0,
|
||||
centerBox := 6.0,
|
||||
classBalance := 1.0,
|
||||
noisePoints := 60,
|
||||
shuffle := True,
|
||||
seed := 1
|
||||
);
|
||||
|
||||
// --- подготовка данных
|
||||
|
||||
var scaler := new StandardScaler;
|
||||
scaler.Fit(X);
|
||||
X := scaler.Transform(X);
|
||||
|
||||
// --- сетка eps
|
||||
var epsList := Arr(0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0);
|
||||
|
||||
var bestEps := -1.0;
|
||||
var bestScore := -1e9;
|
||||
|
||||
Println('eps k max% noise% silhouette score');
|
||||
Println('----------------------------------------------------------------------');
|
||||
|
||||
foreach var eps in epsList do
|
||||
begin
|
||||
var model := new DBSCAN(eps, 5);
|
||||
model.Fit(X);
|
||||
|
||||
var labels := model.PredictLabels(X);
|
||||
|
||||
// --- статистика кластеров
|
||||
var counts := new Dictionary<integer, integer>();
|
||||
foreach var l in labels do
|
||||
counts[l] := counts.Get(l, 0) + 1;
|
||||
|
||||
var n := X.RowCount;
|
||||
|
||||
var k := 0;
|
||||
var maxCluster := 0;
|
||||
var noise := counts.Get(-1, 0);
|
||||
|
||||
var sizes := new List<integer>;
|
||||
|
||||
foreach var kv in counts do
|
||||
if kv.Key <> -1 then
|
||||
begin
|
||||
k += 1;
|
||||
sizes.Add(kv.Value);
|
||||
if kv.Value > maxCluster then
|
||||
maxCluster := kv.Value;
|
||||
end;
|
||||
|
||||
sizes.Sort;
|
||||
sizes.Reverse;
|
||||
|
||||
var secondCluster :=
|
||||
if sizes.Count >= 2 then sizes[1] else 0;
|
||||
|
||||
var maxFrac := maxCluster / n;
|
||||
var noiseFrac := noise / n;
|
||||
var secondFrac := secondCluster / n;
|
||||
|
||||
// --- silhouette
|
||||
var sil := -1.0;
|
||||
if k >= 2 then
|
||||
sil := Metrics.SilhouetteScore(X, labels);
|
||||
|
||||
// --- нормализация silhouette (упрощённо)
|
||||
var silNorm := (sil + 1) / 2; // [-1,1] → [0,1]
|
||||
|
||||
// --- штрафы (ключевая часть!)
|
||||
var penalty :=
|
||||
0.4 * maxFrac // доминирующий кластер
|
||||
+ 0.3 * noiseFrac // шум
|
||||
+ 0.3 * (1 - secondFrac);// слишком маленький второй кластер
|
||||
|
||||
// --- штраф за плохое k
|
||||
if k < 2 then
|
||||
penalty += 0.5;
|
||||
|
||||
// --- итоговый score
|
||||
var score := silNorm - penalty;
|
||||
|
||||
if score > bestScore then
|
||||
begin
|
||||
bestScore := score;
|
||||
bestEps := eps;
|
||||
end;
|
||||
|
||||
Println($'{eps,4:F1} {k,4} {maxFrac,7:F2} {noiseFrac,8:F2} {sil,12:F4} {score,10:F4}');
|
||||
end;
|
||||
|
||||
Println;
|
||||
Println($'Выбран eps: {bestEps,0:F2}');
|
||||
Println;
|
||||
end.
|
||||
|
|
@ -3,11 +3,11 @@
|
|||
begin
|
||||
var ds := Datasets.Iris;
|
||||
var df := ds.Data;
|
||||
|
||||
|
||||
var X := df.ToMatrix(ds.Features);
|
||||
var labels := df.EncodeLabels(ds.Target);
|
||||
|
||||
Plot.PairPlot(X, labels, ds.Features);
|
||||
|
||||
Plot.Title('Iris: пары признаков');
|
||||
Plot.Title := 'Iris: пары признаков';
|
||||
end.
|
||||
|
|
@ -15,6 +15,7 @@ begin
|
|||
target,
|
||||
features,
|
||||
new OneHotEncoder('renovation'),
|
||||
new StandardScaler,
|
||||
new LinearRegression
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ begin
|
|||
seed := 1
|
||||
);
|
||||
|
||||
Plot.Title('MakeMoons синтетический датасет');
|
||||
Plot.Title :='MakeMoons синтетический датасет';
|
||||
|
||||
Plot.Points(X.Col(0), X.Col(1), LabelsToInts(y), size := 4);
|
||||
end.
|
||||
20
InstallerSamples/MachineLearning/13_Seminars/seminar0.pas
Normal file
20
InstallerSamples/MachineLearning/13_Seminars/seminar0.pas
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
uses MLABC;
|
||||
|
||||
begin
|
||||
var X: Matrix :=
|
||||
[[1.0,1.0],[1.2,1.3],[1.5,1.2],[1.8,1.6],[2.0,1.9],[2.2,2.1],
|
||||
[2.4,2.3],[2.6,2.5],[2.8,2.7],[3.0,3.0],[3.2,3.1],[3.4,3.3]];
|
||||
|
||||
var y: Vector :=
|
||||
[0.0,0.0,0.0,0.0,0.0,0.0, 1.0,1.0,1.0,1.0,1.0,1.0];
|
||||
|
||||
var (Xtrain, Xtest, ytrain, ytest) :=
|
||||
Validation.TrainTestSplit(X, y, 0.3, seed := 4);
|
||||
|
||||
var model := new LogisticRegression;
|
||||
model.Fit(Xtrain, ytrain);
|
||||
|
||||
var pred := model.Predict(Xtest);
|
||||
|
||||
Println('Accuracy:', Metrics.Accuracy(ytest, pred):0:3);
|
||||
end.
|
||||
21
InstallerSamples/MachineLearning/13_Seminars/seminar1.pas
Normal file
21
InstallerSamples/MachineLearning/13_Seminars/seminar1.pas
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
uses MLABC;
|
||||
begin
|
||||
var df := CsvLoader.Load('towns_russia.csv', inferCategorical := true);
|
||||
|
||||
df := df.Select(['city','population','lat','lon','region_name','federal_district']);
|
||||
|
||||
df.Schema.Println;
|
||||
|
||||
// Заполняем пропуски в числовых столбцах средним значением
|
||||
var imputer := new Imputer('population', 'lat', 'lon');
|
||||
df := imputer.FitTransform(df);
|
||||
|
||||
// Кодируем категориальные признаки
|
||||
var encoder := new LabelEncoder('region_name');
|
||||
df := encoder.FitTransform(df);
|
||||
|
||||
var encoder2 := new LabelEncoder('federal_district');
|
||||
df := encoder2.FitTransform(df);
|
||||
|
||||
df.PrintPreview(6);
|
||||
end.
|
||||
38
InstallerSamples/MachineLearning/13_Seminars/seminar2.pas
Normal file
38
InstallerSamples/MachineLearning/13_Seminars/seminar2.pas
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
uses MLABC;
|
||||
|
||||
begin
|
||||
var df := CsvLoader.Load('towns_russia.csv',
|
||||
inferCategorical := true);
|
||||
|
||||
df := df.Select([
|
||||
'population',
|
||||
'lat',
|
||||
'lon',
|
||||
'region_name',
|
||||
'federal_district'
|
||||
]);
|
||||
|
||||
// Препроцессинг
|
||||
var imputer := new Imputer('population', 'lat', 'lon');
|
||||
df := imputer.FitTransform(df);
|
||||
|
||||
var le1 := new LabelEncoder('region_name');
|
||||
df := le1.FitTransform(df);
|
||||
|
||||
var le2 := new LabelEncoder('federal_district');
|
||||
df := le2.FitTransform(df);
|
||||
|
||||
// Явно задаём признаки
|
||||
var features := ['lat', 'lon', 'region_name', 'federal_district'];
|
||||
|
||||
var X := df.ToMatrix(features);
|
||||
var y := df.ToVector('population');
|
||||
|
||||
// Модель
|
||||
var model := new LinearRegression;
|
||||
model.Fit(X, y);
|
||||
|
||||
var preds := model.Predict(X);
|
||||
|
||||
Println('RMSE:', Metrics.RMSE(y, preds):0:3);
|
||||
end.
|
||||
31
InstallerSamples/MachineLearning/13_Seminars/seminar3.pas
Normal file
31
InstallerSamples/MachineLearning/13_Seminars/seminar3.pas
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
uses MLABC;
|
||||
|
||||
begin
|
||||
var df := CsvLoader.Load('towns_russia.csv', inferCategorical := true);
|
||||
df := df.Select(['population', 'lat', 'lon', 'region_name', 'federal_district']);
|
||||
|
||||
var imputer := new Imputer('population', 'lat', 'lon');
|
||||
df := imputer.FitTransform(df);
|
||||
|
||||
var le1 := new LabelEncoder('region_name');
|
||||
df := le1.FitTransform(df);
|
||||
|
||||
var le2 := new LabelEncoder('federal_district');
|
||||
df := le2.FitTransform(df);
|
||||
|
||||
var features := ['lat', 'lon', 'region_name', 'federal_district'];
|
||||
|
||||
var X := df.ToMatrix(features);
|
||||
var y := df.ToVector('population');
|
||||
|
||||
var scaler := new StandardScaler;
|
||||
scaler.Fit(X);
|
||||
var Xscaled := scaler.Transform(X);
|
||||
|
||||
var model := new LinearRegression;
|
||||
model.Fit(Xscaled, y);
|
||||
|
||||
var preds := model.Predict(Xscaled);
|
||||
|
||||
Println('RMSE:', Metrics.RMSE(y, preds):0:3);
|
||||
end.
|
||||
29
InstallerSamples/MachineLearning/13_Seminars/seminar4.pas
Normal file
29
InstallerSamples/MachineLearning/13_Seminars/seminar4.pas
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
uses MLABC;
|
||||
|
||||
begin
|
||||
var ds := Datasets.MoscowHousing;
|
||||
var df := ds.Data;
|
||||
|
||||
var features := ['rooms', 'area', 'kitchen_area', 'floor', 'floors_total', 'metro_minutes', 'renovation'];
|
||||
|
||||
var target := 'price';
|
||||
|
||||
var (trainDf, testDf) := df.TrainTestSplit(0.2, 42);
|
||||
|
||||
var pipe :=
|
||||
DataPipeline.Build( // сборка pipeline: target + features + шаги
|
||||
target, // целевая переменная
|
||||
features, // список признаков
|
||||
new OneHotEncoder('renovation'), // DataFrame-уровень: кодирование категории
|
||||
// Внутри - преобразование .ToMatrix .ToVector
|
||||
new StandardScaler, // Matrix-уровень: масштабирование признаков
|
||||
new LinearRegression // модель (всегда последний шаг)
|
||||
);
|
||||
|
||||
pipe.Fit(trainDf); // обучение: последовательно encoding → scaling → model
|
||||
|
||||
var pred := pipe.Predict(testDf); // предсказание: те же преобразования
|
||||
var y := testDf.ToVector(target);
|
||||
|
||||
Println('R²:', Metrics.R2(y, pred):0:3);
|
||||
end.
|
||||
1118
InstallerSamples/MachineLearning/13_Seminars/towns_russia.csv
Normal file
1118
InstallerSamples/MachineLearning/13_Seminars/towns_russia.csv
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1 +1 @@
|
|||
3.11.1.3783
|
||||
3.11.1.3784
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
!define VERSION '3.11.1.3783'
|
||||
!define VERSION '3.11.1.3784'
|
||||
|
|
|
|||
|
|
@ -238,7 +238,9 @@ type
|
|||
///
|
||||
/// Пример:
|
||||
/// var ds := Datasets.Iris;
|
||||
/// var (X,y) := ds.ToXYInt;
|
||||
/// var df := ds.Data;
|
||||
/// var X := df.ToMatrix(ds.Features);
|
||||
/// var y := df.EncodeLabels(ds.Target);
|
||||
static function Iris: Dataset;
|
||||
|
||||
/// Датасет цен на квартиры (задача регрессии)
|
||||
|
|
@ -648,7 +650,7 @@ begin
|
|||
begin
|
||||
var row := idx[i];
|
||||
|
||||
y[row] := -1;
|
||||
y[row] := rnd.Next(centers);
|
||||
|
||||
for var j := 0 to nFeatures - 1 do
|
||||
X[row, j] := (rnd.NextDouble * 2 - 1) * centerBox;
|
||||
|
|
|
|||
|
|
@ -1276,6 +1276,9 @@ type
|
|||
|
||||
/// Создаёт глубокую копию модели.
|
||||
function Clone: IModel;
|
||||
|
||||
/// Количество кластеров
|
||||
function ClustersCount: integer;
|
||||
|
||||
/// Количество кластеров.
|
||||
property NClusters: integer read fNClusters;
|
||||
|
|
@ -1345,7 +1348,9 @@ type
|
|||
function Clone: IModel;
|
||||
|
||||
property Labels: array of integer read fLabels;
|
||||
property ClusterCount: integer read fClusterCount;
|
||||
|
||||
/// Количество кластеров, найденное моделью
|
||||
function ClustersCount: integer;
|
||||
|
||||
function Name: string := Self.GetType.Name;
|
||||
|
||||
|
|
@ -1972,6 +1977,8 @@ const
|
|||
'Model (type: {0}) is not an unsupervised model';
|
||||
ER_DBSCAN_PREDICT_ONLY_TRAIN_DATA =
|
||||
'DBSCAN: Predict поддерживается только для обучающей выборки!!DBSCAN: Predict is only supported for training data';
|
||||
ER_MODEL_NOT_FITTED =
|
||||
'Модель "{0}" не обучена. Сначала вызовите Fit()|Model "{0}" is not fitted. Call Fit() first';
|
||||
|
||||
{$endregion ErrConstants}
|
||||
|
||||
|
|
@ -7168,6 +7175,14 @@ begin
|
|||
Result := km;
|
||||
end;
|
||||
|
||||
function KMeans.ClustersCount: integer;
|
||||
begin
|
||||
if not fFitted then
|
||||
ArgumentError(ER_MODEL_NOT_FITTED, 'KMeans');
|
||||
|
||||
Result := fCenters.RowCount;
|
||||
end;
|
||||
|
||||
//-----------------------------
|
||||
// DBSCAN
|
||||
//-----------------------------
|
||||
|
|
@ -7343,6 +7358,8 @@ begin
|
|||
Result := m;
|
||||
end;
|
||||
|
||||
function DBSCAN.ClustersCount: integer := fClusterCount;
|
||||
|
||||
//-----------------------------
|
||||
// Pipeline
|
||||
//-----------------------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue