{"id":703,"date":"2024-09-11T16:55:24","date_gmt":"2024-09-11T16:55:24","guid":{"rendered":"https:\/\/inventorics.com\/?p=703"},"modified":"2024-09-11T17:03:17","modified_gmt":"2024-09-11T17:03:17","slug":"clustering-of-an-inventory","status":"publish","type":"post","link":"https:\/\/inventorics.com\/?p=703","title":{"rendered":"clustering of an inventory"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Applying a clustering algorithm to an inventory of irregular unique objects can help to reduce the complexity involved in designing with such parts significantly. By dividing the inventory items into groups with similar characteristics, each group can then be represented by one &#8220;proto-part&#8221; instead, therefore reducing the amount of unique elements to be handled in setting up aggregation logics and the aggregation processes.<br>The decision about the number of different groups <em>(Fig. 1)<\/em> can be completely left to an algorithm (depending on various predefined &#8211; by the programmer &#8211; conditions) or be manually determined by the user\/designer.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"357\" src=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/4n5-clusters-bikeframes-01-2-1024x357.jpg\" alt=\"\" class=\"wp-image-710\" srcset=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/4n5-clusters-bikeframes-01-2-1024x357.jpg 1024w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/4n5-clusters-bikeframes-01-2-300x105.jpg 300w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/4n5-clusters-bikeframes-01-2-768x268.jpg 768w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/4n5-clusters-bikeframes-01-2-1536x536.jpg 1536w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/4n5-clusters-bikeframes-01-2.jpg 1676w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\"><sub><em>Fig. 1: clustering of inventory with different amounts of groups (&#8220;proto-parts&#8221;)<\/em><\/sub><\/figcaption><\/figure>\n<\/div>\n\n\n<!--more-->\n\n\n\n<p class=\"wp-block-paragraph\">Furthermore, the reduction to a certain amount of groups allows training of an <em>AI-model<\/em> <em><s>(future blog post)<\/s><\/em>, that will be able to continually produce aggregations from the representing &#8220;proto-parts&#8221;<em> (Figs. 2 + 3)<\/em>; instead of the need of a new training phase for each new set of parts &#8211; as long as each new part fits in one of the initial groups of the training set.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"508\" src=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/AI_v1-1024x508.jpg\" alt=\"\" class=\"wp-image-706\" srcset=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/AI_v1-1024x508.jpg 1024w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/AI_v1-300x149.jpg 300w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/AI_v1-768x381.jpg 768w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/AI_v1-1536x762.jpg 1536w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/AI_v1-2048x1016.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"508\" src=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/AI_v2-1024x508.jpg\" alt=\"\" class=\"wp-image-707\" srcset=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/AI_v2-1024x508.jpg 1024w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/AI_v2-300x149.jpg 300w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/AI_v2-768x381.jpg 768w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/AI_v2-1536x762.jpg 1536w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/AI_v2-2048x1016.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\"><em><sub>Fig. 2 and 3: two topologically equal aggregations with different arrangements of &#8220;proto-parts&#8221; representing all the available parts from a possible inventory<\/sub><\/em><\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Especially in an <a href=\"https:\/\/en.wikipedia.org\/wiki\/Cradle-to-cradle_design\" target=\"_blank\" rel=\"noreferrer noopener\">industrial product lifecycle<\/a><sup data-fn=\"e685bd81-d93e-4ea6-b783-89c219d31b7a\" class=\"fn\"><a href=\"#e685bd81-d93e-4ea6-b783-89c219d31b7a\" id=\"e685bd81-d93e-4ea6-b783-89c219d31b7a-link\">1<\/a><\/sup> this offers a lot of potential as most products&#8217; geometric variance and structural potential tends to fall within a very limited range, due to norms and regulations and fabrication (mass production) constraints. For industrial artifacts it is much easier to find a smaller\/limited representative set of &#8220;proto-parts&#8221; with lesser variance of the individual parts to their &#8220;proto-part&#8221; than for example in natural materials like tree branches<em> (Fig. 4)<\/em> or crushed rocks.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2480\" height=\"1445\" src=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/5clusters_branches-01-1.jpg\" alt=\"\" class=\"wp-image-712\" srcset=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/5clusters_branches-01-1.jpg 2480w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/5clusters_branches-01-1-300x175.jpg 300w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/5clusters_branches-01-1-1024x597.jpg 1024w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/5clusters_branches-01-1-768x447.jpg 768w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/5clusters_branches-01-1-1536x895.jpg 1536w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/5clusters_branches-01-1-2048x1193.jpg 2048w\" sizes=\"auto, (max-width: 2480px) 100vw, 2480px\" \/><figcaption class=\"wp-element-caption\"><sub><em>Fig. 4: A set of 42 tree branch forks grouped into 5 clusters. A much larger variance between the individual items within the same cluster are visible, especially when  compared to industrial objects like e.g. bike-frames (see Fig.1)<\/em><\/sub><\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">In the course of the preceeding research project <a href=\"http:\/\/www.conceptual.joining.com\" data-type=\"link\" data-id=\"www.conceptual.joining.com\" target=\"_blank\" rel=\"noreferrer noopener\">Conceptual Joining<\/a> we assembled spacial frameworks made of beechwood branch forks and used one single &#8220;proto-branch&#8221; for the initial set up which then got populated with the actual items from the sets of branch forks. This led to significantly different grid spacings between the different prototypes <em>(Fig. 5)<\/em>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"534\" src=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/proto-branch_grids_-1-1024x534.jpg\" alt=\"\" class=\"wp-image-716\" srcset=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/proto-branch_grids_-1-1024x534.jpg 1024w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/proto-branch_grids_-1-300x157.jpg 300w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/proto-branch_grids_-1-768x401.jpg 768w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/proto-branch_grids_-1-1536x802.jpg 1536w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/proto-branch_grids_-1.jpg 1966w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\"><em><sub>Fig. 5: The topologically equal grids from two different &#8220;proto-parts&#8221;. The proto-part used in the left hand grid is generated from a set of branch forks with much larger crotch angles than the right hand one.<\/sub><\/em> <em><sub>(www.conceptual-joining.com)<\/sub><\/em><\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Replacing the proto-parts with the geometry of the actual parts will then change the global form of the structure. That means the form of the initial aggregation will change during the<a href=\"https:\/\/conceptual-joining.com\/?portfolio=branch-formations-tetrahedral-aggregation-sample\"> replacement with the actual parts <\/a>depending on how close the approximated proto-part is or on how many different proto-parts are used for its generation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Having the ability to adjust the amount of representative proto-parts to design with provides flexibility and designerly freedom to choose from the complete range between a set of unique elements to one single proto-part. The complexity of setting up aggregation logics can be adjusted in relation to i.a. the type of artifacts in use or the skill-level of the designer.<\/p>\n\n\n\n<h2 class=\"wp-block-heading has-medium-font-size\">K<strong>-means <\/strong>Clustering<\/h2>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/medium.com\/@pranav3nov\/understanding-k-means-clustering-f5e2e84d2129\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/v2\/resize:fit:4800\/format:webp\/0*KfNpMUTtyCNQwYnp.png\" alt=\"\"\/><\/a><figcaption class=\"wp-element-caption\"><em><sub>Fig. 6: &#8220;K-means uses an iterative refinement method to produce its final clustering based on the number of clusters defined by the user (represented by the variable K) and the dataset. It tries to make the data points of same cluster as similar as possible while also keeping the clusters as different as possible.<\/sub><\/em>&#8220;<sup data-fn=\"21308f38-2fc9-42eb-abac-c7900b3e7b6a\" class=\"fn\"><a href=\"#21308f38-2fc9-42eb-abac-c7900b3e7b6a\" id=\"21308f38-2fc9-42eb-abac-c7900b3e7b6a-link\">2<\/a><\/sup><\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Based on an implementation by <a href=\"https:\/\/www.food4rhino.com\/en\/app\/wasp\" target=\"_blank\" rel=\"noreferrer noopener\">Andrea Rossi<\/a> of the <a href=\"https:\/\/medium.com\/@pranav3nov\/understanding-k-means-clustering-f5e2e84d2129\" target=\"_blank\" rel=\"noreferrer noopener\">K-means clustering method<\/a> from the previous project <a href=\"http:\/\/www.conceptual-joining.com\" target=\"_blank\" rel=\"noreferrer noopener\">Conceptual Joining<\/a> the first step was to implement the K-means++ initialization, a smarter initialization method, which spreads out the initial cluster centers more evenly.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Regular K-means Initialization<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Random Initialization<\/strong>:\n<ul class=\"wp-block-list\">\n<li>The standard kMeans algorithm starts by randomly selecting <code>k<\/code> points from the dataset as the initial cluster centers.<\/li>\n\n\n\n<li>This random initialization can sometimes result in poor clustering because the initial centers may not be representative of the actual distribution of the data.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">K-means++ Initialization<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>First Center Selection<\/strong>:\n<ul class=\"wp-block-list\">\n<li>The first cluster center is chosen randomly from the data points.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Subsequent Center Selection<\/strong>:\n<ul class=\"wp-block-list\">\n<li>For each subsequent center, the algorithm does not just pick a point at random. Instead, it selects the next center with a probability proportional to the squared distance of the point from the nearest existing center.<\/li>\n\n\n\n<li>Specifically, for each point <code>x<\/code>, calculate the distance <code>D(x)<\/code> to the nearest current cluster center.<\/li>\n\n\n\n<li>Choose a new data point as a new center with probability proportional to <code>D(x)^2<\/code>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Iteration<\/strong>:\n<ul class=\"wp-block-list\">\n<li>This process continues until all <code>k<\/code> centers have been chosen.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Implementing the K-means++ initialization solved a previously frequently reoccuring problem of the script generating wrong proto-parts &#8211; caused by some interations of the randomly choosen initial cluster centers &#8211; with no assigned items to their group<em> (Fig. 7)<\/em>. With the K-means ++ features that error is completely resolved.<em> (Fig. 8)<\/em> Both illustrated with the branch fork dataset of the <a href=\"http:\/\/www.conceptual-joining.com\" target=\"_blank\" rel=\"noreferrer noopener\">Conceptual Joining <\/a>research project.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"565\" src=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/kmeans-regular-01-1024x565.jpg\" alt=\"\" class=\"wp-image-719\" srcset=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/kmeans-regular-01-1024x565.jpg 1024w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/kmeans-regular-01-300x165.jpg 300w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/kmeans-regular-01-768x424.jpg 768w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/kmeans-regular-01.jpg 1240w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\"><em><sub>Fig. 7: Faulty proto-part generation with regular K-means clustering<\/sub><\/em><\/figcaption><\/figure>\n<\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"565\" src=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/kmeans-plusplus-01-1024x565.jpg\" alt=\"\" class=\"wp-image-721\" srcset=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/kmeans-plusplus-01-1024x565.jpg 1024w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/kmeans-plusplus-01-300x165.jpg 300w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/kmeans-plusplus-01-768x424.jpg 768w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/kmeans-plusplus-01.jpg 1240w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\"><em><sub>Fig. 8: Proto-part and group generation with K-means++ clustering<\/sub><\/em><\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">With this implementation an experienced designer can already explore options and test out a range of cluster amounts to find a suitable one. However for a less exprienced user it might be reasonable to automate the determination of the number of clusters. According to ChatGPT the most common option includes the <a href=\"https:\/\/medium.com\/@zalarushirajsinh07\/the-elbow-method-finding-the-optimal-number-of-clusters-d297f5aeb189\" target=\"_blank\" rel=\"noreferrer noopener\">Elbow Method<\/a>, a Variance Threshold or a Distance-based Threshold.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"6202\">Implementing the Elbow Method<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\" id=\"e753\">The elbow method is used to determine the optimal number of clusters (k) for a dataset. It computes the inertia (or within-cluster sum of squares) for different values of k. The optimal number of clusters is often identified at the &#8220;elbow point,&#8221; where the rate of inertia decrease slows down significantly.<br>These of course adds a lot of computing time to the script (in our Grasshopper3d definition from 1.3 seconds to 11.4 seconds for a maximum amount of 10 clusters and 50 iterations) as it has to calculate a range of number of clusters and then chooses the value where increasing the number of clusters does no longer significantly decreases the within-cluster sum of squares. <em>(Fig. 9)<\/em><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"670\" height=\"498\" src=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/image.webp\" alt=\"\" class=\"wp-image-738\" style=\"width:478px;height:auto\" srcset=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/image.webp 670w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/image-300x223.webp 300w\" sizes=\"auto, (max-width: 670px) 100vw, 670px\" \/><figcaption class=\"wp-element-caption\"><sub><em>Fig. 9: Graphical representation of the Elbow Method<\/em><\/sub><sup data-fn=\"08d59281-f7bc-4fdd-baf6-2d6ff4eefae9\" class=\"fn\"><a href=\"#08d59281-f7bc-4fdd-baf6-2d6ff4eefae9\" id=\"08d59281-f7bc-4fdd-baf6-2d6ff4eefae9-link\">3<\/a><\/sup><\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\" id=\"e753\">The results are consistent with both data sets. With equal settings, no matter which first random cluster center is choosen for the K-means++ calculation the resulting optimum is always 2 clusters for the branch fork data set (42 items) <em>(Fig. 10) <\/em>and in the other very small bike-frame data set (18 items), depending on which bike is choosen as the first cluster center, the calculated optimum is either 2 (10 times) or 3 (8 times)<em> (Fig.11)<\/em>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1966\" height=\"576\" src=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/elbow_branches.gif\" alt=\"\" class=\"wp-image-735\"\/><figcaption class=\"wp-element-caption\"><em><sub>Fig. 10: K-means clustering with elbow method for branch fork data set.<\/sub><\/em><\/figcaption><\/figure>\n<\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1966\" height=\"560\" src=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/elbow_bikes.gif\" alt=\"\" class=\"wp-image-734\"\/><figcaption class=\"wp-element-caption\"><em><sub>Fig. 11: K-means clustering with elbow method for bike-frame data set. First cluster center seen in the upper left corner, the resulting proto-parts below on the left side.<\/sub><\/em><\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Integrating the Elbow Method reduces the amount of proto-parts drastically. In the case of small data sets like the bike-frames it also seems to not be consistent and the amount varies according to the first bike-frame that is choosen as the first cluster center. In contrast the branch fork dataset clustering does not vary that extremely depending on the first choosen brach fork and the generated proto-branches are consistent throughout all 42 possibilities. Although the clustering into two different groups is consistent, the visual difference between the individual items in each group is immense. It stands to reason that in at least such a case (organic artifacts) a larger number of clusters would possibly make more sense for an approach where the artifact is given more agency and becomes the driver for the global design.<br>However, further studies and larger data sets are needed to be able to come to serious conclusions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Other aspects to invetigate further are different methods like the before mentioned Variance Threshold or  Distance-based Threshold as a closer look at the intertias reveals that there might be a better &#8220;Elbow Point&#8221; where the amount of clusters is not minimized but a compromise between complete uniqueness and pure monotony. Here each proto-part would resemble its cluster&#8217;s items very closely and the designer would be relieved of some of the complexity instead of working with an inventory of unique parts. <em>(Fig. 12)<\/em><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"577\" src=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/elbow_bikes_gh_ano-1024x577.jpg\" alt=\"\" class=\"wp-image-736\" srcset=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/elbow_bikes_gh_ano-1024x577.jpg 1024w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/elbow_bikes_gh_ano-300x169.jpg 300w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/elbow_bikes_gh_ano-768x432.jpg 768w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/elbow_bikes_gh_ano.jpg 1284w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\"><em><sub>Fig. 12: The curve shows the calculated intertias on Y for 1-10 clusters along X. The Elbow Method reduces the amount of generated proto-parts to an absolute mathematical minimum. Increasing the amount clusters by a reasonable amount still decreases the complexity for the designer but gives more agency to the artifacts (and the designer).<\/sub><\/em><\/figcaption><\/figure>\n<\/div>\n\n<ol class=\"wp-block-footnotes\"><li id=\"e685bd81-d93e-4ea6-b783-89c219d31b7a\"><sub><em>McDonough, W. and Braungart, M. (2002) Cradle to cradle : remaking the way we make things. 1. ed.. New York, NY.<\/em><\/sub> <a href=\"#e685bd81-d93e-4ea6-b783-89c219d31b7a-link\" aria-label=\"Jump to footnote reference 1\">\u21a9\ufe0e<\/a><\/li><li id=\"21308f38-2fc9-42eb-abac-c7900b3e7b6a\"><sub>from <a href=\"https:\/\/medium.com\/@pranav3nov\/understanding-k-means-clustering-f5e2e84d2129\">https:\/\/medium.com\/@pranav3nov\/understanding-k-means-clustering-f5e2e84d2129<\/a><em> (last access September 10th 2024)<\/em><\/sub> <a href=\"#21308f38-2fc9-42eb-abac-c7900b3e7b6a-link\" aria-label=\"Jump to footnote reference 2\">\u21a9\ufe0e<\/a><\/li><li id=\"08d59281-f7bc-4fdd-baf6-2d6ff4eefae9\"><em><sub>from <a href=\"https:\/\/medium.com\/@zalarushirajsinh07\/the-elbow-method-finding-the-optimal-number-of-clusters-d297f5aeb189\">https:\/\/medium.com\/@zalarushirajsinh07\/the-elbow-method-finding-the-optimal-number-of-clusters-d297f5aeb189<\/a><\/sub><\/em> (<sub><em>(last access September 10th 2024)<\/em><\/sub>) <a href=\"#08d59281-f7bc-4fdd-baf6-2d6ff4eefae9-link\" aria-label=\"Jump to footnote reference 3\">\u21a9\ufe0e<\/a><\/li><\/ol>\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">The final python 2.7 code for Grasshopper3d \/ Rhino 7<\/h3>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1048\" height=\"499\" src=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/gh_python_container.jpg\" alt=\"\" class=\"wp-image-726\" style=\"width:512px;height:auto\" srcset=\"https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/gh_python_container.jpg 1048w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/gh_python_container-300x143.jpg 300w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/gh_python_container-1024x488.jpg 1024w, https:\/\/inventorics.com\/wp-content\/uploads\/2024\/09\/gh_python_container-768x366.jpg 768w\" sizes=\"auto, (max-width: 1048px) 100vw, 1048px\" \/><\/figure>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<pre class=\"wp-block-preformatted\">import math<br>import random as rnd<br>import Grasshopper as gh<br>import ghpythonlib.treehelpers as th<br><br># Remapping values from a source domain to a new target domain<br>def translate(value, sourceMin, sourceMax, targetMin, targetMax):<br>    sourceSpan = sourceMax - sourceMin<br>    targetSpan = targetMax - targetMin<br>    valueScaled = float(value - sourceMin) \/ float(sourceSpan)<br>    return targetMin + (valueScaled * targetSpan)<br><br># Mapping the input values into a target domain 0-1<br>def normalize_values(lst, min_val, max_val):<br>    return [[translate(value, min_val, max_val, 0, 1) for value in sublist] for sublist in lst]<br><br>def vector_dist(v1, v2):<br>    distance = sum(math.pow(v2[i] - v1[i], 2) for i in range(len(v1)))<br>    return math.sqrt(distance)<br><br>def kMeansPlusPlusInitialization(vals, cls_num, first_center_index):<br>    cluster_centers = []<br>    first_center = vals[first_center_index]<br>    cluster_centers.append(first_center)<br>    <br>    for i in range(1, cls_num):<br>        distances = [min(vector_dist(val, center) for center in cluster_centers) for val in vals]<br>        total_distance = sum(distances)<br>        probabilities = [dist \/ total_distance for dist in distances]<br>        <br>        cumulative_probabilities = []<br>        cumulative_sum = 0<br>        for p in probabilities:<br>            cumulative_sum += p<br>            cumulative_probabilities.append(cumulative_sum)<br>        <br>        r = rnd.random()<br>        for i, cumulative_prob in enumerate(cumulative_probabilities):<br>            if r &lt; cumulative_prob:<br>                cluster_centers.append(vals[i])<br>                break<br>    <br>    return cluster_centers<br><br>def kMeanClustering(vals, cls_num, iterations, first_center_index, min_val, max_val):<br>    # Normalize the input data<br>    norm_list = normalize_values(vals, min_val, max_val)<br><br>    cluster_centers = kMeansPlusPlusInitialization(norm_list, cls_num, first_center_index)<br>    <br>    for _ in range(iterations):<br>        clusters = [[] for _ in cluster_centers]<br>        clusters_ids = [[] for _ in cluster_centers]<br>        <br>        for i, norm_val in enumerate(norm_list):<br>            distances = [vector_dist(norm_val, center) for center in cluster_centers]<br>            best_center_id = distances.index(min(distances))<br>            <br>            clusters[best_center_id].append(norm_val)<br>            clusters_ids[best_center_id].append(i)<br>        <br>        for i, cluster in enumerate(clusters):<br>            if cluster:<br>                new_center = [sum(dim) \/ len(cluster) for dim in zip(*cluster)]<br>                cluster_centers[i] = new_center<br>            else:<br>                cluster_centers[i] = rnd.choice(norm_list)<br>    <br>    return th.list_to_tree(clusters_ids), cluster_centers<br><br>def compute_inertia(vals, cluster_ids, cluster_centers, min_val, max_val):<br>    inertia = 0<br>    cluster_ids_list = th.tree_to_list(cluster_ids)<br>    <br>    # Normalize the original values for distance computation<br>    norm_vals = normalize_values([list(val) for val in vals], min_val, max_val)<br>    <br>    for cluster_idx, cluster_branch in enumerate(cluster_ids_list):<br>        for point_idx in cluster_branch:<br>            inertia += vector_dist(norm_vals[point_idx], cluster_centers[cluster_idx]) ** 2<br>    return inertia<br><br>def elbow_method(vals, max_clusters, iterations, first_center_index, min_val, max_val):<br>    inertias = []<br>    first_centerindices = []<br>    for i in range(1, max_clusters + 1):<br>        cluster_ids, cluster_centers = kMeanClustering(vals, i, iterations, first_center_index, min_val, max_val)<br>        inertia = compute_inertia(vals, cluster_ids, cluster_centers, min_val, max_val)<br>        inertias.append(inertia)<br>        print(\"Number of clusters: {0}, Inertia: {1}\".format(i, inertia))<br>    return inertias<br><br>def find_optimal_clusters(inertias):<br>    elbow_point = 0<br>    max_gradient = 0<br>    for i in range(1, len(inertias)):<br>        gradient = inertias[i - 1] - inertias[i]<br>        if gradient &gt; max_gradient:<br>            max_gradient = gradient<br>            elbow_point = i<br>    return elbow_point + 1<br><br># Main script<br>rnd.seed(2)<br><br>values = [[item for item in branch] for branch in value_tree.Branches]<br><br># Compute min_val and max_val for the entire dataset<br>all_values = [item for sublist in values for item in sublist]<br>min_val = min(all_values)<br>max_val = max(all_values)<br><br># Perform the elbow method to determine the optimal number of clusters<br>inertias = elbow_method(values, max_clusters, iterations, first_center_index, min_val, max_val)<br>optimal_clusters = find_optimal_clusters(inertias)<br><br># Run the final clustering with the optimal number of clusters<br>ids, avg_norm_centers = kMeanClustering(values, optimal_clusters, iterations, first_center_index, min_val, max_val)<br><br># Translate the normalized cluster centers back to the original domain<br>mapped_centers = []<br>for center in avg_norm_centers:<br>    mapped_center = [translate(center[i], 0, 1, min_val, max_val) for i in range(len(center))]<br>    mapped_centers.append(mapped_center)<br><br># print(\"Cluster IDs:\", ids)<br># print(\"Cluster Centers (avg):\", mapped_centers)<br><br># Assign the output parameters<br>avg = th.list_to_tree(mapped_centers)<br>i = th.list_to_tree(inertias)<br><br><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Applying a clustering algorithm to an inventory of irregular unique objects can help to reduce the complexity involved in designing with such parts significantly. By dividing the inventory items into groups with similar characteristics, each group can then be represented by one &#8220;proto-part&#8221; instead, therefore reducing the amount of unique elements to be handled in [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","_jetpack_memberships_contains_paid_content":false,"footnotes":"[{\"content\":\"<sub><em>McDonough, W. and Braungart, M. (2002) Cradle to cradle : remaking the way we make things. 1. ed.. New York, NY.<\/em><\/sub>\",\"id\":\"e685bd81-d93e-4ea6-b783-89c219d31b7a\"},{\"content\":\"<sub>from <a href=\\\"https:\/\/medium.com\/@pranav3nov\/understanding-k-means-clustering-f5e2e84d2129\\\">https:\/\/medium.com\/@pranav3nov\/understanding-k-means-clustering-f5e2e84d2129<\/a><em> (last access September 10th 2024)<\/em><\/sub>\",\"id\":\"21308f38-2fc9-42eb-abac-c7900b3e7b6a\"},{\"content\":\"<em><sub>from <a href=\\\"https:\/\/medium.com\/@zalarushirajsinh07\/the-elbow-method-finding-the-optimal-number-of-clusters-d297f5aeb189\\\">https:\/\/medium.com\/@zalarushirajsinh07\/the-elbow-method-finding-the-optimal-number-of-clusters-d297f5aeb189<\/a><\/sub><\/em> (<sub><em>(last access September 10th 2024)<\/em><\/sub>)\",\"id\":\"08d59281-f7bc-4fdd-baf6-2d6ff4eefae9\"}]"},"categories":[7],"tags":[20,38,37,36,34,35],"class_list":["post-703","post","type-post","status-publish","format-standard","hentry","category-digital-studies","tag-bike-frames","tag-catalog","tag-data-management","tag-inventory","tag-k-means","tag-programming"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/inventorics.com\/index.php?rest_route=\/wp\/v2\/posts\/703","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/inventorics.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/inventorics.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/inventorics.com\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/inventorics.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=703"}],"version-history":[{"count":19,"href":"https:\/\/inventorics.com\/index.php?rest_route=\/wp\/v2\/posts\/703\/revisions"}],"predecessor-version":[{"id":742,"href":"https:\/\/inventorics.com\/index.php?rest_route=\/wp\/v2\/posts\/703\/revisions\/742"}],"wp:attachment":[{"href":"https:\/\/inventorics.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=703"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/inventorics.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=703"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/inventorics.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=703"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}