检查NumPy数组中是否存在值的最有效方法是什么?


73

我有一个非常大的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
.... 

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

谢谢!


1
如果第一个索引不降序,则可以使用二进制搜索;如果您做的比10个搜索要多,则可以考虑进行排序
Luka Rahne 2011年

Answers:


76

怎么样

if value in my_array[:, col_num]:
    do_whatever

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


9
您知道,最近我一直在大量使用numpyany()功能,我完全忘记了old in
2011年

9
好的,这(a)比我的答案可读性更好(b)快40%。
2011年

5
原则上,它可以value in …比快any(… == value),因为它可以遍历数组元素并在遇到值时停止(与计算每个数组元素是否等于该值,然后检查布尔结果之一是否为真相反)。 。
Eric O Lebigot

1
@EOL真的吗?在Python中any是短路,不是numpy吗?
2011年

6
此后情况发生了变化,请注意,将来@detly的答案将成为唯一可行的解​​决方案,目前会发出警告。有关更多信息,请参见stackoverflow.com/questions/40659212/…
borgr

49

对我来说最明显的是:

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

2
嗨,@detly您能添加更多的解释吗?对您来说似乎很明显,但是像我这样的初学者却不是。我的直觉告诉我,这可能是即时通讯正在寻找的解决方案,但我无法通过示例进行尝试:D
jameshwart lopez

@jameshwartlopezmy_array[:, 0]为您提供了所有行(由表示:),并且每行都有0th元素,即第一列。例如,这是一个简单的一维数组[1, 3, 6, 2, 9]。如果==在带标量的numpy中使用运算符,它将进行逐元素比较,并返回与该数组相同形状的布尔numpy数组。所以[1, 3, 6, 2, 9] == 3[False, True, False, False, False]。最后,np.any检查此数组中的任何值是否为True
基利安·巴兹纳

42

要检查多个值,可以使用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

3
+1代表不太知名numpy.in1d(),代表速度非常快searchsorted()
Eric O Lebigot

@eryksun:是的,很有趣。同样的观察,这里……
Eric O Lebigot 2011年

1
请注意,IndexError如果的任何元素values大于的最大值,最后一行将抛出data,因此需要特别注意。
fuglede

@fuglede在这种情况下可以替换indexindex % len(data)np.append(index[:-1],0)等效。
mathfux

np.in1d()仅限于一维numpy数组。如果要检查多维numpy数组中是否有多个值,请使用np.isin()方法。
Aelius

20

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

这是我对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数组))
  • 15s x in(清单)
  • 8s N.any(x == numpy数组)
  • 6s x in(numpy数组)
  • .1s x in(设置或词典)

如果您也想知道列表中的某处(顺序很重要):

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

1

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

在此测试中,in1d最快:

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

使用Python集似乎是最快的:

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

10000000 loops, best of 3: 47 ns per loop

1
比较是不公平的。您需要计算将数组转换为的成本set。OP以NumPy数组开头。
jpp

0

我认为最方便的方法是:

(Val in X[:, col_num])

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

(8 in X[:, 2])

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.