【问题标题】:Is there a way to understand clusters of zeros and then remove it from numpy array?有没有办法理解零簇,然后从 numpy 数组中删除它?
【发布时间】:2019-06-19 13:29:19
【问题描述】:

我想从 numpy 数组的中间删除零(但不是所有的零都应该删除)

在 stackoverflow 的多个示例中演示了删除零,但我仍然发现很难为我的问题编写逻辑。

import numpy as np

a = np.array([255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,0,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,207,0,0
,159,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,64,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,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
,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,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,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,0,0,0,88,239,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,231,88])

我有一个数组 a,其中有一些非零值和一大堆零(以及非零值中间的一些零)。我想删除那个大的零簇或找到那个大簇开始的索引。然后将数组简化为如下形式:

a1 = [255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,0,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,207,0,0
,159,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,64]

a2=[88,239,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,231,88]

请注意,数组 a1 中仍有一些零。如果其中有一定数量的连续零(例如 10 个零),则该操作应仅删除零。我可以通过循环遍历数组来做到这一点,但如果可以建议一种更简单、更快的方法,那就太好了。

【问题讨论】:

  • 您希望它以 10 个为一组来删除它们吗?或者如果超过 10 个,则全部删除?
  • @JerryM。如果我看到一个长度超过 10 的块,我想删除它。所以如果我只看到 5 个零一起,我想保留它。如果超过 10 个,则整个零块都应该消失。

标签: python arrays numpy


【解决方案1】:

没有任何导入,使用单个循环:

def remove_clusters(my_array, cluster_value, consecutive_max=10):
    my_result = [[]]
    cluster_list = []
    for e in my_array:
        if e == cluster_value:
            cluster_list.append(e)
        else:
            if len(cluster_list) <= consecutive_max:
                my_result[-1].extend(cluster_list)
            else:
                my_result.append([])
            cluster_list = []
            my_result[-1].append(e)
    return my_result

我使用itertools.groupby 得到了这个,它简化了一点代码:

def remove_clusters(my_array, cluster_value=0, max_consecutive=10):
    from itertools import groupby
    my_result = [[]]
    for k,g in groupby(my_array):
        g = list(g)
        if k != cluster_value or len(g) <= max_consecutive:
            my_result[-1].extend(g)
        else:
            my_result.append([])
    return my_result

那么你可以这样做:

a1, a2 = remove_clusters(a)

最后,一个非常丑陋的使用functools.reduce的oneliner

from itertools import groupby
from functools import reduce
a1, a2 = reduce(lambda x,y: x + [[]] if not y[0] and len(y)>10 
                       else x[:-1] + [x[-1]+y], 
                map(lambda x: list(x[1]), groupby(a)), 
                [[]])

我很想解释一下这个oneliner,但我已经不明白了。

【讨论】:

  • 非常感谢您的回答。第一个很直接,我理解。第二个有点难以掌握(我以前没有使用过 itertools),但它对我很有用! :) 使用 group-by 函数需要更少的循环。这是否也像 numpys 一样在 C/C++ 中实现?我想知道这将如何影响我的应用程序的整体性能。 (但现在看来效果很好)
【解决方案2】:

这是另一种方法,主要使用 numpy 而不是任何数组(列表推导之外)。基本思想是获取[(value1, count1), (value2, count2)...] 的列表,然后在该列表中搜索您需要的条件。

有几件事可以改进,主要是检查条件两次。

import numpy as np

a = np.array([255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,0,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,207,0,0
,159,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
,255,64,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,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
,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,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,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,0,0,0,88,239,255,255,255,255,255,255,255
,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,231,88])

def remove_consecutive(thearray, num, count):

    # Find the indices where there is a *change* in value
    adiff = np.diff(a)
    indices = np.hstack((np.array([0]), np.where(adiff)[0]+1))

    # Given the indices we can find the lengths of the lists by just doing a                                                                     
    # diff on the indices. Have to append a dummy so the last value is included.                                                                 
    lengths = np.diff(indices, append=indices[-1]+1)

    # Now construct a tuple of (value, length)
    the_list = list(zip(a[indices], lengths))

    # Find the places where we need to split based on the num/count requirement.                                                                 
    index_breaks = np.array([ii for ii, (lvalue, lcount) in enumerate(the_list) if lvalue == num and lcount > count])                            

    # Split the (value,length) list based on the index_breaks
    the_list_split = np.split(the_list, index_breaks)

    # Now expand back out.
    output_list = [ np.array([lvalue for lvalue, lcount in sublist for _ in range(lcount) if not( lvalue == num and lcount > count)])            
                    for sublist in the_list_split]

    return np.array(output_list).flatten()

a1, a2 = remove_consecutive(a, 0, 10)

print(a1)
print(a2)

输出是:

[255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
   0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
 255 255 207   0   0 159 255 255 255 255 255 255 255 255 255 255 255 255
 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
 255 255 255 255 255 255  64]
[ 88 239 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
 255 255 255 255 255 255 231  88]

【讨论】:

    猜你喜欢
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 2019-02-14
    相关资源
    最近更新 更多