В этой лабораторной работе мы продолжим изучение методов выбора признаков, используя пакеты caret, FSelector, arules и Boruta.
Установить пакет CARET, выполнить команду names(getModelInfo()), ознакомиться со списком доступных методов выбора признаков. Выполните графический разведочный анализ данных с использование функции featurePlot() для набора данных из справочного файла пакета CARET:
x <- matrix(rnorm(50*5),ncol=5)
y <- factor(rep(c(“A”, “B”), 25))
Сохранить полученные графики в *.jpg файлы. Сделать выводы.
# Установите пакет caret, если он еще не установлен
if(!requireNamespace("caret", quietly = TRUE)) {
install.packages("caret")
}
# Загрузите пакет caret
library(caret)
## Загрузка требуемого пакета: ggplot2
## Загрузка требуемого пакета: lattice
# Выполните команду names(getModelInfo()) и ознакомьтесь со списком доступных методов выбора признаков
model_names <- names(getModelInfo())
print(model_names)
## [1] "ada" "AdaBag" "AdaBoost.M1"
## [4] "adaboost" "amdai" "ANFIS"
## [7] "avNNet" "awnb" "awtan"
## [10] "bag" "bagEarth" "bagEarthGCV"
## [13] "bagFDA" "bagFDAGCV" "bam"
## [16] "bartMachine" "bayesglm" "binda"
## [19] "blackboost" "blasso" "blassoAveraged"
## [22] "bridge" "brnn" "BstLm"
## [25] "bstSm" "bstTree" "C5.0"
## [28] "C5.0Cost" "C5.0Rules" "C5.0Tree"
## [31] "cforest" "chaid" "CSimca"
## [34] "ctree" "ctree2" "cubist"
## [37] "dda" "deepboost" "DENFIS"
## [40] "dnn" "dwdLinear" "dwdPoly"
## [43] "dwdRadial" "earth" "elm"
## [46] "enet" "evtree" "extraTrees"
## [49] "fda" "FH.GBML" "FIR.DM"
## [52] "foba" "FRBCS.CHI" "FRBCS.W"
## [55] "FS.HGD" "gam" "gamboost"
## [58] "gamLoess" "gamSpline" "gaussprLinear"
## [61] "gaussprPoly" "gaussprRadial" "gbm_h2o"
## [64] "gbm" "gcvEarth" "GFS.FR.MOGUL"
## [67] "GFS.LT.RS" "GFS.THRIFT" "glm.nb"
## [70] "glm" "glmboost" "glmnet_h2o"
## [73] "glmnet" "glmStepAIC" "gpls"
## [76] "hda" "hdda" "hdrda"
## [79] "HYFIS" "icr" "J48"
## [82] "JRip" "kernelpls" "kknn"
## [85] "knn" "krlsPoly" "krlsRadial"
## [88] "lars" "lars2" "lasso"
## [91] "lda" "lda2" "leapBackward"
## [94] "leapForward" "leapSeq" "Linda"
## [97] "lm" "lmStepAIC" "LMT"
## [100] "loclda" "logicBag" "LogitBoost"
## [103] "logreg" "lssvmLinear" "lssvmPoly"
## [106] "lssvmRadial" "lvq" "M5"
## [109] "M5Rules" "manb" "mda"
## [112] "Mlda" "mlp" "mlpKerasDecay"
## [115] "mlpKerasDecayCost" "mlpKerasDropout" "mlpKerasDropoutCost"
## [118] "mlpML" "mlpSGD" "mlpWeightDecay"
## [121] "mlpWeightDecayML" "monmlp" "msaenet"
## [124] "multinom" "mxnet" "mxnetAdam"
## [127] "naive_bayes" "nb" "nbDiscrete"
## [130] "nbSearch" "neuralnet" "nnet"
## [133] "nnls" "nodeHarvest" "null"
## [136] "OneR" "ordinalNet" "ordinalRF"
## [139] "ORFlog" "ORFpls" "ORFridge"
## [142] "ORFsvm" "ownn" "pam"
## [145] "parRF" "PART" "partDSA"
## [148] "pcaNNet" "pcr" "pda"
## [151] "pda2" "penalized" "PenalizedLDA"
## [154] "plr" "pls" "plsRglm"
## [157] "polr" "ppr" "pre"
## [160] "PRIM" "protoclass" "qda"
## [163] "QdaCov" "qrf" "qrnn"
## [166] "randomGLM" "ranger" "rbf"
## [169] "rbfDDA" "Rborist" "rda"
## [172] "regLogistic" "relaxo" "rf"
## [175] "rFerns" "RFlda" "rfRules"
## [178] "ridge" "rlda" "rlm"
## [181] "rmda" "rocc" "rotationForest"
## [184] "rotationForestCp" "rpart" "rpart1SE"
## [187] "rpart2" "rpartCost" "rpartScore"
## [190] "rqlasso" "rqnc" "RRF"
## [193] "RRFglobal" "rrlda" "RSimca"
## [196] "rvmLinear" "rvmPoly" "rvmRadial"
## [199] "SBC" "sda" "sdwd"
## [202] "simpls" "SLAVE" "slda"
## [205] "smda" "snn" "sparseLDA"
## [208] "spikeslab" "spls" "stepLDA"
## [211] "stepQDA" "superpc" "svmBoundrangeString"
## [214] "svmExpoString" "svmLinear" "svmLinear2"
## [217] "svmLinear3" "svmLinearWeights" "svmLinearWeights2"
## [220] "svmPoly" "svmRadial" "svmRadialCost"
## [223] "svmRadialSigma" "svmRadialWeights" "svmSpectrumString"
## [226] "tan" "tanSearch" "treebag"
## [229] "vbmpRadial" "vglmAdjCat" "vglmContRatio"
## [232] "vglmCumulative" "widekernelpls" "WM"
## [235] "wsrf" "xgbDART" "xgbLinear"
## [238] "xgbTree" "xyf"
# Подготовьте данные из справочного файла пакета CARET:
x <- matrix(rnorm(50*5),ncol=5)
y <- factor(rep(c("A", "B"), 25))
# Получаем путь к рабочему столу
desktop_path <- file.path(Sys.getenv("USERPROFILE"), "Desktop")
# Создадим графики отдельно для каждой пары признаков
for (i in 1:ncol(x)) {
for (j in 1:ncol(x)) {
if (i != j) {
# Создайте имя файла для графика
filename <- file.path(desktop_path, paste0("featurePlot_", i, "_", j, ".jpg"))
# Создайте график scatterplot
plot(x[,i], x[,j], col=ifelse(y=="A", "red", "blue"),
xlab=paste("Признак", i), ylab=paste("Признак", j),
main=paste("Признаки", i, "vs", j))
legend("topright", legend=levels(y), col=c("red", "blue"), pch=1)
# Откройте графическое устройство JPEG
jpeg(filename, width = 800, height = 600)
# Повторно создайте график scatterplot для сохранения в файл
plot(x[,i], x[,j], col=ifelse(y=="A", "red", "blue"),
xlab=paste("Признак", i), ylab=paste("Признак", j),
main=paste("Признаки", i, "vs", j))
legend("topright", legend=levels(y), col=c("red", "blue"), pch=1)
# Закройте графическое устройство JPEG
dev.off()
# Выведите сообщение о создании файла
cat("График сохранен в файл:", filename, "\n")
}
}
}
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_1_2.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_1_3.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_1_4.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_1_5.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_2_1.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_2_3.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_2_4.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_2_5.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_3_1.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_3_2.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_3_4.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_3_5.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_4_1.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_4_2.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_4_3.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_4_5.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_5_1.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_5_2.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_5_3.jpg
## График сохранен в файл: C:\Users\lexus/Desktop/featurePlot_5_4.jpg
Слабая разделимость: В целом, признаки демонстрируют слабую разделимость между классами A и B. Ящичковые диаграммы сильно перекрываются, что затрудняет четкое разделение классов.
Feature4 и Feature5 потенциально полезны: Feature4 и Feature5 могут внести некоторый вклад в классификацию, но в сочетании с другими признаками или более сложными моделями.
Feature1, Feature2 и Feature3 - низкая информативность: Feature1, Feature2 и Feature3, вероятно, не будут полезны для классификации в текущем виде.
С использование функций из пакета Fselector [2] определить важность признаков для решения задачи классификации. Использовать набор data(iris). Сделать выводы.
не удалось установить и запустить пакет FSelector. Вместо него используется пакет Caret с похожим функционалом
#Установите пакет caret, если он еще не установлен
if(!requireNamespace("caret", quietly = TRUE)) {
install.packages("caret")
}
# Загрузите пакет caret
library(caret)
# Подготовьте данные
data(iris)
dataset <- iris
control <- trainControl(method="cv", number=10)
model <- train(Species ~ ., data=dataset[,c(1:5)], method="rf", trControl=control, importance=TRUE)
print(model)
## Random Forest
##
## 150 samples
## 4 predictor
## 3 classes: 'setosa', 'versicolor', 'virginica'
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 135, 135, 135, 135, 135, 135, ...
## Resampling results across tuning parameters:
##
## mtry Accuracy Kappa
## 2 0.9600000 0.94
## 3 0.9600000 0.94
## 4 0.9533333 0.93
##
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was mtry = 2.
importance <- varImp(model)
print(importance)
## rf variable importance
##
## variables are sorted by maximum importance across the classes
## setosa versicolor virginica
## Petal.Width 67.031 100.00 91.204
## Petal.Length 59.390 94.33 76.212
## Sepal.Length 11.481 15.92 16.659
## Sepal.Width 7.226 0.00 6.922
plot(importance)
Petal.Length и Petal.Width - наиболее важные признаки для классификации видов Iris: Эти два признака имеют значительно более высокую важность по сравнению с Sepal.Length и Sepal.Width для всех трех видов Iris (setosa, versicolor и virginica).
Sepal.Length и Sepal.Width имеют относительно низкую важность: Эти признаки вносят меньший вклад в разделение видов Iris по сравнению с длиной и шириной лепестков. Особенности важности признаков для каждого вида: Для Iris setosa, как Petal.Length так и Petal.Width сильно отделяют от других видов, о чем свидетельствуют высокие значения важности.
Sepal.Length и Sepal.Width имеют низкую важность. Для Iris versicolor и Iris virginica Petal.Length и Petal.Width по-прежнему важны, но разница в важности между этими признаками и Sepal.Length/Sepal.Width менее выражена, чем для Iris setosa. Это указывает на то, что для различения versicolor и virginica требуется больше информации о размерах чашелистиков.
Длина и ширина лепестков - ключевые различители: Размеры лепестков, вероятно, являются наиболее визуально различимыми особенностями, которые помогают в идентификации этих видов Iris. Данные подтверждают эту визуальную гипотезу.
С использованием функции discretize() из пакета arules выполните преобразование непрерывной переменной в категориальную [3] различными методами: «interval» (равная ширина интервала), «frequency» (равная частота), «cluster» (кластеризация) и «fixed» (категории задают границы интервалов). Используйте набор данных iris. Сделайте выводы
# Установите пакет arules, если он еще не установлен
if(!requireNamespace("arules", quietly = TRUE)) {
install.packages("arules")
}
# Загрузите пакет arules
library(arules)
## Загрузка требуемого пакета: Matrix
##
## Присоединяю пакет: 'arules'
## Следующие объекты скрыты от 'package:base':
##
## abbreviate, write
# Подготовьте данные
data(iris)
dataset <- iris
# Определите непрерывные переменные, которые будем дискретизировать
continuous_vars <- c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")
# Определите различные методы дискретизации
methods <- c("interval", "frequency", "cluster", "fixed")
# Задайте границы интервалов для метода "fixed" (пример)
# Важно подобрать эти границы на основе понимания данных
fixed_breaks <- c(0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, Inf)
# Создайте функцию для дискретизации переменной с заданным методом
discretize_variable <- function(data, variable, method, breaks = NULL) {
if (method == "fixed") {
if (is.null(breaks)) {
stop("Необходимо указать границы интервалов для метода 'fixed'")
}
#Определим labels вручную
labels = character()
for (i in 1:(length(breaks)-1)) {
labels = append(labels,paste0("(",breaks[i],", ",breaks[i+1],"]"))
}
discretized_var <- discretize(data[[variable]], method = method, breaks = breaks, labels=labels)
} else {
discretized_var <- discretize(data[[variable]], method = method)
}
return(discretized_var)
}
# Создайте функцию для анализа результатов дискретизации
analyze_discretization <- function(data, variable, discretized_var, method) {
# Выведите таблицу частот для каждой категории
print(table(discretized_var))
# Посчитайте количество уникальных категорий
num_categories <- length(unique(discretized_var))
cat("Количество уникальных категорий:", num_categories, "\n")
# Создайте гистограмму
hist(as.numeric(discretized_var), # Преобразуем в числовой формат для гистограммы
main = paste("Гистограмма для", variable, "(Метод:", method, ")"),
xlab = "Категории",
ylab = "Частота",
col = "lightblue",
border = "black",
breaks = num_categories) # Указываем количество интервалов
}
# Примените дискретизацию к каждой переменной каждым методом и проанализируйте результаты
for (variable in continuous_vars) {
cat("----------------------------------------\n")
cat("Переменная:", variable, "\n")
for (method in methods) {
cat(" Метод:", method, "\n")
if (method == "fixed") {
discretized_var <- discretize_variable(dataset, variable, method, breaks = fixed_breaks)
} else {
discretized_var <- discretize_variable(dataset, variable, method)
}
analyze_discretization(dataset, variable, discretized_var, method) # Передаём имя переменной
}
}
## ----------------------------------------
## Переменная: Sepal.Length
## Метод: interval
## discretized_var
## [4.3,5.5) [5.5,6.7) [6.7,7.9]
## 52 70 28
## Количество уникальных категорий: 3
## Метод: frequency
## discretized_var
## [4.3,5.4) [5.4,6.3) [6.3,7.9]
## 46 53 51
## Количество уникальных категорий: 3
## Метод: cluster
## discretized_var
## [4.3,5.33) [5.33,6.27) [6.27,7.9]
## 46 53 51
## Количество уникальных категорий: 3
## Метод: fixed
## discretized_var
## (0, 4.5] (4.5, 5] (5, 5.5] (5.5, 6] (6, 6.5] (6.5, 7] (7, 7.5] (7.5, 8]
## 4 18 30 31 32 22 7 6
## (8, Inf]
## 0
## Количество уникальных категорий: 8
## ----------------------------------------
## Переменная: Sepal.Width
## Метод: interval
## discretized_var
## [2,2.8) [2.8,3.6) [3.6,4.4]
## 47 88 15
## Количество уникальных категорий: 3
## Метод: frequency
## discretized_var
## [2,2.9) [2.9,3.2) [3.2,4.4]
## 47 47 56
## Количество уникальных категорий: 3
## Метод: cluster
## discretized_var
## [2,2.75) [2.75,3.29) [3.29,4.4]
## 33 74 43
## Количество уникальных категорий: 3
## Метод: fixed
## discretized_var
## (0, 4.5] (4.5, 5] (5, 5.5] (5.5, 6] (6, 6.5] (6.5, 7] (7, 7.5] (7.5, 8]
## 150 0 0 0 0 0 0 0
## (8, Inf]
## 0
## Количество уникальных категорий: 1
## ----------------------------------------
## Переменная: Petal.Length
## Метод: interval
## discretized_var
## [1,2.97) [2.97,4.93) [4.93,6.9]
## 50 54 46
## Количество уникальных категорий: 3
## Метод: frequency
## discretized_var
## [1,2.63) [2.63,4.9) [4.9,6.9]
## 50 49 51
## Количество уникальных категорий: 3
## Метод: cluster
## discretized_var
## [1,2.85) [2.85,4.89) [4.89,6.9]
## 50 49 51
## Количество уникальных категорий: 3
## Метод: fixed
## discretized_var
## (0, 4.5] (4.5, 5] (5, 5.5] (5.5, 6] (6, 6.5] (6.5, 7] (7, 7.5] (7.5, 8]
## 79 25 18 17 7 4 0 0
## (8, Inf]
## 0
## Количество уникальных категорий: 6
## ----------------------------------------
## Переменная: Petal.Width
## Метод: interval
## discretized_var
## [0.1,0.9) [0.9,1.7) [1.7,2.5]
## 50 52 48
## Количество уникальных категорий: 3
## Метод: frequency
## discretized_var
## [0.1,0.867) [0.867,1.6) [1.6,2.5]
## 50 48 52
## Количество уникальных категорий: 3
## Метод: cluster
## discretized_var
## [0.1,0.792) [0.792,1.71) [1.71,2.5]
## 50 54 46
## Количество уникальных категорий: 3
## Метод: fixed
## discretized_var
## (0, 4.5] (4.5, 5] (5, 5.5] (5.5, 6] (6, 6.5] (6.5, 7] (7, 7.5] (7.5, 8]
## 150 0 0 0 0 0 0 0
## (8, Inf]
## 0
## Количество уникальных категорий: 1
Общие наблюдения для всех переменных и методов:
Для методов interval, frequency и cluster количество уникальных категорий всегда равно 3. Это связано с тем, что эти методы по умолчанию разбивают данные на заданное число интервалов (в данном случае, вероятно, по умолчанию используется 3 интервала). Метод fixed позволяет задать произвольные границы интервалов, что приводит к разному количеству категорий в зависимости от выбранных границ. Переменная Sepal.Length:
Метод interval создает интервалы примерно равной ширины (около 1.2 единицы длины чашелистика). Метод frequency создает интервалы, в которых находится примерно одинаковое количество наблюдений (около 50). Метод cluster находит интервалы на основе кластеризации данных. Метод fixed с заданными границами позволяет детально анализировать распределение переменной по различным диапазонам значений. Обратите внимание на количество наблюдений в интервалах (0, 4.5], (4.5, 5] и т.д. Переменная Sepal.Width:
Методы interval, frequency и cluster показывают, что большинство значений Sepal.Width находятся в интервале [2.8, 3.6). Метод fixed показывает, что все значения Sepal.Width попадают в интервал (0, 4.5]. Это связано с тем, что используемые границы интервалов не подходят для этой переменной (они слишком широкие). Нужно изменить границы интервалов для метода fixed, чтобы получить более полезную информацию. Переменная Petal.Length:
Методы interval, frequency и cluster показывают равномерное распределение Petal.Length по трем интервалам. Метод fixed показывает более детальное распределение. Большинство значений (79) находятся в интервале (0, 4.5]. Переменная Petal.Width:
Результаты для Petal.Width аналогичны результатам для Petal.Length. Для метода fixed опять все значения попадают в первый интервал (0, 4.5], что требует корректировки границ интервалов.
Установите пакет Boruta и проведите выбор признаков для набора данных data(“Ozone”) [4, 5, 6]. Построить график boxplot, сделать выводы.
# Установите пакет mlbench, если он еще не установлен
if(!requireNamespace("mlbench", quietly = TRUE)) {
install.packages("mlbench")
}
# Загрузите пакет mlbench
library(mlbench)
# Загрузите пакет Boruta, если он еще не установлен
if(!requireNamespace("Boruta", quietly = TRUE)) {
install.packages("Boruta")
}
# Загрузите пакет Boruta
library(Boruta)
# Подготовьте данные
data("Ozone", package = "mlbench") #Явно указываем, что данные находятся в пакете mlbench
ozone <- na.omit(Ozone) # Удаляем строки с NA
# Выполните выбор признаков с помощью Boruta
set.seed(123) # Для воспроизводимости результатов
boruta_output <- Boruta(V9 ~ ., data = ozone, mcAdj=TRUE)
# Выведите результаты
print(boruta_output)
## Boruta performed 15 iterations in 1.132909 secs.
## 11 attributes confirmed important: V1, V10, V11, V12, V13 and 6 more;
## 1 attributes confirmed unimportant: V3;
# Получите подтвержденные признаки
confirmed_attributes <- getSelectedAttributes(boruta_output, withTentative = FALSE)
cat("Подтвержденные признаки:", paste(confirmed_attributes, collapse = ", "), "\n")
## Подтвержденные признаки: V1, V2, V4, V5, V6, V7, V8, V10, V11, V12, V13
# Визуализируйте результаты с помощью boxplot
plot(boruta_output, main = "Важность признаков (Boruta)", xaxt = "n") # Убираем стандартные метки оси x
#Добавим свои
axis(side = 1, #Горизонтальная ось
at = 1:ncol(ozone[, -1]), #Позиции меток (сколько столбцов без целевой)
labels = colnames(ozone[, -1]), #Имена столбцов
las = 2, #Поворот меток (2 - перпендикулярно оси)
cex.axis = 0.7) #Размер шрифта
Подтвержденные важные признаки (Definite): Признаки V6, V7, V8, V9, V10, V11, V12 и V13 были признаны важными. Об этом свидетельствует их зеленый цвет и высокое расположение boxplot’ов. Значимость этих признаков растет в этом порядке. Наибольшую значимость демонстрирует признак V13. Подтвержденные незначимые признаки (Rejected): Признаки V2 и V3 были признаны незначимыми для модели, о чем говорит их красный цвет и низкое положение соответствующих boxplot’ов. Предварительные (Tentative) признаки (такие, которые требуют уточнения): Признаки V4 и V5 отмечены синим цветом. Boruta не смог однозначно определить их важность на текущем этапе. Возможно, для принятия окончательного решения потребуется дополнительный анализ или больше итераций алгоритма. Общие выводы:
Алгоритм Boruta выявил четкую группу важных признаков (V6-V13) для предсказания целевой переменной. Эти признаки, вероятно, играют ключевую роль в моделировании данных. Признаки V2 и V3, вероятно, не вносят существенного вклада в предсказание целевой переменной и могут быть исключены из модели для ее упрощения и повышения обобщающей способности. Для признаков V4 и V5 требуется дополнительное исследование, чтобы определить, следует ли их включать в модель или исключить.
В этой лабораторной работе мы продолжили изучение методов выбора признаков, используя различные пакеты R. Полученные результаты позволяют сравнить различные подходы к выявлению наиболее важных признаков для задач классификации и прогнозирования.