Returns a list of k clusters, where each cluster is a list of vectors (Lloyd's algorithm). Vectors are assigned to k random centers using a distance metric (EUCLIDEAN, COSINE, ...). Since the initial centers are chosen randomly (by default, seed=RANDOM), there is no guarante
(vectors, k=None, iterations=10, distance=COSINE, seed=RANDOM, **kwargs)
| 1460 | RANDOM, KMPP = "random", "kmeans++" |
| 1461 | |
| 1462 | def k_means(vectors, k=None, iterations=10, distance=COSINE, seed=RANDOM, **kwargs): |
| 1463 | """ Returns a list of k clusters, where each cluster is a list of vectors (Lloyd's algorithm). |
| 1464 | Vectors are assigned to k random centers using a distance metric (EUCLIDEAN, COSINE, ...). |
| 1465 | Since the initial centers are chosen randomly (by default, seed=RANDOM), |
| 1466 | there is no guarantee of convergence or of finding an optimal solution. |
| 1467 | A more efficient way is to use seed=KMPP (k-means++ initialization algorithm). |
| 1468 | """ |
| 1469 | features = kwargs.get("features") or _features(vectors) |
| 1470 | if k is None: |
| 1471 | k = sqrt(len(vectors) / 2) |
| 1472 | if k < 2: |
| 1473 | return [[v for v in vectors]] |
| 1474 | if seed == KMPP: |
| 1475 | clusters = kmpp(vectors, k, distance) |
| 1476 | else: |
| 1477 | clusters = [[] for i in xrange(int(k))] |
| 1478 | for i, v in enumerate(sorted(vectors, key=lambda x: random())): |
| 1479 | # Randomly partition the vectors across k clusters. |
| 1480 | clusters[i % int(k)].append(v) |
| 1481 | # Cache the distance calculations between vectors (up to 4x faster). |
| 1482 | map = DistanceMap(method=distance); distance = map.distance |
| 1483 | converged = False |
| 1484 | while not converged and iterations > 0 and k > 0: |
| 1485 | # Calculate the center of each cluster. |
| 1486 | centroids = [centroid(cluster, features) for cluster in clusters] |
| 1487 | # Triangle inequality: one side is shorter than the sum of the two other sides. |
| 1488 | # We can exploit this to avoid costly distance() calls (up to 3x faster). |
| 1489 | p = 0.5 * kwargs.get("p", 0.8) # "Relaxed" triangle inequality (cosine distance is a semimetric) 0.25-0.5. |
| 1490 | D = {} |
| 1491 | for i in range(len(centroids)): |
| 1492 | for j in range(i, len(centroids)): # center1–center2 < center1–vector + vector–center2 ? |
| 1493 | D[(i,j)] = D[(j,i)] = p * distance(centroids[i], centroids[j]) |
| 1494 | # For every vector in every cluster, |
| 1495 | # check if it is nearer to the center of another cluster. |
| 1496 | # If so, assign it. When visualized, this produces a Voronoi diagram. |
| 1497 | converged = True |
| 1498 | for i in xrange(len(clusters)): |
| 1499 | for v in clusters[i]: |
| 1500 | nearest, d1 = i, distance(v, centroids[i]) |
| 1501 | for j in xrange(len(clusters)): |
| 1502 | if D[(i,j)] < d1: # Triangle inequality (Elkan, 2003). |
| 1503 | d2 = distance(v, centroids[j]) |
| 1504 | if d2 < d1: |
| 1505 | nearest = j |
| 1506 | if nearest != i: # Other cluster is nearer. |
| 1507 | clusters[nearest].append(clusters[i].pop(clusters[i].index(v))) |
| 1508 | converged = False |
| 1509 | iterations -= 1; #print iterations |
| 1510 | return clusters |
| 1511 | |
| 1512 | kmeans = k_means |
| 1513 |
no test coverage detected
searching dependent graphs…