<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/finding-optimal-number-of-clusters/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://datascienceplus.com/finding-optimal-number-of-clusters/"> DataScience+</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>In this post we are going to have a look at one of the problems while applying clustering algorithms such as k-means and expectation maximization that is of determining the optimal number of clusters. The problem of determining what will be the best value for the number of clusters is often not very clear from the data set itself. There are a couple of techniques we will walk-through in this post which one can use to help determine the best k-value for a given data set.</p>
<p>To showcase these techniques we will use one of the readily available dataset from the <a target="_blank" rel="nofollow" href="https://archive.ics.uci.edu/ml/datasets/ser+Knowledge+Modeling+Data+(Students%27+Knowledge+Levels+on+DC+Electrical+Machines)#">UCI_Dataset_StudentKnowledge</a>.<br>
We will download the dataset in the current R studio environment:</p>
<pre>library(readr)
StudentKnowledgeData &lt;- read_csv(&quot;YourdownloadFolderPath/StudentKnowledgeData.csv&quot;)
View(StudentKnowledgeData)</pre>
<h2>Pre-processing</h2>
<p>This dataset is comma-separated with a header line. We will check for <code>NA</code> values and check if there are any categorical variable to ensure the data is ready for processing for the clustering algorithms. As this data set has low feature vector we will not focus on feature selection aspects but will work with all the available features.</p>
<pre>
mydata  = StudentKnowledgeData
#let us analyze the data to find if categorical variables are there and if so
#transform them.
mydata = as.data.frame(unclass(mydata))
summary(mydata)
dim(mydata)
# We can now remove any records that have NAs
myDataClean = na.omit(mydata)
dim(myDataClean)
summary(myDataClean)
<em>[1] 402 5
STG SCG STR LPR Min. :0.0000 Min. :0.0000 Min. :0.0100 Min. :0.0000 1st Qu.:0.2000 1st Qu.:0.2000 1st Qu.:0.2700 1st Qu.:0.2500 Median :0.3025 Median :0.3000 Median :0.4450 Median :0.3300 Mean :0.3540 Mean :0.3568 Mean :0.4588 Mean :0.4324 3rd Qu.:0.4800 3rd Qu.:0.5100 3rd Qu.:0.6800 3rd Qu.:0.6500 Max. :0.9900 Max. :0.9000 Max. :0.9500 Max. :0.9900</em></pre>
<p>Once we have done pre-processing to ensure the data is ready for further applications. Let us try and scale and center this dataset.</p>
<pre>
scaled_data = as.matrix(scale(myDataClean))
</pre>
<h2>Clustering Algorithm – k means a sample example of finding optimal number of clusters in it</h2>
<p>Let us try to create the clusters for this data. As we can observe this data doesnot have a pre-defined class/output type defined and so it becomes necessary to know what will be an optimal number of clusters.Let us choose random value of cluster numbers for now and see how the clusters are created.</p>
<p>Let us start with k=3 and check what the results are. R comes with a builtin kmeans() function and we do not need to import any extra package for this.</p>
<pre>
#Let us apply kmeans for k=3 clusters 
kmm = kmeans(scaled_data,3,nstart = 50,iter.max = 15) #we keep number of iter.max=15 to ensure the algorithm converges and nstart=50 to #ensure that atleat 50 random sets are choosen  
kmm
<em>K-means clustering with 3 clusters of sizes 93, 167, 142
Cluster means:
STG SCG STR LPR PEG
1 0.573053974 0.3863411 0.2689915 1.3028712 0.1560779
2 -0.315847301 -0.4009366 -0.3931942 -0.1794893 -0.8332218
3 -0.003855777 0.2184978 0.2862481 -0.6421993 0.8776957
Clustering vector:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ...................................................................................
Within cluster sum of squares by cluster:
[1] 394.5076 524.4177 497.7787
(between_SS / total_SS = 29.3 %)
Available components:
[1] &quot;cluster&quot; &quot;centers&quot; &quot;totss&quot; &quot;withinss&quot; &quot;tot.withinss&quot;
[6] &quot;betweenss&quot; &quot;size&quot; &quot;iter&quot; &quot;ifault&quot; </em></pre>
<p>When we check the (between_SS / total_SS) we find it to be low. This ratio actually accounts for the amount of total sum of squares of the data points which is between the clusters. We want to increase this value and as we increase the number of clusters we see it increasing , but we do not want to overfit the data. So we see that with k=401 in this we will have 402 clusters which completely overfits the data. So the idea is to find such a value of k for which the model is not overfitting and at the same time clusters the data as per the actual distribution. Let us now approach how we will solve this problem of finding the best number of clusters.</p>
<h2> Elbow Method</h2>
<p>The elbow method looks at the percentage of variance explained as a function of the number of clusters: One should choose a number of clusters so that adding another cluster doesn’t give much better modeling of the data. More precisely, if one plots the percentage of variance explained by the clusters against the number of clusters, the first clusters will add much information (explain a lot of variance), but at some point the marginal gain will drop, giving an angle in the graph. The number of clusters is chosen at this point, hence the “elbow criterion”. This “elbow” cannot always be unambiguously identified.</p>
<pre>
#Elbow Method for finding the optimal number of clusters
set.seed(123)
# Compute and plot wss for k = 2 to k = 15.
k.max &lt;- 15
data &lt;- scaled_data
wss &lt;- sapply(1:k.max, 
              function(k){kmeans(data, k, nstart=50,iter.max = 15 )$tot.withinss})
wss
plot(1:k.max, wss,
     type=&quot;b&quot;, pch = 19, frame = FALSE, 
     xlab=&quot;Number of clusters K&quot;,
     ylab=&quot;Total within-clusters sum of squares&quot;)
<em> [1] 2005.0000 1635.8573 1416.7041 1253.9959 1115.4657 1026.0506 952.4835 887.7202
[9] 830.8277 780.2121 735.6714 693.7745 657.0939 631.5901 608.3576</em></pre>
<p>The plot can be seen below:<br>
<a title="" data-rel="lightbox-0" target="_blank" rel="nofollow" href="https://i0.wp.com/datascienceplus.com/wp-content/uploads/2017/02/Elbow_Method.png?ssl=1"><img sizes="(max-width: 490px) 100vw, 490px" alt="" class="wp-image-5470" src="https://i1.wp.com/datascienceplus.com/wp-content/uploads/2017/02/Elbow_Method-490x285.png?resize=456%2C265&ssl=1" data-recalc-dims="1"></a></p>
<p>Therefore for k=4 the between_ss/total_ss ratio tends to change slowly and remain less changing as compared to other k’s.so for this data k=4 should be a good choice for number of clusters however k=5 also seems to be a potential candidate. So how do we decide what will be the optimal choice. So we look at the second approach which comes with a new package.</p>
<h2>Bayesian Inference Criterion for k means</h2>
<p>The k-means model is “almost” a Gaussian mixture model and one can construct a likelihood for the Gaussian mixture model and thus also determine information criterion values.<br>
We install the <code>mclust</code> package and we will use the Mclust method of it.Determine the optimal model and number of clusters according to the Bayesian Information Criterion for expectation-maximization, initialized by hierarchical clustering for parameterized Gaussian mixture models. In this method we had set the modelNames parameter to mclust.options(“emModelNames”) so that it includes only those models for evaluation where the number of observation is greater than the dimensions of the dataset here 402>5. The best model selected was EVI (Equal Volume but Variable shape and using Identity Matrix for the eigen values) with number of clusters 3 and 4. So based on this and the previous method the natural number of clusters choice was 4. To further validate this we checked for the BIC(Bayesian Information Criterion for k means) and it seems to validate the findings of Mclust package showing that cluster choice of 3 and 4 are the best and of highest value for this distribution of data. </p>
<pre>
d_clust &lt;- Mclust(as.matrix(scaled_data), G=1:15, 
                  modelNames = mclust.options(&quot;emModelNames&quot;))
d_clust$BIC
plot(d_clust)
<em>Bayesian Information Criterion (BIC):
EII VII EEI VEI EVI VVI EEE EVE
1 -5735.105 -5735.105 -5759.091 -5759.091 -5759.091 -5759.091 -5758.712 -5758.712
2 -5731.019 -5719.188 -5702.988 -5635.324 -5725.379 -5729.256 -5698.095 -5707.733
3 -5726.577 -5707.840 -5648.033 -5618.274 -5580.305 -5620.816 -5693.977 -5632.555
..................................................................................
VEE VVE EEV VEV EVV VVV
1 -5758.712 -5758.712 -5758.712 -5758.712 -5758.712 -5758.712
2 -5704.051 -5735.383 -5742.110 -5743.216 -5752.709 -5753.597
3 -5682.312 -5642.217 -5736.306 -5703.742 -5717.796 -5760.915
..............................................................
Top 3 models based on the BIC criterion:
EVI,3 EVI,4 EEI,5 -5580.305 -5607.980 -5613.077 > plot(d_clust)
Model-based clustering plots: 1: BIC
2: classification
3: uncertainty
4: density
Selection: 1
</em></pre>
<p>The plot can be seen below where k=3 and k=4 are the best choices available.<br>
<a title="" data-rel="lightbox-1" target="_blank" rel="nofollow" href="https://i2.wp.com/datascienceplus.com/wp-content/uploads/2017/02/ModelBased_BIC.png?ssl=1"><img sizes="(max-width: 490px) 100vw, 490px" alt="" class="wp-image-5472" src="https://i1.wp.com/datascienceplus.com/wp-content/uploads/2017/02/ModelBased_BIC-490x285.png?resize=456%2C265&ssl=1" data-recalc-dims="1"></a></p>
<p>As we can see from the two approaches we can to a certain extent be sure of what an optimal value for the number of clusters can be for a clustering problem. There are few other techniques which can also be used. Let us take at one such approach using the <code>NbClust</code><br>
NbClust package provides 30 indices for determining the number of clusters and proposes to user the best clustering scheme from the different results obtained by varying all combinations of number of clusters, distance measures, and clustering methods</p>
<pre>
install.packages(&quot;NbClust&quot;,dependencies = TRUE)
library(NbClust)
nb &lt;- NbClust(scaled_data, diss=NULL, distance = &quot;euclidean&quot;, 
              min.nc=2, max.nc=5, method = &quot;kmeans&quot;, 
              index = &quot;all&quot;, alphaBeale = 0.1)
hist(nb$Best.nc[1,], breaks = max(na.omit(nb$Best.nc[1,])))
</pre>
<p>There is an important point to here that this method always takes into the majority of the indexes for each cluster size. So it is important to understand which of the indexes are relevant to the data and based on it to determine if the best choice is the maximum value suggested or any other value.<br>
As we see below looking at the Second differences D-index graph we know it is quite clear the best number of clusters is k=4.</p>
<p><a title="" data-rel="lightbox-2" target="_blank" rel="nofollow" href="https://i0.wp.com/datascienceplus.com/wp-content/uploads/2017/02/SecondDifferenceDindex.png?ssl=1"><img sizes="(max-width: 490px) 100vw, 490px" alt="" class="wp-image-5474" src="https://i1.wp.com/datascienceplus.com/wp-content/uploads/2017/02/SecondDifferenceDindex-490x285.png?resize=456%2C265&ssl=1" data-recalc-dims="1"></a></p>
<p>Hope this gives some of the insight how to use different resources in R to determine the optimal number of clusters for relocation algorithms like Kmeans or EM.</p>
<ul></ul>
<p><strong>
<p>Related Post</p>
<p>
<ol>
<li><a title="Permanent Link toAnalyzing the first Presidential Debate" target="_blank" rel="nofollow" href="https://datascienceplus.com/analyzing-the-first-presidential-debate/">Analyzing the first Presidential Debate</a></li>
<li><a title="Permanent Link toGoodReads: Machine Learning (Part 3)" target="_blank" rel="nofollow" href="https://datascienceplus.com/goodreads-machine-learning-part-3/">GoodReads: Machine Learning (Part 3)</a></li>
<li><a title="Permanent Link toMachine Learning for Drug Adverse Event Discovery" target="_blank" rel="nofollow" href="https://datascienceplus.com/machine-learning-for-drug-adverse-event-discovery/">Machine Learning for Drug Adverse Event Discovery</a></li>
<li><a title="Permanent Link toGoodReads: Exploratory data analysis and sentiment analysis (Part 2)" target="_blank" rel="nofollow" href="https://datascienceplus.com/exploratory-data-analysis-and-sentiment-analysis/">GoodReads: Exploratory data analysis and sentiment analysis (Part 2)</a></li>
<li><a title="Permanent Link toGoodReads: Webscraping and Text Analysis with R (Part 1)" target="_blank" rel="nofollow" href="https://datascienceplus.com/goodreads-webscraping-and-text-analysis-with-r-part-1/">GoodReads: Webscraping and Text Analysis with R (Part 1)</a></li>
</ol></strong>
<div>
<a target="_blank" rel="nofollow" href="http://feeds.feedburner.com/~ff/datascienceplus?a=lchhNqVE_yQ:aUkiipqg9x4:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/datascienceplus?i=lchhNqVE_yQ:aUkiipqg9x4:D7DqB2pKExk" border="0"></a> <a target="_blank" rel="nofollow" href="http://feeds.feedburner.com/~ff/datascienceplus?a=lchhNqVE_yQ:aUkiipqg9x4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/datascienceplus?d=qj6IDK7rITs" border="0"></a> <a target="_blank" rel="nofollow" href="http://feeds.feedburner.com/~ff/datascienceplus?a=lchhNqVE_yQ:aUkiipqg9x4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/datascienceplus?d=yIl2AUoC8zA" border="0"></a>
</div>
<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://datascienceplus.com/finding-optimal-number-of-clusters/"> DataScience+</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/search/data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/search/map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/search/animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/search/sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/search/SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/search/git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/search/hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/search/PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/search/time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/search/trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/E6f1_D871fM"></a></div>