1. CARET: список моделей и разведочный анализ

1.1 Получение списка моделей

Пакет caret содержит множество алгоритмов машинного обучения.
Функция getModelInfo() возвращает список доступных моделей.

library(caret)

all_models <- names(getModelInfo())
cat("Количество доступных моделей в caret:", length(all_models), "\n")
## Количество доступных моделей в caret: 239
head(all_models, 20)
##  [1] "ada"         "AdaBag"      "AdaBoost.M1" "adaboost"    "amdai"      
##  [6] "ANFIS"       "avNNet"      "awnb"        "awtan"       "bag"        
## [11] "bagEarth"    "bagEarthGCV" "bagFDA"      "bagFDAGCV"   "bam"        
## [16] "bartMachine" "bayesglm"    "binda"       "blackboost"  "blasso"

Пояснение:
Команда показывает, сколько методов доступно в caret и какие из них можно использовать для построения моделей.


1.2 Формирование данных

Создаем матрицу признаков x и фактор классов y (как указано в задании).

set.seed(777)
x <- matrix(rnorm(50*5), ncol = 5)
y <- factor(rep(c("A","B"), 25))
colnames(x) <- paste0("Var", 1:5)

1.3 Графический анализ featurePlot()

Density

График плотности показывает распределение значений признаков в классах A и B.

jpeg("plots/caret_density_v2.jpg", width=1700, height=1200, res=200)
featurePlot(x = x, y = y, plot = "density")
dev.off()
## quartz_off_screen 
##                 2

Box

Boxplot позволяет сравнить медиану и разброс признаков по классам.

jpeg("plots/caret_box_v2.jpg", width=1700, height=1200, res=200)
featurePlot(x = x, y = y, plot = "box")
dev.off()
## quartz_off_screen 
##                 2

Pairs

Pairs строит попарные диаграммы рассеяния, позволяя увидеть возможные зависимости между признаками.

jpeg("plots/caret_pairs_v2.jpg", width=1700, height=1200, res=200)
featurePlot(x = x, y = y, plot = "pairs")
dev.off()
## quartz_off_screen 
##                 2

Вывод:
Поскольку данные сгенерированы случайно (rnorm()), классы A и B сильно перекрываются.
На графиках нет четкого разделения, следовательно признаки в этом примере малоинформативны.


2. FSelector: оценка важности признаков (iris)

Используем датасет iris, где нужно определить, какие признаки лучше всего разделяют виды ирисов.

library(FSelector)
data(iris)

gr <- gain.ratio(Species ~ ., iris)
gr[order(-gr$attr_importance), , drop=FALSE]
##              attr_importance
## Petal.Width        0.8713692
## Petal.Length       0.8584937
## Sepal.Length       0.4196464
## Sepal.Width        0.2472972

Дополнительно рассчитаем симметричную неопределенность:

su <- symmetrical.uncertainty(Species ~ ., iris)
su[order(-su$attr_importance), , drop=FALSE]
##              attr_importance
## Petal.Width        0.8705214
## Petal.Length       0.8571872
## Sepal.Length       0.4155563
## Sepal.Width        0.2452743

Пояснение:
Эти методы оценивают вклад каждого признака в классификацию.

Вывод:
Наиболее значимыми оказываются Petal.Length и Petal.Width.
Это означает, что размеры лепестков лучше всего различают виды ирисов.


3. Дискретизация (arules)

Преобразуем числовую переменную Petal.Width в категориальную.

library(arules)

x_cont <- iris$Petal.Width
summary(x_cont)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.100   0.300   1.300   1.199   1.800   2.500

interval — равная ширина

d_interval <- discretize(x_cont, method="interval", categories=5)
table(d_interval)
## d_interval
##  [0.1,0.58) [0.58,1.06) [1.06,1.54) [1.54,2.02)  [2.02,2.5] 
##          49           8          41          29          23

Интервалы одинаковой ширины, но количество объектов в них может различаться.

frequency — равная частота

d_frequency <- discretize(x_cont, method="frequency", categories=5)
table(d_frequency)
## d_frequency
##  [0.1,0.2) [0.2,1.16) [1.16,1.5)  [1.5,1.9)  [1.9,2.5] 
##          5         55         26         30         34

В каждом интервале примерно одинаковое количество наблюдений.

cluster — кластеризация

d_cluster <- discretize(x_cont, method="cluster", categories=5)
table(d_cluster)
## d_cluster
##  [0.1,0.319) [0.319,0.81)  [0.81,1.39)  [1.39,1.88)   [1.88,2.5] 
##           41            9           28           38           34

Интервалы формируются по структуре данных.

fixed — вручную заданные границы

d_fixed <- discretize(
  x_cont,
  method="fixed",
  breaks=c(-Inf, 0.3, 1.0, 1.5, 2.0, Inf),
  labels=c("very_small","small","medium","large","very_large")
)
table(d_fixed)
## d_fixed
## very_small      small     medium      large very_large 
##         34         16         36         35         29

Границы задаются вручную.

Вывод:
Методы дают разное разбиение.
Выбор зависит от цели анализа и требований к интерпретации.


4. Boruta: выбор признаков (Ozone)

Задача — определить, какие признаки действительно влияют на целевую переменную.

library(mlbench)
library(Boruta)

data("Ozone")
oz <- na.omit(Ozone)

target <- names(oz)[ncol(oz)]
form <- as.formula(paste(target, "~ ."))

set.seed(777)
bor <- Boruta(form, data = oz, maxRuns = 60, doTrace = 1)
bor
## Boruta performed 59 iterations in 5.448663 secs.
##  9 attributes confirmed important: V1, V10, V11, V12, V4 and 4 more;
##  2 attributes confirmed unimportant: V2, V3;
##  1 tentative attributes left: V6;

Boxplot важности

jpeg("plots/boruta_box_v2.jpg", width=1900, height=1200, res=200)
plot(bor, las = 2, cex.axis = 0.8)
dev.off()
## quartz_off_screen 
##                 2

История важности

jpeg("plots/boruta_history_v2.jpg", width=1900, height=1200, res=200)
plotImpHistory(bor)
dev.off()
## quartz_off_screen 
##                 2

Итоговые признаки

getSelectedAttributes(bor, withTentative = TRUE)
##  [1] "V1"  "V4"  "V5"  "V6"  "V7"  "V8"  "V9"  "V10" "V11" "V12"
bor_fix <- TentativeRoughFix(bor)
getSelectedAttributes(bor_fix, withTentative = FALSE)
## [1] "V1"  "V4"  "V5"  "V7"  "V8"  "V9"  "V10" "V11" "V12"

Пояснение:
Boruta сравнивает реальные признаки с «теневыми» (случайными).
Если признак стабильно важнее случайного, он считается значимым.

Вывод:
По графику видно, какие признаки имеют наибольшую важность и действительно влияют на модель.