Grafik von Pawel Czerwinski – https://unsplash.com/de/@pawel_czerwinski

Die Fähigkeiten der Dimensionalitätsreduktion nutzen: Eine Einführung in die Principal Component Analysis

Die Dimensionsreduktion ist ein immer wichtigerer Teil des Lernprozesses von maschinellen Lernprogrammen, da die Datensätze immer größer werden. Heute werden wir uns mit einer linearen Transformationsmethode auf niedrigdimensionale Vektorräume beschäftigen, um den Lernprozess potenziell zu verbessern. Dazu wird die Principal Component Analysis vorgestellt.

Henrik Bartsch

Henrik Bartsch

Die Texte in diesem Artikel wurden teilweise mit Hilfe künstlicher Intelligenz erarbeitet und von uns korrigiert und überarbeitet. Für die Generierung wurden folgende Dienste verwendet:

Wie wir maschinelles Lernen bei der Erstellung unserer Artikel einsetzen

Einführung

Die Datenreduktion ist ein wichtiger Schritt in der Datenanalyse und beim maschinellen Lernen, da sie verborgene Muster und Beziehungen in den Daten aufdeckt. Eine der beliebtesten und effektivsten Techniken zur unüberwachten Dimensionalitätsreduktion ist die Principal Component Analysis (PCA). Die PCA ist eine lineare Transformation, die die Originaldaten in einen niedrigdimensionalen Raum projiziert, der durch die Eigenvektoren der Kovarianzmatrix definiert ist. Auf diese Weise kann die PCA die wichtigsten Merkmale der Daten erfassen und gleichzeitig ihre Dimensionalität minimieren. Dies macht sie zu einem idealen Werkzeug für die Visualisierung von Daten, die Extraktion von Merkmalen und die Datenkompression. Darüber hinaus ist die PCA ein deterministischer Algorithmus, was bedeutet, dass sie bei gleichen Eingabedaten immer die gleichen Ergebnisse liefert. Dies erleichtert die Reproduzierbarkeit und Validierung der PCA-Ergebnisse, was bei anderen unüberwachten Dimensionsreduktionverfahren nicht immer der Fall ist. Im folgenden Blog-Eintrag möchten wir diesen Algorithmus vorstellen.

Mathematische Grundlagen

Die Grundidee der Principal Component Analysis ist relativ einfach: Wir versuchen herauszufinden, ob bestimmte Variablen in unseren Eingangsdaten redundant sind, d.h. ob ein Teil dieser Daten nicht durch einen anderen Teil unserer Daten repräsentiert werden kann und somit “versteckt” enthalten ist. Diese Eigenschaft wird auch als Korrelation bezeichnet. Außerdem untersuchen wir, wie hoch der Informationsgehalt einer Eingangsvariablen ist. Wir messen dies durch die Varianz, die es uns erlaubt, irrelevante Informationen durch ihren Mittelwert zu eliminieren, wenn sie einen geringen Informationsgehalt haben. 1 2

Um diese mathematischen Eigenschaften entsprechend zu verstehen, werden sie hier kurz eingeführt. 1 Angenommen, wir haben zwei (oder mehr) Datenpunkte der Form x1,x2Rnx_1, x_2 \in \mathbb{R}^n mit nNn \in \mathbb{N} vorliegen. In diesem Fall kann die Kovarianz der beiden Datenpunkte wie folgt definiert werden:

κ(x1,x2):=1n(x1x1ˉ)T(x2x2ˉ).\kappa(x_1, x_2) := \frac{1}{n} (x_1 - \bar{x_1})^T (x_2 - \bar{x_2}).

Der Ausdruck xˉ\bar{x} für einen Vektor xRnx \in \mathbb{R}^n stellt den Mittelwert des Vektors über alle seine Komponenten dar.

Mit dieser Definition können wir nun die Standardabweichung σ(x)\sigma(x) mit xRnx \in \mathbb{R}^n einführen.

σ(x):=κ(x,x).\sigma(x) := \sqrt{\kappa(x, x)}.

Weiter oben haben wir den Begriff Varianz verwendet. Die Varianz ist das Quadrat unserer Standardabweichung σ(x)\sigma(x), welche uns allerdings einen weiteren Rechenschritt kosten würde. 3 Entsprechend wird dies klassischerweise nicht direkt in Algorithmen verwendet, sondern stattdessen eher die Standardabweichung verwendet.

Im nächsten Schritt benötigen wir noch die Korrelation zwischen zwei Datenpunkten, welche wir unter Verwendung der letzten beiden Definitionen einführen können:

χ(x1,x2):=κ(x1,x2)σ(x1)σ(x2).\chi(x_1, x_2) := \frac{\kappa(x_1, x_2)}{\sigma(x_1)\sigma(x_2)}.

Um letztlich noch unkorrelierte Hauptkomponenten finden zu können, sind noch eine Reihe von Eigenschaften aus der linearen Algebra notwendig. Hierzu beginnen wir mit der Eigenschaft von Eigenwerten und Eigenvektoren: 1 4

Man nennt einen Vektor vRmv \in \mathbb{R}^m mit mNm \in \mathbb{N} einen Eigenvektor einer Matrix ARm×mA \in \mathbb{R}^{m \times m}, wenn es einen skalaren Wert λR\lambda \in \mathbb{R} gibt, sodass

Av=λvAv = \lambda v

gültig ist. In diesem Fall bezeichnen wir λ\lambda als Eigenwert von AA zum Eigenvektor vv.

Anschaulich erklärt bedeutet dieses Konzept, dass die Multiplikation eines spezifischen Vektors für eine gegebene Matrix (welche möglicherweise sowohl Streck- als auch Rotationskomponenten erzeugen kann) lediglich eine Streckung unseres spezfischen Vektors um einen Faktor λ\lambda bewirkt.

Eine solche Definition lässt sich verwenden, um eine sogenannte Eigenraumzerlegung durchzuführen. Dies kann so beschrieben werden:

Zu einer gegebenen Matrix ARm×mA \in \mathbb{R}^{m \times m} seien v1,,vmRmv_1, \dots, v_m \in \mathbb{R}^m Eigenvektoren und die zugehörigen Eigenwerte λ1,,λm\lambda_1, \dots, \lambda_m. In diesem Fall können wir dies in den Matrizen VRm×mV \in \mathbb{R}^{m \times m} und ΛRm×m\Lambda \in \mathbb{R}^{m \times m} zusammenfassen:

V=(v1,,vm),V = (v_1, \dots, v_m),

Λ=diag(λ1,,λm).\Lambda = diag(\lambda_1, \dots, \lambda_m).

In diesem Fall können wir unsere Eigenraumzerlegung durch

AV=VΛA V = V \Lambda

darstellen.

Dies ist eine nützliche Eigenschaft für die Principal Component Analysis. Letztendlich suchen wir nach Linearkombinationen von Eingangsvariablen, die miteinander korreliert sind. Das bedeutet, dass diese im Prinzip durch andere Variablen dargestellt werden können und somit eine Redundanz in unseren Daten darstellen. Eine Eigenraumzerlegung gibt uns die Möglichkeit, eine solche Analyse für alle unsere Daten zu finden. Daten mit besonders hohen Eigenwerten haben also eine hohe Varianz und damit einen hohen Informationsgehalt, der uns interessiert. Daten mit geringen Eigenwerten haben einen geringen Einfluss auf die Information im Datensatz und damit eine geringe Varianz. Die Eigenvektoren sind hier die Hauptkomponenten, die ein transformiertes Koordinatensystem darstellen, in dem wir unsere Daten effizienter darstellen können.

Durch die Suche nach Linearkombinationen der Eingangsvariablen ist der Algorithmus auf lineare Abhängigkeiten zwischen den einzelnen Variablen beschränkt und kann somit keine nichtlinearen Zusammenhänge abbilden.

Um all diese Informationen zu erhalten, müssen wir eine Eigenraumzerlegung auf unsere Kovarianzmatrix anwenden. Wir können unsere Kovarianzmatrix wie folgt darstellen

K=(κ(x1,x1),,κ(x1,xm)κ(xm,x1),κ(xm,xm)).K = \begin{pmatrix} \kappa(x_1, x_1), & \cdots, & \kappa(x_1, x_m) \\ \vdots & & \vdots \\ \kappa(x_m, x_1) & \cdots, & \kappa(x_m, x_m) \end{pmatrix}.

Auf diese Matrix können wir nun eine Eigenraumzerlegung anwenden. Anschließend können wir durch Filtern nach den größten Eigenwerten (und potenzieller Festlegung der Anzahl von späteren Features) die größten lNl \in \mathbb{N} Eigenvektoren verwenden, um auf diesen unsere reduzierten Daten darzustellen. Diese Eigenvektoren nennen wir im nun Hauptkomponenten, um die Verbindung dieser Eigenvektoren mit dem Algorithmus darzustellen. Diese Hauptkomponenten sind unkorreliert und orthogonal zueinander, sind also nicht redundant und können nicht durch eine Kombination anderer Hauptkomponenten dargestellt werden. 1 5

Anwendungsbeispiel

Im Folgenden verwenden wir ähnliche Trainingsdaten wie in unserem Blogpost zum Algorithmus der Random Projections, um die Vergleichbarkeit innerhalb dieser Disziplin darstellen zu können. Auch hier verwenden wir speziell die Version 2.12.02.12.0 von Tensorflow, um Fehler im Code zu vermeiden. Im ersten Schritt importieren wir alle notwendigen Bibliotheken:

pca.py
import tensorflow_datasets as tfds
import tensorflow as tf
import numpy as np

import math

from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import InputLayer, Dense
from tensorflow.python.keras.optimizer_v2.adam import Adam
from tensorflow.python.keras.losses import sparse_categorical_crossentropy
from sklearn.decomposition import PCA

Als nächstes laden wir den Datensatz colorectal_histology herunter. Dieser enthält Bilddaten mit einer Bildgröße von 150×150×3150 \times 150 \times 3. Wir wollen die Anzahl dieser Eingabedaten in unserem Code reduzieren, in der Hoffnung, eine bessere Trainingsgenauigkeit der neuronalen Netze zu erreichen, die für eine Klassifikation trainiert werden. Die Bilddaten werden direkt transformiert, so dass alle Merkmale in einem Vektor für jedes Bild enthalten sind. Dies vereinfacht später die Dimensionsreduktion.

pca.py
hist_data = tfds.load("colorectal_histology")

df_train = tfds.as_dataframe(hist_data["train"])
images = df_train["image"].values

temp = []
for element in images:
element = np.reshape(element, [-1])
temp.append(element)

images = np.array(temp)
labels = df_train["label"].values

Der nächste Schritt ist die Festlegung eines Prozentsatzes für einen Train-Test-Split. In diesem Fall legen wir 80%20%80\%-20\% fest, was häufig verwendete Werte sind.

pca.py
train, test = 0.8, 0.2
amount_train, amount_test = math.ceil(images.shape[0] * train), math.floor(images.shape[0] * test)
print(amount_train, amount_test)

In Verbindung damit ist es notwendig, die entsprechenden Trainings- und Testdaten aus allen Daten zu extrahieren. Dies geschieht im folgenden Codeabschnitt:

pca.py
indices_train = np.random.choice(images.shape[0], amount_train, replace=False)
indices_train = np.sort(indices_train)

indices_test = []
for i in range(images.shape[0]):
if ((i in indices_train) == False):
  indices_test.append(i)

indices_test = np.array(indices_test)

train_x, train_y, test_x, test_y = [], [], [], []

train_x = images[indices_train]
train_y = labels[indices_train]

train_x, train_y = tf.convert_to_tensor(train_x), tf.convert_to_tensor(train_y)

test_x = images[indices_test]
test_y = labels[indices_test]

test_x, test_y = tf.convert_to_tensor(test_x), tf.convert_to_tensor(test_y)

Anschließend definieren wir ein neuronales Netz, mit dem wir unsere Daten klassifizieren können.

pca.py
model = Sequential([
InputLayer(input_shape=(67500,)),
Dense(units=128, activation="relu"),
Dense(units=128, activation="relu"),
Dense(units=64, activation="relu"),
Dense(units=8, activation="softmax")
])

optimizer = Adam(learning_rate=10e-4)
model.compile(optimizer=optimizer,
          loss=sparse_categorical_crossentropy,
          metrics=["accuracy"])
model.summary()

Im nächsten Schritt trainieren wir dies mit unseren Trainingsdaten und lassen uns die Ergebnisse während des Trainings anzeigen.

pca.py
history = model.fit(x=train_x, y=train_y,
                epochs=20, batch_size=64,
                validation_data=(test_x, test_y))

Schließlich können wir noch einen spezifischen Testlauf des neuronalen Netzes auf unseren Testdaten durchführen.

pca.py
model.evaluate(x=test_x, y=test_y)

Aus dieser Grafik können wir erkennen, dass unser Training leider nicht sehr stabil ist. Dafür kann es es mehrere Gründe geben:

  • Fehlerhafte Einstellung der Trainingsepochen,
  • Fehlerhafte Einstellung der Batch Size,
  • Fehlerhafte Architektur des neuronalen Netzes,
  • Ein zu kleiner Datensatz oder
  • Zu hohe Eingangsdimensionen des Datensatzes.

Nun kommen wir zum eigentlich interessanten Teil: Die Dimensionality Reduction mittels Principal Component Analysis. Dies können wir mittels scikit-learn in ein paar Zeilen von Code implementieren:

pca.py
pca = PCA()
reduced_images = pca.fit_transform(images)

Anschließend werden die reduzierten Ausgabedaten zur Erstellung der reduzierten Trainings- und Testdatensätze verwendet.

pca.py
reduced_train_x = reduced_images[indices_train]

reduced_test_x = reduced_images[indices_test]

Nun müssen wir unser neuronales Netz neu definieren, damit es die reduzierten Eingabedaten korrekt verarbeiten kann und nicht die Ergebnisse des letzten Trainingslaufs verwendet, die das Endergebnis verfälschen könnten.

pca.py
model = Sequential([
InputLayer(input_shape=(5000,)),
Dense(units=128, activation="relu"),
Dense(units=128, activation="relu"),
Dense(units=64, activation="relu"),
Dense(units=8, activation="softmax")
])

optimizer = Adam(learning_rate=10e-4)
model.compile(optimizer=optimizer, loss=sparse_categorical_crossentropy, metrics=["accuracy"])
model.summary()

Schließlich trainieren und testen wir das neuronale Netz erneut, um die benötigten Daten zu erhalten.

pca.py
history = model.fit(x=reduced_train_x, y=train_y,
                epochs=20, batch_size=64,
                validation_data=(reduced_test_x, test_y))
pca.py
model.evaluate(x=reduced_test_x, y=test_y)

Zur Veranschaulichung haben wir die Trainingsgenauigkeit und die Testgenauigkeit dargestellt:

Nach der Anwendung des obigen Codes können wir alle hier erzeugten Ergebnisse miteinander vergleichen.

NameVollständiger DatensatzReduzierter Datensatz
Maximale Trainingsgenauigkeit59%59\%99.2%99.2\%
Finale Trainingsgenauigkeit58.38%58.38\%97%97\%
Maximale Testgenauigkeit53.7%53.7\%57%57\%
Finale Testgenauigkeit42.4%42.4\%56.5%56.5\%
Anzahl von Eingangspixeln675006750050005000
Ausführungszeit-13m\approx 13m
Trainingsszeit240s\approx 240s13s13s

Alle Berechnungen wurden mittels der Hardware von Google Colab durchgeführt. Experimente können dort wiederholt werden, obwohl beispielsweise die Ausführungszeit aufgrund der Verfügbarkeit von Hardware bei Google Colab schwanken kann.

Der Parameter Ausführungszeit gibt an, wie lange die Dimensionalitätsreduktion unter Verwendung der Principal Component Analysis gedauert hat.

Insgesamt zeigt sich, dass eine Dimensionalitätsreduktion im Rahmen des Preprocessings sehr gut helfen kann, die Genauigkeit eines Modells zu verbessern. Dies ist grundsätzlich nicht auf neuronale Netze beschränkt, sondern kann auch bei anderen “Machine Learning”-Techniken hilfreich sein. Ebenso wichtig ist die Reduktion der Trainingszeit, die zu Kosteneinsparungen führt.

Die Verbesserung des Trainings- und Testverhaltes beim Training mit dem reduzierten Datensatz kann auf den Fluch der Dimensionalität zurückgeführt werden.

Vor- und Nachteile

Im Folgenden werden die Vor- und Nachteile des hier verwendeten Verfahrens untersucht. Insbesondere vergleichen wir die Principal Component Analysis mit den Random Projections, die ebenfalls ein populärer Algorithmus in diesem Bereich sind.

Vorteile

  1. Verzerrungen: Durch die Eigenschaft der Principal Component Analysis, die Orthogonalität durch die Verwendung von Eigenräumen aufrechtzuerhalten, erzeugen wir keine Verzerrungen in den Daten. Zufallsprojektionen sind nur näherungsweise orthogonal, was zu Verzerrungen führen kann. 6

Diese Eigenschaft ist nur dann erfüllt, wenn die Abhängigkeiten zwischen den einzelnen Merkmalen tatsächlich linear sind. Treten Nichtlinearitäten auf, ist diese Eigenschaft nicht unbedingt erfüllt.

  1. Optimalität: Die Verwendung der Principal Component Analysis führt zu optimalen Ergebnissen, da wir (soweit möglich) mathematisch exakte Eigenschaften verwenden, anstatt uns auf Näherungen zu verlassen, wie es bei den Random Projections der Fall ist. Dies führt in der Regel dazu, dass die Dimension der Ergebnisdaten kleiner ist, als dies bei Random Projections der Fall wäre. 6

Nachteile

  1. Laufzeit: Die Principal Component Analysis liefert zwar bessere Ergebnisse, diese werden aber mit einer längeren Laufzeit erkauft. 6 7 8 In unserem Beispiel benötigt die Principal Component Analysis eine um den Faktor 6.5\approx 6.5 höhere Laufzeit als Random Projections. Dies liegt vor allem an der numerisch aufwendigen Berechnung der Eigenwerte und Eigenvektoren. Insbesondere bei immer größer werdenden Datensätzen kann dies zu Problemen führen. Random Projections sind daher für sehr hochdimensionale Daten besser geeignet.

Grundsätzlich ist es möglich, einen Kompromiss zwischen optimalen Ergebnissen und Rechenzeit zu finden, indem Algorithmen zur Approximation der Eigenwerte und Eigenvektoren unter speziellen Bedingungen eingesetzt werden. Beispiele für solche Algorithmen sind die Potenzmethode oder das Lanczos-Verfahren. 6

  1. Ähnlichkeit: In einigen Beispielen sind Random Projections besser als die Principal Component Analysis in der Lage, die Ähnlichkeit bei der Transformation in einen niedrigerdimensionalen Vektorraum beizubehalten. 6

  2. Linearität: Die Principal Component Analysis beinhaltet die Notwendigkeit, dass die Daten linear voneinander abhängig sind. Wenn die Daten nicht linear voneinander abhängig sind, kann dieser Algorithmus keine guten Ergebnisse liefern.

  3. Ausreißer: Das Vorhandensein von Ausreißern in den Daten kann dazu führen, dass die Daten wesentlich schlechter sind, als wenn diese Ausreißer nicht im Datensatz enthalten wären. Dies liegt daran, dass die Hauptkomponenten durch das Vorhandensein der Ausreißer verändert werden und nicht mehr unbedingt die tatsächliche Struktur des Datensatzes widerspiegeln. 9

Als Abhilfe kann eine Ausreißeranalyse auf den Datensatz angewendet oder eine Normalisierung der Variablen durchgeführt werden. Eine Normalisierung der Variablen wird für die Principal Component Analysis empfohlen. 10 11

Anwendungsgebiete

Die Principal Component Analysis kann theoretisch in vielen Bereichen verwendet werden. Hier sind einige Beispiele, in welchen Bereichen dieser Algorithmus verwendet wird: 9 6

  1. Marketing: Bei der Analyse von Kundendaten kann PCA eingesetzt werden, um irrelevante Faktoren aus Datensätzen herauszufiltern, die nur einen geringen Einfluss auf das Kaufverhalten haben. Dadurch kann Werbung gezielter gestaltet und der Absatz gesteigert werden.

  2. Statistische Analyse: Bei einem statistischen Modell mit vielen Merkmalen kann es vorkommen, dass die Komplexität durch viele Merkmale die Qualität des Modells verringert. Eine Reduzierung der Modellparameter durch PCA kann die Qualität und korrekte Vorhersagewahrscheinlichkeit erhöhen.

  3. Bildverarbeitung: Bei der Analyse von Satellitenbildern liegen häufig große Datensätze vor, welche in ihrer rohen Form eine Analyse schwer machen. Eine Reduzierung der Daten durch PCA hilft, die Analyse zu vereinfachen und die Ergebnisse zu verbessern.

  4. Textanalyse: Durch die hohe Dimension von Textdaten ist eine Reduzierung teilweise notwendig. PCA kann eine solche Reduktion erreichen.

Quellen

Footnotes

  1. imsc.uni-graz.at 2 3 4

  2. link.springer.com

  3. wikipedia.com

  4. wikipedia.com

  5. imb.com

  6. users.ics.aalto.fi 2 3 4 5 6

  7. arxiv.org

  8. medium.com

  9. wikpedia.com 2

  10. link.springer.com

  11. wikipedia.org