Gerne, um die Schritte der Hauptkomponentenanalyse (PCA) auf einem zweidimensionalen Datensatz zu veranschaulichen, werden wir die ersten beiden Merkmale des Iris-Datensatzes – Kelchblattlänge (sepal length) und Kelchblattbreite (sepal width) – auswählen und die Transformationen von den Originaldaten bis zur Darstellung im Hauptkomponenten-Koordinatensystem Schritt für Schritt visualisieren.
Hier ist die Implementierung der geforderten Schritte in Python, begleitet von Erklärungen, die auf den bereitgestellten Quellen basieren:
import matplotlib.pyplot as pltfrom sklearn.decomposition import PCAfrom sklearn.datasets import load_irisfrom sklearn.preprocessing import StandardScalerimport seaborn as snsimport pandas as pdimport numpy as np# Iris-Datensatz ladeniris = load_iris(as_frame=True)iris.frame["target"] = iris.target_names[iris.target]# Für diese Demonstration wählen wir nur die ersten beiden Merkmale des Iris-Datensatzes:# Kelchblattlänge (sepal length) und Kelchblattbreite (sepal width).# Die Originaldaten des Iris-Datensatzes bestehen aus 4 Merkmalen.# Um die Funktionsweise der PCA Schritt für Schritt in 2D zu zeigen,# verwenden wir hier explizit nur 2 dieser Originalmerkmale.X_2d_original = iris.data[['sepal length (cm)', 'sepal width (cm)']]y_target = iris.targettarget_names = iris.target_namesprint(f"Gewählte Merkmale für die PCA: {X_2d_original.columns.tolist()}")# --- 1. Plotte diese zweidimensionalen Daten zunächst in einem klassischen x-y Koordinatensystem. ---plt.figure(figsize=(7,7))sns.scatterplot( x=X_2d_original['sepal length (cm)'], y=X_2d_original['sepal width (cm)'], hue=iris.frame['target'], # Farben nach Iris-Typ palette='viridis', s=70, alpha=0.8)plt.title("1. Originale Iris-Daten (Kelchblattlänge vs. Kelchblattbreite)")plt.xlabel("Kelchblattlänge (cm)")plt.ylabel("Kelchblattbreite (cm)")plt.grid(True, linestyle='--', alpha=0.6)plt.axhline(0, color='gray', linewidth=0.5) # Ursprungslinien zur Orientierungplt.axvline(0, color='gray', linewidth=0.5)plt.show()# --- 2. Skaliere die Daten und zeichne diese ebenfalls. ---# --- 3. Verschiebe die Daten in den Ursprung und zeichne die Daten. ---# Bevor PCA durchgeführt wird, ist es entscheidend, die Daten zu skalieren und zu zentrieren.# Ungleich skalierte Variablen können die PCA verzerren.# Der StandardScaler zentriert die Daten (d.h., der Mittelwert jeder Spalte wird 0)# und skaliert sie (d.h., die Standardabweichung jeder Spalte wird 1).# Das Zentrieren bedeutet effektiv, dass der Mittelpunkt der Daten zum Ursprung (0,0) verschoben wird.scaler = StandardScaler()X_scaled = scaler.fit_transform(X_2d_original)# Konvertiere skalierte Daten zurück in einen DataFrame für einfachere Beschriftung und DarstellungX_scaled_df = pd.DataFrame(X_scaled, columns=X_2d_original.columns)# After scaling the data, determine the axis limitsx_min = X_scaled_df['sepal length (cm)'].min() *1.1x_max = X_scaled_df['sepal length (cm)'].max() *1.1y_min = X_scaled_df['sepal width (cm)'].min() *1.1y_max = X_scaled_df['sepal width (cm)'].max() *1.1# Function to set consistent axis limits and stylingdef set_consistent_axes(ax): ax.set_xlim(x_min, x_max) ax.set_ylim(y_min, y_max) ax.axhline(0, color='gray', linewidth=0.8, linestyle='-') ax.axvline(0, color='gray', linewidth=0.8, linestyle='-') ax.grid(True, linestyle='--', alpha=0.6)# Plot 2/3: Scaled and centered dataplt.figure(figsize=(7,7))ax = plt.gca() # get current axessns.scatterplot( x=X_scaled_df['sepal length (cm)'], y=X_scaled_df['sepal width (cm)'], hue=iris.frame['target'], palette='viridis', s=70, alpha=0.8)plt.title("2./3. Skalierte und zentrierte Iris-Daten (am Ursprung)")plt.xlabel("Skalierte Kelchblattlänge")plt.ylabel("Skalierte Kelchblattbreite")set_consistent_axes(ax)plt.show()# --- 4. Bestimme die erste Hauptkomponente und zeichne diese. ---pca_1_component = PCA(n_components=1)pca_1_component.fit(X_scaled)# Get the direction vector of PC1pc1_vector = pca_1_component.components_[0] # Extract first component vector# Create line coordinates for plottingscale_factor = np.max(np.abs(X_scaled)) *1.5line_x = np.array([-scale_factor * pc1_vector[0], scale_factor * pc1_vector[0]])line_y = np.array([-scale_factor * pc1_vector[1], scale_factor * pc1_vector[1]])# Plot the scaled data and PC1# Plot 4: With PC1plt.figure(figsize=(7,7))ax = plt.gca()sns.scatterplot( x=X_scaled_df['sepal length (cm)'], y=X_scaled_df['sepal width (cm)'], hue=iris.frame['target'], palette='viridis', s=70, alpha=0.8)plt.plot(line_x, line_y, color='red', linestyle='-', linewidth=2, label='Hauptkomponente 1 (PC1)')plt.title("4. Skalierte Daten mit der ersten Hauptkomponente (PC1)")plt.xlabel("Skalierte Kelchblattlänge")plt.ylabel("Skalierte Kelchblattbreite")set_consistent_axes(ax)plt.legend()plt.show()# --- 5. Visualisiere den weiteren Verlauf der PCA, so dass am Ende die transformierten Daten im Koordinatensystem der beiden Hauptkomponenten sichtbar sind! ---# Da es sich um zweidimensionale Daten handelt, ist die zweite Hauptkomponente (PC2)# einfach die Linie durch den Ursprung, die senkrecht zu PC1 steht.# Die transformierten Daten sind die Projektionen der Originaldaten auf diese neuen Achsen.# Die endgültige PCA-Grafik wird erstellt, indem alles so gedreht wird,# dass PC1 horizontal (als neue X-Achse) und PC2 vertikal (als neue Y-Achse) liegt.pca_2_components = PCA(n_components=2)X_pca_2d = pca_2_components.fit_transform(X_scaled) # Transformiert die Daten in das PC-Koordinatensystem# Optional: Visualisierung von PC1 und PC2 auf den skalierten Daten# Optional: Visualisierung von PC1 und PC2 auf den skalierten Datenpc1_vector = pca_2_components.components_[0] # First principal componentpc2_vector = pca_2_components.components_[1] # Second principal component# Scale factor for visualizationscale_factor = np.max(np.abs(X_scaled)) *1.5# Create line coordinates for PC1line1_x = np.array([-scale_factor * pc1_vector[0], scale_factor * pc1_vector[0]])line1_y = np.array([-scale_factor * pc1_vector[1], scale_factor * pc1_vector[1]])# Create line coordinates for PC2line2_x = np.array([-scale_factor * pc2_vector[0], scale_factor * pc2_vector[0]])line2_y = np.array([-scale_factor * pc2_vector[1], scale_factor * pc2_vector[1]])# Plot the scaled data with both principal components# Plot 5a: With PC1 and PC2plt.figure(figsize=(7,7))ax = plt.gca()sns.scatterplot( x=X_scaled_df['sepal length (cm)'], y=X_scaled_df['sepal width (cm)'], hue=iris.frame['target'], palette='viridis', s=70, alpha=0.8)plt.plot(line1_x, line1_y, color='red', linestyle='-', linewidth=2, label='Hauptkomponente 1 (PC1)')plt.plot(line2_x, line2_y, color='blue', linestyle='--', linewidth=2, label='Hauptkomponente 2 (PC2)')plt.title("Skalierte Daten mit PC1 und PC2 (vor der Drehung)")plt.xlabel("Skalierte Kelchblattlänge")plt.ylabel("Skalierte Kelchblattbreite")set_consistent_axes(ax)plt.legend()plt.show()# Plot 5b: Transformed data# # Plot der transformierten Daten im neuen Koordinatensystemplt.figure(figsize=(7,7))ax = plt.gca()sns.scatterplot( x=X_pca_2d[:, 0], y=X_pca_2d[:, 1], hue=iris.frame['target'], palette='viridis', s=70, alpha=0.8)plt.title("Transformierte Iris-Daten im PC1-PC2-Koordinatensystem")plt.xlabel(f"Hauptkomponente 1 (PC1) - {pca_2_components.explained_variance_ratio_[0]:.1%} Varianz")plt.ylabel(f"Hauptkomponente 2 (PC2) - {pca_2_components.explained_variance_ratio_[1]:.1%} Varianz")# Gitter hinzufügenplt.grid(True, linestyle='--', alpha=0.6)# Koordinatenachsen hinzufügenplt.axhline(0, color='red', linewidth=2, linestyle='-')plt.axvline(0, color='blue', linewidth=2, linestyle='--')set_consistent_axes(ax)plt.show()
Gewählte Merkmale für die PCA: ['sepal length (cm)', 'sepal width (cm)']