Compiled, parallelized ordering plus a more functional approach. The switch between DistanceMatrix
and Outer
(for dm
) may be system dependent.
kMeans2[data_, k_]ordC :=
Module[Compile[{{x =, N[data]_Real, c1}},
dmat First@Ordering[x, cn1],
n = Length[data],RuntimeAttributes minpos,-> clusters{Listable},
Parallelization -> True];
kMeans2 sum// ClearAll;
kMeans2[data_, tk_] := 0Module[{x = Developer`ToPackedArray@N[data], dm},(*Randomly
choose kIf[ArrayDepth[x] centriods> from1 the|| datak*Length[x] points*)< 10^5,
c dm =(*Sqrt@*)Total[Outer[Subtract, RandomSample[x##, k];
1]^2, {3}] Do[t++;&,
(*Assigndm each= pointDistanceMatrix;
to the cluster];
of theNestWhile[
closest centriod*) With[
dmat = DistanceMatrix[x,{clusters c];=
With[{minpos = ordC[dmat];ordC[dm[x, Last@#]]},
clusters = Pick[x, minpos, #] & /@ Range@k;Range@k]},
(*Calculate the new{clusters, centriods*)
Mean /@ clusters}
cn = Mean /@ clusters;] &,
(*If* theinitial centriods{clusters, aremeans} the*)
"almost" same then{{}, terminate*)RandomSample[x, k]},
If[Norm[cNorm[Last[#1] - cnLast[#2], Infinity] <=- 0.001,
> 0 Break[]&,
c2,
= cn];, {10100 (*Maximum number of iterations*)]
];
Example:
foo = RandomReal[10, {10^3, 3}];
(SeedRandom[0];
km1 = kMeans[foo, 8];) // RepeatedTiming
(SeedRandom[0];
km2 = kMeans2[foo, 8];) // RepeatedTiming
km1 == km2
(*
{clusters0.212839, cNull}]
{0.0588948, Null}
True
*)