เรียงลำดับอาร์เรย์ใน NumPy ตามคอลัมน์


336

ฉันจะจัดเรียงอาร์เรย์ใน NumPy ตามคอลัมน์ที่ n ได้อย่างไร

ตัวอย่างเช่น,

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

ฉันต้องการเรียงลำดับแถวตามคอลัมน์ที่สองเช่นที่ฉันได้รับกลับมา:

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

8
นี่เป็นตัวอย่างที่ไม่ดีจริง ๆ เนื่องจากnp.sort(a, axis=0)จะเป็นโซลูชันที่น่าพอใจสำหรับเมทริกซ์ที่ให้ ฉันแนะนำการแก้ไขด้วยตัวอย่างที่ดีกว่า แต่ถูกปฏิเสธแม้ว่าจริงๆแล้วคำถามจะชัดเจนกว่านี้มาก ตัวอย่างควรมีลักษณะคล้ายa = numpy.array([[1, 2, 3], [6, 5, 2], [3, 1, 1]])กับผลลัพธ์ที่ต้องการarray([[3, 1, 1], [1, 2, 3], [6, 5, 2]])
David

29
เดวิดคุณไม่เข้าใจประเด็น เขาต้องการรักษาลำดับภายในแต่ละแถวไว้เหมือนเดิม
marcorossi

@marcorossi ฉันได้รับจุด แต่ตัวอย่างเป็นสูตรที่ไม่ดีมากเพราะอย่างที่ฉันบอกว่ามีคำตอบที่เป็นไปได้หลายอย่าง (ซึ่งอย่างไรก็ตามจะไม่พอใจคำขอ OP) การแก้ไขในภายหลังตามความคิดเห็นของฉันได้รับการอนุมัติแน่นอน (ตลกที่ฉันได้ปฏิเสธ) ดังนั้นตอนนี้ทุกอย่างเรียบร้อยดี
David

คำตอบ:


141

คำตอบของ@steveเป็นวิธีที่ดีที่สุดในการทำ

สำหรับวิธีการ "แก้ไข" ให้ดูอาร์กิวเมนต์คำหลักของคำสั่งซื้อของnumpy.ndarray.sort

อย่างไรก็ตามคุณจะต้องดูอาร์เรย์ของคุณเป็นอาร์เรย์ที่มีเขตข้อมูล (อาร์เรย์ที่มีโครงสร้าง)

วิธี "ถูกต้อง" ค่อนข้างน่าเกลียดถ้าคุณไม่ได้กำหนดอาเรย์ด้วยฟิลด์ ...

เป็นตัวอย่างด่วนในการจัดเรียงและส่งคืนสำเนา:

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]])

หากต้องการจัดเรียงในสถานที่:

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 เป็นวิธีที่ดีที่สุดในการทำเท่าที่ฉันรู้ ...

ข้อได้เปรียบเพียงอย่างเดียวของวิธีนี้คืออาร์กิวเมนต์ "สั่งซื้อ" เป็นรายการของเขตข้อมูลที่จะเรียงลำดับการค้นหาด้วย ตัวอย่างเช่นคุณสามารถจัดเรียงตามคอลัมน์ที่สองจากนั้นคอลัมน์ที่สามจากนั้นคอลัมน์แรกโดยการจัดหา order = ['f1', 'f2', 'f0']


3
ใน 1.6.1rc1 numpy ของฉันมันยกValueError: new type not compatible with array.
หนีบกระดาษ

9
มันจะทำให้รู้สึกถึงการยื่นคำขอคุณสมบัติที่ "ถูกต้อง" วิธีที่จะทำให้น่าเกลียดน้อยลง?
endolith

4
เกิดอะไรขึ้นถ้าค่าในอาร์เรย์เป็นfloatอย่างไร ฉันควรเปลี่ยนอะไรไหม
Marco

1
และสำหรับประเภทไฮบริดเช่นa = np.array([['a',1,2,3],['b',4,5,6],['c',0,0,1]])ฉันควรทำตามวิธีใด
ePascoal

10
ข้อได้เปรียบที่สำคัญอย่างหนึ่งของวิธีนี้เหนือ Steve's ก็คือมันสามารถจัดเรียงอาร์เรย์ขนาดใหญ่ได้ สำหรับอาเรย์ที่มีขนาดใหญ่พอดัชนีที่ส่งกลับมาnp.argsortอาจจะใช้หน่วยความจำค่อนข้างมากและนอกจากนั้นการทำดัชนีด้วยอาเรย์ก็จะสร้างสำเนาของอาเรย์ที่จัดเรียงอยู่ด้วย
ali_m

737

ฉันคิดว่างานนี้: a[a[:,1].argsort()]

นี่เป็นการระบุคอลัมน์ที่สองของaและเรียงลำดับตามนั้น


2
ยังไม่ชัดเจนมีอะไร1ในนี้บ้าง ดัชนีจะเรียงตาม?
orezvani

29
[:,1]aบ่งบอกถึงคอลัมน์ที่สองของ
Steve Tjoa

60
หากคุณต้องการเรียงลำดับแบบย้อนกลับให้แก้ไขสิ่งนี้ให้เป็นa[a[:,1].argsort()[::-1]]
Steven C Howell

1
ดูเรียบง่ายและใช้งานได้! มันเร็วกว่าnp.sortหรือไม่?
VáclavPavlík

14
ฉันพบว่าอ่านง่ายกว่านี้:ind = np.argsort( a[:,1] ); a = a[ind]
poppie

32

คุณสามารถจัดเรียงหลายคอลัมน์ตามวิธีของ Steve Tjoa โดยใช้การเรียงแบบคงที่เช่นผสานและเรียงลำดับดัชนีจากคอลัมน์ที่มีนัยสำคัญน้อยที่สุดไปยังคอลัมน์ที่สำคัญที่สุด:

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')]

สิ่งนี้จะเรียงตามคอลัมน์ 0 จากนั้น 1 และ 2


4
เหตุใดการเรียงลำดับแรกจึงไม่จำเป็นต้องมีเสถียรภาพ
Little Bobby Tables

10
คำถามที่ดี - เสถียรหมายความว่าเมื่อมีการผูกคุณรักษาคำสั่งเดิมและคำสั่งเดิมของไฟล์ไม่ได้เรียงลำดับไม่เกี่ยวข้อง
JJ

ดูเหมือนจะเป็นจุดสำคัญสุดยอดจริงๆ การมีรายการที่ไม่เรียงลำดับอย่างเงียบ ๆ จะไม่ดี
แมวเงอะงะ

19

ในกรณีที่มีคนต้องการใช้ประโยชน์จากการเรียงลำดับในส่วนที่สำคัญของโปรแกรมของพวกเขานี่คือการเปรียบเทียบประสิทธิภาพสำหรับข้อเสนอที่แตกต่างกัน:

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

ดังนั้นดูเหมือนว่าการจัดทำดัชนีด้วยargsortเป็นวิธีที่เร็วที่สุดจนถึง ...


19

จากวิกิเอกสาร Pythonฉันคิดว่าคุณสามารถทำได้:

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

ผลลัพธ์คือ:

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

21
ด้วยวิธีนี้ผู้ใช้จะได้รับรายการแทนที่จะเป็นอาร์เรย์ NumPy ดังนั้นอาจไม่สะดวกเสมอไป (ใช้หน่วยความจำมากขึ้นอาจช้ากว่า ฯลฯ )
Eric O Lebigot

"โซลูชัน" นี้ช้าลงโดยคำตอบที่ได้รับการโหวตมากที่สุดโดยปัจจัย ... ดีใกล้กับอนันต์จริง
Jivan

16

จากรายชื่อผู้รับจดหมาย NumPy ต่อไปนี้เป็นวิธีแก้ไขปัญหาอื่น:

>>> 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
a[np.lexsort(a.T[cols])]ทั่วไปที่ถูกต้องคือ ที่cols=[1]อยู่ในคำถามเดิม
วิทยุควบคุม

5

ฉันมีปัญหาที่คล้ายกัน

ปัญหาของฉัน:

ฉันต้องการคำนวณ SVD และจำเป็นต้องจัดเรียงค่าลักษณะเฉพาะของฉันตามลำดับจากมากไปน้อย แต่ฉันต้องการเก็บการแมประหว่างค่าลักษณะเฉพาะและค่าลักษณะเฉพาะ ค่าลักษณะเฉพาะของฉันอยู่ในแถวแรกและค่าลักษณะเฉพาะที่เกี่ยวข้องด้านล่างในคอลัมน์เดียวกัน

ดังนั้นฉันต้องการเรียงคอลัมน์อาเรย์สองมิติโดยเรียงตามลำดับแรกจากมากไปหาน้อย

โซลูชันของฉัน

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

แล้วมันทำงานอย่างไร

a[0,] เป็นเพียงแถวแรกที่ฉันต้องการเรียงลำดับ

ตอนนี้ฉันใช้ argsort เพื่อรับลำดับของดัชนี

ฉันใช้[::-1]เพราะฉันต้องการลำดับจากมากไปน้อย

สุดท้ายฉันใช้a[::, ...]เพื่อรับมุมมองกับคอลัมน์ในลำดับที่ถูกต้อง


1

lexsortตัวอย่างที่ซับซ้อนขึ้นเล็กน้อย- จากมากไปน้อยในคอลัมน์ที่ 1 และจากนั้นขึ้นไปที่อันดับที่สอง เทคนิคด้วยlexsortคือว่ามันเรียงลำดับในแถว (จึง.T) และให้ความสำคัญกับคนสุดท้าย

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

นี่เป็นอีกวิธีการหนึ่งในการพิจารณาคอลัมน์ทั้งหมด ( คำตอบของJJมีขนาดเล็กลง);

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

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

เอาท์พุท:

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

เพียงใช้การเรียงลำดับให้ใช้หมายเลข coloumn ตามที่คุณต้องการเรียงลำดับ

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

มันเป็นคำถามเก่า แต่ถ้าคุณต้องการพูดคุยนี้กับอาร์เรย์ที่มีขนาดสูงกว่า 2 มิตินี่คือคำตอบที่ง่ายกว่าทั่วไป

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

นี่เป็น overkill สำหรับสองมิติและa[a[:,1].argsort()]จะเพียงพอต่อคำตอบของ @ steve อย่างไรก็ตามคำตอบนั้นไม่สามารถทำให้เป็นมิติที่สูงขึ้นได้ คุณสามารถหาตัวอย่างของอาร์เรย์ 3 มิติในคำถามนี้

เอาท์พุท:

[[7 0 5]
 [9 2 3]
 [4 5 6]]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.