Выполним классификацию k-ближайших соседей с использованием функции knn() из пакета class на наборе данных iris. Проведем нормализацию данных, разделим выборку на обучающую и тестовую. Оценим построенную модель с использованием функции CrossTable() из пакета gmodels. Построим матрицу ошибок и диагональную оценку качества прогноза (diagonal mark quality prediction).
Установка и загрузка пакетов
options(repos = c(CRAN = "https://cran.rstudio.com/"))
install.packages(c("class", "gmodels"))
## package 'class' successfully unpacked and MD5 sums checked
## Warning: cannot remove prior installation of package 'class'
## Warning in file.copy(savedcopy, lib, recursive = TRUE): problem copying
## C:\Soft\R-4.5.2\library\00LOCK\class\libs\x64\class.dll to
## C:\Soft\R-4.5.2\library\class\libs\x64\class.dll: Permission denied
## Warning: restored 'class'
## package 'gmodels' successfully unpacked and MD5 sums checked
##
## The downloaded binary packages are in
## C:\Users\alexa\AppData\Local\Temp\RtmpGumjj2\downloaded_packages
library(class) # class - содержит функцию knn() для классификации методом k-ближайших соседей
library(gmodels) # gmodels - содержит функцию CrossTable() для создания перекрестных таблиц
Загрузка данных iris
data(iris)
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
Нормализация данных (масштабирование в диапазон [0, 1])
normalize <- function(x) {
return((x - min(x)) / (max(x) - min(x)))
}
# Применяем нормализацию только к числовым колонкам (первые 4)
# lapply применяет функцию normalize к каждому столбцу и возвращает список
# as.data.frame преобразует список обратно в таблицу
iris_norm <- as.data.frame(lapply(iris[, 1:4], normalize))
# Добавляем обратно колонку с видами ирисов (не нормализуем её, т.к. это категориальная переменная)
iris_norm$Species <- iris$Species
Разделение на обучающую (70%) и тестовую (30%) выборки
set.seed(123)
# sample() случайным образом выбирает 70% индексов строк
train_idx <- sample(1:nrow(iris_norm), 0.7 * nrow(iris_norm))
train_data <- iris_norm[train_idx, ] # 70%
test_data <- iris_norm[-train_idx, ] # 30%
Извлекаем признаки и метки
train_X <- train_data[, 1:4] # Признаки для обучения (первые 4 колонки)
train_y <- train_data$Species # Метки классов для обучения
test_X <- test_data[, 1:4] # Признаки для тестирования
test_y <- test_data$Species # Фактические метки классов тестовой выборки
Классификация k-NN
# knn() находит k ближайших объектов из train_X для каждого объекта test_X
# и присваивает класс, наиболее часто встречающийся среди этих соседей
# train - обучающие данные, test - тестовые данные, cl - метки классов, k - количество соседей
knn_pred <- knn(train = train_X, test = test_X, cl = train_y, k = 3)
Оценка модели с помощью CrossTable
# CrossTable создает таблицу сопряженности между фактическими и предсказанными значениями
# prop.chisq = FALSE отключает вывод статистики хи-квадрат для упрощения таблицы
CrossTable(x = test_y, 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_y | 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 | |
## -------------|------------|------------|------------|------------|
##
##
Матрица ошибок вручную
# table() создает таблицу, показывающую соответствие между фактическими и предсказанными классами
# По диагонали - правильные предсказания, вне диагонали - ошибки
conf_matrix <- table(test_y, knn_pred)
print("Матрица ошибок (Confusion Matrix):")
## [1] "Матрица ошибок (Confusion Matrix):"
print(conf_matrix)
## knn_pred
## test_y setosa versicolor virginica
## setosa 14 0 0
## versicolor 0 17 1
## virginica 0 1 12
Диагональная оценка качества прогноза (accuracy)
# diag(conf_matrix) извлекает диагональные элементы (правильные предсказания)
# sum(conf_matrix) - общее количество предсказаний
# accuracy - доля правильных предсказаний
accuracy <- sum(diag(conf_matrix)) / sum(conf_matrix)
print(round(accuracy * 100, 2))
## [1] 95.56
Модель справилась с классификацией очень хорошо с точностью 95.56%, допустив всего 2 ошибки
Рассмотрим пример реализации метода опорных векторов с использованием функции svm() из пакета e1071. Построим линейный классификатор для прогнозирования. Для подбора параметров модели выполним перекрестную проверку с делением исходной выборки на 10 равных частей (cross=10).
Установка и загрузка пакета
install.packages("e1071") # Пакет e1071 содержит реализацию метода опорных векторов (SVM)
## package 'e1071' successfully unpacked and MD5 sums checked
##
## The downloaded binary packages are in
## C:\Users\alexa\AppData\Local\Temp\RtmpGumjj2\downloaded_packages
library(e1071)
Загрузка данных iris
data(iris)
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
Подготовка данных
# Для простоты линейной классификации оставляем только два класса:
# setosa и versicolor (исключаем virginica, который трудно линейно отделить)
iris_binary <- iris[iris$Species != "virginica", ]
# Преобразуем Species в фактор с двумя уровнями (setosa, versicolor)
# Это необходимо для корректной работы классификатора
iris_binary$Species <- factor(iris_binary$Species)
Разделение на признаки и метки
# Разделение на признаки (X) и целевую переменную (y) для наглядности
X <- iris_binary[, 1:4] # признаки (первые 4 колонки)
y <- iris_binary$Species # метки классов
Построение SVM с линейным ядром и перекрестной проверкой
# svm() - функция для создания модели опорных векторов
# Параметры:
# Species ~ . - формула
# data = iris_binary - используем бинарный набор данных
# kernel = "linear" - линейное ядро (для линейно разделимых данных)
# cost = 1 - параметр стоимости ошибки (штраф за неверную классификацию)
# Чем больше cost, тем меньше допускается ошибок, но выше риск переобучения
# cross = 10 - 10-кратная перекрестная проверка:
# Данные делятся на 10 частей, 9 используются для обучения, 1 для проверки
# Процесс повторяется 10 раз, каждый раз с новой проверочной частью
svm_model <- svm(Species ~ ., data = iris_binary, kernel = "linear",
cost = 1, cross = 10)
Вывод сводки модели
# summary показывает:
# - параметры модели (kernel, cost, gamma и др.)
# - количество опорных векторов
# - результаты перекрестной проверки по каждой из 10 итераций
# - среднюю точность перекрестной проверки
print("Сводка модели SVM")
## [1] "Сводка модели SVM"
summary(svm_model)
##
## Call:
## svm(formula = Species ~ ., data = iris_binary, kernel = "linear",
## cost = 1, cross = 10)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: linear
## cost: 1
##
## Number of Support Vectors: 4
##
## ( 2 2 )
##
##
## Number of Classes: 2
##
## Levels:
## setosa versicolor
##
## 10-fold cross-validation on training data:
##
## Total Accuracy: 100
## Single Accuracies:
## 100 100 100 100 100 100 100 100 100 100
Оценка точности перекрестной проверки
# svm_model$tot.accuracy хранит среднюю точность по всем 10 проверкам
# Это более объективная оценка качества модели, чем точность на обучающей выборке
print(round(svm_model$tot.accuracy, 2))
## [1] 100
Предсказание на полном наборе данных
# predict() применяет обученную модель к данным X
# Возвращает предсказанные классы для каждого образца
svm_pred <- predict(svm_model, X)
conf_matrix <- table(True = y, Predicted = svm_pred)
print("Матрица ошибок")
## [1] "Матрица ошибок"
print(conf_matrix)
## Predicted
## True setosa versicolor
## setosa 50 0
## versicolor 0 50
Точность на полном наборе
# sum(diag(conf_matrix)) - сумма диагональных элементов (правильные ответы)
# sum(conf_matrix) - общее количество образцов
# Точность = правильные ответы / общее количество
accuracy <- sum(diag(conf_matrix)) / sum(conf_matrix)
print(round(accuracy * 100, 2))
## [1] 100
Модель прекрасно определила все типы на полной выборке без ошибок.
Выполним расчет главных компонент с использованием пакета vegan() и его функции rda(). Построим ординационную диаграмму методом PCA и сделаем выводы.
Установка и загрузка пакета
# Пакет vegan предназначен для экологического анализа, но содержит отличные функции для ординации
# rda() - функция для анализа избыточности (redundancy analysis), которая может выполнять PCA
install.packages("vegan")
## package 'vegan' successfully unpacked and MD5 sums checked
##
## The downloaded binary packages are in
## C:\Users\alexa\AppData\Local\Temp\RtmpGumjj2\downloaded_packages
library(vegan)
## Loading required package: permute
Загрузка данных iris
data(iris)
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
Выделяем числовые признаки для PCA
# Для анализа главных компонент нужны только числовые признаки (первые 4 колонки)
iris_features <- iris[, 1:4] # отбираем колонки Sepal.Length, Sepal.Width, Petal.Length, Petal.Width
Выполнение PCA с помощью rda()
# rda() с одним аргументом выполняет обычный PCA
# scale = TRUE - стандартизация данных (приводит все признаки к единому масштабу)
pca_result <- rda(iris_features, scale = TRUE)
Вывод сводки
# summary показывает:
# - Собственные значения (eigenvalues) для каждой главной компоненты
# - Долю объясненной дисперсии
# - Вклад признаков в компоненты (нагрузки)
# - Координаты объектов в новом пространстве
print("Сводка результатов PCA")
## [1] "Сводка результатов PCA"
summary(pca_result)
##
## Call:
## rda(X = iris_features, 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 отображает одновременно:
# - Объекты (точки) - 150 ирисов в пространстве первых двух главных компонент
# - Признаки (стрелки) - показывают направление максимального изменения признаков
# scaling = "species" - масштабирование для лучшего отображения признаков
# main - заголовок графика
biplot(pca_result, scaling = "species", main = "PCA для Iris")
Доля объясненной дисперсии
prop_var <- pca_result$CA$eig / sum(pca_result$CA$eig)
print(round(prop_var * 100, 2))
## PC1 PC2 PC3 PC4
## 72.96 22.85 3.67 0.52
PC1 (72.96%) и PC2 (22.85%) объясняют 95.81% вариации — достаточно для анализа. PC3 и PC4 почти не вносят вклад (3.67% и 0.52%). График показывает, как цветы группируются по видам в пространстве PC1 и PC2. Petal.Length и Petal.Width — ключевые признаки для разделения видов. setosa обычно отделяется четко, а versicolor и virginica ближе друг к другу.