Цель работы

Изучить методы разведочного анализа данных, оценки значимости и отбора признаков, а также способы дискретизации непрерывных переменных с использованием пакетов caret, FSelector, arules и Boruta языка R.

Задачи работы

  1. Изучить возможности пакета caret и выполнить графический разведочный анализ данных.
  2. Определить важность признаков набора iris с помощью пакета FSelector.
  3. Выполнить дискретизацию непрерывных переменных четырьмя методами с использованием пакета arules.
  4. Провести отбор информативных признаков набора Ozone с помощью алгоритма Boruta.
  5. Подготовить единый отчёт в R Markdown и опубликовать его на RPubs.

Ход выполнения работы

Задание 1. Графический разведочный анализ данных с использованием caret

library(caret)

# Список доступных моделей
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"
# Создание набора данных
set.seed(123)
x <- matrix(rnorm(50 * 5), ncol = 5)
colnames(x) <- paste0("X", 1:5)
y <- factor(rep(c("A", "B"), 25))

# Графический анализ
featurePlot(x = x, y = y, plot = "box")

featurePlot(x = x, y = y, plot = "density")

featurePlot(x = x, y = y, plot = "pairs")

# Сохранение графиков в JPG

jpeg("LR2_box.jpg", width = 1200, height = 800)
print(featurePlot(x = x, y = y, plot = "box"))
dev.off()
## png 
##   2
jpeg("LR2_density.jpg", width = 1200, height = 800)
print(featurePlot(x = x, y = y, plot = "density"))
dev.off()
## png 
##   2
jpeg("LR2_pairs.jpg", width = 1200, height = 1200)
print(featurePlot(x = x, y = y, plot = "pairs"))
dev.off()
## png 
##   2

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

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

С использованием функции featurePlot() построены графики типа boxplot, density и pairs для пяти числовых признаков и двух классов A и B.

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

Полученные графики сохранены в формате JPG.

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

В данном задании используется встроенный набор данных iris, содержащий характеристики цветков трёх видов ирисов. Для оценки информативности признаков применяется метод Information Gain.

library(FSelector)

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 ...
# Оценка важности признаков
importance <- information.gain(Species ~ ., data = iris)

# Вывод результатов
print(importance)
##              attr_importance
## Sepal.Length       0.4521286
## Sepal.Width        0.2672750
## Petal.Length       0.9402853
## Petal.Width        0.9554360
# Сортировка признаков по важности
importance_sorted <- importance[
  order(importance$attr_importance, decreasing = TRUE),
  ,
  drop = FALSE
]

print(importance_sorted)
##              attr_importance
## Petal.Width        0.9554360
## Petal.Length       0.9402853
## Sepal.Length       0.4521286
## Sepal.Width        0.2672750
# График важности признаков
par(mar = c(10, 5, 4, 2))

barplot(
  importance_sorted$attr_importance,
  names.arg = rownames(importance_sorted),
  col = "skyblue",
  main = "Важность признаков набора iris",
  ylab = "Information Gain",
  las = 2,
  cex.names = 0.8
)

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

В ходе выполнения задания была проведена оценка важности признаков набора данных iris с использованием пакета FSelector и метода Information Gain.

Наиболее информативными признаками для классификации видов ирисов являются длина и ширина лепестков (Petal.Length и Petal.Width). Признаки, характеризующие чашелистики (Sepal.Length и Sepal.Width), обладают меньшей информативностью.

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

Задание 3. Дискретизация непрерывных переменных с использованием arules

В данном задании выполняется преобразование непрерывной переменной Sepal.Length набора данных iris в категориальную с помощью функции discretize() пакета arules.

Рассматриваются четыре метода дискретизации: interval, frequency, cluster и fixed.

library(arules)

data(iris)

# Выбор непрерывной переменной
x_disc <- iris$Sepal.Length

# 1. Равная ширина интервалов
disc_interval <- discretize(
  x_disc, method = "interval", categories = 3
)

# 2. Равная частота
disc_frequency <- discretize(
  x_disc, method = "frequency", categories = 3
)

# 3. Кластеризация
disc_cluster <- discretize(
  x_disc, method = "cluster", categories = 3
)

# 4. Фиксированные границы
disc_fixed <- discretize(
  x_disc,
  method = "fixed",
  breaks = c(-Inf, 5.5, 6.5, Inf)
)

# Таблица результатов
results <- data.frame(
  Original = x_disc,
  Interval = disc_interval,
  Frequency = disc_frequency,
  Cluster = disc_cluster,
  Fixed = disc_fixed
)

head(results, 15)
##    Original  Interval Frequency     Cluster      Fixed
## 1       5.1 [4.3,5.5) [4.3,5.4)  [4.3,5.33) [-Inf,5.5)
## 2       4.9 [4.3,5.5) [4.3,5.4)  [4.3,5.33) [-Inf,5.5)
## 3       4.7 [4.3,5.5) [4.3,5.4)  [4.3,5.33) [-Inf,5.5)
## 4       4.6 [4.3,5.5) [4.3,5.4)  [4.3,5.33) [-Inf,5.5)
## 5       5.0 [4.3,5.5) [4.3,5.4)  [4.3,5.33) [-Inf,5.5)
## 6       5.4 [4.3,5.5) [5.4,6.3) [5.33,6.27) [-Inf,5.5)
## 7       4.6 [4.3,5.5) [4.3,5.4)  [4.3,5.33) [-Inf,5.5)
## 8       5.0 [4.3,5.5) [4.3,5.4)  [4.3,5.33) [-Inf,5.5)
## 9       4.4 [4.3,5.5) [4.3,5.4)  [4.3,5.33) [-Inf,5.5)
## 10      4.9 [4.3,5.5) [4.3,5.4)  [4.3,5.33) [-Inf,5.5)
## 11      5.4 [4.3,5.5) [5.4,6.3) [5.33,6.27) [-Inf,5.5)
## 12      4.8 [4.3,5.5) [4.3,5.4)  [4.3,5.33) [-Inf,5.5)
## 13      4.8 [4.3,5.5) [4.3,5.4)  [4.3,5.33) [-Inf,5.5)
## 14      4.3 [4.3,5.5) [4.3,5.4)  [4.3,5.33) [-Inf,5.5)
## 15      5.8 [5.5,6.7) [5.4,6.3) [5.33,6.27)  [5.5,6.5)
# Количество значений в каждой категории
table(disc_interval)
## disc_interval
## [4.3,5.5) [5.5,6.7) [6.7,7.9] 
##        52        70        28
table(disc_frequency)
## disc_frequency
## [4.3,5.4) [5.4,6.3) [6.3,7.9] 
##        46        53        51
table(disc_cluster)
## disc_cluster
##  [4.3,5.33) [5.33,6.27)  [6.27,7.9] 
##          46          53          51
table(disc_fixed)
## disc_fixed
## [-Inf,5.5)  [5.5,6.5) [6.5, Inf] 
##         52         63         35
# Визуальное сравнение
par(mfrow = c(2, 2), mar = c(7, 4, 3, 1))

barplot(table(disc_interval),
        main = "Interval",
        col = "lightblue",
        las = 2)

barplot(table(disc_frequency),
        main = "Frequency",
        col = "lightgreen",
        las = 2)

barplot(table(disc_cluster),
        main = "Cluster",
        col = "lightpink",
        las = 2)

barplot(table(disc_fixed),
        main = "Fixed",
        col = "lightyellow",
        las = 2)

par(mfrow = c(1, 1))

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

В ходе выполнения задания были изучены четыре метода дискретизации непрерывных переменных с использованием функции discretize() пакета arules.

Метод interval разделяет диапазон значений на интервалы одинаковой ширины. Метод frequency формирует категории с приблизительно одинаковым количеством наблюдений. Метод cluster группирует близкие значения на основе кластеризации. Метод fixed позволяет самостоятельно задавать границы категорий.

Таким образом, выбор метода дискретизации влияет на распределение наблюдений по категориям. Метод frequency подходит для получения более сбалансированных групп, interval — для равномерного разделения диапазона значений, cluster — для выделения групп близких значений, а fixed — для использования заранее определённых границ.

Задание 4. Отбор признаков с использованием пакета Boruta

В данном задании выполняется отбор информативных признаков с помощью алгоритма Boruta. Для анализа используется набор данных Ozone из пакета mlbench.

Алгоритм Boruta оценивает значимость признаков путём сравнения их важности с важностью случайно перемешанных теневых признаков.

library(Boruta)
library(mlbench)

# Загрузка данных
data("Ozone", package = "mlbench")

# Просмотр структуры данных
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 ...
# Удаление наблюдений с пропущенными значениями
ozone_clean <- na.omit(Ozone)

# Проверка количества наблюдений
cat("Количество наблюдений:", nrow(ozone_clean), "\n")
## Количество наблюдений: 203
# Запуск алгоритма Boruta
set.seed(123)
boruta_result <- Boruta(
  V4 ~ .,
  data = ozone_clean,
  doTrace = 0,
  maxRuns = 100
)

# Результаты отбора признаков
print(boruta_result)
## Boruta performed 18 iterations in 1.259849 secs.
##  9 attributes confirmed important: V1, V10, V11, V12, V13 and 4 more;
##  3 attributes confirmed unimportant: V2, V3, V6;
# Статистика важности признаков
print(attStats(boruta_result))
##         meanImp   medianImp      minImp     maxImp   normHits  decision
## V1   0.40660229  0.39874710  0.37208192 0.50361585 1.00000000 Confirmed
## V2   0.04391890  0.03169822 -0.02604472 0.13137821 0.11111111  Rejected
## V3  -0.03235907 -0.04528594 -0.08039941 0.03178173 0.00000000  Rejected
## V5   0.37961385  0.37663333  0.33809868 0.42147363 1.00000000 Confirmed
## V6   0.04740489  0.05979747 -0.01572443 0.12718160 0.05555556  Rejected
## V7   0.51883205  0.50588169  0.46725744 0.59114026 1.00000000 Confirmed
## V8   0.77086858  0.76889989  0.73251688 0.81327051 1.00000000 Confirmed
## V9   0.86915268  0.86432645  0.84273725 0.92413075 1.00000000 Confirmed
## V10  0.42389058  0.41739463  0.38164901 0.49245967 1.00000000 Confirmed
## V11  0.55143690  0.54721914  0.49482770 0.61161304 1.00000000 Confirmed
## V12  0.66051279  0.65832222  0.60234621 0.73958611 1.00000000 Confirmed
## V13  0.42761454  0.42057856  0.38618408 0.46920282 1.00000000 Confirmed
# График boxplot
plot(
  boruta_result,
  main = "Результаты отбора признаков Boruta",
  las = 2,
  cex.axis = 0.7
)

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

В ходе выполнения задания был применён алгоритм Boruta для отбора информативных признаков набора данных Ozone.

По результатам анализа были выделены девять значимых признаков: V5, V1, V10, V13, V7, V11, V12, V8 и V9. Наибольшую важность продемонстрировали признаки V9, V8 и V12.

Признаки V2, V3 и V6 были признаны неинформативными. На графике boxplot наглядно представлены распределения оценок важности признаков и результаты их сравнения с теневыми признаками.

Таким образом, алгоритм Boruta позволяет выявить значимые характеристики набора данных и исключить признаки, не обладающие достаточной информативностью для решения рассматриваемой задачи.

Заключение

В ходе выполнения практической работы № 2 были изучены методы разведочного анализа данных, оценки значимости признаков, дискретизации непрерывных переменных и отбора информативных характеристик с использованием языка программирования R.

С помощью пакета caret выполнен графический анализ данных и построены графики распределения признаков. Пакет FSelector позволил оценить информативность характеристик набора iris. С использованием пакета arules проведено сравнение четырёх методов дискретизации: interval, frequency, cluster и fixed.

Алгоритм Boruta был применён для определения значимых признаков набора Ozone. Результаты представлены в виде графика boxplot.

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