Repository: scikit-learn/scikit-learn
File: sklearn/semi_supervised/_label_propagation.py (Python)

Code before:
        max_iter=1000,
        tol=1e-3,
        n_jobs=None,
    ):
        super().__init__(
            kernel=kernel,
            gamma=gamma,
            n_neighbors=n_neighbors,
            max_iter=max_iter,
            tol=tol,
            n_jobs=n_jobs,
            alpha=None,
        )

    def _build_graph(self):
        """Matrix representing a fully connected graph between each sample."""
        if self.kernel == "knn":
            self.nn_fit = None
        affinity_matrix = self._get_kernel(self.X_)
        normalizer = affinity_matrix.sum(axis=1)
        if sparse.issparse(affinity_matrix):
            # handle spmatrix (make 1D)
            if sparse.isspmatrix(affinity_matrix):
                normalizer = np.ravel(normalizer)
            # common case: knn method gives row sum k for all rows
            if np.all(normalizer == normalizer[0]):
                affinity_matrix.data /= normalizer[0]
            else:  # row sums not the same
                if affinity_matrix.format == "csr":
                    repeats = np.diff(affinity_matrix.indptr)
                    rows = np.repeat(np.arange(affinity_matrix.shape[0]), repeats)
                else:  # CSC format
                    rows = affinity_matrix.indices
                affinity_matrix.data /= normalizer[rows]
        else:  # Dense affinity_matrix
            affinity_matrix /= normalizer[:, np.newaxis]
        return affinity_matrix

    def fit(self, X, y):
        """Fit a semi-supervised label propagation model to X.

        Parameters
        ----------
        X : {array-like, sparse matrix} of shape (n_samples, n_features)
            Training data, where `n_samples` is the number of samples
            and `n_features` is the number of features.

        y : array-like of shape (n_samples,)
            Target class values with unlabeled points marked as -1.
            All unlabeled samples will be transductively assigned labels
            internally, which are stored in `transduction_`.

Review comment (suggestion):
```suggestion
            # but sometimes row sums are not the same 
            # and need to account for that
            if not np.all(normalizer == normalizer[0]):
```

Code after:
        max_iter=1000,
        tol=1e-3,
        n_jobs=None,
    ):
        super().__init__(
            kernel=kernel,
            gamma=gamma,
            n_neighbors=n_neighbors,
            max_iter=max_iter,
            tol=tol,
            n_jobs=n_jobs,
            alpha=None,
        )

    def _build_graph(self):
        """Matrix representing a fully connected graph between each sample."""
        if self.kernel == "knn":
            self.nn_fit = None
        affinity_matrix = self._get_kernel(self.X_)
        normalizer = affinity_matrix.sum(axis=1)
        # handle spmatrix (make normalizer 1D)
        if sparse.isspmatrix(affinity_matrix):
            normalizer = np.ravel(normalizer)
        # TODO: when SciPy 1.12+ is min dependence, replace up to ---- with:
        # affinity_matrix /= normalizer[:, np.newaxis]
        if sparse.issparse(affinity_matrix):
            inv_normalizer = sparse.diags(1.0 / normalizer)
            affinity_matrix = inv_normalizer @ affinity_matrix
        else:  # Dense affinity_matrix
            affinity_matrix /= normalizer[:, np.newaxis]
        # ----
        return affinity_matrix

    def fit(self, X, y):
        """Fit a semi-supervised label propagation model to X.

        Parameters
        ----------
        X : {array-like, sparse matrix} of shape (n_samples, n_features)
            Training data, where `n_samples` is the number of samples
            and `n_features` is the number of features.

        y : array-like of shape (n_samples,)
            Target class values with unlabeled points marked as -1.
            All unlabeled samples will be transductively assigned labels
            internally, which are stored in `transduction_`.

        Returns
        -------
        self : object
            Returns the instance itself.