【问题标题】:Choose the number of clusters and vertices in python igraph在python igraph中选择簇和顶点的数量
【发布时间】:2016-10-17 01:59:28
【问题描述】:

我有一个完整的加权图,如下图所示:

目标: 我的目标是能够使用python的iGraph实现来选择集群的数量和每个集群中的顶点数

到目前为止我所做的尝试:

import igraph
import cairo
import numpy as np

# Import data (see below, I've included this file)
graph2 = igraph.Graph.Read_Ncol('10_graph.ncol')

# Assigns weights to weights1
weights1 = graph2.es["weight"]

# Converts it to undirected graph
graph2.to_undirected()

# 'graph2.to_undirected()' strips the graph of its weights
# so we restore them to the "weight" attribute after
graph2.es["weight"] = weights1

# Reduces the number of significant figures in each edge label
graph2.es["label"] = np.around(weights1, 2)

# Label all the vertices
graph2.vs["label"] = range(1, 11)

# Things I've tried: (uncomment only one at a time)
# Both return non-clustered graphs.
#community = graph2.community_spinglass(weights1)
community = graph2.community_leading_eigenvector(weights=graph2.es["weight"], clusters=3)
igraph.plot(community)

如果上面的代码运行,你会得到上面的图像作为输出。对于我包含的两种社区查找算法,您会得到相同的图像。我已经注释掉其中一个,所以如果您想使用另一个,请继续取消注释 #community = graph2.community_spinglass(weights1)

问题:

  • 看起来没有一个图表按照我希望的方式进行聚类。
    • 我通过weights=graph2.es["weight"],图中的顶点对应的权重列表。
    • 我还明确地将clusters=3 传递给community_leading_eigenvector()
    • 我仍然没有得到任何基于该图的边权重的聚类。
    • 如何通过颜色或位置绘制适当的集群,或者 iGraph 处理集群的区分?
  • 我找不到任何有关如何选择每个集群中的顶点数的官方文档。
    • 有没有办法(甚至环岛)选择每个簇中的顶点数?它不必是精确的,而是近似的。

10_graph.ncol

这是我导入以形成图表的 .ncol 文件。

10_graph.ncol =

0 1 0.859412093436
0 2 0.696674188289
0 3 0.588339776278
0 4 0.5104097013
0 5 0.462457938906
0 6 0.427462387255
0 7 0.40350595007
0 8 0.382509071902
0 9 0.358689934558
1 2 0.912797848896
1 3 0.78532402562
1 4 0.681472223562
1 5 0.615574694967
1 6 0.567507619872
1 7 0.534715438785
1 8 0.506595029246
1 9 0.474297090248
2 3 0.941218154026
2 4 0.83850483835
2 5 0.759542327211
2 6 0.70025846718
2 7 0.659110815342
2 8 0.624313042633
2 9 0.584580479234
3 4 0.957468322138
3 5 0.886571688707
3 6 0.821838040975
3 7 0.772665012468
3 8 0.730820137423
3 9 0.684372167781
4 5 0.97372551117
4 6 0.92168855187
4 7 0.870589109091
4 8 0.823583870451
4 9 0.772154420843
5 6 0.98093419661
5 7 0.941236624882
5 8 0.895874086289
5 9 0.843755656833
6 7 0.985707938753
6 8 0.9523988462
6 9 0.906031710578
7 8 0.988193527182
7 9 0.955898136286
8 9 0.988293873257

【问题讨论】:

    标签: python graph cluster-analysis graph-theory igraph


    【解决方案1】:

    这两种方法都只返回一个集群。这告诉我,您的顶点之间没有明确的分隔:它们只是一个大缠结,因此没有合理的方法可以将它们分开。

    如果我编辑边缘权重以具有清晰的分隔,例如下面的10_g2.ncol,那么聚类算法会划分顶点。

    起初,这并没有产生我预期的群体。我在顶点集 {0,1,2,3}、{4,5,6} 和 {7,8,9} 中放置了高权重,而在不同的集合之间放置了低权重。但是 spinglass 将其拆分为 {0,1,2,5,6}、{3,4} 和 {7,8,9},而leading_eigenvector 将其拆分为 {0,1,2,5,6} 和 { 3,4,7,8,9}。

    原来这是因为to_undirected() 改变了边的顺序,所以当你在这个操作之后重新分配边权重时,它会将它们与以前不同的边相关联。为避免这种情况,您应该指示to_undirected 保留边缘属性,例如由

    graph2.to_undirected(combine_edges="max")
    

    保留每个边属性的最大值(以防同一顶点之间有多个有向边),或

    graph2.to_undirected(combine_edges="first")
    

    只保留第一个看到的值。 (在这种情况下,该方法应该无关紧要,因为没有多个边。)

    一旦您实际将图表拆分为多个集群,默认的plot 方法将通过颜色区分它们。您还可以使用community.subgraph(i) 来获取第 ith 集群的子图并绘制它。

    控制集群的数量呢?如您所知,leading_eigenvalue 方法有一个clusters 参数来表示所需的集群数量,但它显然更像是一个指导而不是实际规则:给出clusters=3 会导致您的数据只有1 个集群,而我的数据只有2 个集群。

    您可以使用返回 VertexDendrogram 而不是 Clustering 的方法(例如 `community_edge_betweenness)更精确地控制集群的数量。

    com3 = graph2.community_edge_betweenness(clusters=3, directed=False, weights="weight")
    

    要获得包含 n 集群的集群,请调用 com3.as_clustering(n),它为我的所有测试提供了准确的 n 集群。

    它们不一定是好的集群:

    In [21]: print(com3.as_clustering(3))
    Clustering with 10 elements and 3 clusters
    [0] 0
    [1] 1, 2, 3, 4, 5, 7, 8, 9
    [2] 6
    
    In [22]: print(com3.as_clustering(4))
    Clustering with 10 elements and 4 clusters
    [0] 0
    [1] 1, 2, 3, 4, 5, 8, 9
    [2] 6
    [3] 7
    
    In [23]: print(com3.as_clustering(5))
    Clustering with 10 elements and 5 clusters
    [0] 0
    [1] 1, 3, 5
    [2] 2, 4, 8, 9
    [3] 6
    [4] 7
    
    In [24]: print(com3.as_clustering(6))
    Clustering with 10 elements and 6 clusters
    [0] 0
    [1] 1, 3, 5
    [2] 2, 8, 9
    [3] 4
    [4] 6
    [5] 7
    

    返回 VertexDendrograms 的其他方法是 community_walktrapcommunity_fastgreedy。对于这个特定的例子,IMO,它们似乎都表现得更好。

    In [25]: com5 = graph2.community_walktrap(weights='weight')
    
    In [26]: com6 = graph2.community_fastgreedy(weights='weight')
    
    In [27]: print(com5.as_clustering(3))
    Clustering with 10 elements and 3 clusters
    [0] 0, 1, 2, 5, 6
    [1] 3, 4
    [2] 7, 8, 9
    
    In [32]: print(com6.as_clustering(3))
    Clustering with 10 elements and 3 clusters
    [0] 0, 1, 2, 5, 6
    [1] 3, 4
    [2] 7, 8, 9
    

    这是我使用的更多样化的权重。

    10_g2.ncol:

    0 1 0.91
    0 2 0.92
    0 3 0.93
    0 4 0.04
    0 5 0.05
    0 6 0.06
    0 7 0.07
    0 8 0.08
    0 9 0.09
    1 2 0.94
    1 3 0.95
    1 4 0.14
    1 5 0.15
    1 6 0.16
    1 7 0.17
    1 8 0.18
    1 9 0.19
    2 3 0.96
    2 4 0.01
    2 5 0.02
    2 6 0.03
    2 7 0.04
    2 8 0.05
    2 9 0.06
    3 4 0.01
    3 5 0.01
    3 6 0.01
    3 7 0.01
    3 8 0.01
    3 9 0.01
    4 5 0.97
    4 6 0.92
    4 7 0.05
    4 8 0.04
    4 9 0.08
    5 6 0.98
    5 7 0.12
    5 8 0.08
    5 9 0.08
    6 7 0.07
    6 8 0.06
    6 9 0.06
    7 8 0.98
    7 9 0.95
    8 9 0.98
    

    【讨论】:

    • 如果我将每个权重乘以某个系数,比如 100,您认为它会帮助算法挑选出聚类吗?
    • @jackskis:我确实试过了,但没有帮助。某种指数缩放可能会起作用。 dendrogram 方法将您的图拆分为指定数量的集群,其中一些与原始权重合理地发挥作用(其他方法一次只分离一个顶点。)
    • 优秀。我会尝试并报告。还有一件事:鉴于这是一个完整的图,使用树状图的聚类算法是否会产生聚类以使聚类内的权重最大?如果不是,集群是如何产生的?查看文档后,我找不到该算法如何处理只有边权重的完整图。
    • @jackskis:我不知道算法是如何工作的。它们的工作不在 Python 代码中,而是在 igraph C 库中。我发现边缘权重被to_undirected 弄乱了(请参阅编辑后的答案),在我修复它之后,聚类反映了我期望的权重。如果需要,您还可以在聚类之前删除权重较低的边(例如,graph2.delete_edges(weight_lt=0.5) 删除所有权重小于 0.5 的边)。但是有些算法(包括community_spinglass)不喜欢这样做时图表断开连接。
    • 您的解决方案中有一个非常重要的错误:您的graph2.to_undirected(combine_edges="max") 方法实际上仍然以看似任意的方式扰乱了图形。有没有其他选择?照原样,您的输出图不是在原始图中挑选出模式,而是在to_undirected 函数任意选择其他一些图。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 2022-11-14
    • 2021-05-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多