2009-12-14 42 views
29

Nếu tôi có hai danh sách song song và muốn sắp xếp chúng theo thứ tự của các yếu tố trong lần đầu tiên, nó rất dễ dàng:Làm cách nào để "sắp xếp zip" các mảng có nhiều mảng song song?

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

Làm thế nào tôi có thể làm điều tương tự sử dụng mảng NumPy mà không cần giải nén chúng vào danh sách Python thường ?

+1

@YGA, mảng đầu vào của bạn "a" có bao giờ có giá trị không duy nhất không? Nếu vậy, làm thế nào bạn muốn loại hành xử trong trường hợp đó? Thứ tự tùy ý? Phân loại ổn định? Phân loại phụ sử dụng các giá trị tương ứng trong mảng "b"? –

Trả lời

40

b[a.argsort()] nên thực hiện thủ thuật.

Đây là cách hoạt động. Trước tiên, bạn cần tìm một hoán vị sắp xếp a. argsort là một phương pháp mà tính này:

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

Bạn có thể dễ dàng kiểm tra rằng đây là đúng:

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

Bây giờ áp dụng các hoán vị cùng với phương án b.

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

Điều này không sử dụng 'b' cho" phân loại phụ trợ ", ví dụ khi' a' có các phần tử lặp lại. Vui lòng xem câu trả lời của tôi để biết chi tiết. –

+1

otoh, phân loại phụ trợ không phải lúc nào cũng mong muốn. – tacaswell

19

Dưới đây là một phương pháp tạo ra không có danh sách Python trung gian, mặc dù nó đòi hỏi một NumPy "mảng kỷ lục" để sử dụng cho việc phân loại. Nếu hai mảng đầu vào của bạn thực sự có liên quan (như các cột trong bảng tính) thì điều này có thể mở ra một cách thuận tiện để xử lý dữ liệu của bạn nói chung, thay vì giữ hai mảng riêng biệt trong mọi thời gian, trong trường hợp này bạn đã có một mảng bản ghi và vấn đề ban đầu của bạn sẽ được trả lời chỉ bằng cách gọi sắp xếp() trên mảng của bạn.

này không một in-place sort sau khi đóng gói cả hai mảng thành một mảng kỷ lục:

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

Sửa sử dụng rec.fromarrays() vì đơn giản, bỏ qua dtype dư thừa, sử dụng mặc định loại chìa khóa, tên trường sử dụng mặc định thay vì chỉ định (dựa trên this example).

+0

Cảm ơn! Tôi thực sự ước tôi có thể chấp nhận hai câu trả lời. Cái này đơn giản hơn nhưng tổng quát hơn. Tôi đã upvoted nó mặc dù, như là ít nhất tôi có thể làm :-) – YGA

2

Đây có thể là cách đơn giản và tổng quát nhất để thực hiện những gì bạn muốn. (Tôi đã sử dụng ba mảng ở đây, nhưng điều này sẽ làm việc trên các mảng của bất kỳ hình dạng nào, cho dù hai cột hay hai trăm).

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) 

Một cách gián tiếp là bạn phải chỉ định các khóa theo thứ tự ngược lại, tức là, đặt khóa chính thứ hai và khóa phụ của bạn trước tiên. Trong ví dụ của tôi, tôi muốn sắp xếp bằng cách sử dụng cột thứ 2 làm khóa chính vì vậy tôi liệt kê nó thứ hai; cột thứ nhất chỉ giải quyết các mối quan hệ, nhưng nó được liệt kê đầu tiên).

+0

đẹp bắt Brendan, cảm ơn. – doug

Các vấn đề liên quan