Source code for markov_clustering.modularity

"""
Computation of the modularity of a clustering
"""

import numpy as np
from fractions import Fraction
from itertools import permutations

from scipy.sparse import isspmatrix, dok_matrix, find
from .mcl import sparse_allclose

[docs]def is_undirected(matrix): """ Determine if the matrix reprensents a directed graph :param matrix: The matrix to tested :returns: boolean """ if isspmatrix(matrix): return sparse_allclose(matrix, matrix.transpose()) return np.allclose(matrix, matrix.T)
[docs]def convert_to_adjacency_matrix(matrix): """ Converts transition matrix into adjacency matrix :param matrix: The matrix to be converted :returns: adjacency matrix """ for i in range(matrix.shape[0]): if isspmatrix(matrix): col = find(matrix[:,i])[2] else: col = matrix[:,i].T.tolist()[0] coeff = max( Fraction(c).limit_denominator().denominator for c in col ) matrix[:,i] *= coeff return matrix
[docs]def delta_matrix(matrix, clusters): """ Compute delta matrix where delta[i,j]=1 if i and j belong to same cluster and i!=j :param matrix: The adjacency matrix :param clusters: The clusters returned by get_clusters :returns: delta matrix """ if isspmatrix(matrix): delta = dok_matrix(matrix.shape) else: delta = np.zeros(matrix.shape) for i in clusters : for j in permutations(i, 2): delta[j] = 1 return delta
[docs]def modularity(matrix, clusters): """ Compute the modularity :param matrix: The adjacency matrix :param clusters: The clusters returned by get_clusters :returns: modularity value """ matrix = convert_to_adjacency_matrix(matrix) m = matrix.sum() if isspmatrix(matrix): matrix_2 = matrix.tocsr(copy=True) else : matrix_2 = matrix if is_undirected(matrix): expected = lambda i,j : (( matrix_2[i,:].sum() + matrix[:,i].sum() )* ( matrix[:,j].sum() + matrix_2[j,:].sum() )) else: expected = lambda i,j : ( matrix_2[i,:].sum()*matrix[:,j].sum() ) delta = delta_matrix(matrix, clusters) indices = np.array(delta.nonzero()) Q = sum( matrix[i, j] - expected(i, j)/m for i, j in indices.T )/m return Q