Skip to content

Instantly share code, notes, and snippets.

@nigel-sampson
Created March 3, 2015 19:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nigel-sampson/221d49b939cad48a1fe2 to your computer and use it in GitHub Desktop.
Save nigel-sampson/221d49b939cad48a1fe2 to your computer and use it in GitHub Desktop.
Kmeans implementation in F#
namespace KMeans.Core
module Clustering =
type Distance<'a> = 'a -> 'a -> float
type Recenter<'a> = 'a list -> 'a
let sample n (xs : 'a list) =
let step = xs.Length / n
match step with
| _ when step <= 1 -> xs
| _ -> [0..n-1] |> List.map (fun s -> List.nth xs (s * step))
let closest (distance : Distance<'a>) (centers : 'a list) (x : 'a) =
let i, c = centers |> List.mapi (fun i c -> i, c) |> List.minBy (fun (i, c) -> distance c x)
(i, x)
let assign (distance : Distance<'a>) (centers : 'a list) (xs : 'a list) =
xs |> List.map (fun x -> closest distance centers x)
let changed (xs : (int * 'a) list) (ys : (int * 'a) list) =
List.zip xs ys
|> List.exists (fun ((i, _), (j, _)) -> i <> j)
let KMeans (distance : Distance<'a>) (recenter : Recenter<'a>) (n : int) (xs : 'a list) =
let rec calculate (centers : 'a list) (previous : (int * 'a) list) =
let next = assign distance centers xs
let changed = changed next previous
match changed with
| true ->
let recentered = centers |> List.mapi (fun i c -> next |> List.filter (fun (ai, x) -> i = ai)) |> List.map (fun a -> a |> List.map (fun (ai, x) -> x) |> recenter)
calculate recentered next
| false -> (centers, next)
let initalCenters = sample n xs
calculate initalCenters (xs |> List.map (fun x -> (-1, x))) |> fst
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment