{"id":278514,"date":"2026-10-14T19:38:51","date_gmt":"2026-10-14T14:08:51","guid":{"rendered":"https:\/\/imarticus.org\/blog\/?p=278514"},"modified":"2026-10-15T12:32:48","modified_gmt":"2026-10-15T07:02:48","slug":"cluster-analysis","status":"publish","type":"post","link":"https:\/\/imarticus.org\/blog\/cluster-analysis\/","title":{"rendered":"A Guide To Cluster Analysis: Meaning, Types, And Examples"},"content":{"rendered":"\n<style>\n  .wrap {\n    margin: 24px 0;\n    width: 100%;\n    box-sizing: border-box;\n  }\n  .card {\n    box-sizing: border-box;\n    width: 100%;\n    max-width: 720px;\n    margin: 0 auto;\n    background: #eaf6ec;\n    border: 1.5px solid #b0dabb;\n    border-radius: clamp(16px, 3vw, 26px);\n    padding: clamp(22px, 4.5vw, 44px);\n    text-align: center;\n    font-family: 'Manrope', Arial, Helvetica, sans-serif;\n  }\n  .card * {\n    box-sizing: border-box;\n  }\n  .badge {\n    display: block;\n    text-align: left;\n    margin: 0 0 10px 0;\n    color: #2f7a4d;\n    font-weight: 800;\n    font-size: 15px;\n    letter-spacing: 0.04em;\n    text-transform: uppercase;\n  }\n  .card p {\n    font-size: clamp(14.5px, 1.8vw, 16.5px);\n    line-height: 1.7;\n    color: #2c3e33;\n    margin: 0;\n    text-align: left;\n    overflow-wrap: break-word; \/* Prevents long text from pushing width *\/\n  }\n  .card strong {\n    color: #1f3d2a;\n    font-weight: 700;\n  }\n<\/style>\n\n<div class=\"wrap\">\n  <div class=\"card\">\n    <div class=\"badge\">Summary<\/div>\n    <p>\n    Cluster analysis is an unsupervised machine learning technique that groups data points based on shared characteristics, without predefined labels. It helps identify patterns in customer behaviour, research data and large datasets. The main types include partitioning methods such as K-means, hierarchical clustering and density-based clustering. \n<br><br> Your choice of method matters. K-means can be a practical starting point when you know how many groups you want to test. Hierarchical clustering can help you examine relationships at different levels, while density-based methods can identify irregularly shaped groups and separate some outliers. The right approach depends on your data, your objective and how you intend to use the results.\n\n    \n    <\/p>\n  <\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Cluster analysis groups data points so that records in the same group are more alike than records in different groups, without using any labels. The main types are partitioning methods such as k-means, hierarchical methods, and density-based methods such as DBSCAN.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Every result rests on four decisions: which variables go in and how they are scaled, how &#8220;alike&#8221; is measured, which algorithm gathers the groups, and how many groups you ask for. Check the number of clusters with more than one signal, such as the elbow plot and the silhouette score, then ask whether you can name each group.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I ran the same k-means on the same 400 customers twice. Same data. Same number of clusters. The first run gave me groups of 184, 97 and 119 customers. The second gave me 65, 281 and 54. Neither run was a bug. The only difference was one line of code that put every column on the same scale. I will show you exactly what happened further down, because it explains most of what goes wrong in cluster analysis. If you want guided practice on real datasets, Imarticus Learning&#8217;s <a href=\"https:\/\/imarticus.org\/postgraduate-program-in-data-science-analytics\/\"><strong>data analytics course<\/strong><\/a> is a sensible place to build the Python and statistics base.&nbsp; &nbsp;<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>See How Different Cluster Analysis Methods Work<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The same dataset can produce very different groupings depending on the clustering method you choose. K-means looks for central points, DBSCAN identifies dense regions, and hierarchical clustering builds a tree of relationships. Use the interactive demo below to change the settings, compare the results, and see how each method approaches the same task.<\/p>\n\n\n\n<!-- Cluster Analysis Lab: WordPress-safe embed -->\n<style>\n#cluster-analysis-lab {\n  --ink:#17233b;--muted:#5c6880;--line:#dbe2ee;--paper:#f5f7fb;\n  --card:#fff;--blue:#2864dc;--teal:#0c9488;--orange:#e28a2b;\n  --purple:#8256c7;--pink:#d65387;--green:#4c9a58;--red:#d95757;\n  box-sizing:border-box;\n  margin:20px 0;\n  background:var(--paper);\n  color:var(--ink);\n  font:16px\/1.5 Inter,system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;\n}\n#cluster-analysis-lab *,\n#cluster-analysis-lab *::before,\n#cluster-analysis-lab *::after {box-sizing:border-box}\n#cluster-analysis-lab main {max-width:1240px;margin:0 auto;padding:28px 18px 40px}\n#cluster-analysis-lab h1 {font-size:clamp(2rem,4vw,3.2rem);line-height:1.08;letter-spacing:-.04em;margin:8px 0 12px}\n#cluster-analysis-lab h2 {font-size:1.15rem;line-height:1.35;margin:0 0 7px}\n#cluster-analysis-lab h3 {font-size:.95rem;line-height:1.4;margin:0 0 6px}\n#cluster-analysis-lab p {margin:6px 0 12px}\n#cluster-analysis-lab button,\n#cluster-analysis-lab input,\n#cluster-analysis-lab select,\n#cluster-analysis-lab textarea {font:inherit;max-width:100%}\n#cluster-analysis-lab button {cursor:pointer}\n#cluster-analysis-lab .eyebrow {font-size:.75rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--blue)}\n#cluster-analysis-lab .intro {max-width:790px;color:var(--muted);font-size:1.02rem}\n#cluster-analysis-lab .notice {border:1px solid #cbd9f8;background:#edf3ff;padding:12px 15px;border-radius:12px;margin:18px 0;color:#263d68}\n#cluster-analysis-lab .tabs {display:flex;gap:8px;flex-wrap:wrap;margin:20px 0 14px}\n#cluster-analysis-lab .tab {border:1px solid var(--line);border-radius:999px;padding:9px 13px;background:#fff;color:var(--ink);font-size:.88rem;font-weight:750}\n#cluster-analysis-lab .tab[aria-selected=\"true\"] {background:var(--ink);color:#fff;border-color:var(--ink)}\n#cluster-analysis-lab .layout {display:grid;grid-template-columns:minmax(0,1.5fr) minmax(260px,.8fr);gap:16px;align-items:start}\n#cluster-analysis-lab .panel {min-width:0;background:var(--card);border:1px solid var(--line);border-radius:16px;box-shadow:0 5px 20px #1b31500a;overflow:hidden}\n#cluster-analysis-lab .panelhead {padding:18px 20px 12px;border-bottom:1px solid var(--line)}\n#cluster-analysis-lab .panelbody {padding:18px 20px}\n#cluster-analysis-lab .subtle {color:var(--muted);font-size:.92rem}\n#cluster-analysis-lab .method-kicker {font-size:.78rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--blue)}\n#cluster-analysis-lab .visualwrap {padding:12px;background:#fff;overflow:hidden}\n#cluster-analysis-lab svg {display:block;width:100%;height:auto;min-height:0;max-width:100%}\n#cluster-analysis-lab .legend {display:flex;gap:12px;flex-wrap:wrap;padding:8px 20px 16px;color:var(--muted);font-size:.82rem}\n#cluster-analysis-lab .legend span {display:inline-flex;align-items:center;gap:6px}\n#cluster-analysis-lab .dot {width:10px;height:10px;border-radius:50%;display:inline-block;flex-shrink:0}\n#cluster-analysis-lab .controls {display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:12px 0}\n#cluster-analysis-lab .control {min-width:0;background:#f7f9fd;border:1px solid #e6ebf4;padding:10px;border-radius:10px}\n#cluster-analysis-lab .control label {display:flex;justify-content:space-between;gap:8px;font-size:.82rem;font-weight:750;margin-bottom:6px}\n#cluster-analysis-lab .control input[type=\"range\"] {width:100%;accent-color:var(--blue)}\n#cluster-analysis-lab .control select {width:100%;border:1px solid #ccd5e4;border-radius:8px;padding:8px;background:#fff;color:var(--ink)}\n#cluster-analysis-lab .actions {display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}\n#cluster-analysis-lab .btn {border:1px solid var(--line);background:#fff;border-radius:9px;padding:9px 12px;font-size:.88rem;font-weight:750;color:var(--ink)}\n#cluster-analysis-lab .btn.primary {background:var(--blue);color:#fff;border-color:var(--blue)}\n#cluster-analysis-lab .btn:hover,\n#cluster-analysis-lab .tab:hover {filter:brightness(.97)}\n#cluster-analysis-lab button:focus-visible,\n#cluster-analysis-lab input:focus-visible,\n#cluster-analysis-lab select:focus-visible,\n#cluster-analysis-lab textarea:focus-visible {outline:3px solid #8db3ff;outline-offset:2px}\n#cluster-analysis-lab .metrics {display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:14px 0}\n#cluster-analysis-lab .metric {min-width:0;padding:10px;border:1px solid var(--line);border-radius:10px}\n#cluster-analysis-lab .metric strong {display:block;font-size:1.2rem;overflow-wrap:anywhere}\n#cluster-analysis-lab .metric span {display:block;color:var(--muted);font-size:.75rem}\n#cluster-analysis-lab .lesson {background:#f8faff;border:1px solid #e2e9f6;border-radius:11px;padding:13px;margin:12px 0}\n#cluster-analysis-lab .lesson p {font-size:.9rem;color:#43516a;margin:0}\n#cluster-analysis-lab .steps {padding-left:20px;margin:8px 0}\n#cluster-analysis-lab .steps li {padding:3px 0;color:#43516a;font-size:.9rem}\n#cluster-analysis-lab .dataset {margin-top:16px}\n#cluster-analysis-lab .dataset summary {font-weight:800;cursor:pointer}\n#cluster-analysis-lab .dataset textarea {display:block;width:100%;min-height:100px;border:1px solid #ccd5e4;border-radius:9px;padding:10px;font:13px\/1.5 ui-monospace,Consolas,monospace}\n#cluster-analysis-lab .footnote {font-size:.81rem;color:var(--muted);margin-top:10px}\n#cluster-analysis-lab .cta {margin-top:22px;padding:22px;border-radius:14px;background:#17233b;color:#fff;display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap}\n#cluster-analysis-lab .cta p {color:#d4dced;max-width:700px}\n#cluster-analysis-lab .cta a {display:inline-block;color:#17233b;background:#fff;padding:11px 15px;border-radius:9px;text-decoration:none;font-weight:800}\n@media(max-width:850px) {\n  #cluster-analysis-lab .layout {grid-template-columns:minmax(0,1fr)}\n}\n@media(max-width:520px) {\n  #cluster-analysis-lab main {padding:20px 10px}\n  #cluster-analysis-lab .panelhead,\n  #cluster-analysis-lab .panelbody {padding:14px}\n  #cluster-analysis-lab .controls {grid-template-columns:minmax(0,1fr)}\n  #cluster-analysis-lab .tab {font-size:.8rem;padding:8px 10px}\n  #cluster-analysis-lab .legend {padding:8px 12px 14px}\n  #cluster-analysis-lab .metric {padding:8px 6px}\n  #cluster-analysis-lab .metric strong {font-size:1rem}\n}\n@media(prefers-reduced-motion:no-preference) {\n  #cluster-analysis-lab .point {animation:ca-appear .3s both;animation-delay:calc(var(--i,0)*6ms)}\n  #cluster-analysis-lab .cluster-shape {animation:ca-fade .35s both}\n}\n@keyframes ca-appear {from{opacity:0;transform:scale(.5)}to{opacity:1;transform:scale(1)}}\n@keyframes ca-fade {from{opacity:0}to{opacity:1}}\n<\/style>\n\n<div id=\"cluster-analysis-lab\">\n  <main>\n    <div class=\"eyebrow\">Interactive learning lab<\/div>\n    <h1>Cluster Analysis, You Can Actually See<\/h1>\n    <p class=\"intro\">Seven methods can group the same data for very different reasons. Switch methods, change the settings, and see what each one treats as a cluster.<\/p>\n    <div class=\"notice\"><strong>How to use this lab:<\/strong> Choose a method, change its settings, then press <em>Run method<\/em>. Each view highlights a different principle.<\/div>\n\n    <div class=\"tabs\" role=\"tablist\" aria-label=\"Clustering methods\">\n      <button type=\"button\" class=\"tab\" role=\"tab\" aria-selected=\"true\" data-method=\"kmeans\">1. K-means<\/button>\n      <button type=\"button\" class=\"tab\" role=\"tab\" aria-selected=\"false\" data-method=\"kmedoids\">2. K-medoids<\/button>\n      <button type=\"button\" class=\"tab\" role=\"tab\" aria-selected=\"false\" data-method=\"hierarchical\">3. Hierarchical<\/button>\n      <button type=\"button\" class=\"tab\" role=\"tab\" aria-selected=\"false\" data-method=\"dbscan\">4. DBSCAN<\/button>\n      <button type=\"button\" class=\"tab\" role=\"tab\" aria-selected=\"false\" data-method=\"grid\">5. Grid-based<\/button>\n      <button type=\"button\" class=\"tab\" role=\"tab\" aria-selected=\"false\" data-method=\"model\">6. Model-based<\/button>\n      <button type=\"button\" class=\"tab\" role=\"tab\" aria-selected=\"false\" data-method=\"fuzzy\">7. Fuzzy C-means<\/button>\n    <\/div>\n\n    <div class=\"layout\">\n      <section class=\"panel\">\n        <div class=\"panelhead\">\n          <div class=\"method-kicker\" data-el=\"kicker\">Centroid-based partitioning<\/div>\n          <h2 data-el=\"title\">K-means: move the centres<\/h2>\n          <p class=\"subtle\" data-el=\"subtitle\">Each point is assigned to its nearest mean centre.<\/p>\n        <\/div>\n        <div class=\"visualwrap\">\n          <svg data-el=\"viz\" viewBox=\"0 0 700 420\" role=\"img\" aria-label=\"Interactive clustering chart\"><\/svg>\n        <\/div>\n        <div class=\"legend\" data-el=\"legend\"><\/div>\n        <div class=\"panelbody\">\n          <div class=\"metrics\" data-el=\"metrics\"><\/div>\n          <div class=\"lesson\">\n            <h3 data-el=\"insight-title\">What to notice<\/h3>\n            <p data-el=\"insight\"><\/p>\n          <\/div>\n          <details class=\"dataset\">\n            <summary>Use your own points<\/summary>\n            <p class=\"subtle\">Enter one point per line as x,y. Keep both values between 0 and 100.<\/p>\n            <textarea data-el=\"points-input\" aria-label=\"Point data\"><\/textarea>\n            <div class=\"actions\">\n              <button type=\"button\" class=\"btn\" data-action=\"apply-data\">Apply points<\/button>\n              <button type=\"button\" class=\"btn\" data-action=\"restore-data\">Restore sample<\/button>\n            <\/div>\n            <p class=\"footnote\" data-el=\"data-message\" aria-live=\"polite\"><\/p>\n          <\/details>\n        <\/div>\n      <\/section>\n\n      <aside class=\"panel\">\n        <div class=\"panelhead\">\n          <h2>Try the settings<\/h2>\n          <p class=\"subtle\" data-el=\"controls-intro\">Change a parameter to see what it changes.<\/p>\n        <\/div>\n        <div class=\"panelbody\">\n          <div class=\"controls\" data-el=\"controls\"><\/div>\n          <div class=\"actions\">\n            <button type=\"button\" class=\"btn primary\" data-action=\"run\">Run method<\/button>\n            <button type=\"button\" class=\"btn\" data-action=\"animate\">Show steps<\/button>\n            <button type=\"button\" class=\"btn\" data-action=\"reset\">Reset method<\/button>\n          <\/div>\n          <div class=\"lesson\">\n            <h3>How this method thinks<\/h3>\n            <p data-el=\"explainer\"><\/p>\n          <\/div>\n          <h3>What happened<\/h3>\n          <ol class=\"steps\" data-el=\"steps\"><\/ol>\n          <p class=\"footnote\" data-el=\"caveat\"><\/p>\n        <\/div>\n      <\/aside>\n    <\/div>\n\n    <section class=\"cta\">\n      <div>\n        <h2>Practise clustering with real datasets<\/h2>\n        <p>Move from these small examples to customer segmentation, machine learning projects and practical data science work.<\/p>\n      <\/div>\n      <a href=\"https:\/\/imarticus.org\/postgraduate-program-in-data-science-analytics\/\" target=\"_blank\" rel=\"noopener noreferrer\">View the programme<\/a>\n    <\/section>\n  <\/main>\n<\/div>\n\n<script>\n(function () {\n  'use strict';\n\n  const root = document.getElementById('cluster-analysis-lab');\n  if (!root || root.dataset.initialised === 'true') return;\n  root.dataset.initialised = 'true';\n\n  const $ = selector => root.querySelector(selector);\n  const all = selector => Array.from(root.querySelectorAll(selector));\n  const el = name => root.querySelector('[data-el=\"' + name + '\"]');\n\n  const palette = ['#2864dc','#0c9488','#e28a2b','#8256c7','#d65387','#4c9a58','#d95757','#53758f'];\n  const sample = [\n    [15,19],[18,24],[21,17],[24,22],[17,29],[28,27],[30,19],\n    [66,18],[71,22],[75,16],[78,25],[68,30],[82,20],[74,31],\n    [39,69],[44,75],[49,67],[52,76],[43,82],[57,70],[36,78],[91,88]\n  ];\n\n  const state = {\n    k:3, iterations:8, linkage:'average', cut:55,\n    eps:15, minPts:3, cell:12, components:3, fuzz:2\n  };\n\n  let points = sample.map(p => p.slice());\n  let method = 'kmeans';\n  let result = null;\n  let timer = null;\n\n  const descriptions = {\n    kmeans: {\n      kicker:'Centroid-based partitioning',\n      title:'K-means: move the centres',\n      subtitle:'Points belong to the nearest mean centre. The centres move as groups are recalculated.',\n      explainer:'K-means assigns each point to its nearest centre, then moves each centre to the average position of its assigned points. It works best with compact groups of a similar scale.',\n      insightTitle:'Watch the centre, not just the colour',\n      insight:'Cross-shaped markers show averages. A mean centre can sit between observations rather than on a real data point. Change k to change the number of groups.',\n      caveat:'Teaching implementation: results can vary with starting centres.'\n    },\n    kmedoids: {\n      kicker:'Representative-point partitioning',\n      title:'K-medoids: choose a real point',\n      subtitle:'Each thick ring marks a real observation selected to represent a group.',\n      explainer:'K-medoids chooses actual observations as representatives. Other points are assigned to the nearest representative. Unlike a mean, a medoid cannot be pulled into empty space by an extreme observation.',\n      insightTitle:'The representative is a real observation',\n      insight:'Compare the thick rings with the crosses in K-means. Medoids must sit on actual data points. This can make the method more robust to outliers.',\n      caveat:'Teaching implementation using representative-point swaps. K-medoids can be slower on large datasets.'\n    },\n    hierarchical: {\n      kicker:'Nested grouping',\n      title:'Hierarchical: merge into a tree',\n      subtitle:'The dendrogram records which groups merge and the distance at which they join.',\n      explainer:'Agglomerative hierarchical clustering starts with one group per point and repeatedly merges the closest groups. A cut through the dendrogram determines which groups remain separate.',\n      insightTitle:'Merge height carries meaning',\n      insight:'A high merge joins groups that are farther apart. Move the cut line to change the grouping. Linkage controls how distance between groups is measured.',\n      caveat:'Teaching implementation of agglomerative clustering. Large dendrograms can become difficult to read.'\n    },\n    dbscan: {\n      kicker:'Density-based discovery',\n      title:'DBSCAN: find dense neighbourhoods',\n      subtitle:'Dense regions become clusters. Isolated observations can remain noise.',\n      explainer:'DBSCAN counts neighbours within a radius called epsilon. Core points have enough neighbours to form dense regions. Reachable points join those regions, while some points remain noise.',\n      insightTitle:'Noise is a valid result',\n      insight:'Red crosses indicate noise. Increase the radius to connect more points. Raise the minimum-neighbour setting to require denser regions.',\n      caveat:'Teaching implementation using Euclidean distance. A single radius can struggle with groups of very different densities.'\n    },\n    grid: {\n      kicker:'Space divided into cells',\n      title:'Grid-based: count occupied cells',\n      subtitle:'The plane is divided into squares. Each occupied square shows its observation count.',\n      explainer:'Grid-based methods divide the data space into cells and summarise the observations inside each cell. Some algorithms then link dense neighbouring cells to identify regions.',\n      insightTitle:'Cell size changes the picture',\n      insight:'Small cells preserve detail. Larger cells combine nearby observations. This view shows cell occupancy, which is the first step rather than a complete grid-clustering algorithm.',\n      caveat:'Teaching illustration of grid occupancy, not a full production grid-based algorithm.'\n    },\n    model: {\n      kicker:'Probability distributions',\n      title:'Model-based: fit probability clouds',\n      subtitle:'Ellipses show the estimated spread of Gaussian components.',\n      explainer:'Model-based clustering assumes observations come from a mixture of probability distributions. Each component has a centre and spread. Real Gaussian mixture models estimate these values and calculate component membership.',\n      insightTitle:'Clusters can have different shapes',\n      insight:'Ellipses make the estimated spread visible. Overlapping components suggest that membership may be uncertain. The demonstration uses simplified Gaussian components.',\n      caveat:'Teaching illustration using cluster centres and diagonal spread estimates, not a full Gaussian-mixture optimisation.'\n    },\n    fuzzy: {\n      kicker:'Soft membership',\n      title:'Fuzzy C-means: belong by degree',\n      subtitle:'A point can partly belong to more than one cluster.',\n      explainer:'Fuzzy C-means assigns each point a membership score for every centre. Membership scores sum to 100%, so a point between groups can partly belong to both.',\n      insightTitle:'Not every point must choose one side',\n      insight:'The dominant colour shows the strongest membership. Mixed outlines and percentage labels indicate points with less clear membership.',\n      caveat:'Teaching implementation of iterative fuzzy membership. Membership values are degrees of membership, not probabilities.'\n    }\n  };\n\n  function distance(a,b) {\n    return Math.hypot(a[0]-b[0],a[1]-b[1]);\n  }\n\n  function average(group) {\n    return [\n      group.reduce((sum,p)=>sum+p[0],0)\/group.length,\n      group.reduce((sum,p)=>sum+p[1],0)\/group.length\n    ];\n  }\n\n  function nearest(point,centres) {\n    let best=0, bestDistance=Infinity;\n    centres.forEach((centre,index)=>{\n      const d=distance(point,centre);\n      if(d<bestDistance){bestDistance=d;best=index;}\n    });\n    return best;\n  }\n\n  function initialCentres(k) {\n    const sorted=points.slice().sort((a,b)=>a[0]-b[0]);\n    return Array.from({length:k},(_,i)=>{\n      const index=Math.min(sorted.length-1,Math.floor((i+.5)*sorted.length\/k));\n      return sorted[index].slice();\n    });\n  }\n\n  function runKmeans(k,limit) {\n    let centres=initialCentres(k), labels=[];\n    for(let iteration=0;iteration<limit;iteration++) {\n      labels=points.map(p=>nearest(p,centres));\n      const next=centres.map((centre,j)=>{\n        const group=points.filter((p,i)=>labels[i]===j);\n        return group.length?average(group):centre.slice();\n      });\n      const settled=next.every((c,j)=>distance(c,centres[j])<.01);\n      centres=next;\n      if(settled)break;\n    }\n    labels=points.map(p=>nearest(p,centres));\n    return {centres,labels,groups:centres.map((_,j)=>points.filter((p,i)=>labels[i]===j))};\n  }\n\n  function runKmedoids(k) {\n    let centres=initialCentres(k).map(c=>\n      points.reduce((best,p)=>distance(p,c)<distance(best,c)?p:best,points[0]).slice()\n    );\n    centres=centres.filter((c,i)=>centres.findIndex(other=>distance(c,other)<.001)===i);\n\n    while(centres.length<k) {\n      const candidate=points.reduce((best,p)=>{\n        const pDistance=Math.min(...centres.map(c=>distance(p,c)));\n        const bestDistance=Math.min(...centres.map(c=>distance(best,c)));\n        return pDistance>bestDistance?p:best;\n      },points[0]);\n      centres.push(candidate.slice());\n    }\n\n    let labels=points.map(p=>nearest(p,centres));\n    let changed=true, rounds=0;\n    while(changed&&rounds++<15) {\n      changed=false;\n      for(let j=0;j<centres.length;j++) {\n        const group=points.filter((p,i)=>labels[i]===j);\n        if(!group.length)continue;\n        let best=centres[j], bestCost=group.reduce((s,p)=>s+distance(p,best),0);\n        group.forEach(candidate=>{\n          const cost=group.reduce((s,p)=>s+distance(p,candidate),0);\n          if(cost<bestCost){best=candidate;bestCost=cost;}\n        });\n        if(distance(best,centres[j])>.001){centres[j]=best.slice();changed=true;}\n      }\n      labels=points.map(p=>nearest(p,centres));\n    }\n    return {centres,labels,groups:centres.map((_,j)=>points.filter((p,i)=>labels[i]===j))};\n  }\n\n  function runHierarchical() {\n    let clusters=points.map((p,i)=>({ids:[i]})), merges=[];\n    function linkDistance(a,b) {\n      const distances=[];\n      a.ids.forEach(i=>b.ids.forEach(j=>distances.push(distance(points[i],points[j]))));\n      if(state.linkage==='single')return Math.min(...distances);\n      if(state.linkage==='complete')return Math.max(...distances);\n      return distances.reduce((sum,d)=>sum+d,0)\/distances.length;\n    }\n\n    while(clusters.length>1) {\n      let ai=0,bi=1,bestDistance=Infinity;\n      for(let i=0;i<clusters.length;i++) {\n        for(let j=i+1;j<clusters.length;j++) {\n          const d=linkDistance(clusters[i],clusters[j]);\n          if(d<bestDistance){bestDistance=d;ai=i;bi=j;}\n        }\n      }\n      const a=clusters[ai],b=clusters[bi];\n      const ids=a.ids.concat(b.ids);\n      merges.push({a:a.ids.slice(),b:b.ids.slice(),ids:ids.slice(),height:bestDistance});\n      clusters=clusters.filter((_,i)=>i!==ai&&i!==bi);\n      clusters.push({ids});\n    }\n\n    const maxHeight=Math.max(1,...merges.map(m=>m.height));\n    let groups=points.map((_,i)=>[i]);\n    merges.forEach(merge=>{\n      if(merge.height>state.cut)return;\n      const a=groups.find(g=>g.includes(merge.a[0]));\n      const b=groups.find(g=>g.includes(merge.b[0]));\n      if(a&&b&&a!==b) {\n        const joined=[...new Set([...a,...b])];\n        groups=groups.filter(g=>g!==a&&g!==b);\n        groups.push(joined);\n      }\n    });\n\n    const labels=points.map((_,i)=>Math.max(0,groups.findIndex(g=>g.includes(i))));\n    return {merges,maxHeight,groups:groups.map(g=>g.map(i=>points[i])),labels};\n  }\n\n  function runDBSCAN() {\n    const neighbours=points.map(p=>\n      points.map((q,j)=>distance(p,q)<=state.eps?j:-1).filter(j=>j>=0)\n    );\n    const labels=Array(points.length).fill(-2);\n    let clusterId=0;\n\n    for(let i=0;i<points.length;i++) {\n      if(labels[i]!==-2)continue;\n      if(neighbours[i].length<state.minPts){labels[i]=-1;continue;}\n      labels[i]=clusterId;\n      const queue=neighbours[i].slice(), queued=new Set(queue);\n\n      for(let q=0;q<queue.length;q++) {\n        const j=queue[q];\n        if(labels[j]===-1)labels[j]=clusterId;\n        if(labels[j]!==-2)continue;\n        labels[j]=clusterId;\n        if(neighbours[j].length>=state.minPts) {\n          neighbours[j].forEach(n=>{\n            if(!queued.has(n)){queued.add(n);queue.push(n);}\n          });\n        }\n      }\n      clusterId++;\n    }\n\n    return {\n      labels,neighbours,\n      noise:labels.filter(x=>x===-1).length,\n      groups:Array.from({length:clusterId},(_,j)=>points.filter((p,i)=>labels[i]===j))\n    };\n  }\n\n  function runGrid() {\n    const cells={};\n    points.forEach((p,i)=>{\n      const x=Math.floor(p[0]\/state.cell),y=Math.floor(p[1]\/state.cell);\n      const key=x+','+y;\n      if(!cells[key])cells[key]=[];\n      cells[key].push(i);\n    });\n    return {cells};\n  }\n\n  function runModel(k) {\n    const base=runKmeans(k,15),centres=base.centres,labels=base.labels;\n    const variances=centres.map((c,j)=>{\n      const group=points.filter((p,i)=>labels[i]===j);\n      return [\n        Math.max(20,group.reduce((s,p)=>s+(p[0]-c[0])**2,0)\/(group.length||1)),\n        Math.max(20,group.reduce((s,p)=>s+(p[1]-c[1])**2,0)\/(group.length||1))\n      ];\n    });\n    return {centres,labels,variances,groups:base.groups};\n  }\n\n  function runFuzzy(k,m) {\n    let centres=initialCentres(k);\n    function membershipsFor(point) {\n      const raw=centres.map(c=>1\/Math.pow(distance(point,c)+.01,2\/(m-1)));\n      const total=raw.reduce((a,b)=>a+b,0);\n      return raw.map(v=>v\/total);\n    }\n    let memberships=points.map(membershipsFor);\n\n    for(let iteration=0;iteration<25;iteration++) {\n      centres=centres.map((_,j)=>{\n        const denominator=points.reduce((s,p,i)=>s+Math.pow(memberships[i][j],m),0)||1;\n        return [0,1].map(axis=>\n          points.reduce((s,p,i)=>s+Math.pow(memberships[i][j],m)*p[axis],0)\/denominator\n        );\n      });\n      memberships=points.map(membershipsFor);\n    }\n\n    const labels=memberships.map(row=>row.indexOf(Math.max(...row)));\n    return {centres,memberships,labels,groups:centres.map((_,j)=>points.filter((p,i)=>labels[i]===j))};\n  }\n\n  function calculate() {\n    if(method==='kmeans')return runKmeans(state.k,state.iterations);\n    if(method==='kmedoids')return runKmedoids(state.k);\n    if(method==='hierarchical')return runHierarchical();\n    if(method==='dbscan')return runDBSCAN();\n    if(method==='grid')return runGrid();\n    if(method==='model')return runModel(state.components);\n    return runFuzzy(state.k,state.fuzz);\n  }\n\n  function sx(x){return 50+x*5.95;}\n  function sy(y){return 370-y*3.35;}\n\n  function axes() {\n    let s='';\n    for(let x=0;x<=100;x+=20) {\n      s+=`<line x1=\"${sx(x)}\" y1=\"35\" x2=\"${sx(x)}\" y2=\"370\" stroke=\"#e7ebf3\"\/>`;\n      s+=`<text x=\"${sx(x)}\" y=\"393\" text-anchor=\"middle\" font-size=\"11\" fill=\"#7b879c\">${x}<\/text>`;\n    }\n    for(let y=0;y<=100;y+=20) {\n      s+=`<line x1=\"50\" y1=\"${sy(y)}\" x2=\"645\" y2=\"${sy(y)}\" stroke=\"#e7ebf3\"\/>`;\n      s+=`<text x=\"37\" y=\"${sy(y)+4}\" text-anchor=\"end\" font-size=\"11\" fill=\"#7b879c\">${y}<\/text>`;\n    }\n    return s+\n      `<rect x=\"50\" y=\"35\" width=\"595\" height=\"335\" fill=\"none\" stroke=\"#cfd7e5\"\/>`+\n      `<text x=\"347\" y=\"414\" text-anchor=\"middle\" font-size=\"11\" fill=\"#7b879c\">Feature X<\/text>`+\n      `<text x=\"12\" y=\"202\" text-anchor=\"middle\" font-size=\"11\" fill=\"#7b879c\" transform=\"rotate(-90 12 202)\">Feature Y<\/text>`;\n  }\n\n  function circle(p,i,color,r=5,extra='') {\n    return `<circle class=\"point\" style=\"--i:${i}\" cx=\"${sx(p[0])}\" cy=\"${sy(p[1])}\" r=\"${r}\" fill=\"${color}\" stroke=\"#fff\" stroke-width=\"1.5\" ${extra}\/>`;\n  }\n\n  function scatter(labels) {\n    let s=axes();\n    points.forEach((p,i)=>{\n      const label=labels[i];\n      s+=circle(p,i,label<0?'#d95757':palette[label%palette.length],5);\n    });\n    return s;\n  }\n\n  function drawCentres(r,medoids=false) {\n    let s=scatter(r.labels);\n    r.centres.forEach((c,j)=>{\n      if(medoids) {\n        s+=`<circle class=\"cluster-shape\" cx=\"${sx(c[0])}\" cy=\"${sy(c[1])}\" r=\"11\" fill=\"none\" stroke=\"${palette[j]}\" stroke-width=\"4\"\/>`;\n        s+=`<circle cx=\"${sx(c[0])}\" cy=\"${sy(c[1])}\" r=\"3.5\" fill=\"${palette[j]}\"\/>`;\n      } else {\n        s+=`<g class=\"cluster-shape\" transform=\"translate(${sx(c[0])} ${sy(c[1])})\" stroke=\"${palette[j]}\" stroke-width=\"3.5\" stroke-linecap=\"round\"><line x1=\"-9\" y1=\"0\" x2=\"9\" y2=\"0\"\/><line x1=\"0\" y1=\"-9\" x2=\"0\" y2=\"9\"\/><circle r=\"13\" fill=\"none\" stroke-dasharray=\"3 3\" stroke-width=\"1.5\"\/><\/g>`;\n      }\n    });\n    return s;\n  }\n\n  function drawDendrogram(r) {\n    let s=axes();\n    points.forEach((p,i)=>s+=circle(p,i,palette[r.labels[i]%palette.length],4));\n    const treeX=points.map((p,i)=>100+i*(500\/Math.max(1,points.length-1)));\n    let tree=`<rect x=\"65\" y=\"45\" width=\"570\" height=\"280\" rx=\"10\" fill=\"#f8faff\" stroke=\"#dce4f1\"\/>`;\n    tree+=`<text x=\"350\" y=\"28\" text-anchor=\"middle\" font-size=\"13\" font-weight=\"700\" fill=\"#43516a\">Dendrogram: merge height increases upward<\/text>`;\n    let active=points.map((p,i)=>({ids:[i],x:treeX[i],y:320}));\n\n    r.merges.forEach(merge=>{\n      const a=active.find(c=>c.ids.length===merge.a.length&&c.ids.every(id=>merge.a.includes(id)));\n      const b=active.find(c=>c.ids.length===merge.b.length&&c.ids.every(id=>merge.b.includes(id)));\n      if(!a||!b)return;\n      const y=310-(merge.height\/r.maxHeight)*245;\n      tree+=`<path d=\"M ${a.x} ${a.y} V ${y} H ${b.x} V ${b.y}\" fill=\"none\" stroke=\"#71819a\" stroke-width=\"1.5\"\/>`;\n      active=active.filter(c=>c!==a&&c!==b);\n      active.push({ids:merge.ids,x:(a.x+b.x)\/2,y});\n    });\n\n    const cutY=310-(Math.min(state.cut,r.maxHeight)\/r.maxHeight)*245;\n    tree+=`<line x1=\"70\" x2=\"630\" y1=\"${cutY}\" y2=\"${cutY}\" stroke=\"#d95757\" stroke-width=\"2.5\" stroke-dasharray=\"7 5\"\/>`;\n    tree+=`<text x=\"75\" y=\"${cutY-8}\" font-size=\"10\" fill=\"#a12c2c\">Selected cut<\/text>`;\n    treeX.forEach((x,i)=>tree+=`<circle cx=\"${x}\" cy=\"320\" r=\"4\" fill=\"${palette[r.labels[i]%palette.length]}\"\/><text x=\"${x}\" y=\"339\" text-anchor=\"middle\" font-size=\"9\" fill=\"#7b879c\">${i+1}<\/text>`);\n    return s+tree;\n  }\n\n  function drawDensity(r) {\n    let s=axes();\n    points.forEach((p,i)=>{\n      const label=r.labels[i];\n      if(label<0) {\n        s+=`<path d=\"M ${sx(p[0])-5} ${sy(p[1])-5} l 10 10 M ${sx(p[0])+5} ${sy(p[1])-5} l -10 10\" stroke=\"#d95757\" stroke-width=\"3\" stroke-linecap=\"round\"\/>`;\n      } else {\n        const core=r.neighbours[i].length>=state.minPts;\n        s+=circle(p,i,palette[label%palette.length],core?7:4);\n        if(core)s+=`<circle cx=\"${sx(p[0])}\" cy=\"${sy(p[1])}\" r=\"${state.eps*5.95}\" fill=\"${palette[label%palette.length]}\" fill-opacity=\".045\" stroke=\"${palette[label%palette.length]}\" stroke-opacity=\".22\"\/>`;\n      }\n    });\n    return s;\n  }\n\n  function drawGrid(r) {\n    let s=axes();\n    Object.entries(r.cells).forEach(([key,ids])=>{\n      const [x,y]=key.split(',').map(Number);\n      const count=ids.length,cell=state.cell,color=palette[(x+y)%palette.length];\n      s+=`<rect class=\"cluster-shape\" x=\"${sx(x*cell)}\" y=\"${sy((y+1)*cell)}\" width=\"${cell*5.95}\" height=\"${cell*3.35}\" fill=\"${color}\" fill-opacity=\"${Math.min(.78,.12+count*.16)}\" stroke=\"${color}\" stroke-opacity=\".7\"\/>`;\n      s+=`<text x=\"${sx(x*cell)+cell*2.975}\" y=\"${sy((y+.5)*cell)+4}\" text-anchor=\"middle\" font-size=\"12\" font-weight=\"800\" fill=\"${count>=2?'#fff':'#28364d'}\">${count}<\/text>`;\n    });\n    points.forEach((p,i)=>s+=`<circle cx=\"${sx(p[0])}\" cy=\"${sy(p[1])}\" r=\"3\" fill=\"#17233b\" stroke=\"#fff\"\/>`);\n    return s;\n  }\n\n  function drawModel(r) {\n    let s=axes();\n    r.centres.forEach((c,j)=>{\n      const [vx,vy]=r.variances[j];\n      const rx=Math.min(Math.sqrt(vx)*5.95,180),ry=Math.min(Math.sqrt(vy)*3.35,100);\n      s+=`<ellipse class=\"cluster-shape\" cx=\"${sx(c[0])}\" cy=\"${sy(c[1])}\" rx=\"${rx}\" ry=\"${ry}\" fill=\"${palette[j]}\" fill-opacity=\".13\" stroke=\"${palette[j]}\" stroke-width=\"2.5\"\/>`;\n      s+=`<ellipse cx=\"${sx(c[0])}\" cy=\"${sy(c[1])}\" rx=\"${rx*.55}\" ry=\"${ry*.55}\" fill=\"none\" stroke=\"${palette[j]}\" stroke-opacity=\".7\" stroke-dasharray=\"5 4\"\/>`;\n      s+=`<circle cx=\"${sx(c[0])}\" cy=\"${sy(c[1])}\" r=\"5\" fill=\"${palette[j]}\" stroke=\"#fff\" stroke-width=\"2\"\/>`;\n    });\n    points.forEach((p,i)=>s+=circle(p,i,palette[r.labels[i]%palette.length],4));\n    return s;\n  }\n\n  function drawFuzzy(r) {\n    let s=axes();\n    points.forEach((p,i)=>{\n      const row=r.memberships[i];\n      const sorted=row.map((v,j)=>({v,j})).sort((a,b)=>b.v-a.v);\n      const best=sorted[0],second=sorted[1];\n      s+=`<circle class=\"point\" style=\"--i:${i}\" cx=\"${sx(p[0])}\" cy=\"${sy(p[1])}\" r=\"${5+best.v*5}\" fill=\"${palette[best.j]}\" fill-opacity=\"${.35+best.v*.65}\" stroke=\"${palette[second.j]}\" stroke-width=\"${(1-best.v)*5+.5}\"\/>`;\n      if(best.v<.78)s+=`<text x=\"${sx(p[0])+7}\" y=\"${sy(p[1])-8}\" font-size=\"9\" font-weight=\"700\" fill=\"#46546c\">${Math.round(best.v*100)}%<\/text>`;\n    });\n    r.centres.forEach((c,j)=>{\n      s+=`<g transform=\"translate(${sx(c[0])} ${sy(c[1])})\"><path d=\"M -9 -9 L 9 9 M 9 -9 L -9 9\" stroke=\"${palette[j]}\" stroke-width=\"3\"\/><circle r=\"12\" fill=\"none\" stroke=\"${palette[j]}\" stroke-width=\"1.5\" stroke-dasharray=\"3 3\"\/><\/g>`;\n    });\n    return s;\n  }\n\n  function methodSteps(r) {\n    if(method==='kmeans')return [\n      'Started with '+r.centres.length+' mean centres.',\n      'Assigned each observation to its nearest centre.',\n      'Recomputed each centre using the average of its assigned points.',\n      'Repeated the assignment and update until the centres settled or the iteration limit was reached.'\n    ];\n    if(method==='kmedoids')return [\n      'Selected '+r.centres.length+' real observations as starting medoids.',\n      'Assigned each point to its nearest medoid.',\n      'Tested representative-point swaps to reduce within-group distance.',\n      'Stopped when no improving swap was found or the round limit was reached.'\n    ];\n    if(method==='hierarchical')return [\n      'Started with one group per observation.',\n      'Compared groups using '+state.linkage+' linkage.',\n      'Merged the closest groups and recorded each merge height.',\n      'Used the selected cut height to determine which groups remain separate.'\n    ];\n    if(method==='dbscan')return [\n      'Checked each point\u2019s neighbourhood radius: '+state.eps+'.',\n      'Marked points with at least '+state.minPts+' neighbours, including themselves, as core points.',\n      'Connected reachable dense regions into clusters.',\n      'Left '+r.noise+' point(s) labelled as noise.'\n    ];\n    if(method==='grid')return [\n      'Divided the feature space into '+state.cell+' \u00d7 '+state.cell+' cells.',\n      'Counted the observations in each occupied cell.',\n      'Used darker shading for cells with more observations.',\n      'This visual demonstrates cell occupancy; full algorithms add rules for dense cells and neighbouring regions.'\n    ];\n    if(method==='model')return [\n      'Started with '+state.components+' Gaussian components.',\n      'Estimated a centre and spread for each component.',\n      'Displayed ellipses to make the component shapes visible.',\n      'This simplified view assigns points to the nearest fitted centre rather than running full EM optimisation.'\n    ];\n    return [\n      'Initialised '+state.k+' fuzzy centres.',\n      'Assigned every point a membership score for each centre.',\n      'Updated centres using membership-weighted positions.',\n      'Repeated the update so a point could retain membership in more than one group.'\n    ];\n  }\n\n  function slider(id,label,min,max,step,value) {\n    return `<div class=\"control\"><label for=\"ca-${id}\"><span>${label}<\/span><span data-value=\"${id}\">${value}<\/span><\/label><input id=\"ca-${id}\" data-setting=\"${id}\" type=\"range\" min=\"${min}\" max=\"${max}\" step=\"${step}\" value=\"${value}\"><\/div>`;\n  }\n\n  function buildControls() {\n    let html='';\n    if(['kmeans','kmedoids','fuzzy'].includes(method))html+=slider('k','Number of clusters',2,6,1,state.k);\n    if(method==='kmeans')html+=slider('iterations','Iteration limit',1,20,1,state.iterations);\n    if(method==='hierarchical') {\n      html+=`<div class=\"control\"><label for=\"ca-linkage\">Linkage rule<\/label><select id=\"ca-linkage\" data-setting=\"linkage\"><option value=\"single\">Single: nearest pair<\/option><option value=\"complete\">Complete: furthest pair<\/option><option value=\"average\">Average: mean pair distance<\/option><\/select><\/div>`;\n      html+=slider('cut','Dendrogram cut height',5,100,1,state.cut);\n    }\n    if(method==='dbscan') {\n      html+=slider('eps','Neighbourhood radius',5,28,1,state.eps);\n      html+=slider('minPts','Minimum neighbours',2,6,1,state.minPts);\n    }\n    if(method==='grid')html+=slider('cell','Cell width',6,25,1,state.cell);\n    if(method==='model')html+=slider('components','Gaussian components',2,5,1,state.components);\n    if(method==='fuzzy')html+=slider('fuzz','Fuzziness',1.5,3,.1,state.fuzz);\n\n    el('controls').innerHTML=html;\n    el('controls-intro').textContent=\n      method==='hierarchical'?'Change the tree cut or the rule used to measure group distance.':\n      method==='dbscan'?'Radius and minimum neighbours decide what counts as dense.':\n      method==='grid'?'Change the size of the cells used to count observations.':\n      method==='model'?'Choose how many probability clouds to display.':\n      method==='fuzzy'?'Change the number of centres and the softness of memberships.':\n      'Change the settings, then run the method again.';\n\n    const select=$('#ca-linkage');\n    if(select)select.value=state.linkage;\n\n    el('controls').querySelectorAll('[data-setting]').forEach(input=>{\n      input.addEventListener('input',()=>{\n        const id=input.dataset.setting;\n        state[id]=input.type==='range'?Number(input.value):input.value;\n        const valueLabel=el('controls').querySelector('[data-value=\"'+id+'\"]');\n        if(valueLabel)valueLabel.textContent=state[id];\n      });\n      input.addEventListener('change',()=>{\n        if(input.tagName==='SELECT')state[input.dataset.setting]=input.value;\n      });\n    });\n  }\n\n  function render() {\n    stopAnimation();\n    result=calculate();\n    const info=descriptions[method];\n\n    el('kicker').textContent=info.kicker;\n    el('title').textContent=info.title;\n    el('subtitle').textContent=info.subtitle;\n    el('explainer').textContent=info.explainer;\n    el('insight-title').textContent=info.insightTitle;\n    el('insight').textContent=info.insight;\n    el('caveat').textContent=info.caveat;\n\n    let chart='';\n    if(method==='kmeans')chart=drawCentres(result);\n    if(method==='kmedoids')chart=drawCentres(result,true);\n    if(method==='hierarchical')chart=drawDendrogram(result);\n    if(method==='dbscan')chart=drawDensity(result);\n    if(method==='grid')chart=drawGrid(result);\n    if(method==='model')chart=drawModel(result);\n    if(method==='fuzzy')chart=drawFuzzy(result);\n    el('viz').innerHTML=chart;\n\n    let legend=[];\n    if(method==='grid')legend=[['#8256c7','Cell shading = count'],['#17233b','Observations']];\n    else if(method==='hierarchical')legend=[['#71819a','Merge branches'],['#d95757','Selected cut height']];\n    else if(method==='dbscan')legend=[['#2864dc','Cluster points'],['#d95757','Noise points'],['#9aa5b5','Outlined circles show dense neighbourhoods']];\n    else if(method==='model')legend=[[palette[0],'Component 1'],[palette[1],'Component 2'],[palette[2],'Component 3'],['#8256c7','Component spread']];\n    else if(method==='fuzzy')legend=[[palette[0],'Strong membership'],[palette[3],'Mixed membership'],['#17233b','Crosses mark centres']];\n    else legend=[[palette[0],'Group A'],[palette[1],'Group B'],[palette[2],'Group C'],[method==='kmedoids'?'#17233b':'#8256c7',method==='kmedoids'?'Ring = real medoid':'Cross = mean centre']];\n\n    el('legend').innerHTML=legend.map(([color,label])=>`<span><i class=\"dot\" style=\"background:${color}\"><\/i>${label}<\/span>`).join('');\n\n    const count=method==='dbscan'?new Set(result.labels.filter(x=>x>=0)).size:\n      method==='grid'?Object.keys(result.cells).length:\n      method==='hierarchical'?result.groups.length:result.centres.length;\n\n    const extra=method==='dbscan'?result.noise:\n      method==='grid'?Object.keys(result.cells).filter(key=>result.cells[key].length>=2).length:\n      method==='fuzzy'?result.memberships.filter(row=>Math.max(...row)<.75).length:\n      method==='hierarchical'?result.merges.length:result.labels.length;\n\n    el('metrics').innerHTML=\n      `<div class=\"metric\"><strong>${points.length}<\/strong><span>Observations<\/span><\/div>`+\n      `<div class=\"metric\"><strong>${count}<\/strong><span>${method==='grid'?'Occupied cells':method==='hierarchical'?'Groups at cut':'Groups\/components'}<\/span><\/div>`+\n      `<div class=\"metric\"><strong>${extra}<\/strong><span>${method==='dbscan'?'Noise points':method==='grid'?'Cells with 2+ points':method==='hierarchical'?'Recorded merges':method==='fuzzy'?'Ambiguous points':'Points considered'}<\/span><\/div>`;\n\n    el('steps').innerHTML=methodSteps(result).map(text=>'<li>'+text+'<\/li>').join('');\n    el('points-input').value=points.map(p=>p.join(', ')).join('\\n');\n\n    all('.tab').forEach(button=>{\n      button.setAttribute('aria-selected',String(button.dataset.method===method));\n    });\n\n    buildControls();\n  }\n\n  function stopAnimation() {\n    if(timer!==null){clearInterval(timer);timer=null;}\n  }\n\n  all('.tab').forEach(button=>{\n    button.addEventListener('click',()=>{\n      method=button.dataset.method;\n      render();\n    });\n  });\n\n  $('[data-action=\"run\"]').addEventListener('click',render);\n\n  $('[data-action=\"reset\"]').addEventListener('click',()=>{\n    Object.assign(state,{k:3,iterations:8,linkage:'average',cut:55,eps:15,minPts:3,cell:12,components:3,fuzz:2});\n    points=sample.map(p=>p.slice());\n    render();\n    el('data-message').textContent='Sample data and default settings restored.';\n  });\n\n  $('[data-action=\"animate\"]').addEventListener('click',()=>{\n    stopAnimation();\n    if(method!=='kmeans') {\n      el('insight').textContent=descriptions[method].insight+' Change the settings and press Run method to compare results.';\n      return;\n    }\n    let centres=initialCentres(state.k),iteration=0;\n    timer=setInterval(()=>{\n      const labels=points.map(p=>nearest(p,centres));\n      const next=centres.map((c,j)=>{\n        const group=points.filter((p,i)=>labels[i]===j);\n        return group.length?average(group):c;\n      });\n      centres=centres.map((c,j)=>[\n        c[0]+(next[j][0]-c[0])*.4,\n        c[1]+(next[j][1]-c[1])*.4\n      ]);\n      let svg=scatter(points.map(p=>nearest(p,centres)));\n      centres.forEach((c,j)=>{\n        svg+=`<g transform=\"translate(${sx(c[0])} ${sy(c[1])})\" stroke=\"${palette[j]}\" stroke-width=\"4\"><line x1=\"-9\" y1=\"0\" x2=\"9\" y2=\"0\"\/><line x1=\"0\" y1=\"-9\" x2=\"0\" y2=\"9\"\/><circle r=\"13\" fill=\"none\" stroke-dasharray=\"3 3\" stroke-width=\"1.5\"\/><\/g>`;\n      });\n      el('viz').innerHTML=svg;\n      iteration++;\n      if(iteration>=12){stopAnimation();render();}\n    },260);\n  });\n\n  $('[data-action=\"apply-data\"]').addEventListener('click',()=>{\n    const rows=el('points-input').value.trim().split(\/\\n+\/);\n    const parsed=[];\n    for(const row of rows) {\n      const values=row.split(\/[,\\s]+\/).filter(Boolean);\n      if(values.length!==2||!values.every(v=>Number.isFinite(Number(v)))) {\n        el('data-message').textContent='Use one numeric x,y pair on each line.';\n        return;\n      }\n      const point=values.map(Number);\n      if(point.some(v=>v<0||v>100)) {\n        el('data-message').textContent='Keep x and y between 0 and 100.';\n        return;\n      }\n      parsed.push(point);\n    }\n    if(parsed.length<3) {\n      el('data-message').textContent='Enter at least three points.';\n      return;\n    }\n    points=parsed;\n    el('data-message').textContent='Applied '+points.length+' points.';\n    render();\n  });\n\n  $('[data-action=\"restore-data\"]').addEventListener('click',()=>{\n    points=sample.map(p=>p.slice());\n    render();\n    el('data-message').textContent='Sample points restored.';\n  });\n\n  render();\n})();\n<\/script>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>What Is Cluster Analysis?<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Cluster analysis is a method that groups data points so that items in the same group are more alike than items in other groups. It is unsupervised, so you give the algorithm no labels. The groups, called clusters, come from the data itself. If a colleague asked me to define cluster analysis in one line, I would say it finds groups in data that nobody has labelled. Everything else is detail.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Cluster Analysis Meaning In Simple Terms<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Picture a scatter of dots on a page. You can see the blobs without any help. Now picture the same dots spread across 30 columns instead of two. You cannot see anything. A computer still can. That is the cluster analysis meaning in practice: teaching a machine to see the blobs you would see, in dimensions you cannot draw. It needs two things.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A way to measure how alike two records are<\/li>\n\n\n\n<li>A rule for gathering the alike ones. Every method in this post is a different answer to those two problems.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">I think of any result as the product of four decisions. What goes in, meaning the variables and how they are scaled. How &#8220;alike&#8221; is measured. Which algorithm gathers the groups. How many groups you ask for. Change one and the clusters can move. I will keep calling these the four decisions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Cluster Analysis In Statistics<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Statisticians were here first, and they use different words for much of it. They usually cluster cases, such as people or shops, on their scores across several variables. They can also cluster the variables themselves, which comes close to factor analysis.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Cluster analysis in statistics and in <a href=\"https:\/\/imarticus.org\/blog\/the-art-of-machine-learning\/\">machine learning<\/a> starts without them. And the measure of &#8220;alike&#8221; you choose depends on the types of data in cluster analysis you are holding, which is the next section.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>What Is Cluster Analysis In Data Mining?<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If you have ever searched for what is cluster analysis in data mining and got back a wall of formulas, this is the plain version. Cluster analysis in data mining is where I would start with almost any unlabelled table, because it asks for no hypothesis and no training examples. You get a first map of the data. The map tells you what to ask next.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In data mining, cluster analysis is an unsupervised technique that sorts records into groups based on similarity, with no predefined classes. Analysts use it to explore a new dataset, summarise large tables, spot outliers and prepare data for other models.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You will often hear that clustering has no right answer because there are no labels. True, and a bit of a cop-out. No answer key doesn\u2019t mean no standard. My standard is simple:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Can someone name each group in a sentence<\/li>\n\n\n\n<li>Would they do something different for each one?<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Four tidy clusters that fail that test are a failed analysis, however neat the maths looks. A purely technical way to define cluster analysis leaves that out.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Question<\/strong><\/td><td><strong>Clustering<\/strong><\/td><td><strong>Classification<\/strong><\/td><\/tr><tr><td><strong>Needs labelled data?<\/strong><\/td><td>No<\/td><td>Yes<\/td><\/tr><tr><td><strong>What is the goal?<\/strong><\/td><td>Discover groups that already exist<\/td><td>Predict a known label for new records<\/td><\/tr><tr><td><strong>Typical output<\/strong><\/td><td>A cluster number for each record<\/td><td>A class name or a probability<\/td><\/tr><tr><td><strong>Example<\/strong><\/td><td>Grouping shoppers by buying habits<\/td><td>Predicting whether a shopper will churn<\/td><\/tr><tr><td><strong>Typical algorithms<\/strong><\/td><td>k-means, DBSCAN, hierarchical methods<\/td><td>Logistic regression, decision trees<\/td><\/tr><tr><td><strong>How do you check it?<\/strong><\/td><td>Validation scores and judgement<\/td><td>Accuracy against known labels<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The last row is what makes clustering hard. With classification you can mark your own homework. With clustering you cannot, so judgement carries more weight than most tutorials admit. A good method should cope with large tables, mixed variable types, groups that are not round, and a little noise. None does all four well. That is why there are so many. &nbsp;<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">A data analyst\u2019s role goes well beyond preparing reports or working with spreadsheets. Understanding this day-to-day work gives you a clearer picture of what the role demands in a real workplace.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"The Truth About Being a Data Analyst in 2026\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/v3klJkbw7HI?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Types Of Data In Cluster Analysis<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before I choose an algorithm, I look at the columns. The types of data in cluster analysis in <a href=\"https:\/\/imarticus.org\/blog\/a-step-by-step-guide-to-data-mining\/\">data mining<\/a> decide which distance measure I can trust, and a wrong measure quietly wrecks everything after it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Numbers: Interval-Scaled And Ratio-Scaled Data<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Interval-scaled data is numbers on an even scale, like age, temperature or order value. Euclidean or Manhattan distance works, but only after scaling. Skip that, and the column with the biggest numbers wins every argument. That is exactly what happened in my opening example.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ratio-scaled data has a true zero and tends to grow multiplicatively, such as visit counts or bacteria counts. A log transform often tames it. After that, you can treat it like interval data.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Categories: Binary, Nominal And Ordinal Data<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Binary data<\/strong> has two outcomes, like bought or did not buy. Watch the zeros. If &#8220;did not buy&#8221; is true for nearly everyone, two customers who both say no have told you almost nothing. Jaccard similarity ignores shared zeros for exactly that reason.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Nominal data<\/strong> are categories with no order, such as city or payment method. Simple matching counts the categories two records share. K-modes swaps the average for the most common category. One-hot encoding works too, though it can bloat a table fast.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ordinal data<\/strong> is ordered categories, like a rating from 1 to 5. The gaps between steps are not guaranteed to be equal, so I would rescale the ranks to a 0 to 1 range before measuring distance.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Mixed Data<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Real tables mix everything. Gower distance, introduced by J. C. Gower in 1971, measures each column with a rule that suits its type and averages the results. K-prototypes does a similar job inside a k-means-style algorithm.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This table maps the types of data in cluster analysis in data mining to the measures and algorithms that usually fit.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Data type<\/strong><\/td><td><strong>Example<\/strong><\/td><td><strong>Usual measure<\/strong><\/td><td><strong>Usual algorithm<\/strong><\/td><\/tr><tr><td><strong>Interval-scaled<\/strong><\/td><td>Age, order value<\/td><td>Euclidean or Manhattan<\/td><td>k-means, hierarchical<\/td><\/tr><tr><td><strong>Binary<\/strong><\/td><td>Bought or did not buy<\/td><td>Jaccard or simple matching<\/td><td>Hierarchical, k-medoids<\/td><\/tr><tr><td><strong>Nominal<\/strong><\/td><td>City, payment method<\/td><td>Simple matching<\/td><td>k-modes, hierarchical<\/td><\/tr><tr><td><strong>Ordinal<\/strong><\/td><td>Rating from 1 to 5<\/td><td>Distance on rescaled ranks<\/td><td>Hierarchical, k-medoids<\/td><\/tr><tr><td><strong>Ratio-scaled<\/strong><\/td><td>Website visits<\/td><td>Euclidean after a log transform<\/td><td>k-means, hierarchical<\/td><\/tr><tr><td><strong>Mixed<\/strong><\/td><td>Age, city and rating together<\/td><td>Gower distance<\/td><td>k-prototypes, hierarchical<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">If your table has numbers, categories and ratings side by side, give the distance measure a full afternoon. It is the decision people rush. &nbsp; &nbsp;<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"has-background wp-block-paragraph\" style=\"background-color:#7bdbb426\"><strong><em>Pro Tip:<\/em><\/strong> <em>Do not settle on three or four clusters just because the output looks tidy. Compare plausible solutions using silhouette scores, cluster sizes and whether the groups make sense for the problem.&nbsp;<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Types Of Cluster Analysis<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Every clustering method asks a different question of your data.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>K-means asks: where are the centres?<\/li>\n\n\n\n<li>Hierarchical methods ask: who is closest to whom?<\/li>\n\n\n\n<li>DBSCAN asks: where is it crowded?<\/li>\n\n\n\n<li>Gaussian mixture models ask: which overlapping bell curves explain this?<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Pick the question that matches your data and the rest follows. The table below lines up the main types of cluster analysis against the things that decide which one you use.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Family<\/strong><\/td><td><strong>Best for<\/strong><\/td><td><strong>Needs k up front?<\/strong><\/td><td><strong>Outliers<\/strong><\/td><\/tr><tr><td><strong>Partitioning (k-means, k-medoids)<\/strong><\/td><td>Compact groups of similar size in big tables<\/td><td>Yes<\/td><td>k-means is sensitive, k-medoids copes better<\/td><\/tr><tr><td><strong>Hierarchical (agglomerative, divisive)<\/strong><\/td><td>Exploration and nested groups in small or medium tables<\/td><td>No, you cut the tree<\/td><td>Sensitive to noise<\/td><\/tr><tr><td><strong>Density-based (DBSCAN)<\/strong><\/td><td>Odd shapes and noisy data<\/td><td>No<\/td><td>Labelled as noise<\/td><\/tr><tr><td><strong>Grid-based (STING, CLIQUE)<\/strong><\/td><td>Very large datasets where speed matters<\/td><td>Varies<\/td><td>Sparse cells are dropped<\/td><\/tr><tr><td><strong>Model-based (Gaussian mixtures)<\/strong><\/td><td>Overlapping groups with a probability view<\/td><td>Usually<\/td><td>Depends on the model fitting the data<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Partitioning methods in cluster analysis make you pick k first. Hierarchical and density methods let you skip that, but they hand you a different decision instead: where to cut the tree, or how to set eps. You never get out of choosing.&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Partitioning Methods In Cluster Analysis<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Partitioning methods split the data into k groups, and you choose k. The name k-means comes from James MacQueen, who used it in a 1967 paper. The idea is almost embarrassingly simple.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Pick k starting centres.<\/li>\n\n\n\n<li>Assign every point to its nearest centre.<\/li>\n\n\n\n<li>Move each centre to the average of its points.<\/li>\n\n\n\n<li>Repeat until nothing moves.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Take six dots on a grid: (1, 2), (1, 4), (2, 3), (8, 8), (9, 10) and (10, 9). Your eye sees two groups. Start with centre A at (1, 2) and centre B at (8, 8), and measure the straight-line distance from every dot to each centre.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Point<\/strong><\/td><td><strong>Distance to A<\/strong><\/td><td><strong>Distance to B<\/strong><\/td><td><strong>Goes to<\/strong><\/td><\/tr><tr><td><strong>(1, 2)<\/strong><\/td><td>0.00<\/td><td>9.22<\/td><td>A<\/td><\/tr><tr><td><strong>(1, 4)<\/strong><\/td><td>2.00<\/td><td>8.06<\/td><td>A<\/td><\/tr><tr><td><strong>(2, 3)<\/strong><\/td><td>1.41<\/td><td>7.81<\/td><td>A<\/td><\/tr><tr><td><strong>(8, 8)<\/strong><\/td><td>9.22<\/td><td>0.00<\/td><td>B<\/td><\/tr><tr><td><strong>(9, 10)<\/strong><\/td><td>11.31<\/td><td>2.24<\/td><td>B<\/td><\/tr><tr><td><strong>(10, 9)<\/strong><\/td><td>11.40<\/td><td>2.24<\/td><td>B<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Now move each centre to the average of its dots. A lands at (1.33, 3.00) and B at (9.00, 9.00). Assign again. Nothing changes, so the centres stay put and the algorithm stops. Two passes. Real data takes more, but the logic does not change.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">K-medoids does the same job with a real data point as the centre instead of an average. That makes it steadier around outliers. It also gets slow on big tables. The case for k-means is strong. K-means is quick; it also scales to large tables with very little fuss, and everyone understands it. I still think it gets picked out of habit.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Hierarchical Cluster Analysis<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Hierarchical cluster analysis is what I reach for when I do not trust my own guess for k. It builds a tree instead of asking for a number.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Agglomerative methods start with every point alone and keep merging the two closest groups.<\/li>\n\n\n\n<li>Divisive methods run the other way. The tree is called a dendrogram, and you cut it at a height that gives you a sensible number of groups.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">&#8220;Closest&#8221; needs a definition once groups hold more than one point. That is the linkage choice, and it changes the result. Single linkage uses the two nearest points and tends to string groups into chains.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Complete linkage uses the two furthest points and gives tight, similar-sized groups.<\/li>\n\n\n\n<li>Average linkage takes the mean across all pairs.<\/li>\n\n\n\n<li>Ward&#8217;s method merges whichever pair adds the least variance.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If I had to pick blind, I would start with Ward and compare it against average linkage. Two drawbacks. A merge cannot be undone, so an early poor call stays in the tree. And on big tables, the number of rows and columns matter more than you would like, because the method compares many pairs. Hierarchical cluster analysis is a tool for small and medium tables, and for exploring. It is not for a million customers.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Density-Based Clustering<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">What does DBSCAN need? Two settings. Eps is how close two points must be to count as neighbours. Min_samples is how many neighbours make a region dense enough to start a cluster. Everything outside a dense region is labelled noise instead of being forced into a group. Martin Ester and colleagues introduced it in 1996.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I think that noise label is the most underrated idea in clustering. Most methods insist every record belongs somewhere. DBSCAN is allowed to say &#8220;none of the above&#8221;. The scikit-learn documentation warns that eps matters a great deal: too small and most of the data goes unclustered, too large and separate groups merge. It also struggles when real groups have very different densities.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Grid-Based, Model-Based And Fuzzy Clustering<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Three more, briefly. Grid-based methods cut the space into cells and cluster the dense ones, which is fast on very large data. Model-based methods assume the data comes from a mix of probability distributions, usually Gaussian, and give each point a probability of belonging to each group. Fuzzy clustering, such as fuzzy c-means, lets one point sit in several clusters to different degrees, which helps when groups overlap.&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"596\" src=\"https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/types-of-cluster-analysis-1024x596.webp\" alt=\"cluster analysis types\" class=\"wp-image-278517\" srcset=\"https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/types-of-cluster-analysis-1024x596.webp 1024w, https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/types-of-cluster-analysis-300x175.webp 300w, https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/types-of-cluster-analysis-767x447.webp 767w, https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/types-of-cluster-analysis-1536x895.webp 1536w, https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/types-of-cluster-analysis.webp 1643w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Cluster Analysis Diagram: How To Read One<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Caveat before the pictures. The data in all three figures is simulated: 400 made-up customers, with three groups that I built in. Real data is messier, and I do not want a tidy chart to mislead you.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>1. A cluster analysis diagram of 400 simulated customers, coloured by k-means cluster. Each dot is one customer.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Read it by asking three questions. What are the axes? Here, days since last purchase and total spend. What do the colours mean? The cluster each customer landed in. And where do the colours touch? Those borderline customers are the ones I would look at first. One limit. We clustered on three variables, and a flat chart shows two. Purchase count is hidden. A cluster analysis diagram is a picture of one run, not the truth.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>2. A dendrogram of 30 sampled customers using Ward linkage.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A dendrogram reads from the bottom up. Each join is a merge, and the height of the join shows how far apart the groups were when they merged. A long vertical gap means the groups were far apart, so cutting across a long gap gives well-separated clusters. My dashed line sits at 70 per cent of the tallest merge. That is a convenient choice, nothing more.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>3. An elbow plot. The curve bends at three clusters.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The big drop comes between two and three clusters. After three, extra clusters buy very little. That bend is a first hint for k, and nothing more. In my view, the elbow is the most over-trusted chart in data science. On messy real data, the bend can be a gentle curve, and two people will see two different elbows.&nbsp;<\/p>\n\n\n\n<div id=\"cluster-analysis-widget\">\n  <style>\n    #cluster-analysis-widget {\n      --ca-ink: #17233b;\n      --ca-muted: #5d6980;\n      --ca-line: #dce3ee;\n      --ca-blue: #2864dc;\n      --ca-teal: #0c9488;\n      --ca-orange: #e28a2b;\n      font: 16px\/1.55 system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n      color: var(--ca-ink);\n      width: 100%;\n      max-width: 100%;\n      margin: 20px 0;\n      overflow: hidden;\n      overflow-wrap: anywhere;\n      isolation: isolate;\n    }\n\n    #cluster-analysis-widget *,\n    #cluster-analysis-widget *::before,\n    #cluster-analysis-widget *::after {\n      box-sizing: border-box;\n    }\n\n    #cluster-analysis-widget .ca-main {\n      width: 100%;\n      max-width: 1120px;\n      margin: 0 auto;\n      padding: 18px 0;\n    }\n\n    #cluster-analysis-widget .ca-eyebrow {\n      color: var(--ca-blue);\n      font-size: 12px;\n      font-weight: 800;\n      letter-spacing: 1.5px;\n      text-transform: uppercase;\n      margin-bottom: 8px;\n    }\n\n    #cluster-analysis-widget .ca-title {\n      font-size: clamp(25px, 4vw, 38px);\n      line-height: 1.2;\n      letter-spacing: -0.7px;\n      margin: 0 0 12px;\n      color: var(--ca-ink);\n    }\n\n    #cluster-analysis-widget .ca-lead {\n      font-size: 16px;\n      line-height: 1.65;\n      color: var(--ca-muted);\n      margin: 0 0 18px;\n    }\n\n    #cluster-analysis-widget .ca-caveat {\n      padding: 14px 16px;\n      border: 1px solid #cbd9f8;\n      background: #edf3ff;\n      border-radius: 10px;\n      color: #263d68;\n      font-size: 14px;\n      margin: 16px 0;\n    }\n\n    #cluster-analysis-widget .ca-tabs {\n      display: flex;\n      gap: 8px;\n      flex-wrap: wrap;\n      margin: 18px 0 14px;\n    }\n\n    #cluster-analysis-widget .ca-tab,\n    #cluster-analysis-widget .ca-reset {\n      appearance: none;\n      -webkit-appearance: none;\n      font: inherit;\n      cursor: pointer;\n      border: 1px solid var(--ca-line);\n      border-radius: 9px;\n      background: #fff;\n      color: var(--ca-ink);\n      padding: 10px 13px;\n      font-size: 13px;\n      line-height: 1.4;\n      font-weight: 700;\n      box-shadow: none;\n      text-transform: none;\n      text-decoration: none;\n    }\n\n    #cluster-analysis-widget .ca-tab {\n      border-radius: 30px;\n    }\n\n    #cluster-analysis-widget .ca-tab[aria-selected=\"true\"] {\n      background: var(--ca-ink);\n      color: #fff;\n      border-color: var(--ca-ink);\n    }\n\n    #cluster-analysis-widget .ca-tab:hover,\n    #cluster-analysis-widget .ca-reset:hover {\n      filter: brightness(.96);\n    }\n\n    #cluster-analysis-widget .ca-panel {\n      border: 1px solid var(--ca-line);\n      border-radius: 14px;\n      overflow: hidden;\n      background: #fff;\n      width: 100%;\n      max-width: 100%;\n    }\n\n    #cluster-analysis-widget .ca-head {\n      padding: 18px;\n      border-bottom: 1px solid var(--ca-line);\n    }\n\n    #cluster-analysis-widget .ca-heading {\n      font-size: 20px;\n      line-height: 1.35;\n      margin: 0 0 7px;\n      color: var(--ca-ink);\n    }\n\n    #cluster-analysis-widget .ca-subtitle {\n      font-size: 14px;\n      color: var(--ca-muted);\n      margin: 0;\n      line-height: 1.6;\n    }\n\n    #cluster-analysis-widget .ca-visual {\n      padding: 8px;\n      width: 100%;\n      overflow: hidden;\n      background: #fff;\n    }\n\n    #cluster-analysis-widget .ca-chart {\n      display: block;\n      width: 100%;\n      height: auto;\n      min-height: 0;\n      max-width: 100%;\n      overflow: visible;\n    }\n\n    #cluster-analysis-widget .ca-legend {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 8px 16px;\n      padding: 8px 16px 14px;\n      font-size: 12px;\n      color: var(--ca-muted);\n    }\n\n    #cluster-analysis-widget .ca-key {\n      display: inline-flex;\n      gap: 6px;\n      align-items: center;\n    }\n\n    #cluster-analysis-widget .ca-swatch {\n      display: inline-block;\n      width: 10px;\n      height: 10px;\n      min-width: 10px;\n      border-radius: 50%;\n    }\n\n    #cluster-analysis-widget .ca-body {\n      padding: 16px;\n      border-top: 1px solid var(--ca-line);\n    }\n\n    #cluster-analysis-widget .ca-controls {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 12px;\n      margin: 8px 0 14px;\n    }\n\n    #cluster-analysis-widget .ca-control {\n      flex: 1 1 190px;\n      min-width: 0;\n      background: #f7f9fd;\n      border: 1px solid #e5eaf3;\n      padding: 12px;\n      border-radius: 10px;\n    }\n\n    #cluster-analysis-widget .ca-control label {\n      display: flex;\n      align-items: center;\n      justify-content: space-between;\n      gap: 8px;\n      margin: 0 0 8px;\n      font-size: 13px;\n      font-weight: 700;\n      color: var(--ca-ink);\n    }\n\n    #cluster-analysis-widget .ca-control input[type=\"range\"] {\n      display: block;\n      width: 100%;\n      max-width: 100%;\n      margin: 8px 0 0;\n      accent-color: var(--ca-blue);\n    }\n\n    #cluster-analysis-widget .ca-control input[type=\"checkbox\"] {\n      width: 17px;\n      height: 17px;\n      margin: 0;\n      flex: 0 0 auto;\n      accent-color: var(--ca-blue);\n    }\n\n    #cluster-analysis-widget .ca-control select {\n      display: block;\n      width: 100%;\n      max-width: 100%;\n      padding: 9px;\n      margin: 0;\n      font: inherit;\n      font-size: 13px;\n      color: var(--ca-ink);\n      background: #fff;\n      border: 1px solid var(--ca-line);\n      border-radius: 7px;\n    }\n\n    #cluster-analysis-widget .ca-check {\n      display: flex;\n      align-items: center;\n      gap: 9px;\n      font-size: 13px;\n      font-weight: 650;\n      line-height: 1.5;\n    }\n\n    #cluster-analysis-widget .ca-actions {\n      margin: 12px 0;\n    }\n\n    #cluster-analysis-widget .ca-reset {\n      background: #fff;\n    }\n\n    #cluster-analysis-widget .ca-status {\n      color: var(--ca-muted);\n      font-size: 13px;\n      margin: 10px 0;\n      min-height: 1.4em;\n    }\n\n    #cluster-analysis-widget .ca-insight {\n      background: #f8faff;\n      border: 1px solid #e4eaf5;\n      padding: 13px 14px;\n      border-radius: 10px;\n      margin-top: 14px;\n    }\n\n    #cluster-analysis-widget .ca-insight-title {\n      display: block;\n      font-size: 14px;\n      margin-bottom: 5px;\n      color: var(--ca-ink);\n    }\n\n    #cluster-analysis-widget .ca-insight-text {\n      color: #45536b;\n      font-size: 14px;\n      line-height: 1.65;\n      margin: 0;\n    }\n\n    #cluster-analysis-widget .ca-caption {\n      font-size: 12px;\n      line-height: 1.6;\n      color: var(--ca-muted);\n      margin: 12px 0 0;\n    }\n\n    #cluster-analysis-widget .ca-point {\n      cursor: pointer;\n    }\n\n    #cluster-analysis-widget .ca-point:focus {\n      outline: none;\n      stroke: #17233b;\n      stroke-width: 2.5;\n    }\n\n    #cluster-analysis-widget button:focus-visible,\n    #cluster-analysis-widget input:focus-visible,\n    #cluster-analysis-widget select:focus-visible {\n      outline: 2px solid #91b5ff;\n      outline-offset: 3px;\n    }\n\n    @media (max-width: 600px) {\n      #cluster-analysis-widget .ca-head {\n        padding: 14px;\n      }\n\n      #cluster-analysis-widget .ca-body {\n        padding: 12px;\n      }\n\n      #cluster-analysis-widget .ca-tab {\n        padding: 8px 10px;\n        font-size: 12px;\n      }\n\n      #cluster-analysis-widget .ca-visual {\n        padding: 3px;\n      }\n\n      #cluster-analysis-widget .ca-heading {\n        font-size: 18px;\n      }\n\n      #cluster-analysis-widget .ca-lead {\n        font-size: 15px;\n      }\n    }\n  <\/style>\n\n  <div class=\"ca-main\">\n    <div class=\"ca-eyebrow\">Interactive visual guide<\/div>\n\n    <h2 class=\"ca-title\">How to Read a Cluster Analysis Diagram<\/h2>\n\n    <p class=\"ca-lead\">\n      Explore three common visuals: a customer cluster plot, a hierarchical\n      dendrogram and an elbow plot. Each diagram illustrates a different\n      part of cluster analysis.\n    <\/p>\n\n    <div class=\"ca-caveat\">\n      <strong>Important context:<\/strong> The customer data is simulated.\n      The dendrogram and elbow plot are also illustrative examples, not\n      outputs from a fitted clustering model. Use them to understand how\n      to read the diagrams, not as evidence about real customers.\n    <\/div>\n\n    <div class=\"ca-tabs\" role=\"tablist\" aria-label=\"Choose a diagram\">\n      <button type=\"button\" class=\"ca-tab\" role=\"tab\"\n        aria-selected=\"true\" data-view=\"scatter\">\n        Figure 1 \u00b7 Customer clusters\n      <\/button>\n\n      <button type=\"button\" class=\"ca-tab\" role=\"tab\"\n        aria-selected=\"false\" data-view=\"tree\">\n        Figure 2 \u00b7 Dendrogram\n      <\/button>\n\n      <button type=\"button\" class=\"ca-tab\" role=\"tab\"\n        aria-selected=\"false\" data-view=\"elbow\">\n        Figure 3 \u00b7 Elbow plot\n      <\/button>\n    <\/div>\n\n    <section class=\"ca-panel\">\n      <div class=\"ca-head\">\n        <h3 class=\"ca-heading\" data-el=\"title\">Figure 1 \u00b7 400 simulated customers<\/h3>\n        <p class=\"ca-subtitle\" data-el=\"subtitle\">\n          Each dot represents a simulated customer. Hover over a dot to\n          inspect its values. You can also change the dot size to represent\n          a third variable.\n        <\/p>\n      <\/div>\n\n      <div class=\"ca-visual\">\n        <svg class=\"ca-chart\" data-el=\"chart\"\n          viewBox=\"0 0 760 440\" role=\"img\"\n          aria-label=\"Interactive cluster analysis diagram\"><\/svg>\n      <\/div>\n\n      <div class=\"ca-legend\" data-el=\"legend\"><\/div>\n\n      <div class=\"ca-body\">\n        <div class=\"ca-controls\" data-el=\"controls\"><\/div>\n\n        <div class=\"ca-actions\">\n          <button type=\"button\" class=\"ca-reset\" data-el=\"reset\">\n            Reset view\n          <\/button>\n        <\/div>\n\n        <p class=\"ca-status\" data-el=\"status\" aria-live=\"polite\">\n          Adjust a setting to explore the diagram.\n        <\/p>\n\n        <div class=\"ca-insight\">\n          <strong class=\"ca-insight-title\" data-el=\"insight-title\">\n            What to look for\n          <\/strong>\n          <p class=\"ca-insight-text\" data-el=\"insight\">\n            Read the axes first, then the colours. A cluster assignment\n            is the result of a method, not an objective label.\n          <\/p>\n        <\/div>\n\n        <p class=\"ca-caption\" data-el=\"caption\">\n          Figure 1: A cluster analysis diagram of simulated customers,\n          coloured by their assigned group.\n        <\/p>\n      <\/div>\n    <\/section>\n  <\/div>\n\n  <script>\n  (function () {\n    \"use strict\";\n\n    \/* All selectors are confined to this widget instance. *\/\n    var script = document.currentScript;\n    var root = script && script.closest(\"#cluster-analysis-widget\");\n\n    if (!root) {\n      root = document.getElementById(\"cluster-analysis-widget\");\n    }\n    if (!root || root.dataset.caReady === \"true\") return;\n    root.dataset.caReady = \"true\";\n\n    function get(name) {\n      return root.querySelector('[data-el=\"' + name + '\"]');\n    }\n\n    var colors = [\"#2864dc\", \"#0c9488\", \"#e28a2b\"];\n    var view = \"scatter\";\n    var showThird = false;\n    var cutPct = 70;\n    var elbowK = 3;\n    var linkage = \"ward\";\n    var seed = 17;\n\n    var plot = {\n      left: 70,\n      top: 32,\n      width: 635,\n      height: 330\n    };\n\n    function random() {\n      seed = (seed * 9301 + 49297) % 233280;\n      return seed \/ 233280;\n    }\n\n    function gaussian() {\n      var u = Math.max(random(), 0.0001);\n      var v = random();\n      return Math.sqrt(-2 * Math.log(u)) *\n        Math.cos(2 * Math.PI * v);\n    }\n\n    function makeCustomers() {\n      seed = 17;\n\n      var centers = [\n        [22, 28, 25],\n        [70, 30, 68],\n        [47, 74, 43]\n      ];\n\n      var rows = [];\n\n      for (var i = 0; i < 400; i++) {\n        var cluster = Math.floor(i \/ Math.ceil(400 \/ 3)) % 3;\n        var center = centers[cluster];\n        var spread = cluster === 1 ? 10 : 8;\n\n        var x = Math.max(\n          2, Math.min(98, center[0] + gaussian() * spread)\n        );\n\n        var y = Math.max(\n          2, Math.min(98, center[1] + gaussian() * spread * 0.82)\n        );\n\n        var third = Math.max(\n          2, Math.min(98, center[2] + gaussian() * spread * 1.1)\n        );\n\n        rows.push({\n          x: x,\n          y: y,\n          third: third,\n          cluster: cluster + 1,\n          id: i + 1\n        });\n      }\n\n      return rows;\n    }\n\n    var customers = makeCustomers();\n\n    function X(value) {\n      return plot.left + value \/ 100 * plot.width;\n    }\n\n    function Y(value) {\n      return plot.top + plot.height - value \/ 100 * plot.height;\n    }\n\n    function grid() {\n      var out = \"\";\n\n      for (var v = 0; v <= 100; v += 20) {\n        out +=\n          '<line x1=\"' + X(v) + '\" y1=\"' + plot.top +\n          '\" x2=\"' + X(v) + '\" y2=\"' + (plot.top + plot.height) +\n          '\" stroke=\"#e8edf5\"\/>' +\n\n          '<text x=\"' + X(v) + '\" y=\"' + (plot.top + plot.height + 22) +\n          '\" text-anchor=\"middle\" font-size=\"11\" fill=\"#77849a\">' +\n          v + '<\/text>' +\n\n          '<line x1=\"' + plot.left + '\" y1=\"' + Y(v) +\n          '\" x2=\"' + (plot.left + plot.width) + '\" y2=\"' + Y(v) +\n          '\" stroke=\"#e8edf5\"\/>' +\n\n          '<text x=\"' + (plot.left - 12) + '\" y=\"' + (Y(v) + 4) +\n          '\" text-anchor=\"end\" font-size=\"11\" fill=\"#77849a\">' +\n          v + '<\/text>';\n      }\n\n      return out;\n    }\n\n    function axes(xLabel, yLabel) {\n      return grid() +\n        '<rect x=\"' + plot.left + '\" y=\"' + plot.top +\n        '\" width=\"' + plot.width + '\" height=\"' + plot.height +\n        '\" fill=\"none\" stroke=\"#cbd5e3\"\/>' +\n\n        '<text x=\"' + (plot.left + plot.width \/ 2) +\n        '\" y=\"410\" text-anchor=\"middle\" font-size=\"12\" fill=\"#536179\">' +\n        xLabel + '<\/text>' +\n\n        '<text x=\"18\" y=\"' + (plot.top + plot.height \/ 2) +\n        '\" text-anchor=\"middle\" font-size=\"12\" fill=\"#536179\" ' +\n        'transform=\"rotate(-90 18 ' + (plot.top + plot.height \/ 2) + ')\">' +\n        yLabel + '<\/text>';\n    }\n\n    function scatterSvg() {\n      var out = axes(\n        \"Days since last purchase\",\n        \"Total spend (index)\"\n      );\n\n      customers.forEach(function (p) {\n        var radius = showThird ? 3 + p.third \/ 100 * 4 : 3.8;\n\n        out +=\n          '<circle class=\"ca-point\" tabindex=\"0\" role=\"img\" ' +\n          'aria-label=\"Customer ' + p.id +\n          ', days since purchase ' + Math.round(p.x) +\n          ', spend index ' + Math.round(p.y) +\n          ', third variable index ' + Math.round(p.third) + '\" ' +\n          'cx=\"' + X(p.x) + '\" cy=\"' + Y(p.y) +\n          '\" r=\"' + radius + '\" fill=\"' + colors[p.cluster - 1] +\n          '\" fill-opacity=\"0.8\" stroke=\"#fff\" stroke-width=\"1\">' +\n          '<title>Customer ' + p.id +\n          ' | Days since purchase: ' + Math.round(p.x) +\n          ' | Spend index: ' + Math.round(p.y) +\n          ' | Third variable index: ' + Math.round(p.third) +\n          '<\/title><\/circle>';\n      });\n\n      return out;\n    }\n\n    \/*\n     * This is a teaching illustration, not a calculated hierarchical\n     * clustering result. The selected cut changes its position only.\n     *\/\n    function treeSvg() {\n      var out =\n        '<rect x=\"60\" y=\"32\" width=\"650\" height=\"300\" rx=\"10\" ' +\n        'fill=\"#fafbfe\" stroke=\"#e0e6f0\"\/>' +\n        '<text x=\"385\" y=\"22\" text-anchor=\"middle\" font-size=\"12\" ' +\n        'font-weight=\"700\" fill=\"#536179\">' +\n        'Illustrative dendrogram \u00b7 merge height increases upward' +\n        '<\/text>';\n\n      var groups = [];\n\n      for (var i = 0; i < 30; i++) {\n        groups.push({\n          ids: [i],\n          x: 82 + i * 20.3,\n          y: 325\n        });\n      }\n\n      var merges = [];\n      var level = 0;\n\n      while (groups.length > 1) {\n        var next = [];\n\n        for (var j = 0; j < groups.length; j += 2) {\n          if (j + 1 >= groups.length) {\n            next.push(groups[j]);\n            continue;\n          }\n\n          var a = groups[j];\n          var b = groups[j + 1];\n          var height = Math.min(100, 8 + level * 8 + (j % 5) * 2);\n\n          merges.push({ a: a, b: b, height: height });\n\n          next.push({\n            ids: a.ids.concat(b.ids),\n            x: (a.x + b.x) \/ 2,\n            y: 325 - height * 2.45\n          });\n        }\n\n        groups = next;\n        level++;\n      }\n\n      merges.forEach(function (m) {\n        out +=\n          '<path d=\"M ' + m.a.x + ' ' + m.a.y +\n          ' V ' + (325 - m.height * 2.45) +\n          ' H ' + m.b.x +\n          ' V ' + m.b.y +\n          '\" fill=\"none\" stroke=\"#7d8aa1\" stroke-width=\"1.5\"\/>';\n      });\n\n      var cutY = 325 - cutPct \/ 100 * 245;\n\n      out +=\n        '<line x1=\"65\" x2=\"705\" y1=\"' + cutY + '\" y2=\"' + cutY +\n        '\" stroke=\"#d95757\" stroke-width=\"2.5\" stroke-dasharray=\"7 5\"\/>' +\n        '<rect x=\"69\" y=\"' + (cutY - 22) +\n        '\" width=\"92\" height=\"18\" rx=\"5\" fill=\"#fdeaea\"\/>' +\n        '<text x=\"115\" y=\"' + (cutY - 9) +\n        '\" text-anchor=\"middle\" font-size=\"10\" fill=\"#a12c2c\">' +\n        'Cut: ' + cutPct + '%<\/text>';\n\n      for (var k = 0; k < 30; k++) {\n        out +=\n          '<circle cx=\"' + (82 + k * 20.3) +\n          '\" cy=\"325\" r=\"3.4\" fill=\"' + colors[k % 3] + '\"\/>' +\n          '<text x=\"' + (82 + k * 20.3) +\n          '\" y=\"343\" text-anchor=\"middle\" font-size=\"8\" fill=\"#77849a\">' +\n          (k + 1) + '<\/text>';\n      }\n\n      out +=\n        '<text x=\"385\" y=\"380\" text-anchor=\"middle\" font-size=\"11\" ' +\n        'fill=\"#536179\">30 sample positions \u00b7 illustrative merge structure<\/text>';\n\n      return out;\n    }\n\n    function elbowSvg() {\n      var out = axes(\n        \"Number of clusters (k)\",\n        \"Within-cluster sum of squares (relative)\"\n      );\n\n      var values = [100, 61, 34, 29, 25, 22, 20, 18, 17, 16];\n      var path = \"\";\n\n      values.forEach(function (value, index) {\n        path += (index === 0 ? \"M \" : \" L \") +\n          X(index \/ 9 * 100) + \" \" + Y(value);\n      });\n\n      out +=\n        '<path d=\"' + path +\n        '\" fill=\"none\" stroke=\"#2864dc\" stroke-width=\"3\" ' +\n        'stroke-linejoin=\"round\"\/>';\n\n      values.forEach(function (value, index) {\n        var px = X(index \/ 9 * 100);\n        var py = Y(value);\n        var active = index + 1 === elbowK;\n\n        out +=\n          '<circle cx=\"' + px + '\" cy=\"' + py +\n          '\" r=\"' + (active ? 8 : 4.5) +\n          '\" fill=\"' + (active ? \"#e28a2b\" : \"#2864dc\") +\n          '\" stroke=\"#fff\" stroke-width=\"2\">' +\n          '<title>k = ' + (index + 1) +\n          ', relative WCSS = ' + value + '<\/title><\/circle>';\n      });\n\n      var selectedX = X((elbowK - 1) \/ 9 * 100);\n      var selectedY = Y(values[elbowK - 1]);\n      var labelX = Math.min(selectedX + 9, 600);\n      var labelY = Math.max(selectedY - 34, 40);\n\n      out +=\n        '<line x1=\"' + selectedX + '\" y1=\"' + plot.top +\n        '\" x2=\"' + selectedX + '\" y2=\"' + (plot.top + plot.height) +\n        '\" stroke=\"#e28a2b\" stroke-dasharray=\"5 5\" stroke-width=\"2\"\/>' +\n        '<rect x=\"' + labelX + '\" y=\"' + labelY +\n        '\" width=\"92\" height=\"23\" rx=\"6\" fill=\"#fff1df\" stroke=\"#f1c48e\"\/>' +\n        '<text x=\"' + Math.min(selectedX + 55, 646) +\n        '\" y=\"' + Math.max(selectedY - 19, 55) +\n        '\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"700\" ' +\n        'fill=\"#8b4e0b\">Selected k=' + elbowK + '<\/text>';\n\n      return out;\n    }\n\n    function setText(name, value) {\n      get(name).textContent = value;\n    }\n\n    function render() {\n      var title, subtitle, caption, legend, controls;\n      var insightTitle, insight;\n\n      if (view === \"scatter\") {\n        title = \"Figure 1 \u00b7 400 simulated customers\";\n\n        subtitle =\n          \"Each dot represents one customer. Hover over a dot to inspect \" +\n          \"its values. Change dot size to represent the third variable.\";\n\n        caption =\n          \"Figure 1: Cluster analysis diagram of simulated customers. \" +\n          \"The colours indicate the three groups built into this example.\";\n\n        legend = colors.map(function (color, i) {\n          return '<span class=\"ca-key\"><i class=\"ca-swatch\" style=\"background:' +\n            color + '\"><\/i>Cluster ' + (i + 1) + '<\/span>';\n        }).join(\"\");\n\n        legend +=\n          '<span class=\"ca-key\"><i class=\"ca-swatch\" style=\"background:#17233b\"><\/i>' +\n          (showThird ? \"Dot size = third variable index\" : \"Dot size = constant\") +\n          '<\/span>';\n\n        controls =\n          '<div class=\"ca-control\">' +\n            '<label class=\"ca-check\">' +\n              '<input type=\"checkbox\" data-control=\"third\" ' +\n              (showThird ? \"checked\" : \"\") + '>' +\n              '<span>Show third variable through dot size<\/span>' +\n            '<\/label>' +\n          '<\/div>';\n\n        insightTitle = \"What to look for\";\n\n        insight =\n          \"Read the axes first, then the colours. Points near group \" +\n          \"boundaries deserve a closer look. The group labels are part \" +\n          \"of this simulated example, not confirmed customer types.\";\n\n        get(\"chart\").innerHTML = scatterSvg();\n\n      } else if (view === \"tree\") {\n        title = \"Figure 2 \u00b7 Dendrogram\";\n\n        subtitle =\n          \"Read from the bottom upwards. Branches show merges, while \" +\n          \"their vertical positions represent illustrative merge heights.\";\n\n        caption =\n          \"Figure 2: Illustrative dendrogram. The merge structure is \" +\n          \"not calculated from customer data, and the cut line is not \" +\n          \"a statistically validated threshold.\";\n\n        legend =\n          '<span class=\"ca-key\"><i class=\"ca-swatch\" style=\"background:#7d8aa1\"><\/i>Merge branches<\/span>' +\n          '<span class=\"ca-key\"><i class=\"ca-swatch\" style=\"background:#d95757\"><\/i>Selected cut height<\/span>';\n\n        controls =\n          '<div class=\"ca-control\">' +\n            '<label for=\"ca-cut\">' +\n              '<span>Cut height<\/span><span data-el=\"cutval\">' +\n              cutPct + '%<\/span>' +\n            '<\/label>' +\n            '<input id=\"ca-cut\" data-control=\"cut\" type=\"range\" ' +\n              'min=\"15\" max=\"95\" value=\"' + cutPct + '\">' +\n          '<\/div>' +\n\n          '<div class=\"ca-control\">' +\n            '<label for=\"ca-linkage\"><span>Linkage concept<\/span><\/label>' +\n            '<select id=\"ca-linkage\" data-control=\"linkage\">' +\n              '<option value=\"ward\" ' +\n                (linkage === \"ward\" ? \"selected\" : \"\") +\n                '>Ward linkage<\/option>' +\n              '<option value=\"average\" ' +\n                (linkage === \"average\" ? \"selected\" : \"\") +\n                '>Average linkage<\/option>' +\n              '<option value=\"complete\" ' +\n                (linkage === \"complete\" ? \"selected\" : \"\") +\n                '>Complete linkage<\/option>' +\n            '<\/select>' +\n          '<\/div>';\n\n        insightTitle = \"What the cut means\";\n\n        insight =\n          \"A lower cut generally leaves more separate groups, while a \" +\n          \"higher cut joins groups together. Ward, average and complete \" +\n          \"linkage use different rules to decide which groups merge. \" +\n          \"This illustrative tree does not recalculate for the selected rule.\";\n\n        get(\"chart\").innerHTML = treeSvg();\n\n      } else {\n        title = \"Figure 3 \u00b7 Elbow plot\";\n\n        subtitle =\n          \"The curve illustrates how within-cluster sum of squares \" +\n          \"can fall as the number of clusters increases.\";\n\n        caption =\n          \"Figure 3: Illustrative elbow plot. These values are made up \" +\n          \"for demonstration and are not calculated from the customer chart.\";\n\n        legend =\n          '<span class=\"ca-key\"><i class=\"ca-swatch\" style=\"background:#2864dc\"><\/i>Relative within-cluster sum of squares<\/span>' +\n          '<span class=\"ca-key\"><i class=\"ca-swatch\" style=\"background:#e28a2b\"><\/i>Selected k<\/span>';\n\n        controls =\n          '<div class=\"ca-control\">' +\n            '<label for=\"ca-elbow\">' +\n              '<span>Candidate cluster count (k)<\/span>' +\n              '<span data-el=\"elbowval\">' + elbowK + '<\/span>' +\n            '<\/label>' +\n            '<input id=\"ca-elbow\" data-control=\"elbow\" type=\"range\" ' +\n              'min=\"1\" max=\"10\" value=\"' + elbowK + '\">' +\n          '<\/div>';\n\n        insightTitle = \"Treat the elbow as a clue, not a verdict\";\n\n        insight =\n          \"The curve drops sharply up to three clusters and then flattens. \" +\n          \"That makes three a plausible candidate in this illustration. \" +\n          \"Real data may not have a clear elbow, so use other checks and \" +\n          \"the purpose of the analysis before choosing k.\";\n\n        get(\"chart\").innerHTML = elbowSvg();\n      }\n\n      setText(\"title\", title);\n      setText(\"subtitle\", subtitle);\n      setText(\"caption\", caption);\n      get(\"legend\").innerHTML = legend;\n      get(\"controls\").innerHTML = controls;\n      setText(\"insight-title\", insightTitle);\n      setText(\"insight\", insight);\n      setText(\"status\", \"Adjust a setting to explore the diagram.\");\n\n      var third = get(\"controls\").querySelector('[data-control=\"third\"]');\n      if (third) {\n        third.addEventListener(\"change\", function () {\n          showThird = third.checked;\n          render();\n        });\n      }\n\n      var cut = get(\"controls\").querySelector('[data-control=\"cut\"]');\n      if (cut) {\n        cut.addEventListener(\"input\", function () {\n          cutPct = Number(cut.value);\n          var valueLabel = get(\"controls\").querySelector('[data-el=\"cutval\"]');\n          if (valueLabel) valueLabel.textContent = cutPct + \"%\";\n          get(\"chart\").innerHTML = treeSvg();\n        });\n      }\n\n      var link = get(\"controls\").querySelector('[data-control=\"linkage\"]');\n      if (link) {\n        link.addEventListener(\"change\", function () {\n          linkage = link.value;\n          setText(\n            \"status\",\n            \"Linkage selection changed. The illustrative branch structure remains the same.\"\n          );\n        });\n      }\n\n      var elbow = get(\"controls\").querySelector('[data-control=\"elbow\"]');\n      if (elbow) {\n        elbow.addEventListener(\"input\", function () {\n          elbowK = Number(elbow.value);\n          var valueLabel = get(\"controls\").querySelector('[data-el=\"elbowval\"]');\n          if (valueLabel) valueLabel.textContent = elbowK;\n          get(\"chart\").innerHTML = elbowSvg();\n        });\n      }\n    }\n\n    root.querySelectorAll(\".ca-tab\").forEach(function (button) {\n      button.addEventListener(\"click\", function () {\n        view = button.getAttribute(\"data-view\");\n\n        root.querySelectorAll(\".ca-tab\").forEach(function (tab) {\n          tab.setAttribute(\n            \"aria-selected\",\n            String(tab === button)\n          );\n        });\n\n        render();\n      });\n    });\n\n    get(\"reset\").addEventListener(\"click\", function () {\n      showThird = false;\n      cutPct = 70;\n      elbowK = 3;\n      linkage = \"ward\";\n      render();\n    });\n\n    render();\n  })();\n  <\/script>\n<\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Cluster Analysis Tools<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Cluster analysis tools help you group similar data points, uncover hidden patterns, and make sense of large datasets without assigning categories in advance. Tools such as Python\u2019s scikit-learn, R, Excel and specialist platforms like KNIME support methods such as K-means, hierarchical clustering and DBSCAN. The right choice depends on your dataset size, the complexity of the patterns you want to find, and how much control you need over the analysis.&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/imarticus.org\/blog\/python-for-data-science\/\">Python<\/a> is the most common choice, with scikit-learn and SciPy covering k-means, hierarchical methods and DBSCAN.<\/li>\n\n\n\n<li><a href=\"https:\/\/imarticus.org\/blog\/what-is-r-programming-for-data-science\/\">R<\/a> has kmeans and hclust built in.<\/li>\n\n\n\n<li>SPSS suits people who prefer menus, and KNIME offers a drag-and-drop route with no code.<\/li>\n\n\n\n<li>In <a href=\"https:\/\/imarticus.org\/blog\/mastering-excel-for-data-analysis\/\">Excel<\/a>, you are limited to hand-built formulas or an add-in.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">One newer direction is worth watching. Text embeddings, which are lists of numbers that represent the meaning of a document, can be clustered with the same methods to group documents by topic. The tools change. The four decisions do not. &nbsp;<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Moving into data science and AI does not always require a technical background. What matters is building the right foundations, from working with data and statistics to applying machine learning and AI tools to practical problems. The learning curve becomes more manageable when concepts are introduced step by step and reinforced through hands-on projects.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Go From Zero Tech to AI Expert with Executive Postgraduate Program in Data Science &amp; AI\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/4icKVdph8jQ?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>How To Perform Cluster Analysis Step By Step<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Plenty of pages answer what is cluster analysis in data mining. Far fewer show the workflow around the algorithm, and the workflow is where the work is. These seven steps are the four decisions with some housework around them.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Write down the decision the groups will feed.<\/strong> &#8220;Segment customers for the March email campaign&#8221; is a question. &#8220;Find clusters&#8221; is not.<\/li>\n\n\n\n<li><strong>Choose the variables.<\/strong> Pick columns that relate to the question and note the type of each. Mixed types of data in cluster analysis need extra care in step 4.<\/li>\n\n\n\n<li><strong>Clean and scale.<\/strong> Fill or drop missing values, look at outliers, then standardise. A distance-based method cannot know that a rupee and a day are different things.<\/li>\n\n\n\n<li><strong>Pick a distance measure.<\/strong> Check which of the types of data in cluster analysis in data mining you are holding, then match the measure using the table above.<\/li>\n\n\n\n<li><strong>Pick an algorithm.<\/strong> Start with a simple one. Partitioning methods in cluster analysis, k-means first among them, suit big and roughly round data. Hierarchical methods suit exploring, and DBSCAN suits odd shapes and noise.<\/li>\n\n\n\n<li><strong>Choose the number of clusters.<\/strong> Try a range, read the elbow plot and the silhouette scores, then ask whether you can describe each group in a sentence. Often you end up with fewer clusters than your first guess, and that is fine.<\/li>\n\n\n\n<li><strong>Validate and profile.<\/strong> Rerun with another random seed. If the groups fall apart, they were never solid. Then summarise each cluster by its averages and give it a name.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Can you do this in Excel?<\/strong> Standard Excel has no one-click clustering command. People build k-means by hand with formulas, use an add-in such as XLSTAT, or use Python inside Excel where their Microsoft 365 plan allows it. Past a few hundred rows, I would use Python or R.&nbsp;&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"597\" src=\"https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/steps-in-cluster-analysis-1024x597.webp\" alt=\"cluster analysis steps\" class=\"wp-image-278516\" srcset=\"https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/steps-in-cluster-analysis-1024x597.webp 1024w, https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/steps-in-cluster-analysis-300x175.webp 300w, https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/steps-in-cluster-analysis-768x448.webp 768w, https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/steps-in-cluster-analysis-1536x896.webp 1536w, https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/steps-in-cluster-analysis.webp 1642w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Cluster Analysis Example: Customer Segmentation<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Caveat first, because I would want it from anyone showing me results. This data is simulated, built to look like the customers of a small online shop. There are 400 rows and three numbers per row: days since the last purchase, number of purchases, and total spend in rupees. I put three groups in on purpose, so I know what a good answer looks like. You will not have that luxury on real data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First question: how many groups? Inertia, the within-cluster sum of squares, fell from 371.3 at two clusters to 147.7 at three, then only to 122.4 at four. That bend at three is the elbow.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Silhouette scores were 0.635 for two clusters, 0.641 for three and 0.544 for four. Look at that first pair. Silhouette barely separated two from three, and the elbow did the deciding. On real data, I would want a third signal, plus a check that the groups make business sense. So I went with three.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Metric<\/strong><\/td><td><strong>Cluster 0<\/strong><\/td><td><strong>Cluster 1<\/strong><\/td><td><strong>Cluster 2<\/strong><\/td><\/tr><tr><td><strong>Customers<\/strong><\/td><td>184<\/td><td>97<\/td><td>119<\/td><\/tr><tr><td><strong>Average days since last purchase<\/strong><\/td><td>59.5<\/td><td>155.9<\/td><td>14.7<\/td><\/tr><tr><td><strong>Average purchases<\/strong><\/td><td>4.7<\/td><td>1.6<\/td><td>13.9<\/td><\/tr><tr><td><strong>Average spend (INR)<\/strong><\/td><td>2,451<\/td><td>891<\/td><td>9,159<\/td><\/tr><tr><td><strong>What I would call it<\/strong><\/td><td>Steady middle<\/td><td>Drifting away<\/td><td>Loyal big spenders<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The cluster numbers are arbitrary labels. Naming them is your job, and so is deciding what to do about each one. Reward the loyal group, nudge the steady middle, and win back the drifting customers with a clear offer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now back to the opening. The second run was the same k-means with three clusters on the raw numbers, with no scaling. Group sizes came out at 65, 281 and 54, against 184, 97 and 119 with scaling.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Spend is measured in thousands of rupees and recency in tens of days, so spend dominated every distance. Same data, same k, different answer. Scaling is not decoration. For the dendrogram in Figure 2 I tried hierarchical cluster analysis on a sample of just 30 customers. All 400 would have made an unreadable chart.&nbsp; &nbsp;<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"has-background wp-block-paragraph\" style=\"background-color:#7bdbb426\"><strong><em>Did You Know?<\/em><\/strong><strong><em><br><\/em><\/strong><em>Some clustering algorithms can leave data points unassigned to any cluster. DBSCAN labels points in low-density regions as noise instead of forcing every observation into a group. This can be useful when a dataset contains outliers or naturally separated dense regions. (<\/em><a href=\"https:\/\/scikit-learn.org\/stable\/modules\/generated\/sklearn.cluster.DBSCAN.html\"><em>Source<\/em><\/a><em>)&nbsp; &nbsp;<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Where Is Cluster Analysis Used?<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Wherever there are many records and no ready-made categories, cluster analysis in data mining projects tend to appear. Marketing gets the attention. I find the quieter uses more interesting.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>What gets grouped<\/strong><\/td><td><strong>Why it helps<\/strong><\/td><\/tr><tr><td><strong>Marketing<\/strong><\/td><td>Customers by behaviour, spend or preferences<\/td><td>Targeted offers and messages<\/td><\/tr><tr><td><strong>Finance<\/strong><\/td><td>Borrowers by risk, and unusual transactions<\/td><td>Credit decisions and fraud checks<\/td><\/tr><tr><td><strong>Healthcare<\/strong><\/td><td>Patients with similar symptoms or traits<\/td><td>Study groups and treatment research<\/td><\/tr><tr><td><strong>Biology and botany<\/strong><\/td><td>Genes, proteins or plant specimens by measured traits<\/td><td>Classification and disease research<\/td><\/tr><tr><td><strong>Psychology<\/strong><\/td><td>People by symptom or questionnaire scores<\/td><td>Spotting typical profiles<\/td><\/tr><tr><td><strong>Education<\/strong><\/td><td>Students by grades and engagement<\/td><td>Finding who needs extra support<\/td><\/tr><tr><td><strong>Image processing<\/strong><\/td><td>Pixels with similar colour or texture<\/td><td>Separating objects from backgrounds<\/td><\/tr><tr><td><strong>Real estate<\/strong><\/td><td>Properties by location, size and price<\/td><td>Spotting neighbourhood patterns<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Psychology papers lean on cluster analysis in <a href=\"https:\/\/imarticus.org\/blog\/statistics-for-data-science\/\">statistics<\/a> packages such as SPSS to group patients by symptom profile. Every cluster analysis example above has the same shape: many records, no labels, and a decision waiting on the groups. &nbsp;<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"has-background wp-block-paragraph\" style=\"background-color:#7bdbb426\"><strong>Also Read:<\/strong> How Long Does a <a href=\"https:\/\/imarticus.org\/blog\/data-analyst-course\/\">Data Analyst Course<\/a> Take to Complete?<strong>&nbsp;<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>How To Validate Cluster Analysis Results<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">There is no answer key, so I check four things, and I trust the set more than any single one.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>The elbow.<\/strong> Look for the point where extra clusters stop tightening the groups much.<\/li>\n\n\n\n<li><strong>The silhouette score.<\/strong> It ranges from -1 to 1. Values near 1 mean points sit well inside their own cluster and far from the others. Peter Rousseeuw introduced it in 1987, and the <a href=\"https:\/\/scikit-learn.org\/stable\/modules\/generated\/sklearn.metrics.silhouette_score.html\">scikit-learn silhouette documentation<\/a> explains the calculation.<\/li>\n\n\n\n<li><strong>Stability.<\/strong> Rerun with different random seeds, or on a random subset. If the groups fall apart, they were not solid.<\/li>\n\n\n\n<li><strong>Usefulness.<\/strong> Can you name each cluster in a sentence, and does each one suggest a different action?<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Then write your assumptions next to the result: variables, scaling, distance, algorithm and k. Those are the four decisions. Someone who changes one may get different clusters, and they should know why. Put simply, a cluster result with its decisions missing is half a result.&nbsp;&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Advantages, Limitations And Common Mistakes<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The upside is real.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You need no labels<\/li>\n\n\n\n<li>You can find groups nobody thought to look for<\/li>\n\n\n\n<li>The methods scale from a spreadsheet to millions of rows.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Now the limits.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You usually choose the number of clusters yourself<\/li>\n\n\n\n<li>The algorithm will hand you that many even when the data holds no real groups.<\/li>\n\n\n\n<li>Results move with scaling, distance and starting points, so one run proves little.<\/li>\n\n\n\n<li>K-means expects roughly round groups and chops curved ones into pieces. Outliers drag its centres around.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Cluster analysis in statistics has a quiet weakness: it will find groups in random noise. The algorithm always returns something. It&#8217;s easy to fall for a tidy chart and stop checking. The mistakes I would watch for are the boring ones.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Skipping scaling.<\/li>\n\n\n\n<li>Choosing k to match what you hoped to see.<\/li>\n\n\n\n<li>Clustering on every column because it is there.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Treating the output as a fact instead of a view. Never rerunning it. I would rather see four variables you can defend than twelve you cannot.&nbsp;<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"has-background wp-block-paragraph\" style=\"background-color:#7bdbb426\"><strong>Also Read:<\/strong> How Do You Handle Missing Values During <a href=\"https:\/\/imarticus.org\/blog\/data-preprocessing\/\">Data Preprocessing<\/a>?<strong>&nbsp; &nbsp;<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>How Cluster Analysis Moves From Theory To Practice With Imarticus Learning<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Knowing how K-means works is one thing. Using it to group customers, interpret the patterns and explain what a business can do with those findings is a different skill. That practical step is built into Imarticus Learning\u2019s <a href=\"https:\/\/imarticus.org\/postgraduate-program-in-data-science-analytics\/\"><strong>data analytics course<\/strong><\/a>. Its machine learning curriculum covers K-means clustering, hierarchical clustering and RFM analysis, with a dedicated project on customer segmentation using K-means. The course also offers:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>35+ tools and projects to build practical experience across data science and analytics.<\/li>\n\n\n\n<li>Advanced Data Science and AI internships where learners can tackle real-world challenges.<\/li>\n\n\n\n<li>A job-ready project portfolio to demonstrate their work, rather than relying on course completion alone.<\/li>\n\n\n\n<li>GenAI training that includes using AI tools for code generation, debugging and statistical analysis.<\/li>\n\n\n\n<li>10 guaranteed interviews with companies, as advertised on the course page. Review the programme\u2019s terms to understand the eligibility and conditions.<\/li>\n\n\n\n<li>NSDC certification on successful completion, as stated on the programme page.<\/li>\n\n\n\n<li>A choice of learning format: classroom or live online, with six-month weekday and ten-month weekend options.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For someone building a career in analytics, the customer segmentation project is the most relevant starting point. It connects the concept discussed in this article to a task you may need to explain in a project review or job interview.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>FAQs About Cluster Analysis<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">From choosing the right clustering method to interpreting results and handling outliers, these answers clear up frequently asked questions about cluster analysis and its practical uses.&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>What is an example of cluster analysis?<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let us consider the following example of Cluster Analysis: A retailer grouping customers by how recently, how often and how much they buy is a standard cluster analysis example. The result might be loyal big spenders, a steady middle and lapsed buyers, each getting a different marketing approach.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>What are the three types of cluster analysis?<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The three most common types of cluster analysis are partitioning (such as k-means), hierarchical (agglomerative or divisive) and density-based (such as DBSCAN). Grid-based, model-based and fuzzy methods also exist, so three is a convenient grouping in cluster analysis, not a fixed rule.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>How can I perform cluster analysis in Excel?<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You cannot perform cluster analysis in Excel directly, since there is no one-click clustering command in Excel. However, you can do so, by building k-means by hand with formulas, use an add-in such as XLSTAT, or run Python inside Excel where your plan allows. For bigger cluster analysis work, Python is easier, and Imarticus Learning&#8217;s data analytics course is one place to learn it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>What is cluster analysis in marketing?<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In marketing, cluster analysis groups customers by behaviour, spend or preferences, so each group gets its own message, offer or product. It turns one large customer list into a few usable segments. Imarticus Learning&#8217;s data analytics course is one way for marketers to pick up the skills.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>What is cluster analysis and its types?<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Cluster analysis groups similar records without using labels. Its main types are partitioning, hierarchical, density-based, grid-based and model-based methods, plus fuzzy clustering. Each suits different data: k-means for compact groups, DBSCAN for odd shapes, hierarchical when you want a tree.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>How to apply cluster analysis?<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">To apply cluster analysis, define the question, choose variables, clean and scale them, pick a distance measure and an algorithm, choose the number of clusters, then validate and profile the groups. Imarticus Learning&#8217;s data analytics course offers structured Python practice for this.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Where is cluster analysis used?<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Cluster analysis is used in marketing segmentation, finance risk grouping and fraud checks, healthcare, biology and botany, psychology, education, image processing and real estate. Anyone building an analytics career, including through Imarticus Learning, will meet it often.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>What is the main goal of cluster analysis?<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The main goal of cluster analysis is to find natural groups in data, so records in a group are similar and records in different groups differ. It turns a large unlabelled table into a small set of segments you can understand and act on.&nbsp; &nbsp;<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Build Practical Skills in Cluster Analysis&nbsp;<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Cluster analysis is useful when a dataset contains patterns that are difficult to spot by looking at individual records. It can help you group customers by buying behaviour, identify similar research subjects or find recurring patterns in operational data. The value lies in what those groups reveal, not in how many clusters an algorithm produces.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There is one check worth keeping in mind: <strong>a cluster is a statistical grouping, not an explanation in itself.<\/strong> You still need to examine the characteristics of each group, test whether the patterns hold up and decide whether they make sense in the real world.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For students looking to build a career in analytics, this is where practical work matters. Working with tools such as Python, SQL and machine learning methods can help you move from knowing how clustering works to applying it to business problems. Imarticus Learning\u2019s <a href=\"https:\/\/imarticus.org\/postgraduate-program-in-data-science-analytics\/\"><strong>Data Analytics Course<\/strong><\/a> includes K-means and hierarchical clustering, alongside a customer segmentation project using K-means. It is one option to consider if you want structured training that connects analytical concepts with project work.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ultimately, good cluster analysis does more than sort data into groups. It helps you see patterns clearly, question your assumptions and make decisions based on evidence rather than guesswork.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>What separates K-means from hierarchical clustering? See how cluster analysis methods group data and where each fits.<\/p>\n","protected":false},"author":1,"featured_media":278518,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"om_disable_all_campaigns":false,"_lmt_disableupdate":"","_lmt_disable":"","_monsterinsights_skip_tracking":false,"footnotes":""},"categories":[5957],"tags":[],"class_list":["post-278514","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-data-analytics"],"acf":{"youtube-url-id":"","publised_date":"","ls_key":"PG - Analytics","recommended_posts":""},"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"Start with cluster analysis basics, then explore common methods, data types, worked examples and applications in data science.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Imarticus Learning\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/imarticus.org\/blog\/cluster-analysis\/\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_GB\" \/>\n\t\t<meta property=\"og:site_name\" content=\"Imarticus Blog -\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"Cluster Analysis for Beginners With Practical Examples\" \/>\n\t\t<meta property=\"og:description\" content=\"Start with cluster analysis basics, then explore common methods, data types, worked examples and applications in data science.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/imarticus.org\/blog\/cluster-analysis\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2026-10-14T14:08:51+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2026-10-15T07:02:48+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/ImarticusLearning\/\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n\t\t<meta name=\"twitter:site\" content=\"@imarticus\" \/>\n\t\t<meta name=\"twitter:title\" content=\"Cluster Analysis for Beginners With Practical Examples\" \/>\n\t\t<meta name=\"twitter:description\" content=\"Start with cluster analysis basics, then explore common methods, data types, worked examples and applications in data science.\" \/>\n\t\t<meta name=\"twitter:creator\" content=\"@imarticus\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"BlogPosting\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/cluster-analysis\\\/#blogposting\",\"name\":\"Cluster Analysis for Beginners With Practical Examples\",\"headline\":\"A Guide To Cluster Analysis: Meaning, Types, And Examples\",\"author\":{\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/author\\\/imarticus\\\/#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/#organization\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/cluster-analysis.webp\",\"width\":1200,\"height\":630},\"datePublished\":\"2026-10-14T19:38:51+05:30\",\"dateModified\":\"2026-10-15T12:32:48+05:30\",\"inLanguage\":\"en-GB\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/cluster-analysis\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/cluster-analysis\\\/#webpage\"},\"articleSection\":\"Data Analytics\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/cluster-analysis\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/imarticus.org\\\/blog\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/category\\\/data-analytics\\\/#listItem\",\"name\":\"Data Analytics\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/category\\\/data-analytics\\\/#listItem\",\"position\":2,\"name\":\"Data Analytics\",\"item\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/category\\\/data-analytics\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/cluster-analysis\\\/#listItem\",\"name\":\"A Guide To Cluster Analysis: Meaning, Types, And Examples\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/cluster-analysis\\\/#listItem\",\"position\":3,\"name\":\"A Guide To Cluster Analysis: Meaning, Types, And Examples\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/category\\\/data-analytics\\\/#listItem\",\"name\":\"Data Analytics\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/#organization\",\"name\":\"Imarticus Learning\",\"description\":\"Imarticus Learning is the leading institute for career-focused finance and tech programs. Looking for an investment banking course in Mumbai? Our Certified Investment Banking Operations Program (CIBOP) offers industry-leading placements with 100% Job Assurance, making it one of the most sought-after investment banking courses in Mumbai. Aspiring data professionals can enrol in our data science course in Mumbai, the Postgraduate Program in Data Science &amp; Analytics with GenAI (PGA), designed to deliver the highest salaries and a vast hiring network. As a top destination for data science training in Mumbai, we offer live training, hands-on projects &amp; guaranteed outcomes. Imarticus Learning, your launchpad for high-impact careers.\",\"url\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/\",\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/ImarticusLearning\\\/\",\"https:\\\/\\\/x.com\\\/imarticus\",\"https:\\\/\\\/www.instagram.com\\\/imarticus\\\/\",\"https:\\\/\\\/www.youtube.com\\\/@ImarticusLearningInstitute\",\"https:\\\/\\\/in.linkedin.com\\\/company\\\/imarticuslearning\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/author\\\/imarticus\\\/#author\",\"url\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/author\\\/imarticus\\\/\",\"name\":\"Imarticus Learning\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/cluster-analysis\\\/#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/26c0ffd94601c4078ba4c61e5b9dd95dbb2872f64fd398e2c5d020e8ff0eb581?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"Imarticus Learning\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/cluster-analysis\\\/#webpage\",\"url\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/cluster-analysis\\\/\",\"name\":\"Cluster Analysis for Beginners With Practical Examples\",\"description\":\"Start with cluster analysis basics, then explore common methods, data types, worked examples and applications in data science.\",\"inLanguage\":\"en-GB\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/cluster-analysis\\\/#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/author\\\/imarticus\\\/#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/author\\\/imarticus\\\/#author\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/cluster-analysis.webp\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/cluster-analysis\\\/#mainImage\",\"width\":1200,\"height\":630},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/cluster-analysis\\\/#mainImage\"},\"datePublished\":\"2026-10-14T19:38:51+05:30\",\"dateModified\":\"2026-10-15T12:32:48+05:30\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/\",\"name\":\"Imarticus Learning\",\"inLanguage\":\"en-GB\",\"publisher\":{\"@id\":\"https:\\\/\\\/imarticus.org\\\/blog\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<script type=\"text\/javascript\">\n\t\t\t(function(c,l,a,r,i,t,y){\n\t\t\tc[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};t=l.createElement(r);t.async=1;\n\t\t\tt.src=\"https:\/\/www.clarity.ms\/tag\/\"+i+\"?ref=aioseo\";y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);\n\t\t})(window, document, \"clarity\", \"script\", \"p9rn6xgm87\");\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"Cluster Analysis for Beginners With Practical Examples","description":"Start with cluster analysis basics, then explore common methods, data types, worked examples and applications in data science.","canonical_url":"https:\/\/imarticus.org\/blog\/cluster-analysis\/","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"BlogPosting","@id":"https:\/\/imarticus.org\/blog\/cluster-analysis\/#blogposting","name":"Cluster Analysis for Beginners With Practical Examples","headline":"A Guide To Cluster Analysis: Meaning, Types, And Examples","author":{"@id":"https:\/\/imarticus.org\/blog\/author\/imarticus\/#author"},"publisher":{"@id":"https:\/\/imarticus.org\/blog\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/cluster-analysis.webp","width":1200,"height":630},"datePublished":"2026-10-14T19:38:51+05:30","dateModified":"2026-10-15T12:32:48+05:30","inLanguage":"en-GB","mainEntityOfPage":{"@id":"https:\/\/imarticus.org\/blog\/cluster-analysis\/#webpage"},"isPartOf":{"@id":"https:\/\/imarticus.org\/blog\/cluster-analysis\/#webpage"},"articleSection":"Data Analytics"},{"@type":"BreadcrumbList","@id":"https:\/\/imarticus.org\/blog\/cluster-analysis\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/imarticus.org\/blog#listItem","position":1,"name":"Home","item":"https:\/\/imarticus.org\/blog","nextItem":{"@type":"ListItem","@id":"https:\/\/imarticus.org\/blog\/category\/data-analytics\/#listItem","name":"Data Analytics"}},{"@type":"ListItem","@id":"https:\/\/imarticus.org\/blog\/category\/data-analytics\/#listItem","position":2,"name":"Data Analytics","item":"https:\/\/imarticus.org\/blog\/category\/data-analytics\/","nextItem":{"@type":"ListItem","@id":"https:\/\/imarticus.org\/blog\/cluster-analysis\/#listItem","name":"A Guide To Cluster Analysis: Meaning, Types, And Examples"},"previousItem":{"@type":"ListItem","@id":"https:\/\/imarticus.org\/blog#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/imarticus.org\/blog\/cluster-analysis\/#listItem","position":3,"name":"A Guide To Cluster Analysis: Meaning, Types, And Examples","previousItem":{"@type":"ListItem","@id":"https:\/\/imarticus.org\/blog\/category\/data-analytics\/#listItem","name":"Data Analytics"}}]},{"@type":"Organization","@id":"https:\/\/imarticus.org\/blog\/#organization","name":"Imarticus Learning","description":"Imarticus Learning is the leading institute for career-focused finance and tech programs. Looking for an investment banking course in Mumbai? Our Certified Investment Banking Operations Program (CIBOP) offers industry-leading placements with 100% Job Assurance, making it one of the most sought-after investment banking courses in Mumbai. Aspiring data professionals can enrol in our data science course in Mumbai, the Postgraduate Program in Data Science &amp; Analytics with GenAI (PGA), designed to deliver the highest salaries and a vast hiring network. As a top destination for data science training in Mumbai, we offer live training, hands-on projects &amp; guaranteed outcomes. Imarticus Learning, your launchpad for high-impact careers.","url":"https:\/\/imarticus.org\/blog\/","sameAs":["https:\/\/www.facebook.com\/ImarticusLearning\/","https:\/\/x.com\/imarticus","https:\/\/www.instagram.com\/imarticus\/","https:\/\/www.youtube.com\/@ImarticusLearningInstitute","https:\/\/in.linkedin.com\/company\/imarticuslearning"]},{"@type":"Person","@id":"https:\/\/imarticus.org\/blog\/author\/imarticus\/#author","url":"https:\/\/imarticus.org\/blog\/author\/imarticus\/","name":"Imarticus Learning","image":{"@type":"ImageObject","@id":"https:\/\/imarticus.org\/blog\/cluster-analysis\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/26c0ffd94601c4078ba4c61e5b9dd95dbb2872f64fd398e2c5d020e8ff0eb581?s=96&d=mm&r=g","width":96,"height":96,"caption":"Imarticus Learning"}},{"@type":"WebPage","@id":"https:\/\/imarticus.org\/blog\/cluster-analysis\/#webpage","url":"https:\/\/imarticus.org\/blog\/cluster-analysis\/","name":"Cluster Analysis for Beginners With Practical Examples","description":"Start with cluster analysis basics, then explore common methods, data types, worked examples and applications in data science.","inLanguage":"en-GB","isPartOf":{"@id":"https:\/\/imarticus.org\/blog\/#website"},"breadcrumb":{"@id":"https:\/\/imarticus.org\/blog\/cluster-analysis\/#breadcrumblist"},"author":{"@id":"https:\/\/imarticus.org\/blog\/author\/imarticus\/#author"},"creator":{"@id":"https:\/\/imarticus.org\/blog\/author\/imarticus\/#author"},"image":{"@type":"ImageObject","url":"https:\/\/imarticus.org\/blog\/wp-content\/uploads\/2026\/10\/cluster-analysis.webp","@id":"https:\/\/imarticus.org\/blog\/cluster-analysis\/#mainImage","width":1200,"height":630},"primaryImageOfPage":{"@id":"https:\/\/imarticus.org\/blog\/cluster-analysis\/#mainImage"},"datePublished":"2026-10-14T19:38:51+05:30","dateModified":"2026-10-15T12:32:48+05:30"},{"@type":"WebSite","@id":"https:\/\/imarticus.org\/blog\/#website","url":"https:\/\/imarticus.org\/blog\/","name":"Imarticus Learning","inLanguage":"en-GB","publisher":{"@id":"https:\/\/imarticus.org\/blog\/#organization"}}]},"og:locale":"en_GB","og:site_name":"Imarticus Blog -","og:type":"article","og:title":"Cluster Analysis for Beginners With Practical Examples","og:description":"Start with cluster analysis basics, then explore common methods, data types, worked examples and applications in data science.","og:url":"https:\/\/imarticus.org\/blog\/cluster-analysis\/","article:published_time":"2026-10-14T14:08:51+00:00","article:modified_time":"2026-10-15T07:02:48+00:00","article:publisher":"https:\/\/www.facebook.com\/ImarticusLearning\/","twitter:card":"summary_large_image","twitter:site":"@imarticus","twitter:title":"Cluster Analysis for Beginners With Practical Examples","twitter:description":"Start with cluster analysis basics, then explore common methods, data types, worked examples and applications in data science.","twitter:creator":"@imarticus"},"aioseo_meta_data":{"post_id":"278514","title":"Cluster Analysis for Beginners With Practical Examples","description":"Start with cluster analysis basics, then explore common methods, data types, worked examples and applications in data science.","keywords":null,"keyphrases":{"focus":{"keyphrase":"cluster analysis","score":0,"analysis":[]},"additional":[]},"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":"","og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"BlogPosting","isEnabled":true},"graphs":[]},"schema_type":"default","schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":"-1","robots_max_videopreview":"-1","robots_max_imagepreview":"large","priority":null,"frequency":"default","local_seo":null,"breadcrumb_settings":null,"limit_modified_date":0,"ai":{"faqs":[],"keyPoints":[],"schemas":[],"titles":[],"descriptions":[],"socialPosts":{"email":{"subject":"","preview":"","content":""},"linkedin":[],"twitter":[],"facebook":[],"instagram":[]}},"created":"2026-10-14 13:53:52","updated":"2026-10-15 07:02:49","seo_analyzer_scan_date":null,"focus_keyword":"cluster analysis","additional_keywords":null,"truseo_locale":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/imarticus.org\/blog\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/imarticus.org\/blog\/category\/data-analytics\/\" title=\"Data Analytics\">Data Analytics<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tA Guide To Cluster Analysis: Meaning, Types, And Examples\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/imarticus.org\/blog"},{"label":"Data Analytics","link":"https:\/\/imarticus.org\/blog\/category\/data-analytics\/"},{"label":"A Guide To Cluster Analysis: Meaning, Types, And Examples","link":"https:\/\/imarticus.org\/blog\/cluster-analysis\/"}],"modified_by":"Rina Chouhan","_links":{"self":[{"href":"https:\/\/imarticus.org\/blog\/wp-json\/wp\/v2\/posts\/278514","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/imarticus.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/imarticus.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/imarticus.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/imarticus.org\/blog\/wp-json\/wp\/v2\/comments?post=278514"}],"version-history":[{"count":4,"href":"https:\/\/imarticus.org\/blog\/wp-json\/wp\/v2\/posts\/278514\/revisions"}],"predecessor-version":[{"id":278522,"href":"https:\/\/imarticus.org\/blog\/wp-json\/wp\/v2\/posts\/278514\/revisions\/278522"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/imarticus.org\/blog\/wp-json\/wp\/v2\/media\/278518"}],"wp:attachment":[{"href":"https:\/\/imarticus.org\/blog\/wp-json\/wp\/v2\/media?parent=278514"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/imarticus.org\/blog\/wp-json\/wp\/v2\/categories?post=278514"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/imarticus.org\/blog\/wp-json\/wp\/v2\/tags?post=278514"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}