Введение

В данной лабораторной работе рассматриваются методы выбора признаков и дискретизации данных с использованием различных пакетов R:

  • caret - для графического разведочного анализа
  • FSelector - для определения важности признаков
  • arules - для дискретизации непрерывных переменных
  • Boruta - для выбора признаков методом случайного леса

1. Пакет CARET: Графический разведочный анализ

1.1 Установка и загрузка пакета

# Установка пакета caret
if (!requireNamespace("caret", quietly = TRUE)) {
  install.packages("caret", repos = "https://cloud.r-project.org/")
}
library(caret)

1.2 Доступные методы выбора признаков

Функция getModelInfo() возвращает информацию о всех доступных моделях в пакете caret:

# Получить список всех доступных методов
available_methods <- names(getModelInfo())
cat("Количество доступных методов:", length(available_methods), "\n\n")
## Количество доступных методов: 239
cat("Первые 50 методов:\n")
## Первые 50 методов:
print(head(available_methods, 50))
##  [1] "ada"            "AdaBag"         "AdaBoost.M1"    "adaboost"      
##  [5] "amdai"          "ANFIS"          "avNNet"         "awnb"          
##  [9] "awtan"          "bag"            "bagEarth"       "bagEarthGCV"   
## [13] "bagFDA"         "bagFDAGCV"      "bam"            "bartMachine"   
## [17] "bayesglm"       "binda"          "blackboost"     "blasso"        
## [21] "blassoAveraged" "bridge"         "brnn"           "BstLm"         
## [25] "bstSm"          "bstTree"        "C5.0"           "C5.0Cost"      
## [29] "C5.0Rules"      "C5.0Tree"       "cforest"        "chaid"         
## [33] "CSimca"         "ctree"          "ctree2"         "cubist"        
## [37] "dda"            "deepboost"      "DENFIS"         "dnn"           
## [41] "dwdLinear"      "dwdPoly"        "dwdRadial"      "earth"         
## [45] "elm"            "enet"           "evtree"         "extraTrees"    
## [49] "fda"            "FH.GBML"

1.3 Создание тестовых данных

# Установка seed для воспроизводимости
set.seed(42)

# Создание матрицы признаков
x <- matrix(rnorm(50 * 5), ncol = 5)
colnames(x) <- paste0("Feature_", 1:5)

# Создание целевой переменной
y <- factor(rep(c("A", "B"), 25))

# Преобразование в data.frame для удобства
data_df <- data.frame(x, Class = y)

# Просмотр структуры данных
str(data_df)
## 'data.frame':    50 obs. of  6 variables:
##  $ Feature_1: num  1.371 -0.565 0.363 0.633 0.404 ...
##  $ Feature_2: num  0.3219 -0.7838 1.5757 0.6429 0.0898 ...
##  $ Feature_3: num  1.201 1.045 -1.003 1.848 -0.667 ...
##  $ Feature_4: num  -0.0407 -1.5515 1.1672 -0.2736 -0.4678 ...
##  $ Feature_5: num  -2.001 0.334 1.171 2.06 -1.377 ...
##  $ Class    : Factor w/ 2 levels "A","B": 1 2 1 2 1 2 1 2 1 2 ...
summary(data_df)
##    Feature_1          Feature_2         Feature_3         Feature_4       
##  Min.   :-2.65646   Min.   :-2.9931   Min.   :-2.0247   Min.   :-1.74506  
##  1st Qu.:-0.63223   1st Qu.:-0.5262   1st Qu.:-0.5884   1st Qu.:-0.57145  
##  Median :-0.10039   Median : 0.2672   Median :-0.2523   Median : 0.03927  
##  Mean   :-0.03567   Mean   : 0.1007   Mean   :-0.1513   Mean   :-0.02372  
##  3rd Qu.: 0.65072   3rd Qu.: 0.6728   3rd Qu.: 0.1341   3rd Qu.: 0.57841  
##  Max.   : 2.28665   Max.   : 1.5757   Max.   : 2.7019   Max.   : 1.81523  
##    Feature_5        Class 
##  Min.   :-2.00093   A:25  
##  1st Qu.:-0.69399   B:25  
##  Median :-0.15305         
##  Mean   : 0.00794         
##  3rd Qu.: 0.65662         
##  Max.   : 2.05954

1.4 Графический разведочный анализ с featurePlot()

Диаграмма рассеяния (Scatter Plot)

# Scatter plot
featurePlot(x = x, 
            y = y, 
            plot = "pairs",
            auto.key = list(columns = 2))

# Сохранение графика в JPG
jpeg("plots/featureplot_scatter.jpg", width = 800, height = 600, quality = 100)
featurePlot(x = x, 
            y = y, 
            plot = "pairs",
            auto.key = list(columns = 2))
dev.off()
## png 
##   2

Box Plot (Ящик с усами)

# Box plots для каждого признака по классам
featurePlot(x = x, 
            y = y, 
            plot = "box",
            scales = list(x = list(relation = "free"),
                         y = list(relation = "free")),
            auto.key = list(columns = 2))

# Сохранение графика в JPG
jpeg("plots/featureplot_box.jpg", width = 800, height = 600, quality = 100)
featurePlot(x = x, 
            y = y, 
            plot = "box",
            scales = list(x = list(relation = "free"),
                         y = list(relation = "free")),
            auto.key = list(columns = 2))
dev.off()
## png 
##   2

Density Plot (График плотности)

# Графики плотности распределения
featurePlot(x = x, 
            y = y, 
            plot = "density",
            scales = list(x = list(relation = "free"),
                         y = list(relation = "free")),
            auto.key = list(columns = 2),
            layout = c(3, 2))

# Сохранение графика в JPG
jpeg("plots/featureplot_density.jpg", width = 800, height = 600, quality = 100)
featurePlot(x = x, 
            y = y, 
            plot = "density",
            scales = list(x = list(relation = "free"),
                         y = list(relation = "free")),
            auto.key = list(columns = 2),
            layout = c(3, 2))
dev.off()
## png 
##   2

Strip Plot (Точечные диаграммы)

# Strip plots для каждого признака по классам
featurePlot(x = x, 
            y = y, 
            plot = "strip",
            jitter = TRUE,
            scales = list(x = list(relation = "free"),
                         y = list(relation = "free")),
            auto.key = list(columns = 2))

# Сохранение графика в JPG
jpeg("plots/featureplot_strip.jpg", width = 800, height = 600, quality = 100)
featurePlot(x = x, 
            y = y, 
            plot = "strip",
            jitter = TRUE,
            scales = list(x = list(relation = "free"),
                         y = list(relation = "free")),
            auto.key = list(columns = 2))
dev.off()
## png 
##   2

1.5 Выводы по разделу 1

Выводы:

  1. Пакет caret предоставляет более 230 методов машинного обучения для решения задач классификации и регрессии.

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

    • Scatter plots (pairs) - показывают взаимосвязи между признаками
    • Box plots - демонстрируют распределение признаков по классам
    • Density plots - отображают плотность распределения для каждого класса
    • Strip plots - точечные диаграммы с разделением по классам
  3. Поскольку данные сгенерированы случайным образом (rnorm), признаки не показывают значимого разделения между классами A и B - распределения почти идентичны.


2. Пакет FSelector: Определение важности признаков

2.1 Установка и загрузка пакета

# Установка пакета FSelector
if (!requireNamespace("FSelector", quietly = TRUE)) {
  install.packages("FSelector", repos = "https://cloud.r-project.org/")
}
library(FSelector)

2.2 Загрузка данных iris

data(iris)
str(iris)
## 'data.frame':    150 obs. of  5 variables:
##  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
##  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
##  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
##  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
##  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
summary(iris)
##   Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
##  Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
##  1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
##  Median :5.800   Median :3.000   Median :4.350   Median :1.300  
##  Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
##  3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
##  Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
##        Species  
##  setosa    :50  
##  versicolor:50  
##  virginica :50  
##                 
##                 
## 

2.3 Методы определения важности признаков

Information Gain (Информационный прирост)

# Вычисление информационного прироста
info_gain <- information.gain(Species ~ ., data = iris)
print("Information Gain:")
## [1] "Information Gain:"
print(info_gain)
##              attr_importance
## Sepal.Length       0.4521286
## Sepal.Width        0.2672750
## Petal.Length       0.9402853
## Petal.Width        0.9554360

Gain Ratio (Коэффициент прироста)

# Вычисление коэффициента прироста
gain_rat <- gain.ratio(Species ~ ., data = iris)
print("Gain Ratio:")
## [1] "Gain Ratio:"
print(gain_rat)
##              attr_importance
## Sepal.Length       0.4196464
## Sepal.Width        0.2472972
## Petal.Length       0.8584937
## Petal.Width        0.8713692

Symmetrical Uncertainty (Симметричная неопределенность)

# Вычисление симметричной неопределенности
sym_uncert <- symmetrical.uncertainty(Species ~ ., data = iris)
print("Symmetrical Uncertainty:")
## [1] "Symmetrical Uncertainty:"
print(sym_uncert)
##              attr_importance
## Sepal.Length       0.4155563
## Sepal.Width        0.2452743
## Petal.Length       0.8571872
## Petal.Width        0.8705214

Chi-Squared (Хи-квадрат)

# Вычисление важности на основе хи-квадрат теста
chi_sq <- chi.squared(Species ~ ., data = iris)
print("Chi-Squared:")
## [1] "Chi-Squared:"
print(chi_sq)
##              attr_importance
## Sepal.Length       0.6288067
## Sepal.Width        0.4922162
## Petal.Length       0.9346311
## Petal.Width        0.9432359

2.4 Сравнительный анализ методов

# Объединение результатов
importance_df <- data.frame(
  Feature = rownames(info_gain),
  Information_Gain = info_gain$attr_importance,
  Gain_Ratio = gain_rat$attr_importance,
  Symmetrical_Uncertainty = sym_uncert$attr_importance,
  Chi_Squared = chi_sq$attr_importance
)

# Сортировка по Information Gain
importance_df <- importance_df[order(-importance_df$Information_Gain), ]
print(importance_df)
##        Feature Information_Gain Gain_Ratio Symmetrical_Uncertainty Chi_Squared
## 4  Petal.Width        0.9554360  0.8713692               0.8705214   0.9432359
## 3 Petal.Length        0.9402853  0.8584937               0.8571872   0.9346311
## 1 Sepal.Length        0.4521286  0.4196464               0.4155563   0.6288067
## 2  Sepal.Width        0.2672750  0.2472972               0.2452743   0.4922162
# Визуализация важности признаков
par(mfrow = c(2, 2), mar = c(5, 8, 4, 2))

barplot(info_gain$attr_importance[order(info_gain$attr_importance)], 
        names.arg = rownames(info_gain)[order(info_gain$attr_importance)],
        horiz = TRUE, las = 1, col = "steelblue",
        main = "Information Gain", xlab = "Importance")

barplot(gain_rat$attr_importance[order(gain_rat$attr_importance)], 
        names.arg = rownames(gain_rat)[order(gain_rat$attr_importance)],
        horiz = TRUE, las = 1, col = "darkgreen",
        main = "Gain Ratio", xlab = "Importance")

barplot(sym_uncert$attr_importance[order(sym_uncert$attr_importance)], 
        names.arg = rownames(sym_uncert)[order(sym_uncert$attr_importance)],
        horiz = TRUE, las = 1, col = "darkorange",
        main = "Symmetrical Uncertainty", xlab = "Importance")

barplot(chi_sq$attr_importance[order(chi_sq$attr_importance)], 
        names.arg = rownames(chi_sq)[order(chi_sq$attr_importance)],
        horiz = TRUE, las = 1, col = "darkred",
        main = "Chi-Squared", xlab = "Importance")

# Сохранение графика
jpeg("plots/fselector_importance.jpg", width = 800, height = 600, quality = 100)
par(mfrow = c(2, 2), mar = c(5, 8, 4, 2))

barplot(info_gain$attr_importance[order(info_gain$attr_importance)], 
        names.arg = rownames(info_gain)[order(info_gain$attr_importance)],
        horiz = TRUE, las = 1, col = "steelblue",
        main = "Information Gain", xlab = "Importance")

barplot(gain_rat$attr_importance[order(gain_rat$attr_importance)], 
        names.arg = rownames(gain_rat)[order(gain_rat$attr_importance)],
        horiz = TRUE, las = 1, col = "darkgreen",
        main = "Gain Ratio", xlab = "Importance")

barplot(sym_uncert$attr_importance[order(sym_uncert$attr_importance)], 
        names.arg = rownames(sym_uncert)[order(sym_uncert$attr_importance)],
        horiz = TRUE, las = 1, col = "darkorange",
        main = "Symmetrical Uncertainty", xlab = "Importance")

barplot(chi_sq$attr_importance[order(chi_sq$attr_importance)], 
        names.arg = rownames(chi_sq)[order(chi_sq$attr_importance)],
        horiz = TRUE, las = 1, col = "darkred",
        main = "Chi-Squared", xlab = "Importance")
dev.off()
## png 
##   2

Выбор лучших признаков

# Выбор подмножества признаков с помощью cutoff
cutoff_features <- cutoff.k(info_gain, k = 2)
cat("Лучшие 2 признака (Information Gain):", cutoff_features, "\n")
## Лучшие 2 признака (Information Gain): Petal.Width Petal.Length
# Автоматический выбор на основе порога
cutoff_biggest <- cutoff.biggest.diff(info_gain)
cat("Признаки (biggest diff):", cutoff_biggest, "\n")
## Признаки (biggest diff): Petal.Width Petal.Length

2.5 Выводы по разделу 2

Выводы:

  1. Все методы (Information Gain, Gain Ratio, Symmetrical Uncertainty, Chi-Squared) согласованно определяют порядок важности признаков для набора данных iris:

    • Petal.Width - наиболее важный признак
    • Petal.Length - второй по важности
    • Sepal.Length и Sepal.Width - менее информативны для классификации видов ирисов
  2. Признаки лепестка (Petal) значительно более информативны для определения вида ириса, чем признаки чашелистика (Sepal).

  3. Пакет FSelector предоставляет удобные функции cutoff.k() и cutoff.biggest.diff() для автоматического выбора наиболее значимых признаков.


3. Пакет arules: Дискретизация непрерывных переменных

3.1 Установка и загрузка пакета

if (!requireNamespace("arules", quietly = TRUE)) {
  install.packages("arules", repos = "https://cloud.r-project.org/")
}
library(arules)

3.2 Исходные данные

# Используем переменную Sepal.Length из iris
data(iris)
sepal_length <- iris$Sepal.Length

cat("Статистика Sepal.Length:\n")
## Статистика Sepal.Length:
summary(sepal_length)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   4.300   5.100   5.800   5.843   6.400   7.900
cat("\nКоличество наблюдений:", length(sepal_length), "\n")
## 
## Количество наблюдений: 150

3.3 Методы дискретизации

Метод “interval” (равная ширина интервала)

# Дискретизация с равной шириной интервалов
disc_interval <- discretize(sepal_length, method = "interval", breaks = 4)
cat("\nМетод 'interval' (равная ширина интервалов):\n")
## 
## Метод 'interval' (равная ширина интервалов):
print(table(disc_interval))
## disc_interval
## [4.3,5.2) [5.2,6.1)   [6.1,7)   [7,7.9] 
##        41        48        48        13
print(levels(disc_interval))
## [1] "[4.3,5.2)" "[5.2,6.1)" "[6.1,7)"   "[7,7.9]"

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

# Дискретизация с равной частотой (квантили)
disc_frequency <- discretize(sepal_length, method = "frequency", breaks = 4)
cat("\nМетод 'frequency' (равная частота):\n")
## 
## Метод 'frequency' (равная частота):
print(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
print(levels(disc_frequency))
## [1] "[4.3,5.1)" "[5.1,5.8)" "[5.8,6.4)" "[6.4,7.9]"

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

# Дискретизация методом кластеризации
disc_cluster <- discretize(sepal_length, method = "cluster", breaks = 4)
cat("\nМетод 'cluster' (k-means кластеризация):\n")
## 
## Метод 'cluster' (k-means кластеризация):
print(table(disc_cluster))
## disc_cluster
##  [4.3,5.32) [5.32,6.12) [6.12,6.98)  [6.98,7.9] 
##          46          49          42          13
print(levels(disc_cluster))
## [1] "[4.3,5.32)"  "[5.32,6.12)" "[6.12,6.98)" "[6.98,7.9]"

Метод “fixed” (фиксированные границы)

# Дискретизация с фиксированными границами
disc_fixed <- discretize(sepal_length, method = "fixed", 
                         breaks = c(-Inf, 5.0, 6.0, 7.0, Inf),
                         labels = c("Маленький", "Средний", "Большой", "Очень большой"))
cat("\nМетод 'fixed' (фиксированные границы: 5.0, 6.0, 7.0):\n")
## 
## Метод 'fixed' (фиксированные границы: 5.0, 6.0, 7.0):
print(table(disc_fixed))
## disc_fixed
##     Маленький       Средний       Большой Очень большой 
##            22            61            54            13
print(levels(disc_fixed))
## [1] "Маленький"     "Средний"       "Большой"       "Очень большой"

3.4 Сравнительная визуализация

# Визуализация всех методов дискретизации
par(mfrow = c(3, 2), mar = c(4, 4, 3, 1))

# Оригинальные данные
hist(sepal_length, breaks = 20, col = "lightgray", 
     main = "Оригинальные данные", xlab = "Sepal.Length", border = "white")

# Interval
barplot(table(disc_interval), col = "steelblue", 
        main = "Interval (равная ширина)", las = 2, cex.names = 0.7)

# Frequency
barplot(table(disc_frequency), col = "darkgreen", 
        main = "Frequency (равная частота)", las = 2, cex.names = 0.7)

# Cluster
barplot(table(disc_cluster), col = "darkorange", 
        main = "Cluster (k-means)", las = 2, cex.names = 0.7)

# Fixed
barplot(table(disc_fixed), col = "darkred", 
        main = "Fixed (заданные границы)", las = 2, cex.names = 0.7)

# Сохранение графика
jpeg("plots/discretization_comparison.jpg", width = 800, height = 800, quality = 100)
par(mfrow = c(3, 2), mar = c(4, 4, 3, 1))

hist(sepal_length, breaks = 20, col = "lightgray", 
     main = "Оригинальные данные", xlab = "Sepal.Length", border = "white")

barplot(table(disc_interval), col = "steelblue", 
        main = "Interval (равная ширина)", las = 2, cex.names = 0.7)

barplot(table(disc_frequency), col = "darkgreen", 
        main = "Frequency (равная частота)", las = 2, cex.names = 0.7)

barplot(table(disc_cluster), col = "darkorange", 
        main = "Cluster (k-means)", las = 2, cex.names = 0.7)

barplot(table(disc_fixed), col = "darkred", 
        main = "Fixed (заданные границы)", las = 2, cex.names = 0.7)

dev.off()
## png 
##   2

3.5 Дискретизация всех числовых переменных iris

# Дискретизация всех числовых столбцов iris
iris_numeric <- iris[, 1:4]

# Применение метода frequency ко всем столбцам
iris_disc <- as.data.frame(lapply(iris_numeric, function(x) {
  discretize(x, method = "frequency", breaks = 3)
}))

# Добавление целевой переменной
iris_disc$Species <- iris$Species

cat("\nДискретизированный набор данных iris (первые 10 строк):\n")
## 
## Дискретизированный набор данных iris (первые 10 строк):
print(head(iris_disc, 10))
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1     [4.3,5.4)   [3.2,4.4]     [1,2.63) [0.1,0.867)  setosa
## 2     [4.3,5.4)   [2.9,3.2)     [1,2.63) [0.1,0.867)  setosa
## 3     [4.3,5.4)   [3.2,4.4]     [1,2.63) [0.1,0.867)  setosa
## 4     [4.3,5.4)   [2.9,3.2)     [1,2.63) [0.1,0.867)  setosa
## 5     [4.3,5.4)   [3.2,4.4]     [1,2.63) [0.1,0.867)  setosa
## 6     [5.4,6.3)   [3.2,4.4]     [1,2.63) [0.1,0.867)  setosa
## 7     [4.3,5.4)   [3.2,4.4]     [1,2.63) [0.1,0.867)  setosa
## 8     [4.3,5.4)   [3.2,4.4]     [1,2.63) [0.1,0.867)  setosa
## 9     [4.3,5.4)   [2.9,3.2)     [1,2.63) [0.1,0.867)  setosa
## 10    [4.3,5.4)   [2.9,3.2)     [1,2.63) [0.1,0.867)  setosa

3.6 Выводы по разделу 3

Выводы:

  1. Метод “interval” (равная ширина) делит диапазон данных на равные интервалы. Подходит, когда данные распределены равномерно.

  2. Метод “frequency” (равная частота) создает интервалы с примерно одинаковым количеством наблюдений. Лучше подходит для асимметричных распределений.

  3. Метод “cluster” (k-means) определяет границы на основе кластеризации данных. Эффективен для данных с естественными группами.

  4. Метод “fixed” позволяет задать экспертные границы категорий. Полезен, когда есть предметные знания о данных.

  5. Выбор метода дискретизации зависит от:

    • Распределения данных
    • Целей анализа
    • Наличия экспертных знаний о предметной области

4. Пакет Boruta: Выбор признаков для набора данных Ozone

4.1 Установка и загрузка пакетов

# Установка необходимых пакетов
if (!requireNamespace("Boruta", quietly = TRUE)) {
  install.packages("Boruta", repos = "https://cloud.r-project.org/")
}
if (!requireNamespace("mlbench", quietly = TRUE)) {
  install.packages("mlbench", repos = "https://cloud.r-project.org/")
}

library(Boruta)
library(mlbench)

4.2 Загрузка и подготовка данных Ozone

# Загрузка данных 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 ...
cat("\nРазмер данных:", nrow(Ozone), "x", ncol(Ozone), "\n")
## 
## Размер данных: 366 x 13
cat("Количество пропущенных значений по столбцам:\n")
## Количество пропущенных значений по столбцам:
print(colSums(is.na(Ozone)))
##  V1  V2  V3  V4  V5  V6  V7  V8  V9 V10 V11 V12 V13 
##   0   0   0   5  12   0  15   2 139  15   1  14   0
# Удаление строк с пропущенными значениями для Boruta
ozone_clean <- na.omit(Ozone)
cat("\nРазмер данных после удаления NA:", nrow(ozone_clean), "x", ncol(ozone_clean), "\n")
## 
## Размер данных после удаления NA: 203 x 13

4.3 Выполнение алгоритма Boruta

# Установка seed для воспроизводимости
set.seed(123)

# Выполнение Boruta (V4 - целевая переменная - уровень озона)
# V4 - Daily maximum one-hour-average ozone reading
boruta_result <- Boruta(V4 ~ ., data = ozone_clean, doTrace = 0)

print(boruta_result)
## Boruta performed 24 iterations in 1.718744 secs.
##  9 attributes confirmed important: V1, V10, V11, V12, V13 and 4 more;
##  3 attributes confirmed unimportant: V2, V3, V6;

4.4 Результаты выбора признаков

# Получение финальных результатов
cat("\nПодтвержденные (Confirmed) признаки:\n")
## 
## Подтвержденные (Confirmed) признаки:
print(getSelectedAttributes(boruta_result, withTentative = FALSE))
## [1] "V1"  "V5"  "V7"  "V8"  "V9"  "V10" "V11" "V12" "V13"
cat("\nВсе важные признаки (включая Tentative):\n")
## 
## Все важные признаки (включая Tentative):
print(getSelectedAttributes(boruta_result, withTentative = TRUE))
## [1] "V1"  "V5"  "V7"  "V8"  "V9"  "V10" "V11" "V12" "V13"
# Подробная таблица результатов
boruta_df <- attStats(boruta_result)
boruta_df <- boruta_df[order(-boruta_df$meanImp), ]
print(boruta_df)
##        meanImp  medianImp     minImp     maxImp  normHits  decision
## V9  19.2281405 19.0627349 17.5889826 20.9190449 1.0000000 Confirmed
## V8  17.1647491 17.2255744 16.0336735 18.5525852 1.0000000 Confirmed
## V12 14.6326841 14.6095338 13.5595253 16.0775580 1.0000000 Confirmed
## V11 11.8977619 11.8484607 10.9347533 13.6520570 1.0000000 Confirmed
## V7  11.7026875 11.5169965 10.5127703 13.4896943 1.0000000 Confirmed
## V10  9.8662368  9.7266893  8.6477478 11.3131795 1.0000000 Confirmed
## V1   9.5563296  9.7071000  8.4255686 10.7247899 1.0000000 Confirmed
## V13  9.4438214  9.5489762  8.1005306 10.7881019 1.0000000 Confirmed
## V5   9.2426781  9.2313179  8.1108460 10.5140883 1.0000000 Confirmed
## V2   1.1557680  1.1576551 -0.2474598  2.7423660 0.1666667  Rejected
## V6   0.9886679  1.3615721 -1.1013954  1.9852132 0.0000000  Rejected
## V3  -0.9877372 -0.7333367 -3.4162909  0.3794342 0.0000000  Rejected

4.5 Box Plot важности признаков

# Построение boxplot
plot(boruta_result, las = 2, cex.axis = 0.7, 
     xlab = "", main = "Boruta Feature Importance - Ozone Dataset")

# Сохранение графика
jpeg("plots/boruta_boxplot.jpg", width = 1000, height = 600, quality = 100)
plot(boruta_result, las = 2, cex.axis = 0.7, 
     xlab = "", main = "Boruta Feature Importance - Ozone Dataset")
dev.off()
## png 
##   2

4.6 Разрешение неопределенных (Tentative) признаков

# Попытка определить статус Tentative признаков
boruta_final <- TentativeRoughFix(boruta_result)
print(boruta_final)
## Boruta performed 24 iterations in 1.718744 secs.
##  9 attributes confirmed important: V1, V10, V11, V12, V13 and 4 more;
##  3 attributes confirmed unimportant: V2, V3, V6;
cat("\nФинальный список подтвержденных признаков:\n")
## 
## Финальный список подтвержденных признаков:
print(getSelectedAttributes(boruta_final))
## [1] "V1"  "V5"  "V7"  "V8"  "V9"  "V10" "V11" "V12" "V13"

4.7 Выводы по разделу 4

Выводы:

  1. Алгоритм Boruta использует метод случайного леса для определения важности признаков, сравнивая их с “теневыми” (shadow) признаками.

  2. Признаки классифицируются на три категории:

    • Confirmed (зеленый) - достоверно важные признаки
    • Tentative (желтый) - неопределенные признаки, требуют дополнительного анализа
    • Rejected (красный) - неважные признаки
  3. Для набора данных Ozone наиболее важными признаками оказались метеорологические параметры (температура, влажность, давление), что соответствует научным представлениям о факторах, влияющих на концентрацию озона.

  4. Box plot наглядно показывает распределение важности каждого признака по итерациям алгоритма, а также сравнение с теневыми признаками (shadowMin, shadowMean, shadowMax).


Заключение

В данной лабораторной работе были изучены различные методы выбора признаков и дискретизации данных:

  1. Пакет caret предоставляет широкий набор методов машинного обучения и удобные средства визуализации для разведочного анализа данных.

  2. Пакет FSelector позволяет оценить важность признаков различными методами на основе теории информации и статистических тестов.

  3. Пакет arules предлагает гибкие методы дискретизации непрерывных переменных с различными стратегиями определения границ интервалов.

  4. Пакет Boruta реализует надежный алгоритм выбора признаков на основе случайного леса с использованием теневых атрибутов.


Информация о сессии

sessionInfo()
## R version 4.5.2 (2025-10-31)
## Platform: x86_64-pc-linux-gnu
## Running under: CachyOS
## 
## Matrix products: default
## BLAS:   /usr/lib/libblas.so.3.12.0 
## LAPACK: /usr/lib/liblapack.so.3.12.0  LAPACK version 3.12.0
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8          LC_NUMERIC=C                 
##  [3] LC_TIME=en_US.UTF-8           LC_COLLATE=en_US.UTF-8       
##  [5] LC_MONETARY=en_US.UTF-8       LC_MESSAGES=en_US.UTF-8      
##  [7] LC_PAPER=en_US.UTF-8          LC_NAME=en_US.UTF-8          
##  [9] LC_ADDRESS=en_US.UTF-8        LC_TELEPHONE=en_US.UTF-8     
## [11] LC_MEASUREMENT=en_US.UTF-8    LC_IDENTIFICATION=en_US.UTF-8
## 
## time zone: Europe/Samara
## tzcode source: system (glibc)
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] mlbench_2.1-6  Boruta_9.0.0   arules_1.7.13  Matrix_1.7-4   FSelector_0.34
## [6] caret_7.0-1    lattice_0.22-7 ggplot2_4.0.2 
## 
## loaded via a namespace (and not attached):
##  [1] gtable_0.3.6         xfun_0.56            bslib_0.10.0        
##  [4] recipes_1.3.1        rJava_1.0-14         vctrs_0.7.1         
##  [7] tools_4.5.2          generics_0.1.4       stats4_4.5.2        
## [10] parallel_4.5.2       tibble_3.3.1         pkgconfig_2.0.3     
## [13] ModelMetrics_1.2.2.2 data.table_1.18.2.1  RColorBrewer_1.1-3  
## [16] S7_0.2.1             lifecycle_1.0.5      compiler_4.5.2      
## [19] farver_2.1.2         stringr_1.6.0        codetools_0.2-20    
## [22] htmltools_0.5.9      class_7.3-23         sass_0.4.10         
## [25] yaml_2.3.12          prodlim_2025.04.28   pillar_1.11.1       
## [28] jquerylib_0.1.4      MASS_7.3-65          entropy_1.3.2       
## [31] cachem_1.1.0         gower_1.0.2          iterators_1.0.14    
## [34] rpart_4.1.24         foreach_1.5.2        nlme_3.1-168        
## [37] parallelly_1.46.1    lava_1.8.2           tidyselect_1.2.1    
## [40] digest_0.6.39        stringi_1.8.7        future_1.69.0       
## [43] dplyr_1.2.0          reshape2_1.4.5       purrr_1.2.1         
## [46] listenv_0.10.0       RWekajars_3.9.3-2    splines_4.5.2       
## [49] fastmap_1.2.0        grid_4.5.2           cli_3.6.5           
## [52] magrittr_2.0.4       randomForest_4.7-1.2 survival_3.8-3      
## [55] future.apply_1.20.1  withr_3.0.2          scales_1.4.0        
## [58] lubridate_1.9.5      timechange_0.4.0     rmarkdown_2.30      
## [61] globals_0.19.0       nnet_7.3-20          RWeka_0.4-46        
## [64] timeDate_4052.112    ranger_0.18.0        evaluate_1.0.5      
## [67] knitr_1.51           hardhat_1.4.2        rlang_1.1.7         
## [70] Rcpp_1.1.1           glue_1.8.0           pROC_1.19.0.1       
## [73] ipred_0.9-15         jsonlite_2.0.0       R6_2.6.1            
## [76] plyr_1.8.9