# pip install numpy pandas matplotlib minisom scikit-learn
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from minisom import MiniSom
from sklearn.preprocessing import MinMaxScaler

df = pd.read_csv("Credit_Card_Applications.csv")

# Select Numerical Columns
X = df.select_dtypes(include=np.number)

# Remove Empty and Constant Columns
X = X.dropna(axis=1, how='all')
X = X.loc[:, X.nunique() > 1]

# Handle Missing Values
X = X.fillna(X.median())

# Normalize Data
scaler = MinMaxScaler()
X = scaler.fit_transform(X)

# Create SOM
grid = max(5, min(15, int(np.sqrt(len(X)))))

som = MiniSom(
    x=grid,
    y=grid,
    input_len=X.shape[1],
    sigma=1.0,
    learning_rate=0.5,
    random_seed=42
)

# Initialize Weights
som.random_weights_init(X)

# Train SOM
som.train_random(X, num_iteration=1000)
print("SOM Training Completed")
print("Dataset Shape:", X.shape)
print("Total Records:", len(X))
print("Quantization Error:", som.quantization_error(X))
for i in range(30):
    print("Record:", i, "BMU:", som.winner(X[i]))
    
# Plot SOM
plt.figure(figsize=(9, 8))

plt.pcolor(som.distance_map().T, cmap='bone_r')
plt.colorbar(label='Distance')

# Plot Data Points
for i, sample in enumerate(X):
    w = som.winner(sample)

    plt.plot(
        w[0] + 0.5,
        w[1] + 0.5,
        'o',
        markerfacecolor='None',
        markeredgecolor='red',
        markersize=7
    )

plt.title("Self Organizing Map")
plt.show()
