Eu tenho uma numerosa matriz de números, por exemplo,
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
Eu gostaria de encontrar todos os índices dos elementos dentro de um intervalo específico. Por exemplo, se o intervalo for (6, 10), a resposta deve ser (3, 4, 5). Existe uma função integrada para fazer isso?
np.nonzero(np.logical_and(a>=6, a<=10))
.np.where((a > 6) & (a <= 10))
np.logical_and
é um pouco mais rápida do&
que antes. Enp.where
é mais rápido do quenp.nonzero
.Como na resposta de @deinonychusaur, mas ainda mais compacta:
In [7]: np.where((a >= 6) & (a <=10)) Out[7]: (array([3, 4, 5]),)
fonte
a[(a >= 6) & (a <= 10)]
ifa
é uma matriz numpy.a
for uma matriz numpyPensei em adicionar isso porque
a
no exemplo que você deu está classificado: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])
fonte
a = np.array([1,2,3,4,5,6,7,8,9]) b = a[(a>2) & (a<8)]
fonte
Resumo das respostas
Para entender qual é a melhor resposta, podemos fazer algum tempo usando a solução diferente. Infelizmente, a questão não foi bem colocada, então há respostas para diferentes questões, aqui procuro apontar a resposta para a mesma questão. Dada a matriz:
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
A resposta deve ser os índices dos elementos entre um determinado intervalo, assumimos inclusive, neste caso, 6 e 10.
answer = (3, 4, 5)
Correspondendo aos valores 6,9,10.
Para testar a melhor resposta, podemos usar este código.
import timeit setup = """ import numpy as np import numexpr as ne a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56]) # 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)")]', ]
Resultados
Os resultados são relatados no gráfico a seguir. No topo as soluções mais rápidas. Se ao invés dos índices você deseja extrair os valores, você pode realizar os testes usando functions2 mas os resultados são quase os mesmos.
fonte
Este snippet de código retorna todos os números em uma matriz numpy entre dois valores:
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56] ) a[(a>6)*(a<10)]
Funciona da seguinte forma: (a> 6) retorna uma matriz numpy com True (1) e False (0), o mesmo acontece com (a <10). Multiplicando esses dois, você obtém um array com True, se ambas as afirmações forem True (porque 1x1 = 1) ou False (porque 0x0 = 0 e 1x0 = 0).
A parte a [...] retorna todos os valores do array a, onde o array entre colchetes retorna uma declaração True.
Claro que você pode tornar isso mais complicado, dizendo, por exemplo
...*(1-a<10)
que é semelhante a uma declaração "e não".
fonte
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56]) np.argwhere((a>=6) & (a<=10))
fonte
Outra maneira é com:
np.vectorize(lambda x: 6 <= x <= 10)(a)
que retorna:
array([False, False, False, True, True, True, False, False, False])
Às vezes é útil para mascarar séries temporais, vetores, etc.
fonte
Queria adicionar numexpr à mistura:
import numpy as np import numexpr as ne a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56]) np.where(ne.evaluate("(6 <= a) & (a <= 10)"))[0] # array([3, 4, 5], dtype=int64)
Só faria sentido para matrizes maiores com milhões ... ou se você atingir um limite de memória.
fonte
s=[52, 33, 70, 39, 57, 59, 7, 2, 46, 69, 11, 74, 58, 60, 63, 43, 75, 92, 65, 19, 1, 79, 22, 38, 26, 3, 66, 88, 9, 15, 28, 44, 67, 87, 21, 49, 85, 32, 89, 77, 47, 93, 35, 12, 73, 76, 50, 45, 5, 29, 97, 94, 95, 56, 48, 71, 54, 55, 51, 23, 84, 80, 62, 30, 13, 34] dic={} for i in range(0,len(s),10): dic[i,i+10]=list(filter(lambda x:((x>=i)&(x<i+10)),s)) print(dic) for keys,values in dic.items(): print(keys) print(values)
Resultado:
(0, 10) [7, 2, 1, 3, 9, 5] (20, 30) [22, 26, 28, 21, 29, 23] (30, 40) [33, 39, 38, 32, 35, 30, 34] (10, 20) [11, 19, 15, 12, 13] (40, 50) [46, 43, 44, 49, 47, 45, 48] (60, 70) [69, 60, 63, 65, 66, 67, 62] (50, 60) [52, 57, 59, 58, 50, 56, 54, 55, 51]
fonte
Isso pode não ser o mais bonito, mas funciona para qualquer dimensão
a = np.array([[-1,2], [1,5], [6,7], [5,2], [3,4], [0, 0], [-1,-1]]) ranges = (0,4), (0,4) def conditionRange(X : np.ndarray, ranges : list) -> np.ndarray: idx = set() for column, r in enumerate(ranges): tmp = np.where(np.logical_and(X[:, column] >= r[0], X[:, column] <= r[1]))[0] if idx: idx = idx & set(tmp) else: idx = set(tmp) idx = np.array(list(idx)) return X[idx, :] b = conditionRange(a, ranges) print(b)
fonte
Você pode usar
np.clip()
para conseguir o mesmo:a = [1, 3, 5, 6, 9, 10, 14, 15, 56] np.clip(a,6,10)
No entanto, ele mantém os valores menores e maiores que 6 e 10, respectivamente.
fonte