Задание 1. Установить пакет CARET, выполнить команду names(getModelInfo()), ознакомиться со списком доступных методов выбора признаков. Выполните графический разведочный анализ данных с использование функции featurePlot() для набора данных из справочного файла пакета CARET:

x <- matrix(rnorm(50*5),ncol=5)

y <- factor(rep(c("A", "B"), 25))

Сохранить полученные графики в *.jpg файлы. Сделать выводы.

Ход работы

Установим и загрузим пакет с помощью команд install.packages("caret") и library(caret).

Просмотрим доступные методы caret с помощью команды names(getModelInfo())

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

set.seed(123)
x <- matrix(rnorm(50 * 5), ncol = 5)
y <- factor(rep(c("A", "B"), 25))

df <- as.data.frame(x)
colnames(df) <- paste0("X", 1:5)
df$Class <- y

Далее воспользуемся функцией featurePlot() из caret, которая позволяет быстро смотреть взаимосвязи признаков и целевой переменной. Рассмотрим несколько вариантов графиков:

1) График пар (scatterplot matrix)

jpeg("featurePlot_pairs.jpg")
featurePlot(x = df[, 1:5],
            y = df$Class,
            plot = "pairs")
dev.off()

На выходе получаем следующий график:

2) Эллипсы разброса

jpeg("featurePlot_ellipse.jpg")
featurePlot(x = df[, 1:5],
            y = df$Class,
            plot = "ellipse")
dev.off()

3) Диаграммы “ящик с усами” (boxplot)

jpeg("featurePlot_box.jpg")
featurePlot(x = df[, 1:5],
            y = df$Class,
            plot = "box")
dev.off()

4) Плотности распределений

jpeg("featurePlot_density.jpg")
featurePlot(x = df[, 1:5],
            y = df$Class,
            plot = "density")
dev.off()

Основные выводы, учитывая, что данные генерируются случайно:

  • Между признаками (столбцами) может наблюдаться слабая или отсутствующая корреляция, так как мы сгенерировали их случайно.
  • Классы A и B распределяются примерно одинаково при случайной генерации, в реальных задачах на подобных графиках обычно ищут разделимость между классами.
  • featurePlot() удобен для быстрого “разведочного” анализа, чтобы понять, какие признаки отличаются (или не отличаются) по классам.

Задание 2. С использованием функций из пакета Fselector определить важность признаков для решения задачи классификации. Использовать набор data(iris). Сделать выводы.

Установим и запустим пакет с помощью команд install.packages("FSelector") и library(FSelector)

Подготовим данные iris с помощью команд data(iris) и head(iris)

Данные iris содержат 4 числовых признака (длина/ширина чашелистика и лепестка) и факторный признак Species (три вида ирисов).

Рассмотрим пример использования Information Gain для оценки вклада каждого признака в определение вида (Species). Запустим следующие команды: weights_info_gain <- information.gain(Species ~ ., data = iris) и weights_info_gain

Также можно использовать, например, gain ratio с помощью команд weights_gain_ratio <- gain.ratio(Species ~ ., data = iris) и weights_gain_ratio

В результатах заметим, что, как правило, наиболее важными признаками в классификации вида ириса оказываются Petal.Length и Petal.Width (длина и ширина лепестка). Признаки, связанные с чашелистиками, тоже имеют некоторую полезность, но обычно меньшую.

Основные выводы:

Задание 3. С использованием функции discretize() из пакета arules выполните преобразование непрерывной переменной в категориальную [3] различными методами: «interval» (равная ширина интервала), «frequency» (равная частота), «cluster» (кластеризация) и «fixed» (категории задают границы интервалов). Используйте набор данных iris. Сделайте выводы

Установим и запустим arules с помощью команд install.packages("arules") и library(arules)

Рассмотрим признак Sepal.Length, чтобы продемонстрировать разные методы дискретизации:

1) Метод “interval” — равные интервалы

disc_interval <- discretize(iris$Sepal.Length, 
                            method = "interval", 
                            categories = 3)
table(disc_interval)

2) Метод “frequency” — равная частота

disc_frequency <- discretize(iris$Sepal.Length, 
                             method = "frequency", 
                             categories = 3)
table(disc_frequency)

3) Метод “cluster” — кластеризация (k-means)

disc_cluster <- discretize(iris$Sepal.Length, 
                           method = "cluster", 
                           categories = 3)
table(disc_cluster)

4) Метод “fixed” — ручной ввод границ интервалов

Допустим, хотим разделить длину чашелистика примерно так: [4.3, 5.5), [5.5, 6.3), [6.3, 7.9], тогда:

disc_fixed <- discretize(iris$Sepal.Length, 
                         method = "fixed", 
                         categories = c(4.3, 5.5, 6.3, 7.9))
table(disc_fixed)

По частотам в table() будет видно, как распределились значения признака по категориям в каждом методе.

Основные выводы:

  • Метод “interval” делит диапазон значений на равные промежутки, что может быть удобно, если важно сохранить одинаковые размеры “шагов”.
  • Метод “frequency” стремится в каждую бинку (корзину) «уложить» одинаковое количество наблюдений.
  • Метод “cluster” использует алгоритм кластеризации (k-means) для нахождения более «естественных» групп по значению признака.
  • Метод “fixed” даёт полный контроль над границами, но требует от исследователя заранее знать (или логически обосновать) нужные пороги.

Задание 4. Установите пакет Boruta и проведите выбор признаков для набора данных data(“Ozone”) [4, 5, 6]. Построить график boxplot, сделать выводы.

Установим и запустим пакет с помощью команд install.packages("Boruta") и library(Boruta)

Подготовим данные Ozone. Набор данных Ozone доступен, например, в пакете mlbench:

install.packages("mlbench")
library(mlbench)
data("Ozone")
str(Ozone)

Часть столбцов может содержать пропуски. Обычно для Boruta желательно работать с полным набором без NA, поэтому нужно либо удалить пропуски, либо применить какую-то стратегию заполнения (imputation). Выберем удаление строк с пропусками. Осуществим это действие с помощью команды ozone_clean <- na.omit(Ozone)

Запустим Boruta. Допустим, мы хотим предсказывать переменную V4 (загрязнение), а все остальные используем как предикторы. Выполним:

set.seed(123)
boruta_result <- Boruta(V4 ~ ., data = ozone_clean, doTrace = 2, maxRuns = 100)
boruta_result

В результате получим:

Мы получили информацию о том, какие признаки признаны «важными» (Confirmed), «неважными» (Rejected) или «не до конца определёнными» (Tentative).

Так же, Boruta позволяет строить диаграмму боксов (boxplot), отражающую распределение Z-оценок важности признаков. Построим такую диаграму с помощью команд:

plot(boruta_result, xlab = "", xaxt = "n")
lz<-lapply(1:ncol(boruta_result$ImpHistory),function(i)
  boruta_result$ImpHistory[is.finite(boruta_result$ImpHistory[,i]),i])
names(lz) <- colnames(boruta_result$ImpHistory)
axis(side = 1, las=2, labels = names(lz),
     at = 1:ncol(boruta_result$ImpHistory), cex.axis = 0.7)

В итоге, boxplot покажет Z-значения важности каждого признака, включая «теневых» (shadow) признаков, которые Boruta использует как базу для сравнения.

Основные выводы: