Search code examples
roptimizationk-meansparticle-swarm

PSO and K-means based Text Document Clustering in R


I am newbie to Particle Swarm Optimization. I read research paper on Clustering based on PSO and K-means but I did not found any working example of the same. Any kind of help is much appreciated. Thanks in advance!

I want to perform text document clustering using PSO and K-means in R. I have the basic idea that first PSO will give me the optimised values of the cluster centroids, then I have to use those optimised value of cluster centroids of PSO as the initial cluster centroid for k-means to get cluster of documents.

Below are the codes which describe what I have done so far!

#Import library
library(pdist)
library(hydroPSO)

#Create matrix and suppose it is our document term matrix which we get after
the cleaning of corpus

( In my actual data I have 20 documents with 951 terms i.e., dim(dtm) = 20*951 )

matri <- matrix(data = seq(1, 20, 1), nrow = 4, ncol = 7, byrow = TRUE)  
matri
      [,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,]    1    2    3    4    5    6    7
[2,]    8    9   10   11   12   13   14
[3,]   15   16   17   18   19   20    1
[4,]    2    3    4    5    6    7    8

#Initially select first and second row as centroids
cj <- matri[1:2,]

#Calculate Euclidean Distance of each data point from centroids
vm <- as.data.frame(t(as.matrix(pdist(matri, cj))))
vm
     V1       V2       V3        V4
1  0.00000  18.52026 34.81379  2.645751
2 18.52026  0.00000  21.51744 15.874508

#Create binary matrix S in which 1 means Instance Ii is allocated to the cluster Cj otherwise 0.  
S <- matrix(data = NA, nrow = nrow(vm), ncol = ncol(vm))

for(i in 1:nrow(vm)){
  for(j in 1:ncol(vm)){
       cd <- which.min(vm[, j])
       ifelse(cd==i,  S[i,j] <-1, S[i,j] <-0)

     }
  }

S
      [,1] [,2] [,3] [,4]
[1,]    1    0    0    1
[2,]    0    1    1    0

#Apply `hydroPSO()` to get optimised values of centroids.
set.seed(5486)
D <- 4 # Dimension
lower <- rep(0, D)
upper <- rep(10, D)
m_s <- matrix(data = NA, nrow = nrow(S), ncol = ncol(matri))
Fn= function(y) {  #Objective Function which has to be minimised

for(j in 1:ncol(matri)){
    for(i in 1:nrow(matri)){
        for(k in 1:nrow(y)){
            for(l in 1:ncol(y)){
                m_s[k,] <- colSums(matri[y[k,]==1,])/sum(y[k,])
            }
        }
     }
}

  sm <- sum(m_s)/ nrow(S)
  return(sm)

  }

hh1 <- hydroPSO(S,fn=Fn, lower=lower, upper=upper,
                control=list(write2disk=FALSE, npart=3))

But the above hydroPSO() function is not working. It is giving error Error in 1:nrow(y) : argument of length 0. I searched for it but didn't get any solution which works for me.

I also made some changes in my objective function and this time hydroPSO() worked but I guess not correctly. I am passing my initial centroid matrix as a parameter whose dimension is 2*7 but the function returns only 1*7 optimised values. I am not getting its reason.

set.seed(5486)
D <- 7# Dimension
lower <- rep(0, D)
upper <- rep(10, D)

Fn = function(x){
vm <- as.data.frame(t(as.matrix(pdist(matri, x))))

S <- matrix(data = NA, nrow = nrow(vm), ncol = ncol(vm))

for(i in 1:nrow(vm)){
  for(j in 1:ncol(vm)){
       cd <- which.min(vm[, j])
       ifelse(cd==i,  S[i,j] <-1, S[i,j] <-0)

     }
  }

  m_s <- matrix(data = NA, nrow = nrow(S), ncol = ncol(matri))

 for(j in 1:ncol(matri)){
    for(i in 1:nrow(matri)){
        for(k in 1:nrow(S)){
            for(l in 1:ncol(S)){
                m_s[k,] <- colSums(matri[S[k,]==1,])/sum(S[k,])
            }
        }
    }
  }

sm <- sum(m_s)/ nrow(S)
return(sm)

}
hh1 <- hydroPSO(cj,fn=Fn, lower=lower, upper=upper,
                  control=list(write2disk=FALSE, npart=2, K=2))  

Output of the above function.

## $par
## Param1    Param2    Param3    Param4    Param5    Param6  Param7 
## 8.6996174 2.1952303 5.6903588 0.4471795 3.7103161 1.6605425 8.2717574 
## 
## $value
## [1] 61.5
## 
## $best.particle
## [1] 1
## 
## $counts
## function.calls     iterations    regroupings 
##           2000           1000              0 
## 
## $convergence
## [1] 3
## 
## $message
## [1] "Maximum number of iterations reached"

I guess I am passing parameters to the hydroPSO() in a wrong way. Please correct me where I'm doing it wrong.

Thank you very much!


Solution

  • Instead of passing cj to hydroPSO() I used as.vector(t(cj)) in my second approach and it worked fine for me. I got 14 optimised values