Цель лабораторной работы — изучить методы графического анализа, оценки важности, дискретизации и выбора признаков средствами языка R.
В работе используются пакеты caret,
FSelector, arules и Boruta.
Пакет caret содержит большое количество методов
машинного обучения, предварительной обработки и выбора признаков.
Выполним команду names(getModelInfo()).
model_names <- names(getModelInfo())
cat("Количество доступных моделей:", length(model_names), "\n\n")
## Количество доступных моделей: 239
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 также используются
функции:
rfe() — Recursive Feature Elimination;sbf() — Selection By Filtering;gafs() — выбор признаков генетическим алгоритмом;safs() — выбор признаков методом имитации отжига.В соответствии с условием лабораторной работы создадим матрицу из 50 объектов и 5 признаков.
set.seed(123)
x <- matrix(
rnorm(50 * 5),
ncol = 5
)
colnames(x) <- paste0("X", 1:5)
y <- factor(
rep(c("A", "B"), 25)
)
cat("Размер матрицы x:\n")
## Размер матрицы x:
print(dim(x))
## [1] 50 5
cat("\nПервые строки:\n")
##
## Первые строки:
print(head(x))
## X1 X2 X3 X4 X5
## [1,] -0.56047565 0.25331851 -0.71040656 0.7877388 2.1988103
## [2,] -0.23017749 -0.02854676 0.25688371 0.7690422 1.3124130
## [3,] 1.55870831 -0.04287046 -0.24669188 0.3322026 -0.2651451
## [4,] 0.07050839 1.36860228 -0.34754260 -1.0083766 0.5431941
## [5,] 0.12928774 -0.22577099 -0.95161857 -0.1194526 -0.4143399
## [6,] 1.71506499 1.51647060 -0.04502772 -0.2803953 -0.4762469
cat("\nКоличество объектов каждого класса:\n")
##
## Количество объектов каждого класса:
print(table(y))
## y
## A B
## 25 25
featurePlot(
x = x,
y = y,
plot = "ellipse",
auto.key = TRUE
)
featurePlot(
x = x,
y = y,
plot = "strip",
jitter = TRUE,
auto.key = TRUE
)
featurePlot(
x = x,
y = y,
plot = "box",
auto.key = TRUE
)
featurePlot(
x = x,
y = y,
plot = "pairs",
auto.key = TRUE
)
featurePlot(
x = x,
y = y,
plot = "density",
scales = list(
x = list(relation = "free"),
y = list(relation = "free")
),
auto.key = TRUE
)
В результате графического разведочного анализа наблюдается значительное перекрытие объектов классов A и B.
Ни один из пяти признаков не обеспечивает явного разделения объектов на два класса.
Такой результат является ожидаемым, поскольку значения признаков были сгенерированы случайным образом из нормального распределения независимо от целевой переменной.
Следовательно, между сгенерированными признаками и принадлежностью объекта к классу A или B отсутствует выраженная зависимость.
Все построенные графики автоматически сохраняются в формате JPG в
папке graphs.
Для анализа важности признаков используется стандартный набор данных
iris.
data(iris)
cat("Первые строки набора iris:\n")
## Первые строки набора iris:
print(head(iris))
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa
## 5 5.0 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
cat("\nСтруктура данных:\n")
##
## Структура данных:
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 ...
cat("\nСводная статистика:\n")
##
## Сводная статистика:
print(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
##
##
##
Целевой переменной является Species, которая
характеризует вид ириса.
Будем оценивать важность четырех признаков:
Sepal.Length;Sepal.Width;Petal.Length;Petal.Width.ig <- information.gain(
Species ~ .,
data = iris
)
ig <- ig[
order(ig[, 1], decreasing = TRUE),
,
drop = FALSE
]
print(ig)
## attr_importance
## Petal.Width 0.9554360
## Petal.Length 0.9402853
## Sepal.Length 0.4521286
## Sepal.Width 0.2672750
gr <- gain.ratio(
Species ~ .,
data = iris
)
gr <- gr[
order(gr[, 1], decreasing = TRUE),
,
drop = FALSE
]
print(gr)
## attr_importance
## Petal.Width 0.8713692
## Petal.Length 0.8584937
## Sepal.Length 0.4196464
## Sepal.Width 0.2472972
su <- symmetrical.uncertainty(
Species ~ .,
data = iris
)
su <- su[
order(su[, 1], decreasing = TRUE),
,
drop = FALSE
]
print(su)
## attr_importance
## Petal.Width 0.8705214
## Petal.Length 0.8571872
## Sepal.Length 0.4155563
## Sepal.Width 0.2452743
set.seed(123)
rel <- relief(
Species ~ .,
data = iris,
neighbours.count = 5,
sample.size = 100
)
rel <- rel[
order(rel[, 1], decreasing = TRUE),
,
drop = FALSE
]
print(rel)
## attr_importance
## Petal.Width 0.3452500
## Petal.Length 0.3423729
## Sepal.Length 0.1472778
## Sepal.Width 0.1449583
set.seed(123)
rf_imp <- random.forest.importance(
Species ~ .,
data = iris,
importance.type = 1
)
rf_imp <- rf_imp[
order(rf_imp[, 1], decreasing = TRUE),
,
drop = FALSE
]
print(rf_imp)
## attr_importance
## Petal.Length 47.478185
## Petal.Width 46.266486
## Sepal.Length 15.232793
## Sepal.Width 6.771835
features <- rownames(ig)
importance_table <- data.frame(
Feature = features,
Information_Gain = ig[features, 1],
Gain_Ratio = gr[features, 1],
Symmetrical_Uncertainty = su[features, 1],
Relief = rel[features, 1],
Random_Forest = rf_imp[features, 1],
row.names = NULL
)
print(importance_table)
## Feature Information_Gain Gain_Ratio Symmetrical_Uncertainty Relief
## 1 Petal.Width 0.9554360 0.8713692 0.8705214 0.3452500
## 2 Petal.Length 0.9402853 0.8584937 0.8571872 0.3423729
## 3 Sepal.Length 0.4521286 0.4196464 0.4155563 0.1472778
## 4 Sepal.Width 0.2672750 0.2472972 0.2452743 0.1449583
## Random_Forest
## 1 46.266486
## 2 47.478185
## 3 15.232793
## 4 6.771835
barplot(
ig[, 1],
names.arg = rownames(ig),
las = 2,
main = "Важность признаков iris: Information Gain",
ylab = "Важность"
)
Методы оценки важности признаков показывают, что наиболее информативными переменными для определения вида ириса являются характеристики лепестков:
Petal.Length и Petal.Width.
Признаки Sepal.Length и Sepal.Width имеют
меньшую информативность.
Таким образом, при построении классификатора для определения вида ириса наиболее полезными являются длина и ширина лепестка.
Для дискретизации используется функция discretize()
пакета arules.
Исследуем непрерывную переменную Sepal.Length из набора
данных iris.
z <- iris$Sepal.Length
cat("Сводная статистика Sepal.Length:\n")
## Сводная статистика Sepal.Length:
print(summary(z))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 4.300 5.100 5.800 5.843 6.400 7.900
Посмотрим исходное распределение признака.
hist(
z,
breaks = 15,
main = "Исходное распределение Sepal.Length",
xlab = "Sepal.Length"
)
Метод interval делит диапазон значений на интервалы
одинаковой ширины.
d_interval <- discretize(
z,
method = "interval",
breaks = 3
)
cat("Количество объектов в категориях:\n")
## Количество объектов в категориях:
print(table(d_interval))
## d_interval
## [4.3,5.5) [5.5,6.7) [6.7,7.9]
## 52 70 28
cat("\nГраницы интервалов:\n")
##
## Границы интервалов:
print(
discretize(
z,
method = "interval",
breaks = 3,
onlycuts = TRUE
)
)
## [1] 4.3 5.5 6.7 7.9
Метод frequency стремится получить группы с примерно
одинаковым количеством наблюдений.
d_frequency <- discretize(
z,
method = "frequency",
breaks = 3
)
cat("Количество объектов в категориях:\n")
## Количество объектов в категориях:
print(table(d_frequency))
## d_frequency
## [4.3,5.4) [5.4,6.3) [6.3,7.9]
## 46 53 51
cat("\nГраницы интервалов:\n")
##
## Границы интервалов:
print(
discretize(
z,
method = "frequency",
breaks = 3,
onlycuts = TRUE
)
)
## [1] 4.3 5.4 6.3 7.9
Метод cluster использует кластеризацию k-means для
определения границ.
set.seed(123)
d_cluster <- discretize(
z,
method = "cluster",
breaks = 3
)
cat("Количество объектов в категориях:\n")
## Количество объектов в категориях:
print(table(d_cluster))
## d_cluster
## [4.3,5.37) [5.37,6.36) [6.36,7.9]
## 46 62 42
cat("\nГраницы интервалов:\n")
##
## Границы интервалов:
set.seed(123)
print(
discretize(
z,
method = "cluster",
breaks = 3,
onlycuts = TRUE
)
)
## [1] 4.300000 5.371213 6.361482 7.900000
Для метода fixed границы задаются вручную.
Используем следующие интервалы:
d_fixed <- discretize(
z,
method = "fixed",
breaks = c(-Inf, 5, 6, Inf),
labels = c(
"Низкое",
"Среднее",
"Высокое"
)
)
cat("Количество объектов в категориях:\n")
## Количество объектов в категориях:
print(table(d_fixed))
## d_fixed
## Низкое Среднее Высокое
## 22 61 67
discretization_result <- data.frame(
Original = z,
Interval = d_interval,
Frequency = d_frequency,
Cluster = d_cluster,
Fixed = d_fixed
)
print(head(discretization_result, 20))
## Original Interval Frequency Cluster Fixed
## 1 5.1 [4.3,5.5) [4.3,5.4) [4.3,5.37) Среднее
## 2 4.9 [4.3,5.5) [4.3,5.4) [4.3,5.37) Низкое
## 3 4.7 [4.3,5.5) [4.3,5.4) [4.3,5.37) Низкое
## 4 4.6 [4.3,5.5) [4.3,5.4) [4.3,5.37) Низкое
## 5 5.0 [4.3,5.5) [4.3,5.4) [4.3,5.37) Среднее
## 6 5.4 [4.3,5.5) [5.4,6.3) [5.37,6.36) Среднее
## 7 4.6 [4.3,5.5) [4.3,5.4) [4.3,5.37) Низкое
## 8 5.0 [4.3,5.5) [4.3,5.4) [4.3,5.37) Среднее
## 9 4.4 [4.3,5.5) [4.3,5.4) [4.3,5.37) Низкое
## 10 4.9 [4.3,5.5) [4.3,5.4) [4.3,5.37) Низкое
## 11 5.4 [4.3,5.5) [5.4,6.3) [5.37,6.36) Среднее
## 12 4.8 [4.3,5.5) [4.3,5.4) [4.3,5.37) Низкое
## 13 4.8 [4.3,5.5) [4.3,5.4) [4.3,5.37) Низкое
## 14 4.3 [4.3,5.5) [4.3,5.4) [4.3,5.37) Низкое
## 15 5.8 [5.5,6.7) [5.4,6.3) [5.37,6.36) Среднее
## 16 5.7 [5.5,6.7) [5.4,6.3) [5.37,6.36) Среднее
## 17 5.4 [4.3,5.5) [5.4,6.3) [5.37,6.36) Среднее
## 18 5.1 [4.3,5.5) [4.3,5.4) [4.3,5.37) Среднее
## 19 5.7 [5.5,6.7) [5.4,6.3) [5.37,6.36) Среднее
## 20 5.1 [4.3,5.5) [4.3,5.4) [4.3,5.37) Среднее
Количество объектов в категориях:
cat("INTERVAL:\n")
## INTERVAL:
print(table(d_interval))
## d_interval
## [4.3,5.5) [5.5,6.7) [6.7,7.9]
## 52 70 28
cat("\nFREQUENCY:\n")
##
## FREQUENCY:
print(table(d_frequency))
## d_frequency
## [4.3,5.4) [5.4,6.3) [6.3,7.9]
## 46 53 51
cat("\nCLUSTER:\n")
##
## CLUSTER:
print(table(d_cluster))
## d_cluster
## [4.3,5.37) [5.37,6.36) [6.36,7.9]
## 46 62 42
cat("\nFIXED:\n")
##
## FIXED:
print(table(d_fixed))
## d_fixed
## Низкое Среднее Высокое
## 22 61 67
hist(
z,
breaks = 15,
main = "Дискретизация: interval",
xlab = "Sepal.Length"
)
abline(
v = discretize(
z,
method = "interval",
breaks = 3,
onlycuts = TRUE
),
lty = 2,
lwd = 2
)
hist(
z,
breaks = 15,
main = "Дискретизация: frequency",
xlab = "Sepal.Length"
)
abline(
v = discretize(
z,
method = "frequency",
breaks = 3,
onlycuts = TRUE
),
lty = 2,
lwd = 2
)
hist(
z,
breaks = 15,
main = "Дискретизация: cluster",
xlab = "Sepal.Length"
)
set.seed(123)
cluster_cuts <- discretize(
z,
method = "cluster",
breaks = 3,
onlycuts = TRUE
)
abline(
v = cluster_cuts,
lty = 2,
lwd = 2
)
hist(
z,
breaks = 15,
main = "Дискретизация: fixed",
xlab = "Sepal.Length"
)
abline(
v = c(5, 6),
lty = 2,
lwd = 2
)
В работе были рассмотрены четыре метода дискретизации.
Метод interval делит весь диапазон значений на интервалы
одинаковой ширины, поэтому количество объектов в категориях может
отличаться.
Метод frequency формирует интервалы таким образом, чтобы
число наблюдений в них было примерно одинаковым.
Метод cluster использует кластеризацию k-means и
определяет границы исходя из структуры имеющихся данных.
Метод fixed позволяет пользователю самостоятельно
задавать необходимые границы интервалов.
Следовательно, выбор способа дискретизации зависит от распределения данных, целей исследования и наличия заранее известных границ категорий.
Для исследования используется набор данных Ozone из
пакета mlbench.
data(Ozone)
cat("Размер исходного набора Ozone:\n")
## Размер исходного набора Ozone:
print(dim(Ozone))
## [1] 366 13
cat("\nПервые строки:\n")
##
## Первые строки:
print(head(Ozone))
## V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13
## 1 1 1 4 3 5480 8 20 NA NA 5000 -15 30.56 200
## 2 1 2 5 3 5660 6 NA 38 NA NA -14 NA 300
## 3 1 3 6 3 5710 4 28 40 NA 2693 -25 47.66 250
## 4 1 4 7 5 5700 3 37 45 NA 590 -24 55.04 100
## 5 1 5 1 5 5760 3 51 54 45.32 1450 25 57.02 60
## 6 1 6 2 6 5720 4 69 35 49.64 1568 15 53.78 60
В наборе имеются пропущенные значения. Удалим строки, содержащие
NA.
ozone_clean <- na.omit(Ozone)
cat("Размер набора после удаления NA:\n")
## Размер набора после удаления NA:
print(dim(ozone_clean))
## [1] 203 13
cat("\nКоличество удалённых строк:\n")
##
## Количество удалённых строк:
print(nrow(Ozone) - nrow(ozone_clean))
## [1] 163
В соответствии с примером применения Boruta к набору
Ozone, целевой переменной является V4.
set.seed(123)
boruta_result <- Boruta(
V4 ~ .,
data = ozone_clean,
doTrace = 0,
maxRuns = 100
)
print(boruta_result)
## Boruta performed 18 iterations in 0.2613919 secs.
## 9 attributes confirmed important: V1, V10, V11, V12, V13 and 4 more;
## 3 attributes confirmed unimportant: V2, V3, V6;
boruta_stats <- attStats(boruta_result)
boruta_stats <- boruta_stats[
order(
boruta_stats$meanImp,
decreasing = TRUE
),
,
drop = FALSE
]
print(boruta_stats)
## meanImp medianImp minImp maxImp normHits decision
## V9 0.86915268 0.86432645 0.84273725 0.92413075 1.00000000 Confirmed
## V8 0.77086858 0.76889989 0.73251688 0.81327051 1.00000000 Confirmed
## V12 0.66051279 0.65832222 0.60234621 0.73958611 1.00000000 Confirmed
## V11 0.55143690 0.54721914 0.49482770 0.61161304 1.00000000 Confirmed
## V7 0.51883205 0.50588169 0.46725744 0.59114026 1.00000000 Confirmed
## V13 0.42761454 0.42057856 0.38618408 0.46920282 1.00000000 Confirmed
## V10 0.42389058 0.41739463 0.38164901 0.49245967 1.00000000 Confirmed
## V1 0.40660229 0.39874710 0.37208192 0.50361585 1.00000000 Confirmed
## V5 0.37961385 0.37663333 0.33809868 0.42147363 1.00000000 Confirmed
## V6 0.04740489 0.05979747 -0.01572443 0.12718160 0.05555556 Rejected
## V2 0.04391890 0.03169822 -0.02604472 0.13137821 0.11111111 Rejected
## V3 -0.03235907 -0.04528594 -0.08039941 0.03178173 0.00000000 Rejected
stats_original <- attStats(boruta_result)
confirmed <- rownames(
stats_original[
stats_original$decision == "Confirmed",
,
drop = FALSE
]
)
rejected <- rownames(
stats_original[
stats_original$decision == "Rejected",
,
drop = FALSE
]
)
tentative <- rownames(
stats_original[
stats_original$decision == "Tentative",
,
drop = FALSE
]
)
cat("CONFIRMED:\n")
## CONFIRMED:
print(confirmed)
## [1] "V1" "V5" "V7" "V8" "V9" "V10" "V11" "V12" "V13"
cat("\nREJECTED:\n")
##
## REJECTED:
print(rejected)
## [1] "V2" "V3" "V6"
cat("\nTENTATIVE:\n")
##
## TENTATIVE:
print(tentative)
## character(0)
Если после выполнения алгоритма некоторые признаки остались
неопределёнными (Tentative), применим
TentativeRoughFix().
if (length(tentative) > 0) {
boruta_final <- TentativeRoughFix(
boruta_result
)
} else {
boruta_final <- boruta_result
}
print(boruta_final)
## Boruta performed 18 iterations in 0.2613919 secs.
## 9 attributes confirmed important: V1, V10, V11, V12, V13 and 4 more;
## 3 attributes confirmed unimportant: V2, V3, V6;
final_selected <- getSelectedAttributes(
boruta_final,
withTentative = FALSE
)
cat("Окончательно выбранные признаки:\n")
## Окончательно выбранные признаки:
print(final_selected)
## [1] "V1" "V5" "V7" "V8" "V9" "V10" "V11" "V12" "V13"
plot(
boruta_result,
las = 2,
cex.axis = 0.65,
sort = TRUE,
main = "Важность признаков Boruta для Ozone",
xlab = "",
ylab = "Importance"
)
final_stats <- attStats(
boruta_final
)
final_stats <- final_stats[
order(
final_stats$meanImp,
decreasing = TRUE
),
,
drop = FALSE
]
print(final_stats)
## meanImp medianImp minImp maxImp normHits decision
## V9 0.86915268 0.86432645 0.84273725 0.92413075 1.00000000 Confirmed
## V8 0.77086858 0.76889989 0.73251688 0.81327051 1.00000000 Confirmed
## V12 0.66051279 0.65832222 0.60234621 0.73958611 1.00000000 Confirmed
## V11 0.55143690 0.54721914 0.49482770 0.61161304 1.00000000 Confirmed
## V7 0.51883205 0.50588169 0.46725744 0.59114026 1.00000000 Confirmed
## V13 0.42761454 0.42057856 0.38618408 0.46920282 1.00000000 Confirmed
## V10 0.42389058 0.41739463 0.38164901 0.49245967 1.00000000 Confirmed
## V1 0.40660229 0.39874710 0.37208192 0.50361585 1.00000000 Confirmed
## V5 0.37961385 0.37663333 0.33809868 0.42147363 1.00000000 Confirmed
## V6 0.04740489 0.05979747 -0.01572443 0.12718160 0.05555556 Rejected
## V2 0.04391890 0.03169822 -0.02604472 0.13137821 0.11111111 Rejected
## V3 -0.03235907 -0.04528594 -0.08039941 0.03178173 0.00000000 Rejected
Алгоритм Boruta выполняет отбор информативных признаков посредством
сравнения их важности с важностью случайных теневых признаков
(Shadow).
Реальные признаки, важность которых достоверно превосходит важность
теневых признаков, получают статус Confirmed.
Незначимые признаки получают статус Rejected, а
признаки, для которых нельзя сразу принять однозначное решение, получают
статус Tentative.
В результате работы Boruta подтверждены следующие признаки:
V1, V5, V7, V8, V9, V10, V11, V12, V13
Следовательно, подтверждённые алгоритмом Boruta признаки являются
наиболее целесообразными для дальнейшего построения модели,
прогнозирующей переменную V4.
В ходе лабораторной работы были исследованы различные методы анализа, преобразования и выбора признаков.
С помощью пакета caret и функции
featurePlot() был выполнен графический разведочный анализ
искусственно созданного набора данных. Поскольку признаки были
сгенерированы независимо от классов A и B, явного разделения классов
обнаружено не было.
При использовании пакета FSelector для набора
iris установлено, что наиболее информативными для
определения вида ириса являются Petal.Length и
Petal.Width.
С помощью функции discretize() пакета
arules были рассмотрены методы interval,
frequency, cluster и fixed. Эти
методы используют разные способы определения границ категорий.
Алгоритм Boruta был применён к набору данных Ozone. Он
позволил разделить признаки на информативные и неинформативные с
использованием сравнения с искусственными теневыми признаками.
Таким образом, в работе были освоены основные способы визуального исследования, оценки важности, дискретизации и автоматизированного выбора признаков в языке R.