找到细菌群

时间:2015-03-18 19:26:35

标签: python

我必须在Python程序中找到所有连接的细菌簇(4连接)。输入是一个如下所示的文件:

                     ###
                     #####
                     #######
                    #######
                     ######
                     ###### ##
                     ####  #####
                       ## ######        ####
                    #    ######       ####
                  ###  ##########    #####
                #######  ####  ##   ######
                ######### ##   #      #####
      #           ####   ###          ###
     #####        ####    #     ##     ##
     #####                    ######    #
    ######                   ########
     ####                     ########
                              #######
                              #######

注意:无法计算与网格边缘相邻的群集

此文件以类的形式保存在我的班级中。我写了这个函数来查找所有集群,但它创建了许多集群(22而不是5)。知道我可能做错了吗?

我的代码:

def findAll(self):
    self.colonies = [set()]
    for i in range(len(self.grid)):
        for j in range(len(self.grid[i])):
            if self.grid[i][j] == "#":
                added = False
                count = 0
                for k in self.colonies:
                    if self.checkNeighbours((i, j), k):
                        k.add((i, j))
                        added = True
                    count += 1
                if not added:
                    self.colonies.append({(i, j)})

def checkNeighbours(self, pos, current):
    return ((pos[0] + 1, pos[1]) in current
            or (pos[0] - 1, pos[1]) in current
            or (pos[0], pos[1] + 1) in current
            or (pos[0], pos[1] - 1) in current)

2 个答案:

答案 0 :(得分:3)

你遇到的问题是,从你组成两个集群的那一刻起,你就无法加入它们。即使最终这两个集群意味着通过添加中间节点而加入。

这可以通过应用union-find data structure来解决。一个未经优化的python版本是:

s = """\
                     ###                    \
                     #####                  \
                     #######                \
                    #######                 \
                     ######                 \
                     ###### ##              \
                     ####  #####            \
                       ## ######        ####\
                    #    ######       ####  \
                  ###  ##########    #####  \
                #######  ####  ##   ######  \
                ######### ##   #      ##### \
      #           ####   ###          ###   \
     #####        ####    #     ##     ##   \
     #####                    ######    #   \
    ######                   ########       \
     ####                     ########      \
                              #######       \
                              #######       \
"""
representatives = {i: i for i, c in enumerate(s) if c == '#'}
nrows, ncols = 19, 44

def neighbours(idx):
    i, j = divmod(idx, ncols)
    if i > 0: yield idx - ncols
    if i < nrows - 1: yield idx + ncols
    if j > 0: yield idx - 1
    if j < ncols - 1: yield idx + 1

def representative(a):
    while representatives[a] != a: a = representatives[a]
    return a

def join(a, b):
    repr_a, repr_b = representative(a), representative(b)
    if repr_a != repr_b: representatives[repr_a] = repr_b

for idx in representatives:
    for n in neighbours(idx):
        if s[n] == '#': join(idx, n)

cluster_count = len(set(map(representative, representatives)))

结果:

6

您还可以创建图表并使用depth first search查找已连接的组件。上述方法的优点是它是增量的,您可以通过添加新点轻松更新集群。

答案 1 :(得分:3)

使用scipy ndimage measurements模块可轻松检测功能。如果你这样做,它还有速度的附加优势。

import numpy as np
from scipy.ndimage.measurements import label, find_objects

q = np.genfromtxt('bacteria.txt', dtype='S1', comments=':', delimiter=1)
arr = (q == b'#')  # convert to boolean mask because ' ' evaluates to True

labelled, num_features = label(arr)

def count_edge_objects(labelled):
    hulls = find_objects(labelled)
    nbr_edgeobjects = 0
    for rowslice, colslice in hulls:
        if (rowslice.start == 0 or rowslice.stop == labelled.shape[0] or
            colslice.start == 0 or colslice.stop == labelled.shape[1]):
            nbr_edgeobjects += 1
    return nbr_edgeobjects

print('{} objects'.format(num_features - count_edge_objects(labelled)))
# output: 
# 4 objects

在您显示的数据集中,边缘附近有两个对象:顶部的一个和底部的一个。注意我目前假设数据集在每一行上都有相同数量的字符(如果没有,请查看missing_values的{​​{1}}选项)