Методы понижения размерности (обзор) играют важную роль в машинном обучении. Они позволяют строить модели в пространствах меньшей размерности, чем исходное признаковое пространство, с минимальными потерями информации. Особенно полезно понижать размерность до 2, то есть проецировать данные на плоскость. Таким образом можно изучить структуру данных, например, посмотреть, насколько разделимы классы в задачах классификации. В этом сообщении рассмотрены два классических метода - метод главных компонент (PCA) и многомерное шкалирование (MDS), а также один из мощнейших современных методов - t-SNE (t-Distributed Stochastic Neighbor Embedding).
Colon
из пакета plsgenomics. Он содержит 2000 переменных, характеризующих уровень экспрессии генов в 62 образцах тканей (40 опухолевых и 22 нормальных); решить нужно задачу двухклассовой классификации. Здесь n<<p - переменных гораздо больше, чем наблюдений. Попробуем понизить размерность данных разными методами и сравнить результаты.library(plsgenomics)
library(Rtsne)
library(caret)
data(Colon)
df <- Colon$X # предикторы
Y <- as.factor(Colon$Y) # метки классов
preProcValues <- preProcess(df, method = c("center", "scale")) # стандартизация
df <- predict(preProcValues, df)
head(df[, 1:5])
## 1 2 3 4 5
## 1 0.5087761 0.2290114 0.09277894 0.038208566 -0.6921737
## 2 0.6946290 0.8006657 0.43382052 -0.133540752 -0.6794033
## 3 -1.0313974 0.9152589 0.70142142 0.355537305 -1.3048343
## 4 -0.2487376 1.3050329 1.02366571 -0.006054709 -0.6886951
## 5 -1.2238907 -0.5813493 -0.38171451 -0.259624082 -0.5569221
## 6 -1.4566778 -1.3734381 -1.39070424 -0.453161864 -0.8304916
PCA
Применим метод главных компонент, используя предварительно стандартизированные данные. Всего будет создано n-1 ненулевых главных компонент, в данном случае 61 в соответствии с фактическй размерностью данных (см. 1, 2, 3).df.pca <- prcomp(df, center = FALSE, scale = FALSE)
plot(df.pca$x[,1], df.pca$x[, 2], col = Y)
На графике в пространстве первух двух главных компонент классы выглядят неразделимыми. Это довольно предсказуемо, ведь направления наибольшей вариабельности данных вовсе не обязательно будут тесно связаны с переменной отклика.
MDS
Многомерное шкалирование ищет проекцию данных в пространство меньшей размерности таким образом, чтобы как можно точнее сохранить расстояния между объектами. Двухмерная проекция, полученная данным методом, выглядит следующим образом:df.mds <- cmdscale(dist(df), eig = TRUE, k = 2)
plot(df.mds$points[, 1], df.mds$points[, 2], col = Y)
Классы по-прежнему выглядят плохо разделимыми.
t-SNE
Суть метода подробно объясняется в публикации на хабре. Воспользуемся эффективной реализацией алгоритма на C++ при помощи пакета Rstne (есть также реализация непосредственно на R):set.seed(100)
df.rtsne <- Rtsne(Colon$X, dims = 2, perplexity = 20)
plot(df.rtsne$Y, col = Y)
В полученном пространстве классы можно достаточно хорошо разделить с использованием простейших методов, таких как одиночное решающее дерево. Недостаток метода состоит в том, что решаемая им задача оптимизации не имеет единственного решения, а полученные переменные, в координатах которых строится график, не выражаются через исходные переменные. Если на обучающей выборке построить модель, то она окажется бесполезной, поскольку нельзя определить координаты новых точек в пространстве пониженной размерности. Иными словами, мы получили информацию о разделимости классов, но по-прежнему не знаем, как именно их разделить.
Очевидным выходом из ситуации является предложенный ниже алгоритм:
- Для обучающей выборки понизить размерность (например, до 2) при помощи t-SNE.
- Подобрать оптимальную модель с использованием кросс-валидации.
- Новые данные, для которых неизвестны значения целевой переменной, объединить с обучающей выборкой. Получившаяся выборка будет содержать размеченную и неразмеченную часть.
- Аналогичным образом понизить размерность для новой выборки, включающей в себя обучающую.
- На размеченной части выборки построить модель с подобранной в п.2 спецификацией.
- Использовать модель для предсказания значений целевой переменной на неразмеченной части выборки.
set.seed(100)
df.rtsne <- Rtsne(Colon$X, dims = 2, perplexity = 20)$Y
df.rtsne <- cbind(df.rtsne, Colon$Y)
df.rtsne <- as.data.frame(df.rtsne)
df.rtsne[, 3] <- factor(df.rtsne[, 3], levels = c(1, 2),
labels = c("normal", "tumor"))
colnames(df.rtsne) <- c("X1", "X2", "Y")
trainIndex <- createDataPartition(df.rtsne$Y, p = 0.8, list = FALSE, times = 1)
train <- df.rtsne[trainIndex, ]
test <- df.rtsne[-trainIndex, ]
set.seed(100)
fitControl <- trainControl(method = "cv",
number = 5,
classProbs = TRUE,
summaryFunction = twoClassSummary)
set.seed(100)
fit1 <- train(Y ~ X1 + X2,
data = train,
method = "knn",
trControl = fitControl,
metric = "ROC")
fit1
## k-Nearest Neighbors
##
## 50 samples
## 2 predictor
## 2 classes: 'normal', 'tumor'
##
## No pre-processing
## Resampling: Cross-Validated (5 fold)
## Summary of sample sizes: 41, 40, 40, 39, 40
## Resampling results across tuning parameters:
##
## k ROC Sens Spec
## 5 0.8279762 0.65 0.9047619
## 7 0.8263889 0.65 0.8761905
## 9 0.7416667 0.55 0.8761905
##
## ROC was used to select the optimal model using the largest value.
## The final value used for the model was k = 5.
pred <- predict(fit1, newdata = test)
confusionMatrix(pred, test$Y, positive = "tumor")
## Confusion Matrix and Statistics
##
## Reference
## Prediction normal tumor
## normal 3 0
## tumor 1 8
##
## Accuracy : 0.9167
## 95% CI : (0.6152, 0.9979)
## No Information Rate : 0.6667
## P-Value [Acc > NIR] : 0.05395
##
## Kappa : 0.8
## Mcnemar's Test P-Value : 1.00000
##
## Sensitivity : 1.0000
## Specificity : 0.7500
## Pos Pred Value : 0.8889
## Neg Pred Value : 1.0000
## Prevalence : 0.6667
## Detection Rate : 0.6667
## Detection Prevalence : 0.7500
## Balanced Accuracy : 0.8750
##
## 'Positive' Class : tumor
##
P.S. Stochastic k-Neighborhood Selection for Supervised and Unsupervised Learning
Комментариев нет:
Отправить комментарий