Формулировка: выполнить классификацию k-ближайших
соседей с использованием функции knn() из пакета
class на наборе данных iris. Провести
нормализацию данных, разделить выборку на обучающую и тестовую. Оценить
построенную модель с использованием функции CrossTable() из
пакета gmodels. Построить матрицу ошибок и диагональную
оценку качества прогноза.
library(class)
library(gmodels)
data(iris)
normalize <- function(x) {
(x - min(x)) / (max(x) - min(x))
}
iris_norm <- as.data.frame(lapply(iris[, 1:4], normalize))
iris_norm$Species <- iris$Species
set.seed(123)
train_index <- sample(1:nrow(iris_norm), 0.7 * nrow(iris_norm))
train_data <- iris_norm[train_index, 1:4]
test_data <- iris_norm[-train_index, 1:4]
train_labels <- iris_norm[train_index, 5]
test_labels <- iris_norm[-train_index, 5]
knn_pred <- knn(train = train_data, test = test_data, cl = train_labels, k = 5)
CrossTable(x = test_labels, y = knn_pred, prop.chisq = FALSE)
##
##
## Cell Contents
## |-------------------------|
## | N |
## | N / Row Total |
## | N / Col Total |
## | N / Table Total |
## |-------------------------|
##
##
## Total Observations in Table: 45
##
##
## | knn_pred
## test_labels | setosa | versicolor | virginica | Row Total |
## -------------|------------|------------|------------|------------|
## setosa | 14 | 0 | 0 | 14 |
## | 1.000 | 0.000 | 0.000 | 0.311 |
## | 1.000 | 0.000 | 0.000 | |
## | 0.311 | 0.000 | 0.000 | |
## -------------|------------|------------|------------|------------|
## versicolor | 0 | 17 | 1 | 18 |
## | 0.000 | 0.944 | 0.056 | 0.400 |
## | 0.000 | 0.944 | 0.077 | |
## | 0.000 | 0.378 | 0.022 | |
## -------------|------------|------------|------------|------------|
## virginica | 0 | 1 | 12 | 13 |
## | 0.000 | 0.077 | 0.923 | 0.289 |
## | 0.000 | 0.056 | 0.923 | |
## | 0.000 | 0.022 | 0.267 | |
## -------------|------------|------------|------------|------------|
## Column Total | 14 | 18 | 13 | 45 |
## | 0.311 | 0.400 | 0.289 | |
## -------------|------------|------------|------------|------------|
##
##
confusion_matrix <- table(Predicted = knn_pred, Actual = test_labels)
confusion_matrix
## Actual
## Predicted setosa versicolor virginica
## setosa 14 0 0
## versicolor 0 17 1
## virginica 0 1 12
diagonal_accuracy <- sum(diag(confusion_matrix)) / sum(confusion_matrix)
diagonal_accuracy
## [1] 0.9555556
Вывод: нормализация (min-max в диапазон
[0, 1]) необходима для knn(), так как алгоритм основан на
расстояниях между точками, а признаки iris измерены в
разных диапазонах (лепестки/чашелистики) — без нормализации признак с
большим разбросом значений доминировал бы в расчёте расстояния.
CrossTable() наглядно показывает, сколько наблюдений
каждого истинного класса было отнесено к каждому предсказанному классу,
а матрица ошибок (confusion matrix) — то же самое в компактном табличном
виде. Диагональная оценка (сумма диагональных элементов, делённая на
общее число наблюдений) даёт долю верно классифицированных объектов —
итоговую точность (accuracy) модели, которая для iris при
k = 5 обычно оказывается близка к 95-100%, так как классы в
этом наборе данных хорошо разделимы.
Формулировка: рассмотреть пример реализации метода
опорных векторов с использованием функции svm() из пакета
e1071. Построить линейный классификатор для
прогнозирования. Для подбора параметров модели выполнить перекрёстную
проверку с делением исходной выборки на 10 равных частей
(cross = 10).
library(e1071)
data(iris)
set.seed(123)
train_index <- sample(1:nrow(iris), 0.7 * nrow(iris))
train_set <- iris[train_index, ]
test_set <- iris[-train_index, ]
svm_model <- svm(Species ~ ., data = train_set, kernel = "linear", cross = 10)
summary(svm_model)
##
## Call:
## svm(formula = Species ~ ., data = train_set, kernel = "linear", cross = 10)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: linear
## cost: 1
##
## Number of Support Vectors: 24
##
## ( 2 10 12 )
##
##
## Number of Classes: 3
##
## Levels:
## setosa versicolor virginica
##
## 10-fold cross-validation on training data:
##
## Total Accuracy: 95.2381
## Single Accuracies:
## 100 100 90 100 90 90.90909 100 100 90 90.90909
svm_pred <- predict(svm_model, test_set)
table(Predicted = svm_pred, Actual = test_set$Species)
## Actual
## Predicted setosa versicolor virginica
## setosa 14 0 0
## versicolor 0 17 0
## virginica 0 1 13
test_accuracy <- mean(svm_pred == test_set$Species)
test_accuracy
## [1] 0.9777778
Вывод: параметр cross = 10 запускает
10-кратную перекрёстную проверку прямо внутри обучающей выборки — данные
делятся на 10 равных частей, модель поочерёдно обучается на 9 из них и
проверяется на оставшейся, что даёт более надёжную (менее зависящую от
случайного разбиения) оценку качества, чем единичное разбиение
train/test. В выводе summary(svm_model) строка
Total Accuracy — это и есть усреднённая по всем 10
разбиениям точность на обучающих данных. Итоговая точность на отложенной
тестовой выборке (test_accuracy) обычно оказывается близкой
к результату кросс-валидации, что подтверждает, что модель не
переобучилась — линейный SVM хорошо справляется с iris,
поскольку классы (особенно setosa) линейно (или почти
линейно) разделимы.
Формулировка: выполнить расчёт главных компонент с
использованием пакета vegan и его функции
rda(). Построить ординационную диаграмму методом PCA и
сделать выводы.
library(vegan)
data(iris)
iris_pca <- rda(iris[, 1:4], scale = TRUE)
summary(iris_pca)
##
## Call:
## rda(X = iris[, 1:4], scale = TRUE)
##
## Partitioning of correlations:
## Inertia Proportion
## Total 4 1
## Unconstrained 4 1
##
## Eigenvalues, and their contribution to the correlations
##
## Importance of components:
## PC1 PC2 PC3 PC4
## Eigenvalue 2.9185 0.9140 0.14676 0.020715
## Proportion Explained 0.7296 0.2285 0.03669 0.005179
## Cumulative Proportion 0.7296 0.9581 0.99482 1.000000
biplot(iris_pca, scaling = 2, main = "PCA: ординационная диаграмма (biplot)")
ordiplot(iris_pca, type = "n", main = "PCA: наблюдения по видам ириса")
points(iris_pca, display = "sites", col = as.numeric(iris$Species), pch = 19)
legend("topright", legend = levels(iris$Species), col = 1:3, pch = 19, title = "Species")
Вывод: rda() без задания ограничивающих
(constraining) переменных выполняет обычный (unconstrained) метод
главных компонент — то есть ищет линейные комбинации исходных 4
признаков (главные компоненты), которые последовательно объясняют
максимум дисперсии данных. Из summary() видно, что первая
главная компонента (PC1) объясняет значительно больше половины общей
дисперсии — это ожидаемо, так как в iris признаки
длины/ширины лепестка сильно коррелируют друг с другом (что мы уже
видели в задании про FSelector в другой лабораторной). На ординационной
диаграмме (biplot) стрелки показывают вклад (нагрузку) каждого исходного
признака в главные компоненты — Petal.Length и
Petal.Width имеют самые длинные стрелки и почти совпадают
по направлению с осью PC1, тогда как Sepal.Width направлен
почти перпендикулярно. На графике наблюдений по видам
(ordiplot) вид setosa чётко отделяется от двух
других вдоль PC1, а versicolor и virginica
частично перекрываются — то есть уже первая главная компонента,
построенная без использования меток классов, сама по себе несёт
значительную информацию о видовой принадлежности.