The K-Means itself

def fit(self, X):
        """The K-Means itself
        """

        self._X = super().cluster(X)
        candidates = []

        for _ in range(self.n_runs):
            self._init_random_centroids()
            while True:
                prev_clusters = self.clusters
                self._assign_clusters()
                self._move_centroids()

                if np.all(prev_clusters == self.clusters):
                    break

            self._calc_distortion()
            candidates.append((self.distortion, self.centroids, self.clusters))
        
        candidates.sort(key=lambda x: x[0])
        self.distortion = candidates[0][0]
        self.centroids = candidates[0][1]
        self.clusters = candidates[0][2]

        return self