# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# + [markdown] colab_type="text" id="y-3rVFtGLMJM"
# # K-Means Clustering

# + [markdown] colab_type="text" id="_VS3FFSFLR3a"
# Your assignment is to use the [Breast Cancer Wisconsin (Diagnostic) Data Set from Kaggle](https://www.kaggle.com/uciml/breast-cancer-wisconsin-data) to try and cluster types of cancer cells.
#
# It may be helpful to use PCA to reduce the dimensions of your data first in order to obtain --but then again, maybe not. I dunno, you're the data scientist, you tell me.

# + [markdown] colab_type="text" id="899RK3bBn4OE"
# ## This is a supervised learning dataset
#
# (Because it has **labels** - The "diagnosis" column.)

# + colab={"base_uri": "https://localhost:8080/", "height": 278} colab_type="code" id="ws5R9X6hLJQ2" outputId="078a0dfa-1b57-4a70-b7dd-6747910059c9"
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA # You don't necessarily have to use this
from sklearn.cluster import KMeans # You don't necessarily have to use this
from sklearn.preprocessing import StandardScaler # You don't necessarily have to use this

df_full = pd.read_csv("https://raw.githubusercontent.com/ryanleeallred/datasets/master/Cancer_Cells.csv")
print(df_full.shape)
df_full.head()

# + [markdown] colab_type="text" id="IHDDqaU-ove4"
# ## Now it's an unsupervised learning dataset
#
# (Because we've removed the diagnosis label) - Use this version.

# + colab={"base_uri": "https://localhost:8080/", "height": 261} colab_type="code" id="86MHoPJon_aC" outputId="d4d9f1cd-c63c-4623-954e-11a61d1e3ced"
df_unsup = df_full.drop('diagnosis', axis=1)
df_unsup.head()

# + [markdown] colab_type="text" id="rskC80k3OKMA"
# # You take it from here!
#
# See what you can come up with. You have all the know-how! 
#
# - You might want to do some data exploration to see if you can find specific columns that will help you find distinct clusters of cells
# - You might want to do PCA on this data to see if that helps you find distinct linearly-separable clusters.
#   - (In the real world, truly linearly-separable clusters are rare.)
# - You might want to use an elbow chart to decide on the number of clusters to use.
# - You might want to use a scree plot to decide how many principal components to include in your clustering.
# - You might want to standardize your data before PCA (If you decide to use PCA). 
#
# ## Manage your time and don't spend it all on data exploration or something like that. You got this!
# -

df_unsup.isna().sum() / len(df_unsup)

df_unsup.dtypes

df_unsup = df_unsup.drop(columns=['id', 'Unnamed: 32'])

# rule of thumb, you should have 5 times as many observations as dimensions
len(df_unsup) / len(df_unsup.columns)

# standardize our data
df_norm = StandardScaler().fit_transform(df_unsup, copy=True)

# +
pca = PCA(len(df_unsup.columns))
pca.fit(df_norm)

print("\nExplianed Variance: \n", pca.explained_variance_)

# +
import matplotlib.pyplot as plt

plt.plot(pca.explained_variance_ratio_);
# -

# Cummulative version
np.cumsum(pca.explained_variance_ratio_)

plt.plot(np.cumsum(pca.explained_variance_ratio_));

# Keeping the first 5 gives us ~80% of variance
pca = PCA(5)
pca.fit(df_norm)
df_pca_trans = pca.transform(df_norm)

sum_of_squared_distances = []
K = range(1,15)
for k in K:
    km = KMeans(n_clusters=k)
    km = km.fit(df_pca_trans)
    sum_of_squared_distances.append(km.inertia_)

plt.scatter(list(range(1,15)), sum_of_squared_distances);

# + colab={} colab_type="code" id="dW1AeAK8PNah"
kmeans = KMeans(n_clusters=2)
kmeans.fit(df_pca_trans)
labels = kmeans.labels_
# -

labels

# + [markdown] colab_type="text" id="wKBwVaGOOYsq"
# # Stretch Goal:
#
# Once you are satisfied with your clustering, go back and add back in the labels from the original dataset to check how accurate your clustering was. Remember that this will not be a possibility in true unsupervised learning, but it might be a helpful for your learning to be able to check your work against the "ground truth". Try different approaches and see which one is the most successful and try understand why that might be the case. If you go back and try different methods don't ever include the actual "diagnosis" labels in your clustering or PCA.
#
# **Side Note** Data Science is never DONE. You just reach a point where the cost isn't worth the benefit anymore. There's always more moderate to small improvements that we could make. Don't be a perfectionist, be a pragmatist.

# +
df_full = pd.read_csv("https://raw.githubusercontent.com/ryanleeallred/datasets/master/Cancer_Cells.csv")

df_full = df_full.join(pd.Series(labels, name='pred_clust'))
# -

df_full['diagnosis'].unique()

mapping = dict(zip(df_full['diagnosis'].unique(), [0,1]))
df_full['diagnosis'] = df_full['diagnosis'].map(mapping)

(len(df_full.loc[df_full.diagnosis==df_full.pred_clust]) / 
 len(df_full)) * 100

# +
# 91%, not bad!

StarcoderdataJupyterScriptsDedupFiltered