代码之家  ›  专栏  ›  技术社区  ›  mickey

对于一个数组中的每个标签,将另一个数组中的前k个匹配项设置为false。

  •  2
  • mickey  · 技术社区  · 7 年前

    我有两个(排序的)数组,A和B,长度不同,每个数组包含重复多次的唯一标签。 A中每个标签的计数小于或等于B中的计数。 A中的所有标签都将在B中,但B中的某些标签不会出现在A中。

    我需要一个和B一样长的物体,每个标签 i 在(发生的 k_i 时间),第一个 科伊 标签出现次数 在B中需要设置为 False . 剩下的元素应该是 True .

    下面的代码给出了我需要的,但是如果A和B很大,这可能需要很长时间:

    import numpy as np
    
    # The labels and their frequency
    A = np.array((1,1,2,2,3,4,4,4))
    B = np.array((1,1,1,1,1,2,2,3,3,4,4,4,4,4,5,5))
    
    A_uniq, A_count = np.unique(A, return_counts = True)
    new_ind = np.ones(B.shape, dtype = bool)
    for i in range(len(A_uniq)):
        new_ind[np.where(B == A_uniq[i])[0][:A_count[i]]] = False
    
    print(new_ind)
    #[False False  True  True  True False False False  True False False False
    #  True  True  True  True]
    

    有没有更快或更有效的方法?我觉得我可能缺少一些明显的广播或矢量化的解决方案。

    3 回复  |  直到 7 年前
        1
  •  1
  •   Divakar    7 年前

    这里有一个 np.searchsorted -

    idx = np.searchsorted(B, A_uniq)
    id_ar = np.zeros(len(B),dtype=int)
    id_ar[idx] = 1
    id_ar[A_count+idx] -= 1
    out = id_ar.cumsum()==0
    

    我们可以进一步优化计算 A_uniq,A_count 使用其排序性质而不是使用 np.unique 像这样——

    mask_A = np.r_[True,A[:-1]!=A[1:],True]
    A_uniq, A_count = A[mask_A[:-1]], np.diff(np.flatnonzero(mask_A))
    
        2
  •  1
  •   Alex C    7 年前

    不带numpy的示例

    A = [1,1,2,2,3,4,4,4]
    B = [1,1,1,1,1,2,2,3,3,4,4,4,4,4,5,5]
    
    a_i = b_i = 0
    while a_i < len(A):
      if A[a_i] == B[b_i]:
        a_i += 1
        B[b_i] = False
      else:
        B[b_i] = True
      b_i += 1
    # fill the rest of B with True
    B[b_i:] = [True] * (len(B) - b_i)
    # [False, False, True, True, True, False, False, False, True, False, False, False, True, True, True, True]
    
        3
  •  0
  •   Dani Mesejo    7 年前

    此解决方案的灵感来源于@divakar,使用 itertools.groupby :

    import numpy as np
    from itertools import groupby
    A = np.array((1, 1, 2, 2, 3, 4, 4, 4))
    B = np.array((1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 5, 5))
    
    indices = [key + i for key, group in groupby(np.searchsorted(B, A)) for i, _ in enumerate(group)]
    result = np.ones_like(B, dtype=np.bool)
    result[indices] = False
    
    print(result)
    

    产量

    [False False  True  True  True False False False  True False False False
      True  True  True  True]
    

    这个想法是用 np.searchsorted 查找的每个元素的插入位置 A ,因为相等的元素具有相同的插入位置,所以必须按它们中的每一个移动一次,从而产生groupby。然后创建一个数组 True 并设置 indices False .

    如果你能用 pandas 计算 指数 这样地:

    values = np.searchsorted(B, A)
    indices = pd.Series(values).groupby(values).cumcount() + values