2014-09-04 75 views
7

我的問題是以下,如何在二維numpy數組中找到簇大小?

我有一個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),並返回此數組的簇大小列表。

所謂「集羣」我指的是陣列

數組元素[i] [j]時,如果它的所有鄰居都爲零分離,並且元件1的分離的基團其鄰居是元素:

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

所以前一陣在我們的大小(2,1,2,6,1,1,1)

我試圖通過創建兩個函數來完成這個任務的7個集羣,第一個是遞歸函數:

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時,它會增加計數器「計數」的值,並將元素的值更改爲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

這不行,我不能看到那裏的錯誤是...

我想知道是否也許有一個簡單的方法來做到這一點。

回答

7

它似乎是一個滲透問題。 如果您安裝了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個成員通過eye-percolation的集羣。

0

我相信你的方式幾乎是正確的,除非你遞歸地調用你的函數clust_size一次又一次地初始化變量count。我會將計數變量添加到clust_size的輸入參數中,並且只需在嵌套的for循環中爲每個第一次呼叫重新初始化它即可,其中count = 0即可。

像這樣,你會打電話clust_size總是喜歡count=clust_size(array, i ,j, count) 我還沒有測試過,但它似乎應該工作。

希望它有幫助。

-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 
1

我覺得你的問題找到「羣集」,本質上是基於4連接在二進制映像(值爲0或1)中查找連接組件的相同問題。你可以看到幾種算法在這個維基百科頁面識別所連接的組件(或「集羣」爲您定義他們):

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

一旦連接組件或「集羣」的標記,你可以找到任何信息你很容易,包括區域,相對位置或任何其他信息,你可能想要的。