【问题标题】:Is there a more elegant/optimised way I can make this connectivity algorithm?有没有更优雅/优化的方法可以制作这种连接算法?
【发布时间】:2019-02-17 10:49:04
【问题描述】:

我已经制定了一个算法,可以从原子列表中计算出分子中连接的原子(考虑到它们之间的距离)。在物理环境之外考虑这个问题,它只是一个封闭的网络问题,其中节点是原子,边缘是连接原子的原子键。我有一个节点列表和一个连接节点的边列表,我需要找出每个独特分子的列表。我已经在下面的代码中做到了这一点,但是它有点慢而且非常难看。有没有办法优化这个算法?

这是我的代码,相关信息供您尝试(我将提供另一个原子列表来尝试称为pairs_1和choice_atom_1,只需将pairs_1更改为pairs并将choice_atom_1更改为choice_atom即可)

pairs = [[0, 1],
 [0, 2],
 [3, 4],
 [3, 5],
 [6, 7],
 [6, 8],
 [9, 10],
 [9, 11],
 [12, 13],
 [12, 14],
 [15, 16],
 [15, 17],
 [18, 19],
 [18, 20],
 [21, 22],
 [21, 23],
 [24, 25],
 [24, 26],
 [27, 28],
 [27, 29],
 [30, 31],
 [30, 32],
 [33, 34],
 [33, 35],
 [36, 37],
 [36, 38],
 [39, 40],
 [39, 41],
 [42, 43],
 [42, 44],
 [45, 46],
 [45, 47]]

chosen_atom = [np.random.rand() for i in range(48)]

pairs_1 = [[0, 6],
 [1, 7],
 [2, 8],
 [3, 9],
 [4, 10],
 [5, 6],
 [5, 10],
 [6, 7],
 [7, 8],
 [8, 9],
 [9, 10]]

chosen_atom_1 = [np.random.rand() for i in range(11)]

# use list of lists to define unique molecules
molecule_list = []

for i in pairs:
    temp_array = []
    for ii in pairs:
        temp_pair = [i[0], i[1]]

        if temp_pair[0] == ii[0]:
            temp_array.append(ii[1])
            temp_array = set(temp_array)
            temp_array = list(temp_array)
        if temp_pair[1] == ii[1]:
            temp_array.append(ii[0])
            temp_array = set(temp_array)
            temp_array = list(temp_array)

        for iii in temp_array:
            for j in pairs:
                if iii == j[0]:
                    temp_array.append(j[1])
                    temp_array = set(temp_array)
                    temp_array = list(temp_array)
                if iii == j[1]:
                    temp_array.append(j[0])
                    temp_array = set(temp_array)
                    temp_array = list(temp_array)

        if len(temp_array) > len(chosen_atom):
            break
    molecule_list.append(temp_array)

molecule_list = [list(item) for item in set(tuple(row) for row in molecule_list)]

# the output of pairs should be
molecule_list = [[8, 6, 7],
 [27, 28, 29],
 [9, 10, 11],
 [0, 1, 2],
 [32, 30, 31],
 [18, 19, 20],
 [45, 46, 47],
 [33, 34, 35],
 [24, 25, 26],
 [42, 43, 44],
 [16, 17, 15],
 [12, 13, 14],
 [21, 22, 23],
 [3, 4, 5],
 [40, 41, 39],
 [36, 37, 38]]
# the output of pairs_1 should be:
molecule_list = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]

所以上面我已经给出了我现在得到的输出,并且应该得到 - 任何使这段代码更好的想法将不胜感激。

【问题讨论】:

  • 这对于CodeReview.SO 来说可能是一个完美的问题,而这里的重点更多地放在问题和解决问题上:)
  • 啊,很好,将它贴在那里 - 谢谢!
  • 寻找连通分量算法。
  • 你可以通过networkx包和一些图论知识轻松解决。这是化学信息学领域。
  • 你所谓的“封闭图”似乎是一个连通组件。所以这确实是连接组件搜索,并且在 Python 中有大约 bajillion 现成的解决方案。

标签: python algorithm list numpy


【解决方案1】:

正如我在 cmets 中所说,您需要连接组件算法,您可以使用 networkx 包轻松解决它:

import networkx as nx

G = nx.from_edgelist(pairs)

print([i for i in nx.connected_components(G)])

# jupyter notebook
%matplotlib inline
nx.draw(G, with_labels=True)

输出:

[{0, 1, 2}, {3, 4, 5}, {8, 6, 7}, {9, 10, 11}, {12, 13, 14}, {16, 17, 15}, {18, 19, 20}, {21, 22, 23}, {24, 25, 26}, {27, 28, 29}, {32, 30, 31}, {33, 34, 35}, {36, 37, 38}, {40, 41, 39}, {42, 43, 44}, {45, 46, 47}]

这是我的script,用于从原子坐标构建和可视化分子图。

【讨论】:

    【解决方案2】:

    这可以使用“union-find”方法解决。

    将每个原子与同一分子中的另一个原子关联起来。链接可能无效。如果不是,它会导致另一个具有自身链接的原子。递归地跟踪链接,您最终将到达一个带有 void 链接的原子。让我们称它为分子中的原子。

    算法的工作原理如下:

    • 依次取每一条边,让 a-b;

    • 找到a的主原子,让main(a);

    • 将 main(a) 链接到 b,将它们重新组合到同一个分子中。

    这样做,main(a) 变得与 main(b) 相同,最终给定分子的所有原子都具有相同的 main。

    在第一次遍历之后,您可以对原子执行一次遍历以枚举主电源,它们对应于不同的分子。

    您还可以添加第三遍,在其中重新组织链接,以便每个主链都会启动一个包含该分子的所有原子的链表。


    变体和优化:

    • 您可以将 main(a) 链接到 main(b),而不是将 main(a) 链接到 b;

    • 在查找 main(a) 时,可以在途中将所有原子重新链接到 main(a);这缩短了未来搜索的路径;

    • 如果您还存储了从 a 到 main(a) 的路径长度,您可以选择将 main(a) 附加到 main(b) 或将 main(b) 附加到 main(a);

    • 您可以让它链接到自身,而不是让主原子链接到 void。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-13
      • 2013-09-11
      • 2021-12-19
      相关资源
      最近更新 更多