{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "20e84154",
   "metadata": {},
   "source": [
    "# Clustering Concepts\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0be36027",
   "metadata": {},
   "source": [
    "```{contents}\n",
    ":local:\n",
    ":depth: 2\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-aeed9197",
   "metadata": {},
   "source": [
    "This section introduces clustering as an unsupervised learning task for finding useful groups in data. A cluster is not automatically a market segment, a customer type, or a strategy. It is a pattern in the data that still needs interpretation."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-6e4d010d",
   "metadata": {},
   "source": [
    "## Clustering as a Management Tool\n",
    "\n",
    "Clustering is useful when an organization has observations but no labels. A retailer may have customer purchase histories without predefined customer types. A human-resources team may have survey responses without known engagement groups. A product team may have usage logs without clear user personas.\n",
    "\n",
    "The clustering workflow turns those unlabeled observations into candidate groups. The analyst then asks whether the groups are stable, interpretable, and useful for a decision."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-a8c9ee22",
   "metadata": {},
   "source": [
    "## Similarity and Features\n",
    "\n",
    "Clustering depends on a definition of **similarity**. Most introductory clustering examples use numeric features and Euclidean distance, where points close together are treated as similar. That means feature choice matters as much as the algorithm.\n",
    "\n",
    "For example, clustering customers by annual spending and number of purchases will emphasize purchasing behavior. Clustering the same customers by age and distance from a store will emphasize demographics and geography. Both can be reasonable, but they answer different questions."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-53bc0747",
   "metadata": {},
   "source": [
    "## Scale and Distance\n",
    "\n",
    "Scale can dominate a clustering result. If one feature is measured in dollars and another is measured as a count from 1 to 10, the dollar feature may control the distance calculation simply because its numbers are larger.\n",
    "\n",
    "A common fix is **standardization**, which puts features on comparable scales before clustering. Standardization does not make a clustering result correct by itself, but it prevents units from silently deciding the groups."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-266653e0",
   "metadata": {},
   "source": [
    "## Common Clustering Methods\n",
    "\n",
    "Different clustering algorithms encode different ideas about what a group should look like.\n",
    "\n",
    "- **K-means** partitions observations into a fixed number of compact clusters.\n",
    "- **Hierarchical clustering** builds nested groups that can be viewed as a tree.\n",
    "- **DBSCAN** finds dense regions and can mark isolated points as noise.\n",
    "\n",
    "This chapter focuses on k-means because it is simple, common, and useful for learning the core workflow."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-55c5062c",
   "metadata": {},
   "source": [
    "## Practical Interpretation\n",
    "\n",
    "A cluster label such as `0`, `1`, or `2` has no built-in meaning. The meaning comes from the observations inside the cluster: their averages, ranges, common traits, and relationship to the management question.\n",
    "\n",
    "Good cluster descriptions use business language, not only algorithm output. For example, \"high-value repeat purchasers\" is more useful than \"cluster 2\" if the group actually shows high spending and frequent purchases."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-ba3210dd",
   "metadata": {},
   "source": [
    "\n",
    "## Section Practice\n",
    "\n",
    "Use this short exercise to check the main workflow from this section.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "cell-97e3f7df",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:02:55.229793Z",
     "iopub.status.busy": "2026-08-31T06:02:55.229579Z",
     "iopub.status.idle": "2026-08-31T06:02:55.234344Z",
     "shell.execute_reply": "2026-08-31T06:02:55.233912Z"
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Practice Clustering Concepts\n",
    "# Customers are described by annual spend (dollars) and store visits per month.\n",
    "# Which customer is most similar to A depends on the scale of the features.\n",
    "#   1. Compute the distance from A to B and from A to C on the raw features.\n",
    "#   2. Divide each feature by its standard deviation (spend_sd, visits_sd) and\n",
    "#      compute the same two distances again.\n",
    "#   3. Print which customer is closer to A each time.\n",
    "# Print exactly:\n",
    "# Raw features: B is closer to A\n",
    "# Scaled features: C is closer to A\n",
    "import numpy as np\n",
    "\n",
    "A = np.array([1000, 2])    # [annual spend, visits per month]\n",
    "B = np.array([1050, 12])\n",
    "C = np.array([1300, 3])\n",
    "spend_sd = 400\n",
    "visits_sd = 4\n",
    "### Your code starts here\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "cell-e29530db",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T06:02:55.236690Z",
     "iopub.status.busy": "2026-08-31T06:02:55.236499Z",
     "iopub.status.idle": "2026-08-31T06:02:55.240463Z",
     "shell.execute_reply": "2026-08-31T06:02:55.240043Z"
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Raw features: B is closer to A\n",
      "Scaled features: C is closer to A\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "import numpy as np\n",
    "\n",
    "A = np.array([1000, 2])    # [annual spend, visits per month]\n",
    "B = np.array([1050, 12])\n",
    "C = np.array([1300, 3])\n",
    "spend_sd = 400\n",
    "visits_sd = 4\n",
    "\n",
    "def distance(p, q):\n",
    "    return np.sqrt(np.sum((p - q) ** 2))\n",
    "\n",
    "def closer_to_A(dist_b, dist_c):\n",
    "    return 'B' if dist_b < dist_c else 'C'\n",
    "\n",
    "sd = np.array([spend_sd, visits_sd])\n",
    "print('Raw features:', closer_to_A(distance(A, B), distance(A, C)), 'is closer to A')\n",
    "print('Scaled features:', closer_to_A(distance(A / sd, B / sd), distance(A / sd, C / sd)), 'is closer to A')\n",
    "# On the raw features, a $50 spend gap outweighs a gap of 10 visits a month.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.13.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
