【问题标题】:Is there a faster alternative to np.where for determining indeces?是否有更快的替代 np.where 来确定索引?
【发布时间】:2020-04-22 04:37:15
【问题描述】:

我有一个这样的数组:

arrayElements = [[1, 4, 6],[2, 4, 6],[3, 5, 6],...,[2, 5, 6]]

例如,我需要知道 arrayElements 等于 1 的索引。

现在,我正在做:

rows, columns = np.where(arrayElements == 1)

这可行,但我在一个循环中执行此操作,该循环遍历所有可能的元素值,在我的情况下,它是 1-500,000+。这需要 30-40 分钟才能运行,具体取决于我的阵列有多大。任何人都可以提出一个更好的方法来解决这个问题吗? (附加信息是我不关心值所在的列,只关心行,不确定这是否有用。)

编辑:我需要分别知道每个元素的值。也就是说,我需要元素包含的每个值的行值。

【问题讨论】:

  • arrayElements 的典型大小是多少?
  • 通常是 [range(1E5,5E5), 9]

标签: python numpy


【解决方案1】:

所以你正在生成数千个这样的数组:

In [271]: [(i,np.where(arr==i)[0]) for i in range(1,7)]                                                
Out[271]: 
[(1, array([0])),
 (2, array([1, 3])),
 (3, array([2])),
 (4, array([0, 1])),
 (5, array([2, 3])),
 (6, array([0, 1, 2, 3]))]

我可以通过一点广播一次对所有值进行 == 测试:

In [281]: arr==np.arange(1,7)[:,None,None]                                                             
Out[281]: 
array([[[ True, False, False],
        [False, False, False],
        [False, False, False],
        [False, False, False]],

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

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

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

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

       [[False, False,  True],
        [False, False,  True],
        [False, False,  True],
        [False, False,  True]]])

因为你只关心行,所以申请any

In [282]: (arr==np.arange(1,7)[:,None,None]).any(axis=2)                                               
Out[282]: 
array([[ True, False, False, False],
       [False,  True, False,  True],
       [False, False,  True, False],
       [ True,  True, False, False],
       [False, False,  True,  True],
       [ True,  True,  True,  True]])

此处的 where 与 Out[271] 中的值相同,但分组方式不同:

In [283]: np.where((arr==np.arange(1,7)[:,None,None]).any(axis=2))                                     
Out[283]: 
(array([0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 5, 5]),
 array([0, 1, 3, 2, 0, 1, 2, 3, 0, 1, 2, 3]))

可以拆分为:

In [284]: from collections import defaultdict                                                          
In [285]: dd = defaultdict(list)                                                                       
In [287]: for i,j in zip(*Out[283]): dd[i].append(j)                                                   
In [288]: dd                                                                                           
Out[288]: 
defaultdict(list,
            {0: [0], 1: [1, 3], 2: [2], 3: [0, 1], 4: [2, 3], 5: [0, 1, 2, 3]})

对于某些阵列,第二种方法可能更快,但它可能无法很好地适应您的全部问题。

【讨论】:

    【解决方案2】:

    通过使用np.isin(请参阅documentation),您可以测试多个元素值。 例如:

    import numpy as np 
    
    a = np.array([1,2,3,4])
    check_for = np.array([1,2])
    
    locs = np.isin(a, check_for)
    # [True,  True, False, False]
    
    np.where(locs)
    #[0, 1]
    
    

    注意:这假设您不需要分别知道每个元素值的索引。

    如果您需要单独跟踪每个元素值,请使用默认字典并遍历矩阵。

    from collections import defaultdict
    
    tracker = defaultdict(set)
    
    for (row, column), value in np.ndenumerate(arrayElements):
        tracker[value].add(row)
    
    

    【讨论】:

    • 我很欣赏您的回复,但我很困惑这将如何更快。一旦我得到了真/假结果,我仍然需要找出哪些行具有你建议使用 np.where 的真值。似乎我的代码的另一行没有提供加速,因为我仍然需要使用 np.where?我可能会错过一些东西吗?编辑:问题是我需要分别了解每个元素的索引。不过谢谢。
    • 在这种情况下,您可以这样考虑问题:内存中有一个保持静态的矩阵,并且要检查 500k+ 个值。大多数这些值可能永远不会出现。与其迭代那么多值,不如迭代一个矩阵。对于您在行 x 遇到的每个元素,您现在可以将行 x 添加到该值字典中,这样 dict[value] = [row1, row2, ...]。即,您保留一个默认字典,其中元素值作为键,一组行作为值。
    • 我不完全知道您所说的元素名称是什么意思,但我认为这不会有问题。比如你对值1感兴趣,也就是你对np.where(arrayElements == 1)感兴趣。然后,如果你遍历arrayElements,并且你在第二行(所以行索引为1),如果你遇到值1就不会出错。程序会调用tracker[1].add(1),稍后你可以查询tracker[1],它将返回 1。此输出表示在第二行(索引值为 1 的行)中看到了值 1。希望这是有道理的。
    • 是的,我意识到我的后续问题毫无意义。这解决了我的问题。谢谢
    • 完美,乐于助人!
    【解决方案3】:

    您可以尝试使用 numpy.ndenumerateCounterdefaultdictdict 循环遍历值和索引,其中键是数组中的值。

    【讨论】:

    • 不是我的,反正我没有足够的代表投反对票
    • 您知道,您的解决方案是正确的,所以,谢谢。
    • @tc_questions 顺便说一句,作为提问者,您可以对任何您认为有帮助的答案进行投票,并接受最好的答案。请参阅stackoverflow.com/help/someone-answers 了解更多信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-04
    • 1970-01-01
    • 2022-08-19
    • 2017-03-18
    相关资源
    最近更新 更多