{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "72a3787e-bbd1-47a5-a9e5-1e971e70bc84",
   "metadata": {},
   "source": [
    "# Practical-6 (Clustering)\n",
    "\n",
    "---\n",
    "\n",
    "Problem Statement: Implement K-Means clustering/ hierarchical clustering on sales_data_sample.csv dataset. Determine the number of clusters using the elbow method.\n",
    "\n",
    "- Dataset link : https://www.kaggle.com/datasets/kyanyoga/sample-sales-data\n",
    "- Dataset available in [Datasets](https://git.kska.io/sppu-be-comp-content/MachineLearning/src/branch/main/Datasets/) directory.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "9572a287-fea3-4a37-8c7f-b3b3a8c7b438",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# STEPS\n",
    "# ---------------------------------------------------------------\n",
    "\n",
    "# 1. Import libraries\n",
    "# 2. Load dataset\n",
    "# 3. Select numerical features for clustering\n",
    "# 4. Standarize data\n",
    "# 5. K-Means clustering\n",
    "# 6. Hierarcial clustering"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "a7e19837-da2e-4690-a05c-c3991c653295",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 1. IMPORT LIBRARIES\n",
    "# ---------------------------------------------------------------\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.cluster import KMeans\n",
    "from scipy.cluster.hierarchy import linkage, dendrogram, fcluster\n",
    "import seaborn as sns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "922fdb82-53c4-4184-8372-b40c7c9fa7b2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dataset shape: (2823, 25)\n",
      "   ORDERNUMBER  QUANTITYORDERED  PRICEEACH  ORDERLINENUMBER    SALES  \\\n",
      "0        10107               30      95.70                2  2871.00   \n",
      "1        10121               34      81.35                5  2765.90   \n",
      "2        10134               41      94.74                2  3884.34   \n",
      "3        10145               45      83.26                6  3746.70   \n",
      "4        10159               49     100.00               14  5205.27   \n",
      "\n",
      "         ORDERDATE   STATUS  QTR_ID  MONTH_ID  YEAR_ID  ...  \\\n",
      "0   2/24/2003 0:00  Shipped       1         2     2003  ...   \n",
      "1    5/7/2003 0:00  Shipped       2         5     2003  ...   \n",
      "2    7/1/2003 0:00  Shipped       3         7     2003  ...   \n",
      "3   8/25/2003 0:00  Shipped       3         8     2003  ...   \n",
      "4  10/10/2003 0:00  Shipped       4        10     2003  ...   \n",
      "\n",
      "                    ADDRESSLINE1  ADDRESSLINE2           CITY STATE  \\\n",
      "0        897 Long Airport Avenue           NaN            NYC    NY   \n",
      "1             59 rue de l'Abbaye           NaN          Reims   NaN   \n",
      "2  27 rue du Colonel Pierre Avia           NaN          Paris   NaN   \n",
      "3             78934 Hillside Dr.           NaN       Pasadena    CA   \n",
      "4                7734 Strong St.           NaN  San Francisco    CA   \n",
      "\n",
      "  POSTALCODE COUNTRY TERRITORY CONTACTLASTNAME CONTACTFIRSTNAME DEALSIZE  \n",
      "0      10022     USA       NaN              Yu             Kwai    Small  \n",
      "1      51100  France      EMEA         Henriot             Paul    Small  \n",
      "2      75508  France      EMEA        Da Cunha           Daniel   Medium  \n",
      "3      90003     USA       NaN           Young            Julie   Medium  \n",
      "4        NaN     USA       NaN           Brown            Julie   Medium  \n",
      "\n",
      "[5 rows x 25 columns]\n"
     ]
    }
   ],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 2. LOAD DATASET\n",
    "# ---------------------------------------------------------------\n",
    "df = pd.read_csv(\"sales_data_sample.csv\", encoding='latin1', on_bad_lines='skip')\n",
    "print(\"Dataset shape:\", df.shape)\n",
    "print(df.head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "2a8dff33-9608-475c-8a86-9446ceab22db",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Features used for clustering:\n",
      "    ORDERNUMBER  QUANTITYORDERED  PRICEEACH  ORDERLINENUMBER    SALES  QTR_ID  \\\n",
      "0        10107               30      95.70                2  2871.00       1   \n",
      "1        10121               34      81.35                5  2765.90       2   \n",
      "2        10134               41      94.74                2  3884.34       3   \n",
      "3        10145               45      83.26                6  3746.70       3   \n",
      "4        10159               49     100.00               14  5205.27       4   \n",
      "\n",
      "   MONTH_ID  YEAR_ID  MSRP  \n",
      "0         2     2003    95  \n",
      "1         5     2003    95  \n",
      "2         7     2003    95  \n",
      "3         8     2003    95  \n",
      "4        10     2003    95  \n"
     ]
    }
   ],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 3. SELECT NUMERICAL FEATURES FOR CLUSTERING\n",
    "# ---------------------------------------------------------------\n",
    "X = df.select_dtypes(include=['int64', 'float64'])\n",
    "print(\"Features used for clustering:\\n\", X.head())\n",
    "\n",
    "# Select relevant numeric columns\n",
    "# X = df[['SALES', 'QUANTITYORDERED', 'PRICEEACH']]\n",
    "\n",
    "# Handle missing values if any\n",
    "# X = features.dropna()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "0850d1fd-48c7-4db2-84c4-4b66c6c258db",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 4. STANDARDIZE DATA\n",
    "# ---------------------------------------------------------------\n",
    "scaler = StandardScaler()\n",
    "X_scaled = scaler.fit_transform(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "094ea581-9c8f-43e5-8870-61f42f588c48",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.8/site-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
      "  super()._check_params_vs_input(X, default_n_init=10)\n",
      "/usr/local/lib/python3.8/site-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
      "  super()._check_params_vs_input(X, default_n_init=10)\n",
      "/usr/local/lib/python3.8/site-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
      "  super()._check_params_vs_input(X, default_n_init=10)\n",
      "/usr/local/lib/python3.8/site-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
      "  super()._check_params_vs_input(X, default_n_init=10)\n",
      "/usr/local/lib/python3.8/site-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
      "  super()._check_params_vs_input(X, default_n_init=10)\n",
      "/usr/local/lib/python3.8/site-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
      "  super()._check_params_vs_input(X, default_n_init=10)\n",
      "/usr/local/lib/python3.8/site-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
      "  super()._check_params_vs_input(X, default_n_init=10)\n",
      "/usr/local/lib/python3.8/site-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
      "  super()._check_params_vs_input(X, default_n_init=10)\n",
      "/usr/local/lib/python3.8/site-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
      "  super()._check_params_vs_input(X, default_n_init=10)\n",
      "/usr/local/lib/python3.8/site-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
      "  super()._check_params_vs_input(X, default_n_init=10)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 36936 characters]",
      "text/plain": [
       "<Figure size 600x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.8/site-packages/sklearn/cluster/_kmeans.py:1416: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
      "  super()._check_params_vs_input(X, default_n_init=10)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 117984 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "K-Means Cluster Centers:\n",
      " [[ 0.80575256  0.15427129  0.15853912 -0.09904797  0.13718852 -1.15312495\n",
      "  -1.15590439  1.18162177  0.07017959]\n",
      " [-0.26380266  0.03950733  0.70579807  0.01510919  0.53506418  0.50914456\n",
      "   0.50626827 -0.44498338  0.62400764]\n",
      " [-0.30832653 -0.17656987 -1.05002961  0.0605155  -0.80979834  0.26939922\n",
      "   0.2754067  -0.37626384 -0.87164775]]\n",
      "\n",
      "Cluster counts:\n",
      " KMeans_Cluster\n",
      "1    1183\n",
      "2     906\n",
      "0     734\n",
      "Name: count, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 5. K-MEANS CLUSTERING\n",
    "# ---------------------------------------------------------------\n",
    "\n",
    "# Determine optimal number of clusters using Elbow Method\n",
    "wcss = []\n",
    "for k in range(1, 11):\n",
    "    kmeans = KMeans(n_clusters=k, random_state=42)\n",
    "    kmeans.fit(X_scaled)\n",
    "    wcss.append(kmeans.inertia_)\n",
    "\n",
    "# Plot Elbow Method\n",
    "plt.figure(figsize=(6,4))\n",
    "plt.plot(range(1, 11), wcss, marker='o')\n",
    "plt.title('Elbow Method')\n",
    "plt.xlabel('Number of clusters (k)')\n",
    "plt.ylabel('Inertia (WCSS)')\n",
    "plt.show()\n",
    "\n",
    "# Fit KMeans with chosen number of clusters (example: 3 clusters)\n",
    "kmeans = KMeans(n_clusters=3, random_state=42) # Add n_init=10 param in the function to suppress warnings\n",
    "clusters_kmeans = kmeans.fit_predict(X_scaled)\n",
    "df['KMeans_Cluster'] = clusters_kmeans\n",
    "\n",
    "# Visualize clusters\n",
    "sns.scatterplot(x='SALES', y='PRICEEACH', hue='KMeans_Cluster', data=df, palette='viridis')\n",
    "plt.title(\"K-Means Clustering\")\n",
    "plt.show()\n",
    "\n",
    "print(\"\\nK-Means Cluster Centers:\\n\", kmeans.cluster_centers_)\n",
    "print(\"\\nCluster counts:\\n\", df['KMeans_Cluster'].value_counts())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "5f783a85-97de-4ca4-bdba-f03fd805e220",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 49360 characters]",
      "text/plain": [
       "<Figure size 1000x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Hierarchical Cluster counts:\n",
      " 1    1655\n",
      "3     690\n",
      "2     478\n",
      "Name: count, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 6. HIERARCHICAL CLUSTERING\n",
    "# ---------------------------------------------------------------\n",
    "\n",
    "# Create linkage matrix\n",
    "Z = linkage(X_scaled, method='ward')\n",
    "\n",
    "# Plot dendrogram\n",
    "plt.figure(figsize=(10,5))\n",
    "dendrogram(Z)\n",
    "plt.title('Hierarchical Clustering Dendrogram')\n",
    "plt.xlabel('Samples')\n",
    "plt.ylabel('Distance')\n",
    "plt.show()\n",
    "\n",
    "# Assign clusters (example: 3 clusters)\n",
    "clusters_hier = fcluster(Z, t=3, criterion='maxclust')\n",
    "df['Hierarchical_Cluster'] = clusters_hier\n",
    "\n",
    "print(\"\\nHierarchical Cluster counts:\\n\", pd.Series(clusters_hier).value_counts())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "158baf04-1641-4f5e-8f89-64ab01f0388b",
   "metadata": {},
   "source": [
    "---"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.20"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
