models <- names(getModelInfo())
length(models)
## [1] 239
head(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"
set.seed(123)
x <- as.data.frame(matrix(rnorm(50 * 5), ncol = 5))
colnames(x) <- paste0("X", 1:5)
y <- factor(rep(c("A", "B"), 25))
print(featurePlot(x, y, plot = "box"))
print(featurePlot(x, y, plot = "pairs"))
print(featurePlot(x, y, plot = "density"))
print(featurePlot(x, y, plot = "ellipse"))
Вывод. Функция featurePlot() построила пять типов графиков (strip, box, density, pairs, ellipse). На сгенерированных данных x (5 независимых нормальных признаков) и метках y, чередующихся случайно, диаграммы размаха показали почти совпадающие медианы и квартили для классов A и B; кривые плотности практически накладываются друг на друга; на матрице рассеяния точки обоих классов перемешаны, а на графике с эллипсами эллипсы почти полностью перекрываются. Единственный наглядный вывод, который можно сделать — между признаками нет корреляции, а между классами и признаками нет зависимости. Это ожидаемый результат для случайных данных и хороший «нулевой пример»: он наглядно показывает, как выглядят данные без информативных признаков, и позволяет в дальнейшем сравнить их с реальным набором (например, iris), где графики сразу выявляют разделяющие признаки.
library(FSelector)
data(iris)
w_ig <- information.gain(Species ~ ., iris)
w_chi <- chi.squared(Species ~ ., iris)
w_rf <- random.forest.importance(Species ~ ., iris)
w_ig; w_chi; w_rf
## attr_importance
## Sepal.Length 0.4521286
## Sepal.Width 0.2672750
## Petal.Length 0.9402853
## Petal.Width 0.9554360
## attr_importance
## Sepal.Length 0.6288067
## Sepal.Width 0.4922162
## Petal.Length 0.9346311
## Petal.Width 0.9432359
## attr_importance
## Sepal.Length 15.215175
## Sepal.Width 4.983734
## Petal.Length 49.136910
## Petal.Width 47.063541
cutoff.k(w_ig, 2)
## [1] "Petal.Width" "Petal.Length"
cfs(Species ~ ., iris)
## [1] "Petal.Length" "Petal.Width"
Вывод. Для набора iris важность признаков оценивалась тремя методами из пакета FSelector — information.gain (прирост информации), chi.squared (хи-квадрат) и random.forest.importance (по случайному лесу). Каждый метод использует собственную шкалу, поэтому абсолютные значения между ними несопоставимы напрямую: Petal.Width даёт 0.955 у information.gain, 0.943 у chi.squared и 47.06 у random.forest.importance, — корректно сравнивать методы только по порядку признаков. Этот порядок во всех трёх случаях одинаков: Petal.Width и Petal.Length делят первые два места с минимальным отрывом друг от друга, третьим идёт Sepal.Length, а последним — Sepal.Width с заметным отставанием. Автоматические процедуры отбора подтверждают ту же картину: cutoff.k(w_ig, 2) возвращает Petal.Width и Petal.Length, а метод CFS (cfs(Species ~ ., iris)) — ровно ту же пару. Следовательно, для классификации трёх видов ириса достаточно двух признаков лепестка, и размерность задачи можно сократить с четырёх до двух без потери информативности: признаки чашелистика либо слабо разделяют классы (Sepal.Length), либо почти не несут полезной информации (Sepal.Width).
library(arules)
v <- iris$Sepal.Length
d_int <- discretize(v, method = "interval", breaks = 3)
d_freq <- discretize(v, method = "frequency", breaks = 3)
d_clu <- discretize(v, method = "cluster", breaks = 3)
d_fix <- discretize(v, method = "fixed", breaks = c(-Inf, 5.5, 6.5, Inf))
table(d_int); table(d_freq); table(d_clu); table(d_fix)
## d_int
## [4.3,5.5) [5.5,6.7) [6.7,7.9]
## 52 70 28
## d_freq
## [4.3,5.4) [5.4,6.3) [6.3,7.9]
## 46 53 51
## d_clu
## [4.3,5.33) [5.33,6.27) [6.27,7.9]
## 46 53 51
## d_fix
## [-Inf,5.5) [5.5,6.5) [6.5, Inf]
## 52 63 35
Вывод. interval даёт равную ширину интервалов, но неравные группы (52/70/28); frequency и cluster дают близкие по числу наблюдений группы (46/53/51), но разными путями — frequency по порядку, cluster по структуре данных; fixed полностью зависит от заданных порогов. Первый подходит для равномерного шага по шкале, второй и третий — для алгоритмов, чувствительных к дисбалансу, четвёртый — когда границы имеют содержательный смысл.
library(mlbench)
library(Boruta)
data("Ozone", package = "mlbench")
ozone <- na.omit(Ozone)
set.seed(123)
boruta_res <- Boruta(V4 ~ ., data = ozone, doTrace = 0)
print(boruta_res)
## Boruta performed 18 iterations in 0.314564 secs.
## 9 attributes confirmed important: V1, V10, V11, V12, V13 and 4 more;
## 3 attributes confirmed unimportant: V2, V3, V6;
plot(boruta_res, las = 2, cex.axis = 0.7)
attStats(boruta_res)
## meanImp medianImp minImp maxImp normHits decision
## V1 0.40660229 0.39874710 0.37208192 0.50361585 1.00000000 Confirmed
## V2 0.04391890 0.03169822 -0.02604472 0.13137821 0.11111111 Rejected
## V3 -0.03235907 -0.04528594 -0.08039941 0.03178173 0.00000000 Rejected
## V5 0.37961385 0.37663333 0.33809868 0.42147363 1.00000000 Confirmed
## V6 0.04740489 0.05979747 -0.01572443 0.12718160 0.05555556 Rejected
## V7 0.51883205 0.50588169 0.46725744 0.59114026 1.00000000 Confirmed
## V8 0.77086858 0.76889989 0.73251688 0.81327051 1.00000000 Confirmed
## V9 0.86915268 0.86432645 0.84273725 0.92413075 1.00000000 Confirmed
## V10 0.42389058 0.41739463 0.38164901 0.49245967 1.00000000 Confirmed
## V11 0.55143690 0.54721914 0.49482770 0.61161304 1.00000000 Confirmed
## V12 0.66051279 0.65832222 0.60234621 0.73958611 1.00000000 Confirmed
## V13 0.42761454 0.42057856 0.38618408 0.46920282 1.00000000 Confirmed
Вывод. Boruta за 18 итераций подтвердил 9 признаков (V1, V5, V7–V13) и отклонил 3 (V2, V3, V6), неопределённых нет. У подтверждённых normHits = 1.0, то есть важность стабильно выше теневых копий. Самые сильные — V9, V8 и V12 (температуры), что логично для озона. Отклонены V2 и V3 (календарные артефакты) и V6 — связи с концентрацией озона нет. Важность признаков устойчива от итерации к итерации
В лабораторной работе освоены четыре инструмента отбора признаков и подготовки данных в R: caret (обзор моделей, featurePlot()), FSelector (фильтры, CFS, обёртки), arules (discretize()) и Boruta. На случайных данных featurePlot() наглядно показала отсутствие информативных признаков; на iris все методы FSelector согласованно выделили признаки лепестка (Petal.Width, Petal.Length), что позволяет сократить размерность с 4 до 2; дискретизация arules продемонстрировала четыре разных подхода к преобразованию непрерывной переменной, выбор между которыми зависит от задачи; Boruta на Ozone надёжно отделила значимые признаки (температуры и сезонность) от шума без ручного порога важности.