<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ clustering - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ clustering - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 24 Aug 2026 19:19:58 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/clustering/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up a Proxmox Cluster for Free – Virtualization Basics ]]>
                </title>
                <description>
                    <![CDATA[ Virtualization is a game-changer for developers, hobbyists, and IT enthusiasts. It lets you run multiple operating systems on one machine, which is perfect for testing apps, hosting servers, or learning new tech. If you want to take it further, clust... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/set-up-a-proxmox-cluster-virtualization-basics/</link>
                <guid isPermaLink="false">67fd1282e4687cd6aa7dcd1e</guid>
                
                    <category>
                        <![CDATA[ proxmox ]]>
                    </category>
                
                    <category>
                        <![CDATA[ clustering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ virtualization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ KVM ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Shamsuddoha Ranju ]]>
                </dc:creator>
                <pubDate>Mon, 14 Apr 2025 13:49:54 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744488492225/62339e66-50ae-4546-8845-f5c86c415511.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Virtualization is a game-changer for developers, hobbyists, and IT enthusiasts. It lets you run multiple operating systems on one machine, which is perfect for testing apps, hosting servers, or learning new tech. If you want to take it further, clustering ties multiple machines together for more power and flexibility. And you can use Proxmox Virtual Environment (VE) to build a cluster for free – no expensive licenses required.</p>
<p>In this tutorial, you’ll set up a 3-node Proxmox cluster using three computers (or virtual machines for practice). By the end, you’ll have a working cluster ready to host virtual machines (VMs) and experiment with cool features like guest migration and VM replication etc.</p>
<p>Let’s dive in!</p>
<h2 id="heading-prerequisites-what-youll-need-to-know">Prerequisites: What You’ll Need to Know</h2>
<p>This guide is beginner-friendly for clustering, but you’ll need some basic skills to follow along. You should be comfortable with:</p>
<ul>
<li><p>Installing an OS from a USB drive (don’t worry, I’ll walk you through the steps).</p>
</li>
<li><p>Using a terminal for simple commands like <code>ping</code> or <code>nano</code>.</p>
</li>
<li><p>Setting up a home network with static IPs (for example, knowing your router’s IP range). No advanced virtualization or clustering experience is required—I’ll explain the key concepts as we go.</p>
</li>
</ul>
<h2 id="heading-what-youll-need">What You’ll Need</h2>
<ul>
<li><p><strong>Three computers (or VMs):</strong> Start with at least 8GB RAM and 100GB storage per machine, plus a virtualization-capable CPU (most modern ones work). These specs are a baseline—actual RAM and storage depend on how many VMs you want to host (e.g., more VMs need more resources).</p>
</li>
<li><p><strong>Proxmox VE:</strong> Free and open-source. Grab the ISO from <a target="_blank" href="http://proxmox.com">proxmox.com</a>.</p>
</li>
<li><p><strong>Network connection:</strong> All three must be on the same network and be able to ping each other.</p>
</li>
<li><p><strong>A web browser:</strong> For Proxmox’s web interface.</p>
</li>
<li><p><strong>30–60 minutes</strong>: Depending on your setup pace.</p>
</li>
</ul>
<h2 id="heading-why-proxmox-and-clustering">Why Proxmox and Clustering?</h2>
<p>Proxmox VE is a free, open-source virtualization platform built on Debian Linux. It uses KVM for VMs (fully virtualized systems) and LXC for containers (lightweight app environments), all managed via a slick web interface.</p>
<p>Clustering means linking multiple Proxmox machines—called nodes—so they act as one system. Think of it like a team: each node shares the workload, and you control them from a single dashboard. This setup lets you move (migrate) VMs between nodes, boost reliability, and experiment with high availability (HA)—where VMs auto-restart (on healthy node) if a node fails.</p>
<p>Plus, Proxmox offers a handy replication feature: it can sync VM data between nodes automatically, keeping backups ready if something goes wrong.</p>
<p>It’s a must-have skill for DevOps, app testing, or IT tinkering.</p>
<h2 id="heading-2-nodes-vs-3-nodes-which-should-you-choose">2 Nodes vs. 3 Nodes: Which Should You Choose?</h2>
<p>Before we build your 3-node cluster, let’s explore your options. Clustering can start with 2 nodes or go to 3 (or more). Here’s why you might pick one over the other:</p>
<ul>
<li><p><strong>2-Node Cluster</strong>:</p>
<ul>
<li><p><strong>Pros</strong>: Easier setup with just two machines. Great for learning basics or small projects. Uses less hardware.</p>
</li>
<li><p><strong>Cons</strong>: No quorum—a voting majority to keep the cluster running if a node fails—so HA isn’t reliable. You’d need an extra trick (like a quorum device) to avoid stalling.</p>
</li>
<li><p><strong>Best For</strong>: Learning, Testing clustering, or limited resources.</p>
</li>
</ul>
</li>
<li><p><strong>3-Node Cluster</strong>:</p>
<ul>
<li><p><strong>Pros</strong>: Built-in quorum—two out of three nodes keep things going if one crashes. Ideal for HA practice. More stable and scalable.</p>
</li>
<li><p><strong>Cons</strong>: Needs an extra machine and a bit more setup time.</p>
</li>
<li><p><strong>Best For</strong>: Serious learners or small production setups.</p>
</li>
</ul>
</li>
</ul>
<p>We’ll go with 3 nodes—it’s the sweet spot for stability and real-world skills.</p>
<h2 id="heading-step-1-install-proxmox-ve-on-all-three-machines">Step 1: Install Proxmox VE on All Three Machines</h2>
<p>First, download the Proxmox VE ISO from <a target="_blank" href="http://proxmox.com">proxmox.com</a>. Make a bootable USB with Rufus (Windows), <code>dd</code> (Linux/macOS), or Raspberry Pi Imager (available for all platforms).</p>
<p>For <code>dd</code>, use this command (replace placeholders with your ISO and USB device):</p>
<pre><code class="lang-plaintext">sudo dd if=proxmox-ve.iso of=/dev/sdX bs=1M status=progress oflag=sync
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744492694669/777f8642-67dd-4f5f-8e78-b98c0d77ccca.png" alt="Proxmox VE installer screen showing target disk for storage configuration." class="image--center mx-auto" width="1336" height="832" loading="lazy"></p>
<p>Boot each machine from the USB and follow the installer. Stick with the default partitioning scheme (it uses EXT4 filesystem) and set static IPs and hostnames as follows (or you can use your own IPs knowing your router’s IP range):</p>
<ul>
<li><p>Node 1: <code>172.20.1.101</code> [hostname: <code>node01.local</code>]</p>
</li>
<li><p>Node 2: <code>172.20.1.102</code> [hostname: <code>node02.local</code>]</p>
</li>
<li><p>Node 3: <code>172.20.1.103</code> [hostname: <code>node03.local</code>]</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744491592723/4b793ada-e21a-4da1-92f1-dd05ad130980.png" alt="Proxmox VE installer screen showing network configuration with hostname and IP entered for Node 1." class="image--center mx-auto" width="1336" height="835" loading="lazy"></p>
<p>After installation, each node displays its IP on the console (for example, <a target="_blank" href="https://192.168.10.101:8006">https://172.20.1.101:8006</a>). Test it by opening a browser, visiting each IP, and logging in with root and your password. You’ll see the Proxmox dashboard.</p>
<h2 id="heading-step-2-prepare-your-nodes">Step 2: Prepare Your Nodes</h2>
<p>Now, let’s get your nodes ready to talk to each other—a crucial step for clustering. Without this, they won’t recognize each other properly.</p>
<p>Update <code>/etc/hosts</code> on all three nodes to map IPs to hostnames (since we’re not using a DNS server). Open the file with:</p>
<p><code>nano /etc/hosts</code></p>
<p>Add these lines (IPs and hostnames) on each node:</p>
<pre><code class="lang-plaintext">172.20.1.101 node01.local node01
172.20.1.102 node02.local node02
172.20.1.103 node03.local node03
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744492087833/bb9cb873-f107-4fcd-b53f-25408531975e.png" alt="Terminal window displaying /etc/hosts file in nano editor with IP and hostname entries for three Proxmox nodes." class="image--center mx-auto" width="1319" height="704" loading="lazy"></p>
<p>Save and exit (<code>Ctrl+O</code>, <code>Enter</code>, <code>Ctrl+X</code>). This ensures nodes can resolve each other’s names (for example, node01 pings node02.local).</p>
<p>Next, check connectivity. From Node 1’s console (or SSH), ping the others:</p>
<p><code>ping 172.20.1.102</code></p>
<p><code>ping 172.20.1.103</code></p>
<p>Repeat from Node 2 and Node 3. If pings fail, check your network or firewall.</p>
<p>Finally, sync their clocks—clusters need precise time to coordinate. On each node, run:</p>
<p><code>ntpdate pool.ntp.org</code></p>
<p>All three nodes are now primed for clustering.</p>
<h2 id="heading-step-3-create-the-cluster-on-node-1">Step 3: Create the Cluster on Node 1</h2>
<p>Let’s set up the cluster starting with Node 1. Log into its web interface at <a target="_blank" href="https://192.168.10.101:8006">https://172.20.1.101:8006</a>. On the left sidebar, click Datacenter, then Cluster. Hit the Create Cluster button, and a dialog pops up. Name your cluster—let’s call it <strong>MyCluster</strong> and click Create. A task window will appear, showing the process. Wait a few seconds until you see “TASK OK”—that means your cluster is live and Node 1 is its first member. Now we can add the other nodes!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744493528337/b5fb8aa1-e9b6-4028-b129-10d2c665f1b5.png" alt="Proxmox web interface showing the Create Cluster dialog with ‘MyCluster’ entered." class="image--center mx-auto" width="1321" height="705" loading="lazy"></p>
<h2 id="heading-step-4-join-node-2-and-node-3-to-the-cluster">Step 4: Join Node 2 and Node 3 to the Cluster</h2>
<p>With the cluster created, let’s bring in Node 2 and Node 3. On Node 1’s cluster page, click Join Information, then Copy Information—this copies a key you’ll need.</p>
<p>Open Node 2’s web interface (<a target="_blank" href="https://192.168.10.102:8006">https://172.20.1.102:8006</a>), go to Datacenter &gt; Cluster &gt; Join Cluster, paste the key into the Information field, enter Node 1’s root password, and click Join <strong>MyCluster</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744494140010/d1f60b51-480c-44f1-84a1-bb37f79b6bc7.png" alt="Proxmox web interface showing the Join Cluster dialog with ‘join information’ entered." class="image--center mx-auto" width="1315" height="702" loading="lazy"></p>
<p>Repeat this process on Node 3’s interface (<a target="_blank" href="https://192.168.10.103:8006">https://172.20.1.103:8006</a>). Refresh Node 1’s dashboard—under Datacenter, you’ll see all three nodes with green checkmarks.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744495739410/4ce5c263-318d-4a21-94f4-324d30b0fc94.png" alt="Proxmox web interface displaying the Datacenter view with three nodes (node01, node02, node03) showing green status icons." class="image--center mx-auto" width="1317" height="707" loading="lazy"></p>
<p>Your 3-node cluster is up!</p>
<h2 id="heading-step-5-test-your-cluster">Step 5: Test Your Cluster</h2>
<p>Let’s verify it works by creating and moving a test VM. On Node 1, click Create VM, name it TestVM, skip the ISO, and finish with defaults (no disk content needed). Hit the Start button to boot it up.</p>
<p>Now, let’s migrate it around—migration means moving the VM from one node to another to test your cluster’s flexibility. Right-click TestVM, select Migrate, choose Node 2, and click Migrate. The VM stops briefly, copies to Node 2, and restarts (normal without shared storage).</p>
<p>Repeat this, migrating it from Node 2 to Node 3. If it hops between nodes successfully, your cluster’s rocking! With three nodes, you’ve got quorum—try shutting down Node 3 to see the others stay active.</p>
<h2 id="heading-whats-next">What’s Next?</h2>
<p>You’ve built a 3-node Proxmox cluster for free—congrats! Take it further with:</p>
<ul>
<li><p><strong>Shared storage</strong>: Add NFS or a spare drive for live VM migration (no stopping/shutdown needed).</p>
</li>
<li><p><strong>High Availability</strong>: Enable HA—VMs auto-restart on a healthy node if one fails.</p>
</li>
<li><p><strong>VM Replication:</strong> Configure Replication—Sync VM data between nodes automatically, keeping backups ready if something goes wrong.</p>
</li>
<li><p><strong>Scale up</strong>: Add more nodes or try LXC containers.</p>
</li>
</ul>
<p>Check your cluster’s health anytime (from console) with:</p>
<p><code>pvecm status</code></p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>You’ve just set up a 3-node Proxmox cluster at no cost. It’s a playground for virtualization, DevOps practice, or even hosting small projects. Share your thoughts with me – I’d love to hear how you liked it.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 8 Clustering Algorithms in Machine Learning that All Data Scientists Should Know ]]>
                </title>
                <description>
                    <![CDATA[ By Milecia McGregor There are three different approaches to machine learning, depending on the data you have. You can go with supervised learning, semi-supervised learning, or unsupervised learning.  In supervised learning you have labeled data, so y... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/8-clustering-algorithms-in-machine-learning-that-all-data-scientists-should-know/</link>
                <guid isPermaLink="false">66d46042c7632f8bfbf1e449</guid>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ clustering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Data Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Machine Learning ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 21 Sep 2020 16:38:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/analysis.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Milecia McGregor</p>
<p>There are three different approaches to machine learning, depending on the data you have. You can go with supervised learning, semi-supervised learning, or unsupervised learning. </p>
<p>In supervised learning you have labeled data, so you have outputs that you know for sure are the correct values for your inputs. That's like knowing car prices based on features like make, model, style, drivetrain, and other attributes.</p>
<p>With semi-supervised learning, you have a large data set where some of the data is labeled but most of it isn't. </p>
<p>This covers a large amount of real world data because it can be expensive to get an expert to label every data point. You can work around this by using a combination of supervised and unsupervised learning.</p>
<p>Unsupervised learning means you have a data set that is completely unlabeled. You don’t know if there are any patterns hidden in the data, so you leave it to the algorithm to find anything it can. </p>
<p>That's where clustering algorithms come in. It's one of the methods you can use in an unsupervised learning problem.</p>
<h2 id="heading-what-are-clustering-algorithms">What are clustering algorithms?</h2>
<p>Clustering is an unsupervised machine learning task. You might also hear this referred to as cluster analysis because of the way this method works. </p>
<p>Using a clustering algorithm means you're going to give the algorithm a lot of input data with no labels and let it find any groupings in the data it can.</p>
<p>Those groupings are called <em>clusters</em>. A cluster is a group of data points that are similar to each other based on their relation to surrounding data points. Clustering is used for things like feature engineering or pattern discovery. </p>
<p>When you're starting with data you know nothing about, clustering might be a good place to get some insight. </p>
<h2 id="heading-types-of-clustering-algorithms">Types of clustering algorithms</h2>
<p>There are different types of clustering algorithms that handle all kinds of unique data.</p>
<h3 id="heading-density-based">Density-based</h3>
<p>In density-based clustering, data is grouped by areas of high concentrations of data points surrounded by areas of low concentrations of data points. Basically the algorithm finds the places that are dense with data points and calls those clusters.</p>
<p>The great thing about this is that the clusters can be any shape. You aren't constrained to expected conditions. </p>
<p>The clustering algorithms under this type don't try to assign outliers to clusters, so they get ignored.</p>
<h3 id="heading-distribution-based">Distribution-based</h3>
<p>With a distribution-based clustering approach, all of the data points are considered parts of a cluster based on the probability that they belong to a given cluster. </p>
<p>It works like this: there is a center-point, and as the distance of a data point from the center increases, the probability of it being a part of that cluster decreases. </p>
<p>If you aren't sure of how the distribution in your data might be, you should consider a different type of algorithm.</p>
<h3 id="heading-centroid-based">Centroid-based</h3>
<p>Centroid-based clustering is the one you probably hear about the most. It's a little sensitive to the initial parameters you give it, but it's fast and efficient. </p>
<p>These types of algorithms separate data points based on multiple centroids in the data. Each data point is assigned to a cluster based on its squared distance from the centroid. This is the most commonly used type of clustering.</p>
<h3 id="heading-hierarchical-based">Hierarchical-based</h3>
<p>Hierarchical-based clustering is typically used on hierarchical data, like you would get from a company database or taxonomies. It builds a tree of clusters so everything is organized from the top-down. </p>
<p>This is more restrictive than the other clustering types, but it's perfect for specific kinds of data sets.</p>
<h2 id="heading-when-to-use-clustering">When to use clustering</h2>
<p>When you have a set of unlabeled data, it's very likely that you'll be using some kind of unsupervised learning algorithm. </p>
<p>There are a lot of different unsupervised learning techniques, like neural networks, reinforcement learning, and clustering. The specific type of algorithm you want to use is going to depend on what your data looks like.</p>
<p>You might want to use clustering when you're trying to do anomaly detection to try and find outliers in your data. It helps by finding those groups of clusters and showing the boundaries that would determine whether a data point is an outlier or not. </p>
<p>If you aren't sure of what features to use for your machine learning model, clustering discovers patterns you can use to figure out what stands out in the data.</p>
<p>Clustering is especially useful for exploring data you know nothing about. It might take some time to figure out which type of clustering algorithm works the best, but when you do, you'll get invaluable insight on your data. You might find connections you never would have thought of.</p>
<p>Some real world applications of clustering include fraud detection in insurance, categorizing books in a library, and customer segmentation in marketing. It can also be used in larger problems, like earthquake analysis or city planning.</p>
<h2 id="heading-the-top-8-clustering-algorithms">The Top 8 Clustering Algorithms</h2>
<p>Now that you have some background on how clustering algorithms work and the different types available, we can talk about the actual algorithms you'll commonly see in practice. </p>
<p>We'll implement these algorithms on an example data set from the <a target="_blank" href="https://scikit-learn.org/stable/">sklearn library</a> in Python.</p>
<p>We'll be using the _make<em>classification</em> data set from the sklearn library to demonstrate how different clustering algorithms aren't fit for all clustering problems. </p>
<p>You can find <a target="_blank" href="https://github.com/flippedcoder/probable-waddle">the code for all of the following example here</a>.</p>
<h3 id="heading-k-means-clustering-algorithm">K-means clustering algorithm</h3>
<p>K-means clustering is the most commonly used clustering algorithm. It's a centroid-based algorithm and the simplest unsupervised learning algorithm. </p>
<p>This algorithm tries to minimize the variance of data points within a cluster. It's also how most people are introduced to unsupervised machine learning.</p>
<p>K-means is best used on smaller data sets because it iterates over <em>all</em> of the data points. That means it'll take more time to classify data points if there are a large amount of them in the data set. </p>
<p>Since this is how k-means clusters data points, it doesn't scale well.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> unique
<span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> where
<span class="hljs-keyword">from</span> matplotlib <span class="hljs-keyword">import</span> pyplot
<span class="hljs-keyword">from</span> sklearn.datasets <span class="hljs-keyword">import</span> make_classification
<span class="hljs-keyword">from</span> sklearn.cluster <span class="hljs-keyword">import</span> KMeans

<span class="hljs-comment"># initialize the data set we'll work with</span>
training_data, _ = make_classification(
    n_samples=<span class="hljs-number">1000</span>,
    n_features=<span class="hljs-number">2</span>,
    n_informative=<span class="hljs-number">2</span>,
    n_redundant=<span class="hljs-number">0</span>,
    n_clusters_per_class=<span class="hljs-number">1</span>,
    random_state=<span class="hljs-number">4</span>
)

<span class="hljs-comment"># define the model</span>
kmeans_model = KMeans(n_clusters=<span class="hljs-number">2</span>)

<span class="hljs-comment"># assign each data point to a cluster</span>
dbscan_result = dbscan_model.fit_predict(training_data)

<span class="hljs-comment"># get all of the unique clusters</span>
dbscan_clusters = unique(dbscan_result)

<span class="hljs-comment"># plot the DBSCAN clusters</span>
<span class="hljs-keyword">for</span> dbscan_cluster <span class="hljs-keyword">in</span> dbscan_clusters:
    <span class="hljs-comment"># get data points that fall in this cluster</span>
    index = where(dbscan_result == dbscan_clusters)
    <span class="hljs-comment"># make the plot</span>
    pyplot.scatter(training_data[index, <span class="hljs-number">0</span>], training_data[index, <span class="hljs-number">1</span>])

<span class="hljs-comment"># show the DBSCAN plot</span>
pyplot.show()
</code></pre>
<h3 id="heading-dbscan-clustering-algorithm">DBSCAN clustering algorithm</h3>
<p>DBSCAN stands for density-based spatial clustering of applications with noise. It's a density-based clustering algorithm, unlike k-means. </p>
<p>This is a good algorithm for finding outliners in a data set. It finds arbitrarily shaped clusters based on the density of data points in different regions. It separates regions by areas of low-density so that it can detect outliers between the high-density clusters.</p>
<p>This algorithm is better than k-means when it comes to working with oddly shaped data. </p>
<p>DBSCAN uses two parameters to determine how clusters are defined: <em>minPts</em> (the minimum number of data points that need to be clustered together for an area to be considered high-density) and <em>eps</em> (the distance used to determine if a data point is in the same area as other data points). </p>
<p>Choosing the right initial parameters is critical for this algorithm to work.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> unique
<span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> where
<span class="hljs-keyword">from</span> matplotlib <span class="hljs-keyword">import</span> pyplot
<span class="hljs-keyword">from</span> sklearn.datasets <span class="hljs-keyword">import</span> make_classification
<span class="hljs-keyword">from</span> sklearn.cluster <span class="hljs-keyword">import</span> DBSCAN

<span class="hljs-comment"># initialize the data set we'll work with</span>
training_data, _ = make_classification(
    n_samples=<span class="hljs-number">1000</span>,
    n_features=<span class="hljs-number">2</span>,
    n_informative=<span class="hljs-number">2</span>,
    n_redundant=<span class="hljs-number">0</span>,
    n_clusters_per_class=<span class="hljs-number">1</span>,
    random_state=<span class="hljs-number">4</span>
)

<span class="hljs-comment"># define the model</span>
dbscan_model = DBSCAN(eps=<span class="hljs-number">0.25</span>, min_samples=<span class="hljs-number">9</span>)

<span class="hljs-comment"># train the model</span>
dbscan_model.fit(training_data)

<span class="hljs-comment"># assign each data point to a cluster</span>
dbscan_result = dbscan_model.predict(training_data)

<span class="hljs-comment"># get all of the unique clusters</span>
dbscan_cluster = unique(dbscan_result)

<span class="hljs-comment"># plot the DBSCAN clusters</span>
<span class="hljs-keyword">for</span> dbscan_cluster <span class="hljs-keyword">in</span> dbscan_clusters:
    <span class="hljs-comment"># get data points that fall in this cluster</span>
    index = where(dbscan_result == dbscan_clusters)
    <span class="hljs-comment"># make the plot</span>
    pyplot.scatter(training_data[index, <span class="hljs-number">0</span>], training_data[index, <span class="hljs-number">1</span>])

<span class="hljs-comment"># show the DBSCAN plot</span>
pyplot.show()
</code></pre>
<h3 id="heading-gaussian-mixture-model-algorithm">Gaussian Mixture Model algorithm</h3>
<p>One of the problems with k-means is that the data needs to follow a circular format. The way k-means calculates the distance between data points has to do with a circular path, so non-circular data isn't clustered correctly. </p>
<p>This is an issue that Gaussian mixture models fix. You don’t need circular shaped data for it to work well.</p>
<p>The Gaussian mixture model uses multiple Gaussian distributions to fit arbitrarily shaped data. </p>
<p>There are several single Gaussian models that act as hidden layers in this hybrid model. So the model calculates the probability that a data point belongs to a specific Gaussian distribution and that's the cluster it will fall under.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> unique
<span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> where
<span class="hljs-keyword">from</span> matplotlib <span class="hljs-keyword">import</span> pyplot
<span class="hljs-keyword">from</span> sklearn.datasets <span class="hljs-keyword">import</span> make_classification
<span class="hljs-keyword">from</span> sklearn.mixture <span class="hljs-keyword">import</span> GaussianMixture

<span class="hljs-comment"># initialize the data set we'll work with</span>
training_data, _ = make_classification(
    n_samples=<span class="hljs-number">1000</span>,
    n_features=<span class="hljs-number">2</span>,
    n_informative=<span class="hljs-number">2</span>,
    n_redundant=<span class="hljs-number">0</span>,
    n_clusters_per_class=<span class="hljs-number">1</span>,
    random_state=<span class="hljs-number">4</span>
)

<span class="hljs-comment"># define the model</span>
gaussian_model = GaussianMixture(n_components=<span class="hljs-number">2</span>)

<span class="hljs-comment"># train the model</span>
gaussian_model.fit(training_data)

<span class="hljs-comment"># assign each data point to a cluster</span>
gaussian_result = gaussian_model.predict(training_data)

<span class="hljs-comment"># get all of the unique clusters</span>
gaussian_clusters = unique(gaussian_result)

<span class="hljs-comment"># plot Gaussian Mixture the clusters</span>
<span class="hljs-keyword">for</span> gaussian_cluster <span class="hljs-keyword">in</span> gaussian_clusters:
    <span class="hljs-comment"># get data points that fall in this cluster</span>
    index = where(gaussian_result == gaussian_clusters)
    <span class="hljs-comment"># make the plot</span>
    pyplot.scatter(training_data[index, <span class="hljs-number">0</span>], training_data[index, <span class="hljs-number">1</span>])

<span class="hljs-comment"># show the Gaussian Mixture plot</span>
pyplot.show()
</code></pre>
<h3 id="heading-birch-algorithm">BIRCH algorithm</h3>
<p>The Balance Iterative Reducing and Clustering using Hierarchies (BIRCH) algorithm works better on large data sets than the k-means algorithm. </p>
<p>It breaks the data into little summaries that are clustered instead of the original data points. The summaries hold as much distribution information about the data points as possible.</p>
<p>This algorithm is commonly used with other clustering algorithm because the other clustering techniques can be used on the summaries generated by BIRCH. </p>
<p>The main downside of the BIRCH algorithm is that it only works on numeric data values. You can't use this for categorical values unless you do some data transformations.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> unique
<span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> where
<span class="hljs-keyword">from</span> matplotlib <span class="hljs-keyword">import</span> pyplot
<span class="hljs-keyword">from</span> sklearn.datasets <span class="hljs-keyword">import</span> make_classification
<span class="hljs-keyword">from</span> sklearn.cluster <span class="hljs-keyword">import</span> Birch

<span class="hljs-comment"># initialize the data set we'll work with</span>
training_data, _ = make_classification(
    n_samples=<span class="hljs-number">1000</span>,
    n_features=<span class="hljs-number">2</span>,
    n_informative=<span class="hljs-number">2</span>,
    n_redundant=<span class="hljs-number">0</span>,
    n_clusters_per_class=<span class="hljs-number">1</span>,
    random_state=<span class="hljs-number">4</span>
)

<span class="hljs-comment"># define the model</span>
birch_model = Birch(threshold=<span class="hljs-number">0.03</span>, n_clusters=<span class="hljs-number">2</span>)

<span class="hljs-comment"># train the model</span>
birch_model.fit(training_data)

<span class="hljs-comment"># assign each data point to a cluster</span>
birch_result = birch_model.predict(training_data)

<span class="hljs-comment"># get all of the unique clusters</span>
birch_clusters = unique(birch_result)

<span class="hljs-comment"># plot the BIRCH clusters</span>
<span class="hljs-keyword">for</span> birch_cluster <span class="hljs-keyword">in</span> birch_clusters:
    <span class="hljs-comment"># get data points that fall in this cluster</span>
    index = where(birch_result == birch_clusters)
    <span class="hljs-comment"># make the plot</span>
    pyplot.scatter(training_data[index, <span class="hljs-number">0</span>], training_data[index, <span class="hljs-number">1</span>])

<span class="hljs-comment"># show the BIRCH plot</span>
pyplot.show()
</code></pre>
<h3 id="heading-affinity-propagation-clustering-algorithm">Affinity Propagation clustering algorithm</h3>
<p>This clustering algorithm is completely different from the others in the way that it clusters data. </p>
<p>Each data point communicates with all of the other data points to let each other know how similar they are and that starts to reveal the clusters in the data. You don't have to tell this algorithm how many clusters to expect in the initialization parameters.</p>
<p>As messages are sent between data points, sets of data called <em>exemplars</em> are found and they represent the clusters. </p>
<p>An exemplar is found after the data points have passed messages to each other and form a consensus on what data point best represents a cluster. </p>
<p>When you aren't sure how many clusters to expect, like in a computer vision problem, this is a great algorithm to start with.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> unique
<span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> where
<span class="hljs-keyword">from</span> matplotlib <span class="hljs-keyword">import</span> pyplot
<span class="hljs-keyword">from</span> sklearn.datasets <span class="hljs-keyword">import</span> make_classification
<span class="hljs-keyword">from</span> sklearn.cluster <span class="hljs-keyword">import</span> AffinityPropagation

<span class="hljs-comment"># initialize the data set we'll work with</span>
training_data, _ = make_classification(
    n_samples=<span class="hljs-number">1000</span>,
    n_features=<span class="hljs-number">2</span>,
    n_informative=<span class="hljs-number">2</span>,
    n_redundant=<span class="hljs-number">0</span>,
    n_clusters_per_class=<span class="hljs-number">1</span>,
    random_state=<span class="hljs-number">4</span>
)

<span class="hljs-comment"># define the model</span>
model = AffinityPropagation(damping=<span class="hljs-number">0.7</span>)

<span class="hljs-comment"># train the model</span>
model.fit(training_data)

<span class="hljs-comment"># assign each data point to a cluster</span>
result = model.predict(training_data)

<span class="hljs-comment"># get all of the unique clusters</span>
clusters = unique(result)

<span class="hljs-comment"># plot the clusters</span>
<span class="hljs-keyword">for</span> cluster <span class="hljs-keyword">in</span> clusters:
    <span class="hljs-comment"># get data points that fall in this cluster</span>
    index = where(result == cluster)
    <span class="hljs-comment"># make the plot</span>
    pyplot.scatter(training_data[index, <span class="hljs-number">0</span>], training_data[index, <span class="hljs-number">1</span>])

<span class="hljs-comment"># show the plot</span>
pyplot.show()
</code></pre>
<h3 id="heading-mean-shift-clustering-algorithm">Mean-Shift clustering algorithm</h3>
<p>This is another algorithm that is particularly useful for handling images and computer vision processing. </p>
<p>Mean-shift is similar to the BIRCH algorithm because it also finds clusters without an initial number of clusters being set. </p>
<p>This is a hierarchical clustering algorithm, but the downside is that it doesn't scale well when working with large data sets.</p>
<p>It works by iterating over all of the data points and shifts them towards the mode. The mode in this context is the high density area of data points in a region. </p>
<p>That's why you might hear this algorithm referred to as the mode-seeking algorithm. It will go through this iterative process with each data point and move them closer to where other data points are until all data points have been assigned to a cluster.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> unique
<span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> where
<span class="hljs-keyword">from</span> matplotlib <span class="hljs-keyword">import</span> pyplot
<span class="hljs-keyword">from</span> sklearn.datasets <span class="hljs-keyword">import</span> make_classification
<span class="hljs-keyword">from</span> sklearn.cluster <span class="hljs-keyword">import</span> MeanShift

<span class="hljs-comment"># initialize the data set we'll work with</span>
training_data, _ = make_classification(
    n_samples=<span class="hljs-number">1000</span>,
    n_features=<span class="hljs-number">2</span>,
    n_informative=<span class="hljs-number">2</span>,
    n_redundant=<span class="hljs-number">0</span>,
    n_clusters_per_class=<span class="hljs-number">1</span>,
    random_state=<span class="hljs-number">4</span>
)

<span class="hljs-comment"># define the model</span>
mean_model = MeanShift()

<span class="hljs-comment"># assign each data point to a cluster</span>
mean_result = mean_model.fit_predict(training_data)

<span class="hljs-comment"># get all of the unique clusters</span>
mean_clusters = unique(mean_result)

<span class="hljs-comment"># plot Mean-Shift the clusters</span>
<span class="hljs-keyword">for</span> mean_cluster <span class="hljs-keyword">in</span> mean_clusters:
    <span class="hljs-comment"># get data points that fall in this cluster</span>
    index = where(mean_result == mean_cluster)
    <span class="hljs-comment"># make the plot</span>
    pyplot.scatter(training_data[index, <span class="hljs-number">0</span>], training_data[index, <span class="hljs-number">1</span>])

<span class="hljs-comment"># show the Mean-Shift plot</span>
pyplot.show()
</code></pre>
<h3 id="heading-optics-algorithm">OPTICS algorithm</h3>
<p>OPTICS stands for Ordering Points to Identify the Clustering Structure. It's a density-based algorithm similar to DBSCAN, but it's better because it can find meaningful clusters in data that varies in density. It does this by ordering the data points so that the closest points are neighbors in the ordering.</p>
<p>This makes it easier to detect different density clusters. The OPTICS algorithm only processes each data point once, similar to DBSCAN (although it runs slower than DBSCAN). There's also a special distance stored for each data point that indicates a point belongs to a specific cluster.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> unique
<span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> where
<span class="hljs-keyword">from</span> matplotlib <span class="hljs-keyword">import</span> pyplot
<span class="hljs-keyword">from</span> sklearn.datasets <span class="hljs-keyword">import</span> make_classification
<span class="hljs-keyword">from</span> sklearn.cluster <span class="hljs-keyword">import</span> OPTICS

<span class="hljs-comment"># initialize the data set we'll work with</span>
training_data, _ = make_classification(
    n_samples=<span class="hljs-number">1000</span>,
    n_features=<span class="hljs-number">2</span>,
    n_informative=<span class="hljs-number">2</span>,
    n_redundant=<span class="hljs-number">0</span>,
    n_clusters_per_class=<span class="hljs-number">1</span>,
    random_state=<span class="hljs-number">4</span>
)

<span class="hljs-comment"># define the model</span>
optics_model = OPTICS(eps=<span class="hljs-number">0.75</span>, min_samples=<span class="hljs-number">10</span>)

<span class="hljs-comment"># assign each data point to a cluster</span>
optics_result = optics_model.fit_predict(training_data)

<span class="hljs-comment"># get all of the unique clusters</span>
optics_clusters = unique(optics_clusters)

<span class="hljs-comment"># plot OPTICS the clusters</span>
<span class="hljs-keyword">for</span> optics_cluster <span class="hljs-keyword">in</span> optics_clusters:
    <span class="hljs-comment"># get data points that fall in this cluster</span>
    index = where(optics_result == optics_clusters)
    <span class="hljs-comment"># make the plot</span>
    pyplot.scatter(training_data[index, <span class="hljs-number">0</span>], training_data[index, <span class="hljs-number">1</span>])

<span class="hljs-comment"># show the OPTICS plot</span>
pyplot.show()
</code></pre>
<h3 id="heading-agglomerative-hierarchy-clustering-algorithm">Agglomerative Hierarchy clustering algorithm</h3>
<p>This is the most common type of hierarchical clustering algorithm. It's used to group objects in clusters based on how similar they are to each other. </p>
<p>This is a form of bottom-up clustering, where each data point is assigned to its own cluster. Then those clusters get joined together.</p>
<p>At each iteration, similar clusters are merged until all of the data points are part of one big root cluster. </p>
<p>Agglomerative clustering is best at finding small clusters. The end result looks like a dendrogram so that you can easily visualize the clusters when the algorithm finishes.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> unique
<span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> where
<span class="hljs-keyword">from</span> matplotlib <span class="hljs-keyword">import</span> pyplot
<span class="hljs-keyword">from</span> sklearn.datasets <span class="hljs-keyword">import</span> make_classification
<span class="hljs-keyword">from</span> sklearn.cluster <span class="hljs-keyword">import</span> AgglomerativeClustering

<span class="hljs-comment"># initialize the data set we'll work with</span>
training_data, _ = make_classification(
    n_samples=<span class="hljs-number">1000</span>,
    n_features=<span class="hljs-number">2</span>,
    n_informative=<span class="hljs-number">2</span>,
    n_redundant=<span class="hljs-number">0</span>,
    n_clusters_per_class=<span class="hljs-number">1</span>,
    random_state=<span class="hljs-number">4</span>
)

<span class="hljs-comment"># define the model</span>
agglomerative_model = AgglomerativeClustering(n_clusters=<span class="hljs-number">2</span>)

<span class="hljs-comment"># assign each data point to a cluster</span>
agglomerative_result = agglomerative_model.fit_predict(training_data)

<span class="hljs-comment"># get all of the unique clusters</span>
agglomerative_clusters = unique(agglomerative_result)

<span class="hljs-comment"># plot the clusters</span>
<span class="hljs-keyword">for</span> agglomerative_cluster <span class="hljs-keyword">in</span> agglomerative_clusters:
    <span class="hljs-comment"># get data points that fall in this cluster</span>
    index = where(agglomerative_result == agglomerative_clusters)
    <span class="hljs-comment"># make the plot</span>
    pyplot.scatter(training_data[index, <span class="hljs-number">0</span>], training_data[index, <span class="hljs-number">1</span>])

<span class="hljs-comment"># show the Agglomerative Hierarchy plot</span>
pyplot.show()
</code></pre>
<h2 id="heading-other-types-of-clustering-algorithms">Other types of clustering algorithms</h2>
<p>We've covered eight of the top clustering algorithms, but there are plenty more than that available. There are some very specifically tuned clustering algorithms that quickly and precisely handle your data. Here are a few of the others that might be of interest to you.</p>
<p>There's another hierarchical algorithm that's the opposite of the agglomerative approach. It starts with a top-down clustering strategy. So it will start with one large root cluster and break out the individual clusters from there. </p>
<p>This is known as the <strong>Divisive Hierarchical</strong> clustering algorithm. There's research that shows this is creates more accurate hierarchies than agglomerative clustering, but it's way more complex.</p>
<p><strong>Mini-Batch K-means</strong> is similar to K-means, except that it uses small random chunks of data of a fixed size so they can be stored in memory. This helps it run faster than K-means so it converges to a solution in less time. </p>
<p>The drawback to this algorithm is that the speed boost will cost you some cluster quality.</p>
<p>The last algorithm we'll briefly cover is <strong>Spectral Clustering</strong>. This algorithm is completely different from the others we've looked at. </p>
<p>It works by taking advantage of graph theory. This algorithm doesn't make any initial guesses about the clusters that are in the data set. It treats data points like nodes in a graph and clusters are found based on communities of nodes that have connecting edges.</p>
<h2 id="heading-other-thoughts">Other thoughts</h2>
<p>Watch out for scaling issues with the clustering algorithms. Your data set could have millions of data points, and since clustering algorithms work by calculating the similarities between all pairs of data points, you might end up with an algorithm that doesn’t scale well.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Clustering algorithms are a great way to learn new things from old data. Sometimes you'll be surprised by the resulting clusters you get and it might help you make sense of a problem. </p>
<p>One of the coolest things about using clustering for unsupervised learning is that you can use the results in a supervised learning problem.</p>
<p>The clusters could be your new features that you use on a completely different data set! You can use clustering on just about any unsupervised machine learning problem, but make sure that you know how to analyze the results for accuracy.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ An introduction to clustering algorithms ]]>
                </title>
                <description>
                    <![CDATA[ By Peter Gleeson Take a look at the image below. It’s a collection of bugs and creepy-crawlies of different shapes and sizes. Take a moment to categorize them by similarity into a number of groups. This isn’t a trick question. Start with grouping the... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-machines-make-sense-of-big-data-an-introduction-to-clustering-algorithms-4bd97d4fbaba/</link>
                <guid isPermaLink="false">66d4609dd14641365a050951</guid>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ clustering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ combinatorics ]]>
                    </category>
                
                    <category>
                        <![CDATA[ data ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Data Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Machine Learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Math ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mathematics ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ statistics ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 28 Mar 2017 16:44:07 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*Bm4uiBY1JEt6Z-vOme_fTQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Peter Gleeson</p>
<p>Take a look at the image below. It’s a collection of bugs and creepy-crawlies of different shapes and sizes. Take a moment to categorize them by similarity into a number of groups.</p>
<p>This isn’t a trick question. Start with grouping the spiders together.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/BfSVT54goDauX2gz7TL7lE2qPKEnhVnTI6Ir" alt="Image" width="800" height="382" loading="lazy">
<em>Images via Google Image Search, labelled for reuse</em></p>
<p>Done? While there’s not necessarily a “correct” answer here, it’s most likely you split the bugs into four <em>clusters</em>. The spiders in one cluster, the pair of snails in another, the butterflies and moth into one, and the trio of wasps and bees into one more.</p>
<p>That wasn’t too bad, was it? You could probably do the same with twice as many bugs, right? If you had a bit of time to spare — or a passion for entomology — you could probably even do the same with a hundred bugs.</p>
<p>For a machine though, grouping ten objects into however many meaningful clusters is no small task, thanks to a mind-bending branch of maths called <a target="_blank" href="https://en.wikipedia.org/wiki/Bell_number">combinatorics</a>, which tells us that are 115,975 different possible ways you could have grouped those ten insects together.</p>
<p>Had there been twenty bugs, there would have been <a target="_blank" href="https://www.wolframalpha.com/input/?i=bell%27s+number+(20)">over fifty trillion</a> possible ways of clustering them.</p>
<p>With a hundred bugs — there’d be many times more solutions than there are <a target="_blank" href="https://www.wolframalpha.com/input/?i=particles+in+universe">particles in the known universe</a>. </p>
<p>How many times more? By my calculation, approximately <a target="_blank" href="https://www.wolframalpha.com/input/?i=BellB%5B100%5D+%2F+number+of+particles+in+universe">five hundred million billion billion times more</a>. In fact, there are more than <a target="_blank" href="https://www.wolframalpha.com/input/?i=BellB%5B100%5D+%2F+googol">four million billion <em>googol</em></a> solutions (<a target="_blank" href="https://www.wolframalpha.com/input/?i=googol">what’s a googol?</a>).</p>
<p>For just a hundred objects.</p>
<p>Almost all of those solutions would be meaningless — yet from that unimaginable number of possible choices, you pretty quickly found one of the very few that clustered the bugs in a useful way.</p>
<p>Us humans take it for granted how good we are categorizing and making sense of large volumes of data pretty quickly. Whether it’s a paragraph of text, or images on a screen, or a sequence of objects — humans are generally fairly efficient at making sense of whatever data the world throws at us.</p>
<p>Given that a key aspect of developing A.I. and machine learning is getting machines to quickly make sense of large sets of input data, what shortcuts are there available? </p>
<p>Here, you can read about three clustering algorithms that machines can use to quickly make sense of large datasets. This is by no means an exhaustive list — there are other algorithms out there — but they represent a good place to start!</p>
<p>You’ll find for each a quick summary of when you might use them, a brief overview of how they work, and a more detailed, step-by-step worked example. I believe it helps to understand an algorithm by actually carrying out yourself. </p>
<p>If you’re <em>really keen</em>, you’ll find the best way to do this is with pen and paper. Go ahead — nobody will judge!</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/PkvVKjhDBUGlU2gTPj7r0T1aNPdpOZ6MpZ6B" alt="Image" width="800" height="526" loading="lazy">
<em>Three suspiciously neat clusters, with K = 3</em></p>
<h3 id="heading-k-means-clustering">K-means clustering</h3>
<h4 id="heading-use-when"><strong>Use when...</strong></h4>
<p>…you have an idea of how many groups you’re expecting to find <em>a priori</em>.</p>
<h4 id="heading-how-it-works"><strong>How it works</strong></h4>
<p>The algorithm randomly assigns each observation into one of <em>k</em> categories, then calculates the <em>mean</em> of each category. Next, it reassigns each observation to the category with the closest mean before recalculating the means. This step repeats over and over until no more reassignments are necessary.</p>
<h4 id="heading-worked-example"><strong>Worked Example</strong></h4>
<p>Take a group of 12 football (or ‘soccer’) players who have each scored a certain number of goals this season (say in the range 3–30). Let’s divide them into separate clusters — say three.</p>
<p><strong>Step 1</strong> requires us to randomly split the players into three groups and calculate the means of each.</p>
<pre><code>Group <span class="hljs-number">1</span>
  Player A (<span class="hljs-number">5</span> goals),
  Player B (<span class="hljs-number">20</span> goals),
  Player C (<span class="hljs-number">11</span> goals)
Group Mean = (<span class="hljs-number">5</span> + <span class="hljs-number">20</span> + <span class="hljs-number">11</span>) / <span class="hljs-number">3</span> = <span class="hljs-number">12</span> goals

Group <span class="hljs-number">2</span>
  Player D (<span class="hljs-number">5</span> goals),
  Player E (<span class="hljs-number">3</span> goals),
  Player F (<span class="hljs-number">19</span> goals)
Group Mean = <span class="hljs-number">9</span> goals

Group <span class="hljs-number">3</span>
  Player G (<span class="hljs-number">30</span> goals),
  Player H (<span class="hljs-number">3</span> goals),
  Player I (<span class="hljs-number">15</span> goals)
Group Mean = <span class="hljs-number">16</span> goals
</code></pre><p><strong>Step 2:</strong> For each player, reassign them to the group with the closest mean. E.g., Player A (5 goals) is assigned to Group 2 (mean = 9). Then recalculate the group means.</p>
<pre><code>Group <span class="hljs-number">1</span> (Old Mean = <span class="hljs-number">12</span> goals)
  Player C (<span class="hljs-number">11</span> goals)
New Mean = <span class="hljs-number">11</span> goals

Group <span class="hljs-number">2</span> (Old Mean = <span class="hljs-number">9</span> goals)
  Player A (<span class="hljs-number">5</span> goals),
  Player D (<span class="hljs-number">5</span> goals),
  Player E (<span class="hljs-number">3</span> goals),
  Player H (<span class="hljs-number">3</span> goals)
New Mean = <span class="hljs-number">4</span> goals

Group <span class="hljs-number">3</span> (Old Mean = <span class="hljs-number">16</span> goals)
  Player G (<span class="hljs-number">30</span> goals),
  Player I (<span class="hljs-number">15</span> goals),
  Player B (<span class="hljs-number">20</span> goals),
  Player F (<span class="hljs-number">19</span> goals)
New Mean = <span class="hljs-number">21</span> goals
</code></pre><p><strong>Repeat</strong> Step 2 over and over until the group means no longer change. For this somewhat contrived example, this happens on the next iteration. <strong>Stop!</strong> You have now formed three clusters from the dataset!</p>
<pre><code>Group <span class="hljs-number">1</span> (Old Mean = <span class="hljs-number">11</span> goals)
  Player C (<span class="hljs-number">11</span> goals),
  Player I (<span class="hljs-number">15</span> goals)
Final Mean = <span class="hljs-number">13</span> goals

Group <span class="hljs-number">2</span> (Old Mean = <span class="hljs-number">4</span> goals)
  Player A (<span class="hljs-number">5</span> goals),
  Player D (<span class="hljs-number">5</span> goals),
  Player E (<span class="hljs-number">3</span> goals),
  Player H (<span class="hljs-number">3</span> goals)
Final Mean = <span class="hljs-number">4</span> goals

Group <span class="hljs-number">3</span> (Old Mean = <span class="hljs-number">21</span> goals)
  Player G (<span class="hljs-number">30</span> goals),
  Player B (<span class="hljs-number">20</span> goals),
  Player F (<span class="hljs-number">19</span> goals)
Final Mean = <span class="hljs-number">23</span> goals
</code></pre><p>With this example, the clusters could correspond to the players’ positions on the field — such as defenders, midfielders and attackers. </p>
<p>K-means works here because we could have reasonably expected the data to fall naturally into these three categories.</p>
<p>In this way, given data on a range of performance statistics, a machine could do a reasonable job of estimating the positions of players from any team sport — useful for sports analytics, and indeed any other purpose where classification of a dataset into predefined groups can provide relevant insights.</p>
<h4 id="heading-finer-details"><strong>Finer details</strong></h4>
<p>There are several variations on the algorithm described here. The initial method of ‘seeding’ the clusters can be done in one of several ways. </p>
<p>Here, we randomly assigned every player into a group, then calculated the group means. This causes the initial group means to tend towards being similar to one another, which ensures greater repeatability.</p>
<p>An alternative is to seed the clusters with just one player each, then start assigning players to the nearest cluster. The returned clusters are more sensitive to the initial seeding step, reducing repeatability in highly variable datasets. </p>
<p>However, this approach may reduce the number of iterations required to complete the algorithm, as the groups will take less time to diverge.</p>
<p>An obvious limitation to K-means clustering is that you have to provide <em>a priori</em> assumptions about how many clusters you’re expecting to find. </p>
<p>There are methods to assess the fit of a particular set of clusters. For example, the Within-Cluster <a target="_blank" href="https://en.wikipedia.org/wiki/Partition_of_sums_of_squares">Sum-of-Squares</a> is a measure of the variance within each cluster.</p>
<p>The ‘better’ the clusters, the lower the overall WCSS.</p>
<h3 id="heading-hierarchical-clustering">Hierarchical clustering</h3>
<h4 id="heading-use-when-1"><strong>Use when...</strong></h4>
<p>…you wish to uncover the underlying relationships between your observations.</p>
<h4 id="heading-how-it-works-1"><strong>How it works</strong></h4>
<p>A distance matrix is computed, where the value of cell (<em>i, j)</em> is a distance metric between observations <em>i</em> and <em>j</em>. </p>
<p>Then, pair the closest two observations and calculate their average. Form a new distance matrix, merging the paired observations into a single object. </p>
<p>From this distance matrix, pair up the closest two observations and calculate their average. Repeat until all observations are grouped together.</p>
<h4 id="heading-worked-example-1"><strong>Worked example</strong></h4>
<p>Here’s a super-simplified dataset about a selection of whale and dolphin species. As a trained biologist, I can assure you we normally use much more detailed datasets for things like <a target="_blank" href="https://en.wikipedia.org/wiki/Phylogenetic_tree">reconstructing phylogeny</a>. </p>
<p>For now though, we’ll just look at the typical body lengths for these six species. We’ll be using just two repeated steps.</p>
<pre><code>Species          Initials  Length(m)
Bottlenose Dolphin     BD        <span class="hljs-number">3.0</span>
Risso<span class="hljs-string">'s Dolphin        RD        3.6
Pilot Whale            PW        6.5
Killer Whale           KW        7.5
Humpback Whale         HW       15.0
Fin Whale              FW       20.0</span>
</code></pre><p><strong>Step 1:</strong> compute a distance matrix between each species. Here, we’ll use the <a target="_blank" href="https://en.wikipedia.org/wiki/Euclidean_distance">Euclidean distance</a> — how far apart are the data points? </p>
<p>Read this exactly as you would a distance chart in a road atlas. The difference in length between any pair of species can be looked up by reading the value at the intersection of the relevant row and column.</p>
<pre><code>    BD   RD   PW   KW   HW
RD  <span class="hljs-number">0.6</span>                    
PW  <span class="hljs-number">3.5</span>  <span class="hljs-number">2.9</span>               
KW  <span class="hljs-number">4.5</span>  <span class="hljs-number">3.9</span>  <span class="hljs-number">1.0</span>          
HW <span class="hljs-number">12.0</span> <span class="hljs-number">11.4</span>  <span class="hljs-number">8.5</span>  <span class="hljs-number">7.5</span>     
FW <span class="hljs-number">17.0</span> <span class="hljs-number">16.4</span> <span class="hljs-number">13.5</span> <span class="hljs-number">12.5</span>  <span class="hljs-number">5.0</span>
</code></pre><p><strong>Step 2:</strong> Pair up the two closest species. Here, this will be the Bottlenose &amp; Risso’s Dolphins, with an average length of 3.3m.</p>
<p><strong>Repeat</strong> Step 1 by recalculating the distance matrix, but this time merge the Bottlenose &amp; Risso’s Dolphins into a single object with length 3.3m.</p>
<pre><code>    [BD, RD]   PW   KW   HW
PW       <span class="hljs-number">3.2</span>               
KW       <span class="hljs-number">4.2</span>   <span class="hljs-number">1.0</span>          
HW      <span class="hljs-number">11.7</span>   <span class="hljs-number">8.5</span>  <span class="hljs-number">7.5</span>     
FW      <span class="hljs-number">16.7</span>  <span class="hljs-number">13.5</span> <span class="hljs-number">12.5</span>  <span class="hljs-number">5.0</span>
</code></pre><p><strong>Next</strong>, repeat Step 2 with this new distance matrix. Here, the smallest distance is between the Pilot &amp; Killer Whales, so we pair them up and take their average — which gives us 7.0m.</p>
<p><strong>Then</strong>, we repeat Step 1 — recalculate the distance matrix, but now we’ve merged the Pilot &amp; Killer Whales into a single object of length 7.0m.</p>
<pre><code>         [BD, RD] [PW, KW]   HW
 [PW, KW]      <span class="hljs-number">3.7</span>              
 HW           <span class="hljs-number">11.7</span>      <span class="hljs-number">8.0</span>     
 FW           <span class="hljs-number">16.7</span>     <span class="hljs-number">13.0</span>   <span class="hljs-number">5.0</span>
</code></pre><p><strong>Next</strong>, repeat Step 2 with this distance matrix. The smallest distance (3.7m) is between the two merged objects — so now merge them into an even bigger object, and take the average (which is 5.2m).</p>
<p><strong>Then</strong>, repeat Step 1 and compute a new distance matrix, having merged the Bottlenose &amp; Risso’s Dolphins with the Pilot &amp; Killer Whales.</p>
<pre><code>   [[BD, RD] , [PW, KW]]    HW
HW                   <span class="hljs-number">9.8</span>    
FW                  <span class="hljs-number">14.8</span>   <span class="hljs-number">5.0</span>
</code></pre><p><strong>Next</strong>, repeat Step 2. The smallest distance (5.0m) is between the Humpback &amp; Fin Whales, so merge them into a single object, and take the average (17.5m).</p>
<p><strong>Then</strong>, it’s back to Step 1 — compute the distance matrix, having merged the Humpback &amp; Fin Whales.</p>
<pre><code>         [[BD, RD] , [PW, KW]]
[HW, FW]                  <span class="hljs-number">12.3</span>
</code></pre><p><strong>Finally,</strong> repeat Step 2 — there is only one distance (12.3m) in this matrix, so pair everything into one big object. Now you can <strong>stop!</strong> Look at the final merged object:</p>
<pre><code>[[[BD, RD],[PW, KW]],[HW, FW]]
</code></pre><p>It has a nested structure (think <a target="_blank" href="http://json.org/example.html">JSON</a>), which allows it to be drawn up as a tree-like graph, or 'dendrogram'.</p>
<p>It reads in much the same way a family tree might. The nearer two observations are on the tree, the more similar or closely-related they are taken to be.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/mPiihHFW6hWNtBOST4BqWS-JpX9pSUJRb78x" alt="Image" width="480" height="480" loading="lazy">
_A no-frills dendrogram generated at [R-Fiddle.org](http://www.r-fiddle.org/#" rel="noopener" target="<em>blank" title=")</em></p>
<p>The structure of the dendrogram gives insight into how the dataset is structured.</p>
<p>In this example, there are two main branches, with Humpback Whale and Fin Whale on one side, and the Bottlenose Dolphin/Risso’s Dolphin and Pilot Whale/Killer Whale on the other.</p>
<p>In evolutionary biology, much larger datasets with many more specimens and measurements are used in this way to infer taxonomic relationships between them. </p>
<p>Outside of biology, hierarchical clustering has applications in data mining and machine learning contexts.</p>
<p>The cool thing is that this approach requires no assumptions about the number of clusters you’re looking for. </p>
<p>You can split the returned dendrogram into clusters by “cutting” the tree at a given height. This height can be chosen in a number of ways, depending on the resolution at which you wish to cluster the data.</p>
<p>For instance, looking at the dendrogram above, if we draw a horizontal line at height = 10, we’d intersect the two main branches, splitting the dendrogram into two sub-graphs. If we cut at height = 2, we’d be splitting the dendrogram into three clusters.</p>
<h4 id="heading-finer-details-1"><strong>Finer details</strong></h4>
<p>There are essentially three aspects in which hierarchical clustering algorithms can vary to the one given here.</p>
<p>Most fundamental is the approach — here, we have used an <em>agglomerative</em> process, whereby we start with individual data points and iteratively cluster them together until we’re left with one large cluster. </p>
<p>An alternative (but more computationally intensive) approach is to start with one giant cluster, and then proceed to divide the data into smaller and smaller clusters until you’re left with isolated data points.</p>
<p>There are also a range of methods that can be used to calculate the distance matrices. For many purposes, the Euclidean distance (think Pythagoras’ Theorem) will suffice, but there are <a target="_blank" href="https://en.wikipedia.org/wiki/Metric_(mathematics)">alternatives</a> that may be more applicable in some circumstances.</p>
<p>Finally, the <em>linkage criterion</em> can also vary. Clusters are linked according to how close they are to one another, but the way in which we define ‘close’ is flexible.</p>
<p> In the example above, we measured the distances between the means (or ‘centroids’) of each group and paired up the nearest groups. However, you may want to use a different definition.</p>
<p>For example, each cluster is made up of several discrete points. You could define the distance between two clusters to be the minimum (or maximum) distance between any of their points — as illustrated in the figure below.</p>
<p>There are still other ways of defining the linkage criterion, which may be suitable in different contexts.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/cb0OUKorixLdjc-oVQ4srQvwLzzoBT7rdivq" alt="Image" width="800" height="448" loading="lazy">
<em>Red/Blue: centroid linkage; Red/Green: minimum linkage; Green/Blue: maximum linkage</em></p>
<h3 id="heading-graph-community-detection">Graph Community Detection</h3>
<h4 id="heading-use-when-2"><strong>Use when</strong></h4>
<p>…you have data that can be represented as a network, or ‘graph’.</p>
<h4 id="heading-how-it-works-2"><strong>How it works</strong></h4>
<p>A <em>graph community</em> is very generally defined as a subset of vertices which are more connected to each other than with the rest of the network. </p>
<p>Various algorithms exist to identify communities, based upon more specific definitions. Algorithms include, but are not limited to: Edge Betweenness, Modularity-Maximsation, Walktrap, Clique Percolation, Leading Eigenvector…</p>
<h4 id="heading-worked-example-2"><strong>Worked example</strong></h4>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Graph_theory">Graph theory</a>, or the mathematical study of networks, is a fascinating branch of mathematics that lets us model complex systems as an abstract collection of ‘dots’ (or <em>vertices</em>) connected by ‘lines’ (or <em>edges</em>).</p>
<p>Perhaps the most intuitive case-studies are social networks. </p>
<p>Here, the vertices represent people, and edges connect vertices who are friends/followers. However, any system can be modelled as a network if you can justify a method to meaningfully connect different components. </p>
<p>Among the more innovative applications of graph theory to clustering include feature extraction from image data, and analysing gene regulatory networks.</p>
<p>As an entry-level example, take a look at this quickly put-together graph. It shows the eight websites I most recently visited, linked according to whether their respective Wikipedia articles link out to one another.</p>
<p>You could assemble this data manually, but for larger-scale projects, it’s much quicker to write a Python script to do the same. <a target="_blank" href="https://raw.githubusercontent.com/pg0408/Medium-articles/master/graph_maker.py">Here’s one I wrote earlier</a>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ir9Qji2KQ-YrkQSUOs4caYehAT9nDsDPu0jA" alt="Image" width="533" height="327" loading="lazy">
<em>Graph plotted with ‘igraph’ package for R version 3.3.3</em></p>
<p>The vertices are colored according to their community membership, and sized according to their <em>centrality</em>. See how Google and Twitter are the most central?</p>
<p>Also, the clusters make pretty good sense in the real-world (always an important performance indicator). </p>
<p>The yellow vertices are generally reference/look-up sites; the blue vertices are all used for online publishing (of articles, tweets, or code); and the red vertices include YouTube, which was of course founded by former PayPal employees. Not bad deductions for a machine.</p>
<p>Aside from being a useful way to visualize large systems, the real power of networks comes from their mathematical analysis. Let’s start by translating our nice picture of the network into a more mathematical format. Below is the <em>adjacency matrix</em> of the network.</p>
<pre><code>         GH Gl  M  P  Q  T  W  Y
GitHub    <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>  
Google    <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">1</span>  <span class="hljs-number">1</span>  <span class="hljs-number">1</span>  <span class="hljs-number">1</span>  <span class="hljs-number">1</span>
Medium    <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>
PayPal    <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">1</span>
Quora     <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>
Twitter   <span class="hljs-number">1</span>  <span class="hljs-number">1</span>  <span class="hljs-number">1</span>  <span class="hljs-number">1</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>  <span class="hljs-number">1</span>
Wikipedia <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>
YouTube   <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">1</span>  <span class="hljs-number">0</span>  <span class="hljs-number">0</span>
</code></pre><p>The value at the intersection of each row and column records whether there is an edge between that pair of vertices. </p>
<p>For instance, there is an edge between Medium and Twitter (surprise, surprise!), so the value where their rows/columns intersect is 1. Similarly, there is no edge between Medium and PayPal, so the intersection of their rows/columns returns 0.</p>
<p>Encoded within the adjacency matrix are all the properties of this network — it gives us the key to start unlocking all manner of valuable insights.</p>
<p>For a start, summing any column (or row) gives you the <em>degree</em> of each vertex — i.e., how many others it is connected to. This is commonly denoted with the letter <em>k</em>.</p>
<p>Likewise, summing the degrees of every vertex and dividing by two gives you <em>L</em>, the number of edges (or ‘links’) in the network. The number of rows/columns gives us <em>N</em>, the number of vertices (or ‘nodes’) in the network.</p>
<p>Knowing just <em>k</em>, <em>L, N</em> and the value of each cell in the adjacency matrix <em>A</em> lets us calculate the <a target="_blank" href="https://en.wikipedia.org/wiki/Modularity_(networks)"><em>modularity</em></a> of any given clustering of the network.</p>
<p>Say we’ve clustered the network into a number of communities. We can use the modularity score to assess the ‘quality’ of this clustering. </p>
<p>A higher score will show we’ve split the network into ‘accurate’ communities, whereas a low score suggests our clusters are more random than insightful. The image below illustrates this.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/O42yBf3CmmP83k2h5gCmJHer2ycdggjCkuzk" alt="Image" width="800" height="376" loading="lazy">
<em>Modularity serves as a measure of the ‘quality’ of a partition.</em></p>
<p>Modularity can be calculated using the formula below:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/hUA32fMe6NNc7rs8Kq-2UWGGDYxBUtduIo51" alt="Image" width="800" height="297" loading="lazy"></p>
<p>That’s a fair amount of math, but we can break it down bit by bit and it’ll make more sense.</p>
<p><em>M</em> is of course what we’re calculating — modularity.</p>
<p>1/2<em>L</em> tells us to divide everything that follows by 2<em>L</em>, i.e., twice the number of edges in the network. So far, so good.</p>
<p>The <strong>Σ</strong> symbol tells us we’re summing up everything to the right, and lets us iterate over every row and column in the adjacency matrix <em>A</em>.</p>
<p>For those unfamiliar with sum notation, the <em>i, j = 1</em> and the <em>N</em> work much like nested for-loops in programming. In Python, you’d write it as follows:</p>
<pre><code class="lang-python">sum = <span class="hljs-number">0</span>
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,N):
    <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,N):
        ans = <span class="hljs-comment">#stuff with i and j as indices </span>
    sum += ans
</code></pre>
<p>So what is <code>#stuff with i and j</code> in more detail?</p>
<p>Well, the bit in brackets tells us to subtract ( _k_i k<em>j ) / 2L</em> from _A<em>ij</em>.</p>
<p>_A<em>ij</em> is simply the value in the adjacency matrix at row <em>i</em>, column <em>j</em>.</p>
<p>The values of _k<em>i</em> and _k<em>j</em> are the degrees of each vertex — found by adding up the entries in row <em>i</em> and column <em>j</em> respectively. Multiplying these together and dividing by 2<em>L</em> gives us the expected number of edges between vertices <em>i</em> and <em>j</em> if the network were randomly shuffled up.</p>
<p>Overall, the term in the brackets reveals the difference between the network’s real structure and the expected structure it would have if randomly reassembled.</p>
<p>Playing around with the values shows that it returns its highest value when _A<em>ij</em> = 1, and ( _k_i k<em>j ) / 2L</em> is low. This means we see a higher value if there is an ‘unexpected’ edge between vertices <em>i</em> and <em>j.</em></p>
<p>Finally, we multiply the bracketed term by whatever the last few symbols refer to.</p>
<p>The ?c<strong>i,_ c</strong>j i_s the fancy-sounding but totally harmless Kronecker-delta function. Here it is, explained in Python:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">kroneckerDelta</span>(<span class="hljs-params">ci, cj</span>):</span>
    <span class="hljs-keyword">if</span> ci == cj:
        <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>

kroneckerDelta(<span class="hljs-string">"A"</span>,<span class="hljs-string">"A"</span>)
<span class="hljs-comment">#returns 1</span>

kroneckerDelta(<span class="hljs-string">"A"</span>,<span class="hljs-string">"B"</span>)
<span class="hljs-comment">#returns 0</span>
</code></pre>
<p>Yes — it really is that simple. The Kronecker-delta function takes two arguments, and returns 1 if they are identical, otherwise, zero.</p>
<p>This means that if vertices <em>i</em> and <em>j</em> have been put in the same cluster, then ?c<strong>i,_ c</strong>j = 1_. Otherwise, if they are in different clusters, the function returns zero.</p>
<p>As we are multiplying the bracketed term by this Kronecker-delta function, we find that for the nested sum <strong>Σ</strong>, the outcome is highest when there are lots of ‘unexpected’ edges connecting vertices assigned to the same cluster. </p>
<p>As such, modularity is a measure of how well-clustered the graph is into separate communities.</p>
<p>Dividing by <em>2L</em> bounds the upper value of modularity at 1. Modularity scores near to or below zero indicate the current clustering of the network is really no use. The higher the modularity, the better the clustering of the network into separate communities. </p>
<p>By maximising modularity, we can find the best way of clustering the network.</p>
<p>Notice that we have to pre-define how the graph is clustered to find out how ‘good’ that clustering actually is. </p>
<p>Unfortunately, employing brute force to try out every possible way of clustering the graph to find which has the highest modularity score would be computationally impossible beyond a very limited sample size.</p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Partition_of_a_set#Counting_partitions">Combinatorics</a> tells us that for a network of just eight vertices, there are 4140 different ways of clustering them. A network twice the size would have over ten billion possible ways of clustering the vertices. </p>
<p>Doubling the network again (to a very modest 32 vertices) would give 128 septillion possible ways, and a network of eighty vertices would be cluster-able in more ways than there are <a target="_blank" href="https://www.wolframalpha.com/input/?i=991267988808424794443839434655920239360814764000951599022939879419136287216681744888844&amp;lk=1&amp;rawformassumption=%22ClashPrefs%22+-%3E+%7B%22Math%22%7D">atoms in the observable universe</a>.</p>
<p>Instead, we have to turn to a <em>heuristic</em> method that does a reasonably good job at estimating the clusters that will produce the highest modularity score, without trying out every single possibility. </p>
<p>This is an algorithm called <em>Fast-Greedy Modularity-Maximization,</em> and it’s somewhat analogous to the agglomerative hierarchical clustering algorithm describe above. Instead of merging according to distance, ‘Mod-Max’ merges communities according to changes in modularity. </p>
<p>Here’s how it goes:</p>
<p><strong>Begin</strong> by initially assigning every vertex to its own community, and calculating the modularity of the whole network, <em>M</em>.</p>
<p><strong>Step 1</strong> requires that for each community pair linked by at least a single edge, the algorithm calculates the resultant change in modularity Δ<em>M</em> if the two communities were merged into one.</p>
<p><strong>Step 2</strong> then takes the pair of communities that produce the biggest increase in Δ<em>M,</em> which are then merged. Calculate the new modularity <em>M</em> for this clustering, and keep a record of it.</p>
<p><strong>Repeat</strong> steps 1 and 2 — each time merging the pair of communities for which doing so produces the biggest gain in Δ<em>M,</em> then recording the new clustering pattern and its associated modularity score <em>M</em>.</p>
<p><strong>Stop</strong> when all the vertices are grouped into one giant cluster. Now the algorithm checks the records it kept as it went along, and identifies the clustering pattern that returned the highest value of <em>M</em>. This is the returned community structure.</p>
<h4 id="heading-finer-details-2"><strong>Finer details</strong></h4>
<p>Whew! That was computationally intensive, at least for us humans. </p>
<p>Graph theory is a rich source of computationally challenging, often NP-hard problems — yet it also has incredible potential to provide valuable insights into complex systems and datasets. </p>
<p>Just ask Larry Page, whose eponymous PageRank algorithm — which helped propel Google from start-up to basically world domination in less than a generation — was based entirely in graph theory.</p>
<p>Community detection is a major focus of current research in graph theory, and there are plenty of alternatives to Modularity-Maximization, which while useful, does have some drawbacks.</p>
<p>For a start, its agglomerative approach often sees small, well-defined communities swallowed up into larger ones. This is known as the <em>resolution limit</em> — the algorithm will not find communities below a certain size. </p>
<p>Another challenge is that rather than having one distinct, easy-to-reach global peak, the Mod-Max approach actually tends to produce a wide ‘plateau’ of many similar high modularity scores — making it somewhat difficult to truly identify the absolute maximum score.</p>
<p>Other algorithms use different ways to define and approach community detection.</p>
<p><em>Edge-Betweenness</em> is a divisive algorithm, starting with all vertices grouped in one giant cluster. It proceeds to iteratively remove the least ‘important’ edges in the network, until all vertices are left isolated. This produces a hierarchical structure, with similar vertices closer together in the hierarchy.</p>
<p>Another algorithm is <em>Clique Percolation</em>, which takes into account possible overlap between graph communities. </p>
<p>Yet another set of algorithms are based on <a target="_blank" href="https://en.wikipedia.org/wiki/Random_walk">random-walks</a> across the graph, and then there are <a target="_blank" href="https://en.wikipedia.org/wiki/Spectral_clustering"><em>spectral clustering</em></a> methods which start delving into the eigendecomposition of the adjacency matrix and other matrices derived therefrom. These ideas are used in feature extraction in, for example, areas such as computer vision.</p>
<p>It’d be well beyond the scope of this article to give each algorithm its own in-depth worked example. Suffice to say that this is an active area of research, providing powerful methods to make sense of data that even a generation ago would have been extremely difficult to process.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Hopefully this article has informed and inspired you to better understand how machines can make sense of data. The future is a rapidly changing place, and many of those changes will be driven by what technology becomes capable of in the next generation or two.</p>
<p>As outlined in the introduction, machine learning is an extraordinarily ambitious field of research, in which massively complex problems require solving in as accurate and as efficient a way possible. Tasks that come naturally to us humans require innovative solutions when taken on by machines.</p>
<p>There’s still plenty of progress to be made, and whoever contributes the next breakthrough idea will no doubt be generously rewarded. Maybe someone reading this article will be behind the next powerful algorithm?</p>
<p>All great ideas have to start somewhere!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
