2013-10-03 22 views
5

Tôi cố gắng để sắp xếp các mảng sau trên column1, sau đó --COLUMN2 và sau đó cột3Sorting mảng NumPy trên nhiều cột bằng Python

[['2008' '1' '23' 'AAPL' 'Buy' '100'] 
['2008' '1' '30' 'AAPL' 'Sell' '100'] 
['2008' '1' '23' 'GOOG' 'Buy' '100'] 
['2008' '1' '30' 'GOOG' 'Sell' '100'] 
['2008' '9' '8' 'GOOG' 'Buy' '100'] 
['2008' '9' '15' 'GOOG' 'Sell' '100'] 
['2008' '5' '1' 'XOM' 'Buy' '100'] 
['2008' '5' '8' 'XOM' 'Sell' '100']] 

tôi đã sử dụng đoạn mã sau:

idx=np.lexsort((order_array[:,2],order_array[:,1],order_array[:,0])) 
    order_array=order_array[idx] 

Mảng kết quả là

[['2008' '1' '23' 'AAPL' 'Buy' '100'] 
['2008' '1' '23' 'GOOG' 'Buy' '100'] 
['2008' '1' '30' 'AAPL' 'Sell' '100'] 
['2008' '1' '30' 'GOOG' 'Sell' '100'] 
['2008' '5' '1' 'XOM' 'Buy' '100'] 
['2008' '5' '8' 'XOM' 'Sell' '100'] 
['2008' '9' '15' 'GOOG' 'Sell' '100'] 
['2008' '9' '8' 'GOOG' 'Buy' '100']] 

Vấn đề là hai hàng cuối cùng là sai. Mảng chính xác phải có hàng cuối cùng làm hàng cuối cùng. Tôi đã thử mọi thứ nhưng không thể hiểu tại sao điều này lại xảy ra. Sẽ đánh giá cao một số trợ giúp.

Tôi đang sử dụng mã sau để lấy order_array.

for i in …. 
    x= ldt_timestamps[i] # this is a list of timestamps 
    s_sym=…… 
    list=[int(x.year),int(x.month),int(x.day),s_sym,'Buy',100] 
    rows_list.append(list) 

order_array=np.array(rows_list) 
+0

thể trùng lặp của [Sắp xếp một mảng NumPy 2D bằng nhiều trục] (http://stackoverflow.com/questions/2706605/sorting-a-2d-numpy-array-by-multiple -axes) Sử dụng câu trả lời đó, nhưng sử dụng một loại dtype có ý nghĩa cho dữ liệu của bạn (không phải tất cả các chuỗi), ví dụ 'dt = dt = [('y', np.uint32), ('m', np.uint32), ('d', np.uint32), ('sym', 'S4'), ('bs') , 'S4'), ('huh', np.uint32)] ' – askewchan

Trả lời

7

tldr: NumPy chiếu sáng khi thực hiện tính toán số trên mảng số. Mặc dù có thể (xem bên dưới) NumPy không phù hợp với điều này. Có lẽ bạn nên sử dụng Pandas tốt hơn.


Nguyên nhân của vấn đề:

Các giá trị đang được sắp xếp như chuỗi. Bạn cần sắp xếp chúng là ints.

In [7]: sorted(['15', '8']) 
Out[7]: ['15', '8'] 

In [8]: sorted([15, 8]) 
Out[8]: [8, 15] 

Điều này xảy ra vì order_array chứa chuỗi. Bạn cần chuyển đổi các chuỗi đó thành ints nếu thích hợp.

Chuyển đổi loại dtypes từ chuỗi dtype thành dtype dạng số yêu cầu phân bổ không gian cho mảng mới. Do đó, có thể bạn nên cải thiện cách bạn đang tạo order_array ngay từ đầu.

Điều thú vị là, ngay cả khi bạn chuyển đổi các giá trị để ints, khi bạn gọi

order_array = np.array(rows_list) 

NumPy theo mặc định tạo ra một đồng nhất mảng . Trong một mảng đồng nhất, mọi giá trị đều có cùng một kiểu dtype. Vì vậy, NumPy đã cố gắng để tìm mẫu số chung trong số tất cả các giá trị của bạn và chọn một chuỗi dtype, ngăn chặn các nỗ lực bạn đưa vào chuyển đổi các chuỗi để ints!

Bạn có thể kiểm tra dtype cho chính mình bằng cách kiểm tra order_array.dtype:

In [42]: order_array = np.array(rows_list) 

In [43]: order_array.dtype 
Out[43]: dtype('|S4') 

Bây giờ, làm thế nào để chúng tôi sửa lỗi này?


Sử dụng một dtype đối tượng:

Cách đơn giản nhất là sử dụng một 'đối tượng' dtype

In [53]: order_array = np.array(rows_list, dtype='object') 

In [54]: order_array 
Out[54]: 
array([[2008, 1, 23, AAPL, Buy, 100], 
     [2008, 1, 30, AAPL, Sell, 100], 
     [2008, 1, 23, GOOG, Buy, 100], 
     [2008, 1, 30, GOOG, Sell, 100], 
     [2008, 9, 8, GOOG, Buy, 100], 
     [2008, 9, 15, GOOG, Sell, 100], 
     [2008, 5, 1, XOM, Buy, 100], 
     [2008, 5, 8, XOM, Sell, 100]], dtype=object) 

Vấn đề ở đây là np.lexsort hoặc np.sort không làm việc trên mảng của dtype object. Để khắc phục vấn đề đó, bạn có thể sắp xếp các rows_list trước khi tạo order_list:

In [59]: import operator 

In [60]: rows_list.sort(key=operator.itemgetter(0,1,2)) 
Out[60]: 
[(2008, 1, 23, 'AAPL', 'Buy', 100), 
(2008, 1, 23, 'GOOG', 'Buy', 100), 
(2008, 1, 30, 'AAPL', 'Sell', 100), 
(2008, 1, 30, 'GOOG', 'Sell', 100), 
(2008, 5, 1, 'XOM', 'Buy', 100), 
(2008, 5, 8, 'XOM', 'Sell', 100), 
(2008, 9, 8, 'GOOG', 'Buy', 100), 
(2008, 9, 15, 'GOOG', 'Sell', 100)] 

order_array = np.array(rows_list, dtype='object') 

Một lựa chọn tốt hơn là nên kết hợp ba cột đầu tiên vào datetime.date đối tượng:

import operator 
import datetime as DT 

for i in ...: 
    seq = [DT.date(int(x.year), int(x.month), int(x.day)) ,s_sym, 'Buy', 100] 
    rows_list.append(seq) 
rows_list.sort(key=operator.itemgetter(0,1,2))   
order_array = np.array(rows_list, dtype='object') 

In [72]: order_array 
Out[72]: 
array([[2008-01-23, AAPL, Buy, 100], 
     [2008-01-30, AAPL, Sell, 100], 
     [2008-01-23, GOOG, Buy, 100], 
     [2008-01-30, GOOG, Sell, 100], 
     [2008-09-08, GOOG, Buy, 100], 
     [2008-09-15, GOOG, Sell, 100], 
     [2008-05-01, XOM, Buy, 100], 
     [2008-05-08, XOM, Sell, 100]], dtype=object) 

Mặc dù đây là đơn giản, tôi không thích mảng NumPy của đối tượng dtype. Bạn không nhận được tốc độ cũng như mức độ tiết kiệm không gian bộ nhớ của các mảng NumPy với kiểu gốc. Tại thời điểm này, bạn có thể tìm cách làm việc với danh sách các danh sách của Python nhanh hơn và dễ dàng hơn về cú pháp để giải quyết.


Sử dụng một mảng cấu trúc:

Một giải pháp nữa NumPy-ish mà vẫn mang lại lợi ích tốc độ và bộ nhớ là sử dụng một structured array (như trái ngược với mảng đồng nhất). Để thực hiện một mảng cấu trúc với np.array bạn sẽ cần phải cung cấp một dtype một cách rõ ràng:

dt = [('year', '<i4'), ('month', '<i4'), ('day', '<i4'), ('symbol', '|S8'), 
     ('action', '|S4'), ('value', '<i4')] 
order_array = np.array(rows_list, dtype=dt) 

In [47]: order_array.dtype 
Out[47]: dtype([('year', '<i4'), ('month', '<i4'), ('day', '<i4'), ('symbol', '|S8'), ('action', '|S4'), ('value', '<i4')]) 

Để sắp xếp các mảng cấu trúc, bạn có thể sử dụng phương pháp sort:

order_array.sort(order=['year', 'month', 'day']) 

Để làm việc với mảng có cấu trúc, bạn sẽ cần phải biết về một số khác biệt giữa mảng thuần nhất và có cấu trúc:

Bản gốc của bạn mảng đồng nhất là 2 chiều. Ngược lại, tất cả mảng cấu trúc là 1 chiều:

In [51]: order_array.shape 
Out[51]: (8,) 

Nếu bạn chỉ số mảng cấu trúc với một int hoặc lặp qua mảng, bạn nhận lại hàng:

In [52]: order_array[3] 
Out[52]: (2008, 1, 30, 'GOOG', 'Sell', 100) 

Với mảng đồng nhất bạn có thể truy cập các cột với order_array[:, i] Bây giờ, với một mảng có cấu trúc, bạn truy cập chúng theo tên: ví dụ order_array['year'].


Hoặc, sử dụng Pandas:

Nếu bạn có thể cài đặt Pandas, tôi nghĩ bạn có thể làm việc hạnh phúc nhất với một Pandas DataFrame:

In [73]: df = pd.DataFrame(rows_list, columns=['date', 'symbol', 'action', 'value']) 
In [75]: df.sort(['date']) 
Out[75]: 
     date symbol action value 
0 2008-01-23 AAPL Buy 100 
2 2008-01-23 GOOG Buy 100 
1 2008-01-30 AAPL Sell 100 
3 2008-01-30 GOOG Sell 100 
6 2008-05-01 XOM Buy 100 
7 2008-05-08 XOM Sell 100 
4 2008-09-08 GOOG Buy 100 
5 2008-09-15 GOOG Sell 100 

Pandas có chức năng hữu ích cho việc sắp xếp chuỗi thời gian theo ngày, điền vào các giá trị thiếu , nhóm và tổng hợp/chuyển đổi hàng hoặc cột.


Thường thì hữu ích hơn khi có cột ngày đơn thay vì ba cột có giá trị nguyên cho năm, tháng, ngày.

Nếu bạn cần năm, tháng, ngày cột như riêng biệt với mục đích outputing, để nói csv, sau đó bạn có thể thay thế các cột ngày với năm tháng, cột, ngày như thế này:

In [33]: df = df.join(df['date'].apply(lambda x: pd.Series([x.year, x.month, x.day], index=['year', 'month', 'day']))) 

In [34]: del df['date'] 

In [35]: df 
Out[35]: 
    symbol action value year month day 
0 AAPL Buy 100 2008  1 23 
1 GOOG Buy 100 2008  1 23 
2 AAPL Sell 100 2008  1 30 
3 GOOG Sell 100 2008  1 30 
4 XOM Buy 100 2008  5 1 
5 XOM Sell 100 2008  5 8 
6 GOOG Buy 100 2008  9 8 
7 GOOG Sell 100 2008  9 15 

Hoặc, nếu bạn không sử dụng cột 'ngày' để bắt đầu, bạn có thể chỉ để riêng rows_list và xây dựng DataFrame với các cột năm, tháng, ngày từ đầu. Sắp xếp là vẫn dễ dàng:

df.sort(['year', 'month', 'day']) 
+0

cảm ơn. nhưng tôi đang chuyển đổi các chuỗi thành int. Tôi đã chỉnh sửa câu hỏi để bao gồm mã để tạo order_array. mong được sự giúp đỡ của bạn – user2842122

+0

@ user2842122 - những 'ints' đó đang được chuyển đổi thành chuỗi. unutbu - Tôi nghĩ rằng giải pháp đơn giản nhất ở đây có thể là giới thiệu một sự tái diễn NumPy, bao gồm một đối tượng datPy [datetime] (http://docs.scipy.org/doc/numpy/reference/arrays.datetime.html) và phần còn lại của bạn dữ liệu chuỗi và số nguyên. Có [một ví dụ hoàn chỉnh ở đây] (http://stackoverflow.com/a/16618557/122022). –

+0

@AronAhmadia: Cảm ơn bạn đã bình luận! Có, tôi đã nghĩ đến việc thêm một cái gì đó như thế, nhưng tôi sợ câu trả lời này đã quá lâu rồi, và Pandas vẫn có lẽ là cách tốt hơn để đi. – unutbu

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