快速,python式的方式在numpy数组中对1的块进行排名?

发布于 2021-01-29 16:24:14

我有一个numpy的阵列,其中包括0的和1的。1数组中每个的序列表示一个事件的发生。我想用事件特定的ID号标记事件的元素(其他数组元素用np.nan),我当然可以在一个循环中做到这一点,但是还有更多的“
python-ish”(快速,矢量化)方法吗它?

我要标记的带有3个事件的numpy数组的示例。

import numpy as np 
arr = np.array([0,0,0,1,1,1,0,0,0,1,1,0,0,0,1,1,1,1])
some_func(arr)

# Expected output of some_func I search for: 
# [np.nan,np.nan,np.nan,0,0,0,np.nan,np.nan,np.nan,1,1,np.nan,np.nan,np.nan,2,2,2,2]
关注者
0
被浏览
51
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    您想贴上标签,还好,SciPy有一个,scipy.ndimage.label-

    In [43]: from scipy.ndimage import label
    
    In [47]: out = label(arr)[0]
    
    In [48]: np.where(arr==0,np.nan,out-1)
    Out[48]: 
    array([nan, nan, nan,  0.,  0.,  0., nan, nan, nan,  1.,  1., nan, nan,
           nan,  2.,  2.,  2.,  2.])
    

    还有一些NumPy的 工作 -

    def rank_chunks(arr):
        m = np.r_[False,arr.astype(bool)]
        idx = np.flatnonzero(m[:-1] < m[1:])
        id_ar = np.zeros(len(arr),dtype=float)
        id_ar[idx[1:]] = 1
        out = id_ar.cumsum()
        out[arr==0] = np.nan
        return out
    

    另一个与masking+ np.repeat-

    def rank_chunks_v2(arr):
        m = np.r_[False,arr.astype(bool),False]
        idx = np.flatnonzero(m[:-1] != m[1:])
        l = idx[1::2]-idx[::2]
        out = np.full(len(arr),np.nan,dtype=float)
        out[arr!=0] = np.repeat(np.arange(len(l)),l)
        return out
    

    时间(将给定的输入平铺到1Mx)-

    In [153]: arr_big = np.tile(arr,1000000)
    
    In [154]: %timeit np.where(arr_big==0,np.nan,label(arr_big)[0]-1)
         ...: %timeit rank_chunks(arr_big)
         ...: %timeit rank_chunks_v2(arr_big)
    1 loop, best of 3: 312 ms per loop
    1 loop, best of 3: 263 ms per loop
    1 loop, best of 3: 229 ms per loop
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看