dado un conjunto de enteros como
[1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5]
Necesito enmascarar elementos que se repiten más de N
veces. Para aclarar: el objetivo principal es recuperar la matriz de máscara booleana, para usarla más adelante para los cálculos de agrupamiento.
Se me ocurrió una solución bastante complicada
import numpy as np
bins = np.array([1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5])
N = 3
splits = np.split(bins, np.where(np.diff(bins) != 0)[0]+1)
mask = []
for s in splits:
if s.shape[0] <= N:
mask.append(np.ones(s.shape[0]).astype(np.bool_))
else:
mask.append(np.append(np.ones(N), np.zeros(s.shape[0]-N)).astype(np.bool_))
mask = np.concatenate(mask)
dando por ejemplo
bins[mask]
Out[90]: array([1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5])
¿Hay una mejor manera de hacer esto?
EDITAR, # 2
¡Muchas gracias por las respuestas! Aquí hay una versión delgada de la trama de referencia de MSeifert. Gracias por señalarme simple_benchmark
. Mostrando solo las 4 opciones más rápidas:
Conclusión
La idea propuesta por Florian H , modificada por Paul Panzer parece ser una excelente manera de resolver este problema, ya que es bastante simple y directo numpy
. numba
Sin embargo, si está de acuerdo con el uso , la solución de MSeifert supera a la otra.
Elegí aceptar la respuesta de MSeifert como solución, ya que es la respuesta más general: maneja correctamente matrices arbitrarias con bloques (no únicos) de elementos repetidos consecutivos. En caso de numba
que no se pueda , ¡ la respuesta de Divakar también vale la pena!
Respuestas:
Quiero presentar una solución usando numba que debería ser bastante fácil de entender. Supongo que desea "enmascarar" elementos repetidos consecutivos:
Por ejemplo:
Actuación:
Utilizando
simple_benchmark
, sin embargo, no he incluido todos los enfoques. Es una escala log-log:Parece que la solución de numba no puede vencer a la solución de Paul Panzer, que parece ser un poco más rápida para arreglos grandes (y no requiere una dependencia adicional).
Sin embargo, ambos parecen superar a las otras soluciones, pero devuelven una máscara en lugar de la matriz "filtrada".
fuente
out
argumento (o tal vez la forma funcional del operador), por lo que no pude guardar esa copia. Por cierto, me gusta bastantesimple_benchmark
.simple_benchmark
! gracias por eso y gracias por supuesto por la respuesta. Como también lo estoy usandonumba
para otras cosas, soy propenso a usarlo aquí y hacer que esta sea la solución. entre una roca y un lugar duro allí ...Descargo de responsabilidad: esta es solo una implementación más sólida de la idea de @ FlorianH:
Para matrices más grandes, esto hace una gran diferencia:
fuente
[1,1,1,1,2,2,1,1,2,2]
.Enfoque n. ° 1: aquí hay una forma vectorizada:
Ejecución de muestra:
Enfoque # 2: versión un poco más compacta -
Enfoque n. ° 3: Usar los recuentos agrupados y
np.repeat
(aunque no nos dará la máscara):Enfoque n. ° 4: con un
view-based
método:Enfoque # 5: con un
view-based
método sin índices deflatnonzero
-fuente
Podrías hacer esto con la indexación. Para cualquier N el código sería:
salida:
fuente
timeit
ejecuciones.Una forma mucho más agradable sería usar la función
numpy
'sunique()
. Obtendrá entradas únicas en su matriz y también el recuento de la frecuencia con la que aparecen:salida:
fuente
Podría usar un ciclo while que verifique si el elemento de matriz N posiciona de nuevo es igual al actual. Tenga en cuenta que esta solución supone que la matriz está ordenada.
fuente
len(question)
alen(bins)
Se podría utilizar grouby a elementos comunes del grupo y lista de filtros que son más de N .
fuente
Solución
Podrías usar
numpy.unique
. La variablefinal_mask
se puede usar para extraer los elementos traget de la matrizbins
.Salida :
fuente
bins
, ¿verdad?final_values
directa, se puede eliminar el comentario de la línea sólo se ha comentado en la solución y en ese caso se podría descartar tres líneas:mask = ...
,final_mask = ...
ybins[final_mask]
.