Введение

Цель работы — освоить инструменты выбора признаков и предварительного анализа данных в языке R с использованием пакетов caret, FSelector, arules и Boruta.
В отчёте приведены: код, полученные результаты, графики (сохранённые в формате JPG) и выводы.


1. Пакет CARET: список моделей и графический анализ featurePlot()

1.1 Что требуется по заданию

  1. Установить и подключить пакет caret.
  2. Выполнить команду names(getModelInfo()) и ознакомиться со списком доступных методов/моделей.
  3. Сгенерировать набор данных x и метки классов y (как в задании).
  4. Выполнить графический разведочный анализ с помощью featurePlot() и сохранить графики в JPG.
  5. Сделать выводы.

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

getModelInfo() содержит информацию о моделях, доступных в caret.
Команда names(getModelInfo()) выводит названия всех моделей.

library(caret)

m <- names(getModelInfo())
cat("Всего моделей в caret:", length(m), "\n")
## Всего моделей в caret: 239
head(m, 15)
##  [1] "ada"         "AdaBag"      "AdaBoost.M1" "adaboost"    "amdai"      
##  [6] "ANFIS"       "avNNet"      "awnb"        "awtan"       "bag"        
## [11] "bagEarth"    "bagEarthGCV" "bagFDA"      "bagFDAGCV"   "bam"

Пояснение: вывод (список из десятков/сотен методов) подтверждает, что caret поддерживает множество алгоритмов машинного обучения и методов построения моделей.


1.3 Формирование данных x и y (как в задании)

Согласно заданию создаём матрицу признаков x размером 50×5 и вектор классов y из двух классов A и B.

Дополнительно выполним центрирование и масштабирование признаков (scale()), чтобы сравнение распределений по графикам было удобнее (масштабирование не меняет сути данных, но упрощает визуальное сравнение признаков между собой).

set.seed(42)
x <- matrix(rnorm(50*5), ncol=5)
y <- factor(rep(c("A","B"), 25))
colnames(x) <- c("F1","F2","F3","F4","F5")

x_scaled <- scale(x)

1.4 Разведочный анализ featurePlot() + сохранение JPG

1.4.1 График pairs (попарные диаграммы)

Что показывает:
pairs-график строит диаграммы рассеяния для всех пар признаков. Это помогает увидеть: - есть ли группы/кластеры по классам A и B; - есть ли линейные зависимости между признаками; - есть ли визуально разделимые области.

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

1.4.2 График box (ящик с усами)

Что показывает:
Boxplot по классам показывает: - медиану значений признака в каждом классе; - разброс (межквартильный размах); - возможные выбросы.

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

1.4.3 График density (плотности распределений)

Что показывает:
Density-график сравнивает распределения признаков в классах A и B: - если плотности сильно расходятся → признак может хорошо разделять классы; - если графики почти совпадают → разделяющей способности мало.

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

1.4.4 Вставка сохранённых графиков в отчёт

1.4.5 Дополнительная проверка (средние по классам)

Чтобы подкрепить визуальные наблюдения, вычислим средние значения признаков по классам.

x_df <- as.data.frame(x_scaled)
x_df$Class <- y
aggregate(. ~ Class, data = x_df, FUN = mean)
##   Class          F1          F2        F3           F4         F5
## 1     A  0.08293395 -0.09414798 -0.150313  0.005747935 -0.1552154
## 2     B -0.08293395  0.09414798  0.150313 -0.005747935  0.1552154

1.5 Вывод по пункту 1

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

  • pairs: точки классов A и B не образуют чётко разделённые кластеры.
  • boxplot: медианы и размахи в классах близки, сильного смещения нет.
  • density: распределения классов по большинству признаков перекрываются.

Следовательно, в данном примере признаки слабо информативны для классификации.


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

2.1 Что требуется по заданию

  1. Использовать набор данных iris.
  2. С помощью функций пакета FSelector определить важность признаков для задачи классификации (целевой признак — Species).
  3. Сделать вывод.

2.2 Расчёт важности признаков

Используем две оценки: - random.forest.importance() — важность признаков по случайному лесу;
- information.gain() — информационная выгода.

library(FSelector)
data(iris)

rf_imp <- random.forest.importance(Species ~ ., iris)
rf_imp[order(-rf_imp$attr_importance), , drop=FALSE]
##              attr_importance
## Petal.Length       48.621282
## Petal.Width        46.945379
## Sepal.Length       16.330769
## Sepal.Width         7.677002

Для сравнения:

ig <- information.gain(Species ~ ., iris)
ig[order(-ig$attr_importance), , drop=FALSE]
##              attr_importance
## Petal.Width        0.9554360
## Petal.Length       0.9402853
## Sepal.Length       0.4521286
## Sepal.Width        0.2672750

2.3 Вывод по пункту 2

Обе оценки показывают, что наиболее значимыми признаками являются: - Petal.Length - Petal.Width

Это означает, что параметры лепестков лучше всего разделяют виды ирисов (классы Species). Признаки чашелистиков (Sepal.*) обычно оказываются менее информативными.


3. arules: discretize() — преобразование числовой переменной в категориальную

3.1 Что требуется по заданию

Для iris выполнить преобразование непрерывной переменной в категориальную с помощью discretize() четырьмя методами: - interval (равная ширина интервала), - frequency (равная частота), - cluster (кластеризация), - fixed (границы задаются вручную).

3.2 Выбор переменной

Дискретизируем Sepal.Width (ширина чашелистика).

library(arules)

x_cont <- iris$Sepal.Width
summary(x_cont)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   2.000   2.800   3.000   3.057   3.300   4.400

3.3 Метод interval (равная ширина)

d_interval <- discretize(x_cont, method = "interval", categories = 3)
table(d_interval)
## d_interval
##   [2,2.8) [2.8,3.6) [3.6,4.4] 
##        47        88        15

Смысл: диапазон значений делится на 3 одинаковых по ширине интервала.

3.4 Метод frequency (равная частота)

d_frequency <- discretize(x_cont, method = "frequency", categories = 3)
table(d_frequency)
## d_frequency
##   [2,2.9) [2.9,3.2) [3.2,4.4] 
##        47        47        56

Смысл: интервалы подбираются так, чтобы в каждом было примерно одинаковое число наблюдений.

3.5 Метод cluster (кластеризация)

d_cluster <- discretize(x_cont, method = "cluster", categories = 3)
table(d_cluster)
## d_cluster
##    [2,2.85) [2.85,3.44)  [3.44,4.4] 
##          47          78          25

Смысл: границы выбираются по группам значений (кластеризация), чтобы учесть структуру распределения.

3.6 Метод fixed (ручные границы)

d_fixed <- discretize(
  x_cont,
  method = "fixed",
  breaks = c(-Inf, 2.8, 3.4, Inf),
  labels = c("narrow", "normal", "wide")
)
table(d_fixed)
## d_fixed
## narrow normal   wide 
##     33     80     37

Смысл: границы задаются вручную — удобно, если есть экспертные пороги.

3.7 Вывод по пункту 3

Разные методы дают разное распределение по категориям: - interval — равная ширина, частоты могут быть сильно разными; - frequency — частоты примерно равны; - cluster — учитывает “естественные” группы; - fixed — зависит от заданных порогов и удобен для интерпретации.


4. Boruta: отбор признаков для data(“Ozone”) + boxplot

4.1 Что требуется по заданию

  1. Установить/подключить пакет Boruta.
  2. Использовать датасет data("Ozone").
  3. Выполнить отбор признаков.
  4. Построить график boxplot и сделать выводы.

4.2 Подготовка данных

В Ozone есть пропуски, поэтому удалим строки с NA (иначе Boruta может работать некорректно).

library(mlbench)
library(Boruta)

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

# целевая переменная (последний столбец)
target <- names(oz)[ncol(oz)]
form <- as.formula(paste(target, "~ ."))
target
## [1] "V13"

4.3 Запуск Boruta

set.seed(42)
bor <- Boruta(form, data = oz, maxRuns = 80, doTrace = 0)
bor
## Boruta performed 30 iterations in 2.524732 secs.
##  9 attributes confirmed important: V1, V10, V11, V12, V4 and 4 more;
##  3 attributes confirmed unimportant: V2, V3, V6;

4.4 Таблица важности и статусов признаков

stats <- attStats(bor)
stats
##         meanImp   medianImp     minImp    maxImp   normHits  decision
## V1   4.96247429  4.97885767  2.2631618  6.827074 0.93333333 Confirmed
## V2   0.02440981 -0.02535998 -1.4046393  1.640035 0.00000000  Rejected
## V3  -0.21441706 -0.46782979 -1.6209755  1.050368 0.00000000  Rejected
## V4  12.87769681 12.86010088 11.6884754 14.335631 1.00000000 Confirmed
## V5   4.20993059  4.14222674  2.9120333  5.418729 0.80000000 Confirmed
## V6   1.85585034  1.71640544  0.5144455  3.340914 0.03333333  Rejected
## V7  14.90759871 14.94806376 12.4303221 17.106776 1.00000000 Confirmed
## V8   4.78508987  4.89070775  1.9851514  6.709040 0.83333333 Confirmed
## V9   9.31790018  9.36054997  7.8708506 10.761351 0.96666667 Confirmed
## V10  6.68504080  6.84815171  5.1578172  8.431285 0.96666667 Confirmed
## V11  4.73479101  4.84182192  2.1729111  6.490110 0.83333333 Confirmed
## V12 10.34224059 10.29480786  8.9026290 11.587005 0.96666667 Confirmed

Пояснение:
В таблице видно, какие признаки получили статус: - Confirmed (важные), - Rejected (неважные), - Tentative (неопределённые).

4.5 Boxplot важности + сохранение JPG

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

Что показывает график:
Boxplot отражает распределение важности признаков (по итерациям случайного леса) и “теневых” признаков (shadow).
Если важность признака стабильно выше, чем у shadow — признак подтверждается как важный.

4.6 Итоговый набор признаков

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

4.7 Вывод по пункту 4

Boruta отбирает признаки по принципу сравнения с “теневыми” признаками. Это помогает исключить случайно значимые признаки и оставить те, что действительно влияют на целевую переменную.
Boxplot позволяет визуально увидеть, какие признаки превосходят shadow и являются наиболее информативными.