Tengo una gran variedad de números, por ejemplo,
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
Me gustaría encontrar todos los índices de los elementos dentro de un rango específico. Por ejemplo, si el rango es (6, 10), la respuesta debería ser (3, 4, 5). ¿Hay una función incorporada para hacer esto?
np.nonzero(np.logical_and(a>=6, a<=10))
.np.where((a > 6) & (a <= 10))
np.logical_and
es un poco más rápido que eso&
. Ynp.where
es más rápido quenp.nonzero
.Como en la respuesta de @ deinonychusaur, pero aún más compacta:
In [7]: np.where((a >= 6) & (a <=10)) Out[7]: (array([3, 4, 5]),)
fuente
a[(a >= 6) & (a <= 10)]
sia
es una matriz numpy.a
es una matriz numpyPensé que agregaría esto porque
a
en el ejemplo que dio está ordenado: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])
fuente
a = np.array([1,2,3,4,5,6,7,8,9]) b = a[(a>2) & (a<8)]
fuente
Resumen de las respuestas
Para comprender cuál es la mejor respuesta, podemos calcular el tiempo utilizando la solución diferente. Desafortunadamente, la pregunta no estaba bien planteada por lo que hay respuestas a diferentes preguntas, aquí trato de apuntar la respuesta a la misma pregunta. Dada la matriz:
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
La respuesta deben ser los índices de los elementos entre un cierto rango, asumimos inclusivo, en este caso, 6 y 10.
answer = (3, 4, 5)
Correspondiente a los valores 6,9,10.
Para probar la mejor respuesta, 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
Los resultados se informan en la siguiente gráfica. En la parte superior las soluciones más rápidas. Si en lugar de los índices quieres extraer los valores puedes realizar las pruebas usando functions2 pero los resultados son casi los mismos.
fuente
Este fragmento de código devuelve todos los números en una matriz numerosa entre dos valores:
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56] ) a[(a>6)*(a<10)]
Funciona de la siguiente manera: (a> 6) devuelve una matriz numerosa con Verdadero (1) y Falso (0), también lo hace (a <10). Al multiplicar estos dos juntos, se obtiene una matriz con Verdadero, si ambas declaraciones son Verdaderas (porque 1x1 = 1) o Falsa (porque 0x0 = 0 y 1x0 = 0).
La parte a [...] devuelve todos los valores de la matriz a donde la matriz entre corchetes devuelve una declaración Verdadera.
Por supuesto, puede hacer esto más complicado diciendo, por ejemplo
...*(1-a<10)
que es similar a una declaración "y no".
fuente
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56]) np.argwhere((a>=6) & (a<=10))
fuente
Quería agregar numexpr a la mezcla:
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)
Solo tendría sentido para matrices más grandes con millones ... o si alcanza los límites de memoria.
fuente
Otra forma es con:
np.vectorize(lambda x: 6 <= x <= 10)(a)
que devuelve:
array([False, False, False, True, True, True, False, False, False])
A veces es útil para enmascarar series de tiempo, vectores, etc.
fuente
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)
Salida:
(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]
fuente
Puede que este no sea el más bonito, pero funciona para cualquier dimensión.
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)
fuente
Puede usar
np.clip()
para lograr lo mismo:a = [1, 3, 5, 6, 9, 10, 14, 15, 56] np.clip(a,6,10)
Sin embargo, mantiene los valores menores y mayores que 6 y 10 respectivamente.
fuente