我有一个数字阵列,例如,
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)
tia*_*ago 48
和@ deinonychusaur的回复一样,但更紧凑:
In [7]: np.where((a >= 6) & (a <=10))
Out[7]: (array([3, 4, 5]),)
Run Code Online (Sandbox Code Playgroud)
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 执行测试,但结果几乎相同。
其他方式是:
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)
有时它对于屏蔽时间序列、向量等很有用。
此代码片段返回 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”语句。