如何在2D numpy数组中找到最长的非零元素连续发生

时间:2018-03-07 12:13:09

标签: python arrays numpy

我在2D网格上模拟蛋白质折叠,其中每个角度都是±90°或0°,并且存在以下问题:

我有一个n-by-n numpy数组,用零填充,但某些地方的值是从1到n的任何整数。每个整数只出现一次。除端点外,整数k始终是k-1 k + 1的最近邻居。数组被保存为Grid类中的一个对象,我创建它用于进行能量计算和折叠蛋白质。示例数组,n = 5:

>>> from Grid import Grid
>>> a = Grid(5)
>>> a.show()
[[0 0 0 0 0]
 [0 0 0 0 0]
 [1 2 3 4 5]
 [0 0 0 0 0]
 [0 0 0 0 0]]

我的目标是在没有任何弯曲的情况下找到最长的非零元素连续线。在上述情况下,结果应为5。

到目前为止,我的想法是这样的:

def getDiameter(self):
    indexes = np.zeros((self.n, 2))
    for i in range(1, self.n + 1):
        indexes[i - 1] = np.argwhere(self.array == i)[0]

    for i in range(self.n):
         j = 1
        currentDiameter = 1
            while indexes[0][i] == indexes[0][i + j] and i + j <= self.n:
                currentDiameter += 1
                j += 1

        while indexes[i][0] == indexes[i + j][0] and i + j <= self.n:
            currentDiameter += 1
            j += 1

        if currentDiameter > diameter:
            diameter = currentDiameter

     return diameter

这有两个问题:(1)它不起作用,(2)如果我让它工作,它的效率非常低。我想知道是否有人有更好的方法这样做。如果有任何不清楚的地方,请告诉我。

编辑: 不那么简单的例子

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

这里的正确答案是4(最长列和最长行都有四个非零元素)。

2 个答案:

答案 0 :(得分:1)

我从你的问题中理解你需要找到numpy数组中连续元素的最长出现长度(逐行)。

因此对于下面这个,输出应该是5

[[1 2 3 4 0]
 [0 0 0 0 0]
 [10 11 12 13 14]
 [0 1 2 3 0]
 [1 0 0 0 0]]

因为[10 11 12 13 14]是连续元素,并且与任何其他行中的任何连续元素相比,它们的长度最长。

如果这是您所期望的,请考虑以下事项:

import numpy as np
from itertools import groupby

a = np.array([[1, 2, 3, 4, 0],
 [0, 0, 0, 0, 0],
 [10, 11, 12, 13, 14],
 [0, 1, 2, 3, 0],
 [1, 0, 0, 0, 0]])

a = a.astype(float)
a[a == 0] = np.nan
b = np.diff(a)      # Calculate the n-th discrete difference. Consecutive numbers will have a difference of 1.
counter = []
for line in b:       # for each row.
    if 1 in line:    # consecutive elements differ by 1.
        counter.append(max(sum(1 for _ in g) for k, g in groupby(line) if k == 1) + 1)  # find the longest length of consecutive 1's for each row.
print(max(counter))  # find the max of list holding the longest length of consecutive 1's for each row.
# 5

对于您的特定示例:

[[0 0 0 0 0] 
[0 0 0 0 0] 
[1 2 3 4 5] 
[0 0 0 0 0] 
[0 0 0 0 0]]
# 5

答案 1 :(得分:0)

首先找到列表中连续发生的最长时间:

def find_longest(l):
    counter = 0
    counters =[]
    for i in l:
        if i == 0:
            counters.append(counter)
            counter = 0
        else:
            counter += 1
    counters.append(counter)
    return max(counters)

现在您可以将此函数应用于数组的每一行和每一列,并找到最大值:

longest_occurrences = [find_longest(row) for row in a] + [find_longest(col) for col in a.T]
longest_occurrence = max(longest_occurrences)