+"""K-means module"""
+
+import random
+
+def cluster(k, d, data, i_centers=None):
+ borders = [(min(p[0][i] for p in data), max(p[0][i] for p in data))
+ for i in range(d) ]
+ if i_centers:
+ old_centers = i_centers
+ else:
+ old_centers = [[(h - l) * random.random() + l for (l, h) in borders]
+ for _ in range(k)]
+ clusters, centers = next_step(old_centers, data)
+ while delta(old_centers, centers) > 0:
+ old_centers = centers
+ clusters, centers = next_step(old_centers, data)
+
+ return clusters
+
+def next_step(centers, data):
+ clusters = [[] for _ in centers]
+ for point in data:
+ clusters[nearest(centers, point)].append(point)
+ centers = [centroid(c) for c in clusters]
+ return clusters, centers
+
+def nearest(centers, point):
+ d, i = min(((sum((p - c) ** 2 for (p, c) in zip(point[0], center)) ** 0.5 ,
+ index) if center else (float('inf'), len(centers)))
+ for (index, center) in enumerate(centers))
+ return i
+
+def centroid(cluster):
+ l = float(len(cluster))
+ try:
+ d = len(cluster[0][0]) #TODO empty cluster error
+ except IndexError:
+ return None
+ return [sum(c[0][i] for c in cluster) / l for i in range(d)]
+
+def delta(c1, c2):
+ return sum( (sum(abs(cc1 - cc2) for (cc1, cc2) in zip (ccc1, ccc2)) if ccc2
+ else 0.) for (ccc1, ccc2) in zip(c1, c2))