Um zu demonstrieren, wie mit PCA Prognosen (predictions) gemacht werden können, benutzen wir wieder den Iris-Datensatz.
data(iris)
head(iris, 3)
## 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
Die letzte Spalte enthält die Bezeichnung der Art:
levels(iris[,5])
## [1] "setosa" "versicolor" "virginica"
Die PCA kann mit Hilfe der Funktion prcomp
durchgeführt werden. Die Daten sollten auf jeden Fall zentriert werden
(center = TRUE), hier werden wir auch skalieren
(scale = TRUE):
pca <- prcomp(iris[,-5], center = TRUE, scale = TRUE)
Die ersten beiden Hauptkomponenten können mit Hilfe der
autoplot-Funktion aus dem Package ggfortify
abgebildet werden. Das Zuordnen der Farben zu den Arten ist hier sehr
elegant möglich (mit colour = "Species"):
suppressWarnings(suppressPackageStartupMessages(library(ggfortify)))
autoplot(pca, data = iris, colour = "Species")
Wir sehen, dass die Arten aufgrund ihrer Position im Plot hinreichend
gut separiert werden können, auf jeden Fall trifft das auf
setosa zu. Folglich lässt sich die PCA zur Prognose
(“prediction”) verwenden, d.h. wir können bisher noch nicht
klassifizierte Exemplare aufgrund dieser vier morphologischen Daten
einer der drei Arten zuordnen.
Eine Prognose erstellen heißt in dem hier betrachteten Zusammenhang,
dass bisher nicht klassifizierte Exemplare der Gattung Iris aufgrund der
vorliegenden morphologischen Daten einer der 3 Arten zugeordnet
werden.
Wir wenden dabei das sogenannte supervised
learning an. Beim supervised learning benutzen wir Daten
mit bekannter Artzugehörigkeit als Trainingsdaten. Mit
diesen Trainingsdaten erstellen wir ein Modell.
Bei einem anderen Teil der Daten - den Testdaten - ist
die Artzugehörigkeit nicht bekannt, sondern es liegen nur die
morphologischen Daten vor. Mit Hilfe des Modells soll für die Testdaten
nun die Artzugehörigkeit bestimmt werden.
Wir wollen im Folgenden 90% der Iris-Daten verwenden, um mittels PCA ein Modell zu erstellen. Das Modell enthält Informationen darüber, wie die Lage der Punkte im Plot der Hauptkomponenten mit einer der 3 Arten verknüpft ist.
Dann werden wir kurz vergessen, dass wir für die restlichen 10% der Exemplare eigentlich die Arten-Bezeichnungen schon kennen. Diese Arten-Bezeichnungen versuchen wir dann herauszufinden, indem wir ihre Lage in dem mit dem Modell erstellten Hauptkomponenten-Plot auswerten.
Zur programmtechnischen Durchführung wählen wir mit dem sample-Kommando zufällig 15 Zahlen aus den Zahlen 1 bis 150 aus - dies sind dann die Indizes der Testdaten:
set.seed(333)
ind = sample(1:150, 15)
ind
## [1] 142 55 66 39 60 2 134 67 44 103 40 63 87 75 90
testdata = iris[ind,-5]
dim(testdata)
## [1] 15 4
head(testdata, 3)
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## 142 6.9 3.1 5.1 2.3
## 55 6.5 2.8 4.6 1.5
## 66 6.7 3.1 4.4 1.4
Die anderen 135 Exemplare dienen als Trainingsdaten:
traindata = iris[-ind,-5]
dim(traindata)
## [1] 135 4
head(traindata, 3)
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 5.1 3.5 1.4 0.2
## 3 4.7 3.2 1.3 0.2
## 4 4.6 3.1 1.5 0.2
Um das Modell zu erstellen, führen wir nun die PCA mit den
Trainingsdaten durch. Das Ergebnis der PCA wird zunächst im Objekt
pca_model gespeichert:
pca_model = prcomp(traindata, center = TRUE, scale = TRUE) # new object, contains the model
Alle notwendigen Parameter der Projektion sind im Objekt
pca_model gespeichert.
Wir plotten jetzt die ersten beiden Hauptkomponenten der
Trainingsdaten. Die Farben werden anhand der
Species-Bezeichnung gewählt:
color_num = as.numeric(iris[-ind,]$Species) + 1 # specify colours for training data
plot(pca_model$x[,1:2], col = color_num, xlab = "PC1", ylab = "PC2", main = "PCA training results", font.main = 1, pch = 16)
legend(-1, 2.7, c("setosa", "versicolor", "virginica"), col = c(2,3,4), pch = 16)
Nun der eigentliche Schritt bei der Prognose’: Wir
wenden auf die Testdaten genau die gleiche Projektion an, welche bereits
für die Trainingsdaten verwendet wurde. Genauer gesagt: es wird die
gleiche Drehmatrix auf die Testdaten angewendet wie zuvor auf die
Trainingsdaten. Die Drehmatrix besteht aus den Eigenvektoren der
Kovarianzmatrix der Trainingsdaten und ist im Objekt pca_model
enthalten.
Technisch geschieht das mittels der Funktion predict:
prediction = predict(pca_model, newdata = testdata)
head(prediction, 3)
## PC1 PC2 PC3 PC4
## 142 1.881065 0.6642441 0.1110383 0.4697214
## 55 1.070844 -0.2125961 -0.4114502 0.1124056
## 66 0.874583 0.4887231 -0.5104178 0.1157040
Das Objekt prediction enthält die Positionen der
Testdaten im Plot der Hauptkomponenten (welcher mit den Trainingsdaten
erzeugt wurde). Wir werden jetzt die Testdaten zum Plot hinzugefügen.
Zunächst wird noch einmal der Plot mit den Trainingsdaten erstellt. Von
den projizierten Testdaten werden ebenfalls nur die ersten beiden
Haupkomponenten geplottet. Wir können den Testdaten die bekannten
korrekten Farben zuordnen, um zu sehen, wie gut die Prognose
funktioniert (im Realfall kann man dies bei der Prognose natürlich
nicht, da die Arten-Bezeichnungen ja eben nicht bekannt sind,
sondern prognostiziert werden sollen). Wir plotten diesmal die
Trainingsdaten als kleine Kreise (pch = 1) und die
Testdaten als große ausgefüllte Kreise
(pch = 16, cex = 1.5), um die Punkte unterscheiden zu
können:
color_num = as.numeric(iris[-ind,]$Species) + 1 # specify colours for training data
plot(pca_model$x[,1:2], col = color_num, xlab = "PC1", ylab = "PC2", main = "PCA results", font.main = 1, pch = 1)
legend(-1, 2.7, c("setosa", "versicolor", "virginica"), col = c(2,3,4), pch = 1)
test_colors = as.numeric(iris[ind,]$Species) + 1 # colours for the test data
points(prediction[,1:2], pch = 16, cex = 1.5, col = test_colors) # test data
Dies scheint hinreichend gut geklappt zu haben. Die Testdaten könnnen
fast alle anhand ihrer Lage im Plot der korrekten Art zugeordnet werden.
Das heißt: hätten wir die wahren Arten-Bezeichnungen der Testdaten nicht
gekannt, hätten wir diese nun anhand der Lage der Punkte in der
Abbildung erraten können. Probleme würde es eventuell bei der
Unterscheidung von versicolor und virginica
geben, da diese schon in den Trainingsdaten recht nahe beieinander
liegen - kein Modell ist perfekt!.
Note that all code snippets are designed for comprehensibility, not for efficiency!