Dizileri NumPy'de sütuna göre sıralama


336

NumPy'de bir diziyi n. Sütuna göre nasıl sıralayabilirim?

Örneğin,

a = array([[9, 2, 3],
           [4, 5, 6],
           [7, 0, 5]])

Satırları ikinci sütuna göre sıralamak istiyorum, böylece geri dönüyorum:

array([[7, 0, 5],
       [9, 2, 3],
       [4, 5, 6]])

8
Bu gerçekten kötü bir örnektir, çünkü np.sort(a, axis=0)verilen matris için tatmin edici bir çözüm olacaktır. Daha iyi bir örnek içeren bir düzenleme önerdim, ancak aslında soru çok daha açık olsa da reddedildi. Örnek a = numpy.array([[1, 2, 3], [6, 5, 2], [3, 1, 1]])istenen çıktıda olduğu gibi olmalıdırarray([[3, 1, 1], [1, 2, 3], [6, 5, 2]])
David

29
David, sorunun anlamını anlamıyorsun. Her sıradaki düzeni aynı tutmak istiyor.
marcorossi

@marcorossi Anladım, ancak örnek çok kötü bir şekilde formüle edildi, çünkü dediğim gibi, birden fazla olası cevap vardı (ancak OP'nin isteğini yerine getirmezdi). Yorumuma dayalı daha sonra yapılan bir düzenleme gerçekten onaylandı (benimkinin reddedilmesi komikti). Şimdi her şey yolunda.
David

Yanıtlar:


141

@steve 'ın cevabı aslında bunu yapmanın en zarif yoludur.

"Doğru" yol için numpy.ndarray.sort sipariş anahtar kelimesi bağımsız değişkenine bakın

Ancak, dizinizi alanları olan bir dizi olarak (yapılandırılmış bir dizi) görüntülemeniz gerekir.

Dizinizi başlangıçta alanlarla tanımlamadıysanız "doğru" yol oldukça çirkindir ...

Hızlı bir örnek olarak, sıralamak ve bir kopyasını döndürmek için:

In [1]: import numpy as np

In [2]: a = np.array([[1,2,3],[4,5,6],[0,0,1]])

In [3]: np.sort(a.view('i8,i8,i8'), order=['f1'], axis=0).view(np.int)
Out[3]: 
array([[0, 0, 1],
       [1, 2, 3],
       [4, 5, 6]])

Yerinde sıralamak için:

In [6]: a.view('i8,i8,i8').sort(order=['f1'], axis=0) #<-- returns None

In [7]: a
Out[7]: 
array([[0, 0, 1],
       [1, 2, 3],
       [4, 5, 6]])

@ Steve gerçekten bildiğim kadarıyla bunu yapmanın en zarif yolu ...

Bu yöntemin tek avantajı "order" bağımsız değişkeninin, aramayı sıralayacağı alanların bir listesidir. Örneğin, order = ['f1', 'f2', 'f0'] sağlayarak ikinci sütuna, ardından üçüncü sütuna, ardından ilk sütuna göre sıralayabilirsiniz.


3
Benim numpy 1.6.1rc1, yükselirValueError: new type not compatible with array.
Clippit

9
"Doğru" yolun daha az çirkin hale getirilmesi için bir özellik isteği göndermek mantıklı olur mu?
endolith

4
Dizideki değerler ise ne olur float? Bir şey değiştirmeli miyim?
Marco

1
Ve hibrid tip için a = np.array([['a',1,2,3],['b',4,5,6],['c',0,0,1]])hangi yaklaşımı izlemeliyim?
ePascoal

10
Bu yöntemin Steve'e göre en büyük avantajlarından biri, çok büyük dizilerin yerinde sıralanmasına izin vermesidir. Yeterince büyük bir dizi için, döndürülen indeksler np.argsortçok fazla bellek alabilir ve bunun üzerine, bir dizi ile indeksleme de sıralanan dizinin bir kopyasını oluşturur.
ali_m

737

Sanırım bu işe yarıyor: a[a[:,1].argsort()]

Bu, ikinci sütununu gösterir ave buna göre sıralar.


2
Bu belli değil, 1burada ne var? dizine göre sıralanır mı?
orezvani

29
[:,1]'nin ikinci sütununu gösterir a.
Steve Tjoa

60
Ters sıralamayı istiyorsanız, bunu şu şekilde değiştirina[a[:,1].argsort()[::-1]]
Steven C. Howell

1
Basit görünüyor ve çalışıyor! Daha hızlı mı, np.sortdeğil mi?
Václav Pavlík

14
Bunu okumayı daha kolay buluyorum:ind = np.argsort( a[:,1] ); a = a[ind]
haşhaş

32

Steve Tjoa'nın yöntemine göre, mergesort gibi istikrarlı bir sıralama kullanarak ve endeksleri en az anlamlı olandan en önemli sütunlara göre sıralayarak birden çok sütunda sıralayabilirsiniz:

a = a[a[:,2].argsort()] # First sort doesn't need to be stable.
a = a[a[:,1].argsort(kind='mergesort')]
a = a[a[:,0].argsort(kind='mergesort')]

Bu sütun 0, sonra 1, sonra 2'ye göre sıralar.


4
First Sort'un neden kararlı olması gerekmiyor?
Küçük Bobby Masaları

10
İyi soru - kararlı, bir kravat olduğunda orijinal siparişi koruduğunuz ve sıralanmamış dosyanın orijinal sırasının alakasız olduğu anlamına gelir.
JJ

Bu gerçekten çok önemli bir nokta gibi görünüyor. sessizce sıralanmayan bir listeye sahip olmak kötü olurdu.
Sakar kedi

19

Birinin programlarının kritik bir kısmında sıralamayı kullanmak istemesi durumunda, farklı teklifler için bir performans karşılaştırması:

import numpy as np
table = np.random.rand(5000, 10)

%timeit table.view('f8,f8,f8,f8,f8,f8,f8,f8,f8,f8').sort(order=['f9'], axis=0)
1000 loops, best of 3: 1.88 ms per loop

%timeit table[table[:,9].argsort()]
10000 loops, best of 3: 180 µs per loop

import pandas as pd
df = pd.DataFrame(table)
%timeit df.sort_values(9, ascending=True)
1000 loops, best of 3: 400 µs per loop

Yani, argsort ile endeksleme şimdiye kadarki en hızlı yöntem gibi görünüyor ...


19

Gönderen Python dokümantasyon wiki , ben yapabileceğiniz düşünüyorum:

a = ([[1, 2, 3], [4, 5, 6], [0, 0, 1]]); 
a = sorted(a, key=lambda a_entry: a_entry[1]) 
print a

Çıktı:

[[[0, 0, 1], [1, 2, 3], [4, 5, 6]]]

21
Bu çözümle, NumPy dizisi yerine bir liste alınır, bu nedenle bu her zaman uygun olmayabilir (daha fazla bellek alır, muhtemelen daha yavaştır, vb.).
Eric O Lebigot

bu "çözüm" bir faktörü tarafından en çok oylanan cevap yavaş ... aslında, aslında sonsuza yakın
Jivan

16

Gönderen NumPy posta listesi , burada başka bir çözüm var:

>>> a
array([[1, 2],
       [0, 0],
       [1, 0],
       [0, 2],
       [2, 1],
       [1, 0],
       [1, 0],
       [0, 0],
       [1, 0],
      [2, 2]])
>>> a[np.lexsort(np.fliplr(a).T)]
array([[0, 0],
       [0, 0],
       [0, 2],
       [1, 0],
       [1, 0],
       [1, 0],
       [1, 0],
       [1, 2],
       [2, 1],
       [2, 2]])

3
Doğru genelleme a[np.lexsort(a.T[cols])]. cols=[1]orijinal soruda nerede .
Radyo Kontrollü

5

Benzer bir sorun yaşadım.

Benim sorunum:

Ben bir SVD hesaplamak istiyorum ve özdeğerlerimi azalan sırada sıralamak gerekir . Fakat özdeğerler ve özvektörler arasındaki eşlemeyi tutmak istiyorum. Özdeğerlerim ilk satırdaydı ve altındaki karşılık gelen özvektör de aynı sütundaydı.

Bu yüzden iki boyutlu dizi sütun-bilge ilk sıraya göre azalan sırada sıralamak istiyorum.

Çözümüm

a = a[::, a[0,].argsort()[::-1]]

Peki bu nasıl çalışıyor?

a[0,] sıralamak istediğim ilk satır.

Şimdi endekslerin sırasını almak için argsort kullanıyorum.

Kullandığım [::-1]Ben azalan gerek çünkü.

Son olarak a[::, ...], sütunları doğru sırada görüntülemek için kullanıyorum.


1

Biraz daha karmaşık bir lexsortörnek - 1. sütuna inen, ikinciye ikincil olarak artan. Bununla ilgili hileler lexsort, satırlara (dolayısıyla .T) göre sıralanması ve sonuncuya öncelik vermesidir.

In [120]: b=np.array([[1,2,1],[3,1,2],[1,1,3],[2,3,4],[3,2,5],[2,1,6]])
In [121]: b
Out[121]: 
array([[1, 2, 1],
       [3, 1, 2],
       [1, 1, 3],
       [2, 3, 4],
       [3, 2, 5],
       [2, 1, 6]])
In [122]: b[np.lexsort(([1,-1]*b[:,[1,0]]).T)]
Out[122]: 
array([[3, 1, 2],
       [3, 2, 5],
       [2, 1, 6],
       [2, 3, 4],
       [1, 1, 3],
       [1, 2, 1]])

0

İşte tüm sütunları dikkate alan başka bir çözüm ( JJ'nin cevabının daha kompakt bir yolu );

ar=np.array([[0, 0, 0, 1],
             [1, 0, 1, 0],
             [0, 1, 0, 0],
             [1, 0, 0, 1],
             [0, 0, 1, 0],
             [1, 1, 0, 0]])

Lexsort ile sırala,

ar[np.lexsort(([ar[:, i] for i in range(ar.shape[1]-1, -1, -1)]))]

Çıktı:

array([[0, 0, 0, 1],
       [0, 0, 1, 0],
       [0, 1, 0, 0],
       [1, 0, 0, 1],
       [1, 0, 1, 0],
       [1, 1, 0, 0]])

0

Sıralamayı kullanarak, sıralamak istediğiniz sütun numarasını kullanın.

a = np.array([1,1], [1,-1], [-1,1], [-1,-1]])
print (a)
a=a.tolist() 
a = np.array(sorted(a, key=lambda a_entry: a_entry[0]))
print (a)

0

Bu eski bir sorudur, ancak bunu 2 boyuttan daha yüksek bir diziye genellemeniz gerekiyorsa, işte kolayca genelleştirilebilecek bir çözümdür:

np.einsum('ij->ij', a[a[:,1].argsort(),:])

Bu, iki boyut için bir aşırılıktır ve a[a[:,1].argsort()] @ steve'nin cevabı başına yeterli olacaktır, ancak bu cevap daha yüksek boyutlara genelleştirilemez. Bu soruda 3B dizinin bir örneğini bulabilirsiniz .

Çıktı:

[[7 0 5]
 [9 2 3]
 [4 5 6]]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.