som 4.1 → 4.2
raw patch · 3 files changed
+89/−60 lines, 3 filesdep ~gridPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: grid
API changes (from Hackage documentation)
+ Data.Datamining.Pattern: absDifference :: Num a => a -> a -> a
+ Data.Datamining.Pattern: adjustNum :: (Num a, Ord a, Eq a) => a -> a -> a -> a
Files
- som.cabal +3/−3
- src/Data/Datamining/Clustering/SOMInternal.hs +22/−23
- src/Data/Datamining/Pattern.hs +64/−34
som.cabal view
@@ -1,5 +1,5 @@ name: som-version: 4.1+version: 4.2 synopsis: Self-Organising Maps description: A Kohonen Self-organising Map (SOM) maps input patterns onto a regular grid (usually two-dimensional) where each@@ -31,7 +31,7 @@ base-unicode-symbols ==0.2.*, binary == 0.5.* || == 0.6.* || == 0.7.*, containers ==0.4.2.* || ==0.5.*,- grid ==4.*,+ grid >=6.1 && ==6.*, MonadRandom ==0.1.* ghc-options: -Wall exposed-modules: Data.Datamining.Clustering.SOM,@@ -46,7 +46,7 @@ QuickCheck ==2.5.* || ==2.6.*, test-framework == 0.8.*, som,- grid ==4.*,+ grid >=6.1 && ==6.*, base-unicode-symbols ==0.2.*, MonadRandom ==0.1.*, random ==1.0.*
src/Data/Datamining/Clustering/SOMInternal.hs view
@@ -11,7 +11,7 @@ -- use @SOM@ instead. This module is subject to change without notice. -- -------------------------------------------------------------------------{-# LANGUAGE UnicodeSyntax, TypeFamilies, FlexibleContexts, +{-# LANGUAGE UnicodeSyntax, TypeFamilies, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses #-} module Data.Datamining.Clustering.SOMInternal@@ -41,8 +41,8 @@ -- | A Self-Organising Map (SOM). -- -- Although @SOM@ implements @GridMap@, most users will only need the--- interface provided by @Classifier@. If you chose to use the --- @GridMap@ functions, please note:+-- interface provided by @Data.Datamining.Clustering.Classifier@. If+-- you chose to use the @GridMap@ functions, please note: -- -- 1. The functions @adjust@, and @adjustWithKey@ do not increment the -- counter. You can do so manually with @incrementCounter@.@@ -63,11 +63,13 @@ instance (G.Grid (gm p)) ⇒ G.Grid (SOM gm k p) where type Index (SOM gm k p) = G.Index (gm p)+ type Direction (SOM gm k p) = G.Direction (gm p) indices = G.indices . sGridMap distance = G.distance . sGridMap neighbours = G.neighbours . sGridMap contains = G.contains . sGridMap viewpoint = G.viewpoint . sGridMap+ directionTo = G.directionTo . sGridMap tileCount = G.tileCount . sGridMap null = G.null . sGridMap nonNull = G.nonNull . sGridMap@@ -120,10 +122,10 @@ where ds = GM.toList . GM.map (p `difference`) . sGridMap $ s bmu = fst . minimumBy (comparing snd) $ ds -instance - (GM.GridMap gm p, k ~ G.Index (GM.BaseGrid gm p), Pattern p, +instance+ (GM.GridMap gm p, k ~ G.Index (GM.BaseGrid gm p), Pattern p, G.Grid (gm p), GM.GridMap gm (Metric p), k ~ G.Index (gm p),- k ~ G.Index (GM.BaseGrid gm (Metric p)), Ord (Metric p)) ⇒ + k ~ G.Index (GM.BaseGrid gm (Metric p)), Ord (Metric p)) ⇒ Classifier (SOM gm) k p where toList = GM.toList . sGridMap numModels = G.tileCount . sGridMap@@ -154,16 +156,16 @@ -- We recommend setting this parameter to the number of patterns -- (or pattern batches) that will be presented to the classifier. An -- estimate is fine.-defaultSOM +defaultSOM ∷ Floating (Metric p) ⇒ gm p → Metric p → Metric p → Int → SOM gm k p-defaultSOM gm r w t = - SOM { - sGridMap=gm, - sLearningFunction=decayingGaussian r w t, +defaultSOM gm r w t =+ SOM {+ sGridMap=gm,+ sLearningFunction=decayingGaussian r w t, sCounter=0 } --- | Creates a classifier with a custom learning function. +-- | Creates a classifier with a custom learning function. -- Usage is @'customSOM' gm g@, where: -- -- [@gm@] The geometry and initial models for this classifier.@@ -172,8 +174,8 @@ -- -- [@f@] A function used to adjust the models in the classifier. -- This function will be invoked with two parameters.--- The first parameter will indicate how many patterns (or pattern --- batches) have previously been presented to this classifier. +-- The first parameter will indicate how many patterns (or pattern+-- batches) have previously been presented to this classifier. -- Typically this is used to make the learning rate decay over time. -- The second parameter to the function is the grid distance from -- the node being updated to the BMU (Best Matching Unit).@@ -181,22 +183,21 @@ -- which the node's model should be updated to match the target). -- The learning rate should be between zero and one. customSOM ∷ gm p → (Int → Int → Metric p) → SOM gm k p-customSOM gm f = +customSOM gm f = SOM { sGridMap=gm, sLearningFunction=f, sCounter=0 } - -- | Calculates @r/e/^(-d^2/2w^2)@. -- This form of the Gaussian function is useful as a learning rate -- function. In @'gaussian' r w d@, @r@ specifies the highest learning -- rate, which will be applied to the SOM node that best matches the--- input pattern. The learning rate applied to other nodes will be --- applied based on their distance @d@ from the best matching node. +-- input pattern. The learning rate applied to other nodes will be+-- applied based on their distance @d@ from the best matching node. -- The value @w@ controls the \'width\' of the Gaussian. Higher values--- of @w@ cause the learning rate to fall off more slowly with +-- of @w@ cause the learning rate to fall off more slowly with -- distance @d@. gaussian ∷ Floating a ⇒ a → a → Int → a gaussian r w d = r * exp (-d'*d'/(2*w*w))@@ -204,14 +205,12 @@ -- | Configures a typical learning function for classifiers. -- @'decayingGaussian' r w0 tMax@ returns a bell curve-shaped--- function. At time zero, the maximum learning rate (applied to the +-- function. At time zero, the maximum learning rate (applied to the -- BMU) is @r@, and the neighbourhood width is @w@. Over time the bell -- curve shrinks and the learning rate tapers off, until at time -- @tMax@, the learning rate is negligible. decayingGaussian ∷ Floating a ⇒ a → a → Int → (Int → Int → a)-decayingGaussian r w0 tMax = +decayingGaussian r w0 tMax = \t d → let t' = fromIntegral t in gaussian r w0 d * exp (-t'/tMax') where tMax' = fromIntegral tMax--
src/Data/Datamining/Pattern.hs view
@@ -16,19 +16,23 @@ ( -- * Patterns Pattern(..),+ -- * Numbers as patterns+ -- $Num+ adjustNum,+ absDifference, -- * Numeric vectors as patterns+ -- ** Raw vectors+ -- $Vector+ adjustVector,+ euclideanDistanceSquared,+ magnitudeSquared, -- ** Normalised vectors NormalisedVector, normalise, -- ** Scaled vectors ScaledVector, scale,- scaleAll,- -- ** Useful functions- -- $Vector- adjustVector,- euclideanDistanceSquared,- magnitudeSquared+ scaleAll ) where import Data.Eq.Unicode ((≡))@@ -37,35 +41,63 @@ -- | A pattern to be learned or classified. class Pattern p where type Metric p- -- | Compares two patterns and returns a /non-negative/ number - -- representing how different the patterns are. A result of @0@ + -- | Compares two patterns and returns a /non-negative/ number+ -- representing how different the patterns are. A result of @0@ -- indicates that the patterns are identical. difference ∷ p → p → Metric p -- | @'makeSimilar' target amount pattern@ returns a modified copy of- -- @pattern@ that is more similar to @target@ than @pattern@ is. The - -- magnitude of the adjustment is controlled by the @amount@ - -- parameter, which should be a number between 0 and 1. Larger + -- @pattern@ that is more similar to @target@ than @pattern@ is. The+ -- magnitude of the adjustment is controlled by the @amount@+ -- parameter, which should be a number between 0 and 1. Larger -- values for @amount@ permit greater adjustments. If @amount@=1, -- the result should be identical to the @target@. If @amount@=0, -- the result should be the unmodified @pattern@. makeSimilar ∷ p → Metric p → p → p --+-- Using numbers as patterns.+--++absDifference :: Num a => a -> a -> a+absDifference x y = abs (x - y)++adjustNum :: (Num a, Ord a, Eq a) => a -> a -> a -> a+adjustNum target r x+ | r < 0 = error "Negative learning rate"+ | r > 1 = error "Learning rate > 1"+ | r ≡ 1 = x+ | otherwise = adjustNum' r target x++-- Note that parameters are swapped+adjustNum' :: Num a => a -> a -> a -> a+adjustNum' r target x = x + r*(target - x)++{- $Num+If you wish to use, say, a @Double@ as a pattern, one option is to+use @no-warn-orphans@ and add the following to your code:++> instance Double ⇒ Pattern Double where+> type Metric Double = Double+> difference = euclideanDistanceSquared+> makeSimilar = adjustVector+-}++-- -- Using numeric vectors as patterns.--- +-- magnitudeSquared ∷ Num a ⇒ [a] → a magnitudeSquared xs = sum $ map (\x → x*x) xs --- | Calculates the square of the Euclidean distance between two +-- | Calculates the square of the Euclidean distance between two -- vectors. euclideanDistanceSquared ∷ Num a ⇒ [a] → [a] → a euclideanDistanceSquared xs ys = magnitudeSquared $ zipWith (-) xs ys --- | @'adjustVector' target amount vector@ adjusts @vector@ to move it +-- | @'adjustVector' target amount vector@ adjusts @vector@ to move it -- closer to @target@. The amount of adjustment is controlled by the -- learning rate @r@, which is a number between 0 and 1. Larger values--- of @r@ permit more adjustment. If @r@=1, the result will be +-- of @r@ permit more adjustment. If @r@=1, the result will be -- identical to the @target@. If @amount@=0, the result will be the -- unmodified @pattern@. adjustVector ∷ (Num a, Ord a, Eq a) ⇒ [a] → a → [a] → [a]@@ -73,11 +105,9 @@ | r < 0 = error "Negative learning rate" | r > 1 = error "Learning rate > 1" | r ≡ 1 = xs- | otherwise = zipWith (+) ys deltas- where ds = zipWith (-) xs ys- deltas = map (r *) ds+ | otherwise = zipWith (adjustNum' r) xs ys --- | A vector that has been normalised, i.e., the magnitude of the +-- | A vector that has been normalised, i.e., the magnitude of the -- vector = 1. data NormalisedVector a = NormalisedVector [a] deriving Show @@ -90,31 +120,31 @@ norm xs = sqrt $ sum (map f xs) where f x = x*x -instance (Floating a, Fractional a, Ord a, Eq a) ⇒ +instance (Floating a, Fractional a, Ord a, Eq a) ⇒ Pattern (NormalisedVector a) where type Metric (NormalisedVector a) = a- difference (NormalisedVector xs) (NormalisedVector ys) = + difference (NormalisedVector xs) (NormalisedVector ys) = euclideanDistanceSquared xs ys- makeSimilar (NormalisedVector xs) r (NormalisedVector ys) = + makeSimilar (NormalisedVector xs) r (NormalisedVector ys) = normalise $ adjustVector xs r ys --- | A vector that has been scaled so that all elements in the vector --- are between zero and one. To scale a set of vectors, use --- @'scaleAll'@. Alternatively, if you can identify a maximum and --- minimum value for each element in a vector, you can scale +-- | A vector that has been scaled so that all elements in the vector+-- are between zero and one. To scale a set of vectors, use+-- @'scaleAll'@. Alternatively, if you can identify a maximum and+-- minimum value for each element in a vector, you can scale -- individual vectors using @'scale'@. data ScaledVector a = ScaledVector [a] deriving Show -- | Given a vector @qs@ of pairs of numbers, where each pair represents--- the maximum and minimum value to be expected at each index in --- @xs@, @'scale' qs xs@ scales the vector @xs@ element by element, +-- the maximum and minimum value to be expected at each index in+-- @xs@, @'scale' qs xs@ scales the vector @xs@ element by element, -- mapping the maximum value expected at that index to one, and the -- minimum value to zero. scale ∷ Fractional a ⇒ [(a,a)] → [a] → ScaledVector a scale qs xs = ScaledVector $ zipWith scaleValue qs xs -- | Scales a set of vectors by determining the maximum and minimum--- values at each index in the vector, and mapping the maximum +-- values at each index in the vector, and mapping the maximum -- value to one, and the minimum value to zero. scaleAll ∷ (Fractional a, Ord a) ⇒ [[a]] → [ScaledVector a] scaleAll xss = map (scale qs) xss@@ -133,17 +163,17 @@ instance (Fractional a, Ord a, Eq a) ⇒ Pattern (ScaledVector a) where type Metric (ScaledVector a) = a- difference (ScaledVector xs) (ScaledVector ys) = + difference (ScaledVector xs) (ScaledVector ys) = euclideanDistanceSquared xs ys makeSimilar (ScaledVector xs) r (ScaledVector ys) = ScaledVector $ adjustVector xs r ys {- $Vector-If you wish to use raw numeric vectors as a pattern, use-@no-warn-orphans@ and add the following to your code:+If you wish to use raw numeric vectors as a pattern, one option is to+use @no-warn-orphans@ and add the following to your code: -> instance (Floating a, Fractional a, Ord a, Eq a) ⇒ Pattern [a] a where+> instance (Floating a, Fractional a, Ord a, Eq a) ⇒ Pattern [a] where+> type Metric [a] = a > difference = euclideanDistanceSquared > makeSimilar = adjustVector -}-