Пакет 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 и какие из них
можно использовать для построения моделей.
Создаем матрицу признаков 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)
График плотности показывает распределение значений признаков в классах 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
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 строит попарные диаграммы рассеяния, позволяя увидеть возможные зависимости между признаками.
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 сильно перекрываются.
На графиках нет четкого разделения, следовательно признаки в этом
примере малоинформативны.
Используем датасет 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.
Это означает, что размеры лепестков лучше всего различают виды
ирисов.
Преобразуем числовую переменную 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
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
Интервалы одинаковой ширины, но количество объектов в них может различаться.
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
В каждом интервале примерно одинаковое количество наблюдений.
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
Интервалы формируются по структуре данных.
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
Границы задаются вручную.
Вывод:
Методы дают разное разбиение.
Выбор зависит от цели анализа и требований к интерпретации.
Задача — определить, какие признаки действительно влияют на целевую переменную.
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;
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 сравнивает реальные признаки с «теневыми» (случайными).
Если признак стабильно важнее случайного, он считается значимым.
Вывод:
По графику видно, какие признаки имеют наибольшую важность и
действительно влияют на модель.