Tengo una matriz numpy como esta: [1 2 2 0 0 1 3 5]
¿Es posible obtener el índice de los elementos como una matriz 2d? Por ejemplo, la respuesta para la entrada anterior sería[[3 4], [0 5], [1 2], [6], [], [7]]
Actualmente tengo que recorrer los diferentes valores y solicitar numpy.where(input == i)
cada valor, que tiene un rendimiento terrible con una entrada lo suficientemente grande.
python
numpy
numpy-ndarray
Frederico Schardong
fuente
fuente
np.argsort([1, 2, 2, 0, 0, 1, 3, 5])
daarray([3, 4, 0, 5, 1, 2, 6, 7], dtype=int64)
. entonces puedes comparar los siguientes elementos.Respuestas:
Aquí hay un enfoque O (max (x) + len (x)) usando
scipy.sparse
:Esto funciona creando una matriz dispersa con entradas en las posiciones (x [0], 0), (x [1], 1), ... Usando el
CSC
formato (columna dispersa comprimida) esto es bastante simple. La matriz se convierte luego alLIL
formato (lista vinculada). Este formato almacena los índices de columna para cada fila como una lista en surows
atributo, por lo que todo lo que tenemos que hacer es tomar eso y convertirlo a la lista.Tenga en cuenta que las
argsort
soluciones basadas en matrices pequeñas son probablemente más rápidas, pero en algunos de tamaño no increíblemente grande, esto se cruzará.EDITAR:
argsort
basada solo ennumpy
solución:Si el orden de los índices dentro de los grupos no importa, también puede intentarlo
argpartition
(no hace ninguna diferencia en este pequeño ejemplo, pero esto no está garantizado en general):EDITAR:
@Divakar recomienda contra el uso de
np.split
. En cambio, un bucle es probablemente más rápido:O puede utilizar el nuevo operador de morsa (Python3.8 +):
EDITAR (EDITADO):
(No puro numpy): como alternativa a numba (ver la publicación de @ senderle) también podemos usar pythran.
Compilar con
pythran -O3 <filename.py>
Aquí
numba
gana por un bigote en cuanto al rendimiento:Cosas más antiguas:
Tiempos contra numba (antiguo)
fuente
np.split
.Una opción potencial dependiendo del tamaño de sus datos es simplemente abandonar
numpy
y usarcollections.defaultdict
:Entonces terminas con un diccionario de
{value1: [index1, index2, ...], value2: [index3, index4, ...]}
. La escala de tiempo es bastante lineal con el tamaño de la matriz, por lo que 10,000,000 toma ~ 2.7s en mi máquina, lo que parece bastante razonable.fuente
Aunque la solicitud es para una
numpy
solución, decidí ver si hay unanumba
solución basada en algo interesante . Y de hecho lo hay! Aquí hay un enfoque que representa la lista particionada como una matriz irregular almacenada en un único búfer preasignado. Esto se inspira en elargsort
enfoque propuesto por Paul Panzer . (Para una versión anterior que no funcionó tan bien, pero que era más simple, ver más abajo).Esto procesa una lista de diez millones de elementos en 75 ms, que es casi un 50 veces más rápido que una versión basada en listas escrita en Python puro.
Para una versión más lenta pero algo más legible, esto es lo que tenía antes, basado en el soporte experimental recientemente agregado para "listas escritas" de tamaño dinámico, que nos permiten llenar cada contenedor de una manera desordenada mucho más rápidamente.
Esto lucha
numba
un poco con el motor de inferencia de tipos, y estoy seguro de que hay una mejor manera de manejar esa parte. Esto también resulta ser casi 10 veces más lento que el anterior.Probé esto contra lo siguiente:
También los probé con una versión cython precompilada similar a
enum_bins_numba_buffer
(descrita en detalle a continuación).En una lista de diez millones de entradas aleatorias (
ints = np.random.randint(0, 100, 10000000)
) obtengo los siguientes resultados:Impresionantemente, esta forma de trabajar
numba
supera a unacython
versión de la misma función, incluso con la comprobación de límites desactivada. Todavía no tengo suficiente familiaridadpythran
para probar este enfoque al usarlo, pero me interesaría ver una comparación. Parece probable en base a esta aceleración que elpythran
versión también podría ser bastante más rápida con este enfoque.Aquí está la
cython
versión de referencia, con algunas instrucciones de compilación. Una vez que hayacython
instalado, necesitará unsetup.py
archivo simple como este:Y el módulo Cython,
enum_bins_cython.pyx
:Con estos dos archivos en su directorio de trabajo, ejecute este comando:
Luego puede importar la función usando
from enum_bins_cython import enum_bins_cython
.fuente
Aquí hay una manera realmente extraña de hacer esto que es terrible, pero me pareció demasiado divertido para no compartirlo, ¡y todo
numpy
!EDITAR: este es el mejor método que pude encontrar en este camino. Todavía es 10 veces más lento que la solución de @PaulPanzer
argsort
:fuente
Puede hacerlo haciendo un diccionario de números, las claves serían los números y los valores deberían ser los índices que ese número ve, esta es una de las formas más rápidas de hacerlo, puede ver el código a continuación:
fuente
Pseudocódigo:
obtenga el "número de matrices 1d en la matriz 2d", restando el valor mínimo de su matriz numpy del valor máximo y luego más uno. En su caso, será 5-0 + 1 = 6
Inicializar una matriz 2d con el número de matrices 1d dentro de ella. En su caso, inicialice una matriz 2d con 6 matrices 1d. Cada matriz 1d corresponde a un elemento único en su matriz numpy, por ejemplo, la primera matriz 1d corresponderá a '0', la segunda matriz 1d corresponderá a '1', ...
recorra su matriz numpy, coloque el índice del elemento en la matriz 1d correspondiente. En su caso, el índice del primer elemento en su matriz numpy se colocará en la segunda matriz 1d, el índice del segundo elemento en su matriz numpy se colocará en la tercera matriz 1d ...
Este pseudocódigo tardará un tiempo lineal en ejecutarse, ya que depende de la longitud de su matriz numpy.
fuente
Esto le da exactamente lo que desea y tomaría alrededor de 2.5 segundos por 10,000,000 en mi máquina:
fuente
Entonces, dada una lista de elementos, desea hacer pares (elemento, índice). En tiempo lineal, esto podría hacerse como:
Esto debería llevar tiempo O (n). No puedo pensar en una solución más rápida a partir de ahora, pero actualizaré aquí si lo hago.
fuente