如何在2D numpy数组中找到簇大小?

时间:2014-09-04 11:47:01

标签: python arrays numpy block cluster-analysis

我的问题如下,

我有一个2D numpy数组,填充0和1,具有吸收边界条件(所有外部元素都是0),例如:

[[0 0 0 0 0 0 0 0 0 0]
 [0 0 1 0 0 0 0 0 0 0]
 [0 0 1 0 1 0 0 0 1 0]
 [0 0 0 0 0 0 1 0 1 0]
 [0 0 0 0 0 0 1 0 0 0]
 [0 0 0 0 1 0 1 0 0 0]
 [0 0 0 0 0 1 1 0 0 0]
 [0 0 0 1 0 1 0 0 0 0]
 [0 0 0 0 1 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]]

我想创建一个函数,将此数组及其线性尺寸L作为输入参数(在本例中为L = 10),并返回此数组的簇大小列表。

通过"集群"我指的是数组中元素1的孤立组

如果数组元素[i] [j]的所有邻居都是零,则它是孤立的,并且它的邻居是元素:

[i+1][j]
[i-1][j]
[i][j+1]
[i][j-1]

所以在前面的数组中,我们有7个大小的簇(2,1,2,6,1,1,1)

我尝试通过创建两个函数来完成此任务,第一个是递归函数:

def clust_size(array,i,j):

    count = 0

    if array[i][j] == 1:

        array[i][j] = 0

        if array[i-1][j] == 1:

            count += 1
            array[i-1][j] = 0
            clust_size(array,i-1,j)

        elif array[i][j-1] == 1:

            count += 1
            array[i-1][j] = 0
            clust_size(array,i,j-1)

        elif array[i+1][j] == 1:

            count += 1
            array[i-1][j] =  0
            clust_size(array,i+1,j)

        elif array[i][j+1] == 1:

            count += 1
            array[i-1][j] = 0
            clust_size(array,i,j+1)

    return count+1         

它应该返回一个集群的大小。每当函数找到一个等于1的数组元素时,它就会增加计数器的值" count"并将元素的值更改为0,这样每个' 1'它只计算了一次。 如果该元素的一个邻居等于1,则该函数在该元素上调用自身。

第二个功能是:

def clust_list(array,L):

    sizes_list = []

    for i in range(1,L-1):
        for i in range(1,L-1):

           count = clust_size(array,i,j)

           sizes_list.append(count)

    return sizes_list

它应该返回包含簇大小的列表。 for循环从1迭代到L-1,因为所有外部元素都是0。

这不起作用,我无法查看错误的位置......

我想知道是否有更容易的方法。

4 个答案:

答案 0 :(得分:10)

这似乎是一个渗透问题。 如果你安装了scipy,以下链接有你的答案。

http://dragly.org/2013/03/25/working-with-percolation-clusters-in-python/

from pylab import *
from scipy.ndimage import measurements

z2 = array([[0,0,0,0,0,0,0,0,0,0],
    [0,0,1,0,0,0,0,0,0,0],
    [0,0,1,0,1,0,0,0,1,0],
    [0,0,0,0,0,0,1,0,1,0],
    [0,0,0,0,0,0,1,0,0,0],
    [0,0,0,0,1,0,1,0,0,0],
    [0,0,0,0,0,1,1,0,0,0],
    [0,0,0,1,0,1,0,0,0,0],
    [0,0,0,0,1,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0]])

这将识别集群:

lw, num = measurements.label(z2)
print lw
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
   [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
   [0, 0, 1, 0, 2, 0, 0, 0, 3, 0],
   [0, 0, 0, 0, 0, 0, 4, 0, 3, 0],
   [0, 0, 0, 0, 0, 0, 4, 0, 0, 0],
   [0, 0, 0, 0, 5, 0, 4, 0, 0, 0],
   [0, 0, 0, 0, 0, 4, 4, 0, 0, 0],
   [0, 0, 0, 6, 0, 4, 0, 0, 0, 0],
   [0, 0, 0, 0, 7, 0, 0, 0, 0, 0],
   [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

以下将计算他们的面积。

area = measurements.sum(z2, lw, index=arange(lw.max() + 1))
print area
[ 0.  2.  1.  2.  6.  1.  1.  1.]

这给出了你所期望的,虽然我认为你会通过眼睛渗透得到一个有8个成员的聚类。

答案 1 :(得分:1)

我觉得你找到“群集”的问题,基本上是基于4连接在二进制图像中找到连接组件(值为0或1)的问题。您可以在此Wikipedia页面中看到几种算法来识别连接的组件(或您定义它们的“簇”):

http://en.wikipedia.org/wiki/Connected-component_labeling

标记连接的组件或“群集”后,您可以轻松找到所需的任何信息,包括区域,相对位置或您可能需要的任何其他信息。

答案 2 :(得分:0)

我相信您的方式几乎是正确的,除非您在递归调用函数count时反复初始化变量clust_size。我会将count变量添加到clust_size的输入参数中,只需在嵌套for循环中使用count = 0重新初始化它。

像这样,您可以将clust_size称为count=clust_size(array, i ,j, count) 我还没有对它进行过测试,但在我看来它应该可行。

希望它有所帮助。

答案 3 :(得分:-2)

如果将其转换为字符串

,则是一个相对简单的问题
import numpy as np                                       
arr=np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],           
              [0, 0, 1, 0, 0, 0, 0, 0, 0, 0,],           
              [0, 0, 1, 1, 1, 1, 1, 1, 1, 0,],   #modified        
              [0, 0, 0, 0, 0, 0, 1, 0, 1, 0,],           
              [0, 0, 0, 0, 0, 0, 1, 0, 0, 0,],           
              [0, 0, 0, 0, 1, 0, 1, 0, 0, 0,],           
              [0, 0, 0, 0, 0, 1, 1, 0, 0, 0,],           
              [0, 0, 0, 1, 0, 1, 0, 0, 0, 0,],           
              [0, 0, 0, 0, 1, 0, 0, 0, 0, 0,],           
              [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])           

arr = "".join([str(x) for x in arr.reshape(-1)])         
print [len(x) for x in arr.replace("0"," ").split()] 

<强>输出

[1, 7, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1] #Cluster sizes