【问题标题】:Numpy: For every element in one array, find the index in another arrayNumpy:对于一个数组中的每个元素,找到另一个数组中的索引
【发布时间】:2012-01-05 07:07:47
【问题描述】:

我有两个一维数组,x 和 y,一个比另一个小。我正在尝试查找 x 中 y 的每个元素的索引。

我找到了两种简单的方法来做到这一点,第一种很慢,第二种是内存密集型。

缓慢的方式

indices= []
for iy in y:
    indices += np.where(x==iy)[0][0]

内存猪

xe = np.outer([1,]*len(x), y)
ye = np.outer(x, [1,]*len(y))
junk, indices = np.where(np.equal(xe, ye))

是否有更快的方法或更少的内存密集型方法?理想情况下,搜索将利用这样一个事实,即我们不是在列表中搜索一个东西,而是很多东西,因此更适合并行化。 如果您不假设 y 的每个元素实际上都在 x 中,则可以加分。

【问题讨论】:

    标签: python arrays search numpy indexing


    【解决方案1】:

    使用这行代码:-

    indices = np.where(y[:, None] == x[None, :])[1]

    【讨论】:

      【解决方案2】:

      我认为这是一个更清晰的版本:

      np.where(y.reshape(y.size, 1) == x)[1]
      

      indices = np.where(y[:, None] == x[None, :])[1]。您不需要将 x 广播到 2D 中。

      我发现这种类型的解决方案是最好的,因为与此处或其他地方发布的基于 searchsorted() 或 in1d() 的解决方案不同,上述解决方案适用于重复项,并且它不关心是否对任何内容进行了排序。这对我很重要,因为我希望 x 具有特定的自定义顺序。

      【讨论】:

      • 更清晰并不意味着效率更低。
      【解决方案3】:

      一个更直接的解决方案,它不期望对数组进行排序。

      import pandas as pd
      A = pd.Series(['amsterdam', 'delhi', 'chromepet', 'tokyo', 'others'])
      B = pd.Series(['chromepet', 'tokyo', 'tokyo', 'delhi', 'others'])
      
      # Find index position of B's items in A
      B.map(lambda x: np.where(A==x)[0][0]).tolist()
      

      结果是:

      [2, 3, 3, 1, 4]
      

      【讨论】:

        【解决方案4】:

        我会这样做:

        indices = np.where(y[:, None] == x[None, :])[1]
        

        与你的内存消耗方式不同,这利用广播直接生成 2D 布尔数组,而无需为 x 和 y 创建 2D 数组。

        【讨论】:

        • 为了记录,这也占用了内存。
        • 是的,我的意思是它减少了内存占用。我认为我的版本在保持代码整洁同时占用更少内存方面是一个很好的折衷方案。
        • 这种方法的速度比接受的答案慢 1000 倍。
        【解决方案5】:

        numpy_indexed 包(免责声明:我是它的作者)包含一个功能,正是这样做的:

        import numpy_indexed as npi
        indices = npi.indices(x, y, missing='mask')
        

        如果不是 y 中的所有元素都存在于 x 中,它将当前引发 KeyError;但也许我应该添加一个 kwarg,以便人们可以选择用 -1 或其他东西标记这些项目。

        它应该与当前接受的答案具有相同的效率,因为实现方式相似。然而,numpy_indexed 更加灵活,例如,还允许搜索多维数组行的索引。

        编辑:我改变了缺失值的处理;现在可以使用“raise”、“ignore”或“mask”设置“missing”kwarg。在后一种情况下,您将获得一个与 y 长度相同的掩码数组,您可以在其上调用 .compressed() 来获取有效索引。请注意,如果您只需要知道这些,还有 npi.contains(x, y) 。

        【讨论】:

          【解决方案6】:

          我想建议单行解决方案:

          indices = np.where(np.in1d(x, y))[0]
          

          结果是一个数组,其中包含 x 数组的索引,该数组对应于在 x 中找到的 y 元素。

          如果需要,可以在没有 numpy.where 的情况下使用它。

          【讨论】:

          • 这应该是选择的答案。即使 x 的值重复或不存在,它也可以工作。涉及 searchsorted 的答案是复杂、奇怪、不自然的。
          • 虽然这确实返回了 y 中存在于 x 中的元素的索引,但返回的索引的顺序与 x 中值的顺序不匹配。考虑:x=np.array([1,2,3,4,5]; y=np.array([5,4,3,2,1])。上面的方法返回array([0,1, 2,3,4]),所以 x[0]=1 匹配到 y[0]=5,这不是我们想要的...
          • in1d() 解决方案不起作用。取 y = np.array([10, 5, 5, 1, 'auto', 6, 'auto', 1, 5, 10, 10, 'auto']) 和 x = np.array(['auto' , 5, 6, 10, 1])。你会期望 [3, 1, 1, 4, 0, 2, 0, 4, 3, 3, 0]。 np.where(np.in1d(x, y))[0] 不会产生那个。
          • 这里简单的说明x中的元素是否存在于y中,然后给出x中对应的索引。它没有为 x 中的每个项目在 y 中给出相应的索引。
          【解决方案7】:

          正如 Joe Kington 所说,searchsorted() 可以非常快速地搜索元素。处理不在x中的元素,可以用原始y检查搜索结果,并创建一个掩码数组:

          import numpy as np
          x = np.array([3,5,7,1,9,8,6,6])
          y = np.array([2,1,5,10,100,6])
          
          index = np.argsort(x)
          sorted_x = x[index]
          sorted_index = np.searchsorted(sorted_x, y)
          
          yindex = np.take(index, sorted_index, mode="clip")
          mask = x[yindex] != y
          
          result = np.ma.array(yindex, mask=mask)
          print result
          

          结果是:

          [-- 3 1 -- -- 6]
          

          【讨论】:

            【解决方案8】:

            这个怎么样?

            它确实假设 y 的每个元素都在 x 中,(并且即使对于不是的元素也会返回结果!)但它要快得多。

            import numpy as np
            
            # Generate some example data...
            x = np.arange(1000)
            np.random.shuffle(x)
            y = np.arange(100)
            
            # Actually preform the operation...
            xsorted = np.argsort(x)
            ypos = np.searchsorted(x[xsorted], y)
            indices = xsorted[ypos]
            

            【讨论】:

            • 太棒了。确实快得多。我包括assert na.all(na.intersect1d(x,y) == na.sort(y)) 来限制输入,使y 是x 的子集。谢谢!
            猜你喜欢
            • 2016-09-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-06-11
            相关资源
            最近更新 更多