(self, x, manual_init=None)
return lowest_potential_cluster_ixs, lowest_potential_cluster_centers
Perform clustering.

        Parameters
        ----------
        x : torch.Tensor
            Feature matrix of shape `(n_samples, n_features)`.

        manual_init : None or torch.Tensor
            If not None then expecting a tensor of shape `(n_clusters, n_features)`. Note that for this feature
            to be used one needs to set `init='manual'` in the constructor.

        Returns
        -------
        cluster_ixs : torch.Tensor
            1D array of lenght `n_samples` representing to what cluster each sample belongs.

        cluster_centers : torch.tensor
            Tensor of shape `(n_clusters, n_features)` representing the cluster centers.
Perform clustering.
Perform clustering .
def forward(self, x, manual_init=None):
        """Perform clustering.

        Parameters
        ----------
        x : torch.Tensor
            Feature matrix of shape `(n_samples, n_features)`.

        manual_init : None or torch.Tensor
            If not None then expecting a tensor of shape `(n_clusters, n_features)`. Note that for this feature
            to be used one needs to set `init='manual'` in the constructor.

        Returns
        -------
        cluster_ixs : torch.Tensor
            1D array of lenght `n_samples` representing to what cluster each sample belongs.

        cluster_centers : torch.tensor
            Tensor of shape `(n_clusters, n_features)` representing the cluster centers.

        """
        n_samples, n_features = x.shape
        if n_samples < self.n_clusters:
            raise ValueError('The number of samples is lower than the number of clusters.')

        if self.random_state is not None:
            torch.manual_seed(self.random_state)

        lowest_potential = float('inf')
        lowest_potential_cluster_ixs = None
        lowest_potential_cluster_centers = None

        for run in range(self.n_init):
            cluster_centers = self.initialize(x, manual_init=manual_init)
            previous_potential = float('inf')

            for it in range(self.max_iter):
                distances = self.compute_distances(x, cluster_centers)  # (n_samples, n_clusters)

                # E step
                cluster_ixs = torch.argmin(distances, dim=1)  # (n_samples,)

                # M step
                cluster_centers = torch.stack([x[cluster_ixs == i].mean(dim=0) for i in range(self.n_clusters)], dim=0)

                # stats
                current_potential = distances.gather(1, cluster_ixs.view(-1, 1)).sum()

                if abs(current_potential - previous_potential) < self.tol or it == self.max_iter - 1:
                    if self.verbose:
                        print('Run: {}, n_iters: {}, stop_early: {}, potential: {:.3f}'.format(run,
                                                                                               it,
                                                                                               it != self.max_iter - 1,
                                                                                               current_potential))
                    break

                previous_potential = current_potential

            if current_potential < lowest_potential:
                lowest_potential = current_potential
                lowest_potential_cluster_ixs = cluster_ixs.clone()
                lowest_potential_cluster_centers = cluster_centers.clone()

        if self.verbose:
            print('Lowest potential: {}'.format(lowest_potential))

        return lowest_potential_cluster_ixs, lowest_potential_cluster_centers
def forward ( self , x , manual_init = None ) : n_samples , n_features = x . shape if n_samples < self . n_clusters : raise ValueError ( 'The number of samples is lower than the number of clusters.' ) if self . random_state is not None : torch . manual_seed ( self . random_state ) lowest_potential = float ( 'inf' ) lowest_potential_cluster_ixs = None lowest_potential_cluster_centers = None for run in range ( self . n_init ) : cluster_centers = self . initialize ( x , manual_init = manual_init ) previous_potential = float ( 'inf' ) for it in range ( self . max_iter ) : distances = self . compute_distances ( x , cluster_centers ) # (n_samples, n_clusters) # E step cluster_ixs = torch . argmin ( distances , dim = 1 ) # (n_samples,) # M step cluster_centers = torch . stack ( [ x [ cluster_ixs == i ] . mean ( dim = 0 ) for i in range ( self . n_clusters ) ] , dim = 0 ) # stats current_potential = distances . gather ( 1 , cluster_ixs . view ( - 1 , 1 ) ) . sum ( ) if abs ( current_potential - previous_potential ) < self . tol or it == self . max_iter - 1 : if self . verbose : print ( 'Run: {}, n_iters: {}, stop_early: {}, potential: {:.3f}' . format ( run , it , it != self . max_iter - 1 , current_potential ) ) break previous_potential = current_potential if current_potential < lowest_potential : lowest_potential = current_potential lowest_potential_cluster_ixs = cluster_ixs . clone ( ) lowest_potential_cluster_centers = cluster_centers . clone ( ) if self . verbose : print ( 'Lowest potential: {}' . format ( lowest_potential ) ) return lowest_potential_cluster_ixs , lowest_potential_cluster_centers