簡體   English   中英

在 Python 中的多列上對 numpy 數組進行排序

[英]Sorting numpy array on multiple columns in Python

我正在嘗試在 column1、column2 和 column3 上對以下數組進行排序

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

我使用了以下代碼:

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

結果數組是

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

問題是最后兩行錯了。 正確的數組應該將最后一行作為倒數第二行。 我已經嘗試了一切,但無法理解為什么會發生這種情況。 將感謝一些幫助。

我正在使用以下代碼獲取 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)

tldr:NumPy 在對數值數組進行數值計算時大放異彩。 盡管有可能(見下文),但 NumPy 不太適合於此。 您可能最好使用 Pandas。


問題原因:

值按字符串排序。 您需要將它們排序為ints

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

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

這是因為order_array包含字符串。 您需要在適當的情況下將這些字符串轉換為ints

將數據類型從字符串數據類型轉換為數字數據類型需要為新數組分配空間。 因此,您最好從一開始就修改創建order_array的方式。

有趣的是,即使您將值轉換為整數,當您調用

order_array = np.array(rows_list)

NumPy 默認創建一個同構數組。 在同構數組中,每個值都具有相同的 dtype。 所以 NumPy 試圖在所有值中找到公分母並選擇一個字符串 dtype,這阻礙了您將字符串轉換為整數的努力!

您可以通過檢查order_array.dtype為自己檢查order_array.dtype

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

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

現在,我們如何解決這個問題?


使用對象數據類型:

最簡單的方法是使用“對象”數據類型

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)

這里的問題是, np.lexsortnp.sort不要在D型的陣列的工作object 為了解決這個問題,您可以在創建order_list之前對rows_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')

更好的選擇是將前三列組合到 datetime.date 對象中:

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)

盡管這很簡單,但我不喜歡 NumPy dtype 對象數組。 您既無法獲得具有本機 dtype 的 NumPy 數組的速度,也無法獲得節省內存空間的收益。 此時,您可能會發現使用 Python 列表列表更快,並且在語法上更容易處理。


使用結構化數組:

仍然提供速度和內存優勢的更多 NumPy 解決方案是使用結構化數組(與同類數組相反)。 要使用np.array創建結構化數組,您需要明確提供一個np.array

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

要對結構化數組進行排序,您可以使用sort方法:

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

要使用結構化數組,您需要了解同構數組和結構化數組之間的一些區別:

你原來的同構數組是二維的。 相比之下,所有結構化數組都是一維的:

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

如果使用 int 索引結構化數組或遍歷數組,則會返回行:

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

使用同類數組,您可以使用order_array[:, i]訪問列現在,使用結構化數組,您可以按名稱訪問它們:例如order_array['year']


或者,使用熊貓:

如果您可以安裝Pandas ,我認為您可能會最高興使用 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 具有按日期對齊時間序列、填充缺失值、分組和聚合/轉換行或列的有用功能。


通常,對於年、月、日,使用單個日期列而不是三個整數值列更有用。

如果您需要將年、月、日作為單獨的列用於輸出,比如 csv,那么您可以用年、月、日列替換日期列,如下所示:

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

或者,如果您沒有使用 'date' 列開始,您當然可以rows_list並從一開始就使用年、月、日列構建DataFrame。 排序仍然很容易:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM