class_docstr: Clustering by k-means with SPD matrices as inputs.
  
  Find clusters that minimize the sum of squared distance to their centroids.
  This is a direct implementation of the k-means algorithm with a Riemannian
  metric.
  
  Parameters
  ----------
  n_cluster : int, default=2
      Number of clusters.
  max_iter : int, default=100
      The maximum number of iteration to reach convergence.
  metric : string, default='riemann'
      The type of metric used for centroid and distance estimation.
  random_state : integer or np.RandomState, optional
      The generator used to initialize the centers. If an integer is
      given, it fixes the seed. Defaults to the global numpy random
      number generator.
  init : 'random' or ndarray, shape (n_clusters, n_channels, n_channels),             default='random'
      Method for initialization of centers.
      'random': choose k observations (rows) at random from data for
      the initial centroids.
      If an ndarray is passed, it should be of shape
      (n_clusters, n_channels, n_channels) and gives the initial centers.
  n_init : int, default=10
      Number of time the k-means algorithm will be run with different
      centroid seeds. The final results will be the best output of
      n_init consecutive runs in terms of inertia.
  n_jobs : int, default=1
      The number of jobs to use for the computation. This works by computing
      each of the n_init runs in parallel.
      If -1 all CPUs are used. If 1 is given, no parallel computing code is
      used at all, which is useful for debugging. For n_jobs below -1,
      (n_cpus + 1 + n_jobs) are used. Thus for n_jobs = -2, all CPUs but one
      are used.
  tol : float, default=1e-4
      The stopping criterion to stop convergence, representing the minimum
      amount of change in labels between two iterations.
  
  Attributes
  ----------
  mdm_ : MDM instance.
      MDM instance containing the centroids.
  labels_ :
      Labels of each point.
  inertia_ : float
      Sum of distances of samples to their closest cluster center.
  
  Notes
  -----
  .. versionadded:: 0.2.2
  
  See Also
  --------
  Kmeans
  MDM
docstr: Fit (estimates) the clusters.
  
  Parameters
  ----------
  X : ndarray, shape (n_matrices, n_channels, n_channels)
      Set of SPD matrices.
  y : ndarray, shape (n_matrices,) | None, default=None
      Not used, here for compatibility with sklearn API.
  
  Returns
  -------
  self : Kmeans instance
      The Kmeans instance.
docstr_tok: ["Fit","(","estimates",")","the","clusters",".","Parameters","--","--","--","--","--","X",":","ndarray",",","shape","(","n_matrices",",","n_channels",",","n_channels",")","Set","of","SPD","matrices",".","y",":","ndarray",",","shape","(","n_matrices",",",")","|","None",",","default=None","Not","used",",","here","for","compatibility","with","sklearn","API",".","Returns","--","--","--","-","self",":","Kmeans","instance","The","Kmeans","instance","."]
code: def fit(self, X, y=None):
      """Fit (estimates) the clusters.
  
      Parameters
      ----------
      X : ndarray, shape (n_matrices, n_channels, n_channels)
          Set of SPD matrices.
      y : ndarray, shape (n_matrices,) | None, default=None
          Not used, here for compatibility with sklearn API.
  
      Returns
      -------
      self : Kmeans instance
          The Kmeans instance.
      """
      if isinstance(self.init, str) and self.init == "random":
          np.random.seed(self.seed)
          seeds = np.random.randint(
              np.iinfo(np.int32).max, size=self.n_init
          )
          if self.n_jobs == 1:
              res = []
              for i in range(self.n_init):
                  res.append(
                      _fit_single(
                          X,
                          y,
                          n_clusters=self.n_clusters,
                          init=self.init,
                          random_state=seeds[i],
                          metric=self.metric,
                          max_iter=self.max_iter,
                          tol=self.tol,
                      )
                  )
              labels, inertia, mdm = zip(*res)
          else:
              res = Parallel(n_jobs=self.n_jobs, verbose=0)(
                  delayed(_fit_single)(
                      X,
                      y,
                      n_clusters=self.n_clusters,
                      init=self.init,
                      random_state=seed,
                      metric=self.metric,
                      max_iter=self.max_iter,
                      tol=self.tol,
                      n_jobs=1,
                  )
                  for seed in seeds
              )
              labels, inertia, mdm = zip(*res)
  
          best = np.argmin(inertia)
          mdm = mdm[best]
          labels = labels[best]
          inertia = inertia[best]
  
      else:
          # no need to iterate if init is not random
          labels, inertia, mdm = _fit_single(
              X,
              y,
              n_clusters=self.n_clusters,
              init=self.init,
              random_state=self.seed,
              metric=self.metric,
              max_iter=self.max_iter,
              tol=self.tol,
              n_jobs=self.n_jobs,
          )
  
      self.mdm_ = mdm
      self.inertia_ = inertia
      self.labels_ = labels
  
      return self
  
imports: import numpy
  from joblib import Parallel, delayed
  from scipy.stats import norm, chi2
  import sklearn
  from sklearn.base import BaseEstimator, ClassifierMixin, TransformerMixin, ClusterMixin, clone
  from sklearn.cluster import KMeans
  from .classification import MDM, _check_metric
  from .utils.mean import mean_covariance
  from .utils.geodesic import geodesic
label_desc: Use image node_id 2 for calling the Kmeans obj's underlying member method code with example usage: obj.fit(X, y) and returns: self