# 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