def _spherical_kmeans_single_lloyd(
    X,
    n_clusters,
    sample_weight=None,
    max_iter=300,
    init="k-means++",
    verbose=False,
    x_squared_norms=None,
    random_state=None,
    tol=1e-4,
    precompute_distances=True,
):
    """
    Modified from sklearn.cluster.k_means_.k_means_single_lloyd.
    """
    random_state = check_random_state(random_state)

    sample_weight = _check_sample_weight(X, sample_weight)

    best_labels, best_inertia, best_centers = None, None, None

    # init
    centers = _init_centroids(
        X, n_clusters, init, random_state=random_state, x_squared_norms=x_squared_norms
    )
    if verbose:
        print("Initialization complete")

    # Allocate memory to store the distances for each sample to its
    # closer center for reallocation in case of ties
    distances = np.zeros(shape=(X.shape[0],), dtype=X.dtype)

    # iterations
    for i in range(max_iter):
        centers_old = centers.copy()

        # labels assignment
        # TODO: _labels_inertia should be done with cosine distance
        #       since ||a - b|| = 2(1 - cos(a,b)) when a,b are unit normalized
        #       this doesn't really matter.
        labels, inertia = _labels_inertia(
            X,
            sample_weight,
            x_squared_norms,
            centers,
            precompute_distances=precompute_distances,
            distances=distances,
        )

        # computation of the means
        if sp.issparse(X):
            centers = _k_means._centers_sparse(
                X, sample_weight, labels, n_clusters, distances
            )
        else:
            centers = _k_means._centers_dense(
                X, sample_weight, labels, n_clusters, distances
            )

        # l2-normalize centers (this is the main contibution here)
        centers = normalize(centers)

        if verbose:
            print("Iteration %2d, inertia %.3f" % (i, inertia))

        if best_inertia is None or inertia < best_inertia:
            best_labels = labels.copy()
            best_centers = centers.copy()
            best_inertia = inertia

        center_shift_total = squared_norm(centers_old - centers)
        if center_shift_total <= tol:
            if verbose:
                print(
                    "Converged at iteration %d: "
                    "center shift %e within tolerance %e" % (i, center_shift_total, tol)
                )
            break

    if center_shift_total > 0:
        # rerun E-step in case of non-convergence so that predicted labels
        # match cluster centers
        best_labels, best_inertia = _labels_inertia(
            X,
            sample_weight,
            x_squared_norms,
            best_centers,
            precompute_distances=precompute_distances,
            distances=distances,
        )

    return best_labels, best_inertia, best_centers, i + 1
def _spherical_kmeans_single_lloyd ( X , n_clusters , sample_weight = None , max_iter = 300 , init = "k-means++" , verbose = False , x_squared_norms = None , random_state = None , tol = 1e-4 , precompute_distances = True , ) : random_state = check_random_state ( random_state ) sample_weight = _check_sample_weight ( X , sample_weight ) best_labels , best_inertia , best_centers = None , None , None centers = _init_centroids ( X , n_clusters , init , random_state = random_state , x_squared_norms = x_squared_norms ) if verbose : print ( "Initialization complete" ) distances = np . zeros ( shape = ( X . shape [ 0 ] , ) , dtype = X . dtype ) for i in range ( max_iter ) : centers_old = centers . copy ( ) labels , inertia = _labels_inertia ( X , sample_weight , x_squared_norms , centers , precompute_distances = precompute_distances , distances = distances , ) if sp . issparse ( X ) : centers = _k_means . _centers_sparse ( X , sample_weight , labels , n_clusters , distances ) else : centers = _k_means . _centers_dense ( X , sample_weight , labels , n_clusters , distances ) centers = normalize ( centers ) if verbose : print ( "Iteration %2d, inertia %.3f" % ( i , inertia ) ) if best_inertia is None or inertia < best_inertia : best_labels = labels . copy ( ) best_centers = centers . copy ( ) best_inertia = inertia center_shift_total = squared_norm ( centers_old - centers ) if center_shift_total <= tol : if verbose : print ( "Converged at iteration %d: " "center shift %e within tolerance %e" % ( i , center_shift_total , tol ) ) break if center_shift_total > 0 : best_labels , best_inertia = _labels_inertia ( X , sample_weight , x_squared_norms , best_centers , precompute_distances = precompute_distances , distances = distances , ) return best_labels , best_inertia , best_centers , i + 1
Modified from sklearn.cluster.k_means_.k_means_single_lloyd.