2013-08-21 12 views
6

Ich habe zwei Listen, x und y, und ich möchte x sortieren und y durch die Permutation der X-Sortierung permutieren. Zum Beispiel gegebenSchnellste Möglichkeit, mehrere Listen zu sortieren - Python

x = [4, 2, 1, 3] 
y = [40, 200, 1, 30] 

I

x_sorted = [1,2,3,4] 
y_sorted = [1, 200, 30, 40] 

diskutiert zu bekommen Wie in den vergangenen Fragen, eine einfache Möglichkeit, dies zu lösen, ist

x_sorted, y_sorted = zip(*sorted(zip(x,y))) 

Hier meine Frage ist: Was ist der schnellste Weg, dies zu tun?


Ich habe drei Methoden, um die Aufgabe zu erledigen.

import numpy as np 
x = np.random.random(1000) 
y = np.random.random(1000) 

Methode 1:

x_sorted, y_sorted = zip(*sorted(zip(x,y))) #1.08 ms 

Methode 2:

foo = zip(x,y) 
foo.sort() 
zip(*foo)  #1.05 ms 

Methode 3;

ind = range(1000) 
ind.sort(key=lambda i:x[i]) 
x_sorted = [x[i] for i in ind] 
y_sorted = [y[i] for i in ind] #934us 

Gibt es eine bessere Methode, die schneller als die oben genannten drei Methoden ausführt?


Zusätzliche Fragen.

  1. Warum Methode 2 ist nicht schneller als Methode 1, obwohl es Sortiermethode verwendet?
  2. Wenn ich Methode 2 getrennt ausführe, ist es schneller. In IPython Terminal

Ich habe

%timeit foo = zip(x,y) #1000 loops, best of 3: 220 us per loop 
%timeit foo.sort()  #10000 loops, best of 3: 78.9 us per loop 
%timeit zip(*foo)  #10000 loops, best of 3: 73.8 us per loop 

Antwort

4
>>> x = [4, 2, 1, 3] 
>>> y = [40, 200, 1, 30]  
>>> x_sorted, y_sorted = zip(*sorted(zip(x, y), key=lambda a:a[0])) 
>>> x_sorted 
(1, 2, 3, 4) 
>>> y_sorted 
(1, 200, 30, 40) 

Performance:

>>> timeit('foo = zip(x,y); foo.sort(); zip(*foo)', 'from __main__ import x, y', number=1000) 
1.0197240443760691 
>>> timeit('zip(*sorted(zip(x,y)))', 'from __main__ import x, y', number=1000) 
1.0106219310922597 
>>> timeit('ind = range(1000); ind.sort(key=lambda i:x[i]); x_sorted = [x[i] for i in ind]; y_sorteds = [y[i] for i in ind]', 'from __main__ import x, y', number=1000) 
0.9043525504607857 
>>> timeit('zip(*sorted(zip(x, y), key=lambda a:a[0]))', 'from __main__ import x, y', number=1000) 
0.8288150863453723 

das ganze Bild zu sehen:

>>> timeit('sorted(x)', 'from __main__ import x, y', number=1000) 
0.40415491505723367   # just getting sorted list from x 
>>> timeit('x.sort()', 'from __main__ import x, y', number=1000) 
0.008009909448446706   # sort x inplace 

@falsetru Methode - schnellste für np. Arrays

>>> timeit('order = np.argsort(x); x_sorted = x[order]; y_sorted = y[order]', 'from __main__ import x, y, np', number=1000) 
0.05441799872323827 

Wie @AshwiniChaudhary in Kommentaren vorgeschlagen, für Listen gibt es eine Möglichkeit, es zu beschleunigen, indem itertools.izip anstelle von zip:

>>> timeit('zip(*sorted(izip(x, y), key=itemgetter(0)))', 'from __main__ import x, y;from operator import itemgetter;from itertools import izip', number=1000) 
0.4265049757161705 
+1

Sie können 'itertools.izip' für inneres Reißverschluss machen Speicher effizient. –

+0

@AshwiniChaudhary überprüft :) –

+2

Verwenden Sie 'izip nicht außerhalb von sortierten, da es eine Iterator nicht Liste zurückgibt. –

7

Mit numpy.argsort:

>>> import numpy as np 
>>> x = np.array([4,2,1,3]) 
>>> y = np.array([40,200,1,30]) 
>>> order = np.argsort(x) 
>>> x_sorted = x[order] 
>>> y_sorted = y[order] 
>>> x_sorted 
array([1, 2, 3, 4]) 
>>> y_sorted 
array([ 1, 200, 30, 40]) 

>>> timeit('order = np.argsort(x); x_sorted = x[order]; y_sorted = y[order]', 'from __main__ import x, y, np', number=1000) 
0.030632019043 

HINWEIS

Dies macht Sinn, wenn Eingangsdaten bereits numpy Arrays sind.

+0

toll, offensichtlich Gewinner hier :) –

+1

Dies macht Sinn, wenn sie bereits numpy Arrays sind –

+0

@gnibbler, Sie haben Recht. Ich habe das erwähnt. Vielen Dank. – falsetru

4

Sie sind nicht diese richtig

%timeit foo.sort() 

Nach der ersten Schleife Timing, ist es bereits für den Rest sortiert. Timsort ist sehr effizient für vorsortierte Listen.

Ich war ein wenig überrascht, dass @ Romans Verwendung einer Schlüsselfunktion so viel schneller war. Sie können weitere itemgetter unter Verwendung auf diesem verbessern

from operator import itemgetter 
ig0 = itemgetter(0) 
zip(*sorted(zip(x, y), key=ig0)) 

Dies ist etwa 9% schneller als eine Lambda-Funktion für Listen von 1000 Elementen

+0

großartig, überprüft Ihre Lösung, es gibt mir 0,7580892901514744, +1 für Sie –

Verwandte Themen