Новые примеры ML и исправление старых

This commit is contained in:
Mikhalkovich Stanislav 2026-05-20 21:25:14 +03:00
parent 15f45c258f
commit 9e36ff2abc
35 changed files with 732 additions and 66 deletions

View file

@ -43,10 +43,10 @@ begin
var labels := model.PredictLabels(X); var labels := model.PredictLabels(X);
// Получаем названия городов // Получаем названия городов
var cities := df.GetStrColumn('city'); var cities := df.Str('city');
// Получаем численность населения городов // Получаем численность населения городов
var populations := df.GetFloatColumn('population'); var populations := df.Float('population');
// Выводим, сколько кластеров нашёл алгоритм // Выводим, сколько кластеров нашёл алгоритм
Println($'Число кластеров: {model.ClustersCount}'); Println($'Число кластеров: {model.ClustersCount}');

View file

@ -1,4 +1,4 @@
// Пример табличной предобработки: // Пример табличной предобработки:
// сначала заполняем пропуски в числовом столбце, // сначала заполняем пропуски в числовом столбце,
// затем кодируем категориальный столбец числами. // затем кодируем категориальный столбец числами.
uses MLABC; uses MLABC;
@ -18,13 +18,13 @@ city,population,region
Println; Println;
// Заполняем пропуск в числовом столбце средним значением // Заполняем пропуск в числовом столбце средним значением
var imputer := new Imputer(['population']); var imp := new Imputer(['population']);
df := imputer.FitTransform(df); df := imp.FitTransform(df);
// Кодируем названия регионов числами 0, 1, 2, ... // Кодируем названия регионов числами 0, 1, 2, ...
var encoder := new OrdinalEncoder('region'); var encoder := new OrdinalEncoder('region');
df := encoder.FitTransform(df); df := encoder.FitTransform(df);
Println('После Imputer и LabelEncoder:'); Println('После Imputer и OrdinalEncoder:');
df.Print; df.Print;
end. end.

View file

@ -0,0 +1,33 @@
// Confusion matrix для классификации датасета Iris.
uses MLABC, PlotML;
begin
var ds := Datasets.Iris;
var (train, test) := ds.StratifiedTrainTestSplit(0.2, 42);
var Xtrain := train.Data.ToMatrix(train.Features);
var Xtest := test.Data.ToMatrix(test.Features);
var scaler := new StandardScaler;
Xtrain := scaler.FitTransform(Xtrain);
Xtest := scaler.Transform(Xtest);
var encoder := new LabelEncoder;
var ytrain := encoder.FitTransform(train);
var ytest := encoder.Transform(test);
var model := new LogisticRegression;
model.Fit(Xtrain, ytrain);
var pred := model.Predict(Xtest);
var cm := new ConfusionMatrix(ytest, pred);
var acc := Metrics.Accuracy(ytest, pred);
Plot.ConfusionMatrix(cm, encoder.Classes{, normalize := MatrixNormalization.Rows});
Plot.Title := $'Iris: LogisticRegression, accuracy = {acc:F3}';
Plot.XLabel := 'Предсказанный класс';
Plot.YLabel := 'Истинный класс';
end.

View file

@ -0,0 +1,29 @@
// Confusion matrix для Iris с использованием DataPipeline.
// Рекомендуемый стиль - он проще и явно показывает намерения
uses MLABC, PlotML;
begin
var ds := Datasets.Iris;
var (train, test) := ds.StratifiedTrainTestSplit(0.2, 42);
var pipe := DataPipeline.Build(
TaskKind.tkClassification,
ds.Target,
ds.Features,
new StandardScaler,
new LogisticRegression
);
pipe.Fit(train.Data);
var pred := pipe.Predict(test.Data);
var ytest := pipe.GetEncodedLabels(test.Data);
var cm := new ConfusionMatrix(ytest, pred);
var acc := Metrics.Accuracy(ytest, pred);
Plot.ConfusionMatrix(cm, pipe.GetClassLabels{, normalize := MatrixNormalization.Rows});
Plot.Title := $'Iris: DataPipeline, accuracy = {acc:F3}';
Plot.XLabel := 'Предсказанный класс';
Plot.YLabel := 'Истинный класс';
end.

View file

@ -8,6 +8,6 @@ begin
Plot.Hist(price, bins := 40); Plot.Hist(price, bins := 40);
Plot.Title := 'Распределение цен на квартиры в Москве'; Plot.Title := 'Распределение цен на квартиры в Москве';
Plot.XLabel('Цена (руб)'); Plot.XLabel := 'Цена (руб)';
Plot.YLabel('Количество'); Plot.YLabel := 'Количество';
end. end.

View file

@ -9,7 +9,7 @@ begin
Plot.Points(area, price, size := 3); Plot.Points(area, price, size := 3);
Plot.XLabel('Площадь (м²)'); Plot.XLabel := 'Площадь (м²)';
Plot.YLabel('Цена (руб)'); Plot.YLabel := 'Цена (руб)';
Plot.Title := 'Цена квартиры vs площадь'; Plot.Title := 'Цена квартиры vs площадь';
end. end.

View file

@ -9,7 +9,7 @@ begin
Plot.Points(metro.Data.ConvertAll(x -> x*1.0), price.Data, size := 3); Plot.Points(metro.Data.ConvertAll(x -> x*1.0), price.Data, size := 3);
Plot.XLabel('Минуты до метро'); Plot.XLabel := 'Минуты до метро';
Plot.YLabel('Цена (руб)'); Plot.YLabel := 'Цена (руб)';
Plot.Title := 'Зависимость цены квартиры от расстояния до метро'; Plot.Title := 'Зависимость цены квартиры от расстояния до метро';
end. end.

View file

@ -8,5 +8,7 @@ begin
df.Schema.Println; df.Schema.Println;
df.PrintInfo; df.PrintInfo;
Println; Println;
ds.Info;
Println;
df.Print; df.Print;
end. end.

View file

@ -32,7 +32,7 @@ begin
marker := MarkerType.Circle marker := MarkerType.Circle
); );
Plot.XLabel('Долгота'); Plot.XLabel := 'Долгота';
Plot.YLabel('Широта'); Plot.YLabel := 'Широта';
Plot.Title := 'Кластеры городов России'; Plot.Title := 'Кластеры городов России';
end. end.

View file

@ -76,9 +76,7 @@ begin
var labels := model.PredictLabels(X); var labels := model.PredictLabels(X);
var counts := new Dictionary<integer, integer>(); var counts := labels.EachCount;
foreach var l in labels do
counts[l] := counts.Get(l, 0) + 1;
var n := df.RowCount; var n := df.RowCount;

View file

@ -7,10 +7,10 @@ begin
var age := df.ToVector('Возраст'); var age := df.ToVector('Возраст');
var fare := df.ToVector('ЦенаБилета'); var fare := df.ToVector('ЦенаБилета');
var y := df.GetIntColumn('Выжил'); var y := df.Int('Выжил');
Plot.Points(age, fare, y, size := 5); Plot.Points(age, fare, y, size := 5);
Plot.XLabel('Возраст'); Plot.XLabel := 'Возраст';
Plot.YLabel('Цена билета'); Plot.YLabel := 'Цена билета';
Plot.Title := 'Титаник: возраст, цена билета и выживание'; Plot.Title := 'Титаник: возраст, цена билета и выживание';
end. end.

View file

@ -18,6 +18,6 @@ begin
Plot.HistMany([diedAges,survivedAges], bins := 20, colors := [Colors.IndianRed, Colors.SteelBlue], alpha := 0.45, legend := ['не выжили','выжили']); Plot.HistMany([diedAges,survivedAges], bins := 20, colors := [Colors.IndianRed, Colors.SteelBlue], alpha := 0.45, legend := ['не выжили','выжили']);
Plot.Title := 'Титаник: возраст выживших (голубой) и невыживших (красный)'; Plot.Title := 'Титаник: возраст выживших (голубой) и невыживших (красный)';
Plot.XLabel('Возраст'); Plot.XLabel := 'Возраст';
Plot.YLabel('Число пассажиров'); Plot.YLabel := 'Число пассажиров';
end. end.

View file

@ -4,45 +4,39 @@ begin
var ds := Datasets.TitanicRu; var ds := Datasets.TitanicRu;
var df := ds.Data.Drop(['Id', 'Имя']); var df := ds.Data.Drop(['Id', 'Имя']);
// Заполняем пропуски.
var ageImputer := new Imputer(['Возраст']);
df := ageImputer.FitTransform(df);
var portImputer := new Imputer('Саутгемптон', ['ПортПосадки']);
df := portImputer.FitTransform(df);
// Кодируем категориальные признаки числами.
var sexEncoder := new OrdinalEncoder('Пол');
df := sexEncoder.FitTransform(df);
var portEncoder := new OrdinalEncoder('ПортПосадки');
df := portEncoder.FitTransform(df);
var features := ['Класс', 'Пол', 'Возраст', 'БратьяИСупруги', 'РодителиИДети', 'ЦенаБилета', 'ПортПосадки']; var features := ['Класс', 'Пол', 'Возраст', 'БратьяИСупруги', 'РодителиИДети', 'ЦенаБилета', 'ПортПосадки'];
var X := df.ToMatrix(features); var target := 'Выжил';
var y := df.GetIntColumn('Выжил');
var (Xtrain, Xtest, ytrain, ytest) := Validation.TrainTestSplit(X, y, testRatio := 0.2, seed := 42); var (trainDf, testDf) :=
df.StratifiedTrainTestSplit(ds.Target, testRatio := 0.2, seed := 42);
var scaler := new StandardScaler; var prep :=
scaler.Fit(Xtrain); DataPipeline.BuildPreprocessing(
var XtrainScaled := scaler.Transform(Xtrain); TaskKind.tkClassification,
var XtestScaled := scaler.Transform(Xtest); target,
features,
new Imputer(['Возраст']),
new Imputer('Саутгемптон', ['ПортПосадки']),
new OneHotEncoder('Пол'),
new OneHotEncoder('ПортПосадки'),
new StandardScaler
);
var lr := new LogisticRegression(learningRate := 0.01, epochs := 2000); var pipeLR := prep.WithModel(new LogisticRegression(learningRate := 0.01, epochs := 2000));
lr.Fit(XtrainScaled, ytrain); pipeLR.Fit(trainDf);
var predLR := lr.Predict(XtestScaled); var predLR := pipeLR.Predict(testDf);
var y := pipeLR.GetEncodedLabels(testDf);
var tree := new DecisionTreeClassifier(maxDepth := 5, minSamplesLeaf := 3, minSamplesSplit := 6); var pipeTree := prep.WithModel(new DecisionTreeClassifier(maxDepth := 5, minSamplesLeaf := 3, minSamplesSplit := 6));
tree.Fit(Xtrain, ytrain); pipeTree.Fit(trainDf);
var predTree := tree.Predict(Xtest); var predTree := pipeTree.Predict(testDf);
var forest := new RandomForestClassifier(nTrees := 100, maxDepth := 6, minSamplesLeaf := 3, minSamplesSplit := 6); var pipeForest := prep.WithModel(new RandomForestClassifier(nTrees := 100, maxDepth := 6, minSamplesLeaf := 3, minSamplesSplit := 6));
forest.Fit(Xtrain, ytrain); pipeForest.Fit(trainDf);
var predForest := forest.Predict(Xtest); var predForest := pipeForest.Predict(testDf);
Println('Сравнение моделей на TitanicRu'); Println('Сравнение моделей на TitanicRu');
Println($'LogisticRegression: Accuracy = {Metrics.Accuracy(ytest, predLR):F3}'); Println($'LogisticRegression: Accuracy = {Metrics.Accuracy(y, predLR):F3}');
Println($'DecisionTreeClassifier: Accuracy = {Metrics.Accuracy(ytest, predTree):F3}'); Println($'DecisionTreeClassifier: Accuracy = {Metrics.Accuracy(y, predTree):F3}');
Println($'RandomForestClassifier: Accuracy = {Metrics.Accuracy(ytest, predForest):F3}'); Println($'RandomForestClassifier: Accuracy = {Metrics.Accuracy(y, predForest):F3}');
end. end.

View file

@ -32,7 +32,7 @@ begin
var testAccuracy := Metrics.Accuracy(y, pred); var testAccuracy := Metrics.Accuracy(y, pred);
var total := 0.0; var total := 0.0;
var folds := Validation.StratifiedKFold(df.GetIntColumn('Выжил'), 5, seed := 1); var folds := Validation.StratifiedKFold(df.Int('Выжил'), 5, seed := 1);
var foldsCount := 0; var foldsCount := 0;
foreach var (trainIdx, testIdx) in folds do foreach var (trainIdx, testIdx) in folds do

View file

@ -18,7 +18,7 @@ begin
var features := ['Класс', 'Пол', 'Возраст', 'БратьяИСупруги', 'РодителиИДети', 'ЦенаБилета', 'ПортПосадки']; var features := ['Класс', 'Пол', 'Возраст', 'БратьяИСупруги', 'РодителиИДети', 'ЦенаБилета', 'ПортПосадки'];
var X := df.ToMatrix(features); var X := df.ToMatrix(features);
var y := df.GetIntColumn('Выжил'); var y := df.Int('Выжил');
var model := new RandomForestClassifier(nTrees := 100, maxDepth := 6, minSamplesLeaf := 3, minSamplesSplit := 6, seed := 42); var model := new RandomForestClassifier(nTrees := 100, maxDepth := 6, minSamplesLeaf := 3, minSamplesSplit := 6, seed := 42);
model.Fit(X, y); model.Fit(X, y);

View file

@ -2,7 +2,7 @@ uses MLABC;
function SurvivalRate(df: DataFrame): real; function SurvivalRate(df: DataFrame): real;
begin begin
Result := df.GetIntColumn('Выжил').Average; Result := df.Int('Выжил').Average;
end; end;
begin begin

View file

@ -0,0 +1,35 @@
uses MLABC, PlotML;
begin
var ds := Datasets.TitanicRu;
var features := ['Класс', 'Пол', 'Возраст', 'БратьяИСупруги', 'РодителиИДети', 'ЦенаБилета', 'ПортПосадки'];
var df := ds.Data.Drop(['Id', 'Имя']);
var (trainDf, testDf) :=
df.StratifiedTrainTestSplit(ds.Target, testRatio := 0.2, seed := 42);
var pipe :=
DataPipeline.Build(
TaskKind.tkClassification,
ds.Target,
features,
new Imputer(['Возраст']),
new Imputer('Саутгемптон', ['ПортПосадки']),
new OneHotEncoder('Пол'),
new OneHotEncoder('ПортПосадки'),
new StandardScaler,
new LogisticRegression(learningRate := 0.1, epochs := 2000)
);
pipe.Fit(trainDf);
var pred := pipe.Predict(testDf);
var y := pipe.GetEncodedLabels(testDf);
var cm := new ConfusionMatrix(y, pred);
var acc := Metrics.Accuracy(y, pred);
Plot.ConfusionMatrix(cm, ['не выжил', 'выжил']);
Plot.Title := $'TitanicRu: DataPipeline, accuracy = {acc:F3}';
Plot.XLabel := 'Предсказанный класс';
Plot.YLabel := 'Истинный класс';
end.

View file

@ -0,0 +1,39 @@
uses MLABC;
begin
var ds := Datasets.TitanicRu;
var features := ['Класс', 'Пол', 'Возраст', 'БратьяИСупруги', 'РодителиИДети', 'ЦенаБилета', 'ПортПосадки'];
var df := ds.Data.Drop(['Id', 'Имя']);
var (trainDf, testDf) :=
df.StratifiedTrainTestSplit(ds.Target, testRatio := 0.2, seed := 42);
var pipe :=
DataPipeline.Build(
TaskKind.tkClassification,
ds.Target,
features,
new Imputer(['Возраст']),
new Imputer('Саутгемптон', ['ПортПосадки']),
new OneHotEncoder('Пол'),
new OneHotEncoder('ПортПосадки'),
new StandardScaler,
new RandomForestClassifier(nTrees := 100, maxDepth := 6, minSamplesLeaf := 3, minSamplesSplit := 6)
);
pipe.Fit(trainDf);
var pred := pipe.Predict(testDf);
var y := pipe.GetEncodedLabels(testDf);
Println('TitanicRu: Precision, Recall и F1');
Println;
Println('Precision — какая доля пассажиров, предсказанных как "выжил", действительно выжила.');
Println('Recall — какую долю реально выживших пассажиров модель нашла.');
Println('F1 — общий баланс между Precision и Recall.');
Println;
Println($'Accuracy = {Metrics.Accuracy(y, pred):F3}');
Println($'Precision = {Metrics.Precision(y, pred):F3}');
Println($'Recall = {Metrics.Recall(y, pred):F3}');
Println($'F1 = {Metrics.F1(y, pred):F3}');
end.

View file

@ -0,0 +1,65 @@
uses MLABC;
function LabelText(v: integer): string;
begin
Result := if v = 1 then 'выжил' else 'не выжил';
end;
begin
var ds := Datasets.TitanicRu;
var features := ['Класс', 'Пол', 'Возраст', 'БратьяИСупруги', 'РодителиИДети', 'ЦенаБилета', 'ПортПосадки'];
var fullDf := ds.Data;
var (trainFull, testFull) :=
fullDf.StratifiedTrainTestSplit(ds.Target, testRatio := 0.2, seed := 42);
var trainDf := trainFull.Drop(['Id', 'Имя']);
var testDf := testFull.Drop(['Id', 'Имя']);
var pipe :=
DataPipeline.Build(
TaskKind.tkClassification,
ds.Target,
features,
new Imputer(['Возраст']),
new Imputer('Саутгемптон', ['ПортПосадки']),
new OneHotEncoder('Пол'),
new OneHotEncoder('ПортПосадки'),
new StandardScaler,
new RandomForestClassifier(nTrees := 100, maxDepth := 6, minSamplesLeaf := 3, minSamplesSplit := 6)
);
pipe.Fit(trainDf);
var pred := pipe.Predict(testDf);
var y := pipe.GetEncodedLabels(testDf);
var predInt := pred.ToIntArray;
var yInt := y.ToIntArray;
var cur := testFull.GetCursor;
Println('TitanicRu: пассажиры, классифицированные неправильно');
Println;
var shown := 0;
while cur.MoveNext do
begin
var i := cur.Position;
if yInt[i] <> predInt[i] then
begin
var id := cur.Int('Id');
var name := cur.Str('Имя');
var sex := cur.Str('Пол');
var pclass := cur.Int('Класс');
var age := cur.Float('Возраст');
var fare := cur.Float('ЦенаБилета');
Println($'Id={id}, {name}');
Println($' Пол={sex}, класс={pclass}, возраст={age:F1}, билет={fare:F1}');
Println($' Истина: {LabelText(yInt[i])}, прогноз: {LabelText(predInt[i])}');
Println;
shown += 1;
if shown >= 10 then break;
end;
end;
end.

View file

@ -0,0 +1,52 @@
uses MLABC;
function BuildPipe(features: array of string): DataPipeline;
begin
Result :=
DataPipeline.Build(
TaskKind.tkClassification,
'Выжил',
features,
new Imputer(['Возраст']),
new Imputer('Саутгемптон', ['ПортПосадки']),
new OneHotEncoder('Пол'),
new OneHotEncoder('ПортПосадки'),
new StandardScaler,
new RandomForestClassifier(nTrees := 100, maxDepth := 6, minSamplesLeaf := 3, minSamplesSplit := 6)
);
end;
function TestAccuracy(df: DataFrame; features: array of string): real;
begin
var (trainDf, testDf) :=
df.StratifiedTrainTestSplit('Выжил', testRatio := 0.2, seed := 42);
var pipe := BuildPipe(features);
pipe.Fit(trainDf);
var pred := pipe.Predict(testDf);
var y := pipe.GetEncodedLabels(testDf);
Result := Metrics.Accuracy(y, pred);
end;
begin
var ds := Datasets.TitanicRu;
var df := ds.Data.Drop(['Id', 'Имя']);
var allFeatures :=
SetOf('Класс', 'Пол', 'Возраст', 'БратьяИСупруги', 'РодителиИДети', 'ЦенаБилета', 'ПортПосадки');
var noSex := (allFeatures - ['Пол']).ToArray;
var noClass := (allFeatures - ['Класс']).ToArray;
var accAll := TestAccuracy(df, allFeatures.ToArray);
var accNoSex := TestAccuracy(df, noSex);
var accNoClass := TestAccuracy(df, noClass);
Println('TitanicRu: влияние признаков на качество модели');
Println;
Println('Идея примера: убираем один важный признак и смотрим, насколько хуже становится классификация.');
Println;
Println($'Все признаки: Accuracy = {accAll:F3}');
Println($'Без признака "Пол": Accuracy = {accNoSex:F3}');
Println($'Без признака "Класс": Accuracy = {accNoClass:F3}');
end.

View file

@ -0,0 +1,11 @@
uses MLABC;
begin
Datasets.Language := 'ru';
var ds := Datasets.UsedCarsPrice;
ds.Info;
Println;
ds.Data.Print(20);
end.

View file

@ -0,0 +1,12 @@
uses MLABC, PlotML;
begin
var ds := Datasets.UsedCarsPrice;
var df := ds.Data.Filter(r -> r.Float('price_k_rub') <= 6000);
var price := df.ToVector('price_k_rub');
Plot.Hist(price, bins := 30);
Plot.XLabel := 'Цена, тыс. руб.';
Plot.YLabel := 'Число автомобилей';
Plot.Title := 'UsedCars: распределение цен до 6000 тыс. руб.';
end.

View file

@ -0,0 +1,14 @@
uses MLABC, PlotML;
begin
var ds := Datasets.UsedCarsPrice;
var df := ds.Data.Filter(r -> r.Float('price_k_rub') <= 6000);
var mileage := df.ToVector('mileage_km');
var price := df.ToVector('price_k_rub');
Plot.Points(mileage, price, size := 4);
Plot.XLabel := 'Пробег, км';
Plot.YLabel := 'Цена, тыс. руб.';
Plot.Title := 'UsedCars: цена и пробег';
end.

View file

@ -0,0 +1,17 @@
uses MLABC, PlotML;
begin
var ds := Datasets.UsedCarsPrice;
var df := ds.Data.Filter(r -> r.Float('price_k_rub') <= 6000);
var names := Arr('year', 'mileage_1000km', 'l_100km', 'engineSize');
var X := df.ToMatrix(Arr('year', 'mileage_km', 'l_100km', 'engineSize'));
for var i := 0 to X.RowCount - 1 do
X[i, 1] := X[i, 1] / 1000.0;
var price := df.ToVector('price_k_rub');
Plot.PairPlot(X.Data, price.Data, names, bins := 6, maxPoints := 2000);
Plot.Title := 'UsedCars: признаки, окрашенные по цене';
end.

View file

@ -0,0 +1,15 @@
uses MLABC, PlotML;
begin
var ds := Datasets.UsedCarsPrice;
var df := ds.Data.Filter(r -> r.Float('price_k_rub') <= 6000);
var year := df.ToVector('year');
var price := df.ToVector('price_k_rub');
var make := df.EncodeLabels('Make');
Plot.Points(year, price, make, size := 4);
Plot.XLabel := 'Год выпуска';
Plot.YLabel := 'Цена, тыс. руб.';
Plot.Title := 'UsedCars: цена по годам и маркам';
end.

View file

@ -0,0 +1,45 @@
uses MLABC;
begin
var ds := Datasets.UsedCarsPrice;
var df := ds.Data;
var features := [
'model',
'year',
'transmission',
'mileage_km',
'fuelType',
'l_100km',
'engineSize',
'Make'
];
var target := 'price_k_rub';
var (trainDf, testDf) := df.TrainTestSplit(0.2, seed := 42);
var pipe :=
DataPipeline.Build(
TaskKind.tkRegression,
target,
features,
new OrdinalEncoder('model'),
new OneHotEncoder('transmission'),
new OneHotEncoder('fuelType'),
new OneHotEncoder('Make'),
new StandardScaler,
new DecisionTreeRegressor(10)
);
pipe.Fit(trainDf);
var pred := pipe.Predict(testDf);
var y := testDf.ToVector(target);
Println('Прогнозирование цены автомобилей (DecisionTreeRegressor)');
Println($'MAE = {Metrics.MAE(y, pred):F0}');
Println($'RMSE = {Metrics.RMSE(y, pred):F0}');
Println($'R² = {Metrics.R2(y, pred):F3}');
end.

View file

@ -0,0 +1,48 @@
uses MLABC;
begin
var ds := Datasets.UsedCarsPrice;
var df := ds.Data;
var features := [
'model',
'year',
'transmission',
'mileage_km',
'fuelType',
'l_100km',
'engineSize',
'Make'
];
var target := 'price_k_rub';
var (trainDf, testDf) := df.TrainTestSplit(0.2, seed := 42);
var prep :=
DataPipeline.BuildPreprocessing(
TaskKind.tkRegression,
target,
features,
new OrdinalEncoder('model'),
new OneHotEncoder('transmission'),
new OneHotEncoder('fuelType'),
new OneHotEncoder('Make'),
new StandardScaler
);
var pipeTree := prep.WithModel(new DecisionTreeRegressor(12));
pipeTree.Fit(trainDf);
var predTree := pipeTree.Predict(testDf);
var pipeForest := prep.WithModel(new RandomForestRegressor(12, 50));
pipeForest.Fit(trainDf);
var predForest := pipeForest.Predict(testDf);
var y := testDf.ToVector(target);
Println('Сравнение моделей регрессии');
Println($'DecisionTreeRegressor: R² = {Metrics.R2(y, predTree):F3}');
Println($'RandomForestRegressor: R² = {Metrics.R2(y, predForest):F3}');
end.

View file

@ -0,0 +1,64 @@
uses MLABC;
begin
var ds := Datasets.UsedCarsPrice;
var df := ds.Data;
var features := [
'model',
'year',
'transmission',
'mileage_km',
'fuelType',
'l_100km',
'engineSize',
'Make'
];
var target := 'price_k_rub';
var (trainDf, testDf) := df.TrainTestSplit(0.2, seed := 42);
var prep :=
DataPipeline.BuildPreprocessing(
TaskKind.tkRegression,
target,
features,
new OrdinalEncoder('model'),
new OneHotEncoder('transmission'),
new OneHotEncoder('fuelType'),
new OneHotEncoder('Make'),
new StandardScaler
);
var pipe := prep.WithModel(new RandomForestRegressor(12, 50));
pipe.Fit(trainDf);
var pred := pipe.Predict(testDf);
var y := testDf.ToVector(target);
var testR2 := Metrics.R2(y, pred);
var total := 0.0;
var folds := Validation.KFold(df.RowCount, 5, seed := 1);
var foldsCount := 0;
foreach var (trainIdx, testIdx) in folds do
begin
var foldTrain := df.TakeRows(trainIdx);
var foldTest := df.TakeRows(testIdx);
var foldPipe := prep.WithModel(new RandomForestRegressor(12, 50));
foldPipe.Fit(foldTrain);
var foldPred := foldPipe.Predict(foldTest);
var foldY := foldTest.ToVector(target);
total += Metrics.R2(foldY, foldPred);
foldsCount += 1;
end;
var cvR2 := total / foldsCount;
Println('Оценка RandomForestRegressor двумя способами');
Println($'R² на тестовой выборке: {testR2:F3}');
Println($'Средний R² по кросс-валидации: {cvR2:F3}');
end.

View file

@ -0,0 +1,71 @@
uses MLABC;
begin
var ds := Datasets.UsedCarsPrice;
var df := ds.Data;
// В этом примере смотрим не только на R²,
// но и на конкретные ошибки модели для отдельных автомобилей.
// Остаток = истинная цена - предсказанная цена.
// Если остаток положительный, модель занизила цену.
// Если отрицательный, модель завысила цену.
var features := [
'model',
'year',
'transmission',
'mileage_km',
'fuelType',
'l_100km',
'engineSize',
'Make'
];
var target := 'price_k_rub';
var (trainDf, testDf) := df.TrainTestSplit(0.2, seed := 42);
var pipe :=
DataPipeline.Build(
TaskKind.tkRegression,
target,
features,
new OrdinalEncoder('model'),
new OneHotEncoder('transmission'),
new OneHotEncoder('fuelType'),
new OneHotEncoder('Make'),
new StandardScaler,
new RandomForestRegressor(12, 50)
);
pipe.Fit(trainDf);
var pred := pipe.Predict(testDf);
var y := testDf.ToVector(target);
var models := testDf.Str('model');
var makes := testDf.Str('Make');
var years := testDf.Int('year');
var idx := Arr(0..pred.Length - 1);
idx := idx.OrderByDescending(i -> Abs(y[i] - pred[i])).ToArray;
Println('UsedCars: самые большие ошибки модели');
Println;
Println('Остаток = истинная цена - предсказанная цена.');
Println('Положительный остаток означает, что модель занизила цену.');
Println('Отрицательный остаток означает, что модель завысила цену.');
Println;
for var k := 0 to Min(9, idx.Length - 1) do
begin
var i := idx[k];
var residual := y[i] - pred[i];
Println($'{makes[i]} {models[i]}, {years[i]}');
Println($' Истинная цена: {y[i]:F0} тыс. руб.');
Println($' Прогноз: {pred[i]:F0} тыс. руб.');
Println($' Остаток: {residual:F0} тыс. руб.');
Println;
end;
end.

View file

@ -13,8 +13,8 @@ begin
// --- визуализация // --- визуализация
Plot.Title('MakeRegression синтетический датасет'); Plot.Title('MakeRegression синтетический датасет');
Plot.XLabel('признак'); Plot.XLabel := 'признак';
Plot.YLabel('целевая переменная'); Plot.YLabel := 'целевая переменная';
Plot.Points(X.Col(0), y.ToArray, size := 3); Plot.Points(X.Col(0), y.ToArray, size := 3);
end. end.

View file

@ -1,4 +1,4 @@
// В этом примере строится scatter plot для двух признаков датасета Iris. // В этом примере строится scatter plot для двух признаков датасета Iris.
// //
// По оси X откладывается длина чашелистика, // По оси X откладывается длина чашелистика,
// по оси Y — ширина чашелистика. // по оси Y — ширина чашелистика.

View file

@ -0,0 +1,20 @@
uses MLABC, PlotML;
begin
var ds := Datasets.Iris;
var X := ds.Data.ToMatrix(ds.Features);
var y := ds.Data.EncodeLabels(ds.Target);
var scaler := new StandardScaler;
scaler.Fit(X);
X := scaler.Transform(X);
var pca := new PCATransformer(2);
pca.Fit(X);
var X2 := pca.Transform(X);
Plot.Points(X2.Col(0), X2.Col(1), y, size := 5);
Plot.XLabel := 'Первая главная компонента';
Plot.YLabel := 'Вторая главная компонента';
Plot.Title := 'Iris: проекция на две главные компоненты';
end.

View file

@ -0,0 +1,25 @@
uses PlotML;
begin
var fig := Plot.Grid(2, 2);
var labels := ['sedan', 'suv', 'hatchback', 'wagon'];
fig[0, 0].Bar(labels, [120.0, 95.0, 70.0, 40.0]);
fig[0, 0].Title := 'Cars A';
fig[0, 0].XLabel := 'count';
fig[0, 1].Bar(labels, [80.0, 110.0, 55.0, 30.0]);
fig[0, 1].Title := 'Cars B';
fig[0, 1].XLabel := 'count';
fig[1, 0].Bar(labels, [45.0, 65.0, 100.0, 25.0]);
fig[1, 0].Title := 'Cars C';
fig[1, 0].XLabel := 'count';
fig[1, 1].Bar(labels, [30.0, 50.0, 75.0, 90.0]);
fig[1, 1].Title := 'Cars D';
fig[1, 1].XLabel := 'count';
Plot.Title := 'Bar plots 2x2';
end.

View file

@ -0,0 +1,28 @@
// В этом примере строится confusion matrix для классификации Iris.
uses MLABC, PlotML;
begin
var ds := Datasets.Iris;
var (train, test) := ds.StratifiedTrainTestSplit(0.2, 42);
var Xtrain := train.Data.ToMatrix(train.Features);
var Xtest := test.Data.ToMatrix(test.Features);
var encoder := new LabelEncoder;
var ytrain := encoder.FitTransform(train);
var ytest := encoder.Transform(test);
var model := new LogisticRegression;
model.Fit(Xtrain, ytrain);
var pred := model.Predict(Xtest);
var cm := new ConfusionMatrix(ytest, pred);
var acc := Metrics.Accuracy(ytest, pred);
Plot.ConfusionMatrix(cm, encoder.Classes, normalize := MatrixNormalization.Rows);
Plot.Title := $'Iris: LogisticRegression, accuracy = {acc:F3}';
Plot.XLabel := 'Predicted';
Plot.YLabel := 'Actual';
end.

View file

@ -0,0 +1,49 @@
uses PlotML;
begin
var labels := ['cat', 'dog', 'fox'];
var m1 := Matr(
[3.0, 0, 0],
[1.0, 2, 1],
[0.0, 1, 2]
);
var m2 := Matr(
[4.0, 1, 0],
[0.0, 3, 1],
[1.0, 0, 2]
);
var m3 := Matr(
[2.0, 1, 1],
[0.0, 4, 0],
[1.0, 1, 3]
);
var m4 := Matr(
[5.0, 0, 1],
[1.0, 3, 0],
[0.0, 2, 4]
);
var fig := Plot.Grid(2, 2);
fig[0, 0].ConfusionMatrix(m1, labels);
fig[0, 0].Title := 'Model A';
fig[0, 0].YLabel := 'Actual';
fig[0, 1].ConfusionMatrix(m2, labels);
fig[0, 1].Title := 'Model B';
fig[1, 0].ConfusionMatrix(m3, labels);
fig[1, 0].Title := 'Model C';
fig[1, 0].XLabel := 'Predicted';
fig[1, 0].YLabel := 'Actual';
fig[1, 1].ConfusionMatrix(m4, labels);
fig[1, 1].Title := 'Model D';
fig[1, 1].XLabel := 'Predicted';
Plot.Title := 'Confusion Matrices';
end.