[社区发现]k-clique渗透(重叠社区发现算法)

1,984 阅读4分钟

总结

k-clique渗透算法,是一种用于社区发现的算法, 属于可重叠社区发现算法.

该算法通过寻找完全子图(任意2个节点之间都存在边关系),节点数为k的完全子图,称为k-clique。

然后通过相邻的k-clique构成最大的集合来形成社区。 

在k-clique渗透算法中,如果2个k-clique完全子图,有k-1个共同的节点,
那么就称这2个k-clique是相邻的。 
彼此相邻的k-clique完全子图可以构成更大的集合,就可以称为一个社区。 

该算法的具体步骤包括:

1.  初始化:选择一个初始的k-clique(k个节点的完全子图)
2.  扩展:在已找到的k-clique周围尽可能找到其他更多的k-clique。
3.  优化:对所有找到的k-clique进行优化,确保它们之间有足够的连接。
4.  重复步骤2和3,直到无法找到更多的k-clique或达到预设的停止条件。

最后,选择割集规模最小的状态作为最优解。该算法可以帮助揭示图中隐藏的社区结构和模式,在社交网络分析、生物信息学、推荐系统等领域有广泛应用。

什么是渗透算法

 该算法是networkx包自带的算法
 该算法发现的社区是可重叠社区,即一个节点可以同时属于不同的社区,
 5个人6个群,这就是重叠社区。

 在一张网络图中,如果其中有一个完全子图,节点数是k,其中任意两个节点之间均存在边,
 这就是一张完全子图,称为k-clique。
 
 进而,如果两个k-clique之间存在k-1个共同的节点,那么就称这两个k-clique是“相邻”的。
 彼此相邻的这样一串k-clique构成最大集合,就可以称为一个社区,
 而且这样的社区是可以重叠的,就是说有些节点可以同时属于多个社区。
 下面第一组图表示两个3-clique形成了一个社区,第二组图是一个重叠社区的示意图。

实战

1/生成模拟社交数据

import random
import csv

# 生成虚拟社交网络数据
def generate_social_network_data(num_nodes=50, num_edges=150, communities=3):
    edges = set()
    
    # 确保图是连通的
    for i in range(1, num_nodes):
        edges.add((i-1, i))
    
    # 生成社区内部连接
    community_size = num_nodes // communities
    for c in range(communities):
        start = c * community_size
        end = (c + 1) * community_size if c < communities - 1 else num_nodes
        
        # 增加社区内部的连接密度
        for i in range(start, end):
            for j in range(i+1, end):
                if random.random() < 0.4:  # 社区内部连接概率较高
                    edges.add((i, j))
    
    # 生成随机连接,直到达到目标边数
    while len(edges) < num_edges:
        u = random.randint(0, num_nodes-1)
        v = random.randint(0, num_nodes-1)
        if u != v:
            edges.add((min(u, v), max(u, v)))
    
    return list(edges)

# 保存为CSV文件
def save_to_csv(edges, filename='social_network.csv'):
    with open(filename, 'w', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(['node1', 'node2'])
        for edge in edges:
            writer.writerow(edge)

if __name__ == "__main__":
    edges = generate_social_network_data()
    save_to_csv(edges)
    print(f"生成了{len(edges)}条边的社交网络数据,保存到social_network.csv")

生成的模拟输入格式如下:

7f89cf0835bb49b964ac5e8361480041.png

2/k-clique渗透算法挖掘社区

import networkx as nx
import csv

# 从CSV文件加载社交网络数据
def load_social_network(filename='social_network.csv'):
    G = nx.Graph()
    with open(filename, 'r') as f:
        reader = csv.DictReader(f)
        for row in reader:
            node1 = int(row['node1'])
            node2 = int(row['node2'])
            G.add_edge(node1, node2)
    return G

# 使用k-clique算法进行社区检测
def detect_communities(G, k=3):
    # 使用NetworkX的k_clique_communities函数
    communities = list(nx.community.k_clique_communities(G, k))
    return communities

# 保存社区检测结果到CSV文件
def save_communities(communities, filename='community_results.csv'):
    with open(filename, 'w', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(['node', 'community'])
        for i, community in enumerate(communities):
            for node in community:
                writer.writerow([node, i])

# 主函数
def main():
    # 加载数据
    G = load_social_network()
    print(f"加载了社交网络数据,包含{G.number_of_nodes()}个节点和{G.number_of_edges()}条边")
    
    # 检测社区
    k = 3  # 设置k值
    communities = detect_communities(G, k)
    print(f"检测到{len(communities)}个社区")
    
    # 打印社区信息
    for i, community in enumerate(communities):
        print(f"社区{i}包含{len(community)}个节点: {sorted(community)}")
    
    # 保存结果
    save_communities(communities)
    print("社区检测结果已保存到community_results.csv")

if __name__ == "__main__":
    main()

挖掘结果如下所示:

加载了社交网络数据,包含50个节点和177条边

检测到3个社区

社区0包含16个节点: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

社区1包含16个节点: [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]

社区2包含18个节点: [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]

社区检测结果已保存到community_results.csv