社区发现评价指标Q和NMI讲解、代码实现

社区发现评价指标Q和NMI讲解、代码实现

文章目录

    • 社区发现评价指标Q和NMI讲解、代码实现
      • 模块度Q
      • 标准化互信息NMI
      • 代码实现
      • 参考文献

模块度Q

2004年Newman等人提出了模块度Q,之后广泛应用于衡量社区的划分质量,下面公式适用于无向无权的同质网络。若社区内节点的边数越多,Q值越大,相反,Q值越小。
Q = 1 2 m ∑ i , j [ A i j − d i d j 2 m ] δ ( C i , C j ) Q=\frac{1}{2m}\sum_{i,j}\Big[A_{ij}-\frac{d_id_j}{2m}\Big]\delta(C_i,C_j) Q=2m1i,j[Aij2mdidj]δ(Ci,Cj)

m 为 网 络 中 的 边 数 ; A i j 为 邻 接 矩 阵 A 中 的 元 素 , m为网络中的边数;A_{ij}为邻接矩阵A中的元素, mAijA

若 节 点 i , j 相 连 , 则 A i j = 1 , 否 则 A i j = 0 ; 若节点i,j相连,则A_{ij}=1,否则A_{ij}=0; i,jAij=1,Aij=0;

C i 为 节 点 i 所 属 的 社 区 , C j 为 节 点 j 所 属 的 社 区 ; C_i为节点i所属的社区,C_j为节点j所属的社区; CiiCjj

当 i , j 处 于 同 一 社 区 时 , δ ( C i , C j ) = 1 , 否 则 为 0 ; 当i,j处于同一社区时,\delta(C_i,C_j)=1,否则为0; i,jδ(Ci,Cj)=10

d i 代 表 节 点 i 的 度 ; d_i代表节点i的度; dii

d i d j 2 m 表 示 在 随 机 网 络 中 节 点 i 和 节 点 j 之 间 存 在 边 的 可 能 性 。 \frac{d_id_j}{2m}表示在随机网络中节点i和节点j之间存在边的可能性。 2mdidjij

模块度Q也可表示为
Q = ∑ c = 1 k [ l c m − ( d c 2 m ) 2 ] Q=\sum_{c=1}^{k}\Big[\frac{l_c}{m}-(\frac{d_c}{2m})^2\Big] Q=c=1k[mlc(2mdc)2]

上 式 中 , m 为 网 络 中 的 总 边 数 ; k 为 社 区 个 数 , 上式中,m为网络中的总边数;k为社区个数, mk

l c 为 社 区 c 内 部 的 连 接 边 数 , d c 为 社 区 c 内 所 有 节 点 的 度 之 和 。 l_c为社区c内部的连接边数,d_c为社区c内所有节点的度之和。 lccdcc

其中,Q的取值范围为[-0.5, 1]

注:模块度Q适用于已知真实社区或未知真实社区划分结果的评估


标准化互信息NMI

NMInormalized mutual information标准化互信息,也称为归一化互信息,是目前广泛使用的一种社区划分评价指标,用于度量算法所得到的社区和真实社区划分之间的相似程度,也用于评估聚类结果的相似程度。
N M I ( R , F ) = − 2 ∑ i = 1 C R ∑ j = 1 C F N i j l o g ( N i j S N i ∗ N ∗ j ) ∑ C R N i ∗ l o g ( N i ∗ / S ) + ∑ C F N ∗ j l o g ( N ∗ j / S ) NMI(R,F)=\frac{-2\sum_{i=1}^{C_R}\sum_{j=1}^{C_F}N_{ij}log(\frac{N_{ij}S}{N_{i*}N_{*j}})}{\sum^{C_R}N_{i*}log(N_{i*}/S)+\sum^{C_F}N_{*j}log(N_{*j}/S)} NMI(R,F)=CRNilog(Ni/S)+CFNjlog(Nj/S)2i=1CRj=1CFNijlog(NiNjNijS)

其 中 , 矩 阵 N 中 的 行 表 示 真 实 的 社 区 , 列 表 示 算 法 得 到 的 社 区 ; 其中,矩阵N中的行表示真实的社区,列表示算法得到的社区; N

矩 阵 中 第 i 行 的 元 素 表 示 为 N i ∗ , 第 j 列 的 元 素 表 示 为 N ∗ j ; 矩阵中第i行的元素表示为N_{i*},第j列的元素表示为N_{*j}; iNi,jNj;

N i j 表 示 真 实 社 区 与 算 法 所 得 到 的 社 区 相 同 的 节 点 个 数 ; S 为 节 点 个 数 ; N_{ij}表示真实社区与算法所得到的社区相同的节点个数;S为节点个数; NijS

C R 表 示 真 实 社 区 个 数 , C F 表 示 算 法 所 得 到 的 的 社 区 个 数 。 C_R表示真实社区个数,C_F表示算法所得到的的社区个数。 CRCF

当 算 法 所 得 到 的 的 社 区 划 分 与 网 络 中 的 真 实 社 区 划 分 完 全 一 致 时 , N M I = 1 ; 当算法所得到的的社区划分与网络中的真实社区划分完全一致时,NMI=1; NMI=1;

当 算 法 所 得 到 的 划 分 社 区 与 网 络 中 的 真 实 社 区 划 分 完 全 独 立 时 , N M I = 0 。 当算法所得到的划分社区与网络中的真实社区划分完全独立时,NMI=0。 NMI=0

显然,NMI的取值范围为[0,1]

注:NMI适用于已知真实社区结构的数据集上的社区划分评估


代码实现

import networkx as nx
import math

class Evaluate:
    """
    社区划分结果评估
    """

    def __init__(self, G, cur_community, real_community):
        """
        评价指标初始化
        :param G: 图
        :param cur_community: 当前社区划分结果 {id: nodes}
        :param real_community: 真实社区结果{id : nodes}
        :return: null
        """
        self.G = G
        self.cur_community = cur_community
        self.real_community = real_community


    def Q(self):
        """
        计算划分社区的模块度Q(modularity)
        未知和已知社区的评估指标
        :return: Q_value
        """
        nodes_number = self.G.number_of_nodes()
        edges_number = self.G.number_of_edges()
        Q_value = 0
        for key in self.cur_community.keys():
            #社区c
            c = self.cur_community[key]
            #社区内结点度数之和
            degrees = 0
            #社区内部边的总数
            inter_edges = 0
            for u in c:
                u_neighbors = set(nx.all_neighbors(self.G, u))
                degrees += len(u_neighbors)
                for nbr in u_neighbors:
                    if nbr in c:
                        inter_edges += 1
            #因为是无向图,所以边数要除以2
            inter_edges /= 2
            #cq = inter_edges / edges_number - math.pow(degrees / (2 * edges_number), 2)
            cq = inter_edges / edges_number - (degrees / (2 * edges_number)) ** 2
            Q_value += cq
        return Q_value


    def NMI(self):
        """
        标准化互信息值( Normalized mutual information)
        已知真实社区划分结果的评价指标
        行代表真实社区划分(real_community)
        列代表当前社区划分结果(cur_community)
        :return:NMI_value
        """
        nodes_number = self.G.number_of_nodes()
        r_id = [key for key in self.real_community]
        c_id = [key for key in self.cur_community]
        #分子
        sum_rc = 0
        #分母两项之和
        sum_r = sum_c = 0

        for i in range(0, len(r_id)):
            temp = 0
            nodes_i = set(self.real_community[r_id[i]])
            for j in range(0, len(c_id)):
                nodes_j = set(self.cur_community[c_id[j]])
                common = nodes_i & nodes_j
                a = len(common) * nodes_number / (len(nodes_i) * len(nodes_j))
                if a > 0:
                    temp += len(common) * math.log10(a)
            sum_rc += temp

        for i in range(0, len(r_id)):
            nodes_i = set(self.real_community[r_id[i]])
            sum_r += len(nodes_i) * math.log10(len(nodes_i) / nodes_number)
        for j in range(0, len(c_id)):
            nodes_j = set(self.cur_community[c_id[j]])
            sum_c += len(nodes_j) * math.log10(len(nodes_j) / nodes_number)

        sum_rc = sum_rc * (-2)
        NMI_value = sum_rc / (sum_r + sum_c)
        return NMI_value

参考文献

[1]Newman M E J,Girvan M. Finding and evaluating community structure in networks.[J]. Physical review. E, Statistical, nonlinear, and soft matter physics,2004,69(2 Pt 2).

[2] 赵卫绩,张凤斌,刘井莲.复杂网络社区发现研究进展[J].计算机科学,2020,47(02):10-20.


本人理解尚浅,若有错误之处欢迎大家指出!

你可能感兴趣的:(社区发现,社区发现)