# Experiment 8: Dimensionality Reduction using Principal Component Analysis (PCA)
# Requirements: pip install numpy pandas matplotlib seaborn scikit-learn

# ==========================================
# STEP 1: Import Libraries & Load Dataset
# ==========================================
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_breast_cancer
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA

# Load High-Dimensional Dataset (Breast Cancer Dataset - 30 features)
data = load_breast_cancer()
X = data.data
y = data.target
feature_names = data.feature_names

df = pd.DataFrame(X, columns=feature_names)
print("--- Dataset Shape ---")
print(df.shape)
print("\n--- Dataset Head ---")
print(df.head())

# ==========================================
# STEP 2: Feature Standardization
# ==========================================
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# ==========================================
# STEP 3: Full PCA & Scree Plot Analysis
# ==========================================
pca_full = PCA()
pca_full.fit(X_scaled)

cum_variance = np.cumsum(pca_full.explained_variance_ratio_)

plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
plt.bar(range(1, len(pca_full.explained_variance_ratio_) + 1),
        pca_full.explained_variance_ratio_, alpha=0.6, align='center',
        label='Individual Explained Variance')
plt.step(range(1, len(cum_variance) + 1), cum_variance, where='mid',
         color='red', label='Cumulative Explained Variance')
plt.axhline(y=0.90, color='g', linestyle='--', label='90% Variance Threshold')
plt.title('Scree Plot & Cumulative Explained Variance')
plt.xlabel('Principal Component Index')
plt.ylabel('Explained Variance Ratio')
plt.legend(loc='best')
plt.grid(True)

# ==========================================
# STEP 4: PCA Reduction to 2 Components
# ==========================================
pca_2d = PCA(n_components=2)
X_pca_2d = pca_2d.fit_transform(X_scaled)

print("\n--- Explained Variance Ratio (Top 2 Components) ---")
print(f"PC1 Variance Ratio: {pca_2d.explained_variance_ratio_[0]:.4f}")
print(f"PC2 Variance Ratio: {pca_2d.explained_variance_ratio_[1]:.4f}")
print(f"Total Preserved Variance: {np.sum(pca_2d.explained_variance_ratio_):.4f}")

# STEP 5: Visualize Reduced Data Space
plt.subplot(1, 2, 2)
scatter = plt.scatter(X_pca_2d[:, 0], X_pca_2d[:, 1], c=y, cmap='coolwarm', alpha=0.8, edgecolors='k')
plt.title('2D PCA Projection of Dataset')
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.legend(handles=scatter.legend_elements()[0], labels=['Malignant', 'Benign'])
plt.grid(True)

plt.tight_layout()
plt.show()

# Display Component Loadings
df_comp = pd.DataFrame(pca_2d.components_, columns=feature_names, index=['PC1', 'PC2'])
print("\n--- Component Loadings (Top Features Contribution) ---")
print(df_comp.iloc[:, :5])
