"""
## **1. Principal Component Analysis**
"""
"""
### **Make sample data**
<br>

**make_blobs parameter(default)**
- n_features(20): number of independent variables
- n_samples(100): number of total sample data
- centers(3): number of cluster
- cluster_std(1.0): cluster standard deviation
- center_box(-10.0, 10.0): bounding box of cluster
- shuffle(True): whether to shuffle numbers
"""
from sklearn.datasets import make_blobs

X1, Y1 = make_blobs(n_features = 4,
                    n_samples = 100,
                    centers = 4,
                    random_state = 4,
                    cluster_std = 2)
"""
### **Check result**

- X1: total sample data
- Y1: allocated cluster per data
"""
print(X1[:5])
print(Y1[:5])
"""
### **Declare & Apply PCA**
"""
from sklearn import decomposition
import pandas as pd

# class declaration for PCA
pca = decomposition.PCA(n_components = 4, # number of PC
                        random_state = 4) # SEED

# transformation X1 data
# fit_transform > data will be transformated based on X1
pc = pca.fit_transform(X1)

pc_df = pd.DataFrame(data = pc,
                     columns = ['PC1', 'PC2', 'PC3', 'PC4'])

# check result
pc_df['Cluster'] = Y1
pc_df.head()
"""
### **Scree plot(Visualization)**
"""
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

def scree_plot(pca):
    # explained_variance_ratio_: percentage of variance by PC factor
    num_components = len(pca.explained_variance_ratio_)
    ind = np.arange(num_components)
    vals = pca.explained_variance_ratio_
    
    ax = plt.subplot()
    # np.cumsum: calculate the cumulative sum of elements
    cumvals = np.cumsum(vals)
    # bar plot
    ax.bar(ind, vals, color = ['#00da75', '#f1c40f',  '#ff6f15', '#3498db'])
    # line plot
    ax.plot(ind, cumvals, color = '#c0392b')
    
    for i in range(num_components):
        # annotate at screeplot
        ax.annotate(r"%s" % ((str(vals[i]*100)[:3])),
                    (ind[i], vals[i]),
                    va = "bottom",
                    ha = "center",
                    fontsize = 13)
     
    ax.set_xlabel("PC")
    ax.set_ylabel("Variance")
    plt.title('Scree plot')

scree_plot(pca)
"""
## **2. K-Means Clustering**
"""
"""
### **Make sample data**
"""
x, y = make_blobs(n_samples = 100,
                  centers = 3,
                  n_features = 2,
                  random_state = 42)

df = pd.DataFrame(dict(x = x[:, 0],
                       y = x[:, 1],
                       label = y))

points = df.drop('label',
                 axis = 1)
points.head()
"""
### **Assign data**
"""
from sklearn.cluster import KMeans

# class declaration for K-means
kmeans = KMeans(n_clusters = 3, # number of centroid(= cluster)
                random_state = 42) # SEED

# assign data to each cluster
kmeans.fit(x)
labels = kmeans.labels_

# enter new cluster at dataframe
new_series = pd.Series(labels)
df['clusters'] = new_series.values
df.head(15)
"""
### **Calculate centroid**
"""
def get_centroids(df, column_header):
    new_centroids = df.groupby(column_header).mean()
    return new_centroids

# calculate centroid
centroids = get_centroids(df, 'clusters')

# check result
df.groupby('clusters').mean()
"""
### **Result visualization**
"""
def plot_clusters(df, column_header, centroids):
    colors = {0 : 'red', 1 : 'cyan', 2 : 'yellow'}
    fig, ax = plt.subplots()

    # centroid
    ax.plot(centroids.iloc[0].x, centroids.iloc[0].y, "ok") 
    ax.plot(centroids.iloc[1].x, centroids.iloc[1].y, "ok")
    ax.plot(centroids.iloc[2].x, centroids.iloc[2].y, "ok")

    # all data
    grouped = df.groupby(column_header)

    for key, group in grouped:
        group.plot(ax = ax,
                 kind = 'scatter',
                 x = 'x',
                 y = 'y',
                 label = key,
                 color = colors[key])
    plt.show()

plot_clusters(df, 'clusters', centroids)
# elbow methods
sum_of_squared_distances = []
K = range(1, 15)

for k in K:
    km = KMeans(n_clusters = k)
    km = km.fit(points)
    # inertia_: the degree to which the data included in the group is spread
    sum_of_squared_distances.append(km.inertia_)

plt.plot(K, sum_of_squared_distances, 'bx-')
plt.xlabel('k')
plt.ylabel('Sum of squared distances')
plt.title('Elbow Method For Optimal k')
plt.show()