git.iko.soy/distributed-process
on master help sign in
Iterate the local k-means and generate gnuplots
commit9403fd0c08381264dc72959ea11a75239c45b949 authorEdsko de Vries <edsko@edsko.net> dateWed 26 Sep 2012, 10:51 (14 years ago) parent8e92096
2 files changed+49−16
distributed-process-demos/src/MapReduce/KMeans.hs+4−3 distributed-process-demos/src/MapReduce/SimpleLocalnet.hs+45−13
distributed-process-demos/src/MapReduce/KMeans.hs+4−3
@@ -1,5 +1,6 @@
11module KMeans
22 ( Point
3+ , Cluster
34 , localKMeans
45 ) where
56
@@ -27,14 +28,14 @@ nearest p = minimumBy (compare `on` distanceSq p)
2728center :: [Point] -> Point
2829center ps = let (xs, ys) = unzip ps in (average xs, average ys)
2930
30−kmeans :: Array Int Point -> MapReduce (Int, Int) [Cluster] Cluster Point Point
31+kmeans :: Array Int Point -> MapReduce (Int, Int) [Cluster] Cluster Point ([Point], Point)
3132kmeans points = MapReduce {
3233 mrMap = \(lo, hi) cs -> [ let p = points ! i in (nearest p cs, p)
3334 | i <- [lo .. hi]
3435 ]
35− , mrReduce = \_ ps -> center ps
36+ , mrReduce = \_ ps -> (ps, center ps)
3637 }
3738
38−localKMeans :: Array Int Point -> [Cluster] -> Map Cluster Point
39+localKMeans :: Array Int Point -> [Cluster] -> Map Cluster ([Point], Point)
3940localKMeans points cs =
4041 localMapReduce (kmeans points) (Map.fromList [(bounds points, cs)])
distributed-process-demos/src/MapReduce/SimpleLocalnet.hs+45−13
@@ -1,4 +1,5 @@
11import System.Environment (getArgs)
2+import System.IO
23import Control.Applicative
34import Control.Monad
45import System.Random
@@ -7,7 +8,7 @@ import Control.Distributed.Process.Node (initRemoteTable)
78import Control.Distributed.Process.Backend.SimpleLocalnet
89import Data.Map (Map)
910import Data.Array (Array, listArray)
10−import qualified Data.Map as Map (fromList)
11+import qualified Data.Map as Map (fromList, toList, size, elems)
1112
1213import qualified CountWords
1314import qualified MapReduce
@@ -18,17 +19,6 @@ rtable = MapReduce.__remoteTable
1819 . CountWords.__remoteTable
1920 $ initRemoteTable
2021
21−constructInput :: [FilePath] -> IO (Map FilePath CountWords.Document)
22−constructInput files = do
23− contents <- mapM readFile files
24− return . Map.fromList $ zip files contents
25−
26−randomPoint :: IO KMeans.Point
27−randomPoint = (,) <$> randomIO <*> randomIO
28−
29−arrayFromList :: [e] -> Array Int e
30−arrayFromList xs = listArray (0, length xs - 1) xs
31−
3222main :: IO ()
3323main = do
3424 args <- getArgs
@@ -50,9 +40,51 @@ main = do
5040 -- Local k-means
5141 "local" : "kmeans" : [] -> do
5242 points <- replicateM 1000 randomPoint
53− print $ KMeans.localKMeans (arrayFromList points) (take 10 points)
43+ let kmeans = KMeans.localKMeans (arrayFromList points)
44+
45+ let it 0 = kmeans (take 5 points)
46+ it n = let clusters = it (n - 1) in
47+ kmeans (map snd $ Map.elems clusters)
48+
49+ forM_ ([0 .. 4] :: [Int]) $ \n ->
50+ withFile ("plot" ++ show n) WriteMode $
51+ createGnuPlot (it n)
5452
5553 -- Generic slave for distributed examples
5654 "slave" : host : port : [] -> do
5755 backend <- initializeBackend host port rtable
5856 startSlave backend
57+
58+--------------------------------------------------------------------------------
59+-- Auxiliary --
60+--------------------------------------------------------------------------------
61+
62+constructInput :: [FilePath] -> IO (Map FilePath CountWords.Document)
63+constructInput files = do
64+ contents <- mapM readFile files
65+ return . Map.fromList $ zip files contents
66+
67+randomPoint :: IO KMeans.Point
68+randomPoint = (,) <$> randomIO <*> randomIO
69+
70+arrayFromList :: [e] -> Array Int e
71+arrayFromList xs = listArray (0, length xs - 1) xs
72+
73+-- | Create a gnuplot data file for the output of the k-means algorithm
74+--
75+-- To plot the data, use
76+--
77+-- > plot "<<filename>>" u 1:2:3 with points palette
78+createGnuPlot :: Map KMeans.Cluster ([KMeans.Point], KMeans.Point) -> Handle -> IO ()
79+createGnuPlot clusters h =
80+ mapM_ printPoint . flatten . zip colors . Map.toList $ clusters
81+ where
82+ printPoint (x, y, color) =
83+ hPutStrLn h $ show x ++ " " ++ show y ++ " " ++ show color
84+
85+ flatten :: [(Float, (KMeans.Cluster, ([KMeans.Point], KMeans.Point)))]
86+ -> [(Double, Double, Float)]
87+ flatten = concat . map (\(color, (_, (points, _))) -> map (\(x, y) -> (x, y, color)) points)
88+
89+ colors :: [Float]
90+ colors = [0, 1 / fromIntegral (Map.size clusters) .. 1]