hierarchical-spectral-clustering-0.2.1.0: src/Math/Clustering/Hierarchical/Spectral/Eigen/AdjacencyMatrix.hs
{- Math.Clustering.Hierarchical.Spectral.Eigen.AdjacencyMatrix
Gregory W. Schwartz
Collects the functions pertaining to hierarchical spectral clustering.
-}
{-# LANGUAGE BangPatterns #-}
module Math.Clustering.Hierarchical.Spectral.Eigen.AdjacencyMatrix
( hierarchicalSpectralCluster
, AdjacencyMatrix (..)
, Items (..)
) where
-- Remote
import Data.Bool (bool)
import Data.Clustering.Hierarchical (Dendrogram (..))
import Data.Maybe (fromMaybe)
import Data.Tree (Tree (..))
import Math.Clustering.Spectral.Eigen.AdjacencyMatrix (spectralClusterNorm, spectralClusterKNorm)
import Math.Modularity.Eigen.Sparse (getModularity)
import Math.Modularity.Types (Q (..))
import Safe (headMay)
import qualified Data.Foldable as F
import qualified Data.Set as Set
import qualified Data.Eigen.SparseMatrix as S
import qualified Data.Vector as V
import qualified Data.Vector.Storable as VS
-- Local
import Math.Clustering.Hierarchical.Spectral.Types
import Math.Clustering.Hierarchical.Spectral.Utility
type AdjacencyMatrix = S.SparseMatrixXd
type Items a = V.Vector a
-- | Check if there is more than one cluster.
hasMultipleClusters :: S.SparseMatrixXd -> Bool
hasMultipleClusters = (> 1)
. Set.size
. Set.fromList
. concat
. S.toDenseList
-- | Generates a tree through divisive hierarchical clustering using
-- Newman-Girvan modularity as a stopping criteria. Can also use minimum number
-- of observations in a cluster as the stopping criteria.
hierarchicalSpectralCluster :: EigenGroup
-> Maybe NumEigen
-> Maybe Int
-> Maybe Q
-> Items a
-> AdjacencyMatrix
-> ClusteringTree a
hierarchicalSpectralCluster !eigenGroup !numEigenMay !minSizeMay !minModMay !items !adjMat =
if S.rows adjMat > 1
&& hasMultipleClusters clusters
&& ngMod > minMod
&& S.rows left >= minSize
&& S.rows right >= minSize
then do
Node { rootLabel = vertex
, subForest = [ hierarchicalSpectralCluster
eigenGroup
numEigenMay
minSizeMay
minModMay
(subsetVector items leftIdxs)
left
, hierarchicalSpectralCluster
eigenGroup
numEigenMay
minSizeMay
minModMay (subsetVector items rightIdxs)
right
]
}
else
Node {rootLabel = vertex, subForest = []}
where
clusters = spectralClustering eigenGroup adjMat
spectralClustering :: EigenGroup -> AdjacencyMatrix -> S.SparseMatrixXd
spectralClustering SignGroup = spectralClusterNorm
spectralClustering KMeansGroup = spectralClusterKNorm numEigen 2
minMod = fromMaybe (Q 0) minModMay
minSize = fromMaybe 1 minSizeMay
numEigen = fromMaybe 1 numEigenMay
vertex = ClusteringVertex { _clusteringItems = items
, _ngMod = ngMod
}
ngMod = getModularity clusters adjMat
getIdxs val = VS.ifoldr' (\ !i !v !acc -> bool acc (i:acc) $ v == val) []
. VS.fromList
. concat
. S.toDenseList
leftIdxs = getIdxs 0 clusters
rightIdxs = getIdxs 1 clusters
left = S.squareSubset leftIdxs adjMat
right = S.squareSubset rightIdxs adjMat