2009-12-14 16 views
29

Si tengo dos listas paralelas y quiero ordenarlos por el orden de los elementos en la primera, es muy fácil:¿Cómo puedo "ordenar zip" matrices numpy paralelas?

>>> a = [2, 3, 1] 
>>> b = [4, 6, 2] 
>>> a, b = zip(*sorted(zip(a,b))) 
>>> print a 
(1, 2, 3) 
>>> print b 
(2, 4, 6) 

¿Cómo puedo hacer lo mismo usando matrices numpy sin desembalar en listas de Python convencionales ?

+1

@YGA, ¿su matriz de entrada "a" tendrá valores no exclusivos? Si es así, ¿cómo te gustaría que el género se comporte en ese caso? ¿Orden arbitraria? Tipo estable? ¿Secuencia secundaria usando los valores correspondientes en la matriz "b"? –

Respuesta

40

b[a.argsort()] deberían hacer el truco.

Así es como funciona. Primero necesitas encontrar una permutación que clasifique a. argsort es un método que calcula la siguiente:

>>> a = numpy.array([2, 3, 1]) 
>>> p = a.argsort() 
>>> p 
[2, 0, 1] 

Se puede comprobar fácilmente que esto es correcto:

>>> a[p] 
array([1, 2, 3]) 

Ahora aplicar la misma permutación en la posición b.

>>> b = numpy.array([4, 6, 2]) 
>>> b[p] 
array([2, 4, 6]) 
+2

Esto no usa 'b' para" clasificación auxiliar ", por ejemplo cuando' a' tiene elementos que se repiten. Por favor, mira mi respuesta para más detalles. –

+1

otoh, la clasificación auxiliar no siempre es deseada. – tacaswell

19

Aquí es un enfoque que no crea listas de Python intermedios, aunque sí requiere una "matriz de registro" NumPy a utilizar para la clasificación. Si sus dos matrices de entrada están realmente relacionadas (como columnas en una hoja de cálculo), esto podría abrir una forma ventajosa de tratar con sus datos en general, en lugar de mantener dos matrices distintas todo el tiempo, en cuyo caso ya tendría una matriz de registros y su problema original serían respondidos simplemente llamando a sort() en su matriz.

Esto hace un in-place sort después de embalar ambas matrices en una matriz de registro:

>>> from numpy import array, rec 
>>> a = array([2, 3, 1]) 
>>> b = array([4, 6, 2]) 
>>> c = rec.fromarrays([a, b]) 
>>> c.sort() 
>>> c.f1 # fromarrays adds field names beginning with f0 automatically 
array([2, 4, 6]) 

Editado utilizar rec.fromarrays() para simplicidad, omita dtype redundante, por defecto el uso clave de ordenación, uso de nombres de campo predeterminados en lugar de especificar (basado en this example).

+0

Gracias! Realmente desearía poder aceptar dos respuestas. Este es menos simple pero más general. Sin embargo, he votado a favor, como lo menos que pude hacer :-) – YGA

2

Esta es la forma más simple y general de hacer lo que quiera. (Usé tres matrices aquí, pero esto funcionará en matrices de cualquier forma, ya sean dos columnas o doscientas).

import numpy as NP 
fnx = lambda : NP.random.randint(0, 10, 6) 
a, b, c = fnx(), fnx(), fnx() 
abc = NP.column_stack((a, b, c)) 
keys = (abc[:,0], abc[:,1])   # sort on 2nd column, resolve ties using 1st col 
indices = NP.lexsort(keys)  # create index array 
ab_sorted = NP.take(abc, indices, axis=0) 

Una peculiaridad w/lexsort es que usted tiene que indique las claves en orden inverso, es decir, poner la segunda clave primaria y su clave secundaria en primer lugar. En mi ejemplo, quiero ordenar usando la segunda columna como la clave principal, así que la enumero en segundo lugar; la primera columna solo resuelve lazos, pero está en primer lugar).

+0

nice catch Brendan, gracias. – doug

Cuestiones relacionadas