<jupyter_start><jupyter_text>Simple Clustering Examples<jupyter_code>from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline<jupyter_output><empty_output><jupyter_text>**SA Clustering classes**All clustering classes and functions are located in the package `clustering`The module `sa` contains the classes for simulated annealing.  At the moment this splitsthe problem up into a `CoolingSchedule` (the class `CoruCoolingSchedule` is the port from Matlab) and `SACluster`The class `SACluster` has an interface that gives a similar look and feel to `sklearn.KMeans`<jupyter_code>from clustering.sa import SACluster, ExponentialCoolingSchedule, CoruCoolingSchedule
sns.set_style('whitegrid')<jupyter_output><empty_output><jupyter_text>1. Mall Customers Example - toy 2D clustering dataset<jupyter_code>df = pd.read_csv('data/Mall_Customers.csv')
df.head()<jupyter_output><empty_output><jupyter_text>Pre-Process Dataset<jupyter_code>unlabelled_x = df.iloc[:, [3, 4]].values
unlabelled_x.shape<jupyter_output><empty_output><jupyter_text>K-means example<jupyter_code>def elbow_wcss(unlabelled_x, min_clusters=1, max_clusters=10):
    '''
    Graphical approach to estimating the number of 
    cluster to optimise K for the kmeans clustering.
    
    Returns:
    List containing the weighted cluster sum of squares for
    k between min_clusters and max_clusters
    
    Keyword arguments:
    unlabelled_x -- numpy.ndarray of unlabelled data
    min_clusters -- min k (default = 1)
    max_clusters -- max k (default = 10)
    '''
    #weighted sum of squares
    wcss = []

    for k in range(min_clusters, max_clusters+1):
        kmeans = KMeans(n_clusters=k, random_state=0)
        kmeans.fit(unlabelled_x)
        wcss.append(kmeans.inertia_)
        
    return wcss
def plot_elbow(wcss, min_clusters=1):
    plt.plot(range(min_clusters, min_clusters+len(wcss)), wcss, 'bo-')
    plt.xlabel('K')
    plt.ylabel('Weighted Cluster Sum of Squares')
    plt.title('K-means Elbow Plot')
    plt.show()
wcss = elbow_wcss(unlabelled_x)
plot_elbow(wcss)<jupyter_output><empty_output><jupyter_text>Cluster by optimal k<jupyter_code>optimal_k = 5
kmeans = KMeans(n_clusters=optimal_k, random_state=101)
pred = kmeans.fit_predict(unlabelled_x)
df_pred = pd.DataFrame(unlabelled_x, columns=['annual_income', 'spending_score'])
df_pred['cluster'] = pred
df_pred.head()
def plot_clusters(data, kmeans, min_clusters, max_clusters, colours):
    
    plt.figure(figsize=(10,6))
    
    for k in range(max_clusters):
        cluster_data = data.loc[data['cluster'] == k]
        plt.scatter(x='annual_income', y='spending_score', data=cluster_data, 
                    label='Cluster ' + str(k+1), c=colours[k])
        
    plt.scatter(x=kmeans.cluster_centers_[:, 0], y=kmeans.cluster_centers_[:, 1], s=300, 
                c='black', label='Centroids', marker='+')

    
    plt.xlabel('annual income ($k)')
    plt.ylabel('spending score (0-100)')
    #plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
    #       ncol=4, mode='expand', borderaxespad=0.)
    plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
    
    plt.show()
df_pred.values.shape
colours = ['red', 'blue', 'green', 'cyan', 'magenta', 'orange', 'yellow']
plot_clusters(df_pred, kmeans, 1, optimal_k, colours)<jupyter_output><empty_output><jupyter_text>Results from running MatLab code on same data with 5 clustersThe same data was run on the MatLab code.  The solution is very similar.  No objective measure used, but looks **at least** as good as kmeans<jupyter_code>def plot_clusters_mat(data, min_clusters, max_clusters, colours):
    
    plt.figure(figsize=(10,6))
    
    for k in range(max_clusters):
        cluster_data = data.loc[data['cluster'] == k+1]
        plt.scatter(x='annual_income', y='spending_score', data=cluster_data, 
                    label='Cluster ' + str(k+1), c=colours[k])
    
    plt.xlabel('annual income ($k)')
    plt.ylabel('spending score (0-100)')


    plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
    
    plt.show()
arr = np.genfromtxt('data/matlab_output.csv')
df_pred_mat = pd.DataFrame(unlabelled_x, columns=['annual_income', 'spending_score'])
df_pred_mat['cluster'] = arr
plot_clusters_mat(df_pred_mat, 1, optimal_k, colours)<jupyter_output><empty_output><jupyter_text>Simulated Annealing Example* Python port of MatLab code<jupyter_code>n_clusters = 5
max_iter = max(10 * unlabelled_x.shape[0], 10000)
cooling_schedule = CoruCoolingSchedule(1000, max_iter=max_iter)
#cooling_schedule = ExponentialCoolingSchedule(1000)
sa = SACluster(n_clusters=n_clusters, cooling_schedule=cooling_schedule,
               dist_metric='euclidean', max_iter=max_iter, random_state=101)
%%time
state, energy = sa.fit(unlabelled_x)
energy
pd.DataFrame(sa.search_history).tail()
pd.DataFrame(sa.search_history).plot(figsize=(12,6))
df_pred_sa = pd.DataFrame(unlabelled_x, columns=['annual_income', 'spending_score'])
df_pred_sa['cluster'] = state
df_pred_sa.head()
def plot_clusters_sa(data, min_clusters, max_clusters, colours):
    
    plt.figure(figsize=(10,6))
    
    for k in range(max_clusters):
        cluster_data = data.loc[data['cluster'] == k]
        plt.scatter(x='annual_income', y='spending_score', data=cluster_data, 
                    label='Cluster ' + str(k+1), c=colours[k])
        
    #plt.scatter(x=kmeans.cluster_centers_[:, 0], y=kmeans.cluster_centers_[:, 1], s=300, 
    #            c='black', label='Centroids', marker='+')

    
    plt.xlabel('annual income ($k)')
    plt.ylabel('spending score (0-100)')
    #plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
    #       ncol=4, mode='expand', borderaxespad=0.)
    plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
    
    plt.show()
plot_clusters_sa(df_pred_sa, 1, optimal_k, colours)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12848788638262323, 'fraction_numerical': 0.019883040935672516, 'mean_word_length': 4.6525023607176585, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '185609', 'license': 'MIT', 'n_tokens_mistral': 2270, 'n_tokens_neox': 2115, 'n_words': 430, 'path': 'simple_clustering_examples.ipynb', 'repo_name': 'CLAHRCWessex/cluster-sa-py', 'size': '5985'}