Numpy:找到范围内的元素

Bob*_*Bob 72 python numpy

我有一个数字阵列,例如,

a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])  
Run Code Online (Sandbox Code Playgroud)

我想找到特定范围内的所有元素.例如,如果范围是(6,10),答案应该是(3,4,5).是否有内置函数来执行此操作?

dei*_*aur 113

您可以使用np.where获取索引并np.logical_and设置两个条件:

import numpy as np
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])

np.where(np.logical_and(a>=6, a<=10))
# returns (array([3, 4, 5]),)
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,同样是通过`np.nonzero(np.logical_and(a> = 6,a <= 10))`来实现的. (6认同)
  • 还有`np.where((a&gt; 6)&(a &lt;= 10))` (6认同)
  • @ELinda `np.logic_and` 比 `&amp;` 快一点。并且 `np.where` 比 `np.nonzero` 更快。 (3认同)

tia*_*ago 48

和@ deinonychusaur的回复一样,但更紧凑:

In [7]: np.where((a >= 6) & (a <=10))
Out[7]: (array([3, 4, 5]),)
Run Code Online (Sandbox Code Playgroud)

  • 尼斯.如果`a`是一个numpy数组,你也可以`a [(a> = 6)&(a <= 10)]`. (15认同)
  • 以防万一有人像我一样对评论的措辞感到困惑:这不适用于普通列表,只有当“a”是一个 numpy 数组时才有效 (2认同)

Bi *_*ico 13

我以为我会添加这个,因为a你给出的例子中排序了:

import numpy as np
a = [1, 3, 5, 6, 9, 10, 14, 15, 56] 
start = np.searchsorted(a, 6, 'left')
end = np.searchsorted(a, 10, 'right')
rng = np.arange(start, end)
rng
# array([3, 4, 5])
Run Code Online (Sandbox Code Playgroud)


G M*_*G M 11

答案摘要

为了了解什么是最佳答案,我们可以使用不同的解决方案进行一些计时。不幸的是,这个问题没有很好地提出,所以有不同问题的答案,在这里我尝试将答案指向同一个问题。鉴于数组:

a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
Run Code Online (Sandbox Code Playgroud)

答案应该是某个范围内元素的索引,我们假设包含在内,在本例中为 6 和 10。

answer = (3, 4, 5)
Run Code Online (Sandbox Code Playgroud)

对应于值 6、9、10。

为了测试最佳答案,我们可以使用此代码。

import timeit
setup = """
import numpy as np
import numexpr as ne

a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
# or test it with an array of the similar size
# a = np.random.rand(100)*23 # change the number to the an estimate of your array size.

# we define the left and right limit
ll = 6
rl = 10

def sorted_slice(a,l,r):
    start = np.searchsorted(a, l, 'left')
    end = np.searchsorted(a, r, 'right')
    return np.arange(start,end)
"""

functions = ['sorted_slice(a,ll,rl)', # works only for sorted values
'np.where(np.logical_and(a>=ll, a<=rl))[0]',
'np.where((a >= ll) & (a <=rl))[0]',
'np.where((a>=ll)*(a<=rl))[0]',
'np.where(np.vectorize(lambda x: ll <= x <= rl)(a))[0]',
'np.argwhere((a>=ll) & (a<=rl)).T[0]', # we traspose for getting a single row
'np.where(ne.evaluate("(ll <= a) & (a <= rl)"))[0]',]

functions2 = [
   'a[np.logical_and(a>=ll, a<=rl)]',
   'a[(a>=ll) & (a<=rl)]',
   'a[(a>=ll)*(a<=rl)]',
   'a[np.vectorize(lambda x: ll <= x <= rl)(a)]',
   'a[ne.evaluate("(ll <= a) & (a <= rl)")]',
]

rdict = {}
for i in functions:
    rdict[i] = timeit.timeit(i,setup=setup,number=1000)
    print("%s -> %s s" %(i,rdict[i]))

print("Sorted:")
for w in sorted(rdict, key=rdict.get):
    print(w, rdict[w])
Run Code Online (Sandbox Code Playgroud)

结果

正如@EZLearner 所指出的,下图中报告了一个小数组(在最上面是最快的解决方案)的结果,它们可能会根据数组的大小而有所不同。sorted slice对于较大的数组可能会更快,但它需要对数组进行排序,对于超过 10 M 条目的数组ne.evaluate可能是一种选择。因此,使用与您的数组大小相同的数组执行此测试总是更好: 在此处输入图片说明

如果您想提取值而不是索引,则可以使用函数2 执行测试,但结果几乎相同。

  • 这些结果仅适用于特定长度的数组(此处您选择了一个非常小的数组)。对于较大的阵列,这些结果会迅速改变 (2认同)

Abh*_*hek 9

a = np.array([1,2,3,4,5,6,7,8,9])
b = a[(a>2) & (a<8)]
Run Code Online (Sandbox Code Playgroud)


Jor*_*rvz 6

其他方式是:

np.vectorize(lambda x: 6 <= x <= 10)(a)
Run Code Online (Sandbox Code Playgroud)

返回:

array([False, False, False,  True,  True,  True, False, False, False])
Run Code Online (Sandbox Code Playgroud)

有时它对于屏蔽时间序列、向量等很有用。


Nat*_*han 5

此代码片段返回 numpy 数组中两个值之间的所有数字:

a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56] )
a[(a>6)*(a<10)]
Run Code Online (Sandbox Code Playgroud)

它的工作原理如下:(a>6) 返回一个包含 True (1) 和 False (0) 的 numpy 数组,(a<10) 也是如此。通过将这两者相乘,如果两个语句都是 True(因为 1x1 = 1)或 False(因为 0x0 = 0 和 1x0 = 0),则得到一个带有 True 的数组。

a[...] 部分返回数组 a 的所有值,其中括号之间的数组返回 True 语句。

当然,你可以让事情变得更复杂,例如

...*(1-a<10) 
Run Code Online (Sandbox Code Playgroud)

这类似于“and Not”语句。