【问题标题】:What is the most efficient way to check if a value exists in a NumPy array?检查 NumPy 数组中是否存在值的最有效方法是什么?
【发布时间】:2011-10-28 15:39:55
【问题描述】:

我有一个非常大的 NumPy 数组

1 40 3
4 50 4
5 60 7
5 49 6
6 70 8
8 80 9
8 72 1
9 90 7
.... 

我想检查数组的第一列中是否存在值。我有很多本土方法(例如遍历每一行并检查),但考虑到数组的大小,我想找到最有效的方法。

谢谢!

【问题讨论】:

  • 如果第一个索引处于非递减顺序,您可以使用二分搜索,或者如果您执行的搜索次数超过 10 次,则可以考虑排序

标签: python performance numpy


【解决方案1】:

对我来说最明显的是:

np.any(my_array[:, 0] == value)

【讨论】:

  • 嗨@detly你能添加更多解释吗?这对你来说似乎很明显,但像我这样的初学者却不是。我的直觉告诉我,这可能是我正在寻找的解决方案,但没有示例我无法尝试:D
  • @jameshwartlopez my_array[:, 0] 为您提供所有行(由: 表示)和每行0th 元素,即第一列。这是一个简单的一维数组,例如[1, 3, 6, 2, 9]。如果您在 numpy 中使用带有标量的 == 运算符,它将进行元素比较并返回与数组形状相同的布尔 numpy 数组。所以[1, 3, 6, 2, 9] == 3 给了[False, True, False, False, False]。最后,np.any 检查此数组中是否有任何值是 True
【解决方案2】:

怎么样

if value in my_array[:, col_num]:
    do_whatever

编辑:我认为__contains__ 的实现方式与@detly 的版本相同

【讨论】:

  • 你知道,我最近一直在使用numpyany() 函数,我完全忘记了普通的旧in
  • 好的,这 (a) 更具可读性并且 (b) 比我的答案快 40%。
  • 原则上,value in … 可以比any(… == value) 快,因为它可以遍历数组元素并在遇到值时停止(而不是计算每个数组元素是否等于值,然后检查其中一个布尔结果是否为真)。
  • @EOL 真的吗? Python中any是短路的,不是numpy吗?
  • 自那以后情况发生了变化,请注意,将来@detly 的答案将成为唯一可行的解​​决方案,目前会引发警告。有关更多信息,请参阅stackoverflow.com/questions/40659212/… 了解更多信息。
【解决方案3】:

要检查多个值,您可以使用 numpy.in1d(),它是 python 关键字 in 的逐元素函数版本。如果您的数据已排序,您可以使用 numpy.searchsorted():

import numpy as np
data = np.array([1,4,5,5,6,8,8,9])
values = [2,3,4,6,7]
print np.in1d(values, data)

index = np.searchsorted(data, values)
print data[index] == values

【讨论】:

  • +1 用于不太知名的numpy.in1d() 和非常快的searchsorted()
  • @eryksun:是的,很有趣。同样的观察,在这里……
  • 请注意,如果values的任何元素大于data的最大值,最后一行将抛出IndexError,因此需要特别注意。
  • @fuglede 在这种情况下,可以用index % len(data)np.append(index[:-1],0) 等效地替换index
  • np.in1d() 仅限于一维 numpy 数组。如果要检查多个值是否在多维 numpy 数组中,请使用 np.isin() 方法。
【解决方案4】:

添加到@HYRY 的答案 in1d 对于 numpy 来说似乎是最快的。这是使用 numpy 1.8 和 python 2.7.6。

在这个测试中 in1d 是最快的,但是10 in a 看起来更干净:

a = arange(0,99999,3)
%timeit 10 in a
%timeit in1d(a, 10)

10000 loops, best of 3: 150 µs per loop
10000 loops, best of 3: 61.9 µs per loop

构造一个集合比调用 in1d,但是检查值是否存在要快一点:

s = set(range(0, 99999, 3))
%timeit 10 in s

10000000 loops, best of 3: 47 ns per loop

【讨论】:

  • 比较不公平。您需要计算将数组转换为set 的成本。 OP 以 NumPy 数组开头。
  • 我并不是要比较这样的方法,所以我编辑了帖子以指出创建集合的成本。如果你已经有python集,没有太大区别。
【解决方案5】:

令人着迷。我需要提高必须以相同方式执行匹配索引确定的一系列循环的速度。所以我决定在这里计算所有解决方案的时间,以及一些即兴演奏。

这是我对 Python 2.7.10 的速度测试:

import timeit
timeit.timeit('N.any(N.in1d(sids, val))', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')

18.86137104034424

timeit.timeit('val in sids', setup = 'import numpy as N; val = 20010401020091; sids = [20010401010101+x for x in range(1000)]')

15.061666011810303

timeit.timeit('N.in1d(sids, val)', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')

11.613027095794678

timeit.timeit('N.any(val == sids)', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')

7.670552015304565

timeit.timeit('val in sids', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')

5.610057830810547

timeit.timeit('val == sids', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')

1.6632978916168213

timeit.timeit('val in sids', setup = 'import numpy as N; val = 20010401020091; sids = set([20010401010101+x for x in range(1000)])')

0.0548710823059082

timeit.timeit('val in sids', setup = 'import numpy as N; val = 20010401020091; sids = dict(zip([20010401010101+x for x in range(1000)],[True,]*1000))')

0.054754018783569336

非常令人惊讶!数量级差异!

总而言之,如果您只想知道某物是否在一维列表中:

  • 19s N.any(N.in1d(numpy array))
  • 15s x in (list)
  • 8s N.any(x == numpy 数组)
  • 6s x in(numpy 数组)
  • .1s x in(集合或字典)​​

如果您还想知道列表中的某些内容(顺序很重要):

  • 12s N.in1d(x, numpy 数组)
  • 2s x ==(numpy 数组)

【讨论】:

    【解决方案6】:

    我认为最方便的方法是:

    (Val in X[:, col_num])
    

    其中 Val 是您要检查的值,X 是数组。在您的示例中,假设您要检查值 8 是否存在于您的第三列中。简单写

    (8 in X[:, 2])
    

    如果第三列中有 8,则返回 True,否则返回 False。

    【讨论】:

      【解决方案7】:

      如果您正在寻找整数列表,您可以使用索引来完成这项工作。这也适用于 nd-arrays,但似乎更慢。多次这样做可能会更好。

      def valuesInArray(values, array):
          values = np.asanyarray(values)
          array = np.asanyarray(array)
          assert array.dtype == np.int and values.dtype == np.int
          
          matches = np.zeros(array.max()+1, dtype=np.bool_)
          matches[values] = True
          
          res = matches[array]
          
          return np.any(res), res
          
          
      array = np.random.randint(0, 1000, (10000,3))
      values = np.array((1,6,23,543,222))
      
      matched, matches = valuesInArray(values, array)
      

      通过使用 numba 和 njit,我可以将这个速度提高 ~x10。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-23
        • 1970-01-01
        • 1970-01-01
        • 2013-07-04
        • 2023-01-12
        • 1970-01-01
        • 1970-01-01
        • 2012-06-17
        相关资源
        最近更新 更多