【问题标题】:numpy - return index If value inside one of 3d arraynumpy - 如果值在 3d 数组之一内,则返回索引
【发布时间】:2017-01-24 00:11:54
【问题描述】:

如何在 Numpy 中执行此操作:谢谢!

输入:

A = np.array([0, 1, 2, 3]) 

B = np.array([[3, 2, 0], [0, 2, 1], [2, 3, 1], [3, 0, 1]]) 

输出:

result = [[0, 1, 3], [1, 2, 3], [0, 1, 2], [0, 2, 3]]

在 Python 中:

A = np.array([0 ,1 ,2 ,3]) 
B = np.array([[3 ,2 ,0], [0 ,2 ,1], [2 ,3 ,1], [3 ,0 ,1]]) 
result = []
for x ,  valA in enumerate (A) :
    inArray = []
    for y , valB in enumerate (B) : 
        if valA in valB:
            inArray.append (y)
    result.append (inArray)
print result

# result = [[0, 1, 3], [1, 2, 3], [0, 1, 2], [0, 2, 3]]

【问题讨论】:

    标签: python arrays numpy indexing collect


    【解决方案1】:

    方法#1

    这是使用 broadcasting 的 NumPy 矢量化方法 -

    R,C = np.where((A[:,None,None] == B).any(-1))
    out = np.split(C,np.flatnonzero(R[1:]>R[:-1])+1)
    

    方法 #2

    假设AB 保存正数,我们可以认为它们表示2D 网格上的索引,这样B 可以被认为保存每行的列索引。一旦对应于B2D 网格就位,我们只需要考虑与A 相交的列。最后,我们在这样的2D 网格中获得True 值的索引,从而为我们提供RC 值。这应该更节省内存。

    因此,替代方法看起来像这样 -

    ncols = B.max()+1
    nrows = B.shape[0]
    mask = np.zeros((nrows,ncols),dtype=bool)
    mask[np.arange(nrows)[:,None],B] = 1
    mask[:,~np.in1d(np.arange(mask.shape[1]),A)] = 0
    R,C = np.where(mask.T)
    out = np.split(C,np.flatnonzero(R[1:]>R[:-1])+1)
    

    示例运行 -

    In [43]: A
    Out[43]: array([0, 1, 2, 3])
    
    In [44]: B
    Out[44]: 
    array([[3, 2, 0],
           [0, 2, 1],
           [2, 3, 1],
           [3, 0, 1]])
    
    In [45]: out
    Out[45]: [array([0, 1, 3]), array([1, 2, 3]), array([0, 1, 2]), array([0, 2, 3])]
    

    运行时测试

    将数据集大小扩大100x,这是一个快速的运行时测试结果 -

    In [85]: def index_1din2d(A,B):
        ...:     R,C = np.where((A[:,None,None] == B).any(-1))
        ...:     out = np.split(C,np.flatnonzero(R[1:]>R[:-1])+1)
        ...:     return out
        ...: 
        ...: def index_1din2d_initbased(A,B):
        ...:     ncols = B.max()+1
        ...:     nrows = B.shape[0]
        ...:     mask = np.zeros((nrows,ncols),dtype=bool)
        ...:     mask[np.arange(nrows)[:,None],B] = 1
        ...:     mask[:,~np.in1d(np.arange(mask.shape[1]),A)] = 0
        ...:     R,C = np.where(mask.T)
        ...:     out = np.split(C,np.flatnonzero(R[1:]>R[:-1])+1)
        ...:     return out
        ...: 
    
    In [86]: A = np.unique(np.random.randint(0,10000,(400)))
        ...: B = np.random.randint(0,10000,(400,300))
        ...: 
    
    In [87]: %timeit [np.where((B == x).sum(axis = 1))[0] for x in A]
    1 loop, best of 3: 161 ms per loop # @Psidom's soln
    
    In [88]: %timeit index_1din2d(A,B)
    10 loops, best of 3: 91.5 ms per loop
    
    In [89]: %timeit index_1din2d_initbased(A,B)
    10 loops, best of 3: 33.4 ms per loop
    

    性能进一步提升!

    好吧,或者我们可以在第二种方法中以转置的方式创建2D 网格。这个想法是避免R,C = np.where(mask.T) 中的转置,这似乎是瓶颈。因此,第二种方法的修改版本和相关的运行时看起来像这样 -

    In [135]: def index_1din2d_initbased_v2(A,B):
         ...:     nrows = B.max()+1
         ...:     ncols = B.shape[0]
         ...:     mask = np.zeros((nrows,ncols),dtype=bool)
         ...:     mask[B,np.arange(ncols)[:,None]] = 1
         ...:     mask[~np.in1d(np.arange(mask.shape[0]),A)] = 0
         ...:     R,C = np.where(mask)
         ...:     out = np.split(C,np.flatnonzero(R[1:]>R[:-1])+1)
         ...:     return out
         ...: 
    
    In [136]: A = np.unique(np.random.randint(0,10000,(400)))
         ...: B = np.random.randint(0,10000,(400,300))
         ...: 
    
    In [137]: %timeit index_1din2d_initbased(A,B)
    10 loops, best of 3: 57.5 ms per loop
    
    In [138]: %timeit index_1din2d_initbased_v2(A,B)
    10 loops, best of 3: 25.9 ms per loop
    

    【讨论】:

      【解决方案2】:

      numpylist-comprehension 组合的选项:

      import numpy as np
      [np.where((B == x).sum(axis = 1))[0] for x in A]
      # [array([0, 1, 3]), array([1, 2, 3]), array([0, 1, 2]), array([0, 2, 3])]
      

      【讨论】:

        猜你喜欢
        • 2013-02-10
        • 2019-02-06
        • 1970-01-01
        • 2019-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多