Введение

Данная лабораторная работа посвящена изучению базовых инструментов анализа данных в языке R.

В работе используются пакеты caret, FSelector, arules, Boruta и mlbench.

Основные задачи работы:

Перед выполнением отчета необходимые пакеты нужно один раз установить в консоли RStudio:

install.packages("recipes")
install.packages("caret", dependencies = TRUE)
install.packages("FSelector")
install.packages("arules")
install.packages("Boruta")
install.packages("mlbench")

Задание 1. Работа с пакетом CARET

Условие

Установить пакет caret, выполнить команду names(getModelInfo()), ознакомиться со списком доступных методов выбора признаков.

Выполнить графический разведочный анализ данных с использованием функции featurePlot() для набора данных:

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

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

Выполнение задания

library(caret)

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

models <- names(getModelInfo())

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 <- matrix(rnorm(50 * 5), ncol = 5)

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

dim(x)
## [1] 50  5
head(y)
## [1] A B A B A B
## Levels: A B

Матрица x содержит 50 наблюдений и 5 признаков.
Переменная y содержит два класса: A и B.

График box

График box показывает распределение значений признаков по классам.
С его помощью можно увидеть медиану, разброс значений и возможные выбросы.

featurePlot(
  x = x,
  y = y,
  plot = "box",
  main = "Box plot: распределение признаков по классам"
)

Сохраним график в файл .jpg.

jpeg("featurePlot_box.jpg", width = 1200, height = 900)

featurePlot(
  x = x,
  y = y,
  plot = "box",
  main = "Box plot: распределение признаков по классам"
)

dev.off()
## png 
##   2

График density

График density показывает плотность распределения признаков для разных классов.
Если кривые классов сильно отличаются, значит признак может быть полезен для классификации.

featurePlot(
  x = x,
  y = y,
  plot = "density",
  main = "Density plot: распределение признаков по классам",
  auto.key = list(columns = 2)
)

Сохраним график в файл .jpg.

jpeg("featurePlot_density.jpg", width = 1200, height = 900)

featurePlot(
  x = x,
  y = y,
  plot = "density",
  main = "Density plot: распределение признаков по классам",
  auto.key = list(columns = 2)
)

dev.off()
## png 
##   2

График pairs

График pairs показывает попарные зависимости между признаками.
Он помогает увидеть возможные связи между переменными и визуальное разделение классов.

featurePlot(
  x = x,
  y = y,
  plot = "pairs",
  main = "Pairs plot: попарные зависимости признаков",
  auto.key = list(columns = 2)
)

Сохраним график в файл .jpg.

jpeg("featurePlot_pairs.jpg", width = 1200, height = 900)

featurePlot(
  x = x,
  y = y,
  plot = "pairs",
  main = "Pairs plot: попарные зависимости признаков",
  auto.key = list(columns = 2)
)

dev.off()
## png 
##   2

Вывод по заданию 1

В первом задании был использован пакет caret. С помощью команды names(getModelInfo()) был получен список доступных методов машинного обучения.

Функция featurePlot() позволила построить три вида графиков:

  • box;
  • density;
  • pairs.

Так как данные были сгенерированы случайно, четкого разделения между классами A и B не наблюдается. На графиках видно, что распределения классов в основном перекрываются. Это означает, что случайные признаки плохо подходят для разделения классов.

Задание 2. Оценка важности признаков с помощью FSelector

Условие

С использованием функций из пакета FSelector определить важность признаков для решения задачи классификации.

Использовать набор данных iris.

Выполнение задания

library(FSelector)

Загрузим встроенный набор данных iris.

data(iris)

head(iris)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa

Набор данных iris содержит измерения цветков ириса:

  • Sepal.Length — длина чашелистика;
  • Sepal.Width — ширина чашелистика;
  • Petal.Length — длина лепестка;
  • Petal.Width — ширина лепестка;
  • Species — вид ириса.

Целевая переменная — Species.

Для оценки важности признаков используем функцию information.gain().

weights <- information.gain(Species ~ ., data = iris)

weights
##              attr_importance
## Sepal.Length       0.4521286
## Sepal.Width        0.2672750
## Petal.Length       0.9402853
## Petal.Width        0.9554360

Отсортируем признаки по убыванию важности.

weights_sorted <- weights[
  order(-weights$attr_importance),
  ,
  drop = FALSE
]

weights_sorted
##              attr_importance
## Petal.Width        0.9554360
## Petal.Length       0.9402853
## Sepal.Length       0.4521286
## Sepal.Width        0.2672750

Вывод по заданию 2

Функция information.gain() показывает, насколько каждый признак полезен для определения класса.

По результатам видно, что самыми важными признаками являются:

  • Petal.Width;
  • Petal.Length.

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

Наименьшую важность имеет признак Sepal.Width. Следовательно, ширина чашелистика хуже всего помогает при классификации.

Задание 3. Дискретизация переменной с помощью arules

Условие

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

  • interval — равная ширина интервала;
  • frequency — равная частота;
  • cluster — кластеризация;
  • fixed — категории задают границы интервалов.

Использовать набор данных iris.

Выполнение задания

library(arules)

В качестве переменной для дискретизации возьмем Sepal.Length.

summary(iris$Sepal.Length)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   4.300   5.100   5.800   5.843   6.400   7.900

Переменная Sepal.Length является числовой.
Задача дискретизации состоит в том, чтобы преобразовать числовые значения в интервальные категории.

Метод interval

Метод interval делит весь диапазон значений на интервалы одинаковой ширины.

disc_interval <- discretize(
  iris$Sepal.Length,
  method = "interval",
  breaks = 4
)

table(disc_interval)
## disc_interval
## [4.3,5.2) [5.2,6.1)   [6.1,7)   [7,7.9] 
##        41        48        48        13

Метод frequency

Метод frequency делит данные так, чтобы в каждом интервале было примерно одинаковое количество объектов.

disc_frequency <- discretize(
  iris$Sepal.Length,
  method = "frequency",
  breaks = 4
)

table(disc_frequency)
## disc_frequency
## [4.3,5.1) [5.1,5.8) [5.8,6.4) [6.4,7.9] 
##        32        41        35        42

Метод cluster

Метод cluster выполняет разбиение с учетом структуры данных.
Интервалы формируются на основе группировки близких значений.

disc_cluster <- discretize(
  iris$Sepal.Length,
  method = "cluster",
  breaks = 4
)

table(disc_cluster)
## disc_cluster
##  [4.3,4.89) [4.89,5.59) [5.59,6.49)  [6.49,7.9] 
##          16          43          56          35

Метод fixed

Метод fixed использует границы, которые задаются вручную.

disc_fixed <- discretize(
  iris$Sepal.Length,
  method = "fixed",
  breaks = c(-Inf, 5, 6, 7, Inf)
)

table(disc_fixed)
## disc_fixed
## [-Inf,5)    [5,6)    [6,7) [7, Inf] 
##       22       61       54       13

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

discretization_result <- data.frame(
  Sepal.Length = iris$Sepal.Length,
  interval = disc_interval,
  frequency = disc_frequency,
  cluster = disc_cluster,
  fixed = disc_fixed
)

head(discretization_result, 10)
##    Sepal.Length  interval frequency     cluster    fixed
## 1           5.1 [4.3,5.2) [5.1,5.8) [4.89,5.59)    [5,6)
## 2           4.9 [4.3,5.2) [4.3,5.1) [4.89,5.59) [-Inf,5)
## 3           4.7 [4.3,5.2) [4.3,5.1)  [4.3,4.89) [-Inf,5)
## 4           4.6 [4.3,5.2) [4.3,5.1)  [4.3,4.89) [-Inf,5)
## 5           5.0 [4.3,5.2) [4.3,5.1) [4.89,5.59)    [5,6)
## 6           5.4 [5.2,6.1) [5.1,5.8) [4.89,5.59)    [5,6)
## 7           4.6 [4.3,5.2) [4.3,5.1)  [4.3,4.89) [-Inf,5)
## 8           5.0 [4.3,5.2) [4.3,5.1) [4.89,5.59)    [5,6)
## 9           4.4 [4.3,5.2) [4.3,5.1)  [4.3,4.89) [-Inf,5)
## 10          4.9 [4.3,5.2) [4.3,5.1) [4.89,5.59) [-Inf,5)

Вывод по заданию 3

В третьем задании была выполнена дискретизация переменной Sepal.Length.

Метод interval делит диапазон значений на равные по ширине интервалы. Этот метод простой, но количество объектов в группах может быть разным.

Метод frequency формирует интервалы так, чтобы количество объектов в группах было примерно одинаковым.

Метод cluster учитывает распределение данных и группирует близкие значения.

Метод fixed позволяет самостоятельно задать границы интервалов. Такой способ удобен, если заранее известно, какие диапазоны нужно выделить.

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

Задание 4. Выбор признаков с помощью Boruta

Условие

Установить пакет Boruta и провести выбор признаков для набора данных Ozone.

Построить график boxplot и сделать выводы.

Выполнение задания

library(Boruta)
library(mlbench)

Загрузим набор данных Ozone.

data("Ozone")

str(Ozone)
## 'data.frame':    366 obs. of  13 variables:
##  $ V1 : Factor w/ 12 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ V2 : Factor w/ 31 levels "1","2","3","4",..: 1 2 3 4 5 6 7 8 9 10 ...
##  $ V3 : Factor w/ 7 levels "1","2","3","4",..: 4 5 6 7 1 2 3 4 5 6 ...
##  $ V4 : num  3 3 3 5 5 6 4 4 6 7 ...
##  $ V5 : num  5480 5660 5710 5700 5760 5720 5790 5790 5700 5700 ...
##  $ V6 : num  8 6 4 3 3 4 6 3 3 3 ...
##  $ V7 : num  20 NA 28 37 51 69 19 25 73 59 ...
##  $ V8 : num  NA 38 40 45 54 35 45 55 41 44 ...
##  $ V9 : num  NA NA NA NA 45.3 ...
##  $ V10: num  5000 NA 2693 590 1450 ...
##  $ V11: num  -15 -14 -25 -24 25 15 -33 -28 23 -2 ...
##  $ V12: num  30.6 NA 47.7 55 57 ...
##  $ V13: num  200 300 250 100 60 60 100 250 120 120 ...

В наборе данных есть пропущенные значения.
Для корректной работы алгоритма Boruta удалим строки с NA.

Ozone_clean <- na.omit(Ozone)

cat("Количество строк до очистки:", nrow(Ozone), "\n")
## Количество строк до очистки: 366
cat("Количество строк после очистки:", nrow(Ozone_clean), "\n")
## Количество строк после очистки: 203

Запустим алгоритм Boruta.

set.seed(123)

boruta_output <- Boruta(
  V4 ~ .,
  data = Ozone_clean,
  doTrace = 0
)

boruta_output
## Boruta performed 18 iterations in 1.019441 secs.
##  9 attributes confirmed important: V1, V10, V11, V12, V13 and 4 more;
##  3 attributes confirmed unimportant: V2, V3, V6;

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

Построим график важности признаков.

plot(
  boruta_output,
  las = 2,
  cex.axis = 0.7,
  main = "Boruta: важность признаков"
)

Вывод по заданию 4

В четвертом задании был использован пакет Boruta.

Алгоритм Boruta предназначен для выбора важных признаков. Он помогает определить, какие переменные действительно полезны для объяснения целевой переменной.

Перед запуском алгоритма были удалены строки с пропущенными значениями, потому что Boruta не работает с NA.

В результате были получены признаки, которые алгоритм считает важными или неважными. График Boruta показывает распределение важности признаков.

Задание 5. Оформление и публикация отчета

Условие

Всю представленную работу собрать в единый файл RMarkdown. Опубликовать его на RPubs. В качестве отчета о лабораторной работе представить ссылку на полученный файл.

Выполнение задания

Данная работа оформлена в виде единого файла RMarkdown.

После нажатия кнопки Knit формируется HTML-документ, содержащий:

  • текст лабораторной работы;
  • программный код;
  • результаты выполнения кода;
  • графики;
  • выводы.

Для публикации на RPubs необходимо:

  1. Нажать Knit или Knit to HTML.
  2. Дождаться создания HTML-документа.
  3. В окне просмотра нажать Publish.
  4. Выбрать сервис RPubs.
  5. Указать название и описание публикации.
  6. Опубликовать отчет.
  7. Скопировать ссылку на опубликованный документ.

Вывод по заданию 5

Формат RMarkdown удобен для оформления лабораторных работ, так как позволяет объединить теоретическое описание, код, результаты вычислений и графики в одном документе.

Общий вывод

В ходе лабораторной работы были изучены основные способы анализа и выбора признаков в языке R.

С помощью пакета caret был выполнен графический разведочный анализ данных.
С помощью пакета FSelector была определена важность признаков для набора данных iris.
С помощью пакета arules была выполнена дискретизация числовой переменной Sepal.Length.
С помощью пакета Boruta был проведен отбор признаков для набора данных Ozone.

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