# if (!require(caret)) install.packages("caret", dependencies=TRUE)
library(caret)

# 1. Работа с пакетом CARET

cat("Часть 1\n")
## Часть 1
# Ознакомление с методами выбора признаков
methods_list <- names(getModelInfo())
cat("Всего методов:", length(methods_list), "\n")
## Всего методов: 239
head(methods_list, 20)  # Показали 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))

# Построение графиков. Боксплот
jpeg("boxplot_features.jpg")
featurePlot(x, y, plot = "box")
dev.off()
## png 
##   2
knitr::include_graphics("boxplot_features.jpg")

# График плотности
jpeg("density_features.jpg")
featurePlot(x, y, plot = "density")
dev.off()
## png 
##   2
knitr::include_graphics("density_features.jpg")

# График разброса
jpeg("pairs_features.jpg")
featurePlot(x, y, plot = "pairs")
dev.off()
## png 
##   2
knitr::include_graphics("pairs_features.jpg")

# Выводы
cat("Выводы:\n")
## Выводы:
cat("В пакете `caret` доступно", length(methods_list), "методов выбора признаков.Boxplot показывает различия в распределении признаков между классами. Density Plot помогает определить, какие признаки лучше всего разделяют классы.Scatter Plot показывает взаимосвязи между признаками и классами.\n")
## В пакете `caret` доступно 239 методов выбора признаков.Boxplot показывает различия в распределении признаков между классами. Density Plot помогает определить, какие признаки лучше всего разделяют классы.Scatter Plot показывает взаимосвязи между признаками и классами.
cat("Так как мы использовали случайные данные, никакой из методов не показал четкого разделения классов - признаки сильно пересекаются, их распределения смешаны, а различия между классами отсутствуют. В реальной задаче это означало бы, что признаки неинформативны, и нужно искать более значимые переменные.")
## Так как мы использовали случайные данные, никакой из методов не показал четкого разделения классов - признаки сильно пересекаются, их распределения смешаны, а различия между классами отсутствуют. В реальной задаче это означало бы, что признаки неинформативны, и нужно искать более значимые переменные.
# 2. Использование функций из пакета Fselector

# if (!require(FSelector)) install.packages("FSelector", dependencies=TRUE)
library(FSelector)

data(iris) # Используем встроенный набор данных iris

# Оценка важности признаков с помощью метода Information Gain
importance_info_gain <- information.gain(Species ~ ., iris)
print(importance_info_gain)
##              attr_importance
## Sepal.Length       0.4521286
## Sepal.Width        0.2672750
## Petal.Length       0.9402853
## Petal.Width        0.9554360
# Чем выше значение, тем более важен признак для классификации

# Оценка важности признаков с помощью Gain Ratio
# Этот способ нормализует значения, чтобы не отдавать приоритет признакам с большим количеством уникальных значений
importance_gain_ratio <- gain.ratio(Species ~ ., iris)
print(importance_gain_ratio)
##              attr_importance
## Sepal.Length       0.4196464
## Sepal.Width        0.2472972
## Petal.Length       0.8584937
## Petal.Width        0.8713692
# Оценка важности признаков с помощью Symmetrical Uncertainty
# Измеряем взаимосвязь между признаками и классами
importance_sym_uncertainty <- symmetrical.uncertainty(Species ~ ., iris)
print(importance_sym_uncertainty)
##              attr_importance
## Sepal.Length       0.4155563
## Sepal.Width        0.2452743
## Petal.Length       0.8571872
## Petal.Width        0.8705214
# Визуализация важности признаков
jpeg("feature_importance.jpg")
barplot(importance_info_gain$attr_importance, 
        names.arg = rownames(importance_info_gain), 
        col = "steelblue", 
        main = "Важность признаков", 
        las = 2)
dev.off()
## png 
##   2
knitr::include_graphics("feature_importance.jpg")

# Выводы
cat("Выводы:\n")
## Выводы:
cat("Методы Information Gain, Gain Ratio и Symmetrical Uncertainty позволяют оценить важность признаков.Наибольший вклад в классификацию вносят признаки Petal.Length и Petal.Width.Sepal.Length и Sepal.Width оказываются менее значимыми.")
## Методы Information Gain, Gain Ratio и Symmetrical Uncertainty позволяют оценить важность признаков.Наибольший вклад в классификацию вносят признаки Petal.Length и Petal.Width.Sepal.Length и Sepal.Width оказываются менее значимыми.
# 3. Преобразование непрерывной переменной в категориальную

library(arules)
# arules - это пакет для работы с ассоциативными правилами, но здесь мы используем его функцию discretize() для преобразования непрерывных данных в категориальные

# Выбираем признак для дискретизации(длина)
feature <- iris$Sepal.Length

# Дискретизация разными методами

# 1. Interval (равная ширина интервалов)
iris$Sepal.Length_interval <- discretize(feature, method = "interval", categories = 3)
# Разбивает диапазон значений длины на 3 равных интервала(если значения от 4.3 до 7.9, то интервалы будут [4.3–5.5], [5.5–6.7], [6.7–7.9])

# 2. Frequency (равная частота значений в каждом интервале)
iris$Sepal.Length_frequency <- discretize(feature, method = "frequency", categories = 3)
# Делит данные так, чтобы в каждой категории было примерно одинаковое количество значений

# 3. Cluster (кластеризация значений)
iris$Sepal.Length_cluster <- discretize(feature, method = "cluster", categories = 3)
# Использует кластеризацию, чтобы найти естественные группы значений

# 4. Fixed (заданные границы)
fixed_breaks <- c(min(feature), 5.0, 6.0, max(feature))
iris$Sepal.Length_fixed <- discretize(feature, method = "fixed", categories = fixed_breaks)
# Вручную задаём границы интервалов

# Теперь визуализируем распределение дискретизированных значений

library(ggplot2)
library(reshape2)

# Преобразуем данные для удобной визуализации

# Создаём таблицу с дискретизированными значениями
discretized_data <- data.frame(
  Original = feature,
  Interval = as.numeric(iris$Sepal.Length_interval),
  Frequency = as.numeric(iris$Sepal.Length_frequency),
  Cluster = as.numeric(iris$Sepal.Length_cluster),
  Fixed = as.numeric(iris$Sepal.Length_fixed)
)

# Преобразуем таблицу для ggplot2
discretized_long <- melt(discretized_data, id.vars = "Original")

# Строим график распределения
jpeg("discretization_plot.jpg", width = 800, height = 600)
ggplot(discretized_long, aes(x = Original, fill = factor(value))) +
  geom_histogram(bins = 15, alpha = 0.6, position = "identity") +
  facet_wrap(~ variable, scales = "free_y") +
  theme_minimal() +
  labs(title = "Дискретизация Sepal.Length разными методами",
       x = "Исходное значение", y = "Частота", fill = "Категории")
dev.off()
## png 
##   2
knitr::include_graphics("discretization_plot.jpg")

# Выводы
cat("Выводы:\n")
## Выводы:
cat("Метод `interval` делит диапазон на равные промежутки, но может плохо работать с неравномерными данными. Метод `frequency` старается сделать так, чтобы в каждой категории было примерно одинаковое число значений. Метод `cluster` группирует данные по схожести, что может быть полезно, если есть естественные группы. Метод `fixed` позволяет вручную задавать границы интервалов, но требует знания структуры данных.\n")
## Метод `interval` делит диапазон на равные промежутки, но может плохо работать с неравномерными данными. Метод `frequency` старается сделать так, чтобы в каждой категории было примерно одинаковое число значений. Метод `cluster` группирует данные по схожести, что может быть полезно, если есть естественные группы. Метод `fixed` позволяет вручную задавать границы интервалов, но требует знания структуры данных.
# 4. Выбор признаков для набора данных data("Ozone")

library(Boruta)
library(mlbench)

data("Ozone")

# Удаляем строки с пропущенными значениями
Ozone <- na.omit(Ozone)

# Выполняем алгоритм Boruta для выбора значимых признаков
set.seed(123)  # Снова фиксируем случайность для воспроизводимости
boruta_result <- Boruta(V4 ~ ., data = Ozone, doTrace = 0)

# Выводим итоговые результаты
print(boruta_result)
## Boruta performed 24 iterations in 1.189635 secs.
##  9 attributes confirmed important: V1, V10, V11, V12, V13 and 4 more;
##  3 attributes confirmed unimportant: V2, V3, V6;
# Строим boxplot для визуализации важности признаков
jpeg("boruta_boxplot.jpg", width = 800, height = 600)
plot(boruta_result, las = 2, xlab = "Признаки", main = "Важность признаков по Boruta")
dev.off()
## png 
##   2
knitr::include_graphics("boruta_boxplot.jpg")

# Выводы
cat("Выводы:\n")
## Выводы:
cat("Boruta позволяет оценить, какие признаки важны для предсказания целевой переменной. Boxplot показывает распределение важности каждого признака, выявляя значимые и незначимые.\n")
## Boruta позволяет оценить, какие признаки важны для предсказания целевой переменной. Boxplot показывает распределение важности каждого признака, выявляя значимые и незначимые.
cat("На графике мы видим, что действительно значимыми признаками являются V5-V9. Значимые признаки имеют большой разрыв с незначимыми. Его можно увидеть на моменте перехода между ShadowMax и V5")
## На графике мы видим, что действительно значимыми признаками являются V5-V9. Значимые признаки имеют большой разрыв с незначимыми. Его можно увидеть на моменте перехода между ShadowMax и V5